[
  {
    "path": ".circleci/config.yml",
    "content": "anchors:\n  - &srcLibs          \"2024-Sept-src\"\n  - &macOSx86Libs     \"2024-Sept-macOSx86\"\n  - &appleSiliconLibs \"2024-Sept-appleSilicon\"\n  - &u20Libs          \"2025-July-Ubuntu20\"\n\nversion: 2.1\n\norbs:\n  win: circleci/windows@2.2.0\n\nreferences:\n  workspace_root: &workspace_root\n    /tmp/workspace\n  attach_workspace: &attach_workspace\n    attach_workspace:\n      at: *workspace_root\n\ncommands:\n  get_libraries:\n    parameters:\n      useAWS:\n        type: boolean\n        default: true\n      fileName:\n        type: string\n      sudo:\n        type: string\n        default: \"\"\n      dir:\n        type: string\n        default: \"/usr/local/VAPOR-Deps\"\n    steps:\n      - run:\n          name: get third party libraries\n          command: |\n              # if /usr/local/VAPOR-Deps is empty, acquire libraries \n              if [ ! -d <<parameters.dir>> ]; then\n                <<parameters.sudo>> mkdir -p <<parameters.dir>>\n                <<parameters.sudo>> chmod -R 777 <<parameters.dir>>\n                <<parameters.sudo>> chown -R `whoami` <<parameters.dir>>\n                wget https://vaporawsbucket.s3.us-west-2.amazonaws.com/<<parameters.fileName>>.tar.xz\n                tar -xf <<parameters.fileName>>.tar.xz -C <<parameters.dir>>\n              fi\n\n  build_vapor:\n    parameters:\n      branch:\n        type: string\n        default: $CIRCLE_BRANCH\n      beforeCompile:\n        type: string\n        default: \"\"\n      compileArgs:\n        type: string\n        default: \"\"\n      moveToCommand:\n        type: string\n      libDir:\n        type: string\n        default: \"/usr/local/VAPOR-Deps\"\n      libName:\n        type: string\n        default: 2023-Sept\n    steps:\n      - run:\n          name: build vapor\n          command: |\n            libraryDir=`ls <<parameters.libDir>>`\n            ln -s $libraryDir <<parameters.libDir>>/current\n            cp site_files/site.NCAR site.local\n            mkdir -p build\n            cd build\n            git checkout <<parameters.branch>>\n            <<parameters.beforeCompile>>\n            cmake \\\n            -DCMAKE_BUILD_TYPE:String=Release \\\n            -DDIST_INSTALLER:string=ON \\\n            -DUSE_OMP=ON \\\n            <<parameters.compileArgs>> \\\n            -DTHIRD_PARTY_DIR=<<parameters.libDir>>/current ..\n            make -j4\n            make installer\n            for f in VAPOR3-* ; do mv \"$f\" \"<<parameters.moveToCommand>>\" ; done\n            mkdir -p /tmp/workspace/installers\n            find VAPOR* -maxdepth 1 -type f \\( -name \"*.AppImage\" -o -name \"*.exe\" -o -name \"*.dmg\" \\) -exec mv {} /tmp/workspace/installers \\;\n            ls /tmp/workspace/installers\n          no_output_timeout: 30m\n      - store_artifacts:\n          path: /tmp/workspace/installers\n      - persist_to_workspace:\n          root: *workspace_root\n          paths:\n            - installers\n\n  smoke_tests:\n    steps:\n      - restore_cache:\n          name: restore smoke test data\n          keys:\n            - smoke-test-data\n      - run:\n          name: Acquire smoke test data\n          command: |\n            if [ -z \"$(ls -A /smokeTestData)\" ]; then\n                mkdir -p /smokeTestData\n                wget https://vaporawsbucket.s3.us-west-2.amazonaws.com/smokeTestData.tar.gz\n                tar --no-same-owner -xf /root/project/smokeTestData.tar.gz -C /smokeTestData\n                chown -R root:root /smokeTestData\n                chmod -R 777 /smokeTestData\n            else\n                echo \"Data already acquired\"\n            fi\n      - save_cache:\n          key: smoke-test-data\n          paths:\n            - /smokeTestData\n      - run:\n          name: Smoke tests\n          command: |\n            python3 ~/project/test_apps/smokeTests/smokeTests.py \\\n            -testDataRoot=/smokeTestData/smokeTestData \\\n            -binaryRoot=~/project/build/test_binaries \\\n            -resultsDir=~/project/test_apps/smokeTests/testResults\n      - store_artifacts:\n          path: ~/project/test_apps/smokeTests/testResults\n\n  get_macos_dependencies:\n    steps:\n      - run:\n          name: Get dependencies\n          command: |\n            #Caching clang would miss every couple of weeks and require ~2 hours of build time.\n            #Instead of caching it, we're just going to host it on aws and download it.\n            wget https://vaporawsbucket.s3.us-west-2.amazonaws.com/portClang.tar.xz\n            sudo tar -xf portClang.tar.xz -C /\n\n            brew install cmake\n          no_output_timeout: 45m\n\njobs:\n  build_win10_installer:\n    executor: win/default\n    steps:\n      - checkout\n      - run:\n          name: Install dependencies\n          command: |\n            choco install visualstudio2019-workload-vctools -y\n            choco install python -y\n            choco install git -y\n            choco install cmake --version=3.31.6 -y\n            choco install nsis -y\n            python -m pip install gdown\n            setx /M PATH \"%PATH%;C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\MSBuild\\Current\\Bin\"\n            msbuild -version\n            pwd\n            ls\n            python .circleci/downloadWin3rdParty.py\n          no_output_timeout: 20m\n      - run:\n          name: dos2unix\n          command: |\n            dos2unix /c/Users/circleci/project/share/shaders/*\n            dos2unix /c/Users/circleci/project/share/shaders/main\n            dos2unix /c/Users/circleci/project/share/shaders/includes\n          shell: bash.exe\n      - run:\n          name: Build Vapor\n          command: |\n            Copy-Item site_files\\* -Destination .\n            mkdir build\n            cd build\n            git checkout $CIRCLE_BRANCH\n            & 'C:\\\\Program Files\\\\CMake\\\\bin\\\\cmake.exe' -S C:\\Users\\circleci\\project -B C:\\Users\\circleci\\project\\build -DDIST_INSTALLER:string=ON -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_OSP=OFF -G 'Visual Studio 16 2019' -A x64\n            msbuild C:\\Users\\circleci\\project\\build\\PACKAGE.vcxproj /p:Configuration=Release /p:Platform=x64\n            mkdir -p C:\\Users\\circleci\\project\\tmp\\workspace\\installers\n            Copy-Item C:\\Users\\circleci\\project\\build\\*.exe -Destination C:\\Users\\circleci\\project\\tmp\\workspace\\installers\n            if (!(Test-Path -Path C:\\Users\\circleci\\project\\tmp\\workspace\\installers\\*.exe)) {\n              Write-Error \"Build failed: No installers found\"\n              exit 1\n            }\n          no_output_timeout: 45m\n\n      - store_artifacts:\n          path: C:\\Users\\circleci\\project\\tmp\\workspace\\installers\n\n      - persist_to_workspace:\n          root: C:\\Users\\circleci\\project\\tmp\\workspace\n          paths:\n            - installers\n\n  build_macOSx86_installer:\n    macos:\n      xcode: \"14.3.1\"\n    resource_class: m4pro.large\n    steps:\n      - checkout\n      - get_libraries:\n          fileName: *macOSx86Libs\n          sudo: sudo\n      - get_macos_dependencies\n      - build_vapor:\n          beforeCompile: export PATH=/opt/local/bin:$PATH; softwareupdate --install-rosetta --agree-to-license\n          compileArgs: |\n            -DCMAKE_BUILD_TYPE:String=Release \\\n            -DDIST_INSTALLER:string=ON \\\n            -DUSE_OMP=ON \\\n            -DCPACK_BINARY_DRAGNDROP=ON \\\n            -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang \\\n            -DCMAKE_OSX_ARCHITECTURES=x86_64  \\\n            -DTHIRD_PARTY_DIR=/usr/local/VAPOR-Deps/current \\\n          moveToCommand: ${f/Darwin/macOSx86}\n\n  build_appleSilicon_installer:\n    macos:\n      xcode: \"14.3.1\"\n    resource_class: m4pro.large\n    steps:\n      - checkout\n      - get_libraries:\n          fileName: *appleSiliconLibs\n          sudo: sudo\n      - get_macos_dependencies\n      - build_vapor:\n          beforeCompile: export PATH=/opt/local/bin:$PATH\n          compileArgs: |\n            -DCMAKE_BUILD_TYPE:String=Release \\\n            -DDIST_INSTALLER:string=ON \\\n            -DUSE_OMP=ON \\\n            -DCPACK_BINARY_DRAGNDROP=ON \\\n            -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang \\\n            -DTHIRD_PARTY_DIR=/usr/local/VAPOR-Deps/current \\\n          moveToCommand: ${f/Darwin/AppleSilicon}\n\n  build_python_api_ubuntuDebug:\n    docker:\n      - image: conda/miniconda3 # Debian based docker image\n\n    resource_class: xlarge\n\n    steps:\n      - checkout\n\n      - run:\n          name: conda build .\n          command: |\n            cd /root/project/conda\n            conda update -y -n base -c defaults conda\n            conda install -y conda-build\n            conda config --add channels conda-forge\n            conda config --add channels ncar-vapor\n            conda build .\n            mkdir /usr/local/conda-bld/linux-64/tarBallDir\n            mv /usr/local/conda-bld/linux-64/*.tar.bz2 /usr/local/conda-bld/linux-64/tarBallDir\n          no_output_timeout: 180m\n \n      - store_artifacts:\n          path: /usr/local/conda-bld/linux-64/tarBallDir\n\n  build_python_api_ubuntu:\n    docker:\n      - image: conda/miniconda3 # Debian based docker image\n\n    resource_class: large\n\n    steps:\n      - checkout\n\n      - run:\n          name: acquire map image archive\n          command: |\n            cd /root\n            # The following resolves the error \"E: The repository 'http://security.debian.org/debian-security stretch/updates Release' does not have a Release file.\"\n            echo \"deb http://archive.debian.org/debian stretch main contrib non-free\" > /etc/apt/sources.list\n\n            apt update\n            apt install -y git\n            git clone https://github.com/NCAR/VAPOR-Data.git\n\n      - run:\n          name: build conda installer\n          command: |\n            conda update -y -n base -c defaults conda\n            conda config --add channels ncar-vapor\n            conda config --add channels conda-forge\n            conda install -y conda-build\n            cd /root/project/conda\n\n            #conda build .\n            DEBUG_BUILD=false MAP_IMAGES_PATH=\"/root/VAPOR-Data/images\" conda build .\n            mkdir /usr/local/conda-bld/linux-64/tarBallDir\n            mv /usr/local/conda-bld/linux-64/*.tar.bz2 /usr/local/conda-bld/linux-64/tarBallDir\n          no_output_timeout: 180m\n\n      - store_artifacts:\n          path: /usr/local/conda-bld/linux-64/tarBallDir\n\n  build_python_api_osx:\n    macos:\n      xcode: \"13.4.1\"\n\n    steps:\n      - checkout\n\n      - run:\n          name: install miniconda\n          command: |\n            brew install wget\n            wget https://repo.continuum.io/miniconda/Miniconda3-py39_4.9.2-MacOSX-x86_64.sh -O ~/miniconda.sh\n            bash ~/miniconda.sh -b -p ~/miniconda\n\n      - run:\n          name: acquire map image archive\n          command: |\n            cd /Users/distiller\n            git clone https://github.com/NCAR/VAPOR-Data.git\n\n      - run:\n          name: conda build .\n          command: |\n            cd /Users/distiller/project/conda\n            /Users/distiller/miniconda/bin/conda install -y conda-build anaconda conda-verify\n            /Users/distiller/miniconda/bin/conda config --add channels conda-forge\n            DEBUG_BUILD=false MAP_IMAGES_PATH=\"/Users/distiller/VAPOR-Data/images\" /Users/distiller/miniconda/bin/conda build .\n            mkdir -p /tmp/workspace/installers\n            mv /Users/distiller/miniconda/conda-bld/osx-64/*.tar.bz2 /tmp/workspace/installers\n            cd /tmp/workspace/installers\n            fileName=${ls}\n            newFileName=${fileName//vapor/vaporUbuntu}\n          no_output_timeout: 30m\n\n      - store_artifacts:\n          path: /tmp/workspace/installers\n\n  suse_smoke_tests:\n    docker:\n      - image: opensuse/leap\n    resource_class: medium\n    steps:\n      - suse_prerequisites\n      - attach_workspace:\n          at: /\n      - smoke_tests\n\n  build_linux_installer:\n    docker:\n      - image: ubuntu:20.04\n\n    resource_class: xlarge\n\n    steps:\n      - checkout\n\n      - run:\n          name: acquire prerequisites\n          command: |\n            export DEBIAN_FRONTEND=noninteractive\n            apt update\n            apt install -y libffi-dev\n            apt install -y curl\n            apt install -y xz-utils\n            apt install -y git\n            apt install -y g++\n            apt install -y libomp-dev\n            apt install -y freeglut3-dev\n            apt install -y libexpat1-dev\n            apt install -y libglib2.0-0\n            apt install -y libdbus-1-3\n            apt install -y valgrind\n            apt install -y clang-tidy\n            apt install -y lsb-release\n            apt install -y python3-pip\n            pip3 install gdown\n            git config --global --add safe.directory /tmp/_circleci_local_build_repo\n\n            # all for cmake\n            apt-get update\n            apt-get install -y gpg wget\n            wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb\n            dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb\n            wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null\n            echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null\n            DEBIAN_FRONTEND=noninteractive apt install -y software-properties-common\n            apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ focal main'\n            apt install -y cmake --allow-unauthenticated\n     \n            # for AppImage\n            apt install -y \\\n                libxcb-icccm4-dev \\\n                libxcb-image0 \\\n                libxcb-keysyms1 \\\n                libxcb-render-util0 \\\n                libxkbcommon-x11-0 \\\n                desktop-file-utils\n      - restore_cache:\n          name: restore intel's oneapi\n          keys:\n            - intelOneapi\n      - run:\n          name: acquire intel hpckit for bundling ospray\n          command: |\n            # if not restored from cache, acquire oneapi\n            if [ ! -d /opt/intel/oneapi ]; then\n              # For bundling Ospray, which wants Intel's MPI implementation to be bundled\n              apt install -y linux-headers-5.15.0-1053-aws\n              wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null\n              echo \"deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main\" | tee /etc/apt/sources.list.d/oneAPI.list\n              apt update\n              apt install -y intel-hpckit\n            fi\n      - save_cache:\n          key: intelOneapi\n          paths:\n            - /opt/intel/oneapi\n\n      - get_libraries:\n          fileName: *u20Libs\n      - build_vapor:\n          moveToCommand: ${f/Linux/Ubuntu20}\n          compileArgs: |\n            -DDIST_APPIMAGE=ON \\\n            -DBUILD_TEST_APPS=ON \\\n      - smoke_tests\n\n  release_weekly_installers:\n    macos:\n      xcode: \"14.3.1\"\n    steps:\n      - checkout\n      - *attach_workspace\n      - run:\n          name: publish release\n          command: |\n            cd /Users/distiller/project\n            hash=`git rev-parse HEAD`\n            tag=\"Weekly\"\n            cd /tmp/workspace/installers\n            brew install ghr\n            brew install gh\n\n            current_date=$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")\n            release_date=$(gh api -H \"Accept: application/vnd.github+json\" -H \"X-GitHub-Api-Version: 2022-11-28\" /repos/NCAR/VAPOR/releases/latest --jq \".published_at\")\n            current_date_sec=$(date -jf \"%Y-%m-%dT%H:%M:%SZ\" \"$current_date\" +\"%s\")\n            release_date_sec=$(date -jf \"%Y-%m-%dT%H:%M:%SZ\" \"$release_date\" +\"%s\")\n            weeks_since_release=$(( ($current_date_sec - $release_date_sec) / 604800 ))\n            for installer in VAPOR*3*; do\n              extension=\"${installer##*.}\"\n              new_name=\"${installer%.*}-w$weeks_since_release.$extension\"\n              mv \"$installer\" \"$new_name\"\n            done\n\n            endl=$'\\n'\n            title=\"sha 256\"$endl\n            a=\"AppImage:  \"\n            sha=`shasum -a 256 VAPOR*.AppImage`\n            linuxSha=$a$sha$endl\n            os=\"OSX:       \"\n            sha=`shasum -a 256 VAPOR*x86*.dmg`\n            osxSha=$os$sha$endl\n            os=\"AppleSilicon:       \"\n            sha=`shasum -a 256 VAPOR*AppleSilicon*.dmg`\n            siliconSha=$os$sha$endl\n            os=\"Windows:   \"\n            sha=`shasum -a 256 VAPOR*.exe`\n            winSha=$os$sha$endl\n            shaMessage=\"$title$linuxSha$osxSha$siliconSha$winSha\"\n            date=`date +\"%d_%m_%y\"`\n            echo \"$shaMessage\"\n            echo \"$shaMessage\" > \"/tmp/workspace/installers/sha256.txt\" \n            echo ghr -b \"Weekly installers are untested an may not be stable.  Built with commit ${hash} on ${date} \\(DD-MM-YY\\)\" -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -prerelease -c ${CIRCLE_SHA1} -recreate -c ${hash} -n ${tag} ${tag} /tmp/workspace/installers\n            ghr -b \"Weekly installers are untested an may not be stable.  Built with commit ${hash} on ${date} \\(DD-MM-YY\\)\" -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -prerelease -c ${CIRCLE_SHA1} -recreate -c ${hash} -n ${tag} ${tag} /tmp/workspace/installers\n\n\n  build_ubuntu20_libs:\n    docker:\n      - image: ubuntu:20.04\n\n    resource_class: xlarge\n\n    steps:\n      - run:\n          name: acquire prerequisites\n          command: |\n            DEBIAN_FRONTEND=noninteractive\n            apt update\n            apt install -y xz-utils git curl libomp-dev\n            git config --global --add safe.directory /tmp/_circleci_local_build_repo\n\n      - checkout\n\n      - get_libraries:\n          fileName: 2023-Sept-src.tar.xz\n          #driveID: *srcLibID\n\n      - run:\n          name: build libraries\n          command: |\n            chmod 777 /root/project/scripts/build3rdParty.sh\n            /root/project/scripts/build3rdParty.sh -o Ubuntu\n          no_output_timeout: 60m\n\n      - build_vapor:\n          moveToCommand: ${f/Linux/Ubuntu20}\n\n      - store_artifacts:\n          path: /tmp/workspace/installers\n      \n      - store_artifacts:\n          path: /usr/local/VAPOR-Deps/2023-Sept-Ubuntu.tar.xz\n\n  build_macOSx86_libs:\n    macos:\n      xcode: \"13.4.1\"\n\n    resource_class: macos.x86.medium.gen2\n\n    steps:\n      - checkout\n\n      - run:\n          name: Get MacPorts\n          command: |\n            curl -k -O https://distfiles.macports.org/MacPorts/MacPorts-2.7.1.tar.bz2\n            tar xf MacPorts-2.7.1.tar.bz2\n            cd MacPorts-2.7.1/\n            ./configure\n            make -j6\n            sudo make install\n\n      - run:\n          name: Get clang13\n          command: |\n            sudo /opt/local/bin/port selfupdate\n            (sudo yes || true) | sudo /opt/local/bin/port install clang-13\n            sudo /opt/local/bin/port select --set clang mp-clang-13\n            /opt/local/bin/clang++ -v > clangVersion.txt\n          no_output_timeout: 30m\n\n      - get_libraries:\n          fileName: *srcLibs\n          sudo: sudo\n\n      - run:\n          name: build libraries\n          command: |\n            chmod 777 /Users/distiller/project/scripts/build3rdParty.sh\n            /Users/distiller/project/scripts/build3rdParty.sh -o macOSx86\n\n      - build_vapor:\n          beforeCompile: export PATH=/opt/local/bin:$PATH; softwareupdate --install-rosetta --agree-to-license; sudo port select --set clang mp-clang-13\n          compileArgs: |\n            -DCPACK_BINARY_DRAGNDROP=ON \\\n            -DCMAKE_CXX_COMPILER=clang++ \\\n            -DCMAKE_C_COMPILER=clang \\\n            -DMACOS_BUILD_ARM64=OFF \\\n            -DCMAKE_OSX_ARCHITECTURES=x86_64 \\\n          moveToCommand: ${f/Darwin/macOSx86}\n\n      - store_artifacts:\n          path: /tmp/workspace/installers\n      \n      - store_artifacts:\n          path: /usr/local/VAPOR-Deps\n\n  build_AppleSilicon_libs:\n    macos:\n      xcode: \"13.4.1\"\n\n    resource_class: macos.m1.large.gen1\n\n    steps:\n      - checkout\n\n      - get_libraries:\n          driveID: *srcLibs\n          sudo: sudo\n\n      - run:\n          name: Get MacPorts\n          command: |\n            curl -k -O https://distfiles.macports.org/MacPorts/MacPorts-2.7.1.tar.bz2\n            tar xf MacPorts-2.7.1.tar.bz2\n            cd MacPorts-2.7.1/\n            ./configure\n            make -j8\n            sudo make install\n\n      - run:\n          name: Get clang13\n          command: |\n            sudo /opt/local/bin/port selfupdate\n            (sudo yes || true) | sudo /opt/local/bin/port install clang-13\n            sudo /opt/local/bin/port select --set clang mp-clang-13\n            /opt/local/bin/clang++ -v > clangVersion.txt\n          no_output_timeout: 30m\n\n      - run:\n          name: build libraries\n          command: |\n            chmod 777 /Users/distiller/project/scripts/build3rdParty.sh\n            /Users/distiller/project/scripts/build3rdParty.sh -o appleSilicon\n\n      - build_vapor:\n          beforeCompile: export PATH=/opt/local/bin:$PATH\n          compileArgs: |\n            -DCPACK_BINARY_DRAGNDROP=ON \\\n            -DCMAKE_CXX_COMPILER=clang++ \\\n            -DCMAKE_C_COMPILER=clang \\\n          moveToCommand: ${f/Darwin/AppleSilicon}\n\n      - store_artifacts:\n          path: /tmp/workspace/installers\n      \n      - store_artifacts:\n          path: /usr/local/VAPOR-Deps\n\n  build_win10_libs:\n    executor: win/default\n    steps:\n      - checkout\n      - run:\n          name: get source files\n          command: |\n            gdown https://drive.google.com/uc?id=1FG8ngmz9Tk3HKZgGejqwtbkBAVonm91z\n            tar xvf ${filename} -C /usr/local/VAPOR-Deps\n            msbuild -version\n      - run:\n          name: build libraries\n          command: |\n            chmod 777 /root/project/scripts/build3rdParty.sh\n            /root/project/scripts/build3rdParty.sh -o Windows\n\n      - store_artifacts:\n          path: C:\\Users\\circleci\\project\\tmp\\workspace\\installers\n\nworkflows:\n  version: 2\n  build:\n    jobs:\n      #- build_python_api_ubuntuDebug\n      #- build_python_api_ubuntu\n      #- build_python_api_osx\n      - build_win10_installer\n      # - build_macOS_installers\n      # - build_appleSilicon_installer\n      # - build_macOSx86_installer\n      - build_linux_installer\n      #- build_suse_installer\n      #- build_ubuntu20_libs\n      # - build_macOSx86_libs\n      #- build_AppleSilicon_libs\n      #- build_suse_libs\n      # - build_windows_libs\n      # - release_weekly_installers\n      # - release_weekly_installers:\n      #    requires:\n      #      - build_win10_installer\n      #      - build_appleSilicon_installer\n      #      - build_macOSx86_installer\n      #      - build_linux_installer\n  weekly:\n      triggers:\n        - schedule:\n             cron: \"30 17 * * 1\" #Time is GMT\n             filters:\n               branches:\n                 only: main\n      jobs:\n        - build_linux_installer\n        - build_appleSilicon_installer\n        - build_macOSx86_installer\n        - build_win10_installer\n        #- build_macOS_installers\n        #- build_python_api_ubuntu\n        #- build_python_api_osx\n        - release_weekly_installers:\n            requires:\n              - build_linux_installer\n              - build_appleSilicon_installer\n              - build_macOSx86_installer\n              - build_win10_installer\n              #- build_macOS_installers\n              #- build_python_api_ubuntu\n              #- build_python_api_osx\n"
  },
  {
    "path": ".circleci/downloadWin3rdParty.py",
    "content": "import gdown \nurl = \"https://drive.google.com/a/ucar.edu/uc?id=1fzZ-mbY4Cek1TRsaKm79a08Od5gNCogk\"\noutput = \"2019-Aug-Win32.zip\"\ngdown.download(url, output, quiet=False)\n\nimport zipfile\nwith zipfile.ZipFile(\"2019-Aug-Win32.zip\", 'r') as zip_ref:\n    zip_ref.extractall('C:\\\\')\n"
  },
  {
    "path": ".clang-format",
    "content": "---\nLanguage:        Cpp\n# BasedOnStyle:  LLVM\nAccessModifierOffset: -4\nAlignAfterOpenBracket: Align\nAlignConsecutiveAssignments: false\nAlignConsecutiveBitFields: true\nAlignConsecutiveDeclarations: true\nAlignConsecutiveMacros: true\nAlignEscapedNewlines: Left\nAlignOperands: AlignAfterOperator\nAlignTrailingComments: true\nAllowAllArgumentsOnNextLine: true\nAllowAllConstructorInitializersOnNextLine: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: Always\nAllowShortCaseLabelsOnASingleLine: true\nAllowShortEnumsOnASingleLine: true\nAllowShortFunctionsOnASingleLine: All\nAllowShortIfStatementsOnASingleLine: WithoutElse\nAllowShortLambdasOnASingleLine: All\nAllowShortLoopsOnASingleLine: true\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: false\nAlwaysBreakTemplateDeclarations: MultiLine\nBinPackArguments: true\nBinPackParameters: true\nBreakBeforeBinaryOperators: NonAssignment\nBreakBeforeBraces: WebKit\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializers: BeforeColon\nBreakInheritanceList: BeforeColon\nBreakStringLiterals: false\nColumnLimit:     200\nCommentPragmas:  '^ IWYU pragma:'\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: false\nConstructorInitializerIndentWidth: 0\nContinuationIndentWidth: 4\nCpp11BracedListStyle: true\nDeriveLineEnding: true\nDerivePointerAlignment: false\nDisableFormat:   false\nFixNamespaceComments: true\nForEachMacros:\n  - foreach\n  - Q_FOREACH\n  - BOOST_FOREACH\nIncludeBlocks:   Preserve\nIndentCaseBlocks: false\nIndentCaseLabels: false\nIndentExternBlock: NoIndent\nIndentGotoLabels: true\nIndentPPDirectives: BeforeHash\nIndentWidth: 4\nIndentWrappedFunctionNames: false\nKeepEmptyLinesAtTheStartOfBlocks: false\nMaxEmptyLinesToKeep: 3\nNamespaceIndentation: None\nPointerAlignment: Right\nReflowComments:  true\nSortIncludes:    false\nSortUsingDeclarations: true\nSpaceAfterCStyleCast: false\nSpaceAfterLogicalNot: false\nSpaceAfterTemplateKeyword: false\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeCpp11BracedList: false\nSpaceBeforeCtorInitializerColon: true\nSpaceBeforeInheritanceColon: true\nSpaceBeforeParens: ControlStatements\nSpaceBeforeRangeBasedForLoopColon: true\nSpaceBeforeSquareBrackets: false\nSpaceInEmptyBlock: false\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 4\nSpacesInAngles:  false\nSpacesInCStyleCastParentheses: false\nSpacesInConditionalStatement: false\nSpacesInContainerLiterals: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nStandard:        Latest\nStatementMacros:\n  - Q_UNUSED\n  - QT_REQUIRE_VERSION\nTabWidth: 4\nUseCRLF: false\nUseTab: Never\n...\n"
  },
  {
    "path": ".editorconfig",
    "content": "[*.{c,cpp,h,pl,frag,vert}]\nindent_style = tab\nindent_size = 4\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a bug report\ntitle: ''\nlabels: Bug\nassignees: ''\n\n---\n\n### Describe the bug\nA clear and concise description of what the bug is.\n\n**Helpful additional information**\n(*Please click check boxes AFTER submitting ticket*)\n- [ ] Did VAPOR crash?\n- [ ] Did you get wrong results?\n\n**Impact**\n- [ ] High - User productivity significantly degraded\n- [ ] Medium - User productivity partially degraded\n- [ ] Low - User productivity trivially degraded\n\n### To Reproduce\nSteps to reproduce the behavior. For example:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n*Additionally, please attach a session file to this ticket to easily reproduce (use File->Save Session).*\n\n### Expected behavior\nA clear and concise description of what you expected to happen.\n\n### Attachments\n* Can you reproduce the bug on our test data?\n  * If so, which file?\n  * If not, access to your data would be very helpful. If the data set is small, please zip and upload it as an attachment. If it is large, please provide instructions for how we can contact you to obtain this data.\n* Please attach a session file to easily reproduce (use File->Save Session).\n* Please attach any screenshots relevant to understanding the issue.\n\n### Desktop\n - OS and version: [e.g. Ubuntu 18.04]\n - Version: [e.g. Vapor 3.1]\n\n### Additional context\nAdd any other context about the problem here. Attach any (zipped) relevant files, such as data, configurations, session files, etc.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/documentation-request.md",
    "content": "---\nname: Documentation Request\nabout: Submit a request fo Documentation on VAPOR\ntitle: ''\nlabels: Documentation\nassignees: ''\n\n---\n\n### Describe what needs to be documented.\nA clear and concise description of what you would like to see.\n\n### Is the documentation missing?\nIf so, please describe where have you looked for the documentation and where you expect to see it.\n\n### Is the documentation there but needs improvement?\n\n*Please provide the url of the documentation.*\n\n\n\n### Additional context\nAdd any other context or screenshots about the desired documentation.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/enhancement-request.md",
    "content": "---\nname: Enhancement request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: Enhancement\nassignees: ''\n\n---\n\n### Is your feature request related to a problem?\nA clear and concise description of the problem. E.g. I'm always frustrated when [...]\n\n### Describe the solution you'd like.\nA clear and concise description of what you want to happen.\n\n**Impact**\n(*Please click check boxes AFTER submitting ticket*)\n- [ ] High - User productivity significantly improved\n- [ ] Medium - User productivity partially improved\n- [ ] Low - User productivity trivially improved\n\n### Is your feature request specific to a data set?\nCan you use one of our example data sets to demonstrate the desired feature?\n* Please provide a data set.  If the data set is small, please zip and upload it as an attachment. If it is large, please provide instructions on how we can contact you to obtain this data.\n\n### Additional context\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Trigger Documentation Update\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n\njobs:\n  trigger-doc-update:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - name: Checkout VAPOR repo\n        uses: actions/checkout@v4\n\n      - name: Trigger documentation update\n        run: |\n          curl -X POST -H \"Authorization: token ${{ secrets.GH_TOKEN }}\" \\\n          -H \"Accept: application/vnd.github.v3+json\" \\\n          https://api.github.com/repos/NCAR/VaporDocumentationWebsite/dispatches \\\n          -d '{\"event_type\":\"update-docs\"}'"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\napps/vaporgui/guis/ui/*.h\napps/vaporgui/moc/\nlib/idl/IDLMetadataAuto.cpp\nlib/render/moc/\nshare/doc/Doxygen/Doxyfile\nsite.mk\ntargets/\n.ycm_extra_conf.py\nmake/Darwin/VaporXcode/vaporXcode.xcodeproj/project.xcworkspace/\nmake/Darwin/VaporXcode/vaporXcode.xcodeproj/xcuserdata/\nplugins/visit/CMakeCache.txt\nplugins/visit/CMakeFiles/\nplugins/visit/CMakeLists.txt\nplugins/visit/Makefile\nplugins/visit/WASP/CMakeCache.txt\nplugins/visit/WASP/CMakeFiles/\nplugins/visit/WASP/CMakeLists.txt\nplugins/visit/WASP/Makefile\nplugins/visit/WASP/WASP.xml.bak\nplugins/visit/WASP/cmake_install.cmake\nplugins/visit/vdf.xml.bak\nplugins/visit/VDC/CMake*\nshare/fonts/Pacifico.ttf\n__pycache__\n.idea\n\ntags\n\n# CMake\nMakefile\ncmake_install.cmake\nCmakeFiles\nCMakeCache.txt\n/site.local\nbin\n/build\n/build-release\n/cmake-build-*\n/xcode\n/apps/vaporgui/ui/\n/buildutils/LinuxInstallLibs.txt\n\n\n# vim swap files\n*.swp\n*.swo\n\n# object files\n*.o\n*.out*\n"
  },
  {
    "path": ".readthedocs.yml",
    "content": "# .readthedocs.yml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details\n\n# Required\nversion: 2\n\n# Build documentation in the docs/ directory with Sphinx\nsphinx:\n  configuration: docs/conf.py\n\n# Build documentation with MkDocs\n#mkdocs:\n#  configuration: mkdocs.yml\n\n# Optionally build your docs in additional formats such as PDF\nformats:\n  - pdf\n\n# Optionally set the version of Python and requirements required to build your docs\npython:\n  version: 3.7\n#  install:\n#    - requirements: docs/requirements.txt\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "# Note on building VDC only:\n# These packages from Ubuntu repo are required to build VAPOR with only VDC enabled:\n# (tested on Ubuntu 18.04)\n# \n# libnetcdf-dev,  libudunits2-dev,  libproj-dev\n\ncmake_minimum_required (VERSION 3.17)\nproject (VAPOR3)\n\ninclude (buildutils/UtilityFunctions.cmake)\ninclude (buildutils/GetGitRevisionDescription.cmake)\ninclude (buildutils/OpenMPInstaller.cmake)\n\nset (CMAKE_CXX_STANDARD 17)\nset (CMAKE_EXPORT_COMPILE_COMMANDS ON)\n\nif(NOT CMAKE_BUILD_TYPE)\n\tset(CMAKE_BUILD_TYPE \"Debug\" CACHE STRING \"Choose the type of build.\" FORCE)\n\t# Set the possible values of build type for cmake-gui\n\tset_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS \"DEBUG\" \"RELEASE\" \"RELWITHDEBINFO\")\nendif()\n\nif(APPLE)\n    if(\"${CMAKE_OSX_ARCHITECTURES}\" STREQUAL \"\")\n        # Check if the target architecture is arm64\n        include(CheckCXXSourceRuns)\n        set(CMAKE_REQUIRED_FLAGS \"-arch arm64\")\n        set(CHECK_ARM64_SOURCE_CODE \"int main() { return 0; }\")\n        check_cxx_source_runs(\"${CHECK_ARM64_SOURCE_CODE}\" IS_ARM64)\n        if(IS_ARM64)\n            set(CMAKE_OSX_ARCHITECTURES arm64)\n        else()\n            set(CMAKE_OSX_ARCHITECTURES x86_64)\n        endif()\n    endif()\n\n    set(CMAKE_OSX_DEPLOYMENT_TARGET \"12.0\" CACHE STRING \"Minimum OS X deployment version\" FORCE)\n    if (CMAKE_OSX_ARCHITECTURES MATCHES \"arm64\")\n        message(\"Building on macOS M1 architecture (arm64)\")\n    else()\n        message(\"Building on macOS x86 architecture\")\n        set(CMAKE_OSX_ARCHITECTURES \"x86_64\" CACHE STRING \"macOS build architecture\" FORCE)\n    endif()\nendif()\n\nset (VERSION_MAJOR 3)\nset (VERSION_MINOR 11)\nset (VERSION_MICRO 0)\nset (VERSION_RC )\nmessage(\"CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}\")\nif (CMAKE_BUILD_TYPE STREQUAL \"Release\")\n\tget_git_head_revision (GIT_REFSPEC VERSION_COMMIT)\n    message(\"VERSION_COMMIT ${VERSION_COMMIT}\")\n\texecute_process (\n\t\tCOMMAND git rev-parse --short ${VERSION_COMMIT}\n\t\tWORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n\t\tOUTPUT_VARIABLE VERSION_COMMIT \n\t\tOUTPUT_STRIP_TRAILING_WHITESPACE\n\t)\n    message(\"VERSION_COMMIT2 ${VERSION_COMMIT}\")\nendif ()\nstring (TIMESTAMP VERSION_DATE UTC)\nif (VERSION_RC)\n\tset (VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}.${VERSION_RC})\nelse ()\n\tset (VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO})\nendif ()\nset (VERSION_STRING_FULL ${VERSION_STRING}.${VERSION_COMMIT})\n\nif (APPLE)\n\tadd_definitions (-DDarwin)\nelseif (WIN32)\n    add_definitions (-DWIN32 -DNOMINMAX)\n    add_definitions (-DGLAD_API_CALL_EXPORT)\n    add_compile_definitions(_HAS_STD_BYTE=0)\nendif()\n\n# compiler warning flags\nif (NOT WIN32)\n  SET (CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wall -Wno-sign-compare -Wno-overloaded-virtual -Wno-parentheses\")\n  SET (CMAKE_C_FLAGS   \"${CMAKE_C_FLAGS} -Wall -Wno-sign-compare\")\nelse ()\n  # Enable multithread compiling on Visual Studio\n  # This feature is glitchy so you may need to re-run\n  SET (CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} /MP\")\n  SET (CMAKE_C_FLAGS   \"${CMAKE_C_FLAGS} /MP\")\nendif()\n\nif (CMAKE_GENERATOR STREQUAL \"Xcode\")\n\tset (DEFAULT_BUILD_UTILITIES OFF)\nelse ()\n\tset (DEFAULT_BUILD_UTILITIES ON)\nendif ()\n\noption (BUILD_VDC \"Build VDC library and utilities\" ON)\noption (BUILD_GUI \"Build Vapor GUI\" ON)\noption (BUILD_PYTHON \"Build Vapor Python Library\" OFF)\noption (BUILD_OSP \"Build OSPRay\" ON)\noption (BUILD_UTL \"Build conversion and utility applications\" ${DEFAULT_BUILD_UTILITIES})\noption (BUILD_DOC \"Build Vapor Doxygen documentation\" ON)\noption (BUILD_TEST_APPS \"Build test applications\" OFF)\noption (DIST_INSTALLER \"Generate installer for distributing vapor binaries. Will generate standard make install if off\" OFF)\noption (USE_OMP \"Use OpenMP on some calculations\" OFF)\noption (CONDA_BUILD \"Use Conda to build\" OFF)\nif (UNIX AND NOT APPLE)\n    include (CMakeDependentOption)\n    cmake_dependent_option (DIST_APPIMAGE \"Generate an AppImage for VAPOR's installation across multiple Linux platforms\" OFF \"DIST_INSTALLER\" ON)\nendif (UNIX AND NOT APPLE)\n\nif( USE_OMP )\n    find_package(OpenMP REQUIRED)\n    if( OpenMP_CXX_FOUND AND OpenMP_CXX_FLAGS )\n        message(STATUS \"OpenMP found! (${OpenMP_CXX_LIB_NAMES})\")\n    else()\n        message(STATUS \"OpenMP NOT found! Are you using Apple Clang?\")\n    endif()\nendif()\n\nset (GENERATE_FULL_INSTALLER ON)\nif (BUILD_GUI)\n\tset (BUILD_VDC ON)\nendif ()\n\nset (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\nset (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\nset (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\n\nset (test_output_dir ${CMAKE_BINARY_DIR}/test_binaries)\nset (debug_output_dir ${CMAKE_BINARY_DIR}/debug_binaries)\n\nset (QTDIR )\nset (OSPRAYDIR )\nset (PYTHONDIR )\nset (PYTHONVERSION )\nset (PYTHONPATH )\nset (NUMPY_INCLUDE_DIR )\nset (THIRD_PARTY_DIR )\nset (THIRD_PARTY_LIB_DIR )\nset (THIRD_PARTY_INC_DIR )\nset (MAP_IMAGES_PATH )\n\ninclude (site_files/site.NCAR OPTIONAL)\ninclude (site.local           OPTIONAL)\n\nif (CONDA_BUILD)\n    unset (QTDIR)\n    unset (OSPRAYDIR)\n    unset (PYTHONDIR)\n    unset (PYTHONVERSION)\n    unset (PYTHONPATH)\n    unset (NUMPY_INCLUDE_DIR)\n    unset (THIRD_PARTY_DIR)\n    unset (THIRD_PARTY_LIB_DIR)\n    unset (THIRD_PARTY_INC_DIR)\n    if (DEFINED ENV{MAP_IMAGES_PATH})\n        set (MAP_IMAGES_PATH $ENV{MAP_IMAGES_PATH})\n    endif()\nelse()\n    message(\"THIRD_PARTY_DIR = ${THIRD_PARTY_DIR}\")\n    include_directories (SYSTEM ${THIRD_PARTY_INC_DIR})\n    include_directories (SYSTEM ${THIRD_PARTY_INC_DIR}/freetype2)\n    link_directories (${THIRD_PARTY_LIB_DIR})\n    link_directories (${PYTHONPATH})\n\n    list (APPEND CMAKE_PREFIX_PATH ${THIRD_PARTY_LIB_DIR})\n    list (APPEND CMAKE_PREFIX_PATH ${THIRD_PARTY_DIR})\n    list (APPEND CMAKE_PREFIX_PATH ${THIRD_PARTY_DIR}/HDF_Group/HDF5/1.12.2/lib)\n\n    if (APPLE)\n        set(CMAKE_MODULE_PATH /opt/local/lib/libomp)\n    endif()\nendif()\n\ninclude_directories (\"${PROJECT_SOURCE_DIR}/lib/osgl/include\")\ninclude_directories (\"${PROJECT_SOURCE_DIR}/lib/osgl/glad/include\")\n\nif (WIN32)\n\tget_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)\nendif ()\nif (BUILD_VDC AND EXISTS ${PYTHONPATH}/lib-dynload)\n\tlink_directories (${PYTHONPATH}/lib-dynload)\nendif ()\n\nfind_library(NETCDF netcdf)\nfind_library(UDUNITS2 udunits2)\nfind_library(FREETYPE freetype)\nfind_library(GEOTIFF geotiff)\nfind_library(JPEG jpeg)\nfind_library(HDF5_LIB hdf5)\nfind_library(EXPAT expat)\n\nmessage(\"Library NETCDF   = ${NETCDF}\")\nmessage(\"Library UDUNITS2 = ${UDUNITS2}\")\nmessage(\"Library FREETYPE = ${FREETYPE}\")\nmessage(\"Library GEOTIFF  = ${GEOTIFF}\")\nmessage(\"Library JPEG     = ${JPEG}\")\nmessage(\"Library HDF5_LIB = ${HDF5_LIB}\")\nmessage(\"Library EXPAT = ${EXPAT}\")\n\n# find_package(Python)\n#   Output\n#       ${Python_VERSION}\n#       ${Python_LIBRARIES}\n#       ${Python_INCLUDE_DIRS}\n#       ${Python_SITELIB}\n#       ${Python_NumPy_VERSION}\n#       ${Python_NumPy_INCLUDE_DIRS}\n#   https://cmake.org/cmake/help/v3.12/module/FindPython.html\n\nfunction(FIND_BUNDLED_PYTHON)\n    # FindPython supports Python_ROOT_DIR however vapor's bundled python distribution\n    # does not conform to its requirements so this manually configures the results\n    message(\"Using bundled python\")\n    message(\"    PYTHONDIR ${PYTHONDIR}\")\n    message(\"    PYTHONPATH ${PYTHONPATH}\")\n    set(Python_VERSION \"${PYTHONVERSION}\")\n    set(Python_NumPy_INCLUDE_DIRS \"${NUMPY_INCLUDE_DIR}\")\n    unset(Python_LIBRARIES) # This is required for find_library to work in certain cases\n    if (APPLE)\n        set(PYTHON_LIB_DIR \"${PYTHONDIR}/lib\")\n    else()\n        set(PYTHON_LIB_DIR \"${PYTHONPATH}\")\n    endif()\n    message(\"    PYTHON_LIB_DIR ${PYTHON_LIB_DIR}\")\n    find_library(\n        Python_LIBRARIES\n        NAMES python${PYTHONVERSION} python${PYTHONVERSION}m\n        PATHS ${THIRD_PARTY_LIB_DIR} ${PYTHON_LIB_DIR}\n        NO_DEFAULT_PATH\n    )\n\n    if (WIN32)\n        set(Python_SITELIB \"${PYTHONPATH}/Lib/site-packages\")\n    \tset(Python_INCLUDE_DIRS \"${THIRD_PARTY_DIR}/Python${PYTHONVERSION}/include\")\n    else()\n        set(Python_SITELIB \"${PYTHONPATH}/site-packages\")\n        if (NOT DEFINED Python_INCLUDE_DIRS)\n            if (APPLE)\n                set(Python_INCLUDE_DIRS \"${PYTHONDIR}/include/python${PYTHONVERSION}\")\n            else()\n                set(Python_INCLUDE_DIRS \"${THIRD_PARTY_INC_DIR}/python${PYTHONVERSION}\")\n            endif()\n        endif()\n    endif()\n\n    set(Python_VERSION \"${Python_VERSION}\" PARENT_SCOPE)\n    set(Python_LIBRARIES \"${Python_LIBRARIES}\" PARENT_SCOPE)\n    set(Python_INCLUDE_DIRS \"${Python_INCLUDE_DIRS}\" PARENT_SCOPE)\n    set(Python_SITELIB \"${Python_SITELIB}\" PARENT_SCOPE)\n    set(Python_NumPy_VERSION \"UNUSED IN BUNDLED PYTHON\" PARENT_SCOPE)\n    set(Python_NumPy_INCLUDE_DIRS \"${Python_NumPy_INCLUDE_DIRS}\" PARENT_SCOPE)\nendfunction()\n\nfunction(DUMP_FOUND_PYTHON)\n    set(PATHS \"\")\n    list(APPEND PATHS\n        Python_LIBRARIES\n        Python_INCLUDE_DIRS\n        Python_SITELIB\n        Python_NumPy_INCLUDE_DIRS\n    )\n    message(\"Python Found ${ARGV0}\")\n    message(\"\\tPython_VERSION = '${Python_VERSION}'\")\n    message(\"\\tPython_NumPy_VERSION = '${Python_NumPy_VERSION}'\")\n    foreach(V ${PATHS})\n        if (EXISTS \"${${V}}\")\n            set(VE \"OK\")\n        else()\n            set(VE \"**NOT FOUND**\")\n        endif()\n        message(\"\\t${V} = '${${V}}' ${VE}\")\n    endforeach()\nendfunction()\n\n# TODO\n# - Replace PYTHONVERSION with Python_VERSION\n\nif (BUILD_PYTHON)\n    find_package(Python COMPONENTS Interpreter Development NumPy)\n    # find_library (GETTEXT intl)\nelse()\n    find_bundled_python()\nendif()\ndump_found_python()\n\ninclude_directories (\"${Python_INCLUDE_DIRS}\")\ninclude_directories (\"${Python_NumPy_INCLUDE_DIRS}\")\n\n\n# if (BUILD_GUI OR BUILD_PYTHON)\n# \tfind_package (OpenGL REQUIRED)\n# \tinclude_directories (${OPENGL_INCLUDE_DIRS})\n# endif ()\n\nif (WIN32)\n\tfind_library(ASSIMP assimp-vc140-mt)\n    find_library(TIFF libtiff)\n    find_library(PROJ proj_6_1)\nelse ()\n\tfind_library(ASSIMP assimp)\n    find_library(TIFF tiff)\n    find_library(PROJ proj)\nendif()\n\nif (WIN32)\n\tset (INSTALL_BIN_DIR .)\n\tset (INSTALL_LIB_DIR .)\n\tset (INSTALL_SHARE_DIR share)\n\tset (INSTALL_INCLUDE_DIR include/vapor)\nelseif (APPLE)\n\n\t# if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)\n    if (DIST_INSTALLER AND NOT BUILD_PYTHON)\n\t\tset (CMAKE_INSTALL_PREFIX /Applications)\n\t\tset (INSTALL_BIN_DIR ./vapor.app/Contents/MacOS)\n\t\tset (INSTALL_SHARE_DIR ./vapor.app/Contents/share)\n\t\tset (INSTALL_INCLUDE_DIR ./vapor.app/Contents/include/vapor)\n\t\tset (INSTALL_LIB_DIR ./vapor.app/Contents/Frameworks)\n\telse ()\n\t\tset (INSTALL_BIN_DIR bin)\n\t\tset (INSTALL_LIB_DIR lib)\n\t\tset (INSTALL_SHARE_DIR share)\n\t\tset (INSTALL_INCLUDE_DIR include/vapor)\n\tendif ()\n\n    if (BUILD_PYTHON)\n        set (CMAKE_INSTALL_RPATH \"@loader_path\")\n    else()\n        set (CMAKE_INSTALL_RPATH \"@executable_path/../Frameworks;@executable_path/../Resources/lib\")\n    endif ()\n\n    if (DIST_INSTALLER AND USE_OMP)\n\t\tmessage (WARNING \"The build mode is set to distributable installer with OpenMP enabled and will not run from source\")\n\t\tset (INSTALL_NAME_DIR \"${CMAKE_INSTALL_PREFIX}/lib\")\n\t\tset (CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)\n\t\tset (CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)\n\t\tset (CMAKE_SKIP_BUILD_RPATH FALSE)\n\tendif()\nelse ()\n\tif (DIST_INSTALLER)\n\t\tset (INSTALL_BIN_DIR lib)\n\telse ()\n\t\tset (CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)\n\t\tset (CMAKE_INSTALL_RPATH \"${CMAKE_INSTALL_PREFIX}/lib\")\n\t\tset (INSTALL_BIN_DIR bin)\n\tendif ()\n\tset (INSTALL_LIB_DIR lib)\n\tset (INSTALL_INCLUDE_DIR include/vapor)\n\tset (INSTALL_LAUNCHER_DIR bin)\n\tset (INSTALL_SHARE_DIR share)\nendif ()\n\nadd_subdirectory (lib)\nadd_subdirectory (apps)\nadd_subdirectory (include)\nadd_subdirectory (share)\nadd_subdirectory (scripts)\nadd_subdirectory (test_apps)\n\n\n\n\n###############################################################################\n#                            CPack Installation                               #\n###############################################################################\n\nset (CPACK_PACKAGE_NAME ${PROJECT_NAME})\nset (CPACK_PACKAGE_VENDOR \"NCAR\")\nset (CPACK_PACKAGE_DESCRIPTION_SUMMARY \"VAPOR - DESCRIPTION\")\nset (CPACK_PACKAGE_VERSION ${VERSION_STRING})\nset (CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})\nset (CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})\nset (CPACK_PACKAGE_VERSION_PATCH ${VERSION_RC})\nset (CPACK_PACKAGE_INSTALL_DIRECTORY \"VAPOR\")\nset (CPACK_RESOURCE_FILE_LICENSE \"${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt\")\nset (CPACK_PACKAGE_EXECUTABLES vapor;vapor)\nset (CPACK_BINARY_STGZ OFF)\nset (CPACK_BINARY_TGZ OFF)\nset (CPACK_BINARY_TZ OFF)\nset (CPACK_BINARY_DRAGNDROP OFF)\n\nif (WIN32)\n\tset (PRE_INSTALL_LOCAL_PATH \"buildutils/NSIS.preInstall.ini\")\n\tset (PRE_INSTALL_PATH \"${CMAKE_CURRENT_BINARY_DIR}/${PRE_INSTALL_LOCAL_PATH}\")\n\tconfigure_file (\"${PRE_INSTALL_LOCAL_PATH}.in\" \"${PRE_INSTALL_PATH}\" @ONLY)\n\n\tset (PRE_UNINSTALL_LOCAL_PATH \"buildutils/NSIS.preUnInstall.ini\")\n\tset (PRE_UNINSTALL_PATH \"${CMAKE_CURRENT_BINARY_DIR}/${PRE_UNINSTALL_LOCAL_PATH}\")\n\tconfigure_file (\"${PRE_UNINSTALL_LOCAL_PATH}.in\" \"${PRE_UNINSTALL_PATH}\" @ONLY)\n\t\n\tif (GENERATE_FULL_INSTALLER)\n\t\tset (LIB_DIR ${THIRD_PARTY_DIR}/lib)\n\t\tfile (GLOB WIN_INSTALL_DLLS ${LIB_DIR}/*.dll ${QTDIR}/bin/*.dll ${OSPRAYDIR}/bin/*.dll)\n\n\t\tinstall (\n\t\t\tFILES ${WIN_INSTALL_DLLS}\n\t\t\tDESTINATION ${INSTALL_BIN_DIR}\n\t\t\tCOMPONENT Dependencies\n\t\t\t)\n\t\tinstall (\n\t\t\tFILES ${PYTHONPATH}/python${PYTHONVERSION}.dll\n\t\t\tDESTINATION ${INSTALL_BIN_DIR}\n\t\t\tCOMPONENT Dependencies\n\t\t\t)\n\t\tinstall (\n\t\t\tDIRECTORY ${PYTHONPATH}\n\t\t\tDESTINATION ${INSTALL_LIB_DIR}\n\t\t\tCOMPONENT Dependencies\n\t\t\t)\n\t\tinstall(FILES\n\t\t\t${QTDIR}/plugins/platforms/qwindows.dll\n\t\t\tDESTINATION platforms\n\t\t)\n\t\tinstall (\n\t\t\tDIRECTORY ${THIRD_PARTY_DIR}/share/plugins\n\t\t\tDESTINATION ${INSTALL_LIB_DIR}/share\n\t\t\tCOMPONENT Dependencies\n\t\t)\n\tendif (GENERATE_FULL_INSTALLER)\n\n\tset (CPACK_NSIS_MODIFY_PATH OFF)\n\tset (CPACK_NSIS_URL_INFO_ABOUT \"https://www.vapor.ucar.edu\")\n\tset (CPACK_NSIS_EXECUTABLES_DIRECTORY \".\") # Manually fixed in template file\n\tset (CPACK_NSIS_MUI_ICON \"${CMAKE_SOURCE_DIR}/share/images/vapor-win-icon.ico\")\n\tset (CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)\n\t\n\tset (CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS  \"${PRE_INSTALL_PATH}\")\n\tset (CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS  \"${PRE_UNINSTALL_PATH}\")\n\tstring (REGEX REPLACE \"/\" \"\\\\\\\\\" CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS  \"${CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS}\")\n\tstring (REGEX REPLACE \"/\" \"\\\\\\\\\" CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS  \"${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}\")\n\t\n\tset (CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION \".\")\n\tinclude (InstallRequiredSystemLibraries)\n\n\tset (CPACK_MODULE_PATH \"${CMAKE_SOURCE_DIR}/buildutils\")\nendif (WIN32)\n\nif (APPLE)\n\tset (CPACK_BINARY_DRAGNDROP ON)\n\tif (DIST_INSTALLER AND GENERATE_FULL_INSTALLER)\n\t\tfile (GLOB INSTALL_LIBS ${THIRD_PARTY_LIB_DIR}/*.dylib) \n\t\tinstall (\n\t\t\tFILES ${INSTALL_LIBS}\n\t\t\tDESTINATION ${INSTALL_LIB_DIR}\n\t\t\tCOMPONENT Dependencies\n\t\t\t)\n\n        set (FRAMEWORKS Core OpenGL Widgets Gui DBus Network PrintSupport)\n        foreach(item IN LISTS FRAMEWORKS)\n            list(APPEND FRAMEWORKS \"${THIRD_PARTY_LIB_DIR}/Qt${item}.framework\")\n            list(REMOVE_ITEM FRAMEWORKS ${item})\n        endforeach(item IN LISTS ${FRAMEWORKS})\n        install (\n            DIRECTORY ${FRAMEWORKS}\n            DESTINATION ${INSTALL_LIB_DIR}\n            COMPONENT Dependencies\n        )\n\n        if (BUILD_OSP)\n            file (GLOB INSTALL_OSP_LIBS ${OSPRAYDIR}/lib/*.dylib) \n            message (STATUS \"OSPRAYDIR ${OSPRAYDIR}\")\n\t\t    install (\n\t\t    \tFILES ${INSTALL_OSP_LIBS}\n\t\t    \tDESTINATION ${INSTALL_LIB_DIR}\n\t\t    \tCOMPONENT Dependencies\n\t\t    \t)\n        endif ()\n\n        if (NOT BUILD_PYTHON)\n                file (GLOB INSTALL_GUI_FRAMEWORKS ${PYTHONPATH})\n                set (PYTHON_DESTINATION \"${INSTALL_LIB_DIR}/../Resources/lib\")\n\t\t    install (\n                DIRECTORY ${INSTALL_GUI_FRAMEWORKS}\n                DESTINATION ${PYTHON_DESTINATION}\n                COMPONENT Dependencies\n                PATTERN \"bin\" EXCLUDE\n\t\t    \t)\n            install (\n\t\t    \tFILES ${Python_LIBRARIES}\n\t\t    \tDESTINATION ${PYTHON_DESTINATION}\n\t\t    \tCOMPONENT Dependencies\n\t\t    \t)\n            file (GLOB COCOA_LIBS ${THIRD_PARTY_DIR}/plugins/platforms/libqcocoa.dylib)\n\t        install (\n                FILES ${COCOA_LIBS}\n                DESTINATION ${INSTALL_BIN_DIR}/platforms\n                COMPONENT Dependencies\n                )\n            file (GLOB STYLE_LIBS ${THIRD_PARTY_DIR}/plugins/styles/libqmacstyle.dylib)\n\t        install (\n                FILES ${STYLE_LIBS}\n                DESTINATION ${INSTALL_BIN_DIR}/styles\n                COMPONENT Dependencies\n                )\n        endif ()\n\n        if (USE_OMP)\n            get_filename_component(OMP_PATH ${OpenMP_CXX_LIBRARIES} REALPATH)\n            install (\n                FILES ${OMP_PATH}\n                DESTINATION ${INSTALL_LIB_DIR}\n                COMPONENT Dependencies\n                )\n        endif ()\n        file (GLOB_RECURSE HDF5_PLUGINS \"${THIRD_PARTY_DIR}/share/plugins/*.so\")\n        message (STATUS \"plugins ${HDF5_PLUGINS}\")\n\t\tinstall (\n\t\t\tFILES ${HDF5_PLUGINS}\n\t\t\tDESTINATION \"${INSTALL_SHARE_DIR}/plugins\"\n\t\t\tCOMPONENT Dependencies\n\t\t\t)\n        file (GLOB HDF5_LIBS ${THIRD_PARTY_DIR}/HDF_Group/HDF5/1.12.2/lib/*.dylib) \n        install (\n            FILES ${HDF5_LIBS}\n            DESTINATION ${INSTALL_LIB_DIR}\n            COMPONENT Dependencies\n            )\n\n    endif ()\nendif (APPLE)\n\nif (UNIX AND NOT APPLE)\n\tset (CPACK_BINARY_STGZ ON)\n\tif (BUILD_VDC)\n\t\tset (EXTRA_LIBS_SEARCH ${EXTRA_LIBS_SEARCH} GLU glut expat omp)\n\tendif ()\n\tif (BUILD_GUI)\n\t\tset (EXTRA_LIBS_SEARCH ${EXTRA_LIBS_SEARCH} quadmath)\n\tendif ()\n\n\n\tif (DIST_INSTALLER)\n        set (PARSE_BINARY \"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/vapor\")\n        if (BUILD_PYTHON)\n            set (PARSE_BINARY \"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libvapi.so\")\n        endif()\n        message( STATUS \"${CMAKE_SOURCE_DIR}/buildutils/gen_linux_shared_libs.pl\n            ${PARSE_BINARY} ${EXTRA_LIBS_SEARCH} >\n            ${CMAKE_BINARY_DIR}/LinuxInstallLibs.txt\")\n\t\tadd_custom_target (\n\t\t\tlinuxpreinstall\n\t\t\tCOMMAND ${CMAKE_SOURCE_DIR}/buildutils/gen_linux_shared_libs.pl\n\t\t\t${PARSE_BINARY} ${EXTRA_LIBS_SEARCH} >\n\t\t\t${CMAKE_BINARY_DIR}/LinuxInstallLibs.txt\n\t\t\tCOMMAND touch ${CMAKE_SOURCE_DIR}/CMakeLists.txt\n\t\t\t)\n\tendif ()\n\tif (DIST_INSTALLER AND GENERATE_FULL_INSTALLER)\n\t\tif (EXISTS ${CMAKE_BINARY_DIR}/LinuxInstallLibs.txt)\n\t\t\tfile (STRINGS ${CMAKE_BINARY_DIR}/LinuxInstallLibs.txt INSTALL_LIBS)\n\t\tendif ()\n\n\t\tinstall (\n\t\t\tFILES ${INSTALL_LIBS}\n\t\t\tDESTINATION ${INSTALL_LIB_DIR}\n\t\t\tCOMPONENT Dependencies\n\t\t\t)\n\n        if (NOT BUILD_PYTHON)\n\t\t    install (\n\t\t    \tDIRECTORY ${THIRD_PARTY_LIB_DIR}/python${PYTHONVERSION}\n\t\t    \tDESTINATION ${INSTALL_LIB_DIR}\n\t\t    \tCOMPONENT Dependencies\n\t\t    )\n\n            # Include libxcb-xinerama for Ubuntu 20/22 by reading /etc/issue\n            if (EXISTS /etc/issue)\n                file(READ \"/etc/issue\" ETC_ISSUE)\n                string(REGEX MATCH \"Ubuntu\" DIST ${ETC_ISSUE})\n                if(DIST STREQUAL \"Ubuntu\")\n                    file (GLOB XCB_FILES ${THIRD_PARTY_LIB_DIR}/libxcb-xinerama.*)\n                    install (\n                        FILES ${XCB_FILES}\n                        DESTINATION ${INSTALL_LIB_DIR}\n                        COMPONENT Dependencies\n                    )\n                endif(DIST STREQUAL \"Ubuntu\")\n            endif (EXISTS /etc/issue)\n\n            install (\n                FILES ${THIRD_PARTY_DIR}/plugins/platforms/libqxcb.so\n                DESTINATION plugins/platforms\n                COMPONENT Dependencies\n            )\n\n            install (\n                DIRECTORY ${THIRD_PARTY_DIR}/plugins/xcbglintegrations\n                DESTINATION ${INSTALL_LIB_DIR}\n                COMPONENT Dependencies\n            )\n\n            file (GLOB XCB_FILES ${THIRD_PARTY_LIB_DIR}/libxcb-xinput.*)\n            install (\n                FILES ${XCB_FILES}\n                DESTINATION ${INSTALL_LIB_DIR}\n                COMPONENT Dependencies\n            )\n\n            file (GLOB XCBQPA_FILES ${THIRD_PARTY_LIB_DIR}/libQt5XcbQpa.*)\n            install (\n                FILES ${XCBQPA_FILES}\n                DESTINATION ${INSTALL_LIB_DIR}\n                COMPONENT Dependencies\n            )\n\n            if (BUILD_OSP)\n                file (GLOB INSTALL_OSPRAY_LIBS ${OSPRAYDIR}/lib/*.so*)\n                install (\n                    FILES ${INSTALL_OSPRAY_LIBS}\n                    DESTINATION ${INSTALL_LIB_DIR}\n                    COMPONENT Dependencies\n                    )\n            endif (BUILD_OSP)\n\n            file (GLOB HDF5_PLUGINS \"${THIRD_PARTY_DIR}/HDF_Group/HDF5/1.12.2/lib/plugin/*.so\")\n            install (\n                FILES ${HDF5_PLUGINS}\n                DESTINATION \"${INSTALL_SHARE_DIR}/plugins\"\n                COMPONENT Dependencies\n            )\n        endif (NOT BUILD_PYTHON)\n\tendif (DIST_INSTALLER AND GENERATE_FULL_INSTALLER)\nendif (UNIX AND NOT APPLE)\n\nif (DIST_INSTALLER)\n\tif (UNIX AND NOT APPLE)\n        if(DIST_APPIMAGE)\n            set (\n                APPIMAGE_COMMAND \n                bash \n                ${CMAKE_SOURCE_DIR}/buildutils/genAppImage.sh \n                ${VERSION_STRING}\n                ${CMAKE_SOURCE_DIR}\n            )\n        else()\n            set (APPIMAGE_COMMAND echo Skipping AppImage generation)\n        endif()\n\t\t\n        add_custom_target (\n\t\t\tinstaller\n\t\t\tWORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\"\n\t\t\tCOMMAND cpack .\n\t\t\tCOMMAND ${APPIMAGE_COMMAND}\n\t\t\tDEPENDS linuxpreinstall\n        )\n\telse ()\n\t\tadd_custom_target (\n\t\t\tinstaller\n\t\t\tWORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\"\n\t\t\tCOMMAND cpack .\n\t\t\t)\n\tendif ()\nendif ()\n\nif (BUILD_PYTHON)\n    # message(\"GENERATORS = '${CPACK_GENERATOR}'\")\n    set(CPACK_GENERATOR \"External\")\n    # message(\"GENERATORS = '${CPACK_GENERATOR}'\")\n    # message(\"CPACK_TOPLEVEL_DIRECTORY = '${CPACK_TOPLEVEL_DIRECTORY}'\")\n    # message(\"CPACK_TEMPORARY_DIRECTORY = '${CPACK_TEMPORARY_DIRECTORY}'\")\n    # message(\"CPACK_PACKAGE_NAME = '${CPACK_PACKAGE_NAME}'\")\n    # message(\"CPACK_PACKAGE_FILE_NAME = '${CPACK_PACKAGE_FILE_NAME}'\")\n    # message(\"CPACK_PACKAGE_VERSION = '${CPACK_PACKAGE_VERSION}'\")\n    # These only work for some things, dont work for others, and they break other things still\n    # set (CPACK_TOPLEVEL_DIRECTORY \"${CMAKE_BINARY_DIR}/CPACK_TOPLEVEL_DIRECTORY\")\n    # set (CPACK_TEMPORARY_DIRECTORY \"${CPACK_TOPLEVEL_DIRECTORY}/CPACK_TEMPORARY_DIRECTORY\")\n    # message(\"CPACK_TOPLEVEL_DIRECTORY = '${CPACK_TOPLEVEL_DIRECTORY}'\")\n    # message(\"CPACK_TEMPORARY_DIRECTORY = '${CPACK_TEMPORARY_DIRECTORY}'\")\n    set (CPACK_BINARY_DRAGNDROP OFF)\n    # set (CPACK_BINARY_EXTERNAL ON)\n    set (CPACK_EXTERNAL_REQUESTED_VERSIONS \"1.0\")\n    set (CPACK_EXTERNAL_ENABLE_STAGING TRUE)\n\n    if (NOT CONDA_BUILD)\n\t    install (\n\t\t    DIRECTORY ${THIRD_PARTY_DIR}/include\n\t        DESTINATION .\n\t\t    COMPONENT Dependencies\n\t\t)\n    endif()\nendif ()\n\ninclude (CPack)\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nProject maintainers are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nProject maintainers have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the project maintainers responsible for enforcement at\nvapor@ucar.edu.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll project maintainers are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nProject maintainers will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from project maintainers, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available at\nhttps://www.contributor-covenant.org/version/2/0/code_of_conduct.html.\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder](https://github.com/mozilla/diversity).\n\n[homepage]: https://www.contributor-covenant.org\n\nFor answers to common questions about this code of conduct, see the FAQ at\nhttps://www.contributor-covenant.org/faq. Translations are available at\nhttps://www.contributor-covenant.org/translations.\n"
  },
  {
    "path": "Contributing.md",
    "content": "# Contributing\n\nTo make a contribution to Vapor, see our [Contributor's Guide](https://ncar.github.io/VaporDocumentationWebsite/contributingToVapor.html).\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2024, NSF National Center for Atmospheric Research\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.13332956.svg)](https://doi.org/10.5281/zenodo.13332956)\n[![CircleCI](https://circleci.com/gh/NCAR/VAPOR.svg?style=svg)](https://circleci.com/gh/NCAR/VAPOR) \n\n## Vapor:\n\n**VAPOR** is the **V**isualization and **A**nalysis **P**latform for **O**cean, Atmosphere, and Solar **R**esearchers.  VAPOR provides an interactive 3D visualization environment that can also produce animations and still frame images.  VAPOR runs on most UNIX and Windows systems equipped with modern 3D graphics cards.\n\nThe VAPOR Data Collection (**VDC**) data model allows users progressively access the fidelity of their data, allowing for the visualization of terascale data sets on commodity hardware.  VAPOR can also directly import data formats including WRF, MOM, POP, ROMS, and some GRIB and NetCDF files.\n\nUsers can perform ad-hoc analysis with VAPOR's interactive Python interpreter; which allows for the creation, modification, and visualization of new variables based on input model data.\n\nVAPOR is a product of the **NSF National Center for Atmospheric Research's Computational and Information Systems Lab**. Support for VAPOR is provided by the U.S. **National Science Foundation** (grants # 03-25934 and 09-06379, ACI-14-40412), and by the **Korea Institute of Science and Technology Information**\n\nProject homepage and binary releases can be found at [https://www.vapor.ucar.edu/](https://www.vapor.ucar.edu/)\n\n## Citation\nIf VAPOR benefits your research, please kindly cite [this publication](https://www.mdpi.com/2073-4433/10/9/488):\n```\n@Article{atmos10090488,\nAUTHOR = {Li, Shaomeng and Jaroszynski, Stanislaw and Pearse, Scott and Orf, Leigh and Clyne, John},\nTITLE = {VAPOR: A Visualization Package Tailored to Analyze Simulation Data in Earth System Science},\nJOURNAL = {Atmosphere},\nVOLUME = {10},\nYEAR = {2019},\nNUMBER = {9},\nARTICLE-NUMBER = {488},\nURL = {https://www.mdpi.com/2073-4433/10/9/488},\nISSN = {2073-4433},\nABSTRACT = {Visualization is an essential tool for analysis of data and communication of findings in the sciences, and the Earth System Sciences (ESS) are no exception. However, within ESS, specialized visualization requirements and data models, particularly for those data arising from numerical models, often make general purpose visualization packages difficult, if not impossible, to use effectively. This paper presents VAPOR: a domain-specific visualization package that targets the specialized needs of ESS modelers, particularly those working in research settings where highly-interactive exploratory visualization is beneficial. We specifically describe VAPOR&rsquo;s ability to handle ESS simulation data from a wide variety of numerical models, as well as a multi-resolution representation that enables interactive visualization on very large data while using only commodity computing resources. We also describe VAPOR&rsquo;s visualization capabilities, paying particular attention to features for geo-referenced data and advanced rendering algorithms suitable for time-varying, 3D data. Finally, we illustrate VAPOR&rsquo;s utility in the study of a numerically- simulated tornado. Our results demonstrate both ease-of-use and the rich capabilities of VAPOR in such a use case.},\nDOI = {10.3390/atmos10090488}\n}\n```\n\n## Project Members:\n\n- Nihanth Cherukuru\n- John Clyne\n- Scott Pearse\n- Samuel Li\n- Stanislaw Jaroszynski\n- Kenny Gruchalla\n- Niklas Roeber\n- Pamela Gillman\n\n![Vapor Banner](share/images/vapor_banner.png)\n"
  },
  {
    "path": "apps/CMakeLists.txt",
    "content": "if (BUILD_UTL)\n\tadd_subdirectory (vaporversion)\n\tadd_subdirectory (raw2wasp)\n\tadd_subdirectory (wasp2raw)\n\tadd_subdirectory (waspcreate)\n\tadd_subdirectory (ncdf2wasp)\n\tadd_subdirectory (wasp2ncdf)\nendif()\n\nif ((BUILD_VDC OR BUILD_GUI) AND BUILD_UTL)\n\tadd_subdirectory (vdcdump)\n\tadd_subdirectory (cf2vdc)\n\tadd_subdirectory (cfvdccreate)\n\tadd_subdirectory (raw2vdc)\n\tadd_subdirectory (vdc2raw)\n\tadd_subdirectory (vdccreate)\n\tadd_subdirectory (wrf2vdc)\n\tadd_subdirectory (wrfvdccreate)\n\tadd_subdirectory (vdccompare)\n\tadd_subdirectory (vapor_check_udunits)\nendif()\n\nif (BUILD_GUI)\n\tadd_subdirectory (vaporgui)\n\tif (BUILD_UTL)\n\t\tadd_subdirectory (tiff2geotiff)\n\t\tadd_subdirectory (vaporpychecker)\n\tendif()\nendif()\n\nif (BUILD_PYTHON)\n    add_subdirectory (pythonapi)\nendif()\n \nif (UNIX AND NOT APPLE AND DIST_INSTALLER)\n\tadd_subdirectory (linuxlauncher)\nendif ()\n"
  },
  {
    "path": "apps/asciitf2vtf/asciitf2vtf.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <cstring>\n#include <vector>\n#include <sstream>\n#include <algorithm>\n#include <string>\n#include <iomanip>\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/Metadata.h>\n#include <vapor/MetadataSpherical.h>\n#include <vapor/TransferFunctionLite.h>\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n#endif\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n// asciitf2vtf:\n//    This is one of the commandline applications for VAPOR.\n//\n// Modified in April, 2011.\n//    Added the ability for the program to use NCL colormaps as input.\n//\tKendall Southwick\n//\n\nstruct opt_t {\n    char *                  omap;\n    char *                  cmap;\n    char *                  type;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"cmap\", 1, \"\", \"Path to ascii file containing color map\"},\n                                         {\"omap\", 1, \"\", \"Path to ascii file containing opacity map\"},\n                                         {\"type\", 1, \"vapor\", \"Type pf color maps being used, defaults to vapor\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {\"quiet\", 0, \"\", \"Operate quietly\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"cmap\", Wasp::CvtToString, &opt.cmap, sizeof(opt.cmap)},     {\"omap\", Wasp::CvtToString, &opt.omap, sizeof(opt.omap)},\n                                        {\"type\", Wasp::CvtToString, &opt.type, sizeof(opt.type)},     {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {NULL}};\n\nconst char *ProgName;\n\nvoid Usage(OptionParser &op, const char *msg)\n{\n    if (msg) { cerr << ProgName << \" : \" << msg << endl; }\n    cerr << \"Usage: \" << ProgName << \" [options] (-cmap cmap.txt | -omap omap.txt) file.tf3\" << endl;\n    op.PrintOptionHelp(stderr);\n}\n\nvoid ErrMsgCBHandler(const char *msg, int) { cerr << ProgName << \" : \" << msg << endl; }\n\n//\n// This function will process the VAPOR color map files.\n//\n\nint ProcessVAPORCMAP(TransferFunctionLite *transFunct)\n{\n    int           RetVal = 0;\n    vector<float> pvec, hvec, svec, vvec;\n    float         point, h, s, v;\n\n    ColorMap *cmap = transFunct->getColormap();\n    cmap->clear();\n\n    FILE *fp = fopen(opt.cmap, \"r\");\n    if (!fp) {\n        MyBase::SetErrMsg(\"fopen(%s) : %M\", opt.cmap);\n        exit(1);\n    }\n\n    const char *format = \"%f %f %f %f\";\n\n    while ((RetVal = fscanf(fp, format, &point, &h, &s, &v)) == 4) {\n        pvec.push_back(point);\n        hvec.push_back(h);\n        svec.push_back(s);\n        vvec.push_back(v);\n    }\n\n    if (vvec.size() <= 0) {\n        MyBase::SetErrMsg(\"Error parsing file %s , no data.\", opt.cmap);\n        exit(1);\n    }\n\n    vector<float> tmpvec = pvec;\n    sort(tmpvec.begin(), tmpvec.end());\n\n    // Apparently we need to set the min and max values in both\n    // the transfer function and colormap class. Setting the\n    // cmap bounds is needed so that addControlPointAt() will\n    // correctly normalize the data value.\n\n    transFunct->setMinColorMapValue(tmpvec[0]);\n    transFunct->setMaxColorMapValue(tmpvec[tmpvec.size() - 1]);\n    cmap->minValue(tmpvec[0]);\n    cmap->maxValue(tmpvec[tmpvec.size() - 1]);\n\n    ColorMap::Color color;\n    for (int i = 0; i < pvec.size(); i++) {\n        color.hue(hvec[i]);\n        color.sat(svec[i]);\n        color.val(vvec[i]);\n        //\tcmap->addNormControlPoint(pvec[i],  color);\n        cmap->addControlPointAt(pvec[i], color);\n    }\n    //\n    // Ugh. now we need to normalize the data bounds.\n    //\n    cmap->minValue(0.0);\n    cmap->maxValue(1.0);\n\n    if (ferror(fp)) {\n        MyBase::SetErrMsg(\"Error parsing file %s\", opt.cmap);\n        exit(1);\n    }\n    fclose(fp);\n\n    return (RetVal);\n}    // End of ProcessVAPORCMAP.\n\n//\n// This function will process the NCL color map files.\n//\n\nint ProcessNCLCMAP(TransferFunctionLite *transFunct)\n{\n    int           RetVal = 0;\n    int           numColors = 0;\n    int           fileSize;\n    int           rc;\n    int           last_i = 0;\n    float         THRESHOLD = 0.10;\n    float         SLOPE_THRESHOLD = 0.010;\n    float         last_hsv[] = {0.0, 0.0, 0.0};\n    float         rgb[] = {0.0, 0.0, 0.0};\n    float         hsv[] = {0.0, 0.0, 0.0};\n    float         comp_vals[] = {0.0, 0.0, 0.0};\n    vector<float> pvec, hvec, svec, vvec;\n    char *        readLine;\n    bool          header_flag = false;\n    bool          h_slope_flag, slope_flag, interval_flag, delta_flag;\n\n    ColorMap *cmap = transFunct->getColormap();\n    cmap->clear();\n\n    ifstream nclFile(opt.cmap, ios::in);\n    if (!nclFile) {\n        MyBase::SetErrMsg(\"Unable to open file %s: %M\", opt.cmap);\n        exit(1);\n    }\n\n    //\n    // Start parsing the file.\n    // There needs to be a line must be of the form\n    // \"ncolors=##\"  where ## is a number.\n    // The header ends with a lines of the form\n    // # r    b   g\n    // There may a different number of spaces between the\n    // # and the r.\n    //\n\n    nclFile.seekg(0, ios::end);\n    fileSize = nclFile.tellg();\n    nclFile.seekg(0, ios::beg);\n    readLine = (char *)malloc(fileSize * sizeof(char));\n    char *indexChar;\n\n    while (!header_flag && !nclFile.eof()) {\n        nclFile.getline(readLine, fileSize);\n        indexChar = NULL;\n        if (readLine[0] == '#') {\n            indexChar = strstr(readLine, \"r   g   b\");\n            if (indexChar != NULL) { header_flag = true; }    // end of headers.\n        }                                                     // comment line.\n        else {\n            indexChar = strstr(readLine, \"ncolors=\");\n            if (indexChar != NULL) { rc = sscanf(indexChar + 8, \"%d\", &numColors); }    // have ncolors.\n        }                                                                               // non comment line.\n    }                                                                                   // End of while.\n\n    if (nclFile.eof() || numColors == 0 || !header_flag) {\n        MyBase::SetErrMsg(\"Formating error in file %s\", opt.cmap);\n        exit(1);\n    }\n\n    //\n    // Since it is hard to have more the ten color control points\n    // in VAPOR, we need to trim the input down.\n    //\n\n    for (int i = 0; ((i < numColors) && !nclFile.eof()); i++) {\n        nclFile.getline(readLine, fileSize);\n        if (strlen(readLine) > 0) {\n            rc = sscanf(readLine, \"%f %f %f\", &rgb[0], &rgb[1], &rgb[2]);\n            if (rc != 3) {\n                MyBase::SetErrMsg(\"Formating error in file %s\", opt.cmap);\n                exit(1);\n            }\n            h_slope_flag = slope_flag = interval_flag = delta_flag = false;\n            rgb[0] = rgb[0] / 255.0;\n            rgb[1] = rgb[1] / 255.0;\n            rgb[2] = rgb[2] / 255.0;\n            transFunct->rgbToHsv(rgb, hsv);\n            if (i == 0) {\n                comp_vals[0] = hsv[0];\n                comp_vals[1] = hsv[1];\n                comp_vals[2] = hsv[2];\n                last_hsv[0] = hsv[0];\n                last_hsv[1] = hsv[1];\n                last_hsv[2] = hsv[2];\n                last_i = -1;\n            }\n\n            if ((abs(hsv[0] - comp_vals[0]) >= THRESHOLD) || (abs(hsv[1] - comp_vals[1]) >= THRESHOLD) || (abs(hsv[2] - comp_vals[2]) >= THRESHOLD)) { delta_flag = true; }\n            if ((abs((comp_vals[2] - hsv[2]) / (i - last_i) - (last_hsv[2] - hsv[2])) >= SLOPE_THRESHOLD)\n                || (abs((comp_vals[1] - hsv[1]) / (i - last_i) - (last_hsv[1] - hsv[1])) >= SLOPE_THRESHOLD)) {\n                slope_flag = true;\n            }\n            if ((i - last_i) > (0.07 * numColors)) { interval_flag = true; }\n\n            if (slope_flag || interval_flag || (i == 0)) {\n                comp_vals[0] = hsv[0];\n                comp_vals[1] = hsv[1];\n                comp_vals[2] = hsv[2];\n                last_i = i;\n                pvec.push_back(((float)(i)) / ((float)(numColors)));\n                hvec.push_back(hsv[0]);\n                svec.push_back(hsv[1]);\n                vvec.push_back(hsv[2]);\n            }\n            last_hsv[0] = hsv[0];\n            last_hsv[1] = hsv[1];\n            last_hsv[2] = hsv[2];\n        }    // End if strlen.\n    }        // End for.\n\n    if (vvec.size() <= 0) {\n        MyBase::SetErrMsg(\"Error parsing file %s , no data.\", opt.cmap);\n        exit(1);\n    }\n\n    vector<float> tmpvec = pvec;\n    sort(tmpvec.begin(), tmpvec.end());\n\n    // Apparently we need to set the min and max values in both\n    // the transfer function and colormap class. Setting the\n    // cmap bounds is needed so that addControlPointAt() will\n    // correctly normalize the data value.\n\n    transFunct->setMinColorMapValue(tmpvec[0]);\n    transFunct->setMaxColorMapValue(tmpvec[tmpvec.size() - 1]);\n    cmap->minValue(tmpvec[0]);\n    cmap->maxValue(tmpvec[tmpvec.size() - 1]);\n\n    ColorMap::Color color;\n    for (int i = 0; i < pvec.size(); i++) {\n        color.hue(hvec[i]);\n        color.sat(svec[i]);\n        color.val(vvec[i]);\n        //\tcmap->addNormControlPoint(pvec[i],  color);\n        cmap->addControlPointAt(pvec[i], color);\n    }\n\n    //\n    // Ugh. now we need to normalize the data bounds.\n    //\n    cmap->minValue(0.0);\n    cmap->maxValue(1.0);\n\n    nclFile.close();\n\n    return (RetVal);\n}    // End of ProcessNCLCMAP.\n\n//\n// This functions directs how the color maps is t be processed based on the\n// type of color maps, form the -type option.\n//\n\nint ProcessCMAP(TransferFunctionLite *transFunct, char *cmapType)\n{\n    int RetVal;\n\n    if (strcmp(cmapType, \"vapor\") == 0) {\n        RetVal = ProcessVAPORCMAP(transFunct);\n    } else if (strcmp(cmapType, \"VAPOR\") == 0) {\n        RetVal = ProcessVAPORCMAP(transFunct);\n    } else if (strcmp(cmapType, \"ncl\") == 0) {\n        RetVal = ProcessNCLCMAP(transFunct);\n    } else if (strcmp(cmapType, \"NCL\") == 0) {\n        RetVal = ProcessNCLCMAP(transFunct);\n    } else {\n        RetVal = 1;\n        MyBase::SetErrMsg(\"Invalid color map type.\");\n    }\n\n    return (RetVal);\n}    // End of ProcessCMAP.\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    ProgName = Basename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << OptionParser::GetErrMsg();\n        exit(1);\n    }\n\n    MyBase::SetErrMsgCB(ErrMsgCBHandler);\n\n    if (opt.help) {\n        Usage(op, NULL);\n        exit(0);\n    }\n\n    if (argc != 2) {\n        Usage(op, \"Wrong number of arguments\");\n        exit(1);\n    }\n\n    if ((strlen(opt.cmap) == 0) && (strlen(opt.omap) == 0)) {\n        Usage(op, \"Wrong number of arguments\");\n        exit(1);\n    }\n\n    TransferFunctionLite tf(8);\n    if (MyBase::GetErrCode() != 0) exit(1);\n\n    tf.setMinColorMapValue(0.0);\n    tf.setMaxColorMapValue(1.0);\n    tf.setMinOpacMapValue(0.0);\n    tf.setMaxOpacMapValue(1.0);\n\n    string vtffile(argv[1]);\n\n    int rc;\n\n    if (strlen(opt.cmap) != 0) { ProcessCMAP(&tf, opt.type); }\n\n    if (strlen(opt.omap) != 0) {\n        float         point, o;\n        vector<float> pvec, ovec;\n\n        OpacityMap *omap = tf.getOpacityMap(0);\n        omap->clear();\n\n        FILE *fp = fopen(opt.omap, \"r\");\n        if (!fp) {\n            MyBase::SetErrMsg(\"fopen(%s) : %M\", opt.omap);\n            exit(1);\n        }\n\n        const char *format = \"%f %f\";\n\n        while ((rc = fscanf(fp, format, &point, &o)) == 2) {\n            pvec.push_back(point);\n            ovec.push_back(o);\n        }\n\n        vector<float> tmpvec = pvec;\n        sort(tmpvec.begin(), tmpvec.end());\n        tf.setMinOpacMapValue(tmpvec[0]);\n        tf.setMaxOpacMapValue(tmpvec[tmpvec.size() - 1]);\n        omap->minValue(tmpvec[0]);\n        omap->maxValue(tmpvec[tmpvec.size() - 1]);\n\n        for (int i = 0; i < pvec.size(); i++) {\n            //\t\t\tomap->addNormControlPoint(pvec[i],  ovec[i]);\n            omap->addControlPoint(pvec[i], ovec[i]);\n        }\n        omap->minValue(0.0);\n        omap->maxValue(1.0);\n\n        if (ferror(fp)) {\n            MyBase::SetErrMsg(\"Error parsing file %s\", opt.omap);\n            exit(1);\n        }\n        fclose(fp);\n    }    // End of if omap.\n\n    //\n    // Write output file.\n    //\n\n    ofstream fileout;\n    fileout.open(vtffile.c_str());\n    if (!fileout) {\n        MyBase::SetErrMsg(\"Can't open file \\\"%s\\\" for writing\", vtffile.c_str());\n        exit(1);\n    }\n    if (!(tf.saveToFile(fileout))) exit(1);\n\n    exit(0);\n}    // End of Main.\n"
  },
  {
    "path": "apps/cf2vdc/CMakeLists.txt",
    "content": "add_executable (cf2vdc cf2vdc.cpp)\n\ntarget_link_libraries (cf2vdc common vdc)\n\nOpenMPInstall (\n\tTARGETS cf2vdc\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/cf2vdc/cf2vdc.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string.h>\n#include <vector>\n#include <sstream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/CFuncs.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/DCCF.h>\n#include <vapor/FileUtils.h>\n#include <vapor/SetHDF5PluginPath.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    int                     nthreads;\n    int                     numts;\n    std::vector<string>     vars;\n    std::vector<string>     xvars;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"numts\", 1, \"-1\", \"Number of timesteps to be included in the VDC. Default (-1) includes all timesteps.\"},\n                                         {\"vars\", 1, \"\",\n                                          \"Colon delimited list of variable names \"\n                                          \"to be copied to the VDC\"},\n                                         {\"xvars\", 1, \"\",\n                                          \"Colon delimited list of variable names \"\n                                          \"to exclude from copying the VDC\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {\"numts\", Wasp::CvtToInt, &opt.numts, sizeof(opt.numts)},\n                                        {\"vars\", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)},          {\"xvars\", Wasp::CvtToStrVec, &opt.xvars, sizeof(opt.xvars)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},         {NULL}};\n\nstring ProgName;\n\nSmartBuf dataBuffer;\nSmartBuf maskBuffer;\n\n// Product of elements in a vector\n//\nsize_t vproduct(vector<size_t> a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n\nsize_t gcd(size_t n1, size_t n2)\n{\n    size_t tmp;\n    while (n2 != 0) {\n        tmp = n1;\n        n1 = n2;\n        n2 = tmp % n2;\n    }\n    return n1;\n}\n\nsize_t lcm(size_t n1, size_t n2) { return ((n1 * n2) / gcd(n1, n2)); }\n\nint copyVarHelper(DC &dc, VDCNetCDF &vdc, int fdr, int fdw, vector<size_t> &buffer_dims, vector<size_t> &src_hslice_dims, vector<size_t> &dst_hslice_dims, size_t src_nslice, size_t dst_nslice,\n                  double mv, float *buffer)\n{\n    VAssert(buffer_dims.size() == src_hslice_dims.size());\n    VAssert(buffer_dims.size() == dst_hslice_dims.size());\n\n    size_t dim = buffer_dims.size() - 1;\n\n    size_t src_slice_count = 0;\n    size_t dst_slice_count = 0;\n    while (src_slice_count < src_nslice) {\n        float *bufptr = buffer;\n        int    n = buffer_dims[dim] / src_hslice_dims[dim];\n\n        int rCount;\n        for (rCount = 0; rCount < n && src_slice_count < src_nslice; rCount++) {\n            int rc = dc.ReadSlice(fdr, bufptr);\n            if (rc < 0) return (-1);\n            bufptr += vproduct(src_hslice_dims);\n\n            src_slice_count++;\n        }\n\n        // In place replacmenet of missing value with 1-byte flag\n        //\n        size_t         sz = rCount * vproduct(src_hslice_dims);\n        unsigned char *cptr = (unsigned char *)buffer;\n        for (int j = 0; j < sz; j++) {\n            if (buffer[j] == mv) {\n                cptr[j] = 0;    // invalid data\n            } else {\n                cptr[j] = 1;    // valid data\n            }\n        }\n\n        cptr = (unsigned char *)buffer;\n        n = buffer_dims[dim] / dst_hslice_dims[dim];\n\n        for (int i = 0; i < n && dst_slice_count < dst_nslice; i++) {\n            int rc = vdc.WriteSlice(fdw, cptr);\n            if (rc < 0) return (-1);\n\n            cptr += vproduct(dst_hslice_dims);\n\n            dst_slice_count++;\n        }\n    }\n    return (0);\n}\n\nint CopyVar2d3dMask(DC &dc, VDCNetCDF &vdc, size_t ts, string varname, int lod)\n{\n    // Only data variables can have masks\n    //\n    if (!vdc.IsDataVar(varname)) return (0);\n\n    DC::DataVar varInfo;\n    bool        status = vdc.GetDataVarInfo(varname, varInfo);\n    if (!status) {\n        MyBase::SetErrMsg(\"Invalid destination variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    string maskvar = varInfo.GetMaskvar();\n\n    // Do nothing if mask variable already exists on disk\n    //\n    if (maskvar.empty() || vdc.VariableExists(ts, maskvar, 0, lod)) return (0);\n\n    status = dc.GetDataVarInfo(varname, varInfo);\n    if (!status) {\n        MyBase::SetErrMsg(\"Invalid source variable name : %s\", varname.c_str());\n        return (-1);\n    }\n    double mv = varInfo.GetMissingValue();\n\n    // Get the dimensions of a hyper slice for the source and destination\n    // varible\n    //\n    vector<size_t> src_hslice_dims;\n    size_t         src_nslice;\n    int            rc = dc.GetHyperSliceInfo(varname, -1, src_hslice_dims, src_nslice);\n    if (rc < 0) return (rc);\n\n    if (src_hslice_dims.size() < 2) return (0);\n\n    vector<size_t> dst_hslice_dims;\n    size_t         dst_nslice;\n    rc = vdc.GetHyperSliceInfo(varname, -1, dst_hslice_dims, dst_nslice);\n    if (rc < 0) return (rc);\n\n    if (src_hslice_dims.size() != dst_hslice_dims.size()) {\n        MyBase::SetErrMsg(\"Incompatible source and destination variable definitions\");\n        return (-1);\n    }\n\n    // n-1 fastest varying dimensions must be the same for both hyper-slices.\n    // Slowest dimension may be different.\n    //\n    int    dim = src_hslice_dims.size() - 1;\n    size_t src_dimlen = src_hslice_dims[dim];\n    size_t dst_dimlen = dst_hslice_dims[dim];\n\n    for (int i = 0; i < src_hslice_dims.size() - 1; i++) {\n        if (src_hslice_dims[i] != dst_hslice_dims[i]) {\n            MyBase::SetErrMsg(\"Incompatible source and destination variable definitions\");\n            return (-1);\n        }\n    }\n\n    // Find the slice dimension for slowest varying dimension, the Least\n    // Common Multiple for the source and destination\n    //\n    size_t slice_dim = lcm(src_dimlen, dst_dimlen);\n\n    // Common (fastest-varying) dimensions for both variables, plus\n    // the lcm of the slowest varying dimension for the source\n    // and destination.\n    //\n    vector<size_t> buffer_dims = src_hslice_dims;\n    buffer_dims.pop_back();    // Remove slowest varying dimension\n    buffer_dims.push_back(slice_dim);\n\n    int fdr = dc.OpenVariableRead(ts, varname, -1);\n    if (fdr < 0) return (fdr);\n\n    int fdw = vdc.OpenVariableWrite(ts, maskvar, lod);\n    if (fdw < 0) {\n        dc.CloseVariable(fdr);\n        return (fdw);\n    }\n\n    size_t bufsize = vproduct(buffer_dims);\n    float *buffer = (float *)dataBuffer.Alloc(bufsize * sizeof(*buffer));\n\n    rc = copyVarHelper(dc, vdc, fdr, fdw, buffer_dims, src_hslice_dims, dst_hslice_dims, src_nslice, dst_nslice, mv, buffer);\n\n    dc.CloseVariable(fdr);\n    vdc.CloseVariable(fdw);\n\n    return (rc);\n}\n\n// Return a new vector containing elements of v1 with any elements from\n// v2 removed\n//\nvector<string> remove_vector(vector<string> v1, vector<string> v2)\n{\n    vector<string> newvec;\n    for (auto it = v1.begin(); it != v1.end(); ++it) {\n        if (find(v2.begin(), v2.end(), *it) == v2.end()) { newvec.push_back(*it); }\n    }\n    return (newvec);\n}\n\nint main(int argc, char **argv)\n{\n    VAPoR::SetHDF5PluginPath();\n\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { return (1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); }\n\n    if (argc < 3) {\n        cerr << \"Usage: \" << ProgName << \" cffiles... master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        return (1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        return (0);\n    }\n\n    argc--;\n    argv++;\n    vector<string> cffiles;\n    for (int i = 0; i < argc - 1; i++) cffiles.push_back(argv[i]);\n    string master = argv[argc - 1];\n\n    VDCNetCDF vdc(opt.nthreads);\n\n    size_t         chunksize = 1024 * 1024 * 4;\n    vector<size_t> bs;\n    int            rc = vdc.Initialize(master, vector<string>(), VDC::A, bs, chunksize);\n    if (rc < 0) return (1);\n\n    DCCF dccf;\n    rc = dccf.Initialize(cffiles, vector<string>());\n    if (rc < 0) { return (1); }\n\n    //\n    // Copy coordinate variables first, checking to ensure that the\n    // coordinate variable isn't also a data variable (a variable can\n    // be both data and coordinate). If a coord variable is also\n    // a data variable, skip it and handle below\n    //\n    vector<string> varnames = dccf.GetCoordVarNames();\n    vector<string> dvarnames = dccf.GetDataVarNames();\n    for (int i = 0; i < varnames.size(); i++) {\n        // Skip coordinate varibles that are also data variables\n        //\n        if (find(dvarnames.begin(), dvarnames.end(), varnames[i]) != dvarnames.end()) continue;\n\n        int nts = dccf.GetNumTimeSteps(varnames[i]);\n        nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts;\n        VAssert(nts >= 0);\n\n        cout << \"Copying variable \" << varnames[i] << endl;\n\n        for (int ts = 0; ts < nts; ts++) {\n            cout << \"  Time step \" << ts << endl;\n            int rc = vdc.CopyVar(dccf, ts, varnames[i], -1, -1);\n            if (rc < 0) {\n                MyBase::SetErrMsg(\"Failed to copy variable %s\", varnames[i].c_str());\n                return (1);\n            }\n        }\n    }\n\n    if (opt.vars.size()) {\n        varnames = opt.vars;\n    } else {\n        varnames = dccf.GetDataVarNames();\n    }\n\n    varnames = remove_vector(varnames, opt.xvars);\n\n    // Now copy data variables\n    //\n    int estatus = 0;\n    for (int i = 0; i < varnames.size(); i++) {\n        int nts = dccf.GetNumTimeSteps(varnames[i]);\n        nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts;\n        VAssert(nts >= 0);\n\n        cout << \"Copying variable \" << varnames[i] << endl;\n\n        for (int ts = 0; ts < nts; ts++) {\n            cout << \"  Time step \" << ts << endl;\n\n            int rc = CopyVar2d3dMask(dccf, vdc, ts, varnames[i], -1);\n            if (rc < 0) {\n                MyBase::SetErrMsg(\"Failed to copy variable %s\", varnames[i].c_str());\n                continue;\n                estatus = 1;\n            }\n\n            rc = vdc.CopyVar(dccf, ts, varnames[i], -1, -1);\n            if (rc < 0) {\n                MyBase::SetErrMsg(\"Failed to copy variable %s\", varnames[i].c_str());\n                estatus = 1;\n            }\n        }\n    }\n\n    return (estatus);\n}\n"
  },
  {
    "path": "apps/cfvdccreate/CMakeLists.txt",
    "content": "add_executable (cfvdccreate cfvdccreate.cpp)\n\ntarget_link_libraries (cfvdccreate common vdc)\n\nOpenMPInstall (\n\tTARGETS cfvdccreate\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/cfvdccreate/cfvdccreate.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string.h>\n#include <vector>\n#include <sstream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/CFuncs.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/DCCF.h>\n#include <vapor/FileUtils.h>\n#include <vapor/SetHDF5PluginPath.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    OptionParser::Dimension3D_T dim;\n    std::vector<size_t>         bs;\n    std::vector<size_t>         cratios;\n    string                      wname;\n    int                         nthreads;\n    std::vector<string>         vars;\n    OptionParser::Boolean_T     force;\n    OptionParser::Boolean_T     help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"dimension\", 1, \"512x512x512\",\n                                          \"Data volume dimensions expressed in \"\n                                          \"grid points (NXxNYxNZ)\"},\n                                         {\"bs\", 1, \"64:64:64\", \"Internal storage blocking factor expressed in grid points (NX:NY:NZ)\"},\n                                         {\"cratios\", 1, \"1:10:100:500\",\n                                          \"Colon delimited list compression ratios. \"\n                                          \"for 3D variables. The default is 1:10:100:500. The maximum \"\n                                          \"compression ratio is wavelet and block size dependent.\"},\n                                         {\"wname\", 1, \"bior4.4\",\n                                          \"Wavelet family used for compression \"\n                                          \"Valid values are bior1.1, bior1.3, \"\n                                          \"bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, \"\n                                          \"bior3.5, bior3.7, bior3.9, bior4.4\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"vars\", 1, \"\",\n                                          \"Colon delimited list of 3D variable names (compressed) \"\n                                          \"to be included in \"\n                                          \"the VDC\"},\n                                         {\"force\", 0, \"\",\n                                          \"Create a new VDC master file even if a VDC data \"\n                                          \"directory already exists. Results may be undefined if settings between \"\n                                          \"the new master file and old data directory do not match.\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"dimension\", Wasp::CvtToDimension3D, &opt.dim, sizeof(opt.dim)},\n                                        {\"bs\", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)},\n                                        {\"cratios\", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)},\n                                        {\"wname\", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"vars\", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)},\n                                        {\"force\", Wasp::CvtToBoolean, &opt.force, sizeof(opt.force)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nstring ProgName;\n\n// Construct a mask variable name\n//\nvoid maskvar(vector<string> dimnames, string &name)\n{\n    VAssert(dimnames.size() >= 1);\n    name.clear();\n\n    name = \"mask\";\n    for (int i = 0; i < dimnames.size(); i++) { name += \"_\" + dimnames[i]; }\n}\n\nvoid DefineMaskVars(const DCCF &dccf, VDCNetCDF &vdc)\n{\n    // Find all coordinate combinations for data with missing values\n    //\n    vector<pair<string, vector<string>>> dimpairs;\n    for (int d = 1; d < 4; d++) {\n        vector<string> datanames = dccf.DC::GetDataVarNames(d);\n\n        for (int i = 0; i < datanames.size(); i++) {\n            DC::DataVar dvar;\n            dccf.GetDataVarInfo(datanames[i], dvar);\n\n            // skip if no missing value defined for this variable\n            //\n            if (!dvar.GetHasMissing()) continue;\n\n            // Assume missing values locations don't vary over time!\n            //\n            vector<string> dimnames;\n            bool           ok = dccf.GetVarDimNames(datanames[i], true, dimnames);\n            VAssert(ok);\n\n            string maskvar_name;\n            maskvar(dimnames, maskvar_name);\n\n            pair<string, vector<string>> p1 = make_pair(maskvar_name, dimnames);\n\n            dimpairs.push_back(p1);\n        }\n    }\n    sort(dimpairs.begin(), dimpairs.end());\n    vector<pair<string, vector<string>>>::iterator last;\n    last = unique(dimpairs.begin(), dimpairs.end());\n    dimpairs.erase(last, dimpairs.end());\n\n    for (int i = 0; i < dimpairs.size(); i++) {\n        string         maskvar = dimpairs[i].first;\n        vector<string> dimnames = dimpairs[i].second;\n\n        //\n        // 1D coordinates are not blocked\n        //\n        string mywname;\n        bool   compress;\n        if (dimnames.size() < 2) {\n            mywname.clear();\n            compress = false;\n        } else {\n            mywname = \"intbior2.2\";\n            compress = true;\n        }\n\n        // Try to compute \"reasonable\" 1D & 2D compression ratios from 3D\n        // compression ratios\n        //\n        vector<size_t> cratios(1, 1);\n\n        int rc = vdc.SetCompressionBlock(mywname, cratios);\n        if (rc < 0) exit(1);\n\n        rc = vdc.DefineDataVar(maskvar, dimnames, vector<string>(), \"\", DC::INT8, compress);\n\n        if (rc < 0) { exit(1); }\n    }\n}\n\nvoid defineMapProjection(const DCCF &dc, VDCNetCDF &vdc) { vdc.SetMapProjection(dc.GetMapProjection()); }\n\nint main(int argc, char **argv)\n{\n    VAPoR::SetHDF5PluginPath();\n\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { return (1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); }\n\n    if (argc < 3) {\n        cerr << \"Usage: \" << ProgName << \" cf_files... master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        return (1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" cf_files... master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        return (0);\n    }\n\n    argc--;\n    argv++;\n    vector<string> cffiles;\n    for (int i = 0; i < argc - 1; i++) cffiles.push_back(argv[i]);\n    string master = argv[argc - 1];\n\n    if (FileUtils::Extension(master) != \"vdc\") { fprintf(stderr, \"Warning: VDC files should the extension .vdc\\n\"); }\n\n    VDCNetCDF vdc(opt.nthreads);\n\n    if (vdc.DataDirExists(master) && !opt.force) {\n        MyBase::SetErrMsg(\"Data directory exists and -force option not used. \"\n                          \"Remove directory %s or use -force\",\n                          vdc.GetDataDir(master).c_str());\n        return (1);\n    }\n    if (FileUtils::Exists(master) && !opt.force) {\n        MyBase::SetErrMsg(\"\\\"%s\\\" already exists and -force option not used.\", master.c_str());\n        exit(1);\n    }\n\n    size_t chunksize = 1024 * 1024 * 4;\n    int    rc = vdc.Initialize(master, vector<string>(), VDC::W, opt.bs, chunksize);\n    if (rc < 0) return (1);\n\n    DCCF dccf;\n    rc = dccf.Initialize(cffiles, vector<string>());\n    if (rc < 0) { return (1); }\n\n    vector<string> dimnames = dccf.GetDimensionNames();\n    for (int i = 0; i < dimnames.size(); i++) {\n        DC::Dimension dim;\n        dccf.GetDimension(dimnames[i], dim, -1);\n        rc = vdc.DefineDimension(dim.GetName(), dim.GetLength());\n        if (rc < 0) { return (1); }\n    }\n\n    //\n    // Define coordinate variables\n    //\n    vector<size_t> cratios(1, 1);\n    vector<string> coordnames = dccf.GetCoordVarNames();\n\n    for (int i = 0; i < coordnames.size(); i++) {\n        DC::CoordVar cvar;\n        dccf.GetCoordVarInfo(coordnames[i], cvar);\n\n        vector<string> sdimnames;\n        string         time_dimname;\n\n        bool ok = dccf.GetVarDimNames(coordnames[i], sdimnames, time_dimname);\n        VAssert(ok);\n\n        rc = vdc.SetCompressionBlock(opt.wname, cratios);\n        if (rc < 0) return (1);\n\n        if (cvar.GetUniform()) {\n            rc = vdc.DefineCoordVarUniform(cvar.GetName(), sdimnames, time_dimname, cvar.GetUnits(), cvar.GetAxis(), cvar.GetXType(), false);\n        } else {\n            rc = vdc.DefineCoordVar(cvar.GetName(), sdimnames, time_dimname, cvar.GetUnits(), cvar.GetAxis(), cvar.GetXType(), false);\n        }\n\n        if (rc < 0) { return (1); }\n\n        rc = vdc.CopyAtt(dccf, cvar.GetName());\n        if (rc < 0) { return (1); }\n    }\n\n    DefineMaskVars(dccf, vdc);\n\n    defineMapProjection(dccf, vdc);\n\n    //\n    // Define data variables\n    //\n    for (int d = 0; d < 4; d++) {\n        vector<string> datanames = dccf.DC::GetDataVarNames(d);\n\n        //\n        // 1D coordinates are not blocked\n        //\n        string mywname;\n        bool   compress;\n        if (d < 2) {\n            mywname.clear();\n            compress = false;\n        } else {\n            mywname = opt.wname;\n            compress = true;\n        }\n\n        // Try to compute \"reasonable\" 1D & 2D compression ratios from 3D\n        // compression ratios\n        //\n        vector<size_t> cratios = opt.cratios;\n        for (int i = 0; i < cratios.size(); i++) {\n            size_t c = (size_t)pow((double)cratios[i], (double)((float)d / 3.0));\n            cratios[i] = c;\n        }\n\n        rc = vdc.SetCompressionBlock(mywname, cratios);\n        if (rc < 0) return (1);\n\n        for (int i = 0; i < datanames.size(); i++) {\n            DC::DataVar dvar;\n            dccf.GetDataVarInfo(datanames[i], dvar);\n\n            vector<string> dimnames;\n            bool           ok = dccf.GetVarDimNames(datanames[i], false, dimnames);\n            VAssert(ok);\n\n            vector<string> coordvars;\n            ok = dccf.GetVarCoordVars(datanames[i], false, coordvars);\n            VAssert(ok);\n\n            // Don't compress the variable if it is also a coordinate variable\n            // Compression errors in coordinate variables can lead to\n            // non-conformant meshes\n            //\n            bool doCompress = compress;\n            if (find(coordnames.begin(), coordnames.end(), datanames[i]) != coordnames.end()) { doCompress = false; }\n\n            if (dvar.GetHasMissing() && doCompress) {\n                vector<string> sdimnames;\n                bool           ok = dccf.GetVarDimNames(datanames[i], true, sdimnames);\n                VAssert(ok);\n\n                string maskvar_name;\n                maskvar(sdimnames, maskvar_name);\n\n                rc = vdc.DefineDataVar(dvar.GetName(), dimnames, coordvars, dvar.GetUnits(), dvar.GetXType(), dvar.GetMissingValue(), maskvar_name);\n\n            } else if (dvar.GetHasMissing() && !doCompress) {\n                rc = vdc.DefineDataVar(dvar.GetName(), dimnames, coordvars, dvar.GetUnits(), dvar.GetXType(), dvar.GetMissingValue(), \"\");\n\n\n            } else {\n                rc = vdc.DefineDataVar(dvar.GetName(), dimnames, coordvars, dvar.GetUnits(), dvar.GetXType(), doCompress);\n            }\n\n            if (rc < 0) { return (1); }\n\n            rc = vdc.CopyAtt(dccf, dvar.GetName());\n            if (rc < 0) { return (1); }\n        }\n    }\n\n    rc = vdc.EndDefine();\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Failed to write VDC master file : %s\", master.c_str());\n        return (1);\n    }\n\n    return (0);\n}\n"
  },
  {
    "path": "apps/linuxlauncher/CMakeLists.txt",
    "content": "set (TARGETS\n\tcf2vdc\n\tncdf2wasp\n\ttiff2geotiff\n\tvaporversion\n\tvdccreate\n\twasp2raw\n\twrfvdccreate\n\tcfvdccreate\n\traw2vdc\n\tvapor\n\tvdcdump\n\twaspcreate\n\traw2wasp\n\tvdc2raw\n\twasp2ncdf\n\twrf2vdc\n\tvdccompare\n\tvaporpychecker\n\tvapor_check_udunits\n\t)\n\nappend (LAUNCHER_TARGETS _launcher ${TARGETS})\nset_property (GLOBAL PROPERTY LAUNCHER_TARGETS ${LAUNCHER_TARGETS})\n\nforeach (target ${TARGETS})\n\tset (TARGET_NAME ${target})\n\tconfigure_file (launcher.c ${target}_launcher.c)\n\tadd_executable (\n\t\t${target}_launcher\n\t\t${target}_launcher.c\n\t\t)\n\tset_target_properties(\n\t\t${target}_launcher PROPERTIES\n\t\tRUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launchers\n\t\tOUTPUT_NAME ${target}\n\t\t)\n\tinstall (\n\t\tTARGETS ${target}_launcher \n\t\tDESTINATION ${INSTALL_LAUNCHER_DIR}\n\t\tCOMPONENT Utilites\n\t\t)\nendforeach (target)\n"
  },
  {
    "path": "apps/linuxlauncher/launcher.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <limits.h>\n#include <string.h>\n\nint main(int argc, char **argv)\n{\n    char    path[PATH_MAX];\n    ssize_t rc = readlink(\"/proc/self/exe\", path, PATH_MAX);\n    (void)(rc);    // Remove warning\n\n    char *p = &path[strlen(path) - 1];\n    int   up = 2;\n    while (p != path && up) {\n        if (*p == '/') {\n            *p = 0;\n            up--;\n        }\n        p--;\n    }\n\n#ifndef NDEBUG\n    int debug = 0;\n    if (argc > 1 && !strcmp(\"--launcher-debug\", argv[1])) {\n        debug = 1;\n        argc--;\n        int i;\n        for (i = 1; i < argc; i++) argv[i] = argv[i + 1];\n        argv[argc] = 0;\n    }\n#endif\n\n    setenv(\"VAPOR_HOME\", path, 1);\n\n    strcat(path, \"/lib\");\n    char *oldLibPath = getenv(\"LD_LIBRARY_PATH\");\n    if (!oldLibPath) oldLibPath = \"\";\n    char *newLibPath = malloc(strlen(oldLibPath) + strlen(path) + 2);\n    strcpy(newLibPath, path);\n\n    strcat(newLibPath, \":\");\n    strcat(newLibPath, oldLibPath);\n    setenv(\"LD_LIBRARY_PATH\", newLibPath, 1);\n#ifndef NDEBUG\n    if (debug) printf(\"LD_LIBRARY_PATH=%s\\n\", newLibPath);\n#endif\n    free(newLibPath);\n\n    argv[0] = \"@TARGET_NAME@\";\n\n    strcat(path, \"/@TARGET_NAME@\");\n\n    if (access(path, X_OK) == -1) {\n        fprintf(stderr, \"Failed to run \\\"%s\\\"\\n\", path);\n        exit(1);\n    }\n\n    execv(path, argv);\n    return 0;\n}\n"
  },
  {
    "path": "apps/ncdf2wasp/CMakeLists.txt",
    "content": "add_executable (ncdf2wasp ncdf2wasp.cpp)\n\ntarget_link_libraries (ncdf2wasp common wasp)\n\nOpenMPInstall (\n\tTARGETS ncdf2wasp\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/ncdf2wasp/ncdf2wasp.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cerrno>\n#include <cmath>\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/WASP.h>\n#include <vapor/FileUtils.h>\n#include <vapor/SetHDF5PluginPath.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n//\tCommand line argument stuff\n//\nstruct opt_t {\n    string                  varname;\n    string                  wname;\n    int                     lod;\n    int                     nthreads;\n    std::vector<size_t>     bs;\n    std::vector<size_t>     bs2d;\n    std::vector<size_t>     cratios;\n    std::vector<size_t>     cratios2d;\n    std::vector<string>     xvarnames;\n    std::vector<string>     xdimnames;\n    OptionParser::Boolean_T debug;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"varname\", 1, \"var1\", \"Name of variable\"},\n                                         {\"wname\", 1, \"bior4.4\",\n                                          \"Wavelet family used for compression \"\n                                          \"Valid values are bior1.1, bior1.3, \"\n                                          \"bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, \"\n                                          \"bior3.5, bior3.7, bior3.9, bior4.4\"},\n                                         {\"lod\", 1, \"-1\",\n                                          \"Compression levels saved. 0 => coarsest, 1 => \"\n                                          \"next refinement, etc. -1 => all levels defined by the netcdf file\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"bs\", 1, \"64:64:64\",\n                                          \"Internal storage blocking factor expressed in grid points (NZ:NY:NX) \"\n                                          \"for 3D variables\"},\n                                         {\"bs2d\", 1, \"\",\n                                          \"Internal storage blocking factor expressed in grid points (NZ:NY:NX) \"\n                                          \"for 2D variables. If empty the 2D blocking factor uses the fastest \"\n                                          \"varying dimensions of the 3D blocking factor\"},\n                                         {\"cratios\", 1, \"500:100:10:1\",\n                                          \"Colon delimited list of compression \"\n                                          \"ratios for 3D variables. The default is 500:100:10:1. The maximum \"\n                                          \"compression ratio is wavelet and block size dependent.\"},\n                                         {\"cratios2d\", 1, \"\",\n                                          \"Colon delimited list of compression \"\n                                          \"ratios for 2D variables. If empty the 2D compression ratio vector \"\n                                          \"is calculated from the 3D compression vector.\"},\n                                         {\"xvarnames\", 1, \"\",\n                                          \"Colon delimited list of variable names \"\n                                          \"to exclude from compression.\"},\n                                         {\"xdimnames\", 1, \"\",\n                                          \"Colon delimited list of dimension names \"\n                                          \"to exclude from compression.\"},\n                                         {\"debug\", 0, \"\", \"Enable diagnostic\"},\n                                         {\"quiet\", 0, \"\", \"Operate quietly\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"varname\", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)},\n                                        {\"wname\", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)},\n                                        {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"bs\", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)},\n                                        {\"bs2d\", Wasp::CvtToSize_tVec, &opt.bs2d, sizeof(opt.bs2d)},\n                                        {\"cratios\", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)},\n                                        {\"cratios2d\", Wasp::CvtToSize_tVec, &opt.cratios2d, sizeof(opt.cratios2d)},\n                                        {\"xvarnames\", Wasp::CvtToStrVec, &opt.xvarnames, sizeof(opt.xvarnames)},\n                                        {\"xdimnames\", Wasp::CvtToStrVec, &opt.xdimnames, sizeof(opt.xdimnames)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nconst char *ProgName;\n\n// Return true if string 'name' contained in vector of strings, 'names'\n//\nbool name_in(string name, const vector<string> &names) { return (find(names.begin(), names.end(), name) != names.end()); }\n\n// Given a list of dimemsion names and lengths (dimnames, dimlens) return\n// an ordered subset of the inputs that contains only the dimension\n// names and lenghts that will be compressed.\n//\nvoid get_compressed_dims(const vector<string> &dimnames, const vector<size_t> &dimlens, vector<string> &cdimnames, vector<size_t> &cdimlens)\n{\n    VAssert(dimnames.size() == dimlens.size());\n    cdimnames = dimnames;\n    cdimlens = dimlens;\n\n    // if any excluded dimension names match the **slowest**\n    // varying variable dimension name remove the matched dimension\n    // name.\n    //\n    vector<string>::iterator itr1 = cdimnames.begin();\n    vector<size_t>::iterator itr2 = cdimlens.begin();\n    while (itr1 != cdimnames.end()) {\n        if (name_in(*itr1, opt.xdimnames)) {\n            cdimnames.erase(itr1);\n            itr1 = cdimnames.begin();\n\n            cdimlens.erase(itr2);\n            itr2 = cdimlens.begin();\n        } else {\n            break;\n        }\n    }\n}\n\n// Compute the block size from opt.bs and opt.bs2d based on the number\n// of dimensions\n//\nvector<size_t> get_bs(const vector<string> &dimnames, const vector<size_t> &dims)\n{\n    vector<string> cdimnames;\n    vector<size_t> cdims;\n    get_compressed_dims(dimnames, dims, cdimnames, cdims);\n\n    VAssert(cdims.size() == 2 || cdims.size() == 3);\n\n    if (cdims.size() == 3) return (opt.bs);\n\n    if (cdims.size() == 2 && opt.bs2d.size()) return (opt.bs2d);\n\n    // Compute 2D block sizes from 3D block sizes\n    //\n    vector<size_t> bs = opt.bs;\n    bs.erase(bs.begin());\n    return (bs);\n}\n\n// Compute the compression ratios from opt.cratios and opt.cratios2d\n// based on the number of dimensions\n//\nvector<size_t> get_cratios(const vector<string> &dimnames, const vector<size_t> &dims)\n{\n    vector<string> cdimnames;\n    vector<size_t> cdims;\n    get_compressed_dims(dimnames, dims, cdimnames, cdims);\n\n    VAssert(cdims.size() == 2 || cdims.size() == 3);\n\n    if (cdims.size() == 3) return (opt.cratios);\n\n    if (cdims.size() == 2 && opt.cratios2d.size()) return (opt.cratios2d);\n\n    // Compute 2D compression ratios from 3D compression ratios\n    //\n    vector<size_t> cratios = opt.cratios;\n    for (int i = 0; i < cratios.size(); i++) {\n        double v = cratios[i];\n        v = pow(v, 1.0 / 3.0);\n        cratios[i] = (size_t)(v * v);\n    }\n    return (cratios);\n}\n\n//\n// Define the WASP output file using 'ncdf' as a template\n//\nint DefFile(const NetCDFCpp &ncdf, WASP &wasp)\n{\n    vector<string> dimnames;\n    vector<size_t> dimlens;\n\n    int rc = ncdf.InqDims(dimnames, dimlens);\n    if (rc < 0) return (-1);\n\n    VAssert(dimnames.size() == dimlens.size());\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        rc = wasp.DefDim(dimnames[i], dimlens[i]);\n        if (rc < 0) return (-1);\n    }\n\n    vector<string> attnames;\n    rc = ncdf.InqAttnames(\"\", attnames);\n    if (rc < 0) return (-1);\n\n    for (int i = 0; i < attnames.size(); i++) {\n        rc = ncdf.CopyAtt(\"\", attnames[i], wasp, \"\");\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\n// Get all of the variable names, and based on command line arguments parse\n// the names into a vector of\n// variable names that will be copied verbatim, and a vector of variable\n// names that will be compressed.\n//\n\nint GetVarNames(const NetCDFCpp &ncdf, vector<string> &vars, vector<string> &copy_vars, vector<string> &compress_vars)\n{\n    vars.clear();\n    copy_vars.clear();\n    compress_vars.clear();\n\n    int rc = ncdf.InqVarnames(vars);\n    if (rc < 0) return (-1);\n\n    for (int i = 0; i < vars.size(); i++) {\n        vector<string> dimnames;\n        vector<size_t> dimlens;\n        nc_type        xtype;\n\n        rc = ncdf.InqVarDims(vars[i], dimnames, dimlens);\n        if (rc < 0) return (-1);\n\n        rc = ncdf.InqVartype(vars[i], xtype);\n        if (rc < 0) return (-1);\n\n        // Can only compress 3 different data types\n        //\n        if (!((xtype == NC_FLOAT) || (xtype == NC_DOUBLE) || (xtype == NC_INT))) {\n            copy_vars.push_back(vars[i]);\n            continue;\n        }\n\n        // Excluded variable names requested via command line\n        //\n        if (name_in(vars[i], opt.xvarnames)) {\n            copy_vars.push_back(vars[i]);\n            continue;\n        }\n\n        // if any excluded dimension names match the **slowest**\n        // varying variable dimension name remove the matched dimension\n        // name.\n        //\n        get_compressed_dims(dimnames, dimlens, dimnames, dimlens);\n\n        if (!((dimnames.size() == 2) || (dimnames.size() == 3))) {\n            copy_vars.push_back(vars[i]);\n            continue;\n        }\n\n        // If we get this far the variable can be compressed\n        //\n        compress_vars.push_back(vars[i]);\n    }\n\n    return (0);\n}\n\n// Copy variables verbatim from 'ncdf' to 'wasp'\n//\nint CopyVars(const NetCDFCpp &ncdf, const vector<string> &copy_vars, WASP &wasp)\n{\n    for (int i = 0; i < copy_vars.size(); i++) {\n        if (!opt.quiet) { cout << \"Copying variable \" << copy_vars[i] << endl; }\n        int rc = ncdf.CopyVar(copy_vars[i], wasp);\n        if (rc < 0) return (-1);\n    }\n    return (0);\n}\n\n// Define a variable that will not be compressed (i.e copied verbatim)\n//\nint DefCopyVar(const NetCDFCpp &ncdf, string varname, NetCDFCpp &wasp)\n{\n    vector<string> dimnames;\n    vector<size_t> dimlens;\n    int            rc = ncdf.InqVarDims(varname, dimnames, dimlens);\n    if (rc < 0) return (-1);\n\n    nc_type xtype;\n    rc = ncdf.InqVartype(varname, xtype);\n    if (rc < 0) return (-1);\n\n    rc = wasp.DefVar(varname, xtype, dimnames);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\n// Define a variable that will be compressed\n//\nint DefCompressVar(const NetCDFCpp &ncdf, string varname, WASP &wasp)\n{\n    vector<string> dimnames;\n    vector<size_t> dimlens;\n    int            rc = ncdf.InqVarDims(varname, dimnames, dimlens);\n    if (rc < 0) return (-1);\n\n    nc_type xtype;\n    rc = ncdf.InqVartype(varname, xtype);\n    if (rc < 0) return (-1);\n\n    vector<size_t> bs = get_bs(dimnames, dimlens);\n    vector<size_t> cratios = get_cratios(dimnames, dimlens);\n    rc = wasp.DefVar(varname, xtype, dimnames, opt.wname, bs, cratios);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\n// Define all variables in 'wasp', preserving the variable order\n// in 'ncdf'\n//\nint DefVars(const NetCDFCpp &ncdf, const vector<string> &vars, const vector<string> &copy_vars, const vector<string> &comp_vars, WASP &wasp)\n{\n    int rc;\n    for (int i = 0; i < vars.size(); i++) {\n        if (name_in(vars[i], copy_vars)) {\n            rc = DefCopyVar(ncdf, vars[i], wasp);\n            if (rc < 0) return (-1);\n        } else if (name_in(vars[i], comp_vars)) {\n            rc = DefCompressVar(ncdf, vars[i], wasp);\n            if (rc < 0) return (-1);\n        } else {\n            continue;\n        }\n        // Now copy variable attributes\n        //\n        vector<string> attnames;\n        rc = ncdf.InqAttnames(vars[i], attnames);\n        if (rc < 0) return (-1);\n\n        for (int j = 0; j < attnames.size(); j++) {\n            rc = ncdf.CopyAtt(vars[i], attnames[j], wasp, vars[i]);\n            if (rc < 0) return (-1);\n        }\n    }\n    return (0);\n}\n\n// Compress variables\n//\nint CompressVars(NetCDFCpp &ncdf, const vector<string> &copy_vars, WASP &wasp)\n{\n    for (int i = 0; i < copy_vars.size(); i++) {\n        if (!opt.quiet) { cout << \"Compressing  variable \" << copy_vars[i] << endl; }\n        int rc = wasp.CopyVarFrom(copy_vars[i], ncdf);\n        if (rc < 0) return (-1);\n    }\n    return (0);\n}\n\nvoid Process(string ncdffile, string waspfile)\n{\n    NetCDFCpp ncdf;\n    WASP      wasp;\n    size_t    chunksize = 1024 * 1024 * 4;\n\n    int rc = ncdf.Open(ncdffile, NC_NOWRITE);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Error opening %s for reading\", ncdffile.c_str());\n        exit(1);\n    }\n\n    rc = wasp.Create(waspfile, NC_64BIT_OFFSET, 0, chunksize, opt.cratios.size());\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Error opening %s for writing\", waspfile.c_str());\n        exit(1);\n    }\n\n    rc = DefFile(ncdf, wasp);\n    if (rc < 0) exit(1);\n\n    vector<string> vars, copy_vars, compress_vars;\n    rc = GetVarNames(ncdf, vars, copy_vars, compress_vars);\n    if (rc < 0) exit(1);\n\n    rc = DefVars(ncdf, vars, copy_vars, compress_vars, wasp);\n    if (rc < 0) exit(1);\n\n    rc = wasp.EndDef();\n    if (rc < 0) exit(1);\n\n    rc = CopyVars(ncdf, copy_vars, wasp);\n    if (rc < 0) exit(1);\n\n    rc = CompressVars(ncdf, compress_vars, wasp);\n    if (rc < 0) exit(1);\n\n    (void)ncdf.Close();\n    rc = wasp.Close();\n    if (rc < 0) exit(1);\n}\n\nint main(int argc, char **argv)\n{\n    VAPoR::SetHDF5PluginPath();\n\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { exit(1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] netcdffile waspfile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (argc != 3) {\n        cerr << \"Usage: \" << ProgName << \" [options] netcdffile waspfile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    string ncdffile = argv[1];    // Path to a vdf file\n    string waspfile = argv[2];    // Path to wasp file\n\n    if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr);\n\n    Process(ncdffile, waspfile);\n\n    return (0);\n}\n"
  },
  {
    "path": "apps/pythonapi/CMakeLists.txt",
    "content": "message(\"Python Found: '${Python_VERSION}' (${Python_LIBRARIES})\")\n\nSET(PYTHON_API_DIR ${CMAKE_BINARY_DIR}/python)\n\n# CMake does not have proper support for copying files and its scripting language does not make adding it easy.\n\nfunction(COPY_HELPER FILE DESTINATION DEP_LIST)\n    get_filename_component(BASENAME \"${FILE}\" NAME)\n    if (\"${BASENAME}\" IN_LIST COPY_EXCLUDE)\n        return()\n    endif()\n    if (IS_DIRECTORY \"${FILE}\")\n        file(GLOB SUBFILES \"${FILE}/*\")\n        foreach (SUBFILE ${SUBFILES})\n            COPY_HELPER(\"${SUBFILE}\" \"${DESTINATION}/${BASENAME}\" \"${DEP_LIST}\")\n        endforeach()\n    else()\n        set(OUTFILE \"${DESTINATION}/${BASENAME}\")\n        add_custom_command(\n            OUTPUT \"${OUTFILE}\"\n            COMMAND ${CMAKE_COMMAND} -E copy \"${FILE}\" \"${OUTFILE}\"\n            MAIN_DEPENDENCY \"${FILE}\"\n            )\n        list(APPEND DEP_LIST \"${OUTFILE}\")\n        # of course this does not work for custom targets\n        # add_dependencies(target ${OUTFILE})\n    endif()\n    set(DEP_LIST \"${DEP_LIST}\" PARENT_SCOPE)\nendfunction()\n\nset_property(GLOBAL PROPERTY COPY_HELPER_TARGET_COUNTER_PROPERTY \"0\")\n\nfunction(COPY FILE DESTINATION)\n    include(CMakeParseArguments)\n    cmake_parse_arguments(PARSE_ARGV 2\n        \"COPY\"\n        \"\"\n        \"\"\n        \"EXCLUDE\"\n        )\n\n    get_filename_component(FILE \"${FILE}\" REALPATH)\n\n    list(APPEND DEP_LIST \"\")\n    COPY_HELPER(\"${FILE}\" \"${DESTINATION}\" \"${DEP_LIST}\")\n\n    get_property(COPY_HELPER_TARGET_COUNTER GLOBAL PROPERTY COPY_HELPER_TARGET_COUNTER_PROPERTY)\n    math(EXPR COPY_HELPER_TARGET_COUNTER \"${COPY_HELPER_TARGET_COUNTER}+1\")\n    set_property(GLOBAL PROPERTY COPY_HELPER_TARGET_COUNTER_PROPERTY ${COPY_HELPER_TARGET_COUNTER})\n\n    add_custom_target(\n        copy_helper_${COPY_HELPER_TARGET_COUNTER}\n        ALL\n        DEPENDS ${DEP_LIST}\n    )\nendfunction()\n\n\ncopy(vapor ${PYTHON_API_DIR} EXCLUDE cmake.py __pycache__ widget.js jquery.js)\ncopy(setup.py ${PYTHON_API_DIR})\ncopy(example_scripts ${PYTHON_API_DIR} EXCLUDE CMakeLists.txt)\nadd_subdirectory (example_scripts)\n\nadd_custom_command(\n    OUTPUT \"${PYTHON_API_DIR}/vapor/widget.js\"\n    COMMAND esbuild --log-level=warning --format=esm \"${CMAKE_CURRENT_SOURCE_DIR}/vapor/widget.js\" --bundle --outfile=\"${PYTHON_API_DIR}/vapor/widget.js\"\n    MAIN_DEPENDENCY \"${CMAKE_CURRENT_SOURCE_DIR}/vapor/widget.js\"\n)\nadd_custom_target(\n    widget_js\n    ALL\n    DEPENDS \"${PYTHON_API_DIR}/vapor/widget.js\"\n)\n\n# copy(bld.bat ${PYTHON_API_DIR})\n# copy(build.sh ${PYTHON_API_DIR})\n# configure_file (meta.yaml ${PYTHON_API_DIR}/meta.yaml)\n\n# get_target_property(VAPI_PRIVATE_COMPILE_DEFS vapi COMPILE_DEFINITIONS)\nget_target_property(VAPI_COMPILE_DEFS vapi INTERFACE_COMPILE_DEFINITIONS)\nget_property(GLOBAL_COMPILE_DEFS DIRECTORY PROPERTY COMPILE_DEFINITIONS)\n# These don't quite work\n# get_target_property(VAPI_DEFS vapi COMPILE_DEFINITIONS)\n# get_target_property(VAPI_INT_DEFS vapi INTERFACE_COMPILE_DEFINITIONS)\n# get_property(DIR_DEFS DIRECTORY PROPERTY COMPILE_DEFINITIONS)\n\nconfigure_file (cmake.py ${PYTHON_API_DIR}/cmake.py)\nconfigure_file (vapor/cmake.py ${PYTHON_API_DIR}/vapor/cmake.py)\n\n\nif (CONDA_BUILD)\n    set(CONDA_SITE_PACKAGE_DIR \"$ENV{SP_DIR}\")\n    install(\n        DIRECTORY \"${PYTHON_API_DIR}/vapor\"\n\t\tDESTINATION \"${CONDA_SITE_PACKAGE_DIR}\"\n\t\tCOMPONENT Dependencies\n\t)\nendif()\n\n# Fails to find either despite both being installed\n# list(APPEND CMAKE_MODULE_PATH \"/usr/local/Caskroom/miniconda/base/envs/test/lib/python3.9/site-packages/cppyy_backend/cmake\")\n# find_package (LibClang REQUIRED)\n# find_package (Cppyy REQUIRED)\n\n"
  },
  {
    "path": "apps/pythonapi/cmake.py",
    "content": "from pathlib import Path\n\nVERSION_RC          = \"@VERSION_RC@\"\nVERSION_DATE        = \"@VERSION_DATE@\"\nVERSION_COMMIT      = \"@VERSION_COMMIT@\"\nVERSION_STRING      = \"@VERSION_STRING@\"\nVERSION_STRING_FULL = \"@VERSION_STRING_FULL@\"\n\nBUILD_TYPE          = \"@CMAKE_BUILD_TYPE@\"\nSOURCE_DIR          = \"@PROJECT_SOURCE_DIR@\"\nBINARY_DIR          = \"@CMAKE_BINARY_DIR@\"\nTHIRD_PARTY_DIR     = \"@THIRD_PARTY_DIR@\"\n\nPYTHON_VERSION      = \"@PYTHONVERSION@\"\nPYTHON_DIR          = \"@PYTHONDIR@\"\nPYTHON_PATH         = \"@PYTHONPATH@\"\n\nSYSTEM_NAME = \"@CMAKE_SYSTEM_NAME@\"\n\nPYTHON_API_SOURCE_DIR = \"@CMAKE_CURRENT_SOURCE_DIR@\"\n\n#These do not work\nCPACK_TOPLEVEL_DIR  = \"@CPACK_TOPLEVEL_DIRECTORY@\"\nCPACK_TEMPORARY_DIR = \"@CPACK_TEMPORARY_DIRECTORY@\"\n\nCPACK_INSTALLER_NAME = \"@PROJECT_NAME@-@VERSION_STRING@-@CMAKE_SYSTEM_NAME@\"\nCPACK_STAGING_DIR   = f\"{BINARY_DIR}/_CPack_Packages/{SYSTEM_NAME}/External/{CPACK_INSTALLER_NAME}\"\n\n\n\npkg = \"@CPACK_PACKAGE_NAME@\"\npk2g = \"@CPACK_PACKAGE_FILE_NAME@\"\nPROJECT_NAME = \"@PROJECT_NAME@\"\nCPACK_PACKAGE_VERSION = \"@CPACK_PACKAGE_VERSION@\"\n\n\nfor n in ['BINARY_DIR', 'PYTHON_API_SOURCE_DIR', 'CPACK_STAGING_DIR']:\n    f = eval(n)\n    if Path(f).exists():\n        print(f\"{n} OK {f}\")\n    else:\n        print(f\"{n} NOT FOUND {f}\")\n        assert 0\n\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/CMakeLists.txt",
    "content": "set(ALL_NOTEBOOKS \"\")\nset(ALL_MARIMO_NOTEBOOKS \"\")\n\nfunction(NOTEBOOK FILE OUT)\n    include(CMakeParseArguments)\n    cmake_parse_arguments(PARSE_ARGV 2\n        \"NOTEBOOK\"\n        \"\"\n        \"\"\n        \"\"\n        )\n\n    get_filename_component(FILE \"${FILE}\" REALPATH)\n\n    add_custom_command(\n        OUTPUT \"${OUT}\"\n        DEPENDS \"${FILE}\"\n        COMMAND cat \"${FILE}\" | jupytext --to ipynb > \"${OUT}\"\n        )\n\n    list(APPEND ALL_NOTEBOOKS \"${OUT}\")\n    set(ALL_NOTEBOOKS \"${ALL_NOTEBOOKS}\" PARENT_SCOPE)\nendfunction()\n\n\nfunction(CONV_MARIMO FILE OUT)\n    include(CMakeParseArguments)\n    cmake_parse_arguments(PARSE_ARGV 2\n        \"CONV_MARIMO\"\n        \"\"\n        \"\"\n        \"\"\n        )\n\n    get_filename_component(FILE \"${FILE}\" REALPATH)\n\n    add_custom_command(\n        OUTPUT \"${OUT}\"\n        DEPENDS \"${FILE}\"\n        COMMAND marimo -q -y convert \"${FILE}\" -o \"${OUT}\"\n        )\n\n    list(APPEND ALL_MARIMO_NOTEBOOKS \"${OUT}\")\n    set(ALL_MARIMO_NOTEBOOKS \"${ALL_MARIMO_NOTEBOOKS}\" PARENT_SCOPE)\nendfunction()\n\n\n# copy(vapor ${PYTHON_API_DIR} EXCLUDE cmake.py __pycache__)\n# copy(setup.py ${PYTHON_API_DIR})\n\nfind_program(JUPYTEXT \"jupytext\")\nif (JUPYTEXT)\n    set(EXAMPLE_NOTEBOOK_OUT_DIR \"${PYTHON_API_DIR}/example_jupyter_notebooks\")\n    file(MAKE_DIRECTORY ${EXAMPLE_NOTEBOOK_OUT_DIR})\n\n    copy(example_utils.py                 ${EXAMPLE_NOTEBOOK_OUT_DIR})\n    notebook(numpy_example.py             ${EXAMPLE_NOTEBOOK_OUT_DIR}/numpy_example.ipynb)\n    notebook(xarray_example.py            ${EXAMPLE_NOTEBOOK_OUT_DIR}/xarray_example.ipynb)\n    notebook(dataset_example.py           ${EXAMPLE_NOTEBOOK_OUT_DIR}/dataset_example.ipynb)\n    notebook(flow_example.py              ${EXAMPLE_NOTEBOOK_OUT_DIR}/flow_example.ipynb)\n    notebook(annotation_example.py        ${EXAMPLE_NOTEBOOK_OUT_DIR}/annotation_example.ipynb)\n    notebook(camera_example.py            ${EXAMPLE_NOTEBOOK_OUT_DIR}/camera_example.ipynb)\n    notebook(transfer_function_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/transfer_function_example.ipynb)\n    notebook(workflow_example.py          ${EXAMPLE_NOTEBOOK_OUT_DIR}/workflow_example.ipynb)\n    notebook(animation_example.py         ${EXAMPLE_NOTEBOOK_OUT_DIR}/animation_example.ipynb)\n    notebook(visualizer_widget_example.py ${EXAMPLE_NOTEBOOK_OUT_DIR}/visualizer_widget_example.ipynb)\n    notebook(rotate_video.py              ${EXAMPLE_NOTEBOOK_OUT_DIR}/rotate_video.ipynb)\n\n    add_custom_target(\n        example_notebooks\n        ALL\n        DEPENDS ${ALL_NOTEBOOKS}\n    )\nelse()\n    message(WARNING \"jupytext not found\")\n    message(WARNING \"Skipping generation of jupyter notebooks\")\nendif()\n\nfind_program(MARIMO \"marimo\")\nif (JUPYTEXT AND MARIMO)\n    set(EXAMPLE_MARIMO_OUT_DIR \"${PYTHON_API_DIR}/example_marimo_notebooks\")\n    file(MAKE_DIRECTORY ${EXAMPLE_MARIMO_OUT_DIR})\n\n    copy(example_utils.py                                                   ${EXAMPLE_MARIMO_OUT_DIR})\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/numpy_example.ipynb             ${EXAMPLE_MARIMO_OUT_DIR}/numpy_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/xarray_example.ipynb            ${EXAMPLE_MARIMO_OUT_DIR}/xarray_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/dataset_example.ipynb           ${EXAMPLE_MARIMO_OUT_DIR}/dataset_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/flow_example.ipynb              ${EXAMPLE_MARIMO_OUT_DIR}/flow_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/annotation_example.ipynb        ${EXAMPLE_MARIMO_OUT_DIR}/annotation_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/camera_example.ipynb            ${EXAMPLE_MARIMO_OUT_DIR}/camera_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/transfer_function_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/transfer_function_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/workflow_example.ipynb          ${EXAMPLE_MARIMO_OUT_DIR}/workflow_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/animation_example.ipynb         ${EXAMPLE_MARIMO_OUT_DIR}/animation_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/visualizer_widget_example.ipynb ${EXAMPLE_MARIMO_OUT_DIR}/visualizer_widget_example.py)\n    conv_marimo(${EXAMPLE_NOTEBOOK_OUT_DIR}/rotate_video.ipynb              ${EXAMPLE_MARIMO_OUT_DIR}/rotate_video.py)\n\n    add_custom_target(\n        example_marimo_notebooks\n        ALL\n        DEPENDS ${ALL_MARIMO_NOTEBOOKS}\n    )\nelse()\n    message(WARNING \"marimo (or jupytext) not found\")\n    message(WARNING \"Skipping generation of marimo notebooks\")\nendif()\n\nif (CONDA_BUILD)\n    set(CONDA_SITE_PACKAGE_DIR \"$ENV{SP_DIR}\")\n    install(\n        DIRECTORY \"${PYTHON_API_DIR}/example_scripts\"\n\t\tDESTINATION \"${CONDA_SITE_PACKAGE_DIR}/vapor\"\n\t\tCOMPONENT Dependencies\n\t)\n    if (JUPYTEXT)\n        install(\n            DIRECTORY \"${EXAMPLE_NOTEBOOK_OUT_DIR}\"\n\t\t    DESTINATION \"${CONDA_SITE_PACKAGE_DIR}/vapor\"\n\t\t    COMPONENT Dependencies\n\t    )\n    endif()\nendif()\n\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/animation_example.py",
    "content": "# %% [md]\n#\n# # Creating Animations\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\nfrom vapor.animation import Animation\n\n# %%\nses = session.Session()\ndata = example_utils.OpenExampleDataset(ses)\ndimension = 2\nU,V = data.GetDataVarNames(dimension)[0:2]\n\nren:renderer.FlowRenderer = data.NewRenderer(renderer.FlowRenderer)\nren.SetFieldVariableNames([U, V])\nses.GetCamera().ViewAll()\nren.SetRenderType(ren.RenderType.RenderTypeStream)\nren.SetRenderRadiusScalar(3)\nren.SetRenderGeom3D(True)\nren.SetColorMapVariableName(U)\n# ses.Show()\n\n# %%\nanim = Animation(ses)\nfor i in range(0, 200, 2):\n    ren.SetSteadyNumOfSteps(i)\n    anim.CaptureFrame()\n    print(f\"Rendering Animation [{'#'*round(i/5)}{' '*round(40-i/5)}] {(i+1)/2:.0f}%\", end=\"\\r\")\nanim.Show()\n\n# %%\nanim.ShowInteractive()\n\n# %%\nanim.SaveMP4(\"test.mp4\")\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/annotation_example.py",
    "content": "# %% [md]\n#\n# # Annotations\n#\n# You can annotate your renderings using Vapor's build in annotations as well as MatPlotLib\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\nfrom vapor.utils import histogram\n\nses = session.Session()\ndata = example_utils.OpenExampleDataset(ses)\n\nren = data.NewRenderer(renderer.TwoDDataRenderer)\nren.SetVariableName(data.GetDataVarNames(2)[1])\nses.GetCamera().ViewAll()\n\n# %% [md]\n#\n# ## Vapor Colorbars\n#\n# %%\n# Show the basic colorbar annotation for a renderer\ncolorbar = ren.GetColorbarAnnotation()\ncolorbar.SetEnabled(True)\nses.Show()\n\n# %%\n# Customized colorbar annotation\ncolorbar.SetSize((0.2, 0.25))\ncolorbar.SetTitle(\"Colorbar Title\")\ncolorbar.SetCornerPosition((0.95, 0.95))\nses.Show()\n\n# %% [md]\n#\n# ## MatPlotLib Colorbars\n#\n# You can customize the histograms as you would MatPlotLib's `pylab.colorbar`\n#\n# %%\ntf = ren.GetPrimaryTransferFunction()\ntf.ShowMatPlotLibColorbar()\n\n# %%\ntf.ShowMatPlotLibColorbar(orientation=\"vertical\", figsize=(1.5,4))\n\n# %%\n# The MatPlotLib Colorbars are automatically synced to Vapor's transfer functions\ntf.LoadBuiltinColormap(tf.ListBuiltinColormaps()[7])\nses.Show()\ntf.ShowMatPlotLibColorbar()\n\n# %%\ncolorbar.SetEnabled(False)\n\n# %% [md]\n#\n# ## MatPlotLib Histograms\n#\n# %%\nhistogram.ShowMatPlotLibHistogram(ses, ren)\n\n# %% [md]\n# ---\n# You can customize the histograms as you would `matplotlib.pyplot.hist`\n#\n# %%\nplt = histogram.GetMatPlotLibHistogram(ses, ren, color =\"red\")\nplt.xlabel(\"X-Axis\")\nplt.ylabel(\"Y-Axis\")\nplt.title(\"Title\\n\", fontweight=\"bold\")\nplt.show()\n\n# %% [md]\n#\n# ## Axis Annotations\n#\n# %%\naxis = ses.GetAxisAnnotations()\naxis.SetAxisAnnotationEnabled(True)\nses.Show()\n\n# %%\naxis.SetNumTics((5,5))\naxis.SetAxisFontSize(24)\nses.Show()\n\n# This example dataset is not geo-referenced\n# axis.SetLatLonAxesEnabled(True)\n\n# %%\naxis.SetAxisAnnotationEnabled(False)\n\n# %% [md]\n#\n# ## Scene Annotations\n#\n# Scene annotations are other annotations and rendering options that apply to the entire rendering such as background color.\n#\n# %%\nscene = ses.GetSceneAnnotations()\nscene.SetBackgroundColor((1,1,1))\nscene.SetUseDomainFrame(False)\nses.Show()\n\n# %%\nscene.SetAxisArrowEnabled(True)\nscene.SetAxisArrowSize(0.4)\n\nscene.SetTimeType(scene.TimeAnnotationType.Timestep)\nscene.SetTimeColor((0,0,0))\nscene.SetTimeLLX(0.7)\n\nses.Show()"
  },
  {
    "path": "apps/pythonapi/example_scripts/camera_example.py",
    "content": "# %% [md]\n#\n# # Controlling the Camera\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\n\nses = session.Session()\ndata = example_utils.OpenExampleDataset(ses)\n\nren = data.NewRenderer(renderer.VolumeIsoRenderer)\nren.SetIsoValues([-0.10, 0.2])\n\n# Show 3D orientation arrows.\nses.GetSceneAnnotations().SetAxisArrowEnabled(True)\n\n# %%\ncam = ses.GetCamera()\n\n# %%\nhelp(cam.ViewAll)\ncam.ViewAll()\nses.Show()\n\n# %%\nhelp(cam.AlignView)\ncam.AlignView(\"-X\")\nses.Show()\n\n# %%\nhelp(cam.Zoom)\ncam.Zoom(-0.4)\nses.Show()\n\n# %%\nhelp(cam.LookAt)\ncam.LookAt((32, -100, 100), ren.GetTransform().GetOrigin())\nses.Show()\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/dataset_example.py",
    "content": "# %% [md]\n#\n# # Opening Datasets\n#\n# Vapor supports a variety of scientific data formats.\n# This notebook shows how to open a dataset and query its metadata.\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\n\n# %%\nprint(\"Supported dataset types:\", dataset.Dataset.GetDatasetTypes())\n\n# %%\nses = session.Session()\ndata = example_utils.OpenExampleDataset(ses)\n\n# Examples of opening real data\n#\n# data = ses.OpenDataset(dataset.WRF, [\"data/wrf_out.0001\", \"data/wrf_out.0002\"])\n# data = ses.OpenDataset(dataset.VDC, [\"master.vdc\"])\n# data = ses.OpenDataset(dataset.MPAS, [\"x1.static.nc\", \"diag.2021-03-04_10.30.00.nc\"])\n\n# %% [md]\n#\n# ## Dump the dataset metadata\n#\n# %%\nprint(\"Time Coordinate Variable Name:\", data.GetTimeCoordVarName())\nprint(\"Coordinate Variable Names:\", data.GetCoordVarNames())\n\nprint(\"Dimensions:\")\nfor dim in data.GetDimensionNames():\n    print(f\"  {dim}:\", data.GetDimensionLength(dim, 0))\n\nprint(\"Data Variables:\")\nfor var in data.GetDataVarNames():\n    print(f\"  {var}\")\n    print(f\"    Time Varying:\", bool(data.IsTimeVarying(var)))\n    print(f\"    Dimensionality:\", data.GetVarGeometryDim(var))\n    print(f\"    Coordinates:\", data.GetVarCoordVars(var, True))\n    print(\"     Data Range:\", data.GetDataRange(var))\n\n# %% [md]\n#\n# ## Render the first 2D variable as a wireframe\n#\n# %%\nren = data.NewRenderer(renderer.WireFrameRenderer)\nren.SetVariableName(data.GetDataVarNames(2)[0]) # Set to first 2D data variable\n\nses.GetCamera().ViewAll()\nses.Show()\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/example_utils.py",
    "content": "\n###########################################################\n#                       NOTICE\n#\n# This is a utility file for running tests from source and\n# can be ignored when normally using vapor\n#\n###########################################################\n\ntry:\n    import vapor\nexcept ImportError:\n    import sys\n    sys.path.append('..')\n\n\nfrom inspect import signature\nimport numpy as np\nfrom math import sin\n\ndef SampleFunctionOnRegularGrid(f, ext=None, shape=None):\n    if not shape: shape = [64]*len(signature(f).parameters)\n    if not ext: ext = [(0,1)]*len(signature(f).parameters)\n    assert len(signature(f).parameters) == len(shape) and len(shape) == len(ext)\n    d = []\n    for i in np.ndindex(*(shape)):\n        d.append(f(*[v/s*(t-f)+f for v,s,(f,t) in zip(reversed(i), shape, ext)]))\n    return np.asarray(d, dtype=np.float32).reshape(shape)\n\n\ndef OpenExampleDataset(session):\n    data = session.CreatePythonDataset()\n    data.AddNumpyData(\"U10\", SampleFunctionOnRegularGrid(lambda x, y: sin(6 * x) + sin(6 * y)))\n    data.AddNumpyData(\"V10\", SampleFunctionOnRegularGrid(lambda x, y: (x + y) * np.exp(-5.0 * (x ** 2 + y ** 2)), ext=[(-1, 1)] * 2))\n    data.AddNumpyData(\"V\", SampleFunctionOnRegularGrid(lambda x, y, z: (x + y + z) * np.exp(-5.0 * (x ** 2 + y ** 2 + z ** 2)), ext=[(-1, 1)] * 3))\n    return data"
  },
  {
    "path": "apps/pythonapi/example_scripts/flow_example.py",
    "content": "# %% [md]\n#\n# # Advecting Flow Paths\n#\n# Vapor can advect and render flow paths through your data.\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\n\nses = session.Session()\ndata = example_utils.OpenExampleDataset(ses)\n\n# %% [md]\n#\n# ## Default advection\n#\n# When you create a Flow renderer, the default advection will create a regularly dispersed grid of seed points and simulate a streamline advection in 2D or 3D, depending on the provided variables.\n#\n# %%\n# Use first 2 2D variables as our U,V for the flow advection\ndimension = 2\nU,V = data.GetDataVarNames(dimension)[0:2]\n\nren:renderer.FlowRenderer = data.NewRenderer(renderer.FlowRenderer)\nren.SetFieldVariableNames([U, V])\nses.GetCamera().ViewAll()\nses.Show()\n\n# %% [md]\n#\n# ## Rendering techniques\n#\n# The rendering of the flow paths can be configured. A few examples are shown below.\n# Call help(renderer.FlowRenderer) to see additional options.\n#\n# %%\nren.SetRenderType(ren.RenderType.RenderTypeStream)\nren.SetRenderRadiusScalar(3)\nren.SetRenderGeom3D(True)\nren.SetColorMapVariableName(U)\nses.Show()\n\n# %% [md]\n#\n# Rather than rendering the flow lines, you can also render the sample points that are taken along the flow path individually.\n#\n# %%\nren.SetRenderType(ren.RenderType.RenderTypeSamples)\nses.Show()\n\n# %%\nren.SetRenderGlyphType(ren.GlpyhType.GlpyhTypeArrow)\nren.SetRenderRadiusScalar(7)\nses.Show()\n\n# %%\n# Reset the rendering style for the next section\nren.SetRenderRadiusScalar(3)\nren.SetRenderType(ren.RenderType.RenderTypeStream)\n\n# %% [md]\n#\n# ## Seeding the advection\n#\n# The seeds from which the advected particles start can be configured in a variety of manners.\n# Call help(renderer.FlowRenderer) to see additional options.\n#\n\n# %% [md]\n#\n# ### Uniform Distribution\n#\n# This is the default. It creates a uniformly distributed grid of seed points over the area/volume of the advected region.\n#\n# %%\nren.SetSeedGenMode(ren.FlowSeedMode.UNIFORM)\nrake = ren.GetRakeRegion()\ndefaultRakeExtents = rake.GetExtents()\nrake.SetExtents((20, 20), (40, 40))\nprint(f\"Seeding a {ren.GetGridNumOfSeeds()} grid over {rake.GetExtents()}\")\nses.Show()\nrake.SetExtents(*defaultRakeExtents)\n\n# %% [md]\n#\n# ### Random Distribution\n#\n# %%\nren.SetSeedGenMode(ren.FlowSeedMode.RANDOM)\nprint(f\"Seeding {ren.GetRandomNumOfSeeds()} random points over {rake.GetExtents()}\")\nses.Show()\n\n# %% [md]\n#\n# ### Biased Distribution\n#\n# This generates a random list of seed points however they are biased by a given variable.\n# The number of seed points can be higher or lower based on the value of the `RakeBiasVariable`.\n# You can set the `RakeBiasStrength` to a negative value to invert the bias.\n#\n# %%\nren.SetSeedGenMode(ren.FlowSeedMode.RANDOM_BIAS)\nren.SetRakeBiasVariable(V)\nren.SetRakeBiasStrength(1)\nprint(f\"Seeding {ren.GetRandomNumOfSeeds()} random points biased by {ren.GetRakeBiasVariable()} over {rake.GetExtents()}\")\nses.Show()\n\n# %% [md]\n#\n# ### Manual List\n#\n# You can pass in a manually created list of seeds using a basic text file format.\n# The code below generates an example seed file and passes it to Vapor.\n# The full documentation for the seed file format can be found on Vapor's website.\n#\n# %%\nwith open(\"flow_seeds.txt\", \"w\") as f:\n    print(\"# X, Y, Z, T (optional)\", file=f)\n    print(\"10, 10, 0\", file=f)\n    print(\"20, 20, 0\", file=f)\n\nren.SetSeedGenMode(ren.FlowSeedMode.LIST)\nren.SetSeedInputFilename(\"flow_seeds.txt\")\nses.Show()\n\n# %% [md]\n#\n# ### Outputting Flow Lines\n#\n# The advected flow lines can be saved to a .csv file\n#\n# %%\nren.SetFlowlineOutputFilename(\"flow_output.csv\") # Needs to be set once per renderer\nren.SetFlowOutputMoreVariables([U, V]) # Optionally specify additional variables to sample at each point\n\nren.SetNeedFlowlineOutput(True) # Needs to be called before each render call that should output the computed flow in a .csv file\n_ = ses.RenderToImage() # This returns a PIL image variable that is not displayed by default and can be ignored if only saving flow output\n\n# %%\nimport pandas as pd\npd.read_csv(\"flow_output.csv\", sep=\",\").head(10)\n\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/numpy_example.py",
    "content": "# %% [md]\n#\n# # Rendering Numpy data with Vapor\n#\n# Vapor supports rendering 2D and 3D numpy data.\n# In order to pass Numpy data to Vapor, create a data set of the type `vapor.dataset.PYTHON`\n# This can also be done with the convenience function `Session.CreatePythonDataset()`.\n# You can add numpy arrays as variables to that dataset by using `Dataset.AddNumpyData`.\n#\n# These variables can then be rendered normally using any of Vapor's renderers.\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\nimport numpy as np\nfrom math import sqrt\n\nses = session.Session()\ndata = ses.CreatePythonDataset()\n\n# %%\n\n# Create a 2D numpy array and add it to vapor's dataset\n\nnp_array = example_utils.SampleFunctionOnRegularGrid(\n    lambda x,y: abs(sqrt((x-0.5)**2+(y-0.5)**2)-0.4)<0.02 or y,\n    shape=(64,65)\n)\n\ndata.AddNumpyData(\"variable_name\", np_array)\n\nprint(np_array)\n\n# %%\n\n# Create a renderer for the data\n\nren = data.NewRenderer(renderer.TwoDDataRenderer)\nren.SetVariableName(\"variable_name\")\n\n# %%\n\n# Show the rendering\n\nses.GetCamera().ViewAll()\nses.Show()\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/rotate_video.py",
    "content": "# %% [md]\n#\n# # Rotate Video\n#\n# This script will render an animated rotating view of your session file.\n# \n# Also requires the `scipy` package.\n#\n# %%\nimport example_utils\nimport cv2, os\nfrom vapor import session, animation\nfrom numpy import cross, eye, dot, radians, asarray, array\nfrom scipy.linalg import expm, norm\nUseValueFromSessionFile = None\n\n# %% [md]\n#\n# ## Configuration\n#\n# %%\nsession_path = \"/path/to/session.vs3\"\noutput = \"animation.mp4\"\nvideo_framerate = 30\nvideo_resolution = (640, 480)\ndata_timestep_framerate = 6  # set to zero to disable\nduration = 4  # seconds\nrotate_speed = 90  # deg/s\nrotation_axis = [0,0,1]  # Z (up)\nrotation_center = UseValueFromSessionFile  # Can be replaced with [x,y,z] coordinates here\nsave_individual_frames = False\n\n# %% ---------------------------------------------------------------------------------------\nsession_path, output = [os.path.expanduser(p) for p in (session_path, output)]\nn_frames = video_framerate * duration\n\nses = session.Session()\nses.Load(session_path)\nses.SetResolution(*video_resolution)\ncam = ses.GetCamera()\npos, dir, up, tgt = [asarray(x) for x in [cam.GetPosition(), cam.GetDirection(), cam.GetUp(), cam.GetTarget()]]\nif rotation_center:\n    tgt = asarray(rotation_center)\n\ndef rotation_matrix(axis, theta):\n    return expm(cross(eye(3), axis / norm(axis) * theta))\n\nanim = animation.Animation(ses)\nfor i in range(0, n_frames):\n    print(f\"Rendering... [{'#'*round(40*i/(n_frames-1))}{' '*round(40*(1-i/(n_frames-1)))}] {100*(i+1)/n_frames:.0f}%\", end=\"\\r\" if i < n_frames-1 else \"\\n\")\n\n    ses.SetTimestep(int(data_timestep_framerate * i / video_framerate))\n\n    M = rotation_matrix(rotation_axis, radians(rotate_speed) * i / video_framerate)\n    cam.SetPosition(dot(M, pos - tgt) + tgt)\n    cam.SetDirection(dot(M, dir))\n    cam.SetUp(dot(M, up))\n    anim.CaptureFrame()\n    if save_individual_frames:\n        ses.Render(f\"{output}_{i:04}.png\")\n\nanim.SaveMP4(output, video_framerate)\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/transfer_function_example.py",
    "content": "# %% [md]\n#\n# # Transfer Functions\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera, transferfunction\nfrom vapor.utils import histogram\n\nses = session.Session()\ndata = example_utils.OpenExampleDataset(ses)\n\nren = data.NewRenderer(renderer.VolumeRenderer)\nses.GetCamera().LookAt((32, 120, 120), (32, 32, 32))\nses.Show()\n\n# %% [md]\n#\n# We created a volume rendering however it is fully opaque.\n# We can use a transfer function to adjust the visible portions.\n# Before we adjust the opacity map of the TF, we get a histogram to help us determine what we want to hide.\n#\n# %%\nhistogram.ShowMatPlotLibHistogram(ses, ren)\n\n# %% [md]\n#\n# Usually we want to hide the most common value so below we construct an opacity map that accomplishes this.\n#\n# %%\n# List of x,y pairs where x is the data value and y is the opacity for that data value\nopacities = [(-0.3, 1), (-0.1, 0), (0.1, 0), (0.3, 1)]\n\n# %% [md]\n#\n# We can get the matplotlib histogram plot and add our opacity map to it to compare.\n#\n# %%\nplt = histogram.GetMatPlotLibHistogram(ses, ren)\nplt.plot(*zip(*opacities))\nplt.show()\n\n# %% [md]\n#\n# Now we apply the map to the transfer function\n#\n# %%\n# Renderers can have multiple transfer functions.\n# GetPrimaryTransferFunction returns the one that is usually the most useful.\n# You can use `tf.GetTransferFunction(var_name)` to get other transfer functions.\ntf = ren.GetPrimaryTransferFunction()\ntf.SetOpacityControlPoints(opacities)\nses.Show()\n\n# %% [md]\n#\n# You can adjust the colormap in a similar fashion. Use `help(tf)` for more information.\n# Vapor includes a list of built-in colormaps and these can be applied with `tf.LoadBuiltinColormap(name)`\n#\n# ## Builtin Colormaps\n#\n# %%\ntf.LoadBuiltinColormap(\"Sequential/BlackBodyExtended\")\nses.Show()\n\n# %% [md]\n#\n# ## List of All Builtin Colormaps\n#\n# %%\n\nses.DeleteRenderer(ren)\nren = data.NewRenderer(renderer.TwoDDataRenderer)\ntf = ren.GetPrimaryTransferFunction()\n\nfor cmap in transferfunction.TransferFunction.ListBuiltinColormaps():\n    tf.LoadBuiltinColormap(cmap)\n\n    print(cmap)\n    tf.ShowMatPlotLibColorbar()"
  },
  {
    "path": "apps/pythonapi/example_scripts/visualizer_widget_example.py",
    "content": "# %% [md]\n#\n# # Visualizer Widgets\n#\n# Visualizer widgets allow you to interactively explore a session as you would in a Vapor GUI visualizer.\n# This notebook shows how to use visualizer widgets and how to add additional dynamic parameter inputs.\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\n\nses = session.Session()\ndata = example_utils.OpenExampleDataset(ses)\n\n# %% [md]\n#\n# ## Render an Iso Surface\n#\n# %%\nren = data.NewRenderer(renderer.VolumeIsoRenderer)\nren.SetVariableName(data.GetDataVarNames(3)[0]) # Set to first 2D data variable\nren.SetIsoValues([ren.GetIsoValues()[0]+0.1])\n\nses.GetCamera().ViewAll()\nses.Show()\n\n# %% [md]\n#\n# ## Create a visualizer to explore the scene\n#\n# Try dragging the image to rotate the view.\n# Hover over the visualizer to see the full controls.\n#\n# %%\nfrom vapor import widget\n\nviz = widget.VaporVisualizerWidget(ses)\nviz\n\n# %% [md]\n#\n# ## Add an interactive iso value slider using **ipywidgets**\n#\n# %%\nimport ipywidgets\n\ntf = ren.GetPrimaryTransferFunction()\ndataRange = tf.GetMinMaxMapValue()\n\ndef sliderChanged(change):\n    ren.SetIsoValues([change.new])\n    viz.Render(fast=True)\n\nslider = ipywidgets.FloatSlider(value=ren.GetIsoValues()[0], min=dataRange[0], max=dataRange[1], step=(dataRange[1]-dataRange[0])/100)\nslider.observe(sliderChanged, names='value')\n\nipywidgets.VBox([\n    viz,\n    ipywidgets.HBox([ipywidgets.Label(\"Iso value:\"), slider])\n])\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/workflow_example.py",
    "content": "# %% [md]\n#\n# # Vapor Python Tutorial\n#\n# This shows an example workflow with vapor.\n# We begin by creating a session and opening a dataset.\n# You can have multiple sessions open at the same time.\n#\n# %%\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\n\n# %%\nses = session.Session()\ndata = example_utils.OpenExampleDataset(ses)\n\n# %% [md]\n#\n# ## Dump the dataset metadata\n#\n# %%\nprint(\"Time Coordinate Variable Name:\", data.GetTimeCoordVarName())\nprint(\"Coordinate Variable Names:\", data.GetCoordVarNames())\n\nprint(\"Dimensions:\")\nfor dim in data.GetDimensionNames():\n    print(f\"  {dim}:\", data.GetDimensionLength(dim, 0))\n\nprint(\"Data Variables:\")\nfor var in data.GetDataVarNames():\n    print(f\"  {var}\")\n    print(f\"    Time Varying:\", bool(data.IsTimeVarying(var)))\n    print(f\"    Dimensionality:\", data.GetVarGeometryDim(var))\n    print(f\"    Coordinates:\", data.GetVarCoordVars(var, True))\n    print(\"     Data Range:\", data.GetDataRange(var))\n\n# %% [md]\n#\n# ## Render the first 2D variable as a pseudocolor\n#\n# %%\nfirst_2d_var = data.GetDataVarNames(2)[0]\nprint(f\"Rendering 2D variable {first_2d_var}\")\n\nren = data.NewRenderer(renderer.TwoDDataRenderer)\nren.SetVariableName(first_2d_var)\nren.GetPrimaryTransferFunction().SetMinMapValue(-1)\nren.GetPrimaryTransferFunction().SetMaxMapValue(1)\n\nses.GetCamera().ViewAll()\nses.Show()\n\nses.DeleteRenderer(ren)\n\n# %% [md]\n#\n# ## Render U10 and V10 as barbs over a map\n#\n# %%\n# If your dataset is geo-referenced, this will automatically render a geographically correct map.\n# map_ren = data.NewRenderer(renderer.ImageRenderer)\n\nbarbs = data.NewRenderer(renderer.BarbRenderer)\nbarbs.SetDimensions(2)\nbarbs.SetFieldVariableNames(['U10', 'V10'])\nbarbs.SetLineThickness(2)\n\nses.Show()\nses.DeleteRenderer(barbs)\n\n# %% [md]\n#\n# ## Simulate and render a flow advection\n#\n# %%\nflow = data.NewRenderer(renderer.FlowRenderer)\nflow.SetFieldVariableNames(['U10', 'V10'])\n\nses.Show()\n\nses.DeleteRenderer(flow)\n\n# %% [md]\n#\n# ## Volume render a 3D variable\n#\n# %%\nvolume = data.NewRenderer(renderer.VolumeRenderer)\nvolume.SetVariableName(\"V\")\n\ntf = volume.GetPrimaryTransferFunction()\ntf.SetOpacityList([1, 0, 0, 1])\n\nses.GetCamera().ViewAll()\nses.Show()\n\n# Show a colorbar for the volume rendering\ntf.ShowMatPlotLibColorbar(label=\"V\")\n\n# %% [md]\n#\n# ## Scale the dataset Z axis\n#\n# Vapor will automatically scale the Z axis of a dataset to produce reasonable results.\n# This can be manually adjusted as shown below.\n#\n# %%\nscales = data.GetTransform().GetScales()\nprint(\"Default dataset scaling =\", scales);\nscales[2] *= 0.3\ndata.GetTransform().SetScales(scales)\nprint(\"New dataset scaling =\", data.GetTransform().GetScales());\nses.Show()\n\n# %% [md]\n#\n# ## Add axis annotations to the rendering\n#\n# %%\nannotations = ses.GetAxisAnnotations()\nannotations.SetAxisAnnotationEnabled(True)\nses.Show()\n\n# %% [md]\n#\n# ## Saving figures\n#\n# %%\nses.Render(\"figure.png\")\nses.Render(\"figure.jpg\")\nses.Render(\"figure.tif\")\n\n# %% [md]\n#\n# ## Export the session for use in the Vapor GUI application\n#\n# Sessions created in Python can be saved as a .vs3 file.\n# These files can then be opened in the Vapor GUI application and explored interactively.\n# Conversely, sessions created in the Vapor GUI can be loaded into Python with `Session.Load(path)`\n# \n# Since this example uses a dynamically generated dataset, the session cannot be saved as\n# it would point to a dataset that does not exist on disk. If you were using a physical dataset,\n# this would work.\n#\n# %%\nses.Save(\"tutorial.vs3\")\n"
  },
  {
    "path": "apps/pythonapi/example_scripts/xarray_example.py",
    "content": "# %% [md]\n#\n# # Rendering XArray data with Vapor\n#\n# Vapor supports render XArray data in a similar fashion to Numpy data\n# In order to pass XArray data to Vapor, create a data set of the type `vapor.dataset.PYTHON`\n# This can also be done with the convenience function `Session.CreatePythonDataset()`.\n# You can add XArray variables as vapor variables to that dataset by using `Dataset.AddXArrayData`.\n#\n# These variables can then be rendered normally using any of Vapor's renderers.\n#\n# %%\n\nimport example_utils\nfrom vapor import session, renderer, dataset, camera\nimport xarray as xr\nimport numpy as np\nfrom math import cos, sin, pi\n\nses = session.Session()\ndata = ses.CreatePythonDataset()\n\n# %% [md]\n#\n# Below we generate an XArray variable that consists of a curvilinear 2D grid.\n# You can also open an existing dataset with `xarray.open_dataset` and use variables in that dataset.\n#\n# %%\ndef gen2d(w,h,f):\n    \"\"\"Generate a 2D grid of size (w,h) by evaluating f(x,y) for every x,y coordinate\"\"\"\n    ay = []\n    for y in range(0,h):\n        ax = []\n        for x in range(0,w):\n            ax += [f(x,y)]\n        ay += [ax]\n    return ay\n\nw = h = 8\ncurveVar = xr.DataArray(\n    np.random.randn(8, 8),\n    dims=(\"x\", \"y\"),\n    coords={\n        \"x_coord\": xr.DataArray(gen2d(8,8,lambda x,y: cos(y/(h-1)*pi) * (x+(w+1))), dims=(\"x\", \"y\")),\n        \"y_coord\": xr.DataArray(gen2d(8,8,lambda x,y: sin(y/(h-1)*pi) * (x+(w+1))), dims=(\"x\", \"y\"))\n    })\n\ndata.AddXArrayData(\"variable_name\", curveVar)\n\n# %%\n\n# Create a renderer for the data\n\nren = data.NewRenderer(renderer.WireFrameRenderer)\nren.SetVariableName(\"variable_name\")\n\n# %%\n\n# Show the rendering\n\nses.GetCamera().ViewAll()\nses.Show()\n\n# %%\n\nses.DeleteRenderer(ren)\n\n\n# %% [md]\n#\n# Below we generate an XArray variable that consists of a curvilinear 3D grid.\n#\n# %%\n\ndef gen3d(w,h,d,f):\n    \"\"\"Generate a 3D grid of size (w,h,d) by evaluating f(x,y,z) for every x,y,z coordinate\"\"\"\n    az = []\n    for z in range(0,d):\n        ay = []\n        for y in range(0,h):\n            ax = []\n            for x in range(0,w):\n                ax += [f(x,y,z)]\n            ay += [ax]\n        az += [ay]\n    return az\n\n\nw = h = d = 8\ncurveVar = xr.DataArray(\n    gen3d(w,h,d,lambda x,y,z: z*w*h + y*w + x),\n    dims=(\"x\", \"y\", \"z\"),\n    coords={\n        \"x_coord\": xr.DataArray(gen2d(w,h,lambda x,y: x), dims=(\"x\", \"y\")),\n        \"y_coord\": xr.DataArray(gen2d(w,h,lambda x,y: y), dims=(\"x\", \"y\")),\n        \"z_coord\": xr.DataArray(gen3d(w,h,d,lambda x,y,z: z), dims=(\"x\", \"y\", \"z\")),\n    })\n\ndata.AddXArrayData(\"variable_3d\", curveVar)\n\n# %%\n\n# Create a renderer for the data\n\nren = data.NewRenderer(renderer.WireFrameRenderer)\nren.SetVariableName(\"variable_3d\")\n\n# %%\n\n# Show the rendering\n\nses.GetCamera().ViewAll()\nses.Show()\n"
  },
  {
    "path": "apps/pythonapi/setup.py",
    "content": "from distutils.core import setup\nfrom pathlib import Path\nimport itertools\nimport sys, os\n\nimport cmake\n\nprint(\"========================================================================\")\nimport sys; print(f\"Python Version = {sys.version.split(' ')[0]} ({sys.prefix})\")\nif cmake.BUILD_TYPE.lower() != \"release\":\n    print(\"WARNING building wheel with non-release build\")\nprint(\"========================================================================\")\n\n\ndef GenerateSetupDataFilesFormattedListForDir(root, prefix=\"\"):\n    root = Path(root)\n    prefix = Path(prefix)\n    files = filter(Path.is_file, root.glob('**/*'))\n    files = sorted(files, key=lambda f:f.parent)\n    ret = [(str(prefix / g.relative_to(root)), [str(p) for p in f]) for g, f in itertools.groupby(files, lambda f:f.parent)]\n    return ret\n\n\ndef PrintSetupDataFilesFormattedList(l):\n    for target, files in l:\n        print(target)\n        for f in files:\n            print(f\"\\t{f}\")\n\n\ncpackComponents = list(Path(cmake.CPACK_STAGING_DIR).iterdir())\ncpackFormattedFiles = [GenerateSetupDataFilesFormattedListForDir(c, prefix='vapor') for c in cpackComponents]\ncpackFormattedFiles = list(itertools.chain(*cpackFormattedFiles))\n\n\ndef IsCondaBuild():\n    if os.environ.get('CONDA_BUILD', None) == '1': return True\n    # if 'conda-bld' in sys.executable.lower(): return True\n    # if 'conda-bld' in os.environ.get('PIP_CACHE_DIR', None).lower(): return True\n    return False\n\n\ninstall_requires=[\n    'cppyy',\n    'xarray',\n    'scipy', # Required for NetCDF support in xarray\n    'matplotlib',\n    'ipython',\n    'jupyter',\n    ]\n\n# Disable pip requirements for conda build\n# Otherwise, conda needs to have these packages in its build requirements\n# and they need to be installed during build-time otherwise pip will try to\n# install them and break\nif IsCondaBuild():\n    install_requires = []\n\nsetup(name='vapor',\n      version=cmake.VERSION_STRING,\n      description='NCAR Vapor Python Interface',\n      long_description=f\"Detailed Version: {cmake.VERSION_STRING_FULL}.{cmake.BUILD_TYPE}\",\n      author='Vapor Team',\n      author_email='vapor@ucar.edu',\n      url='https://www.vapor.ucar.edu',\n      packages=['vapor'],\n      install_requires=install_requires,\n      # Duplicates symlinked libraries (adds ~200MB to install)\n      # Based on python mailing lists, this is intentional and currently the only option (https://discuss.python.org/t/symbolic-links-in-wheels/1945/12)\n      data_files=cpackFormattedFiles,\n      # data_files=[\n          # ('vapor/lib', list(map(str, chain(cmake_lib_dir.glob(\"*.dylib\"), cmake_lib_dir.glob(\"*.so\"))))),\n          # ('vapor/doc', [str(cmake_doc_dir)]),\n          # ('vapor', cmakeInstallFiles),\n      # ],\n      # package_data = {'vapor': [f\"{cmake_lib_dir}/*.dylib\"]},\n      # package_data = {'': [\"/Users/stasj/Work/vapor-xcode/lib/Debug/libvdc.dylib\"]},\n      # package_data = {'': [\"*.dat\", \"test_folder/*.dat\"]},\n      )\n"
  },
  {
    "path": "apps/pythonapi/tests/CanvasStreamTest.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"1fccf099\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import example_utils\\n\",\n    \"from vapor import widget\\n\",\n    \"\\n\",\n    \"w = widget.CanvasStreamWidget(debug=True)\\n\",\n    \"w\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"id\": \"a525e1bd\",\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"w\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"jupytext\": {\n   \"cell_metadata_filter\": \"region_name,-all\",\n   \"main_language\": \"python\",\n   \"notebook_metadata_filter\": \"-all\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 5\n}"
  },
  {
    "path": "apps/pythonapi/tests/bld.bat",
    "content": "\"%PYTHON%\" setup.py install\nif errorlevel 1 exit 1"
  },
  {
    "path": "apps/pythonapi/tests/build.sh",
    "content": "$PYTHON setup.py install"
  },
  {
    "path": "apps/pythonapi/tests/cppyy-syntax-test.py",
    "content": "import cppyy\nfrom ctypes import c_int\n\n\ncppyy.cppdef(\"\"\"\n#include <string>\nusing std::string;\n\nvoid p(string s) {\n    printf(\"CPP %s\\\\n\", s.c_str());\n}\n\nvoid testVoid(void (*cb)(void)) {\n    printf(\"TEST VOID\\\\n\");\n    cb();\n}\n\nvoid testRet(string (*cb)(void)) {\n    string s = cb();\n    printf(\"TEST RET = %s\\\\n\", s.c_str());\n}\n\nvoid testIn(string (*cb)(string)) {\n    string s = cb(\"CPP STR\");\n    printf(\"TEST RET = %s\\\\n\", s.c_str());\n}\n\nvoid testInConstRef(string (*cb)(const string &)) {\n    string s = cb(\"CPP STR\");\n    printf(\"CONST TEST RET = %s\\\\n\", s.c_str());\n}\n\n\"\"\")\n\n# cppyy.gbl.p(\"hello\")\n\ndef cb():\n    print(\"Python Callback\")\n    return \"<Python Return Value>\"\n\ndef cb2(s):\n    print(f\"Python Callback({s})\")\n    # s = \"d\"\n    return f\"<Python Return Value={s}>\"\n    # raise FileNotFoundError\n    return None\n\ncppyy.gbl.testVoid(cb)\ncppyy.gbl.testRet(cb)\ncppyy.gbl.testIn(cb2)\ncppyy.gbl.testInConstRef(cb2)\n\nexit()\n\n\ncppyy.cppdef(\"\"\"\nvoid ref_int(int &a) {\n    a = 42;\n}\n\n#include <string>\nusing std::string;\n\nvoid ref_str(string &s) {\n    s = \"hello\";\n}\n\"\"\")\n\na = c_int(3)\ncppyy.gbl.ref_int(a)\nprint(a)\n\n# does not work\n# s = \"bye\"\n# cppyy.gbl.ref_str(s)\n# print(s)\n\ns = cppyy.gbl.std.string(\"bye\")\ncppyy.gbl.ref_str(s)\nprint(s)\n"
  },
  {
    "path": "apps/pythonapi/tests/cppyy-test.py",
    "content": "import cppyy\n\ncppyy.add_include_path('/Users/stasj/Work/vapor/apps/vapi')\ncppyy.add_include_path('/Users/stasj/Work/vapor/include')\ncppyy.add_include_path('/usr/local/VAPOR-Deps/2019-Aug/include/')\n\ncppyy.load_library('/Users/stasj/Work/vapor-xcode/lib/Debug/libcommon.dylib')\n\n# class Session:\n#     def __init__(self):\n#         print(\"New Session\")\n\ncppyy.include('vapor/Version.h')\nvaporVersion = cppyy.gbl.Wasp.Version()\nprint(type(vaporVersion).__cpp_name__, \"=\", vaporVersion.GetVersionString())\n\ncppyy.load_library('/Users/stasj/Work/vapor-xcode/lib/Debug/libvapi.dylib')\n\ncppyy.include('vapor/MyPython.h')\ncppyy.gbl.Wasp.MyPython.IsRunningFromPython = True\n\ncppyy.include('GLContextProvider.h')\nctx = cppyy.gbl.GLContextProvider.CreateContext()\nprint(\"GL Version =\", ctx.GetVersion())\n\ncppyy.include('Session.h')\nsession = cppyy.gbl.Session()\nsession.Load(\"/Users/stasj/Work/sessions/time.vs3\")\nsession.Render(\"/Users/stasj/Work/out-python-cppyy.png\")\n\nprint(\"HERERRER ====\")\nexit(0)\n"
  },
  {
    "path": "apps/pythonapi/tests/meta.yaml",
    "content": "package:\n  name: vapor\n  version: \"@VERSION_STRING@\"\n\nsource:\n  path: .\n\nrequirements:\n  build:\n    - python\n\n  run:\n    - python=@Python_VERSION@\n    - numpy=@Python_NumPy_VERSION@\n    - cppyy\n    - xarray\n    - scipy # Required for NetCDF support in xarray\n    - matplotlib\n    - ipython\n    - jupyter\n\n# Conda will try to compile every python file in the proejct by default\n# Vapor has some misc python2 files left over which fail to compile\nbuild:\n  skip_compile_pyc:\n    - \"*.py\"\n\nabout:\n  home: \"https://www.vapor.ucar.edu\"\n"
  },
  {
    "path": "apps/pythonapi/tests/module-data-test.py",
    "content": "import numpy as np\n\narr = np.arange(32**3, dtype=np.float32).reshape(32, 32, 32)\nprint(\"Type =\", arr.dtype)\nprint(type(arr))\n# exit(0)\n\nfrom vapor import session, renderer, dataset, camera\n\nses = session.Session()\n\ndata = ses.OpenDataset(dataset.PYTHON, \"dataset_name\")\ndata.AddNumpyData(\"data_1\", arr)\n\nren = data.NewRenderer(renderer.WireFrameRenderer)\nren.SetVariableName(\"data_1\")\n\ncam = ses.GetCamera()\n# cam.ViewAll()\ncam.LookAt((50, 50, 40), (16, 16, 16))\n# cam.LookAt((3, 3, 2), (0.5, 0.5, 0.5))\nses.Render(\"out-data-test-1.png\")\n\n\narr = np.arange(32**3*2, dtype=np.float32).reshape(32, 32*2, 32)\ndata.AddNumpyData(\"data_1\", arr)\nren.SetVariableName(\"data_1\")\nses.Render(\"out-data-test-2.png\")\nren.SetEnabled(False)\n\narr = np.arange(32**2, dtype=np.float32).reshape(32, 32)\ndata.AddNumpyData(\"data_2d_1\", arr)\nren = data.NewRenderer(renderer.TwoDDataRenderer)\nren.SetVariableName(\"data_2d_1\")\nses.Render(\"out-data-test-3.png\")\n\nimport xarray as xr\nxrd = xr.open_dataset(\"/Users/stasj/Work/data/time/time_01.nc\")\ndata.AddXArrayData(\"XR_Sphere\", xrd.sphere)\nren.SetVariableName(\"XR_Sphere\")\ncam.ViewAll()\nses.Render(\"out-data-test-4.png\")\n\ndef gen2d(w,h,f):\n    ay = []\n    for y in range(0,h):\n        ax = []\n        for x in range(0,w):\n            ax += [f(x,y)]\n        ay += [ax]\n    return ay\n\nfrom math import cos, sin, pi\n\nw = h = 8\ncurveVar = xr.DataArray(\n    np.random.randn(8, 8),\n    dims=(\"x\", \"y\"),\n    coords={\n        \"x_coord\": xr.DataArray(gen2d(8,8,lambda x,y: cos(y/h*pi) * (x+(w+1))), dims=(\"x\", \"y\")),\n        \"y_coord\": xr.DataArray(gen2d(8,8,lambda x,y: sin(y/h*pi) * (x+(w+1))), dims=(\"x\", \"y\"))\n    })\n\n\ndata.AddXArrayData(\"XR_Curve\", curveVar)\nren.SetVariableName(\"XR_Curve\")\ncam.ViewAll()\nses.Render(\"out-data-test-5.png\")\n"
  },
  {
    "path": "apps/pythonapi/tests/module-test.py",
    "content": "from vapor import session, renderer, dataset, camera\n\nses = session.Session()\n\ndata = ses.OpenDataset(dataset.VDC, \"/not/found/data.vdc\")\nprint(f\"Not found data = '{data}'\")\n\n# ses.Load(\"/Users/stasj/Work/sessions/time-empty.vs3\")\n# data = ses.GetDatasets()[0]\ndata = ses.OpenDataset(dataset.VDC, \"/Users/stasj/Work/data/time/time.vdc\")\n\nren = data.NewRenderer(renderer.TwoDDataRenderer)\n# ren = ses.NewRenderer(renderer.TwoDDataRenderer, \"time.vdc\")\nren.SetEnabled(True)\n\nses.Render(\"out-python-cppyy.png\")\nses.Show()\n\nren.SetRefinementLevel(3)\nren.SetCompressionLevel(3)\ntf:renderer.TransferFunction = ren.GetPrimaryTransferFunction()\ntf.LoadBuiltinColormap('Sequential/amp')\ntf.SetOpacityList([1, 0, 1])\nprint(f\"TF Mapping Range for {ren.GetVariableName()} is {tf.GetMinMapValue()} - {tf.GetMaxMapValue()}\")\n\nses.SetTimestep(1)\nses.Render(\"out-python-cppyy-2.png\")\n\nses.SetResolution(300,300)\nses.Save(\"out-session-time.vs3\")\nses.Show()\n\n\n\n#################################\n# Another session\n\nses2 = session.Session()\nmaycontrol = ses2.OpenDataset(dataset.VDC, \"/Users/stasj/Work/data/24Maycontrol.01/24Maycontrol.01.vdc\")\n\nvol = maycontrol.NewRenderer(renderer.VolumeRenderer)\nprint(f\"Volume var name = '{vol.GetVariableName()}'\")\n\ncam = ses2.GetCamera()\ncam.LookAt((-2.5, -2.5, 20), (-2.5,-2.5, 2.5))\n\nses2.Render(\"out-python-cppyy-maycontrol.png\")\nses2.Save(\"out-session-dbz.vs3\")\n\n"
  },
  {
    "path": "apps/pythonapi/tests/syntax-test.py",
    "content": "# import functools\n#\n# class Inner():\n#     def __init__(self):\n#         self.x = 0\n#\n#     def SetX(self, x):\n#         self.x = x\n#\n#     def GetX(self):\n#         return self.x\n#\n# class Outer():\n#     def __init__(self):\n#         self.inner = Inner()\n#\n# expose = [\"SetX\", \"GetX\"]\n# for f in expose:\n#\n#     def wrapper(func):\n#         @functools.wraps(func)\n#         def wrapper_do_twice(*args, **kwargs):\n#             return func(*args, **kwargs)\n#         return wrapper_do_twice\n#         # return func(*args, **kwargs)\n#\n#     func = getattr(Inner, f)\n#\n#     setattr(Outer, f, wrapper(func))\n#     print(\"setattr(Outer, {}, {}\".format(f, wrapper))\n#     # setattr(Outer, \"SetX\", lambda self, x: self.inner.SetX(x))\n#     # setattr(Outer, \"GetX\", lambda self: self.inner.GetX())\n#     # setattr(self, f, getattr(self.inner, f))\n#\n# out = Outer()\n# help(out)\n#\n# out.inner.SetX(3)\n# print(out.inner.GetX())\n#\n# out.SetX(5)\n# print(out.GetX())\n\n#############################################################\nimport functools\n\nprint(\"============ Define Classes ============\")\n\ndef log(func):\n    @functools.wraps(func)\n    def wrapper_debug(*args, **kwargs):\n        args_repr = [repr(a) for a in args]                      # 1\n        kwargs_repr = [f\"{k}={v!r}\" for k, v in kwargs.items()]  # 2\n        signature = \", \".join(args_repr + kwargs_repr)           # 3\n        value = func(*args, **kwargs)\n        print(f\"Call {func.__name__}({signature}) = {value!r}\")\n        return value\n    return wrapper_debug\n\n# class Params():\n#     def Other(self):\n#         print(\"Other\")\n#\n# class SubParams(Params):\n#     def __init__(self):\n#         self.en = False\n#     def SetEnabled(self, e):\n#         self.en = e\n#     def IsEnabled(self):\n#         return self.en\n#\n# def funcWrapper(func):\n#     @functools.wraps(func)\n#     def f(self, *args, **kwargs):\n#         ret = func(self._params, *args, **kwargs)\n#         print(f\"Call {func.__name__}({', '.join([repr(a) for a in args[1:]])}) = {ret!r}\", )\n#         return ret\n#     return f\n#\n# class ParamsWrapperMeta(type):\n#     def __init__(cls, *args, **kwargs):\n#         super().__init__(*args, **kwargs)\n#\n#         for f in cls._wrap:\n#             print(\"wrap\", f)\n#             func = getattr(Params, f)\n#             setattr(cls, f, funcWrapper(func))\n#\n# class ParamsWrapperMeta2(type):\n#     @log\n#     def __new__(cls, clsname, bases, clsdict):\n#         wrapped = {f:funcWrapper(getattr(Params, f)) for f in clsdict['_wrap']}\n#         clsdict.update(wrapped)\n#\n#         # for f in clsdict['_wrap']:\n#         #     print(\"wrap\", f)\n#         #     func = getattr(Params, f)\n#         #     clsdict.update({f:funcWrapper(func)})\n#\n#         return type.__new__(cls, clsname, bases, dict(clsdict))\n#\n#     @log\n#     def __init__(cls, *args, **kwargs):\n#         super().__init__(*args, **kwargs)\n#\n# class ParamsWrapper(object, metaclass=ParamsWrapperMeta2):\n#     _paramsCls = Params\n#     _wrap = []\n#\n#     def __init__(self, p:Params):\n#         self._params = p\n\n# class Renderer(ParamsWrapper):\n#     _paramsCls = SubParams\n#     _wrap = [\"SetEnabled\", \"IsEnabled\"]\n\n\n\n# print(\"============ Test Script ============\")\n\n# help(Renderer)\n# print([f for f in dir(Renderer) if not f.startswith('__')])\n\n# r = Renderer(Params())\n# r.SetEnabled(True)\n# r.IsEnabled()\n# print(\"r._params.en =\", r._params.en)\n\n\nimport re\n\n\nclass ParentClass():\n    def printTest(self):\n        \"\"\"Prints test\"\"\"\n        print(f\"Test from {self.__class__.__name__}\")\n\nclass ChildClass(ParentClass):\n    def printTest(self):\n        \"\"\"Overloaded prints test\"\"\"\n        print(f\"Overloaded test from {self.__class__.__name__}\")\n\n    def printTest2(self):\n        \"\"\"Prints test 2\"\"\"\n        print(f\"Test 2 from {self.__class__.__name__}\")\n\n\nfrom vapor.smartwrapper import *\n\nclass ParentWrapped(SmartWrapper, wrap=ParentClass):\n    printTest = FuncWrapper()\n    # a, b = [FuncWrapper]*2\n    # c, d, *_ = FuncWrappers()\n    pass\n\nclass ChildWrapped(ParentWrapped, wrap=ChildClass):\n    _ = FuncWrapperWrapAll()\n    printTestRenamed = FuncWrapperRename(\"printTest\")\n    # printTest2 = FuncWrapper()\n\n\n\nprint()\nprint(\"============ Test Script ============\")\n\npc = ParentClass()\ncc = ChildClass()\npw = ParentWrapped(pc)\ncw = ChildWrapped(cc)\n\npc.printTest()\ncc.printTest()\npw.printTest()\ncw.printTest()\ncw.printTestRenamed()\n\n# help(ChildWrapped)"
  },
  {
    "path": "apps/pythonapi/tests/test.py",
    "content": "# jupytext --to notebook test.py\n# jupyter nbconvert --to notebook --inplace --execute test.ipynb\n# \n# cat test.py | jupytext --to ipynb | jupyter nbconvert --stdin --execute --no-input --to html --output notebook.html\n# jupyter nbconvert --to html --no-input --execute annotation_example.ipynb\n# jupyter nbconvert --to pdf --execute annotation_example.ipynb\n\nimport numpy as np\nfrom math import *\nfrom vapor import session, renderer, dataset, camera, transferfunction, utils\n\n# help(renderer.VolumeRenderer)\n\nses = session.Session()\ndata = ses.CreatePythonDataset()\n\nfrom inspect import signature\ndef sample(f, ext=None, shape=None):\n    if not shape: shape = [64]*len(signature(f).parameters)\n    if not ext: ext = [(0,1)]*len(signature(f).parameters)\n    assert len(signature(f).parameters) == len(shape) and len(shape) == len(ext)\n    d = []\n    for i in np.ndindex(*reversed(shape)):\n        d.append(f(*[v/s*(t-f)+f for v,s,(f,t) in zip(reversed(i), shape, ext)]))\n    return np.asarray(d, dtype=np.float32).reshape(shape)\n\n\n# arr = sample(lambda x,y: sin(6*x)+sin(6*y))\narr = sample(lambda x,y: (x+y)*np.exp(-5.0*(x**2+y**2)), ext=[(-1,1)]*2)\ndata.AddNumpyData(\"data_2d_1\", arr)\nren = data.NewRenderer(renderer.TwoDDataRenderer)\nren.SetVariableName(\"data_2d_1\")\nren.GetColorbarAnnotation().SetEnabled(True)\n\n# utils.ShowHistogram(ses, ren)\n# utils.ShowHistogram(ses, ren, bins=5)\n\ncam = ses.GetCamera()\ncam.ViewAll()\ntf = ren.GetPrimaryTransferFunction()\n# tf.SetColorNormalizedHSVControlPoints([(0, (0,1,1)), (1, (0.5,1,1))])\n# tf.SetColorNormalizedHSVControlPoints([(h/20, (h/20,1,1)) for h in range(0,20)])\n# tf.SetColorNormalizedRGBControlPoints([(0, (1,0,0)), (1, (0,1,0))])\ntf.SetColorRGBList([(1,0,0), (0,1,0), (0,0,1)])\ntf.LoadBuiltinColormap(\"Sequential/matter\")\n# tf.ShowMatPlotLibColorbar()\n# exit()\nses.Show()\nren.SetEnabled(False)\n# ses.Render(\"out-data-test-3.png\")\n\n# ren = data.NewRenderer(renderer.ImageRenderer)\n# for map in ren.ListBuiltinMaps():\n#     ren.SetBuiltinMap(map)\n#     ses.Show()\n# ses.DeleteRenderer(ren)\n\nren = data.NewRenderer(renderer.FlowRenderer)\nren.SetFieldVariableNames([\"data_2d_1\"]*2)\nren.SetRenderType(ren.RenderType.RenderTypeSamples)\nren.SetRenderRadiusScalar(5)\nren.SetRenderGeom3D(True)\nren.SetGridNumOfSeeds([5,5])\nses.Show()\nses.DeleteRenderer(ren)\n\n\nren = data.NewRenderer(renderer.BarbRenderer)\nren.SetFieldVariableNames([\"data_2d_1\"]*2)\nren.GetRenderRegion().SetExtents([5,5],[40,40])\nren.SetXBarbsCount(3)\nses.Show()\nses.DeleteRenderer(ren)\n\nren = data.NewRenderer(renderer.ContourRenderer)\nren.SetVariableName(\"data_2d_1\")\ndmin = ren.GetPrimaryTransferFunction().GetMinMapValue()\ndmax = ren.GetPrimaryTransferFunction().GetMaxMapValue()\nisos = [dmin + (dmax-dmin)*i/40 for i in range(40)]\nren.SetIsoValues(isos)\nses.Show()\n# ses.DeleteRenderer(ren)\n\n# arr = sample(lambda x,y,z: sin(10*x)+sin(10*y)+sin(10*z))\narr = sample(lambda x,y,z: (x+y+z)*np.exp(-5.0*(x**2+y**2+z**2)), ext=[(-1,1)]*3)\ndata.AddNumpyData(\"data_3d_1\", arr)\nren = data.NewRenderer(renderer.VolumeRenderer)\nren.SetVariableName(\"data_3d_1\")\ntf = ren.GetPrimaryTransferFunction()\n# tf.SetOpacityList([0,0,1])\ntf.SetOpacityList([1,0,1])\n\n# cam.ViewAll()\ncam.LookAt((-120,120,120), (32,32,32))\nses.Show()\n\nren.SetEnabled(False)\nren:renderer.VolumeIsoRenderer = data.NewRenderer(renderer.VolumeIsoRenderer)\nprint(\"Iso Algo=\", ren.GetAlgorithm())\n# ren.SetIsoValues([1.8])\nren.SetIsoValues([-0.1, 0.1])\nses.Show()\nses.DeleteRenderer(ren)\n\nsa = ses.GetAxisAnnotations()\nsa.SetAxisAnnotationEnabled(True)\n\nren:renderer.SliceRenderer = data.NewRenderer(renderer.SliceRenderer)\nses.Show()\nses.DeleteRenderer(ren)\n"
  },
  {
    "path": "apps/pythonapi/vapor/__init__.py",
    "content": "from . import link\nimport sys\nimport hdf5plugin\n\nlink.include('vapor/Version.h')\nvaporVersion = link.Wasp.Version()\nprint(\"Vapor\", vaporVersion.GetVersionString())\n\nprint(f\"Python {sys.version.split(' ')[0]} ({sys.prefix})\")\n\nlink.include('vapor/Log.h')\nlink.Log.InfoLevelEnabled = False\n\nlink.include('vapor/Session.h')\nlink.Session.SetWaspMyBaseErrMsgFilePtrToSTDERR()\n\nfrom . import config\nlink.include('vapor/ResourcePath.h')\nlink.Wasp.RegisterResourceFinder(config.GetResourceSafe)\n\nlink.include('vapor/MyPython.h')\nlink.Wasp.MyPython.IsRunningFromPython = True\n\nlink.include('vapor/RenderManager.h')\nctx = link.RenderManager.GetOSGLContext()\nprint(\"OpenGL\", ctx.GetVersion())\n\n"
  },
  {
    "path": "apps/pythonapi/vapor/animation.py",
    "content": "import os\n\nimport cv2\nimport tempfile\nfrom base64 import b64encode\nfrom io import BytesIO\n\nfrom .session import *\n\nclass Animation:\n    def __init__(self, ses:Session):\n        self._ses = ses\n        self._frames = []\n\n\n    def CaptureFrame(self):\n        frame = self._ses.RenderToImage()\n\n        if self._frames and frame.size != self._frames[0].size:\n            raise ValueError(f\"Frame resolution {frame.size} is different from animation resolution {self._frames[0].size}\")\n\n        self._frames.append(frame)\n\n\n    def ShowInteractive(self):\n        self.__requireIPython()\n\n        from IPython.display import display\n        import ipywidgets as widgets\n\n        # displayHandle = display(None, display_id=True)\n\n        # def callback(frame):\n        #     displayHandle.update(self._frames[frame])\n\n        play = widgets.Play(\n            value=0,\n            min=0,\n            max=len(self._frames) - 1,\n            step=1,\n            interval=80,\n            # _repeat=True,\n        )\n\n        def PILtoJPG(img):\n            buf = BytesIO()\n            img.save(buf, format=\"jpeg\")\n            return buf.getvalue()\n\n        imageWidget = widgets.Image(\n            value=PILtoJPG(self._frames[0]),\n            format='jpg',\n            width=self._frames[0].size[0],\n            height=self._frames[0].size[1]\n        )\n\n        # def callback(frame):\n        #     imageWidget.value = frame\n        #     return imageWidget\n\n        frameSlider = widgets.IntSlider(0, 0, len(self._frames) - 1)\n        widgets.jslink((play, 'value'), (frameSlider, 'value'))\n\n        intervalSlider = widgets.IntSlider(80, 30, 1000)\n        widgets.jslink((intervalSlider, 'value'), (play, 'interval'))\n        intervalWidget = widgets.HBox([widgets.Label(\"Animation Interval\"), intervalSlider])\n\n        # output = widgets.interactive_output(callback, {'frame': frameSlider})\n\n        def frameChanged(change):\n            imageWidget.value = PILtoJPG(self._frames[change.new])\n\n        frameSlider.observe(frameChanged, names='value')\n\n        w = widgets.VBox([imageWidget, widgets.HBox([play, frameSlider]), intervalWidget])\n        display(w)\n\n\n    def Show(self, framerate=15):\n        self.__requireIPython()\n\n        import IPython.display\n\n        f = tempfile.NamedTemporaryFile(suffix='.mp4', delete=False)\n        path = f.name\n        f.close()\n\n        self.SaveMP4(path, framerate)\n        with open(path, \"rb\") as f:\n            data = f.read()\n\n        IPython.display.display(IPython.display.Video(data=data, embed=True, mimetype=\"video/mp4\"))\n\n        os.unlink(path)\n\n\n    def SaveMP4(self, path:str, framerate=15):\n        fourcc = cv2.VideoWriter_fourcc(*'avc1')\n        video = cv2.VideoWriter(path, fourcc, framerate, self._frames[0].size)\n        for i in self._frames:\n            video.write(cv2.cvtColor(np.array(i), cv2.COLOR_RGB2BGR))\n        video.release()\n\n        if config.IsRunningFromIPython():\n            import IPython.display\n            return IPython.display.FileLink(path)\n\n\n    def __requireIPython(self):\n        if not config.IsRunningFromIPython():\n            raise RuntimeError(f\"{self.__class__}.Show() only supported within an IPython environment\")\n"
  },
  {
    "path": "apps/pythonapi/vapor/annotations.py",
    "content": "from . import link\nfrom .params import *\n\nlink.include('vapor/ColorbarPbase.h')\n\nclass ColorbarAnnotation(ParamsWrapper, wrap=link.VAPoR.ColorbarPbase):\n    _wrap = FuncWrapperStrList(\"\"\"\n        GetCornerPosition\n        SetCornerPosition\n        GetSize\n        SetSize\n        GetTitle\n        SetTitle\n        IsEnabled\n        SetEnabled\n        GetFontSize\n        SetFontSize\n        GetNumTicks\n        SetNumTicks\n        GetNumDigits\n        SetNumDigits\n        GetBackgroundColor\n        SetBackgroundColor\n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n        bool UseScientificNotationTag\n    \"\"\")\n\n\nlink.include('vapor/AnnotationParams.h')\n\nclass SceneAnnotation(ParamsWrapper, wrap=link.VAPoR.AnnotationParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n        GetDomainColor\n        SetDomainColor\n        GetUseDomainFrame\n        SetUseDomainFrame\n        GetUseRegionFrame\n        SetUseRegionFrame\n        GetRegionColor\n        GetRegionColor\n        GetBackgroundColor\n        SetBackgroundColor\n        GetCurrentAxisDataMgrName\n        SetCurrentAxisDataMgrName\n        SetAxisFontSize\n        GetAxisFontSize\n        GetTimeLLX\n        SetTimeLLX\n        GetTimeLLY\n        SetTimeLLY\n        GetTimeColor\n        SetTimeColor\n        GetTimeType\n        SetTimeType\n        GetTimeSize\n        SetTimeSize\n        GetAxisArrowEnabled\n        GetAxisArrowSize\n        GetAxisArrowXPos\n        GetAxisArrowYPos\n        SetAxisArrowEnabled\n        SetAxisArrowSize\n        SetAxisArrowXPos\n        SetAxisArrowYPos\n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n    \"\"\")\n\n    class TimeAnnotationType:\n        NoAnnotation = 0\n        Timestep = 1\n        User = 2\n        Formatted = 3\n\n\nlink.include('vapor/AxisAnnotation.h')\n\nclass AxisAnnotation(ParamsWrapper, wrap=link.VAPoR.AxisAnnotation):\n    _wrap = FuncWrapperStrList(\"\"\"\n        SetAxisAnnotationEnabled\n        GetAxisAnnotationEnabled\n        GetAxisBackgroundColor\n        GetAxisBackgroundColor\n        SetAxisBackgroundColor\n        GetAxisColor\n        SetAxisColor\n        SetNumTics\n        GetNumTics\n        SetAxisOrigin\n        GetAxisOrigin\n        SetMinTics\n        GetMinTics\n        SetMaxTics\n        GetMaxTics\n        SetTicSize\n        GetTicSize\n        SetXTicDir\n        GetXTicDir\n        SetYTicDir\n        GetYTicDir\n        SetZTicDir\n        GetZTicDir\n        SetTicDirs\n        GetTicDirs\n        GetTicWidth\n        SetTicWidth\n        GetAxisTextHeight\n        SetAxisTextHeight\n        GetAxisDigits\n        SetAxisDigits\n        SetLatLonAxesEnabled\n        GetLatLonAxesEnabled\n        GetShowAxisArrows\n        SetShowAxisArrows\n        SetAxisFontSize\n        GetAxisFontSize\n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n    \"\"\")\n"
  },
  {
    "path": "apps/pythonapi/vapor/camera.py",
    "content": "from . import link\nfrom .common import *\nimport numpy as np\n\nlink.include('vapor/ControlExecutive.h')\nlink.include(\"vapor/NavigationUtils.h\")\n\nNavigationUtils = link.NavigationUtils\nViewpointParams = link.ViewpointParams\n\nclass Camera():\n\n    __axisDict = {\n        '+X': 2,\n        '+Y': 3,\n        '+Z': 4,\n        '-X': 5,\n        '-Y': 6,\n        '-Z': 7\n    }\n\n    def __init__(self, ce):\n        self.ce: link.VAPoR.ControlExec = ce\n\n    def LoadFromFile(self, path:str):\n        \"\"\"Save camera settings to file\"\"\"\n        ViewpointParams.SetCameraFromFile(NavigationUtils.GetActiveViewpointParams(self.ce), path)\n    \n    def SaveToFile(self, path:str):\n        \"\"\"Load camera settings from file\"\"\"\n        ViewpointParams.SaveCameraToFile(NavigationUtils.GetActiveViewpointParams(self.ce), path)\n\n    def AlignView(self, axis:str):\n        \"\"\"\n        Align camera looking down an axis\n        Axis format: [+-][XYZ]\n        \"\"\"\n        viewNum = self.__axisDict[axis.upper()]\n        NavigationUtils.AlignView(self.ce, viewNum)\n\n    def ViewAll(self):\n        \"\"\"Places the camera above the dataset looking down so that it is visible in its entirety.\n        This is the default view when opening a new dataset.\"\"\"\n        NavigationUtils.ViewAll(self.ce)\n\n    def LookAt(self, camera_position:Vec3, target:Vec3, up:Vec3 = (0, 0, 1)):\n        \"\"\"Moves the camera to camera_position facing target. up can be used to adjust the camera roll.\"\"\"\n        NavigationUtils.LookAt(self.ce, camera_position, target, up)\n\n    def Zoom(self, fractionOfDistanceToTarget:float):\n        \"\"\"Moves the camera a fractionOfDistanceToTarget with positive zooming in and negative zooming out.\"\"\"\n        tgt = self.GetTarget()\n        pos = self.GetPosition()\n        dist = np.linalg.norm(tgt - pos)\n        newDist = dist * (1 - fractionOfDistanceToTarget)\n        newPos = tgt + ((pos-tgt)/dist * newDist)\n        self.SetPosition(newPos)\n\n    def GetPosition (self): return np.array(NavigationUtils.GetCameraPosition(self.ce))\n    def GetDirection(self): return np.array(NavigationUtils.GetCameraDirection(self.ce))\n    def GetUp       (self): return np.array(NavigationUtils.GetCameraUp(self.ce))\n    def GetTarget   (self): return np.array(NavigationUtils.GetCameraTarget(self.ce))\n    def SetPosition (self, v:Vec3): NavigationUtils.SetCameraPosition(self.ce, v)\n    def SetDirection(self, v:Vec3): NavigationUtils.SetCameraDirection(self.ce, v)\n    def SetUp       (self, v:Vec3): NavigationUtils.SetCameraUp(self.ce, v)\n    def SetTarget   (self, v:Vec3): NavigationUtils.SetCameraTarget(self.ce, v)\n\n    def __GUIStateParams(self) -> link.GUIStateParams:\n        pm = self.ce.GetParamsMgr()\n        gsp = pm.GetParams(link.GUIStateParams.GetClassType())\n        return gsp\n\n\n    def TrackMovingDomain(self, on=True):\n        \"\"\"Camera should follows the moving domain\"\"\"\n        gsp = self.__GUIStateParams()\n        gsp.SetValueLong(gsp.MovingDomainTrackCameraTag, \"\", on)\n        print(f\"{gsp.MovingDomainTrackCameraTag} = {bool(gsp.GetValueLong(gsp.MovingDomainTrackCameraTag, 0))}\")\n\n    def TrackMovingDomainRenderRegions(self, on=True):\n        \"\"\"Renderer regions will be tracked relative to the moving domain\"\"\"\n        gsp = self.__GUIStateParams()\n        gsp.SetValueLong(gsp.MovingDomainTrackRenderRegionsTag, \"\", on)\n\n"
  },
  {
    "path": "apps/pythonapi/vapor/cmake.py",
    "content": "from pathlib import Path\n\nSOURCE_DIR      = \"@PROJECT_SOURCE_DIR@\"\nBINARY_DIR      = \"@CMAKE_BINARY_DIR@\"\nTHIRD_PARTY_DIR = \"@THIRD_PARTY_DIR@\"\nRELEASE         = \"@CMAKE_BUILD_TYPE@\".lower() == \"release\"\n\nVAPI_COMPILE_DEFS   = \"\"\"@VAPI_COMPILE_DEFS@\"\"\"\nGLOBAL_COMPILE_DEFS = \"\"\"@GLOBAL_COMPILE_DEFS@\"\"\"\n"
  },
  {
    "path": "apps/pythonapi/vapor/common.py",
    "content": "Vec3 = tuple[float, float, float]"
  },
  {
    "path": "apps/pythonapi/vapor/config.py",
    "content": "import sys, os\nimport site\nimport re\nfrom pathlib import Path\nfrom . import cmake\n\nsourcePaths = [\n    cmake.SOURCE_DIR,\n    cmake.SOURCE_DIR + \"/lib/osgl\",\n    cmake.SOURCE_DIR + \"/lib/osgl/glad\",\n    cmake.BINARY_DIR,\n    cmake.THIRD_PARTY_DIR,\n]\n\n# Files installed using setup(data_files) are placed in one of the following two locations:\n#   sys.prefix for system installations\n#   site.USER_BASE for user installations\n# Conda installs files using setup(data_files) in a different location than pip.\n# Conda installs them in the module root like package_data\n\ninstallPaths = [\n    site.USER_BASE,\n    sys.prefix,\n]\ninstallPaths = [Path(p)/'vapor' for p in installPaths]\n\nmodulePaths = [Path(__file__).parent]\n\ncondaPaths = [os.getenv('CONDA_PREFIX', \"/\")]\n\ndef PathExists(path):\n    try:\n        return path.exists()\n    except PermissionError:\n        return False\n\nroots = sourcePaths + installPaths + modulePaths + condaPaths\nallRoots = roots.copy()\nroots = map(Path, roots)\nroots = filter(PathExists, roots)\nroots = [*roots]\n\n# print(\"Resource Roots:\\n\\t\" + \"\\n\\t\".join(map(str, roots)))\n\nif not roots:\n    print(\"Error: Could not find any valid resource paths from\", allRoots)\n    quit(1)\n\ndef GetAllResources(relPath):\n    \"\"\"For source builds where there can be, for example, multiple lib dirs\"\"\"\n    ret = []\n    for root in roots:\n        if (root / relPath).exists():\n            ret.append(str(root / relPath))\n    if ret:\n        return ret\n    raise FileNotFoundError\n\ndef GetResource(relPath):\n    for root in roots:\n        if (root / relPath).exists():\n            return str(root / relPath)\n    raise FileNotFoundError\n    return None\n\ndef GetResourceSafe(relPath):\n    relPath = str(relPath) # If called from C++ this may be something other than a python str\n    ret = \"\"\n    try: ret = GetResource(relPath)\n    except Exception: ret = \"\"\n    if ret == None: ret = \"\"\n    return ret\n\ndef GetDoxygenRoot():\n    try: return GetResource('share/doc/xml')\n    except FileNotFoundError: pass\n    try: return GetResource('doc/xml')\n    except FileNotFoundError: pass\n    return None\n\ndef GetLibraryDirs():\n    return GetAllResources('lib')\n\ndef GetIncludeDirs():\n    return GetAllResources('include')\n\ndef GetCompileDefinitions(debug=False):\n    cmakeDefLists = [\n        cmake.VAPI_COMPILE_DEFS,\n        cmake.GLOBAL_COMPILE_DEFS,\n    ]\n    cmakeDefLists = filter(lambda x: x and not x.endswith('-NOTFOUND'), cmakeDefLists)\n    cmakeDefList = ';'.join(cmakeDefLists)\n    defs = cmakeDefList.split(';')\n    defs = filter(None, defs)\n    cmds = ['#define ' + ' '.join(filter(bool, re.match(r'(\\w+)=?(.*)', d).groups())) for d in defs]\n    if debug:\n        print('\\n'.join([f\"{d} -> '{s}'\" for d,s in zip(defs, cmds)]))\n    code = '\\n'.join(cmds)\n    return code\n\n\ndef IsRunningFromIPython():\n    try:\n        __IPYTHON__\n        return True\n    except NameError:\n        return False\n\n\ndef IsRunningFromMarimo():\n    try:\n        import marimo as mo\n        return mo.app_meta().mode in (\"edit\", \"run\")\n    except:\n        return False\n\n\ndef IsRunningFromNotebook():\n    return IsRunningFromIPython() or IsRunningFromMarimo()\n\n"
  },
  {
    "path": "apps/pythonapi/vapor/cppyyDoxygenWrapper.py",
    "content": "import xml.etree.ElementTree as ET\nimport functools\nfrom . import config\n\n\nclass CPPYYDoxygenWrapperMeta(type):\n    __doxygenRootPath = config.GetDoxygenRoot()\n\n    @classmethod\n    @functools.cache\n    def __GetDoxgenRoot(cls) -> ET.Element:\n        if not cls.__doxygenRootPath:\n            print(\"WARNING DOxygen not found\")\n            return None\n        root = ET.parse(cls.__doxygenRootPath+'/index.xml').getroot()\n        return root\n\n    @classmethod\n    @functools.cache\n    def __GetClassIndexNode(cls, name:str) -> ET.Element:\n        root: ET.Element = cls.__GetDoxgenRoot()\n        if not root: return None\n        return root.find(f\"./compound/name[.='{name}']/..\")\n\n    @classmethod\n    @functools.cache\n    def __GetClassRoot(cls, name:str) -> ET.Element:\n        classIndexNode = cls.__GetClassIndexNode(name)\n        if not classIndexNode: return None\n        relPath = classIndexNode.get('refid') + '.xml'\n        absPath = f\"{cls.__doxygenRootPath}/{relPath}\"\n        try:\n            root = ET.parse(absPath).getroot()\n        except IOError:\n            return  None\n        return root\n\n    @classmethod\n    def __GetMemberNodes(cls, className:str, memberName:str) -> list[ET.Element]:\n        \"\"\"Returns list for overloaded functions\"\"\"\n        root: ET.Element = cls.__GetClassRoot(className)\n        if not root: return None\n        return root.findall(f\"./compounddef/sectiondef/memberdef/name[.='{memberName}']/..\")\n\n    @classmethod\n    def __ParseDescriptionParameterList(cls, plist: ET.Element) -> str:\n        return \" \".join([t.strip() for t in plist.itertext() if t.strip()]).replace(\"\\n\",\"\")\n\n    @classmethod\n    def __RenderParameterListSection(cls, title:str, kind:str, allLists:list[ET.Element]):\n        ret = \"\"\n        kindLists = [pl for pl in allLists if pl.get(\"kind\") == kind]\n        if kindLists:\n            ret += f\"\\n{title}\\n\"\n            for l in kindLists:\n                ret += \"    \" + cls.__ParseDescriptionParameterList(l)\n        return ret\n\n    @classmethod\n    def __ParseDescriptionParagraph(cls, para: ET.Element, parameterLists: list[ET.Element] = []) -> str:\n        if para.tag == \"parameterlist\" or (para.tag == \"simplesect\" and para.get(\"kind\")):\n            parameterLists.append(para)\n            return \"\"\n\n        text = \"\"\n        if para.text:\n            text += para.text.strip()\n\n        for e in para:\n            ret = cls.__ParseDescriptionParagraph(e, parameterLists)\n            if ret.strip():\n                text += \" \" + ret\n\n        if para.tail and para.tail.strip():\n            text += \" \" + para.tail.strip()\n        return text\n\n    @classmethod\n    def __ParseMemberDetailedDescription(cls, member: ET.Element) -> str:\n        ddNode = member.find('detaileddescription')\n        paragraphs = ddNode.findall('para')\n        parameterLists: list[ET.Element] = []\n        parsedParas = [cls.__ParseDescriptionParagraph(p, parameterLists) for p in paragraphs]\n        ret = \"\\n\".join([\"    \"+p for p in parsedParas if p])\n\n        if parameterLists:\n            ret += cls.__RenderParameterListSection(\"Parameters\", \"param\", parameterLists)\n            ret += cls.__RenderParameterListSection(\"Returns\", \"retval\", parameterLists)\n            ret += cls.__RenderParameterListSection(\"See Also\", \"see\", parameterLists)\n\n        return ret\n\n    @classmethod\n    def __CleanFunctionDefinition(cls, ds: str) -> str:\n        ds = ds.removeprefix(\"virtual \")\n        ds = ds.removesuffix(\" const\")\n        return ds\n\n    @classmethod\n    def __GetDocumentationForMemberNode(cls, node: ET.Element) -> str:\n        if node.get(\"kind\") == \"function\":\n            return cls.__GetDocumentationForFunctionNode(node)\n        elif node.get(\"kind\") == \"variable\":\n            return cls.__GetDocumentationForVariableNode(node)\n\n    @classmethod\n    def __GetDocumentationForFunctionNode(cls, node: ET.Element) -> str:\n        name = node.find('name').text\n        definition = node.find('definition').text\n        args = node.find('argsstring').text\n        fullDefinition = cls.__CleanFunctionDefinition(definition+args)\n        detailedDescription = cls.__ParseMemberDetailedDescription(node)\n\n        return f\"\"\"\n{fullDefinition}\n{detailedDescription}\n\"\"\".strip()\n\n    @classmethod\n    def __GetDocumentationForVariableNode(cls, node: ET.Element) -> str:\n        briefdescription = cls.__ParseClassDescription(node.find('briefdescription'))\n        detaileddescription = cls.__ParseClassDescription(node.find('detaileddescription'))\n        return f\"\"\"\n{briefdescription}\n{detaileddescription}\n\"\"\".strip()\n\n    @classmethod\n    def __GetFunctionDocumentation(cls, pCls:type, func) -> str:\n        name = getattr(func, \"__doxygen_name__\",func.__name__)\n        # if hasattr(func, \"__doxygen_name__\"):\n\n        nodes = cls.__GetMemberNodes(pCls.__cpp_name__, name)\n        if not nodes:\n            # DOxygen does not inherit documentation so base classes need to be recursively queried\n            if pCls.__base__ and cls.__GetClassRoot(pCls.__base__.__cpp_name__):\n                return cls.__GetFunctionDocumentation(pCls.__base__, func)\n            return func.__doc__\n        return \"\\n\\n\".join([cls.__GetDocumentationForMemberNode(node) for node in nodes])\n\n    @classmethod\n    def __ParseClassDescription(cls, ddNode: ET.Element) -> str:\n        paragraphs = ddNode.findall('para')\n        parameterLists: list[ET.Element] = []\n        parsedParas = [cls.__ParseDescriptionParagraph(p, parameterLists) for p in paragraphs]\n        ret = \"\\n\".join([\"    \" + p for p in parsedParas if p])\n\n        return ret\n\n    @classmethod\n    def __GetClassDocumentation(cls, pCls) -> str:\n        className = pCls.__cpp_name__\n        root: ET.Element = cls.__GetClassRoot(className)\n        if not root: return None\n        root = root.find('compounddef')\n        if not root: return None\n        briefdescription    = cls.__ParseClassDescription(root.find('briefdescription'))\n        detaileddescription = cls.__ParseClassDescription(root.find('detaileddescription'))\n        return f\"\"\"\nWraps {className}\n{briefdescription}\n{detaileddescription}\n\"\"\".strip()\n\n    @classmethod\n    def _MakeFunctionWrapper(cls, pCls, func):\n        @functools.wraps(func)\n        def f(self, *args, **kwargs):\n            ret = func(self, *args, **kwargs)\n            return ret\n\n        f.__doc__ = cls.__GetFunctionDocumentation(pCls, func)\n\n        return f\n\n    def __new__(cls, clsname, bases, clsdict:dict, wrap:type=None):\n        if wrap:\n            clsdict['__doc__'] = cls.__GetClassDocumentation(wrap)\n        return super(CPPYYDoxygenWrapperMeta, cls).__new__(cls, clsname, bases, clsdict)\n"
  },
  {
    "path": "apps/pythonapi/vapor/dataset.py",
    "content": "from . import link\nfrom .smartwrapper import *\nfrom .renderer import *\nfrom .transform import *\nimport numpy as np\nimport xarray as xr\n\nlink.include('vapor/PythonDataMgr.h')\nlink.include('vapor/DCRAM.h')\nlink.include('vapor/XmlNode.h')\nlink.include('vapor/GUIStateParams.h')\n\nVDC = \"vdc\"\nWRF = \"wrf\"\nCF = \"cf\"\nMPAS = \"mpas\"\nBOV = \"bov\"\nDCP = \"dcp\"\nUGRID = \"ugrid\"\nPYTHON = \"ram\"\n\nclass Dataset(SmartWrapper, wrap=link.VAPoR.DataMgr):\n    _wrap = FuncWrapperStrList(\"\"\"\n    GetDimensionNames\n    GetDimensionLength\n    GetDataVarNames\n    GetCoordVarNames\n    GetTimeCoordVarName\n    GetVarGeometryDim\n    GetVarTopologyDim\n    GetVarCoordVars\n    GetNumTimeSteps\n    IsTimeVarying\n\n    GetMeshNames\n    GetMesh\n    GetDimLens\n    \"\"\")\n\n    def __init__(self, dataMgr:link.VAPoR.DataMgr, id:str, ses):\n        super().__init__(dataMgr)\n        self.id = id\n        self.ses = ses\n\n    def NewRenderer(self, Class: Renderer) -> Renderer:\n        return self.ses.NewRenderer(Class, self.id)\n\n    def GetName(self):\n        return str(self.id)\n    \n    def __str__(self):\n        output = []\n        # Dataset Name\n        output.append(f\"Dataset: {self.GetName()}\")\n        # Dimensions\n        output.append(\"Dimensions:\")\n        for dim in self.GetDimensionNames():\n            output.append(f\"  {dim}: {self.GetDimensionLength(dim, 0)}\")\n        # Coordinates\n        coord_var_names = self.GetCoordVarNames()\n        if len(coord_var_names) > 0:\n            output.append(f\"Coordinate Variable Names: {coord_var_names}\")\n        # Variables\n        output.append(\"Data Variables:\")\n        for var in self.GetDataVarNames():\n            output.extend([\n                f\"  {var}\",\n                f\"    Dimensionality: {self.GetVarGeometryDim(var)}\",\n                f\"    Number of Timesteps: {self.GetNumTimeSteps(var)}\",\n                f\"    Coordinates: {self.GetVarCoordVars(var, True)}\",\n                f\"    Data Range: {self.GetDataRange(var)}\"\n            ])\n\n        return \"\\n\".join(output)\n\n    def __repr__(self):\n        return self.__str__()\n\n    def GetTransform(self):\n        pm = self.ses.ce.GetParamsMgr()\n        vp = pm.GetViewpointParams(self.ses.GetPythonWinName())\n        t = vp.GetTransform(self.id)\n        return Transform(t)\n\n    def GetDataRange(self, varname: str, atTimestep: int = 0):\n        c_range = link.std.vector[link.double]()\n        self._wrappedInstance.GetDataRange(atTimestep, varname, 0, 0, c_range)\n        return list(c_range)\n\n    @staticmethod\n    def GetDatasetTypes():\n        return [VDC, WRF, CF, MPAS, BOV, UGRID]\n\n\nDC = link.VAPoR.DC\n\nclass PythonDataset(Dataset, wrap=link.VAPoR.PythonDataMgr):\n    def __checkNameValid(self, name):\n        if not link.VAPoR.XmlNode.IsValidXMLElement(name):\n            raise Exception(f\"The variable name '{name}' must be a valid XML tag, i.e. [a-Z0-9_-]+\")\n\n\n    def AddNumpyData(self, name:str, arr:np.ndarray):\n        \"\"\"\n        Vapor expects data to be in order='C' with X as the fastest varying dimension.\n        You can swap your axes with np.swapaxes(data, 0, -1).\n        \"\"\"\n        self.__checkNameValid(name)\n        # assert arr.dtype == np.float32\n        if arr.__array_interface__['strides']:\n            arr = arr.copy() # Flatten data\n        self._wrappedInstance.AddRegularData(name, np.float32(arr), tuple(reversed(arr.shape)))\n        # TODO: Only clear necessary renderers\n        self.ses.ce.ClearAllRenderCaches()\n\n\n    def AddXArrayData(self, varName:str, arr:xr.DataArray):\n        \"\"\"\n        Vapor supports grids commonly used in earth science data.\n        It is recommended to import more complex datasets directly using Session.OpenDataset() as this will ensure coordinates and time varying data are handled automatically.\n        Since xarray does not distinguish temporal dimensions your data will be interpeded as len(n.dims) space-dimensional, therefore arr must only contain spacial dimensions.\n        Vapor expects data to be in order='C' with X as the fastest varying dimension.\n        \"\"\"\n\n        assert len(arr.coords) == 0 or len(arr.coords) >= len(arr.dims)\n\n        if not arr.coords:\n            return self.AddNumpyData(varName, arr.data)\n        \n        self.__checkNameValid(varName)\n        # assert arr.dtype == np.float32\n        dc = self._wrappedInstance.GetDC()\n        dimNames = []\n        dimNameMap = {}\n        xDims = list(arr.sizes.items())\n        # DC::Mesh requires dimensions to be specified in reverse order\n        # i.e. if data is slowest to fastest, DC::Mesh expects them in fastest to slowest\n        xDims.reverse()\n\n        for name,length in xDims:\n            genName = f\"__{varName}_dim_{name}\"\n            dim = DC.Dimension(genName, length)\n            dc.AddDimension(dim)\n            dimNames += [genName]\n            dimNameMap[name] = genName\n\n        coordNames = []\n        for axis,name in enumerate(arr.coords):\n            genName = f\"__{varName}_coord_{name}\"\n            xCoord = arr[name]\n            # assert xCoord.dtype == np.float32\n            periodic = [False]*len(xCoord.dims)\n            uniformHint = False\n            timeDim = \"\"\n            mappedDims = [dimNameMap[d] for d in xCoord.dims]\n            mappedDims.reverse() # DC.CoordVar expects these in fastest to slowest\n            coord = DC.CoordVar(genName, \"m\", DC.FLOAT, periodic, axis, uniformHint, mappedDims, timeDim)\n            xCoordData = xCoord.data.astype(np.float32, copy=False)\n            dc.AddCoordVar(coord, np.float32(xCoordData))\n            coordNames += [genName]\n\n        meshGenName = f\"__{varName}_mesh_{DC.Mesh.MakeMeshName(dimNames)}\"\n        mesh = DC.Mesh(meshGenName, dimNames, coordNames)\n        dc.AddMesh(mesh)\n\n        periodic = [False] * len(arr.dims)\n        timeCoordVar = \"\"\n        var = DC.DataVar(varName, \"\", DC.FLOAT, periodic, mesh.GetName(), timeCoordVar, DC.Mesh.NODE)\n\n        dc.AddDataVar(var, np.float32(arr.data));\n\n        for v in [varName]+coordNames:\n            self._wrappedInstance.ClearCache(v)\n\n        # TODO: Only clear necessary renderers\n        self.ses.ce.ClearAllRenderCaches()\n"
  },
  {
    "path": "apps/pythonapi/vapor/link.py",
    "content": "import wurlitzer, re\nwith wurlitzer.pipes() as (out, err):\n    import cppyy\nprint(out.read(), end=\"\")\nprint(\"\".join(l for l in err.read().splitlines() if not any(x in l for x in (\"(ignoring for now)\", \"building pre-compiled headers\"))), end=\"\")\n\n\nfrom . import config\n\nfor path in config.GetIncludeDirs():\n    cppyy.add_include_path(path)\n\nfor path in config.GetLibraryDirs():\n    # print(f\"Add lib path '{path}'\")\n    cppyy.add_library_path(path)\n\ncppyy.cppdef(config.GetCompileDefinitions())\n\ncppyy.load_library('vapi')\n\n# if platform.system() == \"Darwin\":\n#     cppyy.cppdef(\"#define Darwin 1\")\n\n# from cppyy import include, gbl\n\nclass Link:\n    from cppyy import gbl\n\n    def include(self, path):\n        # print(\"- include\", path)\n        return cppyy.include(path)\n\n    @staticmethod\n    def FixModuleOwnership(Class):\n        \"\"\"\n        Classes that directly inherit from CPPYY C++ classes have an incorrect __module__ attr\n        \"\"\"\n        import inspect\n        callerModule = inspect.getmodule(inspect.stack()[1][0])\n        Class.__module__ = callerModule.__name__\n        return Class\n\n    def __getattr__(self, name):\n        return getattr(cppyy.gbl, name)\n\n\nimport sys\nsys.modules[__name__] = Link()\n"
  },
  {
    "path": "apps/pythonapi/vapor/params.py",
    "content": "from . import link\nfrom .smartwrapper import *\n\nlink.include('vapor/ParamsBase.h')\nParamsBase = link.VAPoR.ParamsBase\n\nclass ParamsWrapper(SmartWrapper):\n    def __init__(self, p:ParamsBase):\n        self._params = p\n        super().__init__(p)\n\n\nclass ParamsTagWrapper(FuncWrapper):\n    def __init__(self, tag:str):\n        self._tag = tag\n\n    def __getAccessorRootName(self):\n        tagName = self._tag\n        if tagName.lower().endswith(\"tag\"): tagName = tagName[0:-3]\n        if tagName.startswith(\"_\"): tagName = tagName[1:]\n        tagName = tagName[0].upper() + tagName[1:]\n        return tagName\n\n    def _getSetter(wself, cls):\n        raise NotImplementedError\n\n    def _getGetter(wself, cls):\n        raise NotImplementedError\n\n    def GetFunctionsToWrap(self, cls, name:str):\n        assert hasattr(cls, self._tag)\n        setter = self._getSetter(cls)\n        getter = self._getGetter(cls)\n        setter.__name__ = \"Set\" + self.__getAccessorRootName()\n        getter.__name__ = \"Get\" + self.__getAccessorRootName()\n        setter.__doxygen_name__ = self._tag\n        getter.__doxygen_name__ = self._tag\n        return [setter, getter]\n\n\nclass ParamsTagWrapperLong(ParamsTagWrapper):\n    def __init__(self, tag:str):\n        self._tag = tag\n\n    def _getSetter(wself, cls):\n        # Self is params class\n        def setter(self, value: int):\n            return self.SetValueLong(getattr(cls, wself._tag), \"\", value)\n        return setter\n\n    def _getGetter(wself, cls):\n        # Self is params class\n        def getter(self) -> int:\n            return self.GetValueLong(getattr(cls, wself._tag), 0)\n        return getter\n\n\nclass ParamsTagWrapperBool(ParamsTagWrapper):\n    def __init__(self, tag:str):\n        self._tag = tag\n\n    def _getSetter(wself, cls):\n        # Self is params class\n        def setter(self, value: bool):\n            return self.SetValueLong(getattr(cls, wself._tag), \"\", value)\n        return setter\n\n    def _getGetter(wself, cls):\n        # Self is params class\n        def getter(self) -> bool:\n            return self.GetValueLong(getattr(cls, wself._tag), 0)\n        return getter\n\n\nclass ParamsTagWrapperDouble(ParamsTagWrapper):\n    def __init__(self, tag:str):\n        self._tag = tag\n\n    def _getSetter(wself, cls):\n        # Self is params class\n        def setter(self, value: float):\n            return self.SetValueDouble(getattr(cls, wself._tag), \"\", value)\n        return setter\n\n    def _getGetter(wself, cls):\n        # Self is params class\n        def getter(self) -> float:\n            return self.GetValueDouble(getattr(cls, wself._tag), 0)\n        return getter\n\n\nclass ParamsTagWrapperString(ParamsTagWrapper):\n    def __init__(self, tag:str):\n        self._tag = tag\n\n    def _getSetter(wself, cls):\n        # Self is params class\n        def setter(self, value: str):\n            return self.SetValueString(getattr(cls, wself._tag), \"\", value)\n        return setter\n\n    def _getGetter(wself, cls):\n        # Self is params class\n        def getter(self) -> str:\n            return self.GetValueString(getattr(cls, wself._tag), 0)\n        return getter\n\n\nclass ParamsTagWrapperList(FuncWrapper):\n    \"\"\"\n    Takes following format:\n        long FirstTag\n        long SecondTag\n        string ThirdTag\n    \"\"\"\n    def __init__(self, slist:str):\n        self._l = self.MakeList(slist)\n\n    def MakeList(self, s: str):\n        return list(filter(None, [str.strip(s) for s in s.split('\\n')]))\n\n    def __makeWrapper(self, typ, tag):\n        if   typ == \"long\":\n            return ParamsTagWrapperLong(tag)\n        elif typ == \"bool\":\n            return ParamsTagWrapperBool(tag)\n        elif typ == \"double\":\n            return ParamsTagWrapperDouble(tag)\n        elif typ == \"string\":\n            return ParamsTagWrapperString(tag)\n        else:\n            raise TypeError\n\n    def GetFunctionsToWrap(self, cls, name:str):\n        return [func for entry in self._l for typ, tag in [entry.split()] for func in self.__makeWrapper(typ, tag).GetFunctionsToWrap(cls, name)]\n        # for entry in self._l:\n        #     print(entry, \"|\", entry.split())\n        for entry in self._l:\n            print(entry.split())\n            typ, tag = entry.split()\n            for func in self.__makeWrapper(typ, tag).GetFunctionsToWrap(cls, name):\n                print(func)"
  },
  {
    "path": "apps/pythonapi/vapor/renderer.py",
    "content": "from . import link\nfrom .params import *\nfrom .transferfunction import *\nfrom . import config\nfrom .annotations import *\nfrom .transform import *\nfrom pathlib import Path\n\nlink.include('vapor/ControlExecutive.h')\n\nlink.include('vapor/Box.h')\nclass BoundingBox():\n    def __init__(self, toWrap:link.VAPoR.Box):\n        self._params = toWrap\n\n    def SetExtents(self, min, max):\n        \"\"\"Sets the region extents. min and max can be 2 or 3-element vectors depending on the dimension of the region.\"\"\"\n        self._params.SetExtents(min, max)\n\n    def GetExtents(self):\n        \"\"\"\n        Returns a tuple (min, max) containing the respective region bounds\n        \"\"\"\n        min = link.gbl.std.vector[link.gbl.double]()\n        max = link.gbl.std.vector[link.gbl.double]()\n        self._params.GetExtents(min, max)\n        return list(min), list(max)\n\n\nRenderParams = link.VAPoR.RenderParams\n\nclass Renderer(ParamsWrapper, wrap=RenderParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n    SetEnabled\n    IsEnabled\n    \n    GetVariableName\n    SetAuxVariableNames\n    GetAuxVariableNames\n    SetFieldVariableNames\n    GetFieldVariableNames\n    SetXFieldVariableName\n    SetYFieldVariableName\n    SetZFieldVariableName\n    GetXFieldVariableName\n    GetYFieldVariableName\n    GetZFieldVariableName\n    SetHeightVariableName\n    GetHeightVariableName\n    SetColorMapVariableName\n    GetColorMapVariableName\n    \n    SetUseSingleColor\n    UseSingleColor\n    GetConstantOpacity\n    SetConstantOpacity\n    \n    GetTransform\n    ResetUserExtentsToDataExents\n    \n    SetRefinementLevel\n    GetRefinementLevel\n    SetCompressionLevel\n    GetCompressionLevel\n    \"\"\")\n    VaporName = None\n\n    def __init__(self, renderParams:link.VAPoR.RenderParams, id:str):\n        super().__init__(renderParams)\n        self.id = id\n\n    def GetTransferFunction(self, varname:str=None) -> TransferFunction:\n        if varname is None:\n            return self.GetPrimaryTransferFunction()\n        return TransferFunction(self._params.GetMapperFunc(varname))\n\n    def GetPrimaryTransferFunction(self) -> TransferFunction:\n        \"\"\"Returns the transfer function for the primary rendered variable.\n        This is usually the variable that is being colormapped and would be\n        represented by the colorbar.\"\"\"\n        return self.GetTransferFunction(self._params.GetActualColorMapVariableName())\n\n    def SetVariableName(self, name:str):\n        # newDim = self._params._dataMgr.GetNumDimensions(name)\n        # oldDim = self._params._dataMgr.GetNumDimensions(self.GetVariableName())\n        # if newDim != oldDim:\n        #     self.__setDimensions(newDim)\n        self._params.SetVariableName(name)\n        self._params.ResetUserExtentsToDataExents()\n\n    def GetRenderRegion(self) -> BoundingBox:\n        return BoundingBox(self._params.GetBox())\n\n    def GetColorbarAnnotation(self) -> ColorbarAnnotation:\n        return ColorbarAnnotation(self._params.GetColorbarPbase())\n\n    def SetDimensions(self, dim:int):\n        assert dim == 2 or dim == 3\n        self._params.BeginGroup(\"Change dim\")\n        if dim == 2:\n            self._params.GetBox().SetPlanar(True)\n            self._params.GetBox().SetOrientation(link.VAPoR.Box.XY)\n        else:\n            self._params.GetBox().SetPlanar(False)\n            self._params.GetBox().SetOrientation(link.VAPoR.Box.XYZ)\n        self._params.SetDefaultVariables(dim, True)\n        self._params.EndGroup()\n\n\nlink.include('vapor/BarbParams.h')\nlink.include('vapor/BarbRenderer.h')\nclass BarbRenderer(Renderer, wrap=link.VAPoR.BarbParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n        GetGrid\n        SetGrid\n        GetLengthScale\n        SetLengthScale\n        GetLineThickness\n        SetLineThickness\n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n        long _xBarbsCountTag\n        long _yBarbsCountTag\n        long _zBarbsCountTag\n    \"\"\")\n\n\nlink.include('vapor/TwoDDataRenderer.h')\nclass TwoDDataRenderer(Renderer, wrap=link.VAPoR.TwoDDataParams):\n    pass\n\n\nlink.include('vapor/ContourRenderer.h')\nclass ContourRenderer(Renderer, wrap=link.VAPoR.ContourParams):\n    def GetIsoValues(self) -> list[float]:\n        return self._params.GetIsoValues(self.GetVariableName())\n\n    def SetIsoValues(self, values: list[float]):\n        return self._params.SetIsoValues(self.GetVariableName(), values)\n\n\nlink.include('vapor/VolumeRenderer.h')\nlink.include('vapor/VolumeParams.h')\nclass VolumeRenderer(Renderer, wrap=link.VAPoR.VolumeParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n    GetAlgorithm\n    \n    GetSamplingMultiplier\n    SetSamplingMultiplier\n    \n    SetLightingEnabled\n    GetLightingEnabled\n    SetPhongAmbient\n    GetPhongAmbient\n    SetPhongDiffuse\n    GetPhongDiffuse\n    SetPhongSpecular\n    GetPhongSpecular\n    SetPhongShininess\n    GetPhongShininess\n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n        double VolumeDensityTag\n        bool UseColormapVariableTag\n    \"\"\")\n\n    def SetAlgorithm(self, algorithm: str):\n        \"\"\"Manually set the rendering algorithm. This is usually done automatically. Valid values in GetAlgorithmNames().\"\"\"\n        if algorithm not in self.GetAlgorithmNames():\n            raise ValueError(\"Algorithm needs to be one of\", self.GetAlgorithmNames())\n        self._params.SetAlgorithmByUser(algorithm)\n\n    def GetAlgorithmNames(self, types=link.VAPoR.VolumeParams.Type.DVR):\n        return link.VAPoR.VolumeParams.GetAlgorithmNames(types)\n\n\nlink.include('vapor/VolumeIsoRenderer.h')\nlink.include('vapor/VolumeIsoParams.h')\nclass VolumeIsoRenderer(VolumeRenderer, wrap=link.VAPoR.VolumeIsoParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n    \n    \"\"\")\n\n    def GetAlgorithmNames(self):\n        return super().GetAlgorithmNames(link.VAPoR.VolumeParams.Type.Iso)\n\n    def GetIsoValues(self) -> list[float]:\n        return self._params.GetIsoValues(self.GetVariableName())\n\n    def SetIsoValues(self, values: list[float]):\n        \"\"\"Supports at most 4 simultaneous iso-surfaces per renderer\"\"\"\n        return self._params.SetIsoValues(self.GetVariableName(), values)\n\n\nlink.include('vapor/FlowRenderer.h')\nlink.include('vapor/FlowParams.h')\nclass FlowRenderer(Renderer, wrap=link.VAPoR.FlowParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n        SetIsSteady\n        GetIsSteady\n        GetVelocityMultiplier\n        SetVelocityMultiplier\n        GetSteadyNumOfSteps\n        SetSteadyNumOfSteps\n        GetSeedGenMode\n        SetSeedGenMode\n        GetFlowDirection\n        SetFlowDirection\n        GetSeedInputFilename\n        SetSeedInputFilename\n        GetFlowlineOutputFilename\n        SetFlowlineOutputFilename\n        GetNeedFlowlineOutput\n        SetNeedFlowlineOutput\n        GetFlowOutputMoreVariables\n        SetFlowOutputMoreVariables\n        GetPeriodic\n        SetPeriodic\n        GetGridNumOfSeeds\n        SetGridNumOfSeeds\n        GetRandomNumOfSeeds\n        SetRandomNumOfSeeds\n        GetRakeBiasVariable\n        SetRakeBiasVariable\n        GetRakeBiasStrength\n        SetRakeBiasStrength\n        GetSeedInjInterval\n        SetSeedInjInterval\n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n        long RenderTypeTag\n        double RenderRadiusScalarTag\n        bool RenderGeom3DTag\n        bool RenderShowStreamDirTag\n        \n        long RenderGlyphTypeTag\n        long RenderGlyphStrideTag\n        bool RenderGlyphOnlyLeadingTag\n        \n        double RenderDensityFalloffTag\n        double RenderDensityToneMappingTag\n        \n        bool RenderFadeTailTag\n        long RenderFadeTailStartTag\n        long RenderFadeTailStopTag\n        long RenderFadeTailLengthTag\n        \n        double PhongAmbientTag\n        double PhongDiffuseTag\n        double PhongSpecularTag\n        double PhongShininessTag\n    \"\"\")\n\n    FlowDir = EnumWrapper(link.VAPoR.FlowDir)\n    FlowSeedMode = EnumWrapper(link.VAPoR.FlowSeedMode)\n    RenderType = EnumWrapper(link.VAPoR.FlowParams.RenderType)\n    GlpyhType = EnumWrapper(link.VAPoR.FlowParams.GlpyhType)\n\n    def GetRakeRegion(self) -> BoundingBox:\n        return BoundingBox(self._params.GetRakeBox())\n\n    def GetIntegrationRegion(self) -> BoundingBox:\n        return BoundingBox(self._params.GetIntegrationBox())\n\n\nlink.include('vapor/ParticleRenderer.h')\nlink.include('vapor/ParticleParams.h')\nclass ParticleRenderer(Renderer, wrap=link.VAPoR.ParticleParams):\n    _tags = ParamsTagWrapperList(\"\"\"\n        long StrideTag\n        \n        long ShowDirectionTag\n        double RenderRadiusScalarTag\n        double DirectionScaleTag\n        \n        double PhongAmbientTag\n        double PhongDiffuseTag\n        double PhongSpecularTag\n        double PhongShininessTag\n    \"\"\")\n\n\nlink.include('vapor/WireFrameRenderer.h')\nlink.include('vapor/WireFrameParams.h')\nclass WireFrameRenderer(Renderer, wrap=link.VAPoR.WireFrameParams):\n    pass\n\n\nlink.include('vapor/ImageRenderer.h')\nlink.include('vapor/ImageParams.h')\nclass ImageRenderer(Renderer, wrap=link.VAPoR.ImageParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n        SetImagePath\n        GetImagePath\n        SetIsGeoRef\n        GetIsGeoRef\n        SetIgnoreTransparency\n        GetIgnoreTransparency\n    \"\"\")\n\n    def ListBuiltinMaps(self) -> list[str]:\n        tms = config.GetResource(\"share/images/NaturalEarth.tms\")\n        if not tms:\n            return []\n        tmsDir = Path(tms).parent\n        return [f.stem for f in tmsDir.iterdir() if f.suffix == \".tms\"]\n\n    def SetBuiltinMap(self, name: str):\n        path = config.GetResource(f\"share/images/{name}.tms\")\n        self.SetImagePath(path)\n\n\nlink.include('vapor/SliceRenderer.h')\nlink.include('vapor/SliceParams.h')\nclass SliceRenderer(Renderer, wrap=link.VAPoR.SliceParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n        GetSlicePlaneRotation\n        GetSlicePlaneOrigin\n        GetSlicePlaneNormal\n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n        double XSlicePlaneOriginTag\n        double YSlicePlaneOriginTag\n        double ZSlicePlaneOriginTag\n        double XSlicePlaneRotationTag\n        double YSlicePlaneRotationTag\n        double ZSlicePlaneRotationTag\n        double SampleRateTag\n        double SliceOffsetTag\n        double SlicePlaneNormalXTag\n        double SlicePlaneNormalYTag\n        double SlicePlaneNormalZTag\n        long SlicePlaneOrientationModeTag\n    \"\"\")\n    SlicePlaneOrientationMode = link.VAPoR.RenderParams.SlicePlaneOrientationMode\n\n\nlink.include('vapor/ModelRenderer.h')\nlink.include('vapor/ModelParams.h')\nclass ModelRenderer(Renderer, wrap=link.VAPoR.ModelParams):\n    _wrap = FuncWrapperStrList(\"\"\"\n        \n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n        string FileTag\n    \"\"\")\n    SlicePlaneOrientationMode = link.VAPoR.RenderParams.SlicePlaneOrientationMode\n\n\nfor Class in Renderer.__subclasses_rec__():\n    Class.VaporName = link.__getattr__(Class.__name__).GetClassType()\n\n\n# print(\"Renderer:\", [f for f in dir(Renderer) if not f.startswith('__')])\n# print(\"TwoDDataRenderer:\", [f for f in dir(TwoDDataRenderer) if not f.startswith('__')])\n"
  },
  {
    "path": "apps/pythonapi/vapor/session.py",
    "content": "from . import link\nfrom .renderer import Renderer\nfrom .renderer import *\nfrom .dataset import *\nfrom .camera import *\nfrom .annotations import *\n\nimport PIL.Image\n\nlink.include('vapor/Session.h')\nlink.include('vapor/RenderManager.h')\n\n@link.FixModuleOwnership\nclass Session(link.Session):\n    def __init__(self):\n        super().__init__(True)\n        self.ce = super()._controlExec\n\n    def NewRenderer(self, Class:Renderer, datasetName:str) -> Renderer:\n        id = super().NewRenderer(Class.VaporName, datasetName)\n        if not id: return None\n        p = self.GetRenderer(id)\n        p.SetEnabled(True)\n        return p\n\n    def DeleteRenderer(self, renderer:Renderer):\n        super().DeleteRenderer(renderer.id)\n\n    def GetRenderer(self, name):\n        c_win = link.std.string()\n        c_dat = link.std.string()\n        c_typ = link.std.string()\n        self.ce.RenderLookup(name, c_win, c_dat, c_typ)\n        p = self.ce.GetRenderParams(c_win, c_dat, c_typ, name)\n        assert p\n        return SmartWrapper.AutoWrap(p, name)\n\n    def GetRenderers(self) -> list[Renderer]:\n        return [self.GetRenderer(name) for name in self.GetRendererNames()]\n\n    def OpenDataset(self, datasetType:str, files:list[str]):\n        \"\"\"\n        Open a dataset of type datasetType from a list of files.\n        A list of supported dataset types can be retrieved from Dataset.GetDatasetTypes()\n        \"\"\"\n        files = [files] if type(files) is not list else files\n        files = [*map(str, files)]\n        name = super().OpenDataset(datasetType, files)\n        if (len(name) == 0): return None\n        return self.GetDataset(name)\n\n    def CreatePythonDataset(self):\n        \"\"\"\n        Creates a python dataset or returns one if it already exists for the current session.\n        \"\"\"\n        name = \"PYTHON_RAM_DATASET\"\n        if self.GetDataset(name):\n            return self.GetDataset(name)\n        return self.OpenDataset(PYTHON, name)\n\n    def GetDataset(self, name) -> Dataset:\n        dataMgr = self.ce.GetDataStatus().GetDataMgr(name)\n        if not dataMgr: return None\n        return SmartWrapper.AutoWrap(dataMgr, name, self)\n\n    def GetDatasets(self):\n        return [self.GetDataset(name) for name in self.GetDatasetNames()]\n\n    def GetCamera(self):\n        return Camera(self.ce)\n\n    def RenderToImage(self, fast=False) -> PIL.Image:\n        from PIL import Image\n        from array import array\n        width, height = self._renderManager.GetResolution()\n        nBytes = width * height * 3\n        buf = array('B', [0] * nBytes)\n        address, length = buf.buffer_info()\n        assert length == nBytes\n        self.Render(f\":RAM:{address:x}\", fast)\n        return Image.frombytes(\"RGB\", (width, height), buf.tobytes())\n\n    def Show(self):\n        from IPython.display import display\n\n        img = self.RenderToImage()\n\n        if config.IsRunningFromNotebook():\n            display(img)\n        else:\n            img.show()\n\n    def SetResolution(self, width, height):\n        self._renderManager.SetResolution(width, height)\n\n    def GetSceneAnnotations(self) -> SceneAnnotation:\n        pm = self.ce.GetParamsMgr()\n        ap = pm.GetAnnotationParams(self.GetPythonWinName())\n        return SceneAnnotation(ap)\n\n    def GetAxisAnnotations(self) -> AxisAnnotation:\n        return AxisAnnotation(self.GetSceneAnnotations()._params.GetAxisAnnotation())\n\n"
  },
  {
    "path": "apps/pythonapi/vapor/smartwrapper.py",
    "content": "import re, sys\nimport functools\nfrom . import cppyyDoxygenWrapper\nimport cppyy\n\n\nclass FuncWrapper():\n    def GetFunctionsToWrap(self, cls, name):\n        names = self.GetFunctionNamesToWrap(cls, name)\n        return [getattr(cls, name) for name in names]\n\n    def GetFunctionNamesToWrap(self, cls, name) -> list[str]:\n        assert hasattr(cls, name)\n        return [name]\n\n    def GetWrappedFunctionName(self, memberName, func) -> str:\n        return func.__name__\n\n\nclass FuncWrapperRename(FuncWrapper):\n    def __init__(self, toWrapName:str):\n        self._toWrapName = toWrapName\n\n    def GetFunctionNamesToWrap(self, cls, name) -> list[str]:\n        assert hasattr(cls, self._toWrapName)\n        return [self._toWrapName]\n\n    def GetWrappedFunctionName(self, memberName, func) -> str:\n        return memberName\n\n\nclass FuncWrapperWrapAll(FuncWrapper):\n    def GetFunctionNamesToWrap(self, cls, name):\n        return [f for f in dir(cls) if not f.startswith('_') and callable(getattr(cls, f))]\n\n\nclass FuncWrapperRegex(FuncWrapper):\n    def __init__(self, regex):\n        self._r = re.compile(regex)\n\n    def GetFunctionNamesToWrap(self, cls, name):\n        return [f for f in dir(cls) if self._r.fullmatch(f) is not None and callable(getattr(cls, f))]\n\n\nclass FuncWrapperStrList(FuncWrapper):\n    def __init__(self, slist:str):\n        self._l = self.MakeList(slist)\n        self._ensureNamesStartUppercase = False\n\n    def MakeList(self, s: str):\n        return list(filter(None, [str.strip(s) for s in s.split('\\n')]))\n\n    def GetFunctionNamesToWrap(self, cls, name):\n        for name in self._l:\n            assert hasattr(cls, name)\n        return self._l.copy()\n\n    def GetWrappedFunctionName(self, memberName, func):\n        name = super().GetWrappedFunctionName(memberName, func)\n        if self._ensureNamesStartUppercase:\n            name = name[0].upper() + name[1:]\n        return name\n\n    def EnsureNamesStartUppercase(self):\n        self._ensureNamesStartUppercase = True\n        return self\n\n\ndef FuncWrappers(n: int = 32):\n    for x in range(n):\n        yield FuncWrapper\n\n\nclass SmartWrapperMeta(cppyyDoxygenWrapper.CPPYYDoxygenWrapperMeta):\n    __wrappedToWrapperRegistry = {\n        cppyy.gbl.std.string: lambda s: str(s),\n        cppyy.gbl.std.vector[str]: lambda v: list(map(str, v)),\n        cppyy.gbl.std.vector[int]: lambda v: list(v),\n        cppyy.gbl.std.vector[float]: lambda v: list(v),\n        cppyy.gbl.std.vector[cppyy.gbl.long]: lambda v: list(v),\n        cppyy.gbl.std.vector[cppyy.gbl.double]: lambda v: list(v),\n    }\n\n    def __new__(cls, clsname, bases, clsdict:dict, wrap:type=None):\n        clsdict['_wrappedClass'] = wrap\n        for name in list(clsdict.keys()):\n            val = clsdict[name]\n            if isinstance(val, FuncWrapper):\n                assert wrap is not None\n                toWrap = val.GetFunctionsToWrap(wrap, name)\n                del clsdict[name]\n                wrappedFunctions = [cls._MakeFunctionWrapper(wrap, f) for f in toWrap]\n                wrappedDict = {val.GetWrappedFunctionName(name, f):f for f in wrappedFunctions}\n                if any((duplicate_name:=n) in clsdict for n in wrappedDict):\n                    print(f'WARNING: Function \"{duplicate_name}\" exposed multiple times', file=sys.stderr)\n                clsdict.update(wrappedDict)\n        return super(SmartWrapperMeta, cls).__new__(cls, clsname, bases, clsdict, wrap=wrap)\n\n    def __init__(cls, *args, **kwargs):\n        cls.__wrappedToWrapperRegistry[cls._wrappedClass] = cls\n        super().__init__(*args, **kwargs)\n\n    @classmethod\n    def AutoWrap(cls, toWrap, *args, **kwargs):\n        if type(toWrap) in cls.__wrappedToWrapperRegistry:\n            return cls.__wrappedToWrapperRegistry[type(toWrap)](toWrap, *args, **kwargs)\n        return toWrap\n\n    @classmethod\n    def _MakeFunctionWrapper(cls, pCls, func):\n        # assert hasattr(pCls, func.__name__)\n\n        @functools.wraps(func)\n        def f(self, *args, **kwargs):\n            ret = func(self._wrappedInstance, *args, **kwargs)\n            return cls.AutoWrap(ret)\n\n        return super()._MakeFunctionWrapper(pCls, f)\n\n\nclass SmartWrapper(metaclass=SmartWrapperMeta):\n    def __init__(self, toWrap):\n        if not type(toWrap) == self._wrappedClass:\n            raise ValueError(f\"{type(toWrap)} is not {self._wrappedClass}\")\n        self._wrappedInstance = toWrap\n\n    @classmethod\n    def __subclasses_rec__(cls):\n        return set(cls.__subclasses__()).union([s for c in cls.__subclasses__() for s in c.__subclasses_rec__()])\n\n\nclass EnumWrapperMeta(type):\n    def __repr__(self):\n        return \"Enum Class\"\n\ndef EnumWrapper(Class:type):\n    d = dict(Class.__dict__)\n    d['__doc__'] = \"\\n\" + \"Enum with the following options:\" + \"\\n    \".join([\"\"]+[*filter(lambda x: not x.startswith(\"__\"), d.keys())])\n    return EnumWrapperMeta(Class.__name__, Class.__bases__, d)"
  },
  {
    "path": "apps/pythonapi/vapor/transferfunction.py",
    "content": "from . import link\nfrom .params import *\nfrom .common import *\nfrom . import config\nfrom typing import Iterable, Any\nimport functools\nfrom pathlib import Path\nimport pylab as pl\nimport numpy as np\n\nlink.include('vapor/MapperFunction.h')\n\nclass TransferFunction(ParamsWrapper, wrap=link.VAPoR.MapperFunction):\n    _wrap = FuncWrapperStrList(\"\"\"\n        getOpacityScale\n        setOpacityScale\n        getMinMapValue\n        setMinMapValue\n        getMaxMapValue\n        setMaxMapValue\n        getMinMaxMapValue\n\n        LoadFromFile\n        LoadColormapFromFile\n        \"\"\").EnsureNamesStartUppercase()\n\n    def LoadBuiltinColormap(self, name:str) -> None:\n        \"\"\"See ListBuiltinColormaps\"\"\"\n        return self.LoadColormapFromFile(config.GetResource(f'share/palettes/{name}.tf3'))\n\n    @classmethod\n    def ListBuiltinColormaps(cls) -> list[str]:\n        root = Path(config.GetResource(f'share/palettes'))\n        return [f\"{category.name}/{color.stem}\" for category in root.iterdir() for color in category.iterdir()]\n\n    def __normalizeControlPoints(self, cp: list[tuple[float, Any]]):\n        rMin = self.GetMinMapValue()\n        rMax = self.GetMaxMapValue()\n        normalize = lambda x: (x - rMin) / (rMax - rMin) if rMax - rMin > 0 else x\n        return [(normalize(x), y) for x, y in cp]\n\n    @staticmethod\n    def __enumerateNormDist(l: list[float]):\n        if not l: return []\n        if len(l) == 1: return [(0.5, l[0])]\n        return [(n / (len(l) - 1), v) for n, v in enumerate(l)]\n\n    @staticmethod\n    def __swapEachXY(l: list):\n        return [(y, x) for x, y in l]\n\n    @staticmethod\n    def __flatten(l: list):\n        def flatten(l):\n            for i in l:\n                if isinstance(i, Iterable):\n                    for j in flatten(i):\n                        yield j\n                else:\n                    yield i\n        return list(flatten(l))\n\n    def __rgbToHsv(self, rgb):\n        if len(rgb) != 3:\n            raise ValueError(\"rgb list must have 3 values\")\n        return [*self._params.rgbToHsv(rgb)]\n\n    def SetOpacityNormalizedControlPoints(self, cp: list[tuple[float, float]]):\n        \"\"\"Sets opacities for normalized x,y values\"\"\"\n        oMap = self._params.GetOpacityMap(0)\n        # cp = [y0, x0, y1, x1, ...]\n        oMap.SetControlPoints(self.__flatten(self.__swapEachXY(cp)))\n\n    def SetOpacityList(self, opacities: list[float]):\n        \"\"\"Sets opacities as equally spaced control points\"\"\"\n        self.SetOpacityNormalizedControlPoints(self.__enumerateNormDist(opacities))\n\n    def SetOpacityControlPoints(self, cp: list[tuple[float, float]]):\n        \"\"\"\n        Sets opacity points for x,y values where MinMapValue<=x<=MaxMapValue and 0<=y<=1\n        Expects a list of form [[x1, y1], [x2, y2], ...] with x representing data values and y representing opacity values\n        Warning: The points are stored as normalized coordinates so if the MapValue range changes\n        it will not be reflected in the mapping range\n        \"\"\"\n        self.SetOpacityNormalizedControlPoints(self.__normalizeControlPoints(cp))\n    \n    def GetOpacityControlPoints(self):\n        \"\"\"\n        Returns opacity points in the form [[x1, y1], [x2, y2], ...] \n        with x representing data values and y representing opacity values\n        \"\"\"\n        minv, maxv = self.GetMinMapValue(), self.GetMaxMapValue()\n        opacities_normalized = np.array(self._params.GetOpacityMap(0).GetControlPoints()).reshape(-1, 2)\n        y = opacities_normalized[:, 0]\n        x_norm = opacities_normalized[:, 1]\n        x_data = x_norm * (maxv - minv) + minv # undo normalization\n        return np.stack([x_data, y], axis=1)\n\n    def SetColorNormalizedHSVControlPoints(self, cp: list[tuple[float, Vec3]]):\n        \"\"\"Sets colormap for normalized data values\"\"\"\n        cMap: link.VAPoR.ColorMap = self._params.GetColorMap()\n        # cp = [h0, s0, v0, x0, h1, s1, v1, x1, ...]\n        cMap.SetControlPoints(self.__flatten(self.__swapEachXY(cp)))\n\n    def SetColorHSVList(self, colors: list[Vec3]):\n        \"\"\"Sets colormap as equally spaced control points\"\"\"\n        self.SetColorNormalizedHSVControlPoints(self.__enumerateNormDist(colors))\n\n    def ReverseColormap(self):\n        \"\"\"Reverses the colormap\"\"\"\n        self.SetColorRGBList([(r, g, b) for r, g, b, _ in list(reversed(self.GetMatPlotLibColormap().colors))])\n\n    def SetColorHSVControlPoints(self, cp: list[tuple[float, Vec3]]):\n        \"\"\"\n        Sets opacities for x,y values where MinMapValue<=x<=MaxMapValue and 0<=y<=1\n        Warning: The points are stored as normalized coordinates so if the MapValue range changes\n        it will not be reflected in the mapping range\n        \"\"\"\n        self.SetColorNormalizedHSVControlPoints(self.__normalizeControlPoints(cp))\n\n    def __rgbEquivalent(func):\n        def dec1(name):\n            @functools.wraps(func)\n            def dec(self, cp):\n                if len(cp[0]) == 2:\n                    return func(self, [(v, self.__rgbToHsv(rgb)) for v, rgb in cp])\n                else:\n                    return func(self, [self.__rgbToHsv(rgb) for rgb in cp])\n            return dec\n        return dec1\n\n    @__rgbEquivalent(SetColorHSVList)\n    def SetColorRGBList(self): pass\n\n    @__rgbEquivalent(SetColorNormalizedHSVControlPoints)\n    def SetColorNormalizedRGBControlPoints(self): pass\n\n    @__rgbEquivalent(SetColorHSVControlPoints)\n    def SetColorRGBControlPoints(self):pass\n\n    def GetMatPlotLibColormap(self):\n        from matplotlib.colors import ListedColormap\n        lut = self._params.makeLut()\n        lut = [[*lut[i:i + 3], 1] for i in range(0, len(lut), 4)]\n        return ListedColormap(lut)\n\n    def GetMatPlotLibColorbar(self, axes=\"auto\", figsize=(9,1.5), **kwargs):\n        \"\"\"\n        Shows a colorbar for Vapor's transfer function using pylab.colorbar.\n        This function takes the same kwargs as pylab.colorbar and those\n        parameters are passed onto the matplotlib function.\n        \"\"\"\n        cmap = self.GetMatPlotLibColormap()\n\n        # a = [[0, 1]]\n        a = [self.GetMinMaxMapValue()]\n        pl.figure(figsize=figsize)\n        img = pl.imshow(a, cmap=cmap)\n        pl.gca().set_visible(False)\n\n        kwargs.setdefault(\"orientation\", \"horizontal\")\n\n        if axes==\"auto\":\n            if kwargs['orientation'] == \"horizontal\":\n                cax = pl.axes([0.1, 0.2, 0.8, 0.6])\n            elif kwargs['orientation'] == \"vertical\":\n                cax = pl.axes([0.2, 0.1, 0.6, 0.8])\n            else:\n                raise ValueError\n        else:\n            cax = axes\n\n        kwargs.setdefault(\"cax\", cax)\n\n        cbar = pl.colorbar(**kwargs)\n        # pl.savefig(\"c.png\")\n        return cbar\n\n    def ShowMatPlotLibColorbar(self, axes=\"auto\", figsize=(9, 1.5), **kwargs):\n        \"\"\"\n        Shows a colorbar for Vapor's transfer function using pylab.colorbar.\n        This function takes the same kwargs as pylab.colorbar and those\n        parameters are passed onto the matplotlib function.\n        \"\"\"\n        self.GetMatPlotLibColorbar(axes, figsize, **kwargs)\n        pl.show()"
  },
  {
    "path": "apps/pythonapi/vapor/transform.py",
    "content": "from . import link\nfrom .params import *\n\nlink.include('vapor/Transform.h')\n\nclass Transform(ParamsWrapper, wrap=link.VAPoR.Transform):\n    _wrap = FuncWrapperStrList(\"\"\"\n        GetRotations\n        SetRotations\n        GetTranslations\n        SetTranslations\n        GetScales\n        SetScales\n        GetOrigin\n        SetOrigin\n    \"\"\")\n    _tags = ParamsTagWrapperList(\"\"\"\n        \n    \"\"\")\n"
  },
  {
    "path": "apps/pythonapi/vapor/utils/__init__.py",
    "content": ""
  },
  {
    "path": "apps/pythonapi/vapor/utils/histogram.py",
    "content": "from ..session import *\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport functools\nimport bqplot as bq\nimport ipywidgets as widgets\nfrom ..widget import VaporVisualizerWidget\n\nlink.include('vapor/Histo.h')\n\ndef GetSamples(session: Session, renderer: Renderer, varName: str):\n    c_win = link.std.string()\n    c_dat = link.std.string()\n    c_typ = link.std.string()\n    session.ce.RenderLookup(renderer.id, c_win, c_dat, c_typ)\n    dataset = session.GetDataset(c_dat)\n    return link.Histo(0).GetDataSamples(varName, dataset._wrappedInstance, renderer._params)\n\n\ndef GetMatPlotLibHistogram(session: Session, renderer: Renderer, **kwargs):\n    \"\"\"\n    Shows a histogram for a given renderer.\n    Wraps matplotlib.pyplot.hist(GetSamples(...))\n    \"\"\"\n    varName = renderer._params.GetActualColorMapVariableName()\n    samples = GetSamples(session, renderer, varName)\n\n    kwargs.setdefault(\"range\", renderer.GetPrimaryTransferFunction().GetMinMaxMapValue())\n    kwargs.setdefault(\"bins\", 128)\n\n    # density=True is supposed to create a probability density however it is broken so this is an alternative\n    weights = np.ones_like(samples) / float(len(samples))\n\n    plt.hist(samples, weights=weights, **kwargs)\n    return plt\n\ndef ShowMatPlotLibHistogram(session: Session, renderer: Renderer, **kwargs):\n    GetMatPlotLibHistogram(session, renderer, **kwargs).show()\n\n\ndef transferFunctionWidget(ses, ren, preserveOpacities = True, nControlPoints=5):\n    # Histogram setup\n    data = np.array(GetSamples(ses, ren, ren._params.GetActualColorMapVariableName()))\n    hist_values, edges = np.histogram(data, bins=50)\n    hist_values = (hist_values / max(hist_values)) * 100 # Scale so y-axis is between 0 and 100. This mitigate's bqplot's auto-rounding\n    hist_values = [np.ceil(y) for y in hist_values] # Round up to handle vanishing values\n    bin_centers = (edges[:-1] + edges[1:]) / 2\n\n    x_sc = bq.LinearScale()\n    y_sc = bq.LinearScale(min=0, max=100)\n    bars = bq.Bars(x=bin_centers, y=hist_values, scales={'x': x_sc, 'y': y_sc})\n\n    # Create control points\n    if(preserveOpacities):\n        init_points = ren.GetPrimaryTransferFunction().GetOpacityControlPoints() * 100\n    else:\n        init_points = [[x, 100] for x in np.linspace(min(data), max(data), nControlPoints)]\n    # Or this\n    control_x, control_y = zip(*init_points)\n    ren.GetPrimaryTransferFunction().SetOpacityControlPoints([[x, float(y)/100] for x, y in init_points])\n\n    # Set up visualizer widget\n    viz = VaporVisualizerWidget(ses)\n    viz_box = widgets.Box([viz])\n\n    # Interactive scatter points\n    scatter = bq.Scatter(\n        x=list(control_x),\n        y=list(control_y),\n        scales={'x': x_sc, 'y': y_sc},\n        enable_move=True,\n        colors=['white'],\n        stroke='black',\n        default_size=64,\n    )\n\n    # Lines connecting control points\n    lines = bq.Lines(\n        x=list(control_x),\n        y=list(control_y),\n        scales={'x': x_sc, 'y': y_sc},\n        stroke='white',\n        stroke_width=2\n    )\n\n    # Update figure and tf on drag\n    def on_drag(change):\n        control_points = list(zip(scatter.x, scatter.y))\n        control_points.sort(key=lambda p: p[0]) # Sort by x-values in case control points cross each other\n        clamped_control_points = [(x, min(100, max(0, y))) for x, y in control_points] # Keep y within [0, 100]\n        xs, ys = zip(*clamped_control_points)\n        lines.x = xs\n        lines.y = ys\n        scatter.x = xs\n        scatter.y = ys\n\n        # Update transfer function\n        ren.GetPrimaryTransferFunction().SetOpacityControlPoints([[x, float(y)/100] for x, y in control_points])\n        viz_box.children = [VaporVisualizerWidget(ses)] # Refresh widget for live update\n\n\n    # Slider for histogram range\n    x_min, x_max = np.min(data), np.max(data)\n    range_slider = widgets.FloatRangeSlider(\n        value=[x_min, x_max],\n        min=x_min,\n        max=x_max,\n        step=(x_max - x_min) / 100,\n        description='Range:',\n        continuous_update=True,\n        readout=False\n    )\n\n    def update_histogram_range(change):\n        x_low, x_high = range_slider.value\n\n        # Remake histogram with given range bounds\n        filtered_data = data[(data >= x_low) & (data <= x_high)]\n        hist_y, new_edges = np.histogram(filtered_data, bins=50, range=(x_low, x_high))\n        hist_y = (hist_y / hist_y.max()) * 100\n        new_centers = (new_edges[:-1] + new_edges[1:]) / 2\n\n        bars.x = new_centers\n        bars.y = [np.ceil(y) for y in hist_y]\n\n        # Keep control points in same relative position\n        new_cp = [[x, y] for x, y in zip(np.linspace(min(filtered_data), max(filtered_data), nControlPoints), scatter.y)]\n        xs, ys = zip(*new_cp)\n        scatter.x = xs\n        scatter.y = ys\n        lines.x = xs\n        lines.y = ys\n\n        # Update x-axis\n        x_sc.min = x_low\n        x_sc.max = x_high\n\n        # Update tf with new cp\n        ren.GetPrimaryTransferFunction().SetOpacityControlPoints([[x, float(y)/100] for x, y in new_cp])\n\n\n    # Set up interactivity\n    scatter.observe(on_drag, names=['x', 'y'])\n    range_slider.observe(update_histogram_range, names='value')\n\n\n    # Create UI layout\n    fig = bq.Figure(\n        marks=[bars, lines, scatter], \n        scales={'x': x_sc, 'y': y_sc}, \n        animation_duration=0, \n        title=str(ren._params.GetVariableName())\n        )\n\n    # Layout Style\n    fig.layout = widgets.Layout(\n        width='99%',\n        height='300px',\n    )\n    range_slider.layout = widgets.Layout(\n        width='90%'\n    )\n    tf_controls = widgets.VBox([fig, range_slider], layout=widgets.Layout(\n        width='500px',\n        align_items='center'\n    ))\n    UI = widgets.HBox([viz_box, tf_controls], layout=widgets.Layout(\n        align_items='flex-start'\n    ))\n    return UI"
  },
  {
    "path": "apps/pythonapi/vapor/utils/keyframing.py",
    "content": "from ..session import Session\nfrom ..animation import Animation\n\ndef animate_camera_keyframes(session_paths, steps = None, time_interpolation = 'static', time_frames = None):\n    \"\"\"\n    Given a list of file paths to sessions with different camera angles, returns an\n    animation that performs keyframing with linear interpolation between those camera angles.\n    Args:\n        session_paths (list): List of file paths to sessions with different camera angles.\n        steps (list, optional): List of number of frames to interpolate between each keyframe. \n                                Defaults to None, which will use 30 frames between each keyframe.\n        time_interpolation (str, optional): How to handle time interpolation. \n                                            Options are 'static', 'auto', or 'manual'. Defaults to 'static'.\n        time_frames (list, optional): If time_interpolation is 'manual', this should be a list of timesteps\n                                      corresponding to the frames in the animation. \n                                      len(time_frames) should equal sum(steps).\n    \"\"\"\n    # Check time_interpolation\n    if(time_interpolation not in [\"static\", \"auto\", 'manual']):\n        raise ValueError(\"time_interpolation must be one of 'static', 'auto', or 'manual'\")\n\n    # Default for steps\n    if steps == None:\n        steps = [30] * (len(session_paths) - 1)\n\n    # Check steps\n    if len(session_paths) - len(steps) != 1:\n        raise ValueError(f\"With {len(session_paths)} keyframes given, 'steps' should be \" +\n                        f\"length {len(session_paths) - 1} (currently {len(steps)})\")\n    total_frames = sum(steps)\n\n    # Load primary session\n    primary_session = session.Session()\n    primary_session.Load(session_paths[0])\n\n    # If time is interpolated, compute time frames\n    if time_interpolation == \"auto\":\n        total_timesteps = primary_session.GetTimesteps()\n        # Compute base number of frames per timestep\n        base = total_frames // total_timesteps\n        remainder = total_frames % total_timesteps\n        # Distribute the remainder by giving one extra frame to the first 'remainder' timesteps\n        time_frames = []\n        for timestep in range(total_timesteps):\n            count = base + (1 if timestep < remainder else 0)\n            time_frames.extend([timestep] * count)\n\n        \n    \n    if time_interpolation == \"manual\":\n        if time_frames is None:\n            raise ValueError(\"If time_interpolation is 'manual', time_frames must be provided\")\n        if len(time_frames) != total_frames:\n            raise ValueError(f\"With {len(session_paths)} steps given, 'time_frames' should be \" +\n                            f\"length {total_frames} (currently {len(time_frames)})\")\n    \n\n    \n    # Load key frames as sessions\n    key_frames = []\n    for path in session_paths:\n        ses = session.Session()\n        ses.Load(path)\n        key_frames.append(ses)\n\n    # Visualization will use renderers from first session in list. Other sessions are only for camera angles\n    primary_session = key_frames[0]\n    anim = Animation(primary_session)\n    cam = primary_session.GetCamera()\n    \n    # Interpolate camera information between each key frame\n    n = 0\n    for i in range(len(key_frames) - 1):\n        start = key_frames[i]\n        end = key_frames[i+1]\n        frames = steps[i]\n        # Get starting information\n        cam1 = start.GetCamera()\n        dir1 = cam1.GetDirection()\n        pos1 = cam1.GetPosition()\n        up1 = cam1.GetUp()\n\n        # Get ending information\n        cam2 = end.GetCamera()\n        dir2 = cam2.GetDirection()\n        pos2 = cam2.GetPosition()\n        up2 = cam2.GetUp()\n\n        # Difference between camera positions on each axis\n        dPositionX  = (pos2[0] - pos1[0])\n        dPositionY  = (pos2[1] - pos1[1])\n        dPositionZ  = (pos2[2] - pos1[2])\n\n        # Difference between camera direction vectors on each axis\n        dDirectionX = (dir2[0] - dir1[0])\n        dDirectionY = (dir2[1] - dir1[1])\n        dDirectionZ = (dir2[2] - dir1[2])\n\n        # Difference between camera up vectors on each axis\n        dUpX        = (up2[0] - up1[0])\n        dUpY        = (up2[1] - up1[1])\n        dUpZ        = (up2[2] - up1[2])\n\n        # Linear interpolation between start and end\n        for j in range(frames):\n            position = [\n                pos1[0]+dPositionX*j/frames,\n                pos1[1]+dPositionY*j/frames,\n                pos1[2]+dPositionZ*j/frames\n            ]\n            cam.SetPosition( position )\n\n            direction = [\n                dir1[0]+dDirectionX*j/frames,\n                dir1[1]+dDirectionY*j/frames,\n                dir1[2]+dDirectionZ*j/frames\n            ]\n            cam.SetDirection( direction )\n\n            up = [\n                up1[0]+dUpX*j/frames,\n                up1[1]+dUpY*j/frames,\n                up1[2]+dUpZ*j/frames\n            ]\n            cam.SetUp( up )\n\n            # If time is interpolated, advance the timestep\n            if (time_interpolation == \"auto\") | (time_interpolation == \"manual\"):\n                timestep = time_frames[n+j]\n                primary_session.SetTimestep(int(timestep))\n\n            anim.CaptureFrame()\n            \n            # Print status\n            print(f\"Rendering Animation [{'#'*round((j+n)*40/total_frames)}{' '*round(40-((j+n)*40/total_frames))}] {(j+1+n)*100/total_frames:.0f}%\", end=\"\\r\")\n        n += steps[i]\n    return anim\n\n\n\ndef animate_camera_keyframes_camerafiles(primary_session, camera_paths, steps=None, time_interpolation='static', time_frames=None):\n    \"\"\"\n    Given a session and a list of paths to saved camera files, returns an animation that performs keyframing\n    with linear interpolation on the saved camera angles. Can also handle time interpolation.\n    \n    Args:\n        primary_session (Session): The primary session to render from.\n        camera_paths (list): List of paths to saved camera files.\n        steps (list, optional): Number of frames to interpolate between each keyframe. Defaults to 30 per segment.\n        time_interpolation (str, optional): How to interpolate timestep. Options: 'static', 'auto', 'manual'. Default is 'static'.\n        time_frames (list, optional): Required if time_interpolation is 'manual'. Should be a list of timesteps with length equal to total frames.\n    \"\"\"\n    # Validate time_interpolation mode\n    if time_interpolation not in [\"static\", \"auto\", \"manual\"]:\n        raise ValueError(\"time_interpolation must be one of 'static', 'auto', or 'manual'\")\n    \n    # Default steps\n    if steps is None:\n        steps = [30] * (len(camera_paths) - 1)\n    \n    # Validate steps length\n    if len(camera_paths) - len(steps) != 1:\n        raise ValueError(f\"With {len(camera_paths)} keyframes, 'steps' should have length {len(camera_paths) - 1} (got {len(steps)})\")\n    \n    total_frames = sum(steps)\n\n    # Handle time_interpolation: auto\n    if time_interpolation == \"auto\":\n        total_timesteps = primary_session.GetTimesteps()\n        base = total_frames // total_timesteps\n        remainder = total_frames % total_timesteps\n        time_frames = []\n        for timestep in range(total_timesteps):\n            count = base + (1 if timestep < remainder else 0)\n            time_frames.extend([timestep] * count)\n\n    # Handle time_interpolation: manual\n    if time_interpolation == \"manual\":\n        if time_frames is None:\n            raise ValueError(\"If time_interpolation is 'manual', time_frames must be provided.\")\n        if len(time_frames) != total_frames:\n            raise ValueError(f\"time_frames length ({len(time_frames)}) must match total_frames ({total_frames})\")\n\n    anim = Animation(primary_session)\n    cam = primary_session.GetCamera()\n    \n    n = 0\n    for i in range(len(camera_paths) - 1):\n        start = camera_paths[i]\n        end = camera_paths[i+1]\n        frames = steps[i]\n        \n        # Load start camera\n        cam.LoadFromFile(start)\n        dir1 = cam.GetDirection()\n        pos1 = cam.GetPosition()\n        up1 = cam.GetUp()\n\n        # Load end camera\n        cam.LoadFromFile(end)\n        dir2 = cam.GetDirection()\n        pos2 = cam.GetPosition()\n        up2 = cam.GetUp()\n\n        # Compute deltas\n        dPosition = [p2 - p1 for p1, p2 in zip(pos1, pos2)]\n        dDirection = [d2 - d1 for d1, d2 in zip(dir1, dir2)]\n        dUp = [u2 - u1 for u1, u2 in zip(up1, up2)]\n\n        for j in range(frames):\n            f = j / frames\n            position = [pos1[k] + dPosition[k]*f for k in range(3)]\n            direction = [dir1[k] + dDirection[k]*f for k in range(3)]\n            up = [up1[k] + dUp[k]*f for k in range(3)]\n\n            cam.SetPosition(position)\n            cam.SetDirection(direction)\n            cam.SetUp(up)\n\n            # Set time if applicable\n            if time_interpolation in [\"auto\", \"manual\"]:\n                timestep = time_frames[n + j]\n                primary_session.SetTimestep(int(timestep))\n\n            anim.CaptureFrame()\n            print(f\"Rendering Animation [{'#'*round((j+n)*40/total_frames)}{' '*round(40-((j+n)*40/total_frames))}] {(j+1+n)*100/total_frames:.0f}%\", end=\"\\r\")\n        \n        n += frames\n\n    return anim\n"
  },
  {
    "path": "apps/pythonapi/vapor/widget-jquery.js",
    "content": "/*! jQuery v3.7.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(ie,e){\"use strict\";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType&&\"function\"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement(\"script\");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[i.call(e)]||\"object\":typeof e}var t=\"3.7.1\",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&\"length\"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}function fe(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}ce.fn=ce.prototype={jquery:t,constructor:ce,length:0,toArray:function(){return ae.call(this)},get:function(e){return null==e?ae.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=ce.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return ce.each(this,e)},map:function(n){return this.pushStack(ce.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(ae.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(ce.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(ce.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:s,sort:oe.sort,splice:oe.splice},ce.extend=ce.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||v(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(ce.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||ce.isPlainObject(n)?n:{},i=!1,a[t]=ce.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},ce.extend({expando:\"jQuery\"+(t+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==i.call(e))&&(!(t=r(e))||\"function\"==typeof(n=ue.call(t,\"constructor\")&&t.constructor)&&o.call(n)===a)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){m(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(c(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},text:function(e){var t,n=\"\",r=0,i=e.nodeType;if(!i)while(t=e[r++])n+=ce.text(t);return 1===i||11===i?e.textContent:9===i?e.documentElement.textContent:3===i||4===i?e.nodeValue:n},makeArray:function(e,t){var n=t||[];return null!=e&&(c(Object(e))?ce.merge(n,\"string\"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:se.call(t,e,n)},isXMLDoc:function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!l.test(t||n&&n.nodeName||\"HTML\")},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(c(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:le}),\"function\"==typeof Symbol&&(ce.fn[Symbol.iterator]=oe[Symbol.iterator]),ce.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var pe=oe.pop,de=oe.sort,he=oe.splice,ge=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",ve=new RegExp(\"^\"+ge+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+ge+\"+$\",\"g\");ce.contains=function(e,t){var n=t&&t.parentNode;return e===n||!(!n||1!==n.nodeType||!(e.contains?e.contains(n):e.compareDocumentPosition&&16&e.compareDocumentPosition(n)))};var f=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;function p(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e}ce.escapeSelector=function(e){return(e+\"\").replace(f,p)};var ye=C,me=s;!function(){var e,b,w,o,a,T,r,C,d,i,k=me,S=ce.expando,E=0,n=0,s=W(),c=W(),u=W(),h=W(),l=function(e,t){return e===t&&(a=!0),0},f=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",t=\"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\"+ge+\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\",p=\"\\\\[\"+ge+\"*(\"+t+\")(?:\"+ge+\"*([*^$|!~]?=)\"+ge+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+t+\"))|)\"+ge+\"*\\\\]\",g=\":(\"+t+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+p+\")*)|.*)\\\\)|)\",v=new RegExp(ge+\"+\",\"g\"),y=new RegExp(\"^\"+ge+\"*,\"+ge+\"*\"),m=new RegExp(\"^\"+ge+\"*([>+~]|\"+ge+\")\"+ge+\"*\"),x=new RegExp(ge+\"|>\"),j=new RegExp(g),A=new RegExp(\"^\"+t+\"$\"),D={ID:new RegExp(\"^#(\"+t+\")\"),CLASS:new RegExp(\"^\\\\.(\"+t+\")\"),TAG:new RegExp(\"^(\"+t+\"|[*])\"),ATTR:new RegExp(\"^\"+p),PSEUDO:new RegExp(\"^\"+g),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+ge+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+ge+\"*(?:([+-]|)\"+ge+\"*(\\\\d+)|))\"+ge+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+f+\")$\",\"i\"),needsContext:new RegExp(\"^\"+ge+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+ge+\"*((?:-\\\\d)?\\\\d*)\"+ge+\"*\\\\)|)(?=[^-]|$)\",\"i\")},N=/^(?:input|select|textarea|button)$/i,q=/^h\\d$/i,L=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,H=/[+~]/,O=new RegExp(\"\\\\\\\\[\\\\da-fA-F]{1,6}\"+ge+\"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\",\"g\"),P=function(e,t){var n=\"0x\"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,\"fieldset\")},{dir:\"parentNode\",next:\"legend\"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+\" \"]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute(\"id\"))?s=ce.escapeSelector(s):e.setAttribute(\"id\",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?\"#\"+s:\":scope\")+\" \"+Q(l[o]);c=l.join(\",\")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute(\"id\")}}}return re(t.replace(ve,\"$1\"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,\"input\")&&e.type===t}}function _(t){return function(e){return(fe(e,\"input\")||fe(e,\"button\"))&&e.type===t}}function z(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&R(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function U(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener(\"unload\",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,\"*\")}),le.scope=$(function(){return T.querySelectorAll(\":scope\")}),le.cssHas=$(function(){try{return T.querySelector(\":has(*,:jqfake)\"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML=\"<a id='\"+S+\"' href='' disabled='disabled'></a><select id='\"+S+\"-\\r\\\\' disabled='disabled'><option selected=''></option></select>\",e.querySelectorAll(\"[selected]\").length||d.push(\"\\\\[\"+ge+\"*(?:value|\"+f+\")\"),e.querySelectorAll(\"[id~=\"+S+\"-]\").length||d.push(\"~=\"),e.querySelectorAll(\"a#\"+S+\"+*\").length||d.push(\".#.+[+~]\"),e.querySelectorAll(\":checked\").length||d.push(\":checked\"),(t=T.createElement(\"input\")).setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&d.push(\":enabled\",\":disabled\"),(t=T.createElement(\"input\")).setAttribute(\"name\",\"\"),e.appendChild(t),e.querySelectorAll(\"[name='']\").length||d.push(\"\\\\[\"+ge+\"*name\"+ge+\"*=\"+ge+\"*(?:''|\\\"\\\")\")}),le.cssHas||d.push(\":has\"),d=d.length&&new RegExp(d.join(\"|\")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+\" \"]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0<I(t,T,null,[e]).length},I.contains=function(e,t){return(e.ownerDocument||e)!=T&&V(e),ce.contains(e,t)},I.attr=function(e,t){(e.ownerDocument||e)!=T&&V(e);var n=b.attrHandle[t.toLowerCase()],r=n&&ue.call(b.attrHandle,t.toLowerCase())?n(e,t,!C):void 0;return void 0!==r?r:e.getAttribute(t)},I.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},ce.uniqueSort=function(e){var t,n=[],r=0,i=0;if(a=!le.sortStable,o=!le.sortStable&&ae.call(e,0),de.call(e,l),a){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)he.call(e,n[r],1)}return o=null,e},ce.fn.uniqueSort=function(){return this.pushStack(ce.uniqueSort(ae.apply(this)))},(b=ce.expr={cacheLength:50,createPseudo:F,match:D,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||\"\").replace(O,P),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+\" \"];return t||(t=new RegExp(\"(^|\"+ge+\")\"+e+\"(\"+ge+\"|$)\"))&&s(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(v,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(d,e,t,h,g){var v=\"nth\"!==d.slice(0,3),y=\"last\"!==d.slice(-4),m=\"of-type\"===e;return 1===h&&0===g?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u=v!==y?\"nextSibling\":\"previousSibling\",l=e.parentNode,c=m&&e.nodeName.toLowerCase(),f=!n&&!m,p=!1;if(l){if(v){while(u){o=e;while(o=o[u])if(m?fe(o,c):1===o.nodeType)return!1;s=u=\"only\"===d&&!s&&\"nextSibling\"}return!0}if(s=[y?l.firstChild:l.lastChild],y&&f){p=(a=(r=(i=l[S]||(l[S]={}))[d]||[])[0]===E&&r[1])&&r[2],o=a&&l.childNodes[a];while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if(1===o.nodeType&&++p&&o===e){i[d]=[E,a,p];break}}else if(f&&(p=a=(r=(i=e[S]||(e[S]={}))[d]||[])[0]===E&&r[1]),!1===p)while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if((m?fe(o,c):1===o.nodeType)&&++p&&(f&&((i=o[S]||(o[S]={}))[d]=[E,p]),o===e))break;return(p-=g)===h||p%h==0&&0<=p/h}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||I.error(\"unsupported pseudo: \"+e);return a[S]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?F(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=se.call(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:F(function(e){var r=[],i=[],s=ne(e.replace(ve,\"$1\"));return s[S]?F(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:F(function(t){return function(e){return 0<I(t,e).length}}),contains:F(function(t){return t=t.replace(O,P),function(e){return-1<(e.textContent||ce.text(e)).indexOf(t)}}),lang:F(function(n){return A.test(n||\"\")||I.error(\"unsupported lang: \"+n),n=n.replace(O,P).toLowerCase(),function(e){var t;do{if(t=C?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=ie.location&&ie.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===r},focus:function(e){return e===function(){try{return T.activeElement}catch(e){}}()&&T.hasFocus()&&!!(e.type||e.href||~e.tabIndex)},enabled:z(!1),disabled:z(!0),checked:function(e){return fe(e,\"input\")&&!!e.checked||fe(e,\"option\")&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return q.test(e.nodeName)},input:function(e){return N.test(e.nodeName)},button:function(e){return fe(e,\"input\")&&\"button\"===e.type||fe(e,\"button\")},text:function(e){var t;return fe(e,\"input\")&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:X(function(){return[0]}),last:X(function(e,t){return[t-1]}),eq:X(function(e,t,n){return[n<0?n+t:n]}),even:X(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:X(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:X(function(e,t,n){var r;for(r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:X(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=B(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=_(e);function G(){}function Y(e,t){var n,r,i,o,a,s,u,l=c[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=y.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=m.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(ve,\" \")}),a=a.slice(n.length)),b.filter)!(r=D[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?I.error(e):c(e,s).slice(0)}function Q(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function J(a,e,t){var s=e.dir,u=e.next,l=u||s,c=t&&\"parentNode\"===l,f=n++;return e.first?function(e,t,n){while(e=e[s])if(1===e.nodeType||c)return a(e,t,n);return!1}:function(e,t,n){var r,i,o=[E,f];if(n){while(e=e[s])if((1===e.nodeType||c)&&a(e,t,n))return!0}else while(e=e[s])if(1===e.nodeType||c)if(i=e[S]||(e[S]={}),u&&fe(e,u))e=e[s]||e;else{if((r=i[l])&&r[0]===E&&r[1]===f)return o[2]=r[2];if((i[l]=o)[2]=a(e,t,n))return!0}return!1}}function K(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Z(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function ee(d,h,g,v,y,e){return v&&!v[S]&&(v=ee(v)),y&&!y[S]&&(y=ee(y,e)),F(function(e,t,n,r){var i,o,a,s,u=[],l=[],c=t.length,f=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)I(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),p=!d||!e&&h?f:Z(f,u,d,n,r);if(g?g(p,s=y||(e?d:c||v)?[]:t,n,r):s=p,v){i=Z(s,l),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(s[l[o]]=!(p[l[o]]=a))}if(e){if(y||d){if(y){i=[],o=s.length;while(o--)(a=s[o])&&i.push(p[o]=a);y(null,s=[],i,r)}o=s.length;while(o--)(a=s[o])&&-1<(i=y?se.call(e,a):u[o])&&(e[i]=!(t[i]=a))}}else s=Z(s===t?s.splice(c,s.length):s),y?y(null,t,s,r):k.apply(t,s)})}function te(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=J(function(e){return e===i},a,!0),l=J(function(e){return-1<se.call(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!=w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[J(K(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return ee(1<s&&K(c),1<s&&Q(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace(ve,\"$1\"),t,s<n&&te(e.slice(s,n)),n<r&&te(e=e.slice(n)),n<r&&Q(e))}c.push(t)}return K(c)}function ne(e,t){var n,v,y,m,x,r,i=[],o=[],a=u[e+\" \"];if(!a){t||(t=Y(e)),n=t.length;while(n--)(a=te(t[n]))[S]?i.push(a):o.push(a);(a=u(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG(\"*\",i),h=E+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==T||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==T||(V(o),n=!C);while(s=v[a++])if(s(o,t||T,n)){k.call(r,o);break}i&&(E=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=pe.call(r));f=Z(f)}k.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&ce.uniqueSort(r)}return i&&(E=h,w=p),c},m?F(r):r))).selector=e}return a}function re(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&Y(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&C&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(O,P),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=D.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(O,P),H.test(o[0].type)&&U(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&Q(o)))return k.apply(n,r),n;break}}}return(l||ne(e,c))(r,t,!C,n,!t||H.test(e)&&U(t.parentNode)||t),n}G.prototype=b.filters=b.pseudos,b.setFilters=new G,le.sortStable=S.split(\"\").sort(l).join(\"\")===S,V(),le.sortDetached=$(function(e){return 1&e.compareDocumentPosition(T.createElement(\"fieldset\"))}),ce.find=I,ce.expr[\":\"]=ce.expr.pseudos,ce.unique=ce.uniqueSort,I.compile=ne,I.select=re,I.setDocument=V,I.tokenize=Y,I.escape=ce.escapeSelector,I.getText=ce.text,I.isXML=ce.isXMLDoc,I.selectors=ce.expr,I.support=ce.support,I.uniqueSort=ce.uniqueSort}();var d=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&ce(e).is(n))break;r.push(e)}return r},h=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},b=ce.expr.match.needsContext,w=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?ce.grep(e,function(e){return-1<se.call(n,e)!==r}):ce.filter(n,e,r)}ce.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?ce.find.matchesSelector(r,e)?[r]:[]:ce.find.matches(e,ce.grep(t,function(e){return 1===e.nodeType}))},ce.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(ce(e).filter(function(){for(t=0;t<r;t++)if(ce.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)ce.find(e,i[t],n);return 1<r?ce.uniqueSort(n):n},filter:function(e){return this.pushStack(T(this,e||[],!1))},not:function(e){return this.pushStack(T(this,e||[],!0))},is:function(e){return!!T(this,\"string\"==typeof e&&b.test(e)?ce(e):e||[],!1).length}});var k,S=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(ce.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&ce(e);if(!b.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&ce.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?ce.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?se.call(ce(e),this[0]):se.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(ce.uniqueSort(ce.merge(this.get(),ce(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),ce.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return d(e,\"parentNode\")},parentsUntil:function(e,t,n){return d(e,\"parentNode\",n)},next:function(e){return A(e,\"nextSibling\")},prev:function(e){return A(e,\"previousSibling\")},nextAll:function(e){return d(e,\"nextSibling\")},prevAll:function(e){return d(e,\"previousSibling\")},nextUntil:function(e,t,n){return d(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return d(e,\"previousSibling\",n)},siblings:function(e){return h((e.parentNode||{}).firstChild,e)},children:function(e){return h(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(fe(e,\"template\")&&(e=e.content||e),ce.merge([],e.childNodes))}},function(r,i){ce.fn[r]=function(e,t){var n=ce.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=ce.filter(t,n)),1<this.length&&(j[r]||ce.uniqueSort(n),E.test(r)&&n.reverse()),this.pushStack(n)}});var D=/[^\\x20\\t\\r\\n\\f]+/g;function N(e){return e}function q(e){throw e}function L(e,t,n,r){var i;try{e&&v(i=e.promise)?i.call(e).done(t).fail(n):e&&v(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}ce.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},ce.each(e.match(D)||[],function(e,t){n[t]=!0}),n):ce.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){ce.each(e,function(e,t){v(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==x(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return ce.each(arguments,function(e,t){var n;while(-1<(n=ce.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<ce.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},ce.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",ce.Callbacks(\"memory\"),ce.Callbacks(\"memory\"),2],[\"resolve\",\"done\",ce.Callbacks(\"once memory\"),ce.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",ce.Callbacks(\"once memory\"),ce.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return ce.Deferred(function(r){ce.each(o,function(e,t){var n=v(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&v(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,v(t)?s?t.call(e,l(u,o,N,s),l(u,o,q,s)):(u++,t.call(e,l(u,o,N,s),l(u,o,q,s),l(u,o,N,o.notifyWith))):(a!==N&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){ce.Deferred.exceptionHook&&ce.Deferred.exceptionHook(e,t.error),u<=i+1&&(a!==q&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(ce.Deferred.getErrorHook?t.error=ce.Deferred.getErrorHook():ce.Deferred.getStackHook&&(t.error=ce.Deferred.getStackHook()),ie.setTimeout(t))}}return ce.Deferred(function(e){o[0][3].add(l(0,e,v(r)?r:N,e.notifyWith)),o[1][3].add(l(0,e,v(t)?t:N)),o[2][3].add(l(0,e,v(n)?n:q))}).promise()},promise:function(e){return null!=e?ce.extend(e,a):a}},s={};return ce.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=ae.call(arguments),o=ce.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?ae.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(L(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||v(i[t]&&i[t].then)))return o.then();while(t--)L(i[t],a(t),o.reject);return o.promise()}});var H=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;ce.Deferred.exceptionHook=function(e,t){ie.console&&ie.console.warn&&e&&H.test(e.name)&&ie.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},ce.readyException=function(e){ie.setTimeout(function(){throw e})};var O=ce.Deferred();function P(){C.removeEventListener(\"DOMContentLoaded\",P),ie.removeEventListener(\"load\",P),ce.ready()}ce.fn.ready=function(e){return O.then(e)[\"catch\"](function(e){ce.readyException(e)}),this},ce.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--ce.readyWait:ce.isReady)||(ce.isReady=!0)!==e&&0<--ce.readyWait||O.resolveWith(C,[ce])}}),ce.ready.then=O.then,\"complete\"===C.readyState||\"loading\"!==C.readyState&&!C.documentElement.doScroll?ie.setTimeout(ce.ready):(C.addEventListener(\"DOMContentLoaded\",P),ie.addEventListener(\"load\",P));var M=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===x(n))for(s in i=!0,n)M(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,v(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(ce(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},R=/^-ms-/,I=/-([a-z])/g;function W(e,t){return t.toUpperCase()}function F(e){return e.replace(R,\"ms-\").replace(I,W)}var $=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function B(){this.expando=ce.expando+B.uid++}B.uid=1,B.prototype={cache:function(e){var t=e[this.expando];return t||(t={},$(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[F(t)]=n;else for(r in t)i[F(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][F(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(F):(t=F(t))in r?[t]:t.match(D)||[]).length;while(n--)delete r[t[n]]}(void 0===t||ce.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!ce.isEmptyObject(t)}};var _=new B,z=new B,X=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,U=/[A-Z]/g;function V(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(U,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:X.test(i)?JSON.parse(i):i)}catch(e){}z.set(e,t,n)}else n=void 0;return n}ce.extend({hasData:function(e){return z.hasData(e)||_.hasData(e)},data:function(e,t,n){return z.access(e,t,n)},removeData:function(e,t){z.remove(e,t)},_data:function(e,t,n){return _.access(e,t,n)},_removeData:function(e,t){_.remove(e,t)}}),ce.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=z.get(o),1===o.nodeType&&!_.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=F(r.slice(5)),V(o,r,i[r]));_.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){z.set(this,n)}):M(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=z.get(o,n))?t:void 0!==(t=V(o,n))?t:void 0;this.each(function(){z.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){z.remove(this,e)})}}),ce.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=_.get(e,t),n&&(!r||Array.isArray(n)?r=_.access(e,t,ce.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=ce.queue(e,t),r=n.length,i=n.shift(),o=ce._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){ce.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return _.get(e,n)||_.access(e,n,{empty:ce.Callbacks(\"once memory\").add(function(){_.remove(e,[t+\"queue\",n])})})}}),ce.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?ce.queue(this[0],t):void 0===n?this:this.each(function(){var e=ce.queue(this,t,n);ce._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&ce.dequeue(this,t)})},dequeue:function(e){return this.each(function(){ce.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=ce.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=_.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var G=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,Y=new RegExp(\"^(?:([+-])=|)(\"+G+\")([a-z%]*)$\",\"i\"),Q=[\"Top\",\"Right\",\"Bottom\",\"Left\"],J=C.documentElement,K=function(e){return ce.contains(e.ownerDocument,e)},Z={composed:!0};J.getRootNode&&(K=function(e){return ce.contains(e.ownerDocument,e)||e.getRootNode(Z)===e.ownerDocument});var ee=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&K(e)&&\"none\"===ce.css(e,\"display\")};function te(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return ce.css(e,t,\"\")},u=s(),l=n&&n[3]||(ce.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(ce.cssNumber[t]||\"px\"!==l&&+u)&&Y.exec(ce.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)ce.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,ce.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ne={};function re(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=_.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&ee(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ne[s])||(o=a.body.appendChild(a.createElement(s)),u=ce.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),ne[s]=u)))):\"none\"!==n&&(l[c]=\"none\",_.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}ce.fn.extend({show:function(){return re(this,!0)},hide:function(){return re(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){ee(this)?ce(this).show():ce(this).hide()})}});var xe,be,we=/^(?:checkbox|radio)$/i,Te=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,Ce=/^$|^module$|\\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement(\"div\")),(be=C.createElement(\"input\")).setAttribute(\"type\",\"radio\"),be.setAttribute(\"checked\",\"checked\"),be.setAttribute(\"name\",\"t\"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML=\"<textarea>x</textarea>\",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML=\"<option></option>\",le.option=!!xe.lastChild;var ke={thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function Se(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n<r;n++)_.set(e[n],\"globalEval\",!t||_.get(t[n],\"globalEval\"))}ke.tbody=ke.tfoot=ke.colgroup=ke.caption=ke.thead,ke.th=ke.td,le.option||(ke.optgroup=ke.option=[1,\"<select multiple='multiple'>\",\"</select>\"]);var je=/<|&#?\\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===x(o))ce.merge(p,o.nodeType?[o]:o);else if(je.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(Te.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ke[s]||ke._default,a.innerHTML=u[1]+ce.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;ce.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&-1<ce.inArray(o,r))i&&i.push(o);else if(l=K(o),a=Se(f.appendChild(o),\"script\"),l&&Ee(a),n){c=0;while(o=a[c++])Ce.test(o.type||\"\")&&n.push(o)}return f}var De=/^([^.]*)(?:\\.(.+)|)/;function Ne(){return!0}function qe(){return!1}function Le(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)Le(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=qe;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return ce().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=ce.guid++)),e.each(function(){ce.event.add(this,t,i,r,n)})}function He(e,r,t){t?(_.set(e,r,!1),ce.event.add(e,r,{namespace:!1,handler:function(e){var t,n=_.get(this,r);if(1&e.isTrigger&&this[r]){if(n)(ce.event.special[r]||{}).delegateType&&e.stopPropagation();else if(n=ae.call(arguments),_.set(this,r,n),this[r](),t=_.get(this,r),_.set(this,r,!1),n!==t)return e.stopImmediatePropagation(),e.preventDefault(),t}else n&&(_.set(this,r,ce.event.trigger(n[0],n.slice(1),this)),e.stopPropagation(),e.isImmediatePropagationStopped=Ne)}})):void 0===_.get(e,r)&&ce.event.add(e,r,Ne)}ce.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.get(t);if($(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&ce.find.matchesSelector(J,i),n.guid||(n.guid=ce.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof ce&&ce.event.triggered!==e.type?ce.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(D)||[\"\"]).length;while(l--)d=g=(s=De.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=ce.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=ce.event.special[d]||{},c=ce.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&ce.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),ce.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.hasData(e)&&_.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(D)||[\"\"]).length;while(l--)if(d=g=(s=De.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=ce.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||ce.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)ce.event.remove(e,d+t[l],n,r,!0);ce.isEmptyObject(u)&&_.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=ce.event.fix(e),l=(_.get(this,\"events\")||Object.create(null))[u.type]||[],c=ce.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=ce.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((ce.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<ce(i,this).index(l):ce.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(ce.Event.prototype,t,{enumerable:!0,configurable:!0,get:v(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[ce.expando]?e:new ce.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,\"input\")&&He(t,\"click\",!0),!1},trigger:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,\"input\")&&He(t,\"click\"),!0},_default:function(e){var t=e.target;return we.test(t.type)&&t.click&&fe(t,\"input\")&&_.get(t,\"click\")||fe(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},ce.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},ce.Event=function(e,t){if(!(this instanceof ce.Event))return new ce.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ne:qe,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&ce.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[ce.expando]=!0},ce.Event.prototype={constructor:ce.Event,isDefaultPrevented:qe,isPropagationStopped:qe,isImmediatePropagationStopped:qe,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ne,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ne,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ne,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},ce.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},ce.event.addProp),ce.each({focus:\"focusin\",blur:\"focusout\"},function(r,i){function o(e){if(C.documentMode){var t=_.get(this,\"handle\"),n=ce.event.fix(e);n.type=\"focusin\"===e.type?\"focus\":\"blur\",n.isSimulated=!0,t(e),n.target===n.currentTarget&&t(n)}else ce.event.simulate(i,e.target,ce.event.fix(e))}ce.event.special[r]={setup:function(){var e;if(He(this,r,!0),!C.documentMode)return!1;(e=_.get(this,i))||this.addEventListener(i,o),_.set(this,i,(e||0)+1)},trigger:function(){return He(this,r),!0},teardown:function(){var e;if(!C.documentMode)return!1;(e=_.get(this,i)-1)?_.set(this,i,e):(this.removeEventListener(i,o),_.remove(this,i))},_default:function(e){return _.get(e.target,r)},delegateType:i},ce.event.special[i]={setup:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i);n||(C.documentMode?this.addEventListener(i,o):e.addEventListener(r,o,!0)),_.set(t,i,(n||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i)-1;n?_.set(t,i,n):(C.documentMode?this.removeEventListener(i,o):e.removeEventListener(r,o,!0),_.remove(t,i))}}}),ce.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){ce.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||ce.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),ce.fn.extend({on:function(e,t,n,r){return Le(this,e,t,n,r)},one:function(e,t,n,r){return Le(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,ce(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=qe),this.each(function(){ce.event.remove(this,e,n,t)})}});var Oe=/<script|<style|<link/i,Pe=/checked\\s*(?:[^=]|=\\s*.checked.)/i,Me=/^\\s*<!\\[CDATA\\[|\\]\\]>\\s*$/g;function Re(e,t){return fe(e,\"table\")&&fe(11!==t.nodeType?t:t.firstChild,\"tr\")&&ce(e).children(\"tbody\")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function We(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,\"handle events\"),s)for(n=0,r=s[i].length;n<r;n++)ce.event.add(t,i,s[i][n]);z.hasData(e)&&(o=z.access(e),a=ce.extend({},o),z.set(t,a))}}function $e(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=v(d);if(h||1<f&&\"string\"==typeof d&&!le.checkClone&&Pe.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),$e(t,r,i,o)});if(f&&(t=(e=Ae(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=ce.map(Se(e,\"script\"),Ie)).length;c<f;c++)u=e,c!==p&&(u=ce.clone(u,!0,!0),s&&ce.merge(a,Se(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,ce.map(a,We),c=0;c<s;c++)u=a[c],Ce.test(u.type||\"\")&&!_.access(u,\"globalEval\")&&ce.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?ce._evalUrl&&!u.noModule&&ce._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")},l):m(u.textContent.replace(Me,\"\"),u,l))}return n}function Be(e,t,n){for(var r,i=t?ce.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||ce.cleanData(Se(r)),r.parentNode&&(n&&K(r)&&Ee(Se(r,\"script\")),r.parentNode.removeChild(r));return e}ce.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=K(e);if(!(le.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||ce.isXMLDoc(e)))for(a=Se(c),r=0,i=(o=Se(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&we.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||Se(e),a=a||Se(c),r=0,i=o.length;r<i;r++)Fe(o[r],a[r]);else Fe(e,c);return 0<(a=Se(c,\"script\")).length&&Ee(a,!f&&Se(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=ce.event.special,o=0;void 0!==(n=e[o]);o++)if($(n)){if(t=n[_.expando]){if(t.events)for(r in t.events)i[r]?ce.event.remove(n,r):ce.removeEvent(n,r,t.handle);n[_.expando]=void 0}n[z.expando]&&(n[z.expando]=void 0)}}}),ce.fn.extend({detach:function(e){return Be(this,e,!0)},remove:function(e){return Be(this,e)},text:function(e){return M(this,function(e){return void 0===e?ce.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return $e(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Re(this,e).appendChild(e)})},prepend:function(){return $e(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Re(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return $e(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return $e(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(ce.cleanData(Se(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return ce.clone(this,e,t)})},html:function(e){return M(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!Oe.test(e)&&!ke[(Te.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=ce.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(ce.cleanData(Se(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return $e(this,arguments,function(e){var t=this.parentNode;ce.inArray(this,n)<0&&(ce.cleanData(Se(this)),t&&t.replaceChild(e,this))},n)}}),ce.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){ce.fn[e]=function(e){for(var t,n=[],r=ce(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),ce(r[o])[a](t),s.apply(n,t.get());return this.pushStack(n)}});var _e=new RegExp(\"^(\"+G+\")(?!px)[a-z%]+$\",\"i\"),ze=/^--/,Xe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=ie),t.getComputedStyle(e)},Ue=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ve=new RegExp(Q.join(\"|\"),\"i\");function Ge(e,t,n){var r,i,o,a,s=ze.test(t),u=e.style;return(n=n||Xe(e))&&(a=n.getPropertyValue(t)||n[t],s&&a&&(a=a.replace(ve,\"$1\")||void 0),\"\"!==a||K(e)||(a=ce.style(e,t)),!le.pixelBoxStyles()&&_e.test(a)&&Ve.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=n.width,u.width=r,u.minWidth=i,u.maxWidth=o)),void 0!==a?a+\"\":a}function Ye(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",l.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",J.appendChild(u).appendChild(l);var e=ie.getComputedStyle(l);n=\"1%\"!==e.top,s=12===t(e.marginLeft),l.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),l.style.position=\"absolute\",i=12===t(l.offsetWidth/3),J.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=C.createElement(\"div\"),l=C.createElement(\"div\");l.style&&(l.style.backgroundClip=\"content-box\",l.cloneNode(!0).style.backgroundClip=\"\",le.clearCloneStyle=\"content-box\"===l.style.backgroundClip,ce.extend(le,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=C.createElement(\"table\"),t=C.createElement(\"tr\"),n=C.createElement(\"div\"),e.style.cssText=\"position:absolute;left:-11111px;border-collapse:separate\",t.style.cssText=\"box-sizing:content-box;border:1px solid\",t.style.height=\"1px\",n.style.height=\"9px\",n.style.display=\"block\",J.appendChild(e).appendChild(t).appendChild(n),r=ie.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,J.removeChild(e)),a}}))}();var Qe=[\"Webkit\",\"Moz\",\"ms\"],Je=C.createElement(\"div\").style,Ke={};function Ze(e){var t=ce.cssProps[e]||Ke[e];return t||(e in Je?e:Ke[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Qe.length;while(n--)if((e=Qe[n]+t)in Je)return e}(e)||e)}var et=/^(none|table(?!-c[ea]).+)/,tt={position:\"absolute\",visibility:\"hidden\",display:\"block\"},nt={letterSpacing:\"0\",fontWeight:\"400\"};function rt(e,t,n){var r=Y.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function it(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0,l=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(l+=ce.css(e,n+Q[a],!0,i)),r?(\"content\"===n&&(u-=ce.css(e,\"padding\"+Q[a],!0,i)),\"margin\"!==n&&(u-=ce.css(e,\"border\"+Q[a]+\"Width\",!0,i))):(u+=ce.css(e,\"padding\"+Q[a],!0,i),\"padding\"!==n?u+=ce.css(e,\"border\"+Q[a]+\"Width\",!0,i):s+=ce.css(e,\"border\"+Q[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u+l}function ot(e,t,n){var r=Xe(e),i=(!le.boxSizingReliable()||n)&&\"border-box\"===ce.css(e,\"boxSizing\",!1,r),o=i,a=Ge(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if(_e.test(a)){if(!n)return a;a=\"auto\"}return(!le.boxSizingReliable()&&i||!le.reliableTrDimensions()&&fe(e,\"tr\")||\"auto\"===a||!parseFloat(a)&&\"inline\"===ce.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===ce.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+it(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function at(e,t,n,r,i){return new at.prototype.init(e,t,n,r,i)}ce.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ge(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=F(t),u=ze.test(t),l=e.style;if(u||(t=Ze(s)),a=ce.cssHooks[t]||ce.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=Y.exec(n))&&i[1]&&(n=te(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(ce.cssNumber[s]?\"\":\"px\")),le.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=F(t);return ze.test(t)||(t=Ze(s)),(a=ce.cssHooks[t]||ce.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Ge(e,t,r)),\"normal\"===i&&t in nt&&(i=nt[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),ce.each([\"height\",\"width\"],function(e,u){ce.cssHooks[u]={get:function(e,t,n){if(t)return!et.test(ce.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?ot(e,u,n):Ue(e,tt,function(){return ot(e,u,n)})},set:function(e,t,n){var r,i=Xe(e),o=!le.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===ce.css(e,\"boxSizing\",!1,i),s=n?it(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-it(e,u,\"border\",!1,i)-.5)),s&&(r=Y.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=ce.css(e,u)),rt(0,t,s)}}}),ce.cssHooks.marginLeft=Ye(le.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Ge(e,\"marginLeft\"))||e.getBoundingClientRect().left-Ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),ce.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){ce.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+Q[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(ce.cssHooks[i+o].set=rt)}),ce.fn.extend({css:function(e,t){return M(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Xe(e),i=t.length;a<i;a++)o[t[a]]=ce.css(e,t[a],!1,r);return o}return void 0!==n?ce.style(e,t,n):ce.css(e,t)},e,t,1<arguments.length)}}),((ce.Tween=at).prototype={constructor:at,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||ce.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(ce.cssNumber[n]?\"\":\"px\")},cur:function(){var e=at.propHooks[this.prop];return e&&e.get?e.get(this):at.propHooks._default.get(this)},run:function(e){var t,n=at.propHooks[this.prop];return this.options.duration?this.pos=t=ce.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):at.propHooks._default.set(this),this}}).init.prototype=at.prototype,(at.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=ce.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){ce.fx.step[e.prop]?ce.fx.step[e.prop](e):1!==e.elem.nodeType||!ce.cssHooks[e.prop]&&null==e.elem.style[Ze(e.prop)]?e.elem[e.prop]=e.now:ce.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=at.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},ce.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},ce.fx=at.prototype.init,ce.fx.step={};var st,ut,lt,ct,ft=/^(?:toggle|show|hide)$/,pt=/queueHooks$/;function dt(){ut&&(!1===C.hidden&&ie.requestAnimationFrame?ie.requestAnimationFrame(dt):ie.setTimeout(dt,ce.fx.interval),ce.fx.tick())}function ht(){return ie.setTimeout(function(){st=void 0}),st=Date.now()}function gt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=Q[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function vt(e,t,n){for(var r,i=(yt.tweeners[t]||[]).concat(yt.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function yt(o,e,t){var n,a,r=0,i=yt.prefilters.length,s=ce.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=st||ht(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:ce.extend({},e),opts:ce.extend(!0,{specialEasing:{},easing:ce.easing._default},t),originalProperties:e,originalOptions:t,startTime:st||ht(),duration:t.duration,tweens:[],createTween:function(e,t){var n=ce.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=F(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=ce.cssHooks[r])&&\"expand\"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=yt.prefilters[r].call(l,o,c,l.opts))return v(n.stop)&&(ce._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return ce.map(c,vt,l),v(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),ce.fx.timer(ce.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}ce.Animation=ce.extend(yt,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return te(n.elem,e,Y.exec(t),n),n}]},tweener:function(e,t){v(e)?(t=e,e=[\"*\"]):e=e.match(D);for(var n,r=0,i=e.length;r<i;r++)n=e[r],yt.tweeners[n]=yt.tweeners[n]||[],yt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&ee(e),v=_.get(e,\"fxshow\");for(r in n.queue||(null==(a=ce._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,ce.queue(e,\"fx\").length||a.empty.fire()})})),t)if(i=t[r],ft.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||ce.style(e,r)}if((u=!ce.isEmptyObject(t))||!ce.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=_.get(e,\"display\")),\"none\"===(c=ce.css(e,\"display\"))&&(l?c=l:(re([e],!0),l=e.style.display||l,c=ce.css(e,\"display\"),re([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===ce.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?\"hidden\"in v&&(g=v.hidden):v=_.access(e,\"fxshow\",{display:l}),o&&(v.hidden=!g),g&&re([e],!0),p.done(function(){for(r in g||re([e]),_.remove(e,\"fxshow\"),d)ce.style(e,r,d[r])})),u=vt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?yt.prefilters.unshift(e):yt.prefilters.push(e)}}),ce.speed=function(e,t,n){var r=e&&\"object\"==typeof e?ce.extend({},e):{complete:n||!n&&t||v(e)&&e,duration:e,easing:n&&t||t&&!v(t)&&t};return ce.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in ce.fx.speeds?r.duration=ce.fx.speeds[r.duration]:r.duration=ce.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){v(r.old)&&r.old.call(this),r.queue&&ce.dequeue(this,r.queue)},r},ce.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ee).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=ce.isEmptyObject(t),o=ce.speed(e,n,r),a=function(){var e=yt(this,ce.extend({},t),o);(i||_.get(this,\"finish\"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=ce.timers,r=_.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&pt.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||ce.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=_.get(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=ce.timers,o=n?n.length:0;for(t.finish=!0,ce.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),ce.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=ce.fn[r];ce.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(gt(r,!0),e,t,n)}}),ce.each({slideDown:gt(\"show\"),slideUp:gt(\"hide\"),slideToggle:gt(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){ce.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),ce.timers=[],ce.fx.tick=function(){var e,t=0,n=ce.timers;for(st=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||ce.fx.stop(),st=void 0},ce.fx.timer=function(e){ce.timers.push(e),ce.fx.start()},ce.fx.interval=13,ce.fx.start=function(){ut||(ut=!0,dt())},ce.fx.stop=function(){ut=null},ce.fx.speeds={slow:600,fast:200,_default:400},ce.fn.delay=function(r,e){return r=ce.fx&&ce.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=ie.setTimeout(e,r);t.stop=function(){ie.clearTimeout(n)}})},lt=C.createElement(\"input\"),ct=C.createElement(\"select\").appendChild(C.createElement(\"option\")),lt.type=\"checkbox\",le.checkOn=\"\"!==lt.value,le.optSelected=ct.selected,(lt=C.createElement(\"input\")).value=\"t\",lt.type=\"radio\",le.radioValue=\"t\"===lt.value;var mt,xt=ce.expr.attrHandle;ce.fn.extend({attr:function(e,t){return M(this,ce.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){ce.removeAttr(this,e)})}}),ce.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?ce.prop(e,t,n):(1===o&&ce.isXMLDoc(e)||(i=ce.attrHooks[t.toLowerCase()]||(ce.expr.match.bool.test(t)?mt:void 0)),void 0!==n?null===n?void ce.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=ce.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!le.radioValue&&\"radio\"===t&&fe(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(D);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),mt={set:function(e,t,n){return!1===t?ce.removeAttr(e,n):e.setAttribute(n,n),n}},ce.each(ce.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=xt[t]||ce.find.attr;xt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=xt[o],xt[o]=r,r=null!=a(e,t,n)?o:null,xt[o]=i),r}});var bt=/^(?:input|select|textarea|button)$/i,wt=/^(?:a|area)$/i;function Tt(e){return(e.match(D)||[]).join(\" \")}function Ct(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function kt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(D)||[]}ce.fn.extend({prop:function(e,t){return M(this,ce.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[ce.propFix[e]||e]})}}),ce.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&ce.isXMLDoc(e)||(t=ce.propFix[t]||t,i=ce.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=ce.find.attr(e,\"tabindex\");return t?parseInt(t,10):bt.test(e.nodeName)||wt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),le.optSelected||(ce.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),ce.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){ce.propFix[this.toLowerCase()]=this}),ce.fn.extend({addClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).addClass(t.call(this,e,Ct(this)))}):(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&\" \"+Tt(r)+\" \"){for(o=0;o<e.length;o++)i=e[o],n.indexOf(\" \"+i+\" \")<0&&(n+=i+\" \");a=Tt(n),r!==a&&this.setAttribute(\"class\",a)}}):this},removeClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).removeClass(t.call(this,e,Ct(this)))}):arguments.length?(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&\" \"+Tt(r)+\" \"){for(o=0;o<e.length;o++){i=e[o];while(-1<n.indexOf(\" \"+i+\" \"))n=n.replace(\" \"+i+\" \",\" \")}a=Tt(n),r!==a&&this.setAttribute(\"class\",a)}}):this:this.attr(\"class\",\"\")},toggleClass:function(t,n){var e,r,i,o,a=typeof t,s=\"string\"===a||Array.isArray(t);return v(t)?this.each(function(e){ce(this).toggleClass(t.call(this,e,Ct(this),n),n)}):\"boolean\"==typeof n&&s?n?this.addClass(t):this.removeClass(t):(e=kt(t),this.each(function(){if(s)for(o=ce(this),i=0;i<e.length;i++)r=e[i],o.hasClass(r)?o.removeClass(r):o.addClass(r);else void 0!==t&&\"boolean\"!==a||((r=Ct(this))&&_.set(this,\"__className__\",r),this.setAttribute&&this.setAttribute(\"class\",r||!1===t?\"\":_.get(this,\"__className__\")||\"\"))}))},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+Tt(Ct(n))+\" \").indexOf(t))return!0;return!1}});var St=/\\r/g;ce.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=v(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,ce(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=ce.map(t,function(e){return null==e?\"\":e+\"\"})),(r=ce.valHooks[this.type]||ce.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=ce.valHooks[t.type]||ce.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(St,\"\"):null==e?\"\":e:void 0}}),ce.extend({valHooks:{option:{get:function(e){var t=ce.find.attr(e,\"value\");return null!=t?t:Tt(ce.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!fe(n.parentNode,\"optgroup\"))){if(t=ce(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=ce.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<ce.inArray(ce.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),ce.each([\"radio\",\"checkbox\"],function(){ce.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<ce.inArray(ce(e).val(),t)}},le.checkOn||(ce.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})});var Et=ie.location,jt={guid:Date.now()},At=/\\?/;ce.parseXML=function(e){var t,n;if(!e||\"string\"!=typeof e)return null;try{t=(new ie.DOMParser).parseFromString(e,\"text/xml\")}catch(e){}return n=t&&t.getElementsByTagName(\"parsererror\")[0],t&&!n||ce.error(\"Invalid XML: \"+(n?ce.map(n.childNodes,function(e){return e.textContent}).join(\"\\n\"):e)),t};var Dt=/^(?:focusinfocus|focusoutblur)$/,Nt=function(e){e.stopPropagation()};ce.extend(ce.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||C],d=ue.call(e,\"type\")?e.type:e,h=ue.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||C,3!==n.nodeType&&8!==n.nodeType&&!Dt.test(d+ce.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(h=d.split(\".\")).shift(),h.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[ce.expando]?e:new ce.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:ce.makeArray(t,[e]),c=ce.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!y(n)){for(s=c.delegateType||d,Dt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||C)&&p.push(a.defaultView||a.parentWindow||ie)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(_.get(o,\"events\")||Object.create(null))[e.type]&&_.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&$(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!$(n)||u&&v(n[d])&&!y(n)&&((a=n[u])&&(n[u]=null),ce.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Nt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Nt),ce.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=ce.extend(new ce.Event,n,{type:e,isSimulated:!0});ce.event.trigger(r,null,t)}}),ce.fn.extend({trigger:function(e,t){return this.each(function(){ce.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return ce.event.trigger(e,t,n,!0)}});var qt=/\\[\\]$/,Lt=/\\r?\\n/g,Ht=/^(?:submit|button|image|reset|file)$/i,Ot=/^(?:input|select|textarea|keygen)/i;function Pt(n,e,r,i){var t;if(Array.isArray(e))ce.each(e,function(e,t){r||qt.test(n)?i(n,t):Pt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==x(e))i(n,e);else for(t in e)Pt(n+\"[\"+t+\"]\",e[t],r,i)}ce.param=function(e,t){var n,r=[],i=function(e,t){var n=v(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!ce.isPlainObject(e))ce.each(e,function(){i(this.name,this.value)});else for(n in e)Pt(n,e[n],t,i);return r.join(\"&\")},ce.fn.extend({serialize:function(){return ce.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=ce.prop(this,\"elements\");return e?ce.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!ce(this).is(\":disabled\")&&Ot.test(this.nodeName)&&!Ht.test(e)&&(this.checked||!we.test(e))}).map(function(e,t){var n=ce(this).val();return null==n?null:Array.isArray(n)?ce.map(n,function(e){return{name:t.name,value:e.replace(Lt,\"\\r\\n\")}}):{name:t.name,value:n.replace(Lt,\"\\r\\n\")}}).get()}});var Mt=/%20/g,Rt=/#.*$/,It=/([?&])_=[^&]*/,Wt=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Ft=/^(?:GET|HEAD)$/,$t=/^\\/\\//,Bt={},_t={},zt=\"*/\".concat(\"*\"),Xt=C.createElement(\"a\");function Ut(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(D)||[];if(v(t))while(n=i[r++])\"+\"===n[0]?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Vt(t,i,o,a){var s={},u=t===_t;function l(e){var r;return s[e]=!0,ce.each(t[e]||[],function(e,t){var n=t(i,o,a);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s[\"*\"]&&l(\"*\")}function Gt(e,t){var n,r,i=ce.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&ce.extend(!0,e,r),e}Xt.href=Et.href,ce.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":zt,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":ce.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Gt(Gt(e,ce.ajaxSettings),t):Gt(ce.ajaxSettings,e)},ajaxPrefilter:Ut(Bt),ajaxTransport:Ut(_t),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=ce.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?ce(y):ce.event,x=ce.Deferred(),b=ce.Callbacks(\"once memory\"),w=v.statusCode||{},a={},s={},u=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Wt.exec(p))n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2])}t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+\"\").replace($t,Et.protocol+\"//\"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||\"*\").toLowerCase().match(D)||[\"\"],null==v.crossDomain){r=C.createElement(\"a\");try{r.href=v.url,r.href=r.href,v.crossDomain=Xt.protocol+\"//\"+Xt.host!=r.protocol+\"//\"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&\"string\"!=typeof v.data&&(v.data=ce.param(v.data,v.traditional)),Vt(Bt,v,t,T),h)return T;for(i in(g=ce.event&&v.global)&&0==ce.active++&&ce.event.trigger(\"ajaxStart\"),v.type=v.type.toUpperCase(),v.hasContent=!Ft.test(v.type),f=v.url.replace(Rt,\"\"),v.hasContent?v.data&&v.processData&&0===(v.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(v.data=v.data.replace(Mt,\"+\")):(o=v.url.slice(f.length),v.data&&(v.processData||\"string\"==typeof v.data)&&(f+=(At.test(f)?\"&\":\"?\")+v.data,delete v.data),!1===v.cache&&(f=f.replace(It,\"$1\"),o=(At.test(f)?\"&\":\"?\")+\"_=\"+jt.guid+++o),v.url=f+o),v.ifModified&&(ce.lastModified[f]&&T.setRequestHeader(\"If-Modified-Since\",ce.lastModified[f]),ce.etag[f]&&T.setRequestHeader(\"If-None-Match\",ce.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader(\"Content-Type\",v.contentType),T.setRequestHeader(\"Accept\",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+(\"*\"!==v.dataTypes[0]?\", \"+zt+\"; q=0.01\":\"\"):v.accepts[\"*\"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u=\"abort\",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Vt(_t,v,t,T)){if(T.readyState=1,g&&m.trigger(\"ajaxSend\",[T,v]),h)return T;v.async&&0<v.timeout&&(d=ie.setTimeout(function(){T.abort(\"timeout\")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,\"No Transport\");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&ie.clearTimeout(d),c=void 0,p=r||\"\",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<ce.inArray(\"script\",v.dataTypes)&&ce.inArray(\"json\",v.dataTypes)<0&&(v.converters[\"text script\"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader(\"Last-Modified\"))&&(ce.lastModified[f]=u),(u=T.getResponseHeader(\"etag\"))&&(ce.etag[f]=u)),204===e||\"HEAD\"===v.type?l=\"nocontent\":304===e?l=\"notmodified\":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l=\"error\",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+\"\",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?\"ajaxSuccess\":\"ajaxError\",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger(\"ajaxComplete\",[T,v]),--ce.active||ce.event.trigger(\"ajaxStop\")))}return T},getJSON:function(e,t,n){return ce.get(e,t,n,\"json\")},getScript:function(e,t){return ce.get(e,void 0,t,\"script\")}}),ce.each([\"get\",\"post\"],function(e,i){ce[i]=function(e,t,n,r){return v(t)&&(r=r||n,n=t,t=void 0),ce.ajax(ce.extend({url:e,type:i,dataType:r,data:t,success:n},ce.isPlainObject(e)&&e))}}),ce.ajaxPrefilter(function(e){var t;for(t in e.headers)\"content-type\"===t.toLowerCase()&&(e.contentType=e.headers[t]||\"\")}),ce._evalUrl=function(e,t,n){return ce.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){ce.globalEval(e,t,n)}})},ce.fn.extend({wrapAll:function(e){var t;return this[0]&&(v(e)&&(e=e.call(this[0])),t=ce(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return v(n)?this.each(function(e){ce(this).wrapInner(n.call(this,e))}):this.each(function(){var e=ce(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=v(t);return this.each(function(e){ce(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){ce(this).replaceWith(this.childNodes)}),this}}),ce.expr.pseudos.hidden=function(e){return!ce.expr.pseudos.visible(e)},ce.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},ce.ajaxSettings.xhr=function(){try{return new ie.XMLHttpRequest}catch(e){}};var Yt={0:200,1223:204},Qt=ce.ajaxSettings.xhr();le.cors=!!Qt&&\"withCredentials\"in Qt,le.ajax=Qt=!!Qt,ce.ajaxTransport(function(i){var o,a;if(le.cors||Qt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(Yt[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o(\"error\"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&ie.setTimeout(function(){o&&a()})},o=o(\"abort\");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),ce.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),ce.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return ce.globalEval(e),e}}}),ce.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),ce.ajaxTransport(\"script\",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=ce(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\\?(?=&|$)|\\?\\?/;ce.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Kt.pop()||ce.expando+\"_\"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Zt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||ce.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),\"script\"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=Tt(e.slice(s)),e=e.slice(0,s)),v(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&ce.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?ce(\"<div>\").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,\"position\"),c=ce(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=ce.css(e,\"top\"),u=ce.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===ce.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===ce.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,\"borderTopWidth\",!0),i.left+=ce.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-ce.css(r,\"marginTop\",!0),left:t.left-i.left-ce.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===ce.css(e,\"position\"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each([\"top\",\"left\"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+\"px\":t})}),ce.each({Height:\"height\",Width:\"width\"},function(a,s){ce.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return M(this,function(e,t,n){var r;return y(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)},hover:function(e,t){return this.on(\"mouseenter\",e).on(\"mouseleave\",t||e)}}),ce.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){ce.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var en=/^[\\s\\uFEFF\\xA0]+|([^\\s\\uFEFF\\xA0])[\\s\\uFEFF\\xA0]+$/g;ce.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),v(e))return r=ae.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(ae.call(arguments)))}).guid=e.guid=e.guid||ce.guid++,i},ce.holdReady=function(e){e?ce.readyWait++:ce.ready(!0)},ce.isArray=Array.isArray,ce.parseJSON=JSON.parse,ce.nodeName=fe,ce.isFunction=v,ce.isWindow=y,ce.camelCase=F,ce.type=x,ce.now=Date.now,ce.isNumeric=function(e){var t=ce.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},ce.trim=function(e){return null==e?\"\":(e+\"\").replace(en,\"$1\")},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return ce});var tn=ie.jQuery,nn=ie.$;return ce.noConflict=function(e){return ie.$===ce&&(ie.$=nn),e&&ie.jQuery===ce&&(ie.jQuery=tn),ce},\"undefined\"==typeof e&&(ie.jQuery=ie.$=ce),ce});\n"
  },
  {
    "path": "apps/pythonapi/vapor/widget.css",
    "content": ".counter-button {\n  background-image: linear-gradient(to right, #a1c4fd, #c2e9fb);\n  border: 0;\n  border-radius: 10px;\n  padding: 10px 50px;\n  color: white;\n}\n\n.vapor-jupyter-widget {\n    position: relative;\n}\n.vapor-jupyter-widget > img {\n    position: absolute;\n    top: 0;\n    left: 0;\n}"
  },
  {
    "path": "apps/pythonapi/vapor/widget.js",
    "content": "import $ from './widget-jquery';\n\nfunction render({ model, el }) {\n    let $root = $(\"<div>\");\n    $root.addClass(\"vapor-jupyter-widget\");\n\n    let $img = $('<img>', {src:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVQImWNISUkBAAJcAS0OBgnuAAAAAElFTkSuQmCC'});\n    for (var i = 0; i < 2; i++) $root.append($img.clone().attr(\"id\", \"\"+i));\n    let $imgs = $root.find('img');\n    var img_i = 0;\n\n    $imgs.on(\"load\", e=>{\n        let $e = $(e.target);\n        $e.parent().append($e);\n    });\n    $imgs.on(\"dragstart\", e=>e.preventDefault());\n\n    function loadImage() {\n        let width = model.get('resolution')[0];\n        let height = model.get('resolution')[1];\n        $root.width(width);\n        $root.height(height);\n        // console.log(`Image data received: ${width}x${height}`);\n        if (model.get('imageFormat') !== \"\") {\n            $($imgs[img_i]).attr(\"src\", \"data:image/\" + model.get('imageFormat') + \";base64,\" + model.get('imageData'));\n            img_i = (img_i+1)%2;\n        }\n    }\n\n    model.on(\"change:imageData\", loadImage);\n    if (model.get('imageData'))\n        loadImage();\n\n    $root.on(\"mousedown\", e => {\n        e.preventDefault();\n        var key = e.which;\n        if (e.originalEvent.shiftKey && key == 1)\n            key = 2;\n\n        model.set('mouseButton', key);\n        model.set('mouseDown', true);\n        model.save_changes();\n    });\n\n    $root.on(\"mouseup\", e => {\n        e.preventDefault();\n        model.set('mouseDown', false);\n        model.save_changes();\n    });\n\n    $root.on(\"mousemove\", e => {\n        e.preventDefault();\n        // this.$img.css('border', '2px solid orange');\n        var offset = $root.offset();\n        var nx = e.pageX - offset.left;\n        var ny = e.pageY - offset.top;\n        // console.log(`offset=(${offset.left}, ${offset.top})  e.page=(${e.pageX}, ${e.pageY})  n=(${nx}, ${ny})`)\n        if ($root.width() !== 0 && $root.height() !== 0) {\n            nx /= $root.width();\n            ny /= $root.height();\n        } else {\n            nx = 0;\n            ny = 0;\n        }\n        // console.log(\"mouse move \" + nx + \", \" + ny);\n        model.set('mousePos', [nx, ny]);\n        model.save_changes();\n    });\n\n    el.appendChild($root.get(0));\n}\nexport default { render };"
  },
  {
    "path": "apps/pythonapi/vapor/widget.py",
    "content": "import anywidget\nfrom traitlets import Unicode, Bytes, Tuple, Bool, observe, Int\nimport traitlets\n\n##########################################\n#          Development utility\nimport importlib\nvapor_spec = importlib.util.find_spec(\"vapor\")\nfound = vapor_spec is not None\n\nif not found:\n    import sys\n    import os\n    from pathlib import Path\n    sys.path.append(os.path.expanduser('~/Work/build-work/python'))\n#########################################\n\nfrom PIL import Image\nfrom PIL import ImageDraw\nfrom base64 import b64encode\nfrom io import BytesIO\nimport pathlib\nimport os, sys, random\n\n# class VaporVisualizerWidget(anywidget.AnyWidget):\n#     _esm = pathlib.Path(\"widget.js\")\n\n\nclass CanvasStreamWidget(anywidget.AnyWidget):\n    _esm = pathlib.Path(__file__).parent / \"widget.js\"\n    _css = pathlib.Path(__file__).parent / \"widget.css\"\n\n    imageData = Unicode('').tag(sync=True)\n    resolution = Tuple((640, 480)).tag(sync=True)\n    mousePos = Tuple((0.0, 0.0)).tag(sync=True)\n    mouseDown = Bool(False).tag(sync=True)\n    mouseButton = Int(1).tag(sync=True)\n    _debugLog = Unicode('').tag(sync=True)\n\n    value = Int(0).tag(sync=True)\n\n\n\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        if \"debug\" in kwargs and kwargs[\"debug\"]:\n            self.on_trait_change(self.valueChanged, \"value\")\n            self.on_trait_change(self._DebugShowMousePos, \"mousePos\")\n\n\n    def test(self):\n        self.SetImage(Image.new('RGB', self.resolution, (0,0,100)))\n        # self.value = 999\n\n    def valueChanged(self):\n        print(\"VALUE CHANGED TO\", self.value)\n        self.SetImage(Image.new('RGB', self.resolution, (random.randint(0,255),random.randint(0,255),random.randint(0,255))))\n\n\n    def SetImage(self, img: Image):\n        buf = BytesIO()\n        img.save(buf, format=\"jpeg\")\n        self.resolution = img.size\n        self.imageData = b64encode(buf.getvalue())\n\n    def _DebugShowMousePos(self):\n        print(\"DEBUG SHOW MOUSE POS\")\n        print(\"DEBUG SHOW MOUSE POS\", file=sys.stderr)\n        image = Image.new('RGB', self.resolution)\n        draw = ImageDraw.Draw(image)\n\n        iw = int(image.size[0])\n        ih = int(image.size[1])\n        mx = int(self.mousePos[0] * iw)\n        my = int(self.mousePos[1] * ih)\n        # self.value = mx\n        self._debugLog = f\"\"\"\n                    mousePos: {mx}, {my} <br>\n                    imagesize = {iw, ih} <br>\n                    self.res = {self.resolution}\n                    \"\"\"\n        white = (255, 255, 255)\n        red = (255, 0, 0)\n        draw.rectangle([0, 0, iw, ih], outline=red, width=5)\n        draw.line([mx, 0, mx, ih], fill=white, width=5)\n        draw.line([0, my, iw, my], fill=white, width=5)\n\n        self.SetImage(image)\n\n\n\n# widget setup.py installer will try to run tests which will fail \n# because CPPYY cannot be present at build time due to conda bugs\n\nimport importlib\nif importlib.util.find_spec(\"cppyy\") is not None:\n\n    from vapor import session, renderer, dataset, camera, utils\n    # from examples import example_utils\n    \n    from vapor import link\n    link.include('vapor/TrackBall.h')\n    \n    link.include('vapor/ControlExecutive.h')\n    link.include(\"vapor/NavigationUtils.h\")\n    \n    NavigationUtils = link.NavigationUtils\n    \n    class VaporVisualizerWidget(CanvasStreamWidget):\n        \"\"\"\n        Creates an interactive visualizer widget for a Vapor session.\n        Controls are the same as the Vapor GUI application (They are shown as a tooltip on the visualizer for reference).\n        \"\"\"\n        class TrackballButton:\n            Left = 1\n            Right = 3\n            Middle = 2\n    \n        def __init__(self, ses:session.Session, *args, **kwargs):\n            # import sys\n            # sys.stdout = open(\"stdout.txt\", \"w\")\n            # sys.stderr = open(\"stderr.txt\", \"w\")\n    \n            super().__init__(*args, **kwargs)\n\n            self._ses = ses\n            self._trackball = link.Trackball()\n\n            self.on_trait_change(self.mouseDownChanged, \"mouseDown\")\n            self.on_trait_change(self.mousePosChanged, \"mousePos\")\n\n            self.Render()\n\n\n        def Render(self, fast=False):\n            \"\"\"\n            Update the visualizer with a current rendering of the session.\n            :fast: renders with lower fidelity but faster. Useful for interactive rendering such as to observe a changing value with a slider.\n            \"\"\"\n            self.SetImage(self._ses.RenderToImage(fast=fast))\n\n    \n        def mouseDownChanged(self):\n            w, h = map(int, self.resolution)\n            x, y = map(int, (lambda x,y:(x*w,y*h))(*self.mousePos))\n    \n            if self.mouseDown:\n                NavigationUtils.ConfigureTrackball(self._ses.ce, self._trackball)\n                self._trackball.MouseOnTrackball(0, self.mouseButton, x, y, w, h)\n            else:\n                self._trackball.MouseOnTrackball(2, self.mouseButton, x, y, w, h)\n                self._trackball.TrackballSetMatrix()\n                NavigationUtils.SetAllCameras(self._ses.ce, self._trackball)\n                self.Render(fast=False)\n    \n            # self.value = f\"mouseDown change {change['old']} -> {change['new']}\"\n    \n    \n        def mousePosChanged(self):\n            # self.value = f\"mousePos change {change['old']} -> {change['new']}\"\n            w, h = map(int, self.resolution)\n            x, y = map(int, (lambda x,y:(x*w,y*h))(*self.mousePos))\n    \n            if self.mouseDown:\n                self._trackball.MouseOnTrackball(1, self.mouseButton, x, y, w, h)\n                self._trackball.TrackballSetMatrix()\n                NavigationUtils.SetAllCameras(self._ses.ce, self._trackball)\n    \n                self.Render(fast=True)\n"
  },
  {
    "path": "apps/raw2vdc/CMakeLists.txt",
    "content": "add_executable (raw2vdc raw2vdc.cpp)\n\ntarget_link_libraries (raw2vdc common vdc)\n\nOpenMPInstall (\n\tTARGETS raw2vdc\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/raw2vdc/raw2vdc.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cerrno>\n#include <stdio.h>\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n//\tCommand line argument stuff\n//\nstruct opt_t {\n    string                  varname;\n    string                  type;\n    int                     lod;\n    int                     nthreads;\n    int                     ts;\n    OptionParser::Boolean_T swapbytes;\n    OptionParser::Boolean_T debug;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"varname\", 1, \"var1\", \"Name of variable\"},\n                                         {\"type\", 1, \"float32\", \"Primitive type of input data.  Valid types are int8, float32, float64, and double\"},\n                                         {\"lod\", 1, \"-1\",\n                                          \"Compression levels saved. 0 => coarsest, 1 => \"\n                                          \"next refinement, etc. -1 => all levels defined by the netcdf file\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"ts\", 1, \"0\", \"Specify time step offset\"},\n                                         {\"swapbytes\", 0, \"\", \"Swap bytes in data as they are read from disk\"},\n                                         {\"debug\", 0, \"\", \"Enable diagnostic\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"varname\", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)},\n                                        {\"type\", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)},\n                                        {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"ts\", Wasp::CvtToInt, &opt.ts, sizeof(opt.ts)},\n                                        {\"swapbytes\", Wasp::CvtToBoolean, &opt.swapbytes, sizeof(opt.swapbytes)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nsize_t size_of_type(string type)\n{\n    if (type.compare(\"float32\") == 0) return (4);\n    if (type.compare(\"float64\") == 0) return (8);\n    if (type.compare(\"double\") == 0) return (8);\n    if (type.compare(\"int8\") == 0) return (1);\n    return (1);\n}\n\nvoid swapbytes(void *vptr, size_t size, size_t n)\n{\n    unsigned char *ucptr = (unsigned char *)vptr;\n    unsigned char  uc;\n    size_t         i, j;\n\n    for (j = 0; j < n; j++) {\n        for (i = 0; i < size / 2; i++) {\n            uc = ucptr[i];\n            ucptr[i] = ucptr[size - i - 1];\n            ucptr[size - i - 1] = uc;\n        }\n        ucptr += size;\n    }\n}\n\nint read_data(FILE * fp,\n              string type,    // element type\n              bool swap, size_t n, float *slice)\n{\n    static SmartBuf smart_buf;\n\n    size_t         element_sz = size_of_type(type);\n    unsigned char *buffer = (unsigned char *)smart_buf.Alloc(n * element_sz);\n\n    size_t rc = fread(buffer, element_sz, n, fp);\n    if (rc != n) {\n        if (ferror(fp) != 0) {\n            MyBase::SetErrMsg(\"Error reading input file : %M\");\n        } else {\n            MyBase::SetErrMsg(\"Short read on input file\");\n        }\n        return (-1);\n    }\n\n    // Swap bytes in place if needed\n    //\n    if (swap) { swapbytes(buffer, element_sz, n); }\n\n    float *dptr = slice;\n    if (type.compare(\"float32\") == 0) {\n        float *sptr = (float *)buffer;\n        for (size_t i = 0; i < n; i++) { *dptr++ = (float)*sptr++; }\n    } else if ((type.compare(\"float64\") == 0) || (type.compare(\"double\") == 0)) {\n        double *sptr = (double *)buffer;\n        for (size_t i = 0; i < n; i++) { *dptr++ = (float)*sptr++; }\n    } else if (type.compare(\"int8\") == 0) {\n        char *sptr = (char *)buffer;\n        for (size_t i = 0; i < n; i++) { *dptr++ = (float)*sptr++; }\n    }\n\n    return (0);\n}\n\nconst char *ProgName;\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { return (1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] vdcFile rawDataFile\" << endl;\n        op.PrintOptionHelp(stderr);\n        return (0);\n    }\n\n    if (argc != 3) {\n        cerr << \"Usage: \" << ProgName << \" [options] vdcFile rawDataFile\" << endl;\n        op.PrintOptionHelp(stderr);\n        return (1);\n    }\n\n    string master = argv[1];      // Path to VDC master file\n    string datafile = argv[2];    // Path to raw data file\n\n    if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr);\n\n    VDCNetCDF vdc(opt.nthreads);\n\n    vector<size_t> bs;\n    int            rc = vdc.Initialize(master, vector<string>(), VDC::A, bs, 4 * 1024 * 1024);\n\n    vector<size_t> hslice_dims;\n    size_t         nslice;\n    rc = vdc.GetHyperSliceInfo(opt.varname, -1, hslice_dims, nslice);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Invalid variable name : %s\", opt.varname.c_str());\n        return (1);\n    }\n\n    size_t nelements = 1;\n    for (int i = 0; i < hslice_dims.size(); i++) { nelements *= hslice_dims[i]; }\n\n    vector<size_t> dimlens;\n    bool           ok = vdc.GetVarDimLens(opt.varname, true, dimlens);\n    VAssert(ok == true);\n\n    size_t ntotal = 1;\n    for (int i = 0; i < dimlens.size(); i++) { ntotal *= dimlens[i]; }\n\n    float *slice = new float[nelements];\n\n    FILE *fp = fopen(datafile.c_str(), \"rb\");\n    if (!fp) {\n        MyBase::SetErrMsg(\"fopen(%s) : %M\", datafile.c_str());\n        return (1);\n    }\n\n    int fdr = vdc.OpenVariableWrite(opt.ts, opt.varname, opt.lod);\n    if (fdr < 0) return (1);\n\n    for (size_t i = 0; i < nslice; i++) {\n        nelements = nelements < ntotal ? nelements : ntotal;\n        int rc = read_data(fp, opt.type, opt.swapbytes, nelements, slice);\n        if (rc < 0) return (1);\n\n        ntotal -= nelements;\n\n        rc = vdc.WriteSlice(fdr, slice);\n        if (rc < 0) return (1);\n    }\n\n    rc = vdc.CloseVariableWrite(fdr);\n    if (rc < 0) return (1);\n\n    fclose(fp);\n\n    return (0);\n}\n"
  },
  {
    "path": "apps/raw2wasp/CMakeLists.txt",
    "content": "add_executable (raw2wasp raw2wasp.cpp)\n\ntarget_link_libraries (raw2wasp common wasp)\n\nOpenMPInstall (\n\tTARGETS raw2wasp\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/raw2wasp/raw2wasp.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cerrno>\n#include <stdio.h>\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/WASP.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n//\tCommand line argument stuff\n//\nstruct opt_t {\n    string                  varname;\n    string                  type;\n    int                     lod;\n    int                     nthreads;\n    OptionParser::Boolean_T debug;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"varname\", 1, \"var1\", \"Name of variable\"},\n                                         {\"type\", 1, \"float32\", \"Primitive type of input data\"},\n                                         {\"lod\", 1, \"-1\",\n                                          \"Compression levels saved. 0 => coarsest, 1 => \"\n                                          \"next refinement, etc. -1 => all levels defined by the netcdf file\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"debug\", 0, \"\", \"Enable diagnostic\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"varname\", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)},\n                                        {\"type\", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)},\n                                        {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nconst char *ProgName;\n\ntemplate<class T> void CopyVar(string datafile, string ncdffile, T dummy)\n{\n    WASP wasp(opt.nthreads);\n\n    int rc = wasp.Open(ncdffile, NC_WRITE);\n\n    vector<string> dimnames;\n    vector<size_t> dims;\n    rc = wasp.InqVarDims(opt.varname, dimnames, dims);\n    if (rc < 0) exit(1);\n\n    size_t nelements = 1;\n    for (int i = 0; i < dims.size(); i++) nelements *= dims[i];\n\n    T *data = new T[nelements];\n\n    FILE *fp = fopen(datafile.c_str(), \"rb\");\n    if (!fp) {\n        MyBase::SetErrMsg(\"fopen(%s) : %M\", datafile.c_str());\n        exit(1);\n    }\n\n    rc = wasp.OpenVarWrite(opt.varname, -1);\n    if (rc < 0) exit(1);\n\n    rc = fread(data, sizeof(*data), nelements, fp);\n    if (rc != nelements) {\n        MyBase::SetErrMsg(\"fread() : %M\");\n        exit(1);\n    }\n\n    vector<size_t> count = dims;\n    vector<size_t> start(dims.size(), 0);\n\n    rc = wasp.PutVara(start, count, data);\n    if (rc < 0) exit(1);\n\n    rc = wasp.CloseVar();\n    if (rc < 0) exit(1);\n\n    rc = wasp.Close();\n    if (rc < 0) exit(1);\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { exit(1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] netcdffile datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (argc != 3) {\n        cerr << \"Usage: \" << ProgName << \" [options] netcdffile datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    string ncdffile = argv[1];    // Path to a vdf file\n    string datafile = argv[2];    // Path to raw data file\n\n    if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr);\n\n    if (opt.type == \"float32\") {\n        float dummy = 0.0;\n        CopyVar(datafile, ncdffile, dummy);\n    } else if (opt.type == \"float64\") {\n        double dummy = 0.0;\n        CopyVar(datafile, ncdffile, dummy);\n    } else if (opt.type == \"int32\") {\n        int dummy = 0.0;\n        CopyVar(datafile, ncdffile, dummy);\n    } else if (opt.type == \"int16\") {\n        int16_t dummy = 0.0;\n        CopyVar(datafile, ncdffile, dummy);\n    } else if (opt.type == \"uint8\") {\n        unsigned char dummy = 0.0;\n        CopyVar(datafile, ncdffile, dummy);\n    } else {\n        cerr << \"Invalid type \" << opt.type << endl;\n    }\n\n    return (0);\n}\n"
  },
  {
    "path": "apps/tiff2geotiff/CMakeLists.txt",
    "content": "add_executable (tiff2geotiff tiff2geotiff.cpp geotiff_proj4.cpp getopt.cpp)\n\nif (WIN32)\n\ttarget_link_libraries (tiff2geotiff libtiff geotiff proj_6_1 common)\nelse ()\n\ttarget_link_libraries (tiff2geotiff tiff geotiff proj common)\nendif()\n\nOpenMPInstall (\n\tTARGETS tiff2geotiff\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/tiff2geotiff/geotiff_proj4.cpp",
    "content": "/******************************************************************************\n * $Id$\n *\n * Project:  libgeotiff\n * Purpose:  Code to convert a normalized GeoTIFF definition into a PROJ.4\n *           (OGDI) compatible projection string.\n * Author:   Frank Warmerdam, warmerda@home.com\n *\n ******************************************************************************\n * Copyright (c) 1999, Frank Warmerdam\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included\n * in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n ******************************************************************************\n *\n * $Log$\n * Revision 1.7  2010/02/11 18:10:38  alannorton\n *\n * Cleaned up code to avoid extraneous compiler warnings on windows.\n * Fixed metadata merge and vdf write to work with new DataMgr\n *\n * Revision 1.6  2009/07/14 20:34:07  alannorton\n * Changes to compile on Windows\n *\n * Revision 1.5  2009/07/13 19:03:18  clynejp\n *\n * Ported to RHEL5\n *\n * Revision 1.4  2009/05/22 22:25:54  alannorton\n * Added capability of handling lat/long projection, added option of specifying\n * corners as a command line argument.\n *\n * Revision 1.3  2009/04/06 22:12:03  alannorton\n * Modifications to geotiff to fix polar stereo and mercator projections.\n *\n * Revision 1.2  2009/04/03 20:56:13  alannorton\n * Changes to polar stereo projection parameters\n *\n * Revision 1.1  2009/04/03 18:00:05  alannorton\n * Added modified version of geotiff_proj4 because the library version did\n * not support mercator or polar stereographic projections.\n *\n * Revision 1.25  2008/05/21 04:25:01  fwarmerdam\n * avoid warnings.\n *\n * Revision 1.24  2008/05/21 04:12:57  fwarmerdam\n * added preliminary GTIFSetFromProj4() support\n *\n * Revision 1.23  2007/03/13 18:04:33  fwarmerdam\n * added new zealand map grid support per bug 1519\n *\n * Revision 1.22  2005/03/04 04:32:37  fwarmerdam\n * added cylindricalequalarea support\n *\n * Revision 1.21  2003/08/21 18:42:39  warmerda\n * fixed support for ModelTypeGeographic as per email from Young Su, Cha\n *\n * Revision 1.20  2003/07/08 17:31:30  warmerda\n * cleanup various warnings\n *\n * Revision 1.19  2002/11/29 20:57:09  warmerda\n * added LCC1SP mapping\n *\n * Revision 1.18  2002/07/09 14:47:53  warmerda\n * fixed translation of polar stereographic\n *\n * Revision 1.17  2001/11/23 19:53:56  warmerda\n * free PROJ.4 definitions after use\n *\n * Revision 1.16  2000/12/05 19:21:45  warmerda\n * added cassini support\n *\n * Revision 1.15  2000/12/05 17:44:41  warmerda\n * Use +R_A for Miller and VanDerGrinten\n *\n * Revision 1.14  2000/10/13 18:06:51  warmerda\n * added econic support for PROJ.4 translation\n *\n * Revision 1.13  2000/09/15 19:30:48  warmerda\n * *** empty log message ***\n *\n * Revision 1.12  2000/09/15 18:21:07  warmerda\n * Fixed order of parameters for LCC 2SP.  When parameters\n * were read from EPSG CSV files the standard parallels and origin\n * were mixed up.  This affects alot of state plane zones!\n *\n * Revision 1.11  2000/06/06 17:39:45  warmerda\n * Modify to work with projUV version of library.\n *\n * Revision 1.10  1999/07/06 15:05:51  warmerda\n * Fixed up LCC_1SP notes.\n *\n * Revision 1.9  1999/05/04 16:24:49  warmerda\n * Fixed projection string formating with zones.\n *\n * Revision 1.8  1999/05/04 12:27:01  geotiff\n * only emit proj unsupported warning if DEBUG defined\n *\n * Revision 1.7  1999/05/04 03:14:59  warmerda\n * fixed use of foot instead of ft for units\n *\n * Revision 1.6  1999/05/03 17:50:31  warmerda\n * avoid warnings on IRIX\n *\n * Revision 1.5  1999/04/29 23:02:24  warmerda\n * added mapsys utm test.\n *\n * Revision 1.4  1999/03/18 21:35:42  geotiff\n * Added reprojection functions\n *\n * Revision 1.3  1999/03/10 18:11:17  geotiff\n * Removed comment about this not being the master ... now it is.\n *\n * Revision 1.2  1999/03/10 18:10:27  geotiff\n * Avoid use of cpl_serv.h and CPLStrdup().\n *\n * Revision 1.1  1999/03/10 15:20:43  geotiff\n * New\n *\n */\n\n#ifdef WIN32\n    #include \"geotiff/cpl_serv.h\"\n    #include \"geotiff/geotiff.h\"\n    #include \"geotiff/geo_normalize.h\"\n    #include \"geotiff/geovalues.h\"\n#else\n    #include \"cpl_serv.h\"\n    #include \"geotiff.h\"\n    #include \"geo_normalize.h\"\n    #include \"geovalues.h\"\n#endif\n\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n#endif\n\n/************************************************************************/\n/*                          OSRProj4Tokenize()                          */\n/*                                                                      */\n/*      Custom tokenizing function for PROJ.4 strings.  The main        */\n/*      reason we can't just use CSLTokenizeString is to handle         */\n/*      strings with a + sign in the exponents of parameter values.     */\n/************************************************************************/\n\nstatic char **OSRProj4Tokenize(const char *pszFull)\n\n{\n    char * pszStart = NULL;\n    char * pszFullWrk;\n    char **papszTokens = (char **)calloc(sizeof(char *), 200);\n    int    i;\n    int    nTokens = 0;\n\n    if (pszFull == NULL) return NULL;\n\n    pszFullWrk = strdup(pszFull);\n\n    for (i = 0; pszFullWrk[i] != '\\0'; i++) {\n        switch (pszFullWrk[i]) {\n        case '+':\n            if (i == 0 || pszFullWrk[i - 1] == '\\0') {\n                if (pszStart != NULL) {\n                    if (strstr(pszStart, \"=\") != NULL) {\n                        papszTokens[nTokens++] = strdup(pszStart);\n                    } else {\n                        char szAsBoolean[100];\n                        strcpy(szAsBoolean, pszStart);\n                        strcat(szAsBoolean, \"=yes\");\n                        papszTokens[nTokens++] = strdup(szAsBoolean);\n                    }\n                }\n                pszStart = pszFullWrk + i + 1;\n            }\n            break;\n\n        case ' ':\n        case '\\t':\n        case '\\n': pszFullWrk[i] = '\\0'; break;\n\n        default: break;\n        }\n    }\n\n    if (pszStart != NULL && strlen(pszStart) > 0) { papszTokens[nTokens++] = strdup(pszStart); }\n\n    free(pszFullWrk);\n\n    return papszTokens;\n}\n\n/************************************************************************/\n/*                              OSR_GSV()                               */\n/************************************************************************/\n\nstatic const char *OSR_GSV(char **papszNV, const char *pszField)\n\n{\n    int field_len = (int)strlen(pszField);\n    int i;\n\n    if (!papszNV) return NULL;\n\n    for (i = 0; papszNV[i] != NULL; i++) {\n        if (EQUALN(papszNV[i], pszField, field_len)) {\n            if (papszNV[i][field_len] == '=') return papszNV[i] + field_len + 1;\n\n            if (strlen(papszNV[i]) == field_len) return \"\";\n        }\n    }\n\n    return NULL;\n}\n\n/************************************************************************/\n/*                              OSR_GDV()                               */\n/*                                                                      */\n/*      Fetch a particular parameter out of the parameter list, or      */\n/*      the indicated default if it isn't available.  This is a         */\n/*      helper function for importFromProj4().                          */\n/************************************************************************/\n\nstatic double OSR_GDV(char **papszNV, const char *pszField, double dfDefaultValue)\n\n{\n    const char *pszValue = OSR_GSV(papszNV, pszField);\n\n    // special hack to use k_0 if available.\n    if (pszValue == NULL && EQUAL(pszField, \"k\")) return OSR_GDV(papszNV, \"k_0\", dfDefaultValue);\n\n    if (pszValue == NULL)\n        return dfDefaultValue;\n    else\n        return atof(pszValue);\n}\n\n/************************************************************************/\n/*                         OSRFreeStringList()                          */\n/************************************************************************/\n\nstatic void OSRFreeStringList(char **list)\n\n{\n    int i;\n\n    for (i = 0; list != NULL && list[i] != NULL; i++) free(list[i]);\n    free(list);\n}\n\n/************************************************************************/\n/*                          GTIFSetFromProj4_WRF()                      */\n/* version modified from geotiff library version of GTIFSetFromPRoj4    */\n/* to handle mercator and polar stereo projections as required in WRF   */\n/*    Modifications by Alan Norton, April 2009                          */\n/************************************************************************/\n\nint GTIFSetFromProj4_WRF(GTIF *gtif, const char *proj4)\n\n{\n    char **     papszNV = OSRProj4Tokenize(proj4);\n    short       nSpheroid = KvUserDefined;\n    double      dfSemiMajor = 0.0, dfSemiMinor = 0.0, dfInvFlattening = 0.0;\n    int         nDatum = KvUserDefined;\n    int         nGCS = KvUserDefined;\n    const char *value;\n\n    /* -------------------------------------------------------------------- */\n    /*      Get the ellipsoid definition.                                   */\n    /* -------------------------------------------------------------------- */\n    value = OSR_GSV(papszNV, \"ellps\");\n\n    if (value == NULL) {\n        nSpheroid = Ellipse_Sphere;\n    } else if (EQUAL(value, \"WGS84\"))\n        nSpheroid = Ellipse_WGS_84;\n    else if (EQUAL(value, \"clrk66\"))\n        nSpheroid = Ellipse_Clarke_1866;\n    else if (EQUAL(value, \"clrk80\"))\n        nSpheroid = Ellipse_Clarke_1880;\n    else if (EQUAL(value, \"GRS80\"))\n        nSpheroid = Ellipse_GRS_1980;\n\n    if (nSpheroid == KvUserDefined) {\n        dfSemiMajor = OSR_GDV(papszNV, \"a\", 0.0);\n        dfSemiMinor = OSR_GDV(papszNV, \"b\", 0.0);\n        dfInvFlattening = OSR_GDV(papszNV, \"rf\", 0.0);\n        if (dfSemiMinor != 0.0 && dfInvFlattening == 0.0) dfInvFlattening = -1.0 / (dfSemiMinor / dfSemiMajor - 1.0);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Get the GCS/Datum code.                                         */\n    /* -------------------------------------------------------------------- */\n    value = OSR_GSV(papszNV, \"datum\");\n\n    if (value == NULL) {\n    } else if (EQUAL(value, \"WGS84\")) {\n        nGCS = GCS_WGS_84;\n        nDatum = Datum_WGS84;\n    } else if (EQUAL(value, \"NAD83\")) {\n        nGCS = GCS_NAD83;\n        nDatum = Datum_North_American_Datum_1983;\n    } else if (EQUAL(value, \"NAD27\")) {\n        nGCS = GCS_NAD27;\n        nDatum = Datum_North_American_Datum_1927;\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Operate on the basis of the projection name.                    */\n    /* -------------------------------------------------------------------- */\n    value = OSR_GSV(papszNV, \"proj\");\n\n    if (value == NULL) {\n        OSRFreeStringList(papszNV);\n        return FALSE;\n    }\n\n    else if (EQUAL(value, \"longlat\") || EQUAL(value, \"latlong\")) {\n        GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeGeographic);\n        GTIFKeySet(gtif, GTRasterTypeGeoKey, TYPE_SHORT, 1, RasterPixelIsArea);\n        GTIFKeySet(gtif, GeogAngularUnitsGeoKey, TYPE_SHORT, 1, Angular_Degree);\n\n    }\n    /* Handle just the WRF-required mercator tags:*/\n    else if (EQUAL(value, \"merc\")) {\n        GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected);\n        GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_Mercator);\n        GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lat_ts\", 0.0));\n        GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lon_0\", 0.0));\n        GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"k\", 1.0));\n        GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"x_0\", 0.0));\n        GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"y_0\", 0.0));\n\n        // specify lat_ts as standard parallel 1 (default 0? ????)\n        GTIFKeySet(gtif, ProjStdParallel1GeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lat_0\", 0.0));\n\n    } else if (EQUAL(value, \"tmerc\")) {\n        GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected);\n        GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined);\n\n        GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_TransverseMercator);\n\n        GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lat_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lon_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"k\", 1.0));\n\n        GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"x_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"utm\")) {\n        int         nZone = (int)OSR_GDV(papszNV, \"zone\", 0);\n        const char *south = OSR_GSV(papszNV, \"south\");\n\n        GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected);\n        GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined);\n\n        GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_TransverseMercator);\n\n        GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, 0.0);\n\n        GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, nZone * 6 - 183.0);\n\n        GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, 0.9996);\n\n        GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, 500000.0);\n\n        if (south != NULL)\n            GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, 10000000.0);\n        else\n            GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, 0.0);\n    }\n    /* For polar stereo only handle pure north or south projections*/\n    else if (EQUAL(value, \"stere\")) {\n        GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected);\n        GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_PolarStereographic);\n\n        // specify lat_ts as natural origin latitude\n        GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lat_ts\", 90.0));\n        GTIFKeySet(gtif, ProjStraightVertPoleLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lon_0\", 0.0));\n        GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"k\", 1.0));\n        GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"x_0\", 0.0));\n        GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"y_0\", 0.0));\n\n    } else if (EQUAL(value, \"lcc\") && OSR_GDV(papszNV, \"lat_0\", 0.0) == OSR_GDV(papszNV, \"lat_1\", 0.0)) {\n        GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected);\n        GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined);\n\n        GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_LambertConfConic_1SP);\n\n        GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lat_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lon_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"k\", 1.0));\n\n        GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"x_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"lcc\") && OSR_GDV(papszNV, \"lat_0\", 0.0) != OSR_GDV(papszNV, \"lat_1\", 0.0)) {\n        GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected);\n        GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined);\n\n        GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_LambertConfConic_2SP);\n\n        GTIFKeySet(gtif, ProjFalseOriginLatGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lat_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjFalseOriginLongGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lon_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjStdParallel1GeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lat_1\", 0.0));\n\n        GTIFKeySet(gtif, ProjStdParallel2GeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"lat_2\", 0.0));\n\n        GTIFKeySet(gtif, ProjFalseOriginEastingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"x_0\", 0.0));\n\n        GTIFKeySet(gtif, ProjFalseOriginNorthingGeoKey, TYPE_DOUBLE, 1, OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n#ifdef notdef\n    else if (EQUAL(value, \"bonne\")) {\n        SetBonne(OSR_GDV(papszNV, \"lat_1\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"cass\")) {\n        SetCS(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"nzmg\")) {\n        SetNZMG(OSR_GDV(papszNV, \"lat_0\", -41.0), OSR_GDV(papszNV, \"lon_0\", 173.0), OSR_GDV(papszNV, \"x_0\", 2510000.0), OSR_GDV(papszNV, \"y_0\", 6023150.0));\n    }\n\n    else if (EQUAL(value, \"cea\")) {\n        SetCEA(OSR_GDV(papszNV, \"lat_ts\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"merc\") /* 2SP form */\n             && OSR_GDV(papszNV, \"lat_ts\", 1000.0) < 999.0) {\n        SetMercator2SP(OSR_GDV(papszNV, \"lat_ts\", 0.0), 0.0, OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"merc\")) /* 1SP form */\n    {\n        SetMercator(0.0, OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"k\", 1.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"stere\") && ABS(OSR_GDV(papszNV, \"lat_0\", 0.0) - 90) < 0.001) {\n        SetPS(OSR_GDV(papszNV, \"lat_ts\", 90.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"k\", 1.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"stere\") && ABS(OSR_GDV(papszNV, \"lat_0\", 0.0) + 90) < 0.001) {\n        SetPS(OSR_GDV(papszNV, \"lat_ts\", -90.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"k\", 1.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUALN(value, \"stere\", 5) /* mostly sterea */\n             && CSLFetchNameValue(papszNV, \"k\") != NULL) {\n        SetOS(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"k\", 1.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"stere\")) {\n        SetStereographic(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), 1.0, OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"eqc\")) {\n        if (OSR_GDV(papszNV, \"lat_0\", 0.0) != OSR_GDV(papszNV, \"lat_ts\", 0.0))\n            SetEquirectangular2(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0) + dfFromGreenwich, OSR_GDV(papszNV, \"lat_ts\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0),\n                                OSR_GDV(papszNV, \"y_0\", 0.0));\n        else\n            SetEquirectangular(OSR_GDV(papszNV, \"lat_ts\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0) + dfFromGreenwich, OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"glabsgm\")) {\n        SetGaussLabordeReunion(OSR_GDV(papszNV, \"lat_0\", -21.116666667), OSR_GDV(papszNV, \"lon_0\", 55.53333333309) + dfFromGreenwich, OSR_GDV(papszNV, \"k_0\", 1.0), OSR_GDV(papszNV, \"x_0\", 160000.000),\n                               OSR_GDV(papszNV, \"y_0\", 50000.000));\n    }\n\n    else if (EQUAL(value, \"gnom\")) {\n        SetGnomonic(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"ortho\")) {\n        SetOrthographic(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"laea\")) {\n        SetLAEA(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"aeqd\")) {\n        SetAE(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"eqdc\")) {\n        SetEC(OSR_GDV(papszNV, \"lat_1\", 0.0), OSR_GDV(papszNV, \"lat_2\", 0.0), OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0),\n              OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"mill\")) {\n        SetMC(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"moll\")) {\n        SetMollweide(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"eck4\")) {\n        SetEckertIV(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"eck6\")) {\n        SetEckertVI(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"poly\")) {\n        SetPolyconic(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"aea\")) {\n        SetACEA(OSR_GDV(papszNV, \"lat_1\", 0.0), OSR_GDV(papszNV, \"lat_2\", 0.0), OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0),\n                OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"robin\")) {\n        SetRobinson(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"vandg\")) {\n        SetVDG(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"sinu\")) {\n        SetSinusoidal(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"gall\")) {\n        SetGS(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"goode\")) {\n        SetGH(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"geos\")) {\n        SetGEOS(OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"h\", 35785831.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"lcc\")) {\n        if (OSR_GDV(papszNV, \"lat_0\", 0.0) == OSR_GDV(papszNV, \"lat_1\", 0.0)) {\n            /* 1SP form */\n            SetLCC1SP(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"k_0\", 1.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n        } else {\n            /* 2SP form */\n            SetLCC(OSR_GDV(papszNV, \"lat_1\", 0.0), OSR_GDV(papszNV, \"lat_2\", 0.0), OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0),\n                   OSR_GDV(papszNV, \"y_0\", 0.0));\n        }\n    }\n\n    else if (EQUAL(value, \"omerc\")) {\n        SetHOM(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lonc\", 0.0), OSR_GDV(papszNV, \"alpha\", 0.0), 0.0, /* ??? */\n               OSR_GDV(papszNV, \"k\", 1.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"somerc\")) {\n        SetHOM(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), 90.0, 90.0, OSR_GDV(papszNV, \"k\", 1.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"krovak\")) {\n        SetKrovak(OSR_GDV(papszNV, \"lat_0\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"alpha\", 0.0),\n                  0.0,    // pseudo_standard_parallel_1\n                  OSR_GDV(papszNV, \"k\", 1.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"iwm_p\")) {\n        SetIWMPolyconic(OSR_GDV(papszNV, \"lat_1\", 0.0), OSR_GDV(papszNV, \"lat_2\", 0.0), OSR_GDV(papszNV, \"lon_0\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"wag1\")) {\n        SetWagner(1, 0.0, OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"wag2\")) {\n        SetWagner(2, 0.0, OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"wag3\")) {\n        SetWagner(3, OSR_GDV(papszNV, \"lat_ts\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"wag1\")) {\n        SetWagner(4, 0.0, OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"wag1\")) {\n        SetWagner(5, 0.0, OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"wag1\")) {\n        SetWagner(6, 0.0, OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"wag1\")) {\n        SetWagner(7, 0.0, OSR_GDV(papszNV, \"x_0\", 0.0), OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n\n    else if (EQUAL(value, \"tpeqd\")) {\n        SetTPED(OSR_GDV(papszNV, \"lat_1\", 0.0), OSR_GDV(papszNV, \"lon_1\", 0.0), OSR_GDV(papszNV, \"lat_2\", 0.0), OSR_GDV(papszNV, \"lon_2\", 0.0), OSR_GDV(papszNV, \"x_0\", 0.0),\n                OSR_GDV(papszNV, \"y_0\", 0.0));\n    }\n#endif\n    else {\n        /* unsupported coordinate system */\n        OSRFreeStringList(papszNV);\n        return FALSE;\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Write the GCS if we have it, otherwise write the datum.         */\n    /* -------------------------------------------------------------------- */\n    if (nGCS != KvUserDefined) {\n        GTIFKeySet(gtif, GeographicTypeGeoKey, TYPE_SHORT, 1, nGCS);\n    } else {\n        GTIFKeySet(gtif, GeographicTypeGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, GeogGeodeticDatumGeoKey, TYPE_SHORT, 1, nDatum);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Write the ellipsoid if we don't know the GCS.                   */\n    /* -------------------------------------------------------------------- */\n    if (nGCS == KvUserDefined) {\n        if (nSpheroid != KvUserDefined)\n            GTIFKeySet(gtif, GeogEllipsoidGeoKey, TYPE_SHORT, 1, nSpheroid);\n        else {\n            GTIFKeySet(gtif, GeogEllipsoidGeoKey, TYPE_SHORT, 1, KvUserDefined);\n            GTIFKeySet(gtif, GeogSemiMajorAxisGeoKey, TYPE_DOUBLE, 1, dfSemiMajor);\n            if (dfInvFlattening == 0.0)\n                GTIFKeySet(gtif, GeogSemiMinorAxisGeoKey, TYPE_DOUBLE, 1, dfSemiMajor);\n            else\n                GTIFKeySet(gtif, GeogInvFlatteningGeoKey, TYPE_DOUBLE, 1, dfInvFlattening);\n        }\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Linear units translation                                        */\n    /* -------------------------------------------------------------------- */\n    value = OSR_GSV(papszNV, \"units\");\n\n    if (value == NULL) {\n        value = OSR_GSV(papszNV, \"to_meter\");\n        if (value) {\n            GTIFKeySet(gtif, ProjLinearUnitsGeoKey, TYPE_SHORT, 1, KvUserDefined);\n            GTIFKeySet(gtif, ProjLinearUnitSizeGeoKey, TYPE_DOUBLE, 1, atof(value));\n        }\n    } else if (EQUAL(value, \"meter\") || EQUAL(value, \"m\")) {\n        GTIFKeySet(gtif, ProjLinearUnitsGeoKey, TYPE_SHORT, 1, Linear_Meter);\n    } else if (EQUAL(value, \"us-ft\")) {\n        GTIFKeySet(gtif, ProjLinearUnitsGeoKey, TYPE_SHORT, 1, Linear_Foot_US_Survey);\n    } else if (EQUAL(value, \"ft\")) {\n        GTIFKeySet(gtif, ProjLinearUnitsGeoKey, TYPE_SHORT, 1, Linear_Foot);\n    }\n\n    OSRFreeStringList(papszNV);\n\n    return TRUE;\n}\n\n/************************************************************************/\n/*                          GTIFGetProj4Defn()                          */\n/************************************************************************/\n\nchar *GTIFGetProj4Defn(GTIFDefn *psDefn)\n\n{\n    char   szProjection[512];\n    char   szUnits[24];\n    double dfFalseEasting, dfFalseNorthing;\n\n    szProjection[0] = '\\0';\n\n    /* ==================================================================== */\n    /*      Translate the units of measure.                                 */\n    /*                                                                      */\n    /*      Note that even with a +units, or +to_meter in effect, it is     */\n    /*      still assumed that all the projection parameters are in         */\n    /*      meters.                                                         */\n    /* ==================================================================== */\n    if (psDefn->UOMLength == Linear_Meter) {\n        strcpy(szUnits, \"+units=m \");\n    } else if (psDefn->UOMLength == Linear_Foot) {\n        strcpy(szUnits, \"+units=ft \");\n    } else if (psDefn->UOMLength == Linear_Foot_US_Survey) {\n        strcpy(szUnits, \"+units=us-ft \");\n    } else if (psDefn->UOMLength == Linear_Foot_Indian) {\n        strcpy(szUnits, \"+units=ind-ft \");\n    } else if (psDefn->UOMLength == Linear_Link) {\n        strcpy(szUnits, \"+units=link \");\n    } else if (psDefn->UOMLength == Linear_Yard_Indian) {\n        strcpy(szUnits, \"+units=ind-yd \");\n    } else if (psDefn->UOMLength == Linear_Fathom) {\n        strcpy(szUnits, \"+units=fath \");\n    } else if (psDefn->UOMLength == Linear_Mile_International_Nautical) {\n        strcpy(szUnits, \"+units=kmi \");\n    } else {\n        sprintf(szUnits, \"+to_meter=%.10f\", psDefn->UOMLengthInMeters);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      false easting and northing are in meters and that is what       */\n    /*      PROJ.4 wants regardless of the linear units.                    */\n    /* -------------------------------------------------------------------- */\n    dfFalseEasting = psDefn->ProjParm[5];\n    dfFalseNorthing = psDefn->ProjParm[6];\n\n    /* ==================================================================== */\n    /*      Handle general projection methods.                              */\n    /* ==================================================================== */\n\n    /* -------------------------------------------------------------------- */\n    /*      Geographic.                                                     */\n    /* -------------------------------------------------------------------- */\n    if (psDefn->Model == ModelTypeGeographic) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=latlong \");\n\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      UTM - special case override on transverse mercator so things    */\n    /*      will be more meaningful to the user.                            */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->MapSys == MapSys_UTM_North) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=utm +zone=%d \", psDefn->Zone);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Transverse Mercator                                             */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_TransverseMercator) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=tmerc +lat_0=%.9f +lon_0=%.9f +k=%f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting,\n                dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Mercator\t\t\t\t\t\t\t*/\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_Mercator) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=merc +lat_ts=%.9f +lon_0=%.9f +k=%f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting,\n                dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Cassini/Soldner                                                 */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_CassiniSoldner) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=cass +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Oblique Stereographic - Should this really map onto             */\n    /*      Stereographic?                                                  */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_ObliqueStereographic) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=stere +lat_0=%.9f +lon_0=%.9f +k=%f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting,\n                dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Stereographic                                                   */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_Stereographic) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=stere +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Polar Stereographic                                             */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_PolarStereographic) {\n        if (psDefn->ProjParm[0] > 0.0)\n            sprintf(szProjection + strlen(szProjection),\n                    \"+proj=stere +lat_0=90 +lat_ts=%.9f +lon_0=%.9f \"\n                    \"+k=%.9f +x_0=%.3f +y_0=%.3f \",\n                    psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting, dfFalseNorthing);\n        else\n            sprintf(szProjection + strlen(szProjection),\n                    \"+proj=stere +lat_0=-90 +lat_ts=%.9f +lon_0=%.9f \"\n                    \"+k=%.9f +x_0=%.3f +y_0=%.3f \",\n                    psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Equirectangular                                                 */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_Equirectangular) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=eqc +lat_ts=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Gnomonic                                                        */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_Gnomonic) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=gnom +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Orthographic                                                    */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_Orthographic) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=ortho +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Lambert Azimuthal Equal Area                                    */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_LambertAzimEqualArea) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=laea +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Azimuthal Equidistant                                           */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_AzimuthalEquidistant) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=aeqd +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Miller Cylindrical                                              */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_MillerCylindrical) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=mill +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f +R_A \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Polyconic                                                       */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_Polyconic) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=poly +lat_0=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[0], psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      AlbersEqualArea                                                 */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_AlbersEqualArea) {\n        sprintf(szProjection + strlen(szProjection),\n                \"+proj=aea +lat_1=%.9f +lat_2=%.9f +lat_0=%.9f +lon_0=%.9f\"\n                \" +x_0=%.3f +y_0=%.3f \",\n                psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[2], psDefn->ProjParm[3], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      EquidistantConic                                                */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_EquidistantConic) {\n        sprintf(szProjection + strlen(szProjection),\n                \"+proj=eqdc +lat_1=%.9f +lat_2=%.9f +lat_0=%.9f +lon_0=%.9f\"\n                \" +x_0=%.3f +y_0=%.3f \",\n                psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[2], psDefn->ProjParm[3], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Robinson                                                        */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_Robinson) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=robin +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      VanDerGrinten                                                   */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_VanDerGrinten) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=vandg +lon_0=%.9f +x_0=%.3f +y_0=%.3f +R_A \", psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Sinusoidal                                                      */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_Sinusoidal) {\n        sprintf(szProjection + strlen(szProjection), \"+proj=sinu +lon_0=%.9f +x_0=%.3f +y_0=%.3f \", psDefn->ProjParm[1], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      LambertConfConic_2SP                                            */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_LambertConfConic_2SP) {\n        sprintf(szProjection + strlen(szProjection),\n                \"+proj=lcc +lat_0=%.9f +lon_0=%.9f +lat_1=%.9f +lat_2=%.9f \"\n                \" +x_0=%.3f +y_0=%.3f \",\n                psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[2], psDefn->ProjParm[3], dfFalseEasting, dfFalseNorthing);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      LambertConfConic_1SP                                            */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_LambertConfConic_1SP) {\n        sprintf(szProjection + strlen(szProjection),\n                \"+proj=lcc +lat_0=%.9f +lat_1=%.9f +lon_0=%.9f\"\n                \" +k_0=%.9f +x_0=%.3f +y_0=%.3f \",\n                psDefn->ProjParm[0], psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[4], psDefn->ProjParm[5], psDefn->ProjParm[6]);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      CT_CylindricalEqualArea                                         */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_CylindricalEqualArea) {\n        sprintf(szProjection + strlen(szProjection),\n                \"+proj=cea +lat_ts=%.9f +lon_0=%.9f \"\n                \" +x_0=%.3f +y_0=%.3f \",\n                psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[5], psDefn->ProjParm[6]);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      NewZealandMapGrid                                               */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_NewZealandMapGrid) {\n        sprintf(szProjection + strlen(szProjection),\n                \"+proj=nzmg +lat_0=%.9f +lon_0=%.9f\"\n                \" +x_0=%.3f +y_0=%.3f \",\n                psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[5], psDefn->ProjParm[6]);\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      Transverse Mercator - south oriented.                           */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_TransvMercator_SouthOriented) {\n        /* this appears to be an unsupported formulation with PROJ.4 */\n    }\n\n    /* -------------------------------------------------------------------- */\n    /*      ObliqueMercator (Hotine)                                        */\n    /* -------------------------------------------------------------------- */\n    else if (psDefn->CTProjection == CT_ObliqueMercator) {\n        /* not clear how ProjParm[3] - angle from rectified to skewed grid -\n           should be applied ... see the +not_rot flag for PROJ.4.\n           Just ignoring for now. */\n\n        sprintf(szProjection + strlen(szProjection),\n                \"+proj=omerc +lat_0=%.9f +lonc=%.9f +alpha=%.9f\"\n                \" +k=%.9f +x_0=%.3f +y_0=%.3f \",\n                psDefn->ProjParm[0], psDefn->ProjParm[1], psDefn->ProjParm[2], psDefn->ProjParm[4], psDefn->ProjParm[5], psDefn->ProjParm[6]);\n    }\n\n    /* ==================================================================== */\n    /*      Handle ellipsoid information.                                   */\n    /* ==================================================================== */\n    if (psDefn->Ellipsoid == Ellipse_WGS_84)\n        strcat(szProjection, \"+ellps=WGS84 \");\n    else if (psDefn->Ellipsoid == Ellipse_Clarke_1866)\n        strcat(szProjection, \"+ellps=clrk66 \");\n    else if (psDefn->Ellipsoid == Ellipse_Clarke_1880)\n        strcat(szProjection, \"+ellps=clrk80 \");\n    else if (psDefn->Ellipsoid == Ellipse_GRS_1980)\n        strcat(szProjection, \"+ellps=GRS80 \");\n    else {\n        if (psDefn->SemiMajor != 0.0 && psDefn->SemiMinor != 0.0) { sprintf(szProjection + strlen(szProjection), \"+a=%.3f +b=%.3f \", psDefn->SemiMajor, psDefn->SemiMinor); }\n    }\n\n    strcat(szProjection, szUnits);\n\n    return (strdup(szProjection));\n}\n\n#if !defined(HAVE_LIBPROJ) || !defined(HAVE_PROJECTS_H)\n\nint GTIFProj4ToLatLong(GTIFDefn *psDefn, int nPoints, double *padfX, double *padfY)\n{\n    (void)psDefn;\n    (void)nPoints;\n    (void)padfX;\n    (void)padfY;\n    #ifdef DEBUG\n    fprintf(stderr, \"GTIFProj4ToLatLong() - PROJ.4 support not compiled in.\\n\");\n    #endif\n    return FALSE;\n}\n\nint GTIFProj4FromLatLong(GTIFDefn *psDefn, int nPoints, double *padfX, double *padfY)\n{\n    (void)psDefn;\n    (void)nPoints;\n    (void)padfX;\n    (void)padfY;\n    #ifdef DEBUG\n    fprintf(stderr, \"GTIFProj4FromLatLong() - PROJ.4 support not compiled in.\\n\");\n    #endif\n    return FALSE;\n}\n#else\n\n    #include \"proj_api.h\"\n\n    #ifdef USE_PROJUV\n        #define UV projUV\n    #endif\n\n/************************************************************************/\n/*                        GTIFProj4FromLatLong()                        */\n/*                                                                      */\n/*      Convert lat/long values to projected coordinate for a           */\n/*      particular definition.                                          */\n/************************************************************************/\n\nint GTIFProj4FromLatLong(GTIFDefn *psDefn, int nPoints, double *padfX, double *padfY)\n\n{\n    char * pszProjection, **papszArgs;\n    projPJ psPJ;\n    int    i;\n\n    /* -------------------------------------------------------------------- */\n    /*      Get a projection definition.                                    */\n    /* -------------------------------------------------------------------- */\n    pszProjection = GTIFGetProj4Defn(psDefn);\n\n    if (pszProjection == NULL) return FALSE;\n\n    /* -------------------------------------------------------------------- */\n    /*      Parse into tokens for pj_init(), and initialize the projection. */\n    /* -------------------------------------------------------------------- */\n\n    papszArgs = CSLTokenizeStringComplex(pszProjection, \" +\", TRUE, FALSE);\n    free(pszProjection);\n\n    psPJ = pj_init(CSLCount(papszArgs), papszArgs);\n\n    CSLDestroy(papszArgs);\n\n    if (psPJ == NULL) { return FALSE; }\n\n    /* -------------------------------------------------------------------- */\n    /*      Process each of the points.                                     */\n    /* -------------------------------------------------------------------- */\n    for (i = 0; i < nPoints; i++) {\n        projUV sUV;\n\n        sUV.u = padfX[i] * DEG_TO_RAD;\n        sUV.v = padfY[i] * DEG_TO_RAD;\n\n        sUV = pj_fwd(sUV, psPJ);\n\n        padfX[i] = sUV.u;\n        padfY[i] = sUV.v;\n    }\n\n    pj_free(psPJ);\n\n    return TRUE;\n}\n\n/************************************************************************/\n/*                         GTIFProj4ToLatLong()                         */\n/*                                                                      */\n/*      Convert projection coordinates to lat/long for a particular     */\n/*      definition.                                                     */\n/************************************************************************/\n\nint GTIFProj4ToLatLong(GTIFDefn *psDefn, int nPoints, double *padfX, double *padfY)\n\n{\n    char * pszProjection, **papszArgs;\n    projPJ psPJ;\n    int    i;\n\n    /* -------------------------------------------------------------------- */\n    /*      Get a projection definition.                                    */\n    /* -------------------------------------------------------------------- */\n    pszProjection = GTIFGetProj4Defn(psDefn);\n\n    if (pszProjection == NULL) return FALSE;\n\n    /* -------------------------------------------------------------------- */\n    /*      Parse into tokens for pj_init(), and initialize the projection. */\n    /* -------------------------------------------------------------------- */\n\n    papszArgs = CSLTokenizeStringComplex(pszProjection, \" +\", TRUE, FALSE);\n    free(pszProjection);\n\n    psPJ = pj_init(CSLCount(papszArgs), papszArgs);\n\n    CSLDestroy(papszArgs);\n\n    if (psPJ == NULL) { return FALSE; }\n\n    /* -------------------------------------------------------------------- */\n    /*      Process each of the points.                                     */\n    /* -------------------------------------------------------------------- */\n    for (i = 0; i < nPoints; i++) {\n        projUV sUV;\n\n        sUV.u = padfX[i];\n        sUV.v = padfY[i];\n\n        sUV = pj_inv(sUV, psPJ);\n\n        padfX[i] = sUV.u * RAD_TO_DEG;\n        padfY[i] = sUV.v * RAD_TO_DEG;\n    }\n\n    pj_free(psPJ);\n\n    return TRUE;\n}\n\n#endif /* has projects.h and -lproj */\n"
  },
  {
    "path": "apps/tiff2geotiff/getopt.cpp",
    "content": "/*\n * Copyright (c) 1987 Regents of the University of California.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n * 3. All advertising materials mentioning features or use of this software\n *    must display the following acknowledgement:\n *\tThis product includes software developed by the University of\n *\tCalifornia, Berkeley and its contributors.\n * 4. Neither the name of the University nor the names of its contributors\n *    may be used to endorse or promote products derived from this software\n *    without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n#if defined(LIBC_SCCS) && !defined(lint)\nstatic char sccsid[] = \"@(#)getopt.c\t4.13 (Berkeley) 2/23/91\";\n#endif /* LIBC_SCCS and not lint */\n\n#include <stdio.h>\n#include <string.h>\n\nconst char *myoptarg = 0;\nint         optind = 1;\n\n/*\n * get option letter from argument vector\n */\n\nint opterr = 1; /* if error message should be printed */\nint optopt;     /* character checked for validity */\n\n#define BADCH (int)'?'\n#define EMSG  \"\"\n\nint getopt(int nargc, char **nargv, const char *ostr)\n{\n    const static char *place = EMSG; /* option letter processing */\n    const char *       oli;          /* option letter list index */\n    char *             p;\n\n    if (!*place) { /* update scanning pointer */\n        if (optind >= nargc || *(place = nargv[optind]) != '-') {\n            place = EMSG;\n            return (EOF);\n        }\n        if (place[1] && *++place == '-') { /* found \"--\" */\n            ++optind;\n            place = EMSG;\n            return (EOF);\n        }\n    } /* option letter okay? */\n    if ((optopt = (int)*place++) == (int)':' || !(oli = strchr(ostr, optopt))) {\n        /*\n         * if the user didn't specify '-' as an option,\n         * assume it means EOF.\n         */\n        if (optopt == (int)'-') return (EOF);\n        if (!*place) ++optind;\n        if (opterr) {\n            if (!(p = strrchr(*nargv, '/')))\n                p = *nargv;\n            else\n                ++p;\n            (void)fprintf(stderr, \"%s: illegal option -- %c\\n\", p, optopt);\n        }\n        return (BADCH);\n    }\n    if (*++oli != ':') { /* don't need argument */\n        myoptarg = NULL;\n        if (!*place) ++optind;\n    } else {        /* need an argument */\n        if (*place) /* no white space */\n            myoptarg = place;\n        else if (nargc <= ++optind) { /* no arg */\n            place = EMSG;\n            if (!(p = strrchr(*nargv, '/')))\n                p = *nargv;\n            else\n                ++p;\n            if (opterr) (void)fprintf(stderr, \"%s: option requires an argument -- %c\\n\", p, optopt);\n            return (BADCH);\n        } else /* white space */\n            myoptarg = nargv[optind];\n        place = EMSG;\n        ++optind;\n    }\n    return (optopt); /* dump back option letter */\n}\n"
  },
  {
    "path": "apps/tiff2geotiff/tiff2geotiff.cpp",
    "content": "/* tiff2geotiff.c -- based on Sam Leffler's \"tiffcp\" and \"geotifcp\" codes */\n\n/*\n *  Original code had this copyright notice:\n *\n * Copyright (c) 1988-1995 Sam Leffler\n * Copyright (c) 1991-1995 Silicon Graphics, Inc.\n *\n * and a lot of legal stuff denying liability for anything.\n * This version modified (by A. Norton) to enable specifying a file of lon-lat extents\n * and timesteps that can be inserted to georeference and date the\n * separate directories in the output geotiff file.\n */\n\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <ctype.h>\n#include <stdint.h>\n#include \"vapor/VAssert.h\"\n\n#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1\n\n/* GeoTIFF overrides */\n\n#ifdef WIN32\n    #include \"geotiff/geotiff.h\"\n    #include \"geotiff/geo_normalize.h\"\n    #include \"geotiff/geo_tiffp.h\"\n    #include \"geotiff/geo_keyp.h\"\n    #include \"geotiff/xtiffio.h\"\n    #include \"geotiff/cpl_serv.h\"\n    #include \"proj_api.h\"\n#else\n    #include \"geotiff.h\"\n    #include \"geo_normalize.h\"\n    #include \"geo_tiffp.h\"\n    #include \"geo_keyp.h\"\n    #include \"xtiffio.h\"\n    #include \"cpl_serv.h\"\n    #include \"proj_api.h\"\n#endif\n\n#ifdef WIN32\n    #include <float.h>\n    #pragma warning(disable : 4996)\n#endif\n\n#define TIFFOpen  XTIFFOpen\n#define TIFFClose XTIFFClose\n\n#if defined(VMS)\n    #define unlink delete\n#endif\n\n#define streq(a, b)     (strcmp(a, b) == 0)\n#define strneq(a, b, n) (strncmp(a, b, n) == 0)\n\n#define TRUE  1\n#define FALSE 0\n\nint getopt(int nargc, char **nargv, const char *ostr);\n\nstatic int    outtiled = -1;\nstatic uint32_t tilewidth;\nstatic uint32_t tilelength;\nstatic int    convert_8_to_4 = 0;\n\nstatic uint16_t      config;\nstatic uint16_t      compression;\nstatic uint16_t      predictor;\nstatic uint16_t      fillorder;\nstatic uint32_t      rowsperstrip;\nstatic uint32_t      g3opts;\nstatic int         ignore = FALSE; /* if true, ignore read errors */\nstatic uint32_t      defg3opts = (uint32_t)-1;\nstatic int         quality = 75; /* JPEG quality */\nstatic int         jpegcolormode = JPEGCOLORMODE_RGB;\nstatic uint16_t      defcompression = (uint16_t)-1;\nstatic uint16_t      defpredictor = (uint16_t)-1;\nstatic const char *geofile = (char *)0;\nstatic const char *timeLonLatName = (char *)0;\nstatic const char *timeName = (char *)0;\nstatic FILE *      timeLonLatFile = (FILE *)0;\nstatic FILE *      timeFile = (FILE *)0;\nstatic float       lonLatExts[4] = {999.f, 999.f, 999.f, 999.f};\nstatic uint32_t      currentImageWidth;\nstatic uint32_t      currentImageHeight;\n\nstatic const char *proj4_string = (char *)0;\nstatic const char *p4string;\nstatic const char *worldfile = (char *)0;\nstatic int         dirnum = 0;\nstatic void        ApplyWorldFile(const char *worldfile, TIFF *out);\nstatic int         tiffcp(TIFF *, TIFF *);\nstatic int         processCompressOptions(const char *);\nstatic void        usage(void);\nstatic int         applyCorners(float cors[4], float relpos[4], TIFF *out);\nextern int         GTIFSetFromProj4_WRF(GTIF *gtif, const char *proj4);\n\nint main(int argc, char *argv[])\n{\n    uint16_t             defconfig = (uint16_t)-1;\n    uint16_t             deffillorder = 0;\n    uint32_t             deftilewidth = (uint32_t)-1;\n    uint32_t             deftilelength = (uint32_t)-1;\n    uint32_t             defrowsperstrip = (uint32_t)-1;\n    uint32_t             diroff = 0;\n    TIFF *             in;\n    TIFF *             out;\n    const char *       mode = \"w\";\n    int                c;\n    extern int         optind;\n    extern const char *myoptarg;\n\n    while ((c = getopt(argc, argv, \"c:f:l:m:M:n:o:p:r:w:e:g:4:aistd\")) != -1) switch (c) {\n        case 'a': /* append to output */ mode = \"a\"; break;\n        case 'd': /* down cast 8bit to 4bit */ convert_8_to_4 = 1; break;\n        case 'c': /* compression scheme */\n            if (!processCompressOptions(myoptarg)) usage();\n            break;\n        case 'e': worldfile = myoptarg; break;\n        case 'f': /* fill order */\n            if (streq(myoptarg, \"lsb2msb\"))\n                deffillorder = FILLORDER_LSB2MSB;\n            else if (streq(myoptarg, \"msb2lsb\"))\n                deffillorder = FILLORDER_MSB2LSB;\n            else\n                usage();\n            break;\n        case 'i': /* ignore errors */ ignore = TRUE; break;\n        case 'g': /* GeoTIFF metadata file */ geofile = myoptarg; break;\n        case 'm': /*multiple times and latlon extents file */\n            timeLonLatName = myoptarg;\n            timeLonLatFile = fopen(timeLonLatName, \"r\");\n            if (!timeLonLatFile) {\n                fprintf(stderr, \"Failure to open %s\\n\", timeLonLatName);\n                exit(-1);\n            }\n            break;\n        case 'M': /*multiple timestamps file */\n            timeName = myoptarg;\n            timeFile = fopen(timeName, \"r\");\n            if (!timeFile) {\n                fprintf(stderr, \"Failure to open %s\\n\", timeName);\n                exit(-1);\n            }\n            break;\n        case 'n': /* single latlong extents, requires option 4 */\n        {\n            int retval = sscanf(myoptarg, \"%f %f %f %f\", lonLatExts, lonLatExts + 1, lonLatExts + 2, lonLatExts + 3);\n            if (retval != 4) {\n                fprintf(stderr, \"Four lon/lat extent values required\\n\");\n                exit(-1);\n            }\n        } break;\n\n        case '4': proj4_string = myoptarg; break;\n        case 'l': /* tile length */\n            outtiled = TRUE;\n            deftilelength = atoi(myoptarg);\n            break;\n        case 'o': /* initial directory offset */ diroff = strtoul(myoptarg, NULL, 0); break;\n        case 'p': /* planar configuration */\n            if (streq(myoptarg, \"separate\"))\n                defconfig = PLANARCONFIG_SEPARATE;\n            else if (streq(myoptarg, \"contig\"))\n                defconfig = PLANARCONFIG_CONTIG;\n            else\n                usage();\n            break;\n        case 'r': /* rows/strip */ defrowsperstrip = atoi(myoptarg); break;\n        case 's': /* generate stripped output */ outtiled = FALSE; break;\n        case 't': /* generate tiled output */ outtiled = TRUE; break;\n        case 'w': /* tile width */\n            outtiled = TRUE;\n            deftilewidth = atoi(myoptarg);\n            break;\n        case '?':\n            usage();\n            /*NOTREACHED*/\n        }\n    if (argc - optind < 2) usage();\n    out = TIFFOpen(argv[argc - 1], mode);\n    if (out == NULL) return (-2);\n    for (; optind < argc - 1; optind++) {\n        in = TIFFOpen(argv[optind], \"r\");\n        if (in == NULL) return (-3);\n        if (diroff != 0 && !TIFFSetSubDirectory(in, diroff)) {\n            TIFFError(TIFFFileName(in), \"Error, setting subdirectory at %#x\", diroff);\n            (void)TIFFClose(out);\n            return (1);\n        }\n        do {\n            config = defconfig;\n            compression = defcompression;\n            predictor = defpredictor;\n            fillorder = deffillorder;\n            rowsperstrip = defrowsperstrip;\n            tilewidth = deftilewidth;\n            tilelength = deftilelength;\n            g3opts = defg3opts;\n            if (!tiffcp(in, out) || !TIFFWriteDirectory(out)) {\n                (void)TIFFClose(out);\n                return (1);\n            }\n        } while (TIFFReadDirectory(in));\n        (void)TIFFClose(in);\n    }\n    (void)TIFFClose(out);\n    return (0);\n}\n\nstatic void ApplyWorldFile(const char *worldfilename, TIFF *out)\n\n{\n    FILE * tfw;\n    double pixsize[3], xoff, yoff, tiepoint[6], x_rot, y_rot;\n\n    /*\n     * Read the world file.  Note we currently ignore rotational coefficients!\n     */\n    tfw = fopen(worldfilename, \"rt\");\n    if (tfw == NULL) {\n        perror(worldfilename);\n        return;\n    }\n\n    int rt;\n    rt = std::fscanf(tfw, \"%lf\", pixsize + 0);\n    VAssert(rt > 0 && rt != EOF);\n    rt = std::fscanf(tfw, \"%lf\", &y_rot);\n    VAssert(rt > 0 && rt != EOF);\n    rt = std::fscanf(tfw, \"%lf\", &x_rot);\n    VAssert(rt > 0 && rt != EOF);\n    rt = std::fscanf(tfw, \"%lf\", pixsize + 1);\n    VAssert(rt > 0 && rt != EOF);\n    rt = std::fscanf(tfw, \"%lf\", &xoff);\n    VAssert(rt > 0 && rt != EOF);\n    rt = std::fscanf(tfw, \"%lf\", &yoff);\n    VAssert(rt > 0 && rt != EOF);\n\n    fclose(tfw);\n\n    /*\n     * Write out pixel scale, and tiepoint information.\n     */\n    if (x_rot == 0.0 && y_rot == 0.0) {\n        pixsize[1] = ABS(pixsize[1]);\n        pixsize[2] = 0.0;\n        TIFFSetField(out, GTIFF_PIXELSCALE, 3, pixsize);\n\n        tiepoint[0] = 0.5;\n        tiepoint[1] = 0.5;\n        tiepoint[2] = 0.0;\n        tiepoint[3] = xoff;\n        tiepoint[4] = yoff;\n        tiepoint[5] = 0.0;\n        TIFFSetField(out, GTIFF_TIEPOINTS, 6, tiepoint);\n    } else {\n        double adfMatrix[16];\n\n        memset(adfMatrix, 0, sizeof(double) * 16);\n\n        adfMatrix[0] = pixsize[0];\n        adfMatrix[1] = x_rot;\n        adfMatrix[3] = xoff - (pixsize[0] + x_rot) * 0.5;\n        adfMatrix[4] = y_rot;\n        adfMatrix[5] = pixsize[1];\n        adfMatrix[7] = yoff - (pixsize[1] + y_rot) * 0.5;\n        adfMatrix[15] = 1.0;\n\n        TIFFSetField(out, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix);\n    }\n}\n\nstatic void InstallGeoTIFF(TIFF *out)\n{\n    GTIF *gtif = (GTIF *)0; /* GeoKey-level descriptor */\n    FILE *fd;\n\n    gtif = GTIFNew(out);\n    if (!gtif) {\n        printf(\"failed in GTIFNew\\n\");\n        return;\n    }\n\n    if (geofile) {\n        /* Install keys and tags */\n        fd = fopen(geofile, \"r\");\n        if (fd == NULL) {\n            perror(geofile);\n            exit(-1);\n        }\n        if (!GTIFImport(gtif, 0, fd)) {\n            fprintf(stderr, \"Failure in GTIFImport\\n\");\n            exit(-1);\n        }\n        fclose(fd);\n    } else if (proj4_string) {\n        // Make sure ellps is in string:\n        int pos;\n        for (pos = 0; pos < (int)strlen(proj4_string) - 6; pos++) {\n            if (strncmp(proj4_string + pos, \"+ellps\", 6) == 0) {\n                pos = -1;\n                break;\n            }\n        }\n        p4string = proj4_string;\n        if (pos >= 0) {\n            char *newString = new char[strlen(proj4_string) + 15];\n            strcpy(newString, proj4_string);\n            strcat(newString, \" +ellps=sphere\");\n\n            p4string = newString;\n        }\n\n        if (!GTIFSetFromProj4_WRF(gtif, p4string)) {\n            fprintf(stderr, \"Failure in GTIFSetFromProj4_WRF\\n\");\n            exit(-1);\n        }\n        if (timeLonLatFile) {\n            // get next timestamp and latlon extents from timeLonLatFile\n            float lonlat[4];\n            float relPos[4];\n            char  timestamp[20];\n            // double modelPixelScale[3] = {0.,0.,0.};\n            // double tiePoint[6] = {0.,0.,0.,0.,0.,0.};\n\n            int rc = fscanf(timeLonLatFile, \"%19s %f %f %f %f %f %f %f %f\", timestamp, lonlat, lonlat + 1, lonlat + 2, lonlat + 3, relPos, relPos + 1, relPos + 2, relPos + 3);\n            dirnum++;\n            if (rc != 9) {\n                fprintf(stderr, \"Failed to read line %d of time-lon-lat file\\n\", dirnum);\n                if (rc == 0) fprintf(stderr, \"time-lon-lat file has fewer entries than images in tiff file\\n\");\n                exit(-3);\n            } else {    // convert the latlon and time and put into geotiff\n\n                // insert time stamp from file\n                TIFFSetField(out, TIFFTAG_DATETIME, timestamp);\n\n                // Use proj4 to calculate the corner coordinates of the\n                // image from the lonlat extents\n                int rc = applyCorners(lonlat, relPos, out);\n                if (rc) exit(rc);\n            }\n        } else if (lonLatExts[0] != 999.f) {\n            // Use proj4 to calculate the corner coordinates of the\n            // image from the lonlat extents\n            float relpos[4] = {0.f, 0.f, 1.f, 1.f};\n            int   rc = applyCorners(lonLatExts, relpos, out);\n            if (rc) exit(rc);\n        }\n    } else if (timeFile) {\n        // get next timestamp from timeFile\n        char timestamp[20];\n        int  rc = fscanf(timeFile, \"%19s\", timestamp);\n        dirnum++;\n        if (rc != 1) {\n            fprintf(stderr, \"Failed to read line %d of timestamp file\\n\", dirnum);\n            if (rc == 0) fprintf(stderr, \"timestamp file has fewer entries than images in tiff file\\n\");\n            exit(-3);\n        } else {    // put timestamp into tiff\n\n            // insert time stamp from file\n            TIFFSetField(out, TIFFTAG_DATETIME, timestamp);\n        }\n    }\n    GTIFWriteKeys(gtif);\n    GTIFFree(gtif);\n    return;\n}\n//\nstatic int applyCorners(float lonlat[4], float relPos[4], TIFF *out)\n{\n    void * p;\n    double modelPixelScale[3] = {0., 0., 0.};\n    double tiePoint[6] = {0., 0., 0., 0., 0., 0.};\n    p = pj_init_plus(p4string);\n\n    if (!p && !ignore) {\n        // Invalid string. Get the error code:\n        int *pjerrnum = pj_get_errno_ref();\n        fprintf(stderr, \"Invalid Proj4 string %s; message:\\n %s\\n\", p4string, pj_strerrno(*pjerrnum));\n        return -1;\n    }\n    if (p) {\n        // reproject latlon to specified coord projection.\n        // unless it's already a lat/lon projection\n        double dbextents[4];\n        if (pj_is_latlong(static_cast<projPJ>(p))) {\n            for (int j = 0; j < 4; j++) { dbextents[j] = lonlat[j]; }\n        } else {\n            // Must convert to radians:\n            const double DEG2RAD = 3.141592653589793 / 180.;\n            const char * latLongProjString = \"+proj=latlong +ellps=sphere\";\n            projPJ       latlon_p = pj_init_plus(latLongProjString);\n            // convert to radians...\n            for (int j = 0; j < 4; j++) dbextents[j] = lonlat[j] * DEG2RAD;\n            // convert the latlons to coordinates in the projection.\n            double dummy[1] = {0.0};\n            int    rc = pj_transform(latlon_p, static_cast<projPJ>(p), 2, 2, dbextents, dbextents + 1, dummy);\n            if (rc && !ignore) {\n                int *pjerrnum = pj_get_errno_ref();\n                fprintf(stderr, \"Error converting lonlat to projection\\n %s\\n\", pj_strerrno(*pjerrnum));\n                return (-1);\n            }\n        }\n        // Now the extents in projection space must be scaled, to\n        // allow for the corners being in the interior of the page.\n        // If R0 and R1 are the relative positions of the plot corners\n        // in the page, and X0 and X1 are the x-coords of the plot corners\n        // then the page corners are at:\n        // LOWER = (X0*R1 - X1*R0)/(R1-R0)\n        // UPPER = LOWER + (X1-X0)/(R1-R0)\n\n        // When dealing with x coordinates,\n        // R0 and R1 are relPos[0] and [2] , X0 and X1 are dbextents[0] and [2]\n        // similarly the y coordinates use the [1] and [3] indices\n        double newDBExtents[4];\n        newDBExtents[0] = (dbextents[0] * relPos[2] - dbextents[2] * relPos[0]) / (relPos[2] - relPos[0]);\n        newDBExtents[2] = newDBExtents[0] + (dbextents[2] - dbextents[0]) / (relPos[2] - relPos[0]);\n        newDBExtents[1] = (dbextents[1] * relPos[3] - dbextents[3] * relPos[1]) / (relPos[3] - relPos[1]);\n        newDBExtents[3] = newDBExtents[1] + (dbextents[3] - dbextents[1]) / (relPos[3] - relPos[1]);\n        // calculate scale and model tie point\n        modelPixelScale[0] = (newDBExtents[2] - newDBExtents[0]) / ((double)currentImageWidth - 1.);\n        modelPixelScale[1] = (newDBExtents[3] - newDBExtents[1]) / ((double)currentImageHeight - 1.);\n\n        tiePoint[3] = newDBExtents[0];\n        // Following is just dbextents[1] + dbextents[3]-dbextents[1] = dbextents[3].\n        // tiePoint[4] = dbextents[1] + ((double)currentImageHeight -1.)*modelPixelScale[1];\n        tiePoint[4] = newDBExtents[3];\n        TIFFSetField(out, GTIFF_TIEPOINTS, 6, tiePoint);\n        TIFFSetField(out, GTIFF_PIXELSCALE, 3, modelPixelScale);\n    }\n    return 0;\n}\n\nstatic void CopyGeoTIFF(TIFF *in, TIFF *out)\n{\n    GTIF *  gtif = (GTIF *)0; /* GeoKey-level descriptor */\n    double *d_list = NULL;\n    int16_t   d_list_count;\n\n    /* read definition from source file. */\n    gtif = GTIFNew(in);\n    if (!gtif) return;\n\n    if (TIFFGetField(in, GTIFF_TIEPOINTS, &d_list_count, &d_list)) TIFFSetField(out, GTIFF_TIEPOINTS, d_list_count, d_list);\n    if (TIFFGetField(in, GTIFF_PIXELSCALE, &d_list_count, &d_list)) TIFFSetField(out, GTIFF_PIXELSCALE, d_list_count, d_list);\n    if (TIFFGetField(in, GTIFF_TRANSMATRIX, &d_list_count, &d_list)) TIFFSetField(out, GTIFF_TRANSMATRIX, d_list_count, d_list);\n\n    /* Here we violate the GTIF abstraction to retarget on another file.\n       We should just have a function for copying tags from one GTIF object\n       to another. */\n    gtif->gt_tif = out;\n    gtif->gt_flags |= FLAG_FILE_MODIFIED;\n\n    /* Install keys and tags */\n    GTIFWriteKeys(gtif);\n    GTIFFree(gtif);\n    return;\n}\n\nstatic void processG3Options(const char *cp)\n{\n    if ((cp = strchr(cp, ':')) != NULL) {\n        if (defg3opts == (uint32_t)-1) defg3opts = 0;\n        do {\n            cp++;\n            if (strneq(cp, \"1d\", 2))\n                defg3opts &= ~GROUP3OPT_2DENCODING;\n            else if (strneq(cp, \"2d\", 2))\n                defg3opts |= GROUP3OPT_2DENCODING;\n            else if (strneq(cp, \"fill\", 4))\n                defg3opts |= GROUP3OPT_FILLBITS;\n            else\n                usage();\n        } while ((cp = strchr(cp, ':')) != NULL);\n    }\n}\n\nstatic int processCompressOptions(const char *opt)\n{\n    if (streq(opt, \"none\"))\n        defcompression = COMPRESSION_NONE;\n    else if (streq(opt, \"packbits\"))\n        defcompression = COMPRESSION_PACKBITS;\n    else if (strneq(opt, \"jpeg\", 4)) {\n        const char *cp = strchr(opt, ':');\n        if (cp && isdigit(cp[1])) quality = atoi(cp + 1);\n        if (cp && strchr(cp, 'r')) jpegcolormode = JPEGCOLORMODE_RAW;\n        defcompression = COMPRESSION_JPEG;\n    } else if (strneq(opt, \"g3\", 2)) {\n        processG3Options(opt);\n        defcompression = COMPRESSION_CCITTFAX3;\n    } else if (streq(opt, \"g4\"))\n        defcompression = COMPRESSION_CCITTFAX4;\n    else if (strneq(opt, \"lzw\", 3)) {\n        const char *cp = strchr(opt, ':');\n        if (cp) defpredictor = atoi(cp + 1);\n        defcompression = COMPRESSION_LZW;\n    } else if (strneq(opt, \"zip\", 3)) {\n        const char *cp = strchr(opt, ':');\n        if (cp) defpredictor = atoi(cp + 1);\n        defcompression = COMPRESSION_DEFLATE;\n    } else\n        return (0);\n    return (1);\n}\n\nconst char *stuff[] = {\"usage: tiff2geotiff [options] input... output\",\n                       \"where options are:\",\n                       \" -g file\tinstall GeoTIFF metadata from <file>\",\n                       \" -4 proj4_str\tinstall GeoTIFF metadata from proj4 string\",\n                       \" -e file\tinstall positioning info from ESRI Worldfile <file>\",\n                       \" -a\t\tappend to output instead of overwriting\",\n                       \" -m file\tSpecify filename with multiple timestamps and image placement info:\",\n                       \"\t\t\tEach line of file has date/timestamp, and 8 floats;\",\n                       \"\t\t\tfirst four are lon/lat corners of plot area,\",\n                       \"\t\t\tsecond four are relative positions of plot corners in page.\",\n                       \"\t\t\tThis option requires option -4\",\n                       \" -M file   Specify filename with multiple timestamps, w/o georeferencing:\",\n                       \"\t\t\tEach line of file has date/timestamp only\",\n                       \"\t\t\tOption -4 must not be specified.\",\n                       \" -n llx lly urx ury\",\n                       \"\t\t\tInstall longitude/latitude extents;\",\n                       \"\t\t\tFour lon and lat values must in quotes in the order:\",\n                       \"\t\t\tlower-left longitude, lower-left latitude,\",\n                       \"\t\t\tupper-right longitute, upper-right latitude\",\n                       \"\t\t\tThis option requires option -4\",\n                       \"\t\t\tOption '-m' overrides this option\",\n                       \" -o offset\tset initial directory offset\",\n                       \" -p contig\tpack samples contiguously (e.g. RGBRGB...)\",\n                       \" -p separate\tstore samples separately (e.g. RRR...GGG...BBB...)\",\n                       \" -s\t\twrite output in strips\",\n                       \" -t\t\twrite output in tiles\",\n                       \" -i\t\tignore read errors\",\n                       \" -d\t\ttruncate 8 bitspersample to 4bitspersample\",\n                       \"\",\n                       \" -r #\t\tmake each strip have no more than # rows\",\n                       \" -w #\t\tset output tile width (pixels)\",\n                       \" -l #\t\tset output tile length (pixels)\",\n                       \"\",\n                       \" -f lsb2msb\tforce lsb-to-msb FillOrder for output\",\n                       \" -f msb2lsb\tforce msb-to-lsb FillOrder for output\",\n                       \"\",\n                       \" -c lzw[:opts]\tcompress output with Lempel-Ziv & Welch encoding\",\n                       \" -c zip[:opts]\tcompress output with deflate encoding\",\n                       \" -c jpeg[:opts]compress output with JPEG encoding\",\n                       \" -c packbits\tcompress output with packbits encoding\",\n                       \" -c g3[:opts]\tcompress output with CCITT Group 3 encoding\",\n                       \" -c g4\t\tcompress output with CCITT Group 4 encoding\",\n                       \" -c none\tuse no compression algorithm on output\",\n                       \"\",\n                       \"Group 3 options:\",\n                       \" 1d\t\tuse default CCITT Group 3 1D-encoding\",\n                       \" 2d\t\tuse optional CCITT Group 3 2D-encoding\",\n                       \" fill\t\tbyte-align EOL codes\",\n                       \"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs\",\n                       \"\",\n                       \"JPEG options:\",\n                       \" #\t\tset compression quality level (0-100, default 75)\",\n                       \" r\t\toutput color image as RGB rather than YCbCr\",\n                       \"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality\",\n                       \"\",\n                       \"LZW and deflate options:\",\n                       \" #\t\tset predictor value\",\n                       \"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing\",\n                       NULL};\n\nstatic void usage(void)\n{\n    char buf[BUFSIZ];\n    int  i;\n\n    setbuf(stderr, buf);\n    for (i = 0; stuff[i] != NULL; i++) fprintf(stderr, \"%s\\n\", stuff[i]);\n    exit(-1);\n}\n\nstatic void CheckAndCorrectColormap(TIFF *tif, int n, uint16_t *r, uint16_t *g, uint16_t *b)\n{\n    int i;\n\n    for (i = 0; i < n; i++)\n        if (r[i] >= 256 || g[i] >= 256 || b[i] >= 256) return;\n    TIFFWarning(TIFFFileName(tif), \"Scaling 8-bit colormap\");\n#define CVT(x) (((x) * ((1L << 16) - 1)) / 255)\n    for (i = 0; i < n; i++) {\n        r[i] = CVT(r[i]);\n        g[i] = CVT(g[i]);\n        b[i] = CVT(b[i]);\n    }\n#undef CVT\n}\n\n#define CopyField(tag, v) \\\n    if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)\n#define CopyField2(tag, v1, v2) \\\n    if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)\n#define CopyField3(tag, v1, v2, v3) \\\n    if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)\n#define CopyField4(tag, v1, v2, v3, v4) \\\n    if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)\n\nstatic struct cpTag {\n    uint16_t       tag;\n    uint16_t       count;\n    TIFFDataType type;\n} tags[] = {\n    {TIFFTAG_SUBFILETYPE, 1, TIFF_LONG},\n    {TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT},\n    {TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII},\n    {TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII},\n    {TIFFTAG_MAKE, 1, TIFF_ASCII},\n    {TIFFTAG_MODEL, 1, TIFF_ASCII},\n    {TIFFTAG_ORIENTATION, 1, TIFF_SHORT},\n    {TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT},\n    {TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT},\n    {TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL},\n    {TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL},\n    {TIFFTAG_PAGENAME, 1, TIFF_ASCII},\n    {TIFFTAG_XPOSITION, 1, TIFF_RATIONAL},\n    {TIFFTAG_YPOSITION, 1, TIFF_RATIONAL},\n    {TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG},\n    {TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT},\n    {TIFFTAG_PAGENUMBER, 2, TIFF_SHORT},\n    {TIFFTAG_SOFTWARE, 1, TIFF_ASCII},\n    {TIFFTAG_DATETIME, 1, TIFF_ASCII},\n    {TIFFTAG_ARTIST, 1, TIFF_ASCII},\n    {TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII},\n    {TIFFTAG_WHITEPOINT, 1, TIFF_RATIONAL},\n    {TIFFTAG_PRIMARYCHROMATICITIES, (uint16_t)-1, TIFF_RATIONAL},\n    {TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT},\n    {TIFFTAG_BADFAXLINES, 1, TIFF_LONG},\n    {TIFFTAG_CLEANFAXDATA, 1, TIFF_SHORT},\n    {TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG},\n    {TIFFTAG_INKSET, 1, TIFF_SHORT},\n    {TIFFTAG_INKNAMES, 1, TIFF_ASCII},\n    {TIFFTAG_DOTRANGE, 2, TIFF_SHORT},\n    {TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII},\n    {TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT},\n    {TIFFTAG_YCBCRCOEFFICIENTS, (uint16_t)-1, TIFF_RATIONAL},\n    {TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT},\n    {TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT},\n    {TIFFTAG_REFERENCEBLACKWHITE, (uint16_t)-1, TIFF_RATIONAL},\n    {TIFFTAG_EXTRASAMPLES, (uint16_t)-1, TIFF_SHORT},\n    {TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE},\n    {TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE},\n};\n#define NTAGS (sizeof(tags) / sizeof(tags[0]))\n\nstatic void cpOtherTags(TIFF *in, TIFF *out)\n{\n    struct cpTag *p = tags;\n    for (int i = 0; i < NTAGS; i++, p++) {\n        switch (p->type) {\n        case TIFF_SHORT:\n            if (p->count == 1) {\n                uint16_t shortv;\n                CopyField(p->tag, shortv);\n            } else if (p->count == 2) {\n                uint16_t shortv1, shortv2;\n                CopyField2(p->tag, shortv1, shortv2);\n            } else if (p->count == (uint16_t)-1) {\n                uint16_t  shortv1;\n                uint16_t *shortav;\n                CopyField2(p->tag, shortv1, shortav);\n            }\n            break;\n        case TIFF_LONG: {\n            uint32_t longv;\n            CopyField(p->tag, longv);\n        } break;\n        case TIFF_RATIONAL:\n            if (p->count == 1) {\n                float floatv;\n                // CopyField(tag, v) replaced by following\n                // Workaround a tiff lib bug:  TIFFGetField gets a very small float\n                if (TIFFGetField(in, p->tag, &floatv) && floatv >= .00001) TIFFSetField(out, p->tag, floatv);\n            } else if (p->count == (uint16_t)-1) {\n                float *floatav;\n                CopyField(p->tag, floatav);\n            }\n            break;\n        case TIFF_ASCII: {\n            char *stringv;\n            CopyField(p->tag, stringv);\n        } break;\n        case TIFF_DOUBLE:\n            if (p->count == 1) {\n                double doublev;\n                CopyField(p->tag, doublev);\n            } else if (p->count == (uint16_t)-1) {\n                double *doubleav;\n                CopyField(p->tag, doubleav);\n            }\n            break;\n        default: break;\n        }\n    }\n}\n\ntypedef int (*copyFunc)(TIFF *in, TIFF *out, uint32_t l, uint32_t w, uint16_t samplesperpixel);\nstatic copyFunc pickCopyFunc(TIFF *, TIFF *, uint16_t, uint16_t);\n\nstatic int tiffcp(TIFF *in, TIFF *out)\n{\n    uint16_t   samplesperpixel, shortv;\n    uint16_t   bitspersample = 0;\n    copyFunc cf;\n    uint32_t   w, l;\n\n    CopyField(TIFFTAG_IMAGEWIDTH, w);\n    CopyField(TIFFTAG_IMAGELENGTH, l);\n\n    currentImageWidth = w;\n    currentImageHeight = l;\n    if (convert_8_to_4) {\n        TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 4);\n    } else {\n        CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample);\n    }\n    if (compression != (uint16_t)-1)\n        TIFFSetField(out, TIFFTAG_COMPRESSION, compression);\n    else\n        CopyField(TIFFTAG_COMPRESSION, compression);\n    if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB)\n        TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);\n    else\n        CopyField(TIFFTAG_PHOTOMETRIC, shortv);\n    if (fillorder != 0)\n        TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);\n    else\n        CopyField(TIFFTAG_FILLORDER, shortv);\n    CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);\n    /*\n     * Choose tiles/strip for the output image according to\n     * the command line arguments (-tiles, -strips) and the\n     * structure of the input image.\n     */\n    if (outtiled == -1) outtiled = TIFFIsTiled(in);\n    if (outtiled) {\n        /*\n         * Setup output file's tile width&height.  If either\n         * is not specified, use either the value from the\n         * input image or, if nothing is defined, use the\n         * library default.\n         */\n        if (tilewidth == (uint32_t)-1) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);\n        if (tilelength == (uint32_t)-1) TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);\n        TIFFDefaultTileSize(out, &tilewidth, &tilelength);\n        TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);\n        TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);\n    } else {\n        /*\n         * RowsPerStrip is left unspecified: use either the\n         * value from the input image or, if nothing is defined,\n         * use the library default.\n         */\n        if (rowsperstrip == (uint32_t)-1) TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);\n        rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);\n        TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);\n    }\n    if (config != (uint16_t)-1)\n        TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);\n    else\n        CopyField(TIFFTAG_PLANARCONFIG, config);\n    if (g3opts != (uint32_t)-1)\n        TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts);\n    else\n        CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);\n    if (samplesperpixel <= 4) {\n        uint16_t *tr, *tg, *tb, *ta;\n        CopyField4(TIFFTAG_TRANSFERFUNCTION, tr, tg, tb, ta);\n    }\n    {\n        uint16_t *red, *green, *blue;\n        if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue)) {\n            CheckAndCorrectColormap(in, 1 << bitspersample, red, green, blue);\n            TIFFSetField(out, TIFFTAG_COLORMAP, red, green, blue);\n        }\n    }\n    /* SMinSampleValue & SMaxSampleValue */\n    switch (compression) {\n    case COMPRESSION_JPEG:\n        TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);\n        TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);\n        break;\n    case COMPRESSION_LZW:\n    case COMPRESSION_DEFLATE:\n        if (predictor != (uint16_t)-1)\n            TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);\n        else\n            CopyField(TIFFTAG_PREDICTOR, predictor);\n        break;\n    }\n    cpOtherTags(in, out);\n\n    if (geofile || proj4_string || timeFile)\n        InstallGeoTIFF(out);\n    else\n        CopyGeoTIFF(in, out);\n\n    if (worldfile) ApplyWorldFile(worldfile, out);\n\n    cf = pickCopyFunc(in, out, bitspersample, samplesperpixel);\n    return (cf ? (*cf)(in, out, l, w, samplesperpixel) : FALSE);\n}\n\n/*\n * Copy Functions.\n */\n#define DECLAREcpFunc(x) static int x(TIFF *in, TIFF *out, uint32_t imagelength, uint32_t imagewidth, tsample_t spp)\n\n#define DECLAREreadFunc(x) static void x(TIFF *in, unsigned char *buf, uint32_t imagelength, uint32_t imagewidth, tsample_t spp)\ntypedef void (*readFunc)(TIFF *, unsigned char *, uint32_t, uint32_t, tsample_t);\n\n#define DECLAREwriteFunc(x) static int x(TIFF *out, unsigned char *buf, uint32_t imagelength, uint32_t imagewidth, tsample_t spp)\ntypedef int (*writeFunc)(TIFF *, unsigned char *, uint32_t, uint32_t, tsample_t);\n\n/*\n * Contig -> contig by scanline for rows/strip change.\n */\nDECLAREcpFunc(cpContig2ContigByRow)\n{\n    unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));\n    uint32_t         row;\n\n    (void)imagewidth;\n    (void)spp;\n    for (row = 0; row < imagelength; row++) {\n        if (TIFFReadScanline(in, buf, row, 0) < 0 && !ignore) goto done;\n        if (TIFFWriteScanline(out, buf, row, 0) < 0) goto bad;\n    }\ndone:\n    _TIFFfree(buf);\n    return (TRUE);\nbad:\n    _TIFFfree(buf);\n    return (FALSE);\n}\n\n/*\n * Contig -> contig by scanline for rows/strip change.\n */\nDECLAREcpFunc(cpContig2ContigByRow_8_to_4)\n{\n    unsigned char *buf_in = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));\n    unsigned char *buf_out = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));\n    uint32_t         row;\n\n    printf(\"Downsample\\n\");\n\n    (void)imagewidth;\n    (void)spp;\n    for (row = 0; row < imagelength; row++) {\n        int i_in, i_out_byte;\n\n        if (TIFFReadScanline(in, buf_in, row, 0) < 0 && !ignore) goto done;\n\n        for (i_in = 0, i_out_byte = 0; i_in < (int)imagewidth; i_in += 2, i_out_byte++) { buf_out[i_out_byte] = (buf_in[i_in] & 0xf) * 16 + (buf_in[i_in + 1] & 0xf); }\n\n        if (TIFFWriteScanline(out, buf_out, row, 0) < 0) goto bad;\n    }\ndone:\n    _TIFFfree(buf_in);\n    _TIFFfree(buf_out);\n    return (TRUE);\nbad:\n    _TIFFfree(buf_in);\n    _TIFFfree(buf_out);\n    return (FALSE);\n}\n\n/*\n * Strip -> strip for change in encoding.\n */\nDECLAREcpFunc(cpDecodedStrips)\n{\n    tsize_t        stripsize = TIFFStripSize(in);\n    unsigned char *buf = (unsigned char *)_TIFFmalloc(stripsize);\n\n    (void)imagewidth;\n    (void)spp;\n    if (buf) {\n        tstrip_t s, ns = TIFFNumberOfStrips(in);\n        uint32_t   row = 0;\n        for (s = 0; s < ns; s++) {\n            tsize_t cc = (row + rowsperstrip > imagelength) ? TIFFVStripSize(in, imagelength - row) : stripsize;\n            if (TIFFReadEncodedStrip(in, s, buf, cc) < 0 && !ignore) break;\n            if (TIFFWriteEncodedStrip(out, s, buf, cc) < 0) {\n                _TIFFfree(buf);\n                return (FALSE);\n            }\n            row += rowsperstrip;\n        }\n        _TIFFfree(buf);\n        return (TRUE);\n    }\n    return (FALSE);\n}\n\n/*\n * Separate -> separate by row for rows/strip change.\n */\nDECLAREcpFunc(cpSeparate2SeparateByRow)\n{\n    unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));\n    uint32_t         row;\n    tsample_t      s;\n\n    (void)imagewidth;\n    for (s = 0; s < spp; s++) {\n        for (row = 0; row < imagelength; row++) {\n            if (TIFFReadScanline(in, buf, row, s) < 0 && !ignore) goto done;\n            if (TIFFWriteScanline(out, buf, row, s) < 0) goto bad;\n        }\n    }\ndone:\n    _TIFFfree(buf);\n    return (TRUE);\nbad:\n    _TIFFfree(buf);\n    return (FALSE);\n}\n\n/*\n * Contig -> separate by row.\n */\nDECLAREcpFunc(cpContig2SeparateByRow)\n{\n    unsigned char *inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));\n    unsigned char *outbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));\n    unsigned char *inp, *outp;\n    uint32_t         n;\n    uint32_t         row;\n    tsample_t      s;\n\n    /* unpack channels */\n    for (s = 0; s < spp; s++) {\n        for (row = 0; row < imagelength; row++) {\n            if (TIFFReadScanline(in, inbuf, row, 0) < 0 && !ignore) goto done;\n            inp = inbuf + s;\n            outp = outbuf;\n            for (n = imagewidth; n-- > 0;) {\n                *outp++ = *inp;\n                inp += spp;\n            }\n            if (TIFFWriteScanline(out, outbuf, row, s) < 0) goto bad;\n        }\n    }\ndone:\n    if (inbuf) _TIFFfree(inbuf);\n    if (outbuf) _TIFFfree(outbuf);\n    return (TRUE);\nbad:\n    if (inbuf) _TIFFfree(inbuf);\n    if (outbuf) _TIFFfree(outbuf);\n    return (FALSE);\n}\n\n/*\n * Separate -> contig by row.\n */\nDECLAREcpFunc(cpSeparate2ContigByRow)\n{\n    unsigned char *inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));\n    unsigned char *outbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));\n    unsigned char *inp, *outp;\n    uint32_t         n;\n    uint32_t         row;\n    tsample_t      s;\n\n    for (row = 0; row < imagelength; row++) {\n        /* merge channels */\n        for (s = 0; s < spp; s++) {\n            if (TIFFReadScanline(in, inbuf, row, s) < 0 && !ignore) goto done;\n            inp = inbuf;\n            outp = outbuf + s;\n            for (n = imagewidth; n-- > 0;) {\n                *outp = *inp++;\n                outp += spp;\n            }\n        }\n        if (TIFFWriteScanline(out, outbuf, row, 0) < 0) goto bad;\n    }\ndone:\n    if (inbuf) _TIFFfree(inbuf);\n    if (outbuf) _TIFFfree(outbuf);\n    return (TRUE);\nbad:\n    if (inbuf) _TIFFfree(inbuf);\n    if (outbuf) _TIFFfree(outbuf);\n    return (FALSE);\n}\n\nstatic void cpStripToTile(unsigned char *out, unsigned char *in, uint32_t rows, uint32_t cols, int outskew, int inskew)\n{\n    while (rows-- > 0) {\n        uint32_t j = cols;\n        while (j-- > 0) *out++ = *in++;\n        out += outskew;\n        in += inskew;\n    }\n}\n\nstatic void cpContigBufToSeparateBuf(unsigned char *out, unsigned char *in, uint32_t rows, uint32_t cols, int outskew, int inskew, tsample_t spp)\n{\n    while (rows-- > 0) {\n        uint32_t j = cols;\n        while (j-- > 0) *out++ = *in, in += spp;\n        out += outskew;\n        in += inskew;\n    }\n}\n\nstatic void cpSeparateBufToContigBuf(unsigned char *out, unsigned char *in, uint32_t rows, uint32_t cols, int outskew, int inskew, tsample_t spp)\n{\n    while (rows-- > 0) {\n        uint32_t j = cols;\n        while (j-- > 0) *out = *in++, out += spp;\n        out += outskew;\n        in += inskew;\n    }\n}\n\nstatic int cpImage(TIFF *in, TIFF *out, readFunc fin, writeFunc fout, uint32_t imagelength, uint32_t imagewidth, tsample_t spp)\n{\n    int            status = FALSE;\n    unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFRasterScanlineSize(in) * imagelength);\n    if (buf) {\n        (*fin)(in, buf, imagelength, imagewidth, spp);\n        status = (fout)(out, buf, imagelength, imagewidth, spp);\n        _TIFFfree(buf);\n    }\n    return (status);\n}\n\nDECLAREreadFunc(readContigStripsIntoBuffer)\n{\n    tsize_t        scanlinesize = TIFFScanlineSize(in);\n    unsigned char *bufp = buf;\n    uint32_t         row;\n\n    (void)imagewidth;\n    (void)spp;\n    for (row = 0; row < imagelength; row++) {\n        if (TIFFReadScanline(in, bufp, row, 0) < 0 && !ignore) break;\n        bufp += scanlinesize;\n    }\n}\n\nDECLAREreadFunc(readSeparateStripsIntoBuffer)\n{\n    tsize_t        scanlinesize = TIFFScanlineSize(in);\n    unsigned char *scanline = (unsigned char *)_TIFFmalloc(scanlinesize);\n\n    (void)imagewidth;\n    if (scanline) {\n        unsigned char *bufp = buf;\n        uint32_t         row;\n        tsample_t      s;\n\n        for (row = 0; row < imagelength; row++) {\n            /* merge channels */\n            for (s = 0; s < spp; s++) {\n                unsigned char *sp = scanline;\n                unsigned char *bp = bufp + s;\n                tsize_t        n = scanlinesize;\n\n                if (TIFFReadScanline(in, sp, row, s) < 0 && !ignore) goto done;\n                while (n-- > 0) *bp = *bufp++, bp += spp;\n            }\n            bufp += scanlinesize;\n        }\n    done:\n        _TIFFfree(scanline);\n    }\n}\n\nDECLAREreadFunc(readContigTilesIntoBuffer)\n{\n    unsigned char *tilebuf = (unsigned char *)_TIFFmalloc(TIFFTileSize(in));\n    uint32_t         imagew = TIFFScanlineSize(in);\n    uint32_t         tilew = TIFFTileRowSize(in);\n    int            iskew = imagew - tilew;\n    unsigned char *bufp = buf;\n    uint32_t         tw, tl;\n    uint32_t         row;\n\n    (void)spp;\n    if (tilebuf == 0) return;\n    (void)TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);\n    (void)TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);\n    for (row = 0; row < imagelength; row += tl) {\n        uint32_t nrow = (row + tl > imagelength) ? imagelength - row : tl;\n        uint32_t colb = 0;\n        uint32_t col;\n\n        for (col = 0; col < imagewidth; col += tw) {\n            if (TIFFReadTile(in, tilebuf, col, row, 0, 0) < 0 && !ignore) goto done;\n            if (colb + tilew > imagew) {\n                uint32_t width = imagew - colb;\n                uint32_t oskew = tilew - width;\n                cpStripToTile(bufp + colb, tilebuf, nrow, width, oskew + iskew, oskew);\n            } else\n                cpStripToTile(bufp + colb, tilebuf, nrow, tilew, iskew, 0);\n            colb += tilew;\n        }\n        bufp += imagew * nrow;\n    }\ndone:\n    _TIFFfree(tilebuf);\n}\n\nDECLAREreadFunc(readSeparateTilesIntoBuffer)\n{\n    uint32_t         imagew = TIFFScanlineSize(in);\n    uint32_t         tilew = TIFFTileRowSize(in);\n    int            iskew = imagew - tilew;\n    unsigned char *tilebuf = (unsigned char *)_TIFFmalloc(TIFFTileSize(in));\n    unsigned char *bufp = buf;\n    uint32_t         tw, tl;\n    uint32_t         row;\n\n    if (tilebuf == 0) return;\n    (void)TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);\n    (void)TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);\n    for (row = 0; row < imagelength; row += tl) {\n        uint32_t nrow = (row + tl > imagelength) ? imagelength - row : tl;\n        uint32_t colb = 0;\n        uint32_t col;\n\n        for (col = 0; col < imagewidth; col += tw) {\n            tsample_t s;\n\n            for (s = 0; s < spp; s++) {\n                if (TIFFReadTile(in, tilebuf, col, row, 0, s) < 0 && !ignore) goto done;\n                /*\n                 * Tile is clipped horizontally.  Calculate\n                 * visible portion and skewing factors.\n                 */\n                if (colb + tilew > imagew) {\n                    uint32_t width = imagew - colb;\n                    int    oskew = tilew - width;\n                    cpSeparateBufToContigBuf(bufp + colb + s, tilebuf, nrow, width, oskew + iskew, oskew, spp);\n                } else\n                    cpSeparateBufToContigBuf(bufp + colb + s, tilebuf, nrow, tw, iskew, 0, spp);\n            }\n            colb += tilew;\n        }\n        bufp += imagew * nrow;\n    }\ndone:\n    _TIFFfree(tilebuf);\n}\n\nDECLAREwriteFunc(writeBufferToContigStrips)\n{\n    tsize_t scanline = TIFFScanlineSize(out);\n    uint32_t  row;\n\n    (void)imagewidth;\n    (void)spp;\n    for (row = 0; row < imagelength; row++) {\n        if (TIFFWriteScanline(out, buf, row, 0) < 0) return (FALSE);\n        buf += scanline;\n    }\n    return (TRUE);\n}\n\nDECLAREwriteFunc(writeBufferToSeparateStrips)\n{\n    unsigned char *obuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));\n    tsample_t      s;\n\n    if (obuf == NULL) return (0);\n    for (s = 0; s < spp; s++) {\n        uint32_t row;\n        for (row = 0; row < imagelength; row++) {\n            unsigned char *inp = buf + s;\n            unsigned char *outp = obuf;\n            uint32_t         n = imagewidth;\n\n            while (n-- > 0) *outp++ = *inp, inp += spp;\n            if (TIFFWriteScanline(out, obuf, row, s) < 0) {\n                _TIFFfree(obuf);\n                return (FALSE);\n            }\n        }\n    }\n    _TIFFfree(obuf);\n    return (TRUE);\n}\n\nDECLAREwriteFunc(writeBufferToContigTiles)\n{\n    uint32_t         imagew = TIFFScanlineSize(out);\n    uint32_t         tilew = TIFFTileRowSize(out);\n    int            iskew = imagew - tilew;\n    unsigned char *obuf = (unsigned char *)_TIFFmalloc(TIFFTileSize(out));\n    unsigned char *bufp = buf;\n    uint32_t         tl, tw;\n    uint32_t         row;\n\n    (void)spp;\n    if (obuf == NULL) return (FALSE);\n    (void)TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);\n    (void)TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);\n    for (row = 0; row < imagelength; row += tilelength) {\n        uint32_t nrow = (row + tl > imagelength) ? imagelength - row : tl;\n        uint32_t colb = 0;\n        uint32_t col;\n\n        for (col = 0; col < imagewidth; col += tw) {\n            /*\n             * Tile is clipped horizontally.  Calculate\n             * visible portion and skewing factors.\n             */\n            if (colb + tilew > imagew) {\n                uint32_t width = imagew - colb;\n                int    oskew = tilew - width;\n                cpStripToTile(obuf, bufp + colb, nrow, width, oskew, oskew + iskew);\n            } else\n                cpStripToTile(obuf, bufp + colb, nrow, tilew, 0, iskew);\n            if (TIFFWriteTile(out, obuf, col, row, 0, 0) < 0) {\n                _TIFFfree(obuf);\n                return (FALSE);\n            }\n            colb += tilew;\n        }\n        bufp += nrow * imagew;\n    }\n    _TIFFfree(obuf);\n    return (TRUE);\n}\n\nDECLAREwriteFunc(writeBufferToSeparateTiles)\n{\n    uint32_t         imagew = TIFFScanlineSize(out);\n    tsize_t        tilew = TIFFTileRowSize(out);\n    int            iskew = imagew - tilew;\n    unsigned char *obuf = (unsigned char *)_TIFFmalloc(TIFFTileSize(out));\n    unsigned char *bufp = buf;\n    uint32_t         tl, tw;\n    uint32_t         row;\n\n    if (obuf == NULL) return (FALSE);\n    (void)TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);\n    (void)TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);\n    for (row = 0; row < imagelength; row += tl) {\n        uint32_t nrow = (row + tl > imagelength) ? imagelength - row : tl;\n        uint32_t colb = 0;\n        uint32_t col;\n\n        for (col = 0; col < imagewidth; col += tw) {\n            tsample_t s;\n            for (s = 0; s < spp; s++) {\n                /*\n                 * Tile is clipped horizontally.  Calculate\n                 * visible portion and skewing factors.\n                 */\n                if (colb + tilew > imagew) {\n                    uint32_t width = imagew - colb;\n                    int    oskew = tilew - width;\n\n                    cpContigBufToSeparateBuf(obuf, bufp + colb + s, nrow, width, oskew / spp, oskew + imagew, spp);\n                } else\n                    cpContigBufToSeparateBuf(obuf, bufp + colb + s, nrow, tilewidth, 0, iskew, spp);\n                if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0) {\n                    _TIFFfree(obuf);\n                    return (FALSE);\n                }\n            }\n            colb += tilew;\n        }\n        bufp += nrow * imagew;\n    }\n    _TIFFfree(obuf);\n    return (TRUE);\n}\n\n/*\n * Contig strips -> contig tiles.\n */\nDECLAREcpFunc(cpContigStrips2ContigTiles) { return cpImage(in, out, readContigStripsIntoBuffer, writeBufferToContigTiles, imagelength, imagewidth, spp); }\n\n/*\n * Contig strips -> separate tiles.\n */\nDECLAREcpFunc(cpContigStrips2SeparateTiles) { return cpImage(in, out, readContigStripsIntoBuffer, writeBufferToSeparateTiles, imagelength, imagewidth, spp); }\n\n/*\n * Separate strips -> contig tiles.\n */\nDECLAREcpFunc(cpSeparateStrips2ContigTiles) { return cpImage(in, out, readSeparateStripsIntoBuffer, writeBufferToContigTiles, imagelength, imagewidth, spp); }\n\n/*\n * Separate strips -> separate tiles.\n */\nDECLAREcpFunc(cpSeparateStrips2SeparateTiles) { return cpImage(in, out, readSeparateStripsIntoBuffer, writeBufferToSeparateTiles, imagelength, imagewidth, spp); }\n\n/*\n * Contig strips -> contig tiles.\n */\nDECLAREcpFunc(cpContigTiles2ContigTiles) { return cpImage(in, out, readContigTilesIntoBuffer, writeBufferToContigTiles, imagelength, imagewidth, spp); }\n\n/*\n * Contig tiles -> separate tiles.\n */\nDECLAREcpFunc(cpContigTiles2SeparateTiles) { return cpImage(in, out, readContigTilesIntoBuffer, writeBufferToSeparateTiles, imagelength, imagewidth, spp); }\n\n/*\n * Separate tiles -> contig tiles.\n */\nDECLAREcpFunc(cpSeparateTiles2ContigTiles) { return cpImage(in, out, readSeparateTilesIntoBuffer, writeBufferToContigTiles, imagelength, imagewidth, spp); }\n\n/*\n * Separate tiles -> separate tiles (tile dimension change).\n */\nDECLAREcpFunc(cpSeparateTiles2SeparateTiles) { return cpImage(in, out, readSeparateTilesIntoBuffer, writeBufferToSeparateTiles, imagelength, imagewidth, spp); }\n\n/*\n * Contig tiles -> contig tiles (tile dimension change).\n */\nDECLAREcpFunc(cpContigTiles2ContigStrips) { return cpImage(in, out, readContigTilesIntoBuffer, writeBufferToContigStrips, imagelength, imagewidth, spp); }\n\n/*\n * Contig tiles -> separate strips.\n */\nDECLAREcpFunc(cpContigTiles2SeparateStrips) { return cpImage(in, out, readContigTilesIntoBuffer, writeBufferToSeparateStrips, imagelength, imagewidth, spp); }\n\n/*\n * Separate tiles -> contig strips.\n */\nDECLAREcpFunc(cpSeparateTiles2ContigStrips) { return cpImage(in, out, readSeparateTilesIntoBuffer, writeBufferToContigStrips, imagelength, imagewidth, spp); }\n\n/*\n * Separate tiles -> separate strips.\n */\nDECLAREcpFunc(cpSeparateTiles2SeparateStrips) { return cpImage(in, out, readSeparateTilesIntoBuffer, writeBufferToSeparateStrips, imagelength, imagewidth, spp); }\n\n/*\n * Select the appropriate copy function to use.\n */\nstatic copyFunc pickCopyFunc(TIFF *in, TIFF *out, uint16_t bitspersample, uint16_t samplesperpixel)\n{\n    uint16_t shortv;\n    uint32_t w, l, tw, tl;\n    int    bychunk;\n\n    (void)TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);\n    if (shortv != config && bitspersample != 8 && samplesperpixel > 1) {\n        fprintf(stderr, \"%s: Can not handle different planar configuration w/ bits/sample != 8\\n\", TIFFFileName(in));\n        return (NULL);\n    }\n    TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);\n    TIFFGetField(in, TIFFTAG_IMAGELENGTH, &l);\n    if (TIFFIsTiled(out)) {\n        if (!TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw)) tw = w;\n        if (!TIFFGetField(in, TIFFTAG_TILELENGTH, &tl)) tl = l;\n        bychunk = (tw == tilewidth && tl == tilelength);\n    } else if (TIFFIsTiled(in)) {\n        TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);\n        TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);\n        bychunk = (tw == w && tl == rowsperstrip);\n    } else {\n        uint32_t irps = (uint32_t)-1L;\n        TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &irps);\n        bychunk = (rowsperstrip == irps);\n    }\n#define T                   1\n#define F                   0\n#define pack(a, b, c, d, e) ((long)(((a) << 11) | ((b) << 3) | ((c) << 2) | ((d) << 1) | (e)))\n    switch (pack(shortv, config, TIFFIsTiled(in), TIFFIsTiled(out), bychunk)) {\n        /* Strips -> Tiles */\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F, T, F):\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F, T, T): return cpContigStrips2ContigTiles;\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F, T, F):\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F, T, T): return cpContigStrips2SeparateTiles;\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F, T, F):\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F, T, T): return cpSeparateStrips2ContigTiles;\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F, T, F):\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F, T, T):\n        return cpSeparateStrips2SeparateTiles;\n        /* Tiles -> Tiles */\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T, T, F):\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T, T, T): return cpContigTiles2ContigTiles;\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T, T, F):\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T, T, T): return cpContigTiles2SeparateTiles;\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T, T, F):\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T, T, T): return cpSeparateTiles2ContigTiles;\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T, T, F):\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T, T, T):\n        return cpSeparateTiles2SeparateTiles;\n        /* Tiles -> Strips */\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T, F, F):\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T, F, T): return cpContigTiles2ContigStrips;\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T, F, F):\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T, F, T): return cpContigTiles2SeparateStrips;\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T, F, F):\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T, F, T): return cpSeparateTiles2ContigStrips;\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T, F, F):\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T, F, T):\n        return cpSeparateTiles2SeparateStrips;\n        /* Strips -> Strips */\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F, F, F):\n        if (convert_8_to_4)\n            return cpContig2ContigByRow_8_to_4;\n        else\n            return cpContig2ContigByRow;\n\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F, F, T):\n        if (convert_8_to_4)\n            return cpContig2ContigByRow_8_to_4;\n        else\n            return cpDecodedStrips;\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F, F, F):\n    case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F, F, T): return cpContig2SeparateByRow;\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F, F, F):\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F, F, T): return cpSeparate2ContigByRow;\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F, F, F):\n    case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F, F, T): return cpSeparate2SeparateByRow;\n    }\n#undef pack\n#undef F\n#undef T\n    fprintf(stderr, \"tiffcp: %s: Don't know how to copy/convert image.\\n\", TIFFFileName(in));\n    return (NULL);\n}\n"
  },
  {
    "path": "apps/vapor_check_udunits/CMakeLists.txt",
    "content": "add_executable (vapor_check_udunits vapor_check_udunits.cpp)\n\ntarget_link_libraries (vapor_check_udunits common vdc)\n\nOpenMPInstall (\n\tTARGETS vapor_check_udunits\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/vapor_check_udunits/vapor_check_udunits.cpp",
    "content": "#include <iostream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/CFuncs.h>\n#include <vapor/FileUtils.h>\n#include <vapor/UDUnitsClass.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"quiet\", 0, \"\", \"Don't print anything, just exit with status\"}, {\"help\", 0, \"\", \"Print this message and exit\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}};\n\nstring ProgName;\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { return 1; }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { return 1; }\n\n    if (argc != 1 || opt.help) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        return 1;\n    }\n\n    string path = UDUnits::GetDatabasePath();\n    if (!opt.quiet && !path.empty()) printf(\"VAPOR UDUnits database path: \\\"%s\\\"\\n\", path.c_str());\n\n    UDUnits ud;\n    int     rc = ud.Initialize();\n\n    if (rc < 0) return 1;\n\n    if (!opt.quiet) { printf(\"UDUnits passed\\n\"); }\n\n    return 0;\n}\n"
  },
  {
    "path": "apps/vaporgui/.gitignore",
    "content": "vaporgui_autogen\n"
  },
  {
    "path": "apps/vaporgui/AbstractWidgetGroup.cpp",
    "content": "#include \"AbstractWidgetGroup.h\"\n"
  },
  {
    "path": "apps/vaporgui/AbstractWidgetGroup.h",
    "content": "#pragma once\n\n#include <initializer_list>\n#include <vector>\n\n//! \\class AbstractWidgetGroup\n//! \\brief Provides an interface that standardizes widget grouping classes\n//! \\author Stas Jaroszynski\n\ntemplate<class This, class Widget> class AbstractWidgetGroup {\nprotected:\n    std::vector<Widget *> _children;\n\npublic:\n    typedef std::initializer_list<Widget *> List;\n\n    //! Adds a widget.\n    virtual This *Add(Widget *w)\n    {\n        _children.push_back(w);\n        return (This *)this;\n    }\n    //! Adds multiple widgets.\n    //! Has a different name for compiler reasons.\n    This *AddM(const List &list)\n    {\n        for (const auto &w : list) Add(w);\n        return (This *)this;\n    }\n};\n\n//! \\class WidgetGroupWrapper\n//! \\brief Automates the creation of widget groups that wrap other widget groups\n//! \\author Stas Jaroszynski\n\ntemplate<class This, class Widget, class That> class WidgetGroupWrapper : public AbstractWidgetGroup<This, Widget> {\nprotected:\n    That *_group;\n\npublic:\n    WidgetGroupWrapper(That *group) : _group(group) {}\n\n    virtual This *Add(Widget *w) override\n    {\n        _group->Add(w);\n        return AbstractWidgetGroup<This, Widget>::Add(w);\n    }\n};\n"
  },
  {
    "path": "apps/vaporgui/AnimationController.cpp",
    "content": "#include \"AnimationController.h\"\n#include <vapor/ControlExecutive.h>\n#include <vapor/AnimationParams.h>\n#include <vapor/GUIStateParams.h>\n#include <vapor/NavigationUtils.h>\n\n#include <QAction>\n\nusing namespace VAPoR;\n\nAnimationController::AnimationController(VAPoR::ControlExec *ce) : _controlExec(ce), _myTimer(new QTimer(this)) {}\n\nusing glm::vec3;\n\nvoid AnimationController::setCurrentTimestep(size_t ts) const {\n    NavigationUtils::SetTimestep(_controlExec, ts);\n}\n\n\n// Insert values from params into tab panel\n//\nvoid AnimationController::Update()\n{\n    DataStatus *     dataStatus = _controlExec->GetDataStatus();\n    AnimationParams *aParams = (AnimationParams *)GetActiveParams();\n\n    size_t numTS = dataStatus->GetTimeCoordinates().size();\n    if (numTS == 0) {\n        // no data\n        return;\n    }\n\n    size_t startFrame = aParams->GetStartTimestep();\n    size_t endFrame = aParams->GetEndTimestep();\n    size_t currentFrame = aParams->GetCurrentTimestep();\n\n    if (startFrame >= numTS) {\n        startFrame = numTS - 1;\n        aParams->SetStartTimestep(startFrame);\n    }\n\n    if (endFrame >= numTS) {\n        endFrame = numTS - 1;\n        aParams->SetEndTimestep(endFrame);\n    }\n\n    if (startFrame > endFrame) {\n        startFrame = endFrame;\n        aParams->SetStartTimestep(startFrame);\n    }\n\n    if (currentFrame < startFrame) {\n        currentFrame = startFrame;\n        setCurrentTimestep(currentFrame);\n    }\n\n    if (currentFrame > endFrame) {\n        currentFrame = endFrame;\n        setCurrentTimestep(currentFrame);\n    }\n}\n\n\nvoid AnimationController::AnimationPause()\n{\n    _animationOn = false;\n    setPlay(0);\n}\n\nvoid AnimationController::AnimationPlayReverse()\n{\n    _animationOn = true;\n    setPlay(-1);\n}\n\nvoid AnimationController::AnimationPlayForward()\n{\n    _capturingImageSequence = qobject_cast<QAction*>(sender()) ? false : true;\n    _animationOn = true;\n    setPlay(1);\n}\n\nvoid AnimationController::AnimationStepForward()\n{\n    AnimationParams *aParams = (AnimationParams *)GetActiveParams();\n\n    int currentFrame = aParams->GetCurrentTimestep();\n    int endFrame = aParams->GetEndTimestep();\n\n    currentFrame++;\n\n    if (currentFrame > endFrame) return;\n\n    setCurrentTimestep(currentFrame);\n}\n\nvoid AnimationController::AnimationStepReverse()\n{\n    AnimationParams *aParams = (AnimationParams *)GetActiveParams();\n\n    int currentFrame = aParams->GetCurrentTimestep();\n    int startFrame = aParams->GetStartTimestep();\n\n    currentFrame--;\n\n    if (currentFrame < startFrame) return;\n\n    setCurrentTimestep(currentFrame);\n}\n\nvoid AnimationController::SetTimeStep(int ts) { setCurrentTimestep((size_t)ts); }\n\n// Following are set by gui, result in save history state.\n// Whenever play is pressed, it wakes up the animation controller.\n\nvoid AnimationController::setPlay(int direction)\n{\n    _direction = direction;\n\n    if (_direction) {\n        // If on is true send notification (signal) that we are in\n        // animation mode. Set a timer to go off at the appropriate\n        // interval based on the frame rate. The timer slot will advance\n        // the frame, etc.\n        //\n        emit AnimationOnOffSignal(true);\n        emit AnimationDrawSignal();\n\n        AnimationParams *aParams = (AnimationParams *)GetActiveParams();\n        int frameRate = aParams->GetMaxFrameRate();\n        int msec = (int)(1.0 / (float)frameRate * 1000.0);\n        connect(_myTimer, SIGNAL(timeout()), this, SLOT(playNextFrame()));\n        _myTimer->start(msec);\n    } else {\n        // Done animating. Disable timer and send notification\n        //\n        disconnect(_myTimer, 0, 0, 0);\n        GUIStateParams* gsp = NavigationUtils::GetGUIStateParams(_controlExec);\n    \n        string windowName = gsp->GetActiveVizName();\n        _controlExec->EnableAnimationCapture(windowName, false);\n        _controlExec->GetParamsMgr()->ManuallyAddCurrentStateToUndoStack(\"End animation playback\");\n\n        _capturingImageSequence = false;\n        emit AnimationOnOffSignal(false);\n    }\n}\n\n// TODO Refactor\nvoid AnimationController::playNextFrame()\n{\n    VAssert(_direction == -1 || _direction == 1);\n\n    // Draw the frame, and then advance the frame count\n    // ^?\n\n    AnimationParams *aParams = (AnimationParams *)GetActiveParams();\n\n    int startFrame, endFrame;\n    if (_capturingImageSequence) {\n        startFrame = aParams->GetValueLong(AnimationParams::CaptureStartTag, aParams->GetStartTimestep());\n        endFrame = aParams->GetValueLong(AnimationParams::CaptureEndTag, aParams->GetEndTimestep());\n    }\n    else {\n        startFrame = aParams->GetStartTimestep();\n        endFrame = aParams->GetEndTimestep();\n    }\n\n    int  currentFrame = aParams->GetCurrentTimestep();\n\n    currentFrame += (int)(_direction);\n\n    if ((currentFrame < startFrame || currentFrame > endFrame)) {\n        AnimationPause();\n        return;\n    }\n\n    if (currentFrame < startFrame) currentFrame = endFrame;\n    if (currentFrame > endFrame) currentFrame = startFrame;\n\n    bool undoEnabled = _controlExec->GetParamsMgr()->GetSaveStateUndoEnabled();\n    _controlExec->GetParamsMgr()->SetSaveStateUndoEnabled(false);\n    setCurrentTimestep(currentFrame);\n    _controlExec->GetParamsMgr()->SetSaveStateUndoEnabled(undoEnabled);\n    emit AnimationDrawSignal();\n}\n\nAnimationParams *AnimationController::GetActiveParams() const { return NavigationUtils::GetAnimationParams(_controlExec); }\n\nvoid AnimationController::_updateTab() { Update(); }\n"
  },
  {
    "path": "apps/vaporgui/AnimationController.h",
    "content": "#pragma once\n\n#include <QTimer>\n#include <glm/fwd.hpp>\n\nclass AnimationParams;\nnamespace VAPoR {\nclass ControlExec;\n}\n\n//! \\class AnimationController\n//! \\brief This class is just migrated legacy code to de-spaghetti other legacy code.\n//! (It is not written by me)\n\nclass AnimationController : public QObject {\n    Q_OBJECT\n    VAPoR::ControlExec *_controlExec;\n    QTimer *            _myTimer;\n    int                 _direction;\n    bool                _animationOn = false;\n    bool                _capturingImageSequence;\n\npublic:\n    AnimationController(VAPoR::ControlExec *ce);\n    void Update();\n\npublic slots:\n    void AnimationPause();\n    void AnimationPlayReverse();\n    void AnimationPlayForward();\n    void AnimationStepForward();\n    void AnimationStepReverse();\n    void SetTimeStep(int ts);\n\nsignals:\n\n    // Emitted when animation is turned on (true) or off (false)\n    //\n    void AnimationOnOffSignal(bool onOff);\n\n    // Emitted when the client should draw a frame during animation. Only\n    // Emitted if AnimationOnOffChanged() was most recently called with\n    // onOff == true;\n    //\n    void AnimationDrawSignal();\n\nprivate:\n    void             setCurrentTimestep(size_t ts) const;\n    void             setPlay(int direction);\n    AnimationParams *GetActiveParams() const;\n    void             _updateTab();\n\nprivate slots:\n    void playNextFrame();\n};\n"
  },
  {
    "path": "apps/vaporgui/AnnotationEventRouter.cpp",
    "content": "#include \"AnnotationEventRouter.h\"\n#include <vapor/AnnotationParams.h>\n#include <vapor/ControlExecutive.h>\n#include \"VSection.h\"\n#include \"PWidgets.h\"\n#include \"PEnumDropdownHLI.h\"\n#include \"PSliderEditHLI.h\"\n#include \"VPushButton.h\"\n#include \"PCopyRegionAnnotationWidget.h\"\n#include \"PAxisAnnotationWidget.h\"\n\nusing namespace VAPoR;\n\nAnnotationEventRouter::AnnotationEventRouter(ControlExec *ce) : _controlExec(ce)\n{\n    setLayout(new QVBoxLayout);\n\n    PGroup *timeAnnotationGroup = new PGroup({new PSection(\n        \"Time Annotation\", {new PEnumDropdown(AnnotationParams::_timeTypeTag, {\"No annotation\", \"Time step number\", \"User time\", \"Formatted date/time\"}, {0, 1, 2, 3}, \"Annotation type\"),\n                            (new PIntegerSliderEdit(VAPoR::AnnotationParams::_timeSizeTag, \"Font Size\"))->SetRange(24, 100)->EnableDynamicUpdate(),\n                            (new PDoubleSliderEdit(AnnotationParams::_timeLLXTag, \"X Position\"))->EnableDynamicUpdate(),\n                            (new PDoubleSliderEdit(AnnotationParams::_timeLLYTag, \"Y Position\"))->EnableDynamicUpdate(), \n                            new PColorSelector(AnnotationParams::_timeColorTag, \"Text Color\")})\n    });\n    layout()->addWidget(timeAnnotationGroup);\n    _groups.push_back(timeAnnotationGroup);\n\n    VSection *axisAnnotationTab = new VSection(\"Axis Annotations\");\n    PGroup *  axisAnnotationGroup1 = new PGroup(\n        {new PCheckbox(AxisAnnotation::_annotationEnabledTag, \"Axis Annotations Enabled\"), \n         new PCheckbox(AxisAnnotation::_latLonAxesTag, \"Annotate with lat/lon\"), \n         new PAxisAnnotationWidget(ce)\n    });\n    axisAnnotationTab->layout()->addWidget(axisAnnotationGroup1);\n    _axisGroups.push_back(axisAnnotationGroup1);\n\n    PGroup *axisAnnotationGroup2 = new PGroup({\n        new PColorSelector(AxisAnnotation::_colorTag, \"Axis Text Color\"),\n        new PColorSelector(AxisAnnotation::_backgroundColorTag, \"Text Background Color\"),\n        (new PIntegerSliderEditHLI<AxisAnnotation>(\"Font Size\", &AxisAnnotation::GetAxisFontSize, &AxisAnnotation::SetAxisFontSize))->SetRange(2, 48)->EnableDynamicUpdate(),\n        (new PIntegerSliderEdit(AxisAnnotation::_digitsTag, \"Digits\"))->SetRange(0, 8)->EnableDynamicUpdate(),\n        //(new PIntegerSliderEdit(AxisAnnotation::_ticWidthTag, \"Tic Width\"))->SetRange(0, 10)->EnableDynamicUpdate(), // Broken, see 2711\n        new PEnumDropdownHLI<AxisAnnotation>(\"X Tickmark Orientation\", {\"Y axis\", \"Z axis\"}, {1, 2}, &AxisAnnotation::GetXTicDir, &AxisAnnotation::SetXTicDir),\n        new PEnumDropdownHLI<AxisAnnotation>(\"Y Tickmark Orientation\", {\"X axis\", \"Z axis\"}, {0, 2}, &AxisAnnotation::GetYTicDir, &AxisAnnotation::SetYTicDir),\n        new PEnumDropdownHLI<AxisAnnotation>(\"Z Tickmark Orientation\", {\"X axis\", \"Y axis\"}, {0, 1}, &AxisAnnotation::GetZTicDir, &AxisAnnotation::SetZTicDir),\n    });\n    axisAnnotationTab->layout()->addWidget(axisAnnotationGroup2);\n    _axisGroups.push_back(axisAnnotationGroup2);\n\n    layout()->addWidget(axisAnnotationTab);\n\n    PGroup* copyRegionGroup = new PGroup({\n        new PCopyRegionAnnotationWidget(ce)\n    });\n    layout()->addWidget(copyRegionGroup);\n    _groups.push_back(copyRegionGroup);\n\n    PGroup *axisArrowGroup = new PGroup({new PSection(\"Orientation Arrows\", {(new PCheckbox(AnnotationParams::AxisArrowEnabledTag, \"Show arrows (XYZ->RGB)\")),\n                                                                             (new PDoubleSliderEdit(AnnotationParams::AxisArrowSizeTag, \"Size\"))->SetRange(0.f, 1.f)->EnableDynamicUpdate(),\n                                                                             (new PDoubleSliderEdit(AnnotationParams::AxisArrowXPosTag, \"X Position\"))->SetRange(0.f, 1.f)->EnableDynamicUpdate(),\n                                                                             (new PDoubleSliderEdit(AnnotationParams::AxisArrowYPosTag, \"Y Position\"))->SetRange(0.f, 1.f)->EnableDynamicUpdate()})});\n    layout()->addWidget(axisArrowGroup);\n    _groups.push_back(axisArrowGroup);\n\n    PGroup *ThreeDGeometryGroup = new PGroup(\n        {new PSection(\"3D Geometry\", {new PCheckbox(AnnotationParams::_domainFrameTag, \"Display Domain Bounds\"), \n                                      new PColorSelector(AnnotationParams::_domainColorTag, \"Domain Frame Color\"),\n                                      new PColorSelector(AnnotationParams::_backgroundColorTag, \"Background Color\"),\n                                         // new PColorSelector(AnnotationParams::_regionColorTag, \"Region Frame Color\")  Broken.  See #1742\n                                     })});\n    layout()->addWidget(ThreeDGeometryGroup);\n    _groups.push_back(ThreeDGeometryGroup);\n}\n\nvoid AnnotationEventRouter::Update()\n{\n    AnnotationParams *aParams = (AnnotationParams *)_controlExec->GetParamsMgr()->GetParams(AnnotationParams::GetClassType());\n    AxisAnnotation *  aa = aParams->GetAxisAnnotation();\n\n    for (PGroup *group : _groups) group->Update(aParams);\n    for (PGroup *group : _axisGroups) group->Update(aa, _controlExec->GetParamsMgr());\n}\n"
  },
  {
    "path": "apps/vaporgui/AnnotationEventRouter.h",
    "content": "#pragma once\n\n#include \"VaporFwd.h\"\n#include <QWidget>\n#include \"Updatable.h\"\n\nclass PGroup;\n\nclass AnnotationEventRouter : public QWidget, public Updatable {\n    Q_OBJECT\n\n    ControlExec *_controlExec;\n    std::vector<PGroup *> _groups;\n    std::vector<PGroup *> _axisGroups;\n\npublic:\n    AnnotationEventRouter(VAPoR::ControlExec *ce);\n    void Update() override;\n};\n"
  },
  {
    "path": "apps/vaporgui/AppSettingsMenu.cpp",
    "content": "#include <vapor/OpenMPSupport.h>\n#include <QVBoxLayout>\n#include <AppSettingsMenu.h>\n#include <vapor/SettingsParams.h>\n#include \"PWidgets.h\"\n#include \"PGroup.h\"\n#include \"PFileSelectorHLI.h\"\n#include \"PIntegerInputHLI.h\"\n#include \"PCheckboxHLI.h\"\n#include \"VPushButton.h\"\n#include \"ErrorReporter.h\"\n#include \"CheckForUpdate.h\"\n#include <QLabel>\n#ifndef _WIN32\n#include <unistd.h>\n#endif\n#include \"vapor/STLUtils.h\"\n\nclass PUpdateChecker : public PWidget {\n    VGroup *     _group;\n    QLabel *     _label;\n    VPushButton *_checkButton;\n    VPushButton *_getButton;\n    UpdateInfo   _updateInfo;\n\n    void updateGUI() const override {}\n    void openURL()\n    {\n        if (!_updateInfo.url.empty()) _updateInfo.OpenURL();\n    }\n    void checkForUpdate()\n    {\n        _label->setText(\"Checking...\");\n        _checkButton->setHidden(true);\n        _label->setVisible(true);\n\n        CheckForUpdate([=](bool updateAvailable, UpdateInfo info) {\n            if (updateAvailable) {\n                DisplayUpdateAvailable(info);\n            } else {\n                if (info.error)\n                    DisplayError();\n                else\n                    DisplayUpToDate();\n            }\n        });\n    }\n\npublic:\n    PUpdateChecker() : PWidget(\"\", _group = new VGroup())\n    {\n        _checkButton = new VPushButton(\"Check for update\");\n        _group->Add(_checkButton);\n\n        _label = new QLabel;\n        _label->setHidden(true);\n        _group->Add(_label);\n\n        _getButton = new VPushButton(\"Get Latest Version\");\n        _getButton->setHidden(true);\n        _group->Add(_getButton);\n\n        QObject::connect(_checkButton, &VPushButton::ButtonClicked, this, &PUpdateChecker::checkForUpdate);\n        QObject::connect(_getButton, &VPushButton::ButtonClicked, this, &PUpdateChecker::openURL);\n    }\n    void DisplayUpToDate()\n    {\n        _label->setText(\"Vapor is up to date\");\n\n        _checkButton->setHidden(true);\n        _label->setVisible(true);\n        _getButton->setHidden(true);\n    }\n    void DisplayUpdateAvailable(UpdateInfo info)\n    {\n        _updateInfo = info;\n        _label->setText(QString::fromStdString(\"New version available: \" + info.version));\n\n        _checkButton->setHidden(true);\n        _label->setVisible(true);\n        _getButton->setVisible(true);\n    }\n    void DisplayError()\n    {\n        _label->setText(\"Unable to check for new version.\");\n\n        _checkButton->setHidden(true);\n        _label->setVisible(true);\n        _getButton->setHidden(true);\n    }\n};\n\nAppSettingsMenu::AppSettingsMenu(QWidget *parent) : QDialog(parent), ParamsUpdatable(), _params(nullptr)\n{\n    int nthreads = 1;\n#pragma omp parallel\n    {\n        if (omp_get_thread_num() == 0) nthreads = omp_get_num_threads();\n    }\n\n    PSection *startupSettings;\n    _settings = new PGroup({\n        new PSection(\"Automatic Session Recovery\",\n                     {\n                         new PCheckboxHLI<SettingsParams>(\"Automatically save session\", &SettingsParams::GetSessionAutoSaveEnabled, &SettingsParams::SetSessionAutoSaveEnabled),\n                         (new PIntegerInputHLI<SettingsParams>(\"Changes per auto-save\", &SettingsParams::GetChangesPerAutoSave, &SettingsParams::SetChangesPerAutoSave))\n                             ->EnableBasedOnParam(SettingsParams::_sessionAutoSaveEnabledTag),\n                         (new PFileSaveSelectorHLI<SettingsParams>(\"Auto-save file\", &SettingsParams::GetAutoSaveSessionFile, &SettingsParams::SetAutoSaveSessionFile))\n                             ->EnableBasedOnParam(SettingsParams::_sessionAutoSaveEnabledTag),\n                     }),\n\n        startupSettings = new PSection(\"Vapor's Startup Settings\",\n                     {\n                         new PLabel(\"*Vapor must be restarted for these settings to take effect\"),\n                         new PCheckboxHLI<SettingsParams>(\"Automatically stretch domain\", &SettingsParams::GetAutoStretchEnabled, &SettingsParams::SetAutoStretchEnabled),\n                         new PCheckbox(SettingsParams::UseAllCoresTag, \"Use all (\" + std::to_string(nthreads) + \") available cores for multithreaded tasks\"),\n                         new PSubGroup({(new PIntegerInputHLI<SettingsParams>(\"Limit threads to\", &SettingsParams::GetNumThreads, &SettingsParams::SetNumThreads))\n                                            ->SetRange(1, 1024)\n                                            ->EnableBasedOnParam(SettingsParams::UseAllCoresTag, false)}),\n                         new PIntegerInputHLI<SettingsParams>(\"Cache size (Megabytes)\", &SettingsParams::GetCacheMB, &SettingsParams::SetCacheMB),\n                         new PCheckboxHLI<SettingsParams>(\"Check for and show notices on startup\", &SettingsParams::GetAutoCheckForNotices, &SettingsParams::SetAutoCheckForNotices),\n                     }),\n        new PSection(\"Default Search Paths\", {new PDirectorySelectorHLI<SettingsParams>(\"Session file path\", &SettingsParams::GetSessionDir, &SettingsParams::SetSessionDir),\n                                              new PDirectorySelectorHLI<SettingsParams>(\"Data set path\", &SettingsParams::GetMetadataDir, &SettingsParams::SetMetadataDir)}),\n\n        // clang-format off\n        new PSection(\"Updates\", {\n            new PCheckboxHLI<SettingsParams>(\"Automatically check for updates\", &SettingsParams::GetAutoCheckForUpdates, &SettingsParams::SetAutoCheckForUpdates),\n            new PUpdateChecker,\n        }),\n        // clang-format on\n\n        new PButton(\"Restore defaults\", [](VAPoR::ParamsBase *p) { dynamic_cast<SettingsParams *>(p)->Init(); }),\n    });\n\n    #ifndef _WIN32\n        char hostname[1024];\n        hostname[1023] = '\\0';\n        gethostname(hostname, 1023);\n        if (STLUtils::BeginsWith(hostname, \"casper\"))\n            startupSettings->Add(new PCheckboxHLI<SettingsParams>(\"Check for VGL on Casper\", &SettingsParams::GetCasperCheckForVGL, &SettingsParams::SetCasperCheckForVGL));\n    #endif\n\n    setLayout(new QVBoxLayout);\n    layout()->addWidget(_settings);\n\n    VPushButton *close = new VPushButton(\"Close\");\n    connect(close, &VPushButton::ButtonClicked, this, &AppSettingsMenu::accept);\n    layout()->addWidget(close);\n\n    setFocusPolicy(Qt::ClickFocus);\n}\n\n// Handle the pressing of the escape key\n// Since settings are applied when changed in the gui,\n// we still want to save the settings file, even if esc is pressed\nvoid AppSettingsMenu::reject() { accept(); }\n\nvoid AppSettingsMenu::accept()\n{\n    VAssert(_params != nullptr);\n    int rc = _params->SaveSettings();\n    if (rc < 0) {\n        std::string settingsPath = _params->GetSettingsPath();\n        MSG_ERR(\"Unable to write to settings file \" + settingsPath);\n    }\n    QDialog::accept();\n}\n\nvoid AppSettingsMenu::Update(VAPoR::ParamsBase *p, VAPoR::ParamsMgr *paramsMgr, VAPoR::DataMgr *dataMgr)\n{\n    _params = dynamic_cast<SettingsParams *>(p);\n    VAssert(_params != nullptr);\n\n    _settings->Update(_params);\n}\n"
  },
  {
    "path": "apps/vaporgui/AppSettingsMenu.h",
    "content": "#pragma once\n\n#include <QDialog>\n#include \"PWidget.h\"\n#include \"ParamsUpdatable.h\"\n#include \"PFileSelectorHLI.h\"\n#include \"VFileSelector.h\"\n\nclass QWidget;\nclass SettingsParams;\nclass PGroup;\nclass PSection;\nclass SettingsParams;\n\n//! \\class Preferences Menu\n//! \\ingroup Public_GUI\n//! \\brief Menu for global application preferences\n//! \\author Scott Pearse\n\nclass AppSettingsMenu : public QDialog, public ParamsUpdatable {\n    Q_OBJECT\n\npublic:\n    AppSettingsMenu(QWidget *parent);\n    virtual void Update(VAPoR::ParamsBase *p, VAPoR::ParamsMgr *paramsMgr = nullptr, VAPoR::DataMgr *dataMgr = nullptr) override;\n\nprivate:\n    void accept() override;\n    void reject() override;\n\n    PGroup *        _settings;\n    SettingsParams *_params;\n};\n"
  },
  {
    "path": "apps/vaporgui/AppSettingsParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2015\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tAppSettingsparams.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tNovember 2015\n//\n//\tDescription:\tImplements the AppSettingsParams class.\n//\t\tThis class supports application settings\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n\n#include \"AppSettingsParams.h\"\n\nusing namespace VAPoR;\n\nconst string AppSettingsParams::m_classType = \"ApplicationSettings\";\n\nconst string AppSettingsParams::_shortName = \"AppSettings\";\nconst string AppSettingsParams::_currentJpegQualityTag = \"CurrentJpegQuality\";\nconst string AppSettingsParams::_currentAutosaveEnabledTag = \"CurrentAutosaveEnabled\";\nconst string AppSettingsParams::_currentAutosaveIntervalTag = \"CurrentAutosaveInterval\";\nconst string AppSettingsParams::_currentShowDataWarningTag = \"CurrentWarnMissingData\";\nconst string AppSettingsParams::_currentUseLessAccurateTag = \"CurrentUseLessAccurateData\";\nconst string AppSettingsParams::_currentTrackMouseTag = \"CurrentTrackMouse\";\nconst string AppSettingsParams::_currentShowCitationTag = \"CurrentShowCitation\";\nconst string AppSettingsParams::_currentLogFileNameTag = \"CurrentLogfileName\";\nconst string AppSettingsParams::_currentAutosaveFileNameTag = \"CurrentAutosaveName\";\nconst string AppSettingsParams::_currentMessagesSilencedTag = \"CurrentMessageSilence\";\nconst string AppSettingsParams::_currentLogfileEnabledTag = \"CurrentLogfileEnabled\";\nconst string AppSettingsParams::_logFileNameTag = \"LogfileName\";\nconst string AppSettingsParams::_logfileEnabledTag = \"LogfileEnabled\";\nconst string AppSettingsParams::_autosaveFileNameTag = \"AutosaveName\";\nconst string AppSettingsParams::_jpegQualityTag = \"JpegQuality\";\nconst string AppSettingsParams::_autosaveEnabledTag = \"AutosaveEnabled\";\nconst string AppSettingsParams::_autosaveIntervalTag = \"AutosaveInterval\";\nconst string AppSettingsParams::_showDataWarningTag = \"WarnMissingData\";\nconst string AppSettingsParams::_useLessAccurateTag = \"UseLessAccurateData\";\nconst string AppSettingsParams::_trackMouseTag = \"TrackMouse\";\nconst string AppSettingsParams::_showCitationTag = \"ShowCitation\";\nconst string AppSettingsParams::_messagesSilencedTag = \"MessageSilence\";\n\nstatic ParamsRegistrar<AppSettingsParams> registrar(AppSettingsParams::GetClassType());\n\n// Reset AppSettings settings to initial state\nvoid AppSettingsParams::_init()\n{\n    SetJpegQuality(99);\n    SetAutosaveInterval(10);\n    SetAutosaveEnabled(true);\n    SetShowWarning(false);\n    SetUseLessAccurate(true);\n    SetTrackMouse(true);\n    SetShowCitation(true);\n    SetLogFileName(string(\"/tmp/logfile.txt\"));\n    SetAutosaveName(string(\"/tmp/autosave.vs3\"));\n    SetMessageSilence(false);\n    SetLogfileEnabled(false);\n}\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nAppSettingsParams::AppSettingsParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, m_classType) { _init(); }\n\nAppSettingsParams::AppSettingsParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    // If node isn't tagged correctly we correct the tag and reinitialize\n    // from scratch;\n    //\n    if (node->GetTag() != AppSettingsParams::GetClassType()) {\n        node->SetTag(AppSettingsParams::GetClassType());\n        _init();\n    }\n}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nAppSettingsParams::~AppSettingsParams() { MyBase::SetDiagMsg(\"AppSettingsParams::~AppSettingsParams() this=%p\", this); }\n\nvoid AppSettingsParams::restoreDefaults() { _init(); }\n\n#ifdef VAPOR3_0_0_ALPHA\nvoid AppSettingsParams::saveCurrentSettings()\n{\n    // This copying should not be saved as a command;\n    // It cannot be undone.  Copy all the current settings to the permanent settings.\n    SetJpegQuality(GetCurrentJpegQuality());\n    SetAutosaveInterval(GetCurrentAutosaveInterval());\n    SetAutosaveEnabled(GetCurrentAutosaveEnabled());\n    SetShowWarning(GetCurrentShowWarning());\n    SetUseLessAccurate(GetCurrentUseLessAccurate());\n    SetTrackMouse(GetCurrentTrackMouse());\n    SetShowCitation(GetCurrentShowCitation());\n    SetMessageSilence(GetCurrentMessageSilence());\n    SetLogFileName(GetCurrentLogFileName());\n    SetAutosaveName(GetCurrentAutosaveName());\n    SetLogfileEnabled(GetCurrentLogfileEnabled());\n}\n\nvoid AppSettingsParams::copySavedSettings()\n{\n    SetCurrentJpegQuality(GetJpegQuality());\n    SetCurrentAutosaveInterval(GetAutosaveInterval());\n    SetCurrentAutosaveEnabled(GetAutosaveEnabled());\n    SetCurrentShowWarning(GetShowWarning());\n    SetCurrentUseLessAccurate(GetUseLessAccurate());\n    SetCurrentTrackMouse(GetTrackMouse());\n    SetCurrentShowCitation(GetShowCitation());\n    SetCurrentMessageSilence(GetMessageSilence());\n    SetCurrentLogfileEnabled(GetLogfileEnabled());\n}\n\n#endif\n\nvoid AppSettingsParams::SetJpegQuality(int val)\n{\n    if (val < 1 || val > 99) val = 99;\n    SetValueLong(_jpegQualityTag, \"Set jpeg quality\", val);\n}\n\nlong AppSettingsParams::GetJpegQuality() const\n{\n    int defaultv = 99;\n    int val = GetValueLong(_jpegQualityTag, defaultv);\n    if (val < 1 || val > 99) val = defaultv;\n    return (val);\n}\n\nvoid AppSettingsParams::SetAutosaveInterval(int val)\n{\n    if (val < 1) val = 1;\n    SetValueLong(_autosaveIntervalTag, \"Set autosave interval\", val);\n}\n\nlong AppSettingsParams::GetAutosaveInterval() const\n{\n    int defaultv = 5;\n    int val = GetValueLong(_autosaveIntervalTag, defaultv);\n    if (val < 1) val = defaultv;\n    return (val);\n}\n\nvoid AppSettingsParams::SetCurrentJpegQuality(int val)\n{\n    if (val < 1 || val > 99) val = 99;\n    SetValueLong(_currentJpegQualityTag, \"Set current jpeg quality\", val);\n}\n\nlong AppSettingsParams::GetCurrentJpegQuality() const\n{\n    int defaultv = 99;\n    int val = GetValueLong(_currentJpegQualityTag, defaultv);\n    if (val < 1 || val > 99) val = defaultv;\n    return (val);\n}\n\nvoid AppSettingsParams::SetCurrentAutosaveInterval(int val)\n{\n    if (val < 1) val = 1;\n    SetValueLong(_currentAutosaveIntervalTag, \"Set current autosave interval\", val);\n}\n\nlong AppSettingsParams::GetCurrentAutosaveInterval() const\n{\n    int defaultv = 5;\n    int val = GetValueLong(_currentAutosaveIntervalTag, defaultv);\n    if (val < 1) val = defaultv;\n    return (val);\n}\n"
  },
  {
    "path": "apps/vaporgui/AppSettingsParams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2015\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tAppSettingsParams.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune 2015\n//\n//\tDescription:\tDefines the AppSettingsParams class.\n//\t\tThis class supports parameters associted with the\n//\t\tAppSettings panel, describing the visual features in the visualizer\n//\n#ifndef APPSETTINGSPARAMS_H\n#define APPSETTINGSPARAMS_H\n\n#include <vector>\n#include <vapor/ParamsBase.h>\n\n//! \\class AppSettingsParams\n//! \\ingroup Public_Params\n//! \\brief A class for describing visual features displayed in the visualizer.\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    June 2015\n\n//! The AppSettingsParams class controls various features displayed in the visualizers\n//! There is a global AppSettingsParams, that\n//! is shared by all windows whose AppSettings is set to \"global\".  There is also\n//! a local AppSettingsParams for each window, that users can select whenever there are multiple windows.\n//! When local settings are used, they only affect one currently active visualizer.\n//! The AppSettingsParams class also has several methods that are useful in setting up data requests from the DataMgr.\n//!\nclass AppSettingsParams : public VAPoR::ParamsBase {\npublic:\n    AppSettingsParams(VAPoR::ParamsBase::StateSave *ssave);\n\n    AppSettingsParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node);\n\n    virtual ~AppSettingsParams();\n\n    //! Pure virtual method on Params. Provide a short name suitable for use in the GUI\n    //! \\retval string name\n    const std::string getShortName() { return _shortName; }\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Copy the current settings to the saved settings\n    //! Needed whenever user wants to make current settings default\n    //! All of the settings in this Params have an additional \"current\" state\n    //! The current state is what is shown in the tab panel\n    void saveCurrentSettings();\n\n    //! Copy the saved settings to the current settings.\n    //! Needed whenever settings are loaded.\n    void copySavedSettings();\n#endif\n\n    //! Restore default settings\n    //! performed on user request.\n    void restoreDefaults();\n\n    //! Specify jpeg quality level\n    //! \\param[in] val quality level (1-99)\n    void SetJpegQuality(int val);\n\n    //! Obtain jpeg quality\n    //! \\return jpeg quality level\n    long GetJpegQuality() const;\n\n    //! Specify autosave interval\n    //! \\param[in] val autosave interval >= 1\n    void SetAutosaveInterval(int val);\n\n    //! Obtain autosave interval\n    //! \\return interval between autosaves\n    long GetAutosaveInterval() const;\n\n    bool GetAutosaveEnabled() { return (0 != GetValueLong(_autosaveEnabledTag, (long)true)); }\n\n    void SetAutosaveEnabled(bool onOff) { SetValueLong(_autosaveEnabledTag, \"toggle autosave enabled\", (long)onOff); }\n\n    bool GetShowWarning() const { return (0 != GetValueLong(_showDataWarningTag, (long)true)); }\n    void SetShowWarning(bool onOff) { SetValueLong(_showDataWarningTag, \"toggle warn data missing\", (long)onOff); }\n\n    bool GetUseLessAccurate() const { return (0 != GetValueLong(_useLessAccurateTag, (long)false)); }\n    void SetUseLessAccurate(bool onOff) { SetValueLong(_useLessAccurateTag, \"toggle use lower accuracy\", (long)onOff); }\n\n    bool GetTrackMouse() const { return (0 != GetValueLong(_trackMouseTag, (long)true)); }\n\n    void SetTrackMouse(bool onOff) { SetValueLong(_trackMouseTag, \"toggle track mouse\", (long)onOff); }\n\n    bool GetShowCitation() const { return (0 != GetValueLong(_showCitationTag, (long)true)); }\n\n    void SetShowCitation(bool onOff) { SetValueLong(_showCitationTag, \"toggle show citation info\", (long)onOff); }\n\n    void SetMessageSilence(bool val) { SetValueLong(_messagesSilencedTag, \"(Un)Silence messages\", (long)val); }\n\n    bool   GetMessageSilence() const { return (0 != GetValueLong(_messagesSilencedTag, (long)false)); }\n    string GetAutosaveName() { return GetValueString(_autosaveFileNameTag, string(\"/tmp/vapor_autosave.vs3\")); }\n\n    void SetAutosaveName(string name) { SetValueString(_autosaveFileNameTag, \"set autosave file\", name); }\n\n    string GetLogFileName() const { return GetValueString(_logFileNameTag, string(\"/tmp/vaporLog.txt\")); }\n\n    void SetLogFileName(string name) { SetValueString(_logFileNameTag, \"set log file\", name); }\n\n    bool GetLogfileEnabled() const { return (0 != GetValueLong(_logfileEnabledTag, (long)false)); }\n\n    void SetLogfileEnabled(bool val) { SetValueLong(_logfileEnabledTag, \"toggle logfile enabled\", (long)val); }\n\n    //! Specify current jpeg quality level\n    //! \\param[in] val quality level (1-99)\n    void SetCurrentJpegQuality(int val);\n\n    long GetCurrentJpegQuality() const;\n\n    //! Specify current autosave interval\n    //! \\param[in] val autosave interval >= 1\n    void SetCurrentAutosaveInterval(int val);\n\n    //! Obtain Current autosave interval\n    //! \\return interval between autosaves\n    long GetCurrentAutosaveInterval() const;\n\n    bool GetCurrentAutosaveEnabled() const { return (0 != GetValueLong(_currentAutosaveEnabledTag, (long)true)); }\n\n    void SetCurrentAutosaveEnabled(bool onOff) { SetValueLong(_currentAutosaveEnabledTag, \"Toggle current autosave enabled\", (long)onOff); }\n\n    bool GetCurrentShowWarning() const { return (0 != GetValueLong(_currentShowDataWarningTag, (long)true)); }\n\n    void SetCurrentShowWarning(bool onOff) { SetValueLong(_currentShowDataWarningTag, \"toggle current show warning\", (long)onOff); }\n\n    bool GetCurrentUseLessAccurate() const { return (0 != GetValueLong(_currentUseLessAccurateTag, (long)false)); }\n\n    void SetCurrentUseLessAccurate(bool onOff) { SetValueLong(_currentUseLessAccurateTag, \"toggle current use less accuracy\", (long)onOff); }\n\n    bool GetCurrentTrackMouse() const { return (0 != GetValueLong(_currentTrackMouseTag, (long)true)); }\n\n    void SetCurrentTrackMouse(bool onOff) { SetValueLong(_currentTrackMouseTag, \"toggle current track mouse\", (long)onOff); }\n\n    bool GetCurrentShowCitation() const { return (0 != GetValueLong(_currentShowCitationTag, (long)true)); }\n\n    void SetCurrentShowCitation(bool onOff) { SetValueLong(_currentShowCitationTag, \"toggle current show citation\", (long)onOff); }\n\n    string GetCurrentAutosaveName() const { return GetValueString(_currentAutosaveFileNameTag, string(\"/tmp/vapor_autosave.vs3\")); }\n\n    void SetCurrentAutosaveName(string name) { SetValueString(_currentAutosaveFileNameTag, \"set current autosave file\", name); }\n\n    string GetCurrentLogFileName() const { return GetValueString(_currentLogFileNameTag, string(\"/tmp/vaporLog.txt\")); }\n    void   SetCurrentLogFileName(string name) { SetValueString(_currentLogFileNameTag, \"set current log file\", name); }\n    void   SetCurrentMessageSilence(bool val) { SetValueLong(_currentMessagesSilencedTag, \"(Un)Silence current messages\", (long)val); }\n\n    bool GetCurrentMessageSilence() const { return (0 != GetValueLong(_currentMessagesSilencedTag, (long)false)); }\n\n    bool GetCurrentLogfileEnabled() const { return (0 != GetValueLong(_currentLogfileEnabledTag, (long)false)); }\n\n    void SetCurrentLogfileEnabled(bool val) { SetValueLong(_currentLogfileEnabledTag, \"toggle current logfile enabled\", (long)val); }\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (m_classType); }\n\nprivate:\n    static const string m_classType;\n    static const string _shortName;\n    static const string _jpegQualityTag;\n    static const string _autosaveEnabledTag;\n    static const string _autosaveIntervalTag;\n    static const string _showDataWarningTag;\n    static const string _useLessAccurateTag;\n    static const string _trackMouseTag;\n    static const string _showCitationTag;\n    static const string _logFileNameTag;\n    static const string _logfileEnabledTag;\n    static const string _autosaveFileNameTag;\n    static const string _messagesSilencedTag;\n    static const string _currentLogFileNameTag;\n    static const string _currentLogfileEnabledTag;\n    static const string _currentAutosaveFileNameTag;\n    static const string _currentJpegQualityTag;\n    static const string _currentAutosaveEnabledTag;\n    static const string _currentAutosaveIntervalTag;\n    static const string _currentShowDataWarningTag;\n    static const string _currentUseLessAccurateTag;\n    static const string _currentTrackMouseTag;\n    static const string _currentShowCitationTag;\n    static const string _currentMessagesSilencedTag;\n\n    void _init();\n};\n\n#endif    // APPSETTINGSPARAMS_H\n"
  },
  {
    "path": "apps/vaporgui/BannerGUI.cpp",
    "content": "\n#include <QTranslator>\n#include <qboxlayout.h>\n#include <qtimer.h>\n#include <qmessagebox.h>\n#include <qapplication.h>\n#include <qdesktopwidget.h>\n#include <QDesktopServices>\n#include <QUrl>\n#include <QScreen>\n#include <vapor/ResourcePath.h>\n#include <vapor/VAssert.h>\n#include \"BannerGUI.h\"\n\nBannerGUI::BannerGUI(QWidget *parent, std::string imagefile, int maxwait, bool center, QString text, QString url)\n{\n    _parent = parent;\n    this->url = url;\n\n    if (maxwait >= 0) this->setWindowFlags(Qt::FramelessWindowHint);\n    if (maxwait > 0) QTimer::singleShot(maxwait, this, SLOT(on_timer_end()));\n\n    central = new QWidget();\n    setCentralWidget(central);\n\n    mainLayout = new QVBoxLayout();\n    central->setLayout(mainLayout);\n    buttonLayout = new QHBoxLayout();\n\n    textLabel = new QLabel(text, this);\n    textLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);\n\n    imageLabel = new QLabel(\"\", this);\n    imageLabel->setBackgroundRole(QPalette::Base);\n    imageLabel->setScaledContents(true);\n\n    infoButton = new QPushButton(\"More Info\");\n    connect(infoButton, SIGNAL(released()), this, SLOT(infoButton_action()));\n\n    closeButton = new QPushButton(\"Close\");\n    connect(closeButton, SIGNAL(released()), this, SLOT(closeButton_action()));\n\n    if (!imagefile.empty()) {\n        QImage image(Wasp::GetSharePath(\"images/\" + imagefile).c_str());\n        // QImage image(imagefile.c_str());\n        if (image.isNull()) {\n            QMessageBox::information(this, tr(\"VAPoR Banner\"), tr(\"Could not load banner image.\\n\"));\n        } else {\n            imageLabel->setPixmap(QPixmap::fromImage(image));\n            // setCentralWidget(imageLabel);\n            if (text.compare(\"\") != 0) mainLayout->addWidget(textLabel);\n            mainLayout->addWidget(imageLabel);\n            if (maxwait < 0 || url.compare(\"\") != 0) mainLayout->addLayout(buttonLayout);\n            if (url.compare(\"\") != 0) buttonLayout->addWidget(infoButton);\n            if (maxwait < 0) buttonLayout->addWidget(closeButton);\n\n            if (center) {\n                QPoint mpos = parent->pos();\n                move(mpos.x() + (this->width() / 2) - (image.width() / 2), mpos.y() + (this->height() / 2) - (image.height() / 2));\n            } else {\n                QScreen *screen = QGuiApplication::primaryScreen();\n                QRect    screenGeometry = screen->geometry();\n\n                int x = (screenGeometry.width() - image.size().width()) / 2;\n                int y = (screenGeometry.height() - image.size().height()) / 2;\n                move(x, y);\n            }\n            mainLayout->setSizeConstraint(QLayout::SetFixedSize);\n            setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n            show();\n        }\n    }\n}\n\nvoid BannerGUI::request_close() { close(); }\n\nvoid BannerGUI::on_timer_end() { close(); }\n\nvoid BannerGUI::infoButton_action()\n{\n    // TODO: THIS APPEARS NOT TO WORK. FIND OUT HOW OTHERS DO IT.\n    QDesktopServices::openUrl(QUrl(url));\n}\n\nvoid BannerGUI::closeButton_action() { close(); }\n"
  },
  {
    "path": "apps/vaporgui/BannerGUI.h",
    "content": "#ifndef BANNERGUI_H\n#define BANNERGUI_H\n\n#include <qmainwindow.h>\n#include <qlabel.h>\n#include <qboxlayout.h>\n#include <qpushbutton.h>\n\nclass BannerGUI : QMainWindow {\n    Q_OBJECT\npublic:\n    BannerGUI(QWidget *parent, std::string imagefile, int maxwait = 0, bool center = false, QString text = \"\", QString url = \"\");\n\n    void request_close();\n\nprivate:\n    QWidget *    central;\n    QVBoxLayout *mainLayout;\n    QLabel *     textLabel;\n    QLabel *     imageLabel;\n    QHBoxLayout *buttonLayout;\n    QPushButton *closeButton;\n    QPushButton *infoButton;\n    QString      url;\n    QWidget *    _parent;\n\nprivate slots:\n    void on_timer_end();\n    void infoButton_action();\n    void closeButton_action();\n};\n\n#endif    // BANNERGUI_H\n"
  },
  {
    "path": "apps/vaporgui/BarbEventRouter.cpp",
    "content": "#include \"BarbEventRouter.h\"\n#include \"vapor/BarbParams.h\"\n#include \"PWidgets.h\"\n#include \"PConstantColorWidget.h\"\n#include \"PMetadataClasses.h\"\n\nusing namespace VAPoR;\ntypedef BarbParams BP;\n\nstatic RenderEventRouterRegistrar<BarbEventRouter> registrar(BarbEventRouter::GetClassType());\n\nBarbEventRouter::BarbEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, BarbParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PDimensionSelector,\n            new PXFieldVariableSelector,\n            new PYFieldVariableSelector,\n            new PZFieldVariableSelector,\n            new PHeightVariableSelector,\n            new PColorMapVariableSelector,\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    AddAppearanceSubtab(new PGroup({\n        new PColormapTFEditor,\n        new PSection(\"Barbs\", {\n            (new PIntegerSliderEdit(BP::_xBarbsCountTag, \"X Barbs\"))->SetRange(1, 50),\n            (new PIntegerSliderEdit(BP::_yBarbsCountTag, \"Y Barbs\"))->SetRange(1, 50),\n            (new PIntegerSliderEdit(BP::_zBarbsCountTag, \"Z Barbs\"))->SetRange(1, 50),\n            (new PDoubleSliderEdit(BP::_lengthScaleTag, \"Length Scale\"))->SetRange(0.01, 4)->EnableDynamicUpdate(),\n            (new PDoubleSliderEdit(BP::_thicknessScaleTag, \"Thickness Scale\"))->SetRange(0.01, 4)->EnableDynamicUpdate(),\n            new PCheckbox(BP::LightingEnabledTag, \"Enable Lighting\"),\n            new PConstantColorWidget,\n            new PCheckbox(BP::DrawInFrontTag, \"Draw renderer in front\")\n        }),\n    }));\n    \n    AddGeometrySubtab(new PGeometrySubtab);\n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nstring BarbEventRouter::_getDescription() const\n{\n    return (\"Displays an \"\n            \"array of arrows with the users domain, with custom dimensions that are \"\n            \"defined by the user in the X, Y, and Z axes.  The arrows represent a vector \"\n            \"whos direction is determined by up to three user-defined variables.\\n\\nBarbs \"\n            \"can have a constant color applied to them, or they may be colored according \"\n            \"to an additional user-defined variable.\\n\\n\");\n}\n"
  },
  {
    "path": "apps/vaporgui/BarbEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include \"vapor/BarbRenderer.h\"\n\n//! \\class BarbEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Barb renderer GUI\n//! \\author Stas Jaroszynski\n\nclass BarbEventRouter : public RenderEventRouterGUI {\npublic:\n    BarbEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::BarbRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return true; }\n    bool          Supports3DVariables() const { return true; }\n\nprotected:\n    virtual string _getDescription() const;\n    virtual string _getSmallIconImagePath() const { return \"Barbs_small.png\"; }\n    virtual string _getIconImagePath() const { return \"Barbs.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/BookmarkManager.cpp",
    "content": "#include \"BookmarkManager.h\"\n#include <QApplication>\n#include <QMenu>\n#include <QInputDialog>\n#include <vapor/BookmarkParams.h>\n#include <vapor/Base16StringStream.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/GUIStateParams.h>\n#include \"VizWinMgr.h\"\n#include \"QCustomIconSizeProxyStyle.h\"\n\n\nBookmarkManager::BookmarkManager(QObject *parent, VAPoR::ControlExec *ce, VizWinMgr *vizWinMgr)\n: QObject(parent),\n  _controlExec(ce), _paramsMgr(ce->GetParamsMgr()), _vizWinMgr(vizWinMgr),\n  _loadBookmarkMenu(new QMenu(\"Load Bookmark\")),\n  _deleteBookmarkMenu(new QMenu(\"Delete Bookmark\"))\n{\n    _loadBookmarkMenu->setStyle(new QCustomIconSizeProxyStyle(BookmarkParams::DefaultIconSize()));\n    _deleteBookmarkMenu->setStyle(new QCustomIconSizeProxyStyle(BookmarkParams::DefaultIconSize()));\n}\n\n\nvoid BookmarkManager::RegisterToMenu(QMenu *menu)\n{\n    menu->addAction(\"Create Bookmark\", this, &BookmarkManager::createBookmark);\n    menu->addMenu(_loadBookmarkMenu);\n    menu->addMenu(_deleteBookmarkMenu);\n}\n\n\nvoid BookmarkManager::Update()\n{\n    populateBookmarkList();\n}\n\n\nvoid BookmarkManager::createBookmark()\n{\n    bool    ok;\n    QString input = QInputDialog::getText(nullptr, \"New Bookmark\", \"Bookmark Name:\", QLineEdit::Normal, \"\", &ok);\n    if (!ok) return;\n\n    string title = input.toStdString();\n    if (title.empty()) title = \"Unnamed Bookmark\";\n\n    auto p = _controlExec->GetParams<GUIStateParams>();\n\n    p->BeginGroup(\"Create Bookmark\");\n\n    vector<BookmarkParams> bookmarks;\n    for (auto *b : p->GetBookmarks()) bookmarks.push_back(BookmarkParams(*b));\n    p->ClearBookmarks();\n\n    Base16StringStream ss;\n    XmlNode::streamOut(ss, *_paramsMgr->GetXMLRoot());\n\n    for (auto &b : bookmarks) p->AddBookmark(&b);\n\n    string           activeVizWin = p->GetActiveVizName();\n    ViewpointParams *vpp = _paramsMgr->GetViewpointParams(activeVizWin);\n\n    bool useCustomViewport = vpp->GetValueLong(vpp->UseCustomFramebufferTag, 0);\n    int  customViewportWidth = vpp->GetValueLong(vpp->CustomFramebufferWidthTag, 0);\n    int  customViewportHeight = vpp->GetValueLong(vpp->CustomFramebufferHeightTag, 0);\n\n    const int iconSize = BookmarkParams::DefaultIconSize();\n    const int iconDataSize = iconSize * iconSize * 3;\n    auto      iconData = std::unique_ptr<unsigned char[]>(new unsigned char[iconDataSize]);\n\n    char iconDataString[64];\n    snprintf(iconDataString, 64, \":RAM:%p\", iconData.get());\n    // The above string is a \"file path\" that points to an address in memory\n    // which tells the visualizer to save the resulting image to ram rather than\n    // to disk. The current \"image capture\" implementation is very buggy spaghetti\n    // and this is the cleanest solution without major refactoring.\n\n    vpp->SetValueLong(vpp->UseCustomFramebufferTag, \"\", true);\n    vpp->SetValueLong(vpp->CustomFramebufferWidthTag, \"\", iconSize);\n    vpp->SetValueLong(vpp->CustomFramebufferHeightTag, \"\", iconSize);\n\n    _vizWinMgr->EnableImageCapture(iconDataString, activeVizWin);\n\n    vpp->SetValueLong(vpp->UseCustomFramebufferTag, \"\", useCustomViewport);\n    vpp->SetValueLong(vpp->CustomFramebufferWidthTag, \"\", customViewportWidth);\n    vpp->SetValueLong(vpp->CustomFramebufferHeightTag, \"\", customViewportHeight);\n\n    Base16StringStream is;\n    is.write((char *)iconData.get(), iconDataSize);\n\n    BookmarkParams *b = p->CreateBookmark();\n    b->SetName(title);\n    b->SetIcon(iconSize, is.ToString());\n    b->SetData(ss.ToString());\n    p->EndGroup();\n}\n\n\nvoid BookmarkManager::populateBookmarkList()\n{\n    auto bookmarks = _controlExec->GetParams<GUIStateParams>()->GetBookmarks();\n    _loadBookmarkMenu->clear();\n    _deleteBookmarkMenu->clear();\n\n    if (bookmarks.empty()) {\n        _loadBookmarkMenu->addAction(\"(empty)\")->setEnabled(false);\n        _deleteBookmarkMenu->addAction(\"(empty)\")->setEnabled(false);\n    }\n\n    unsigned char *buf = nullptr;\n    size_t         bufSize = 0;\n\n    int i = 0;\n    for (auto b : bookmarks) {\n        if (bufSize != b->GetIconDataSize()) {\n            if (buf) delete[] buf;\n            buf = new unsigned char[b->GetIconDataSize()];\n            bufSize = b->GetIconDataSize();\n        }\n\n        Base16DecoderStream ds(b->GetIconData());\n        ds.read((char *)buf, bufSize);\n        int    s = b->GetIconSize();\n        QImage iconImage(buf, s, s, s * 3, QImage::Format_RGB888);\n        QIcon  icon(QPixmap::fromImage(iconImage));\n\n        _loadBookmarkMenu->addAction(icon, QString::fromStdString(b->GetName()), [this, i]() { loadBookmark(i); });\n        _deleteBookmarkMenu->addAction(icon, QString::fromStdString(b->GetName()), [this, i]() { deleteBookmark(i); });\n        i++;\n    }\n\n    if (buf) delete[] buf;\n}\n\n\nvoid BookmarkManager::loadBookmark(int i)\n{\n    auto p = _controlExec->GetParams<GUIStateParams>();\n\n    XmlNode             root;\n    XmlParser           parser;\n    Base16DecoderStream stream(p->GetBookmark(i)->GetData());\n    parser.LoadFromFile(&root, stream);\n\n    bool paramsStateSaveEnabled = _controlExec->GetSaveStateEnabled();\n    _controlExec->SetSaveStateEnabled(false);\n\n    vector<BookmarkParams> bookmarks;\n    for (auto *b : p->GetBookmarks()) bookmarks.push_back(BookmarkParams(*b));\n\n    _controlExec->LoadState(&root);\n    p = _controlExec->GetParams<GUIStateParams>();\n    p->ClearBookmarks();\n    for (auto &b : bookmarks) p->AddBookmark(&b);\n\n    _controlExec->SetDataCacheDirty(); // TODO <small> determine if necessary\n\n    _controlExec->SetSaveStateEnabled(paramsStateSaveEnabled);\n    _paramsMgr->UndoRedoClear();\n    _paramsMgr->TriggerManualStateChangeEvent();\n}\n\n\nvoid BookmarkManager::deleteBookmark(int i)\n{\n    auto p = _controlExec->GetParams<GUIStateParams>();\n    p->DeleteBookmark(i);\n}"
  },
  {
    "path": "apps/vaporgui/BookmarkManager.h",
    "content": "#pragma once\n#include \"Updatable.h\"\n#include <common.h>\n\nclass QMenu;\nclass VizWinMgr;\n\nclass BookmarkManager : public QObject, public Updatable {\n    Q_OBJECT\npublic:\n    BookmarkManager(QObject *parent, ControlExec *ce, VizWinMgr *vizWinMgr);\n    void RegisterToMenu(QMenu *menu);\n    void Update() override;\n\nprivate:\n    ControlExec * const _controlExec;\n    ParamsMgr * const _paramsMgr;\n    VizWinMgr * const _vizWinMgr;\n    QMenu * const _loadBookmarkMenu;\n    QMenu * const _deleteBookmarkMenu;\n\n    void createBookmark();\n    void populateBookmarkList();\n    void loadBookmark(int i);\n    void deleteBookmark(int i);\n};\n"
  },
  {
    "path": "apps/vaporgui/CLIToolInstaller.cpp",
    "content": "#include \"CLIToolInstaller.h\"\n#include <QMessageBox>\n#include <common.h>\n#include <vapor/ResourcePath.h>\n\n#ifdef WIN32\n    #include \"windowsUtils.h\"\n#endif\n\nusing namespace std;\nusing namespace Wasp;\n\nvoid CLIToolInstaller::Install()\n{\n    QMessageBox box;\n    box.addButton(QMessageBox::Ok);\n\n#ifdef Darwin\n    string home = GetResourcePath(\"\");\n    string binPath = home + \"/MacOS\";\n    home.erase(home.size() - strlen(\"Contents/\"), strlen(\"Contents/\"));\n\n    vector<string> profilePaths = {\n        string(getenv(\"HOME\")) + \"/.profile\",\n        string(getenv(\"HOME\")) + \"/.zshrc\",\n    };\n    bool success = true;\n\n    for (auto profilePath : profilePaths) {\n        FILE *prof = fopen(profilePath.c_str(), \"a\");\n        success &= (bool)prof;\n        if (prof) {\n            fprintf(prof, \"\\n\\n\");\n            fprintf(prof, \"export VAPOR_HOME=\\\"%s\\\"\\n\", home.c_str());\n            fprintf(prof, \"export PATH=\\\"%s:$PATH\\\"\\n\", binPath.c_str());\n            fclose(prof);\n        }\n    }\n\n    if (success) {\n        box.setText(\"Installation Successful\");\n        box.setInformativeText(\"Environmental variables set in ~/.profile and ~/.zshrc. The vapor command line utilities should be available from the terminal.\");\n        box.setIcon(QMessageBox::Information);\n    } else {\n        box.setText(\"Unable to set environmental variables\");\n        box.setIcon(QMessageBox::Critical);\n    }\n#endif\n\n#ifdef WIN32\n    HKEY   key;\n    long   error;\n    long   errorClose;\n    bool   pathWasModified = false;\n    string home = GetResourcePath(\"\");\n\n    error = Windows_OpenRegistry(WINDOWS_HKEY_CURRENT_USER, \"Environment\", key);\n    if (error == WINDOWS_SUCCESS) {\n        string path;\n        error = Windows_GetRegistryString(key, \"Path\", path, \"\");\n        if (error == WINDOWS_ERROR_FILE_NOT_FOUND) {\n            error = WINDOWS_SUCCESS;\n            path = \"\";\n        }\n        if (error == WINDOWS_SUCCESS) {\n            bool   alreadyExists = false;\n            size_t index;\n            if (path.find(\";\" + home + \";\") != std::string::npos)\n                alreadyExists = true;\n            else if ((index = path.find(\";\" + home)) != std::string::npos && index + home.length() + 1 == path.length())\n                alreadyExists = true;\n            else if ((index = path.find(home + \";\")) != std::string::npos && index == 0)\n                alreadyExists = true;\n            else if (path == home)\n                alreadyExists = true;\n\n            if (!alreadyExists) {\n                if (path.length() > 0) path += \";\";\n                path += home;\n                error = Windows_SetRegistryString(key, \"Path\", path);\n                if (error == WINDOWS_SUCCESS) pathWasModified = true;\n            }\n        }\n        errorClose = Windows_CloseRegistry(key);\n    }\n\n    if (error == WINDOWS_SUCCESS && errorClose == WINDOWS_SUCCESS) {\n        // This tells windows to re-load the environment variables\n        SendMessage(HWND_BROADCAST, WM_WININICHANGE, NULL, (LPARAM) \"Environment\");\n\n        box.setIcon(QMessageBox::Information);\n        if (pathWasModified)\n            box.setText(\"Vapor conversion utilities were added to your path\");\n        else\n            box.setText(\"Your path is properly configured\");\n    } else {\n        box.setIcon(QMessageBox::Critical);\n        box.setText(\"Unable to set environmental variables\");\n        string errString = \"\";\n        if (error != WINDOWS_SUCCESS) errString += Windows_GetErrorString(error) + \"\\n\";\n        if (errorClose != WINDOWS_SUCCESS) errString += \"CloseRegistry: \" + Windows_GetErrorString(errorClose);\n        box.setInformativeText(QString::fromStdString(errString));\n    }\n#endif\n\n    box.exec();\n}\n"
  },
  {
    "path": "apps/vaporgui/CLIToolInstaller.h",
    "content": "#pragma once\n\nclass CLIToolInstaller {\npublic:\n    static void Install();\n};\n"
  },
  {
    "path": "apps/vaporgui/CMakeLists.txt",
    "content": "# TODO REMOVE\nadd_definitions (-DNEW_GUI)\nset (SRCS\n\tRenderEventRouter.cpp\n\tRenderHolder.cpp\n\tGLWidget.cpp\n\tErrorReporter.cpp\n\tAnnotationEventRouter.cpp\n\tExportTab.cpp\n\tExportTab.h\n\tTwoDDataEventRouter.cpp\n\tTwoDDataEventRouter.h\n\tWireFrameEventRouter.cpp\n    PythonVariables.cpp\n\tStatistics.cpp\n\tPlot.cpp\n\tCopyRegionWidget.cpp\n\tCopyRegionAnnotationWidget.cpp\n\tRangeCombos.cpp\n\tBarbEventRouter.cpp\n\tBarbEventRouter.h\n\tBannerGUI.cpp\n\tmain.cpp\n\tMainForm.cpp\n\tMainForm_isOpenGLContextActive.cpp\n    VizWin.cpp\n\tVizWinMgr.cpp\n\tImageEventRouter.cpp\n\tImageEventRouter.h\n\tContourEventRouter.cpp\n\tContourEventRouter.h\n    SliceEventRouter.cpp\n    SliceEventRouter.h\n\tPlotParams.cpp\n\tStatisticsParams.cpp\n\tVaporTable.cpp\n\tFidelityWidget.cpp\n\tQSliderEdit.cpp\n\tQRange.cpp\n\tQSinglePoint.cpp\n\tQIntValidatorWithFixup.cpp\n\tFileOperationChecker.cpp\n\tCombo.cpp\n\twindowsUtils.cpp\n\tManip.cpp\n    FlowEventRouter.cpp\n\tVolumeEventRouter.cpp\n\tVolumeEventRouter.h\n\tVolumeIsoEventRouter.cpp\n\tVolumeIsoEventRouter.h\n\tParamsMenuItems.cpp\n\tParamsMenuItems.h\n\tTFOpacityWidget.cpp\n\tTFOpacityWidget.h\n\tTFColorWidget.cpp\n\tTFColorWidget.h\n\tQRangeSlider.cpp\n\tQRangeSlider.h\n\tTFHistogramWidget.cpp\n\tTFHistogramWidget.h\n\tTFInfoWidget.cpp\n\tTFInfoWidget.h\n\tQColorWidget.cpp\n\tQColorWidget.h\n\tTFColorInfoWidget.cpp\n\tTFColorInfoWidget.h\n\tTFOpacityInfoWidget.cpp\n\tTFOpacityInfoWidget.h\n\tTFMapWidget.cpp\n\tTFMapWidget.h\n\tTFMapGroupWidget.cpp\n\tTFMapGroupWidget.h\n\tTFHistogramInfoWidget.cpp\n\tTFHistogramInfoWidget.h\n\tTFIsoValueWidget.cpp\n\tTFIsoValueWidget.h\n\tTFIsoValueInfoWidget.cpp\n\tTFIsoValueInfoWidget.h\n\tTFUtils.cpp\n\tTFUtils.h\n\tTFMappingRangeSelector.cpp\n\tTFMappingRangeSelector.h\n\tQRangeSliderTextCombo.cpp\n\tQRangeSliderTextCombo.h\n\tQPaintUtils.cpp\n\tQPaintUtils.h\n\tVSection.cpp\n\tVSection.h\n    VFrame.h\n\tVFrame.cpp\n\tVLineItem.cpp\n\tVLineItem.h\n\tVHBoxWidget.cpp\n\tVHBoxWidget.h\n    VComboBox.cpp\n    VComboBox.h\n    VIntSpinBox.cpp\n    VIntSpinBox.h\n    VCheckBox.cpp\n    VCheckBox.h\n    VLineEdit_Deprecated.cpp\n    VLineEdit_Deprecated.h\n    VActions.h\n    VActions.cpp\n    VSlider.cpp\n    VSlider.h\n    VSliderEdit.cpp\n    VSliderEdit.h\n    VSliderEditInterface.cpp\n    VSliderEditInterface.h\n    VStringLineEdit.h\n    VStringLineEdit.cpp\n    VIntLineEdit.h\n    VIntLineEdit.cpp\n    VDoubleLineEdit.h\n    VDoubleLineEdit.cpp\n    VDoubleSliderEdit.cpp\n    VDoubleSliderEdit.h\n    VDoubleSliderEditMenu.cpp\n    VDoubleSliderEditMenu.h\n    VIntSliderEditMenu.cpp\n    VIntSliderEditMenu.h\n    VIntSliderEdit.cpp\n    VIntSliderEdit.h\n    VNumericLineEdit.cpp\n    VNumericLineEdit.h\n    VIntRangeMenu.cpp\n    VIntRangeMenu.h\n    VDoubleRangeMenu.cpp\n    VDoubleRangeMenu.h\n    VNumericFormatMenu.cpp\n    VNumericFormatMenu.h\n    VPushButton.cpp\n    VPushButton.h\n    QPushButtonWithDoubleClick.h\n    VFileSelector.cpp\n    VFileSelector.h\n\tV3DInput.cpp\n\tV3DInput.h\n\tV3DIntInput.cpp\n\tV3DIntInput.h\n\tVGroup.cpp\n\tVGroup.h\n        ParamsUpdatable.cpp\n        ParamsUpdatable.h\n\tPOrientationSelector.cpp\n\tPOrientationSelector.h\n\tPWidget.cpp\n\tPWidget.h\n\tPWidgetHLI.h\n\tPGroup.cpp\n\tPGroup.h\n\tPSection.cpp\n\tPSection.h\n\tPCheckbox.cpp\n\tPCheckbox.h\n\tPCheckboxHLI.h\n\tPDoubleInput.cpp\n\tPDoubleInput.h\n\tPDoubleInputHLI.h\n\tPIntegerInput.cpp\n\tPIntegerInput.h\n\tPIntegerInputHLI.h\n\tPDisplay.cpp\n\tPDisplay.h\n\tPDisplayHLI.h\n\tPLabel.cpp\n\tPLabel.h\n\tPLineItem.cpp\n\tPLineItem.h\n\tPEnumDropdown.cpp\n\tPEnumDropdown.h\n\tPEnumDropdownHLI.h\n\tPStringDropdown.cpp\n\tPStringDropdown.h\n\tPStringDropdownHLI.h\n\tPColorSelector.cpp\n\tPColorSelector.h\n\tPFileButton.cpp\n\tPFileButton.h\n\tPFileSelector.cpp\n\tPFileSelector.h\n\tPFileSelectorHLI.h\n\tPDynamicMixin.cpp\n\tPDynamicMixin.h\n\tPSliderEdit.cpp\n\tPSliderEdit.h\n\tPSliderEditHLI.h\n\tPRegionSelector.cpp\n\tPRegionSelector.h\n\tParamsWidgetDemo.cpp\n\tParamsWidgetDemo.h\n\tPTFEditor.cpp\n\tPTFEditor.h\n    PFidelitySection.cpp\n    PFidelitySection.h\n    PAxisAnnotationWidget.cpp\n    PAxisAnnotationWidget.h\n    PTMSLODInput.h\n    PMovingDomainSettings.cpp\n    PMovingDomainSettings.h\n\tModelEventRouter.cpp\n\tModelEventRouter.h\n\tVDoubleValidator.cpp\n\tVDoubleValidator.h\n\thide_std_error_util.cpp\n\thide_std_error_util.h\n\tVContainer.cpp\n\tVContainer.h\n\tUWidget.cpp\n\tUWidget.h\n\tAbstractWidgetGroup.cpp\n\tAbstractWidgetGroup.h\n\tPTransformWidget.cpp\n\tPTransformWidget.h\n\tPCopyRegionAnnotationWidget.cpp\n\tPCopyRegionAnnotationWidget.h\n\tPCopyRegionWidget.cpp\n\tPCopyRegionWidget.h\n\tPSliceController.cpp\n\tPSliceController.h\n\tPAnnotationColorbarWidget.cpp\n\tPAnnotationColorbarWidget.h\n\tPStringInput.cpp\n\tPStringInput.h\n\tPWidgets.h\n\tPWidgetsFwd.h\n\tPGeometrySubtab.cpp\n\tPGeometrySubtab.h\n\tPDimensionSelector.cpp\n\tPDimensionSelector.h\n\tPVariableSelector.cpp\n\tPVariableSelector.h\n\tPShowIf.cpp\n\tPShowIf.h\n\tPWidgetWrapper.cpp\n\tPWidgetWrapper.h\n\tPButton.cpp\n\tPButton.h\n\tPFlowRakeRegionSelector.cpp\n\tPFlowRakeRegionSelector.h\n    PFlowIntegrationRegionSelector.cpp\n    PFlowIntegrationRegionSelector.h\n\tPMultiVarSelector.cpp\n\tPMultiVarSelector.h\n\tAppSettingsMenu.cpp\n\tAppSettingsMenu.h\n    PConstantColorWidget.cpp\n    PConstantColorWidget.h\n    PCornerSelector.cpp\n    PCornerSelector.h\n    RenderEventRouterGUI.cpp\n    RenderEventRouterGUI.h\n    CheckForUpdate.cpp\n    CheckForUpdate.h\n    PDatasetTransformWidget.cpp\n    PDatasetTransformWidget.h\n    PCameraControlsSection.cpp\n    PCameraControlsSection.h\n    PProjectionStringWidget.cpp\n    PProjectionStringWidget.h\n    VProjectionStringFrame.cpp\n    VProjectionStringFrame.h\n    POutputResolutionSection.cpp\n    POutputResolutionSection.h\n    VLabel.cpp\n    VLabel.h\n    VLabelPair.cpp\n    VLabelPair.h\n    VHyperlink.cpp\n    VHyperlink.h\n    PTimestepInput.cpp\n    PTimestepInput.h\n    PTotalTimestepsDisplay.cpp\n    PTotalTimestepsDisplay.h\n    AnimationController.cpp\n    AnimationController.h\n    CaptureController.cpp\n    CaptureController.h\n    DatasetImportController.cpp\n    DatasetImportController.h\n    CheckForNotices.cpp\n    CheckForNotices.h\n    NoticeBoard.cpp\n    NoticeBoard.h\n    ParticleEventRouter.cpp\n    ParticleEventRouter.h\n    PTimestepSliderEdit.cpp\n    PTimestepSliderEdit.h\n    PMetadataClasses.cpp\n    PMetadataClasses.h\n    VVisibilityCheckbox.cpp\n    VVisibilityCheckbox.h\n    RendererList.cpp\n    RendererList.h\n    VRouter.cpp\n    VRouter.h\n    RenderersPanel.cpp\n    RenderersPanel.h\n    RendererInspector.cpp\n    RendererInspector.h\n    DatasetInspector.cpp\n    DatasetInspector.h\n    VScrollArea.cpp\n    VScrollArea.h\n    VScrollGroup.h\n    NewRendererDialogManager.cpp\n    NewRendererDialogManager.h\n    PVisualizerSelector.cpp\n    PVisualizerSelector.h\n    QtVizWinGLContextManager.cpp\n    QtVizWinGLContextManager.h\n    common.cpp\n    common.h\n    Updatable.h\n    ProgressStatusBar.h\n    LeftPanel.cpp\n    LeftPanel.h\n    CLIToolInstaller.cpp\n    CLIToolInstaller.h\n    BookmarkManager.cpp\n    BookmarkManager.h\n    UCloseVDCMenu.cpp\n    UCloseVDCMenu.h\n    NcarCasperUtils.cpp\n    NcarCasperUtils.h\n    ViewpointToolbar.cpp\n    ViewpointToolbar.h\n    CheckForUpdateUI.cpp\n    CheckForUpdateUI.h\n    VRadioButton.h\n    VRadioButton.cpp\n    PRadioButtons.h\n    PRadioButtons.cpp\n    PImportDataWidget.h\n    PImportDataWidget.cpp\n    PImportDataButton.h\n    PImportDataButton.cpp\n    PTimeRangeSelector.cpp\n    PTimeRangeSelector.h\n    PCaptureWidget.h\n    PCaptureWidget.cpp\n    ImportTab.h\n    ImportTab.cpp\n    DatasetTypeLookup.h\n    DatasetTypeLookup.cpp\n\n\t# Need to include all files that request .ui files\n\tStatistics.h\n\tPlot.h\n    PythonVariables.h\n    VaporTable.h \n\tFidelityWidget.h\n\tQSliderEdit.h\n\tQRange.h\n\tQSinglePoint.h\n\n\tMainForm.h\n\tVizWinMgr.h\n\twindowsUtils.h\n\tErrorReporter.h\n\tGLWidget.h\n\tVizWin.h\n\tCore3_2_context.h\n    Manip.h \n\tAnnotationEventRouter.h\n\tBannerGUI.h\n\tFlowEventRouter.h\n\tCombo.h\n\tCopyRegionWidget.h\n\tCopyRegionAnnotationWidget.h\n\tFileOperationChecker.h\n\tPlotParams.h\n    PythonVariablesParams.h\n\tQIntValidatorWithFixup.h\n\tRangeCombos.h\n\tRenderEventRouter.h\n\tRenderHolder.h\n\tStatisticsParams.h\n\tWireFrameEventRouter.h\n\tFlags.h\n\tQMontereySlider.h\n    CitationReminder.h\n    QCustomIconSizeProxyStyle.h\n)\n\nset (UIS \n\tNewRendererDialog.ui\n\tstatsWindow.ui\n\tplotWindow.ui\n    PythonVariablesGUI.ui\n\tFidelityWidgetGUI.ui\n\t\n\tQSliderEdit.ui\n\tQRange.ui\n\tQSinglePoint.ui\n)\n\nsource_group (UIs FILES ${UIS})\n\nfind_package(Qt5 REQUIRED COMPONENTS Core OpenGL Widgets Gui DBus Network)\n\nset (CMAKE_AUTOUIC ON) # This needs to appear before adding sources to work properly\nset (CMAKE_AUTOMOC ON)\nset (CMAKE_AUTORCC ON)\nset (CMAKE_INCLUDE_CURRENT_DIR ON)\n\nset (ASSIMP_LIB assimp)\nset (TIFF_LIB tiff)\n\nif (APPLE)\n\tset (SRCS ${SRCS}\n        core_profile_attributes.mm\n        mac_helpers.mm\n        mac_helpers.h\n        )\n\tset (MACOSX_BUNDLE_GUI_IDENTIFIER Vapor3)\n\tset (MACOSX_BUNDLE_SHORT_VERSION_STRING ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}})\n\tset (MACOSX_BUNDLE_BUNDLE_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}.${VERSION_RC})\n\tset (MACOSX_BUNDLE_ICON_FILE VAPOR.icns)\n\tset (MACOSX_BUNDLE_ICON_FILE_PATH ${CMAKE_SOURCE_DIR}/share/images/VAPOR.icns)\n\tset_source_files_properties(${MACOSX_BUNDLE_ICON_FILE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION \"Resources\")\n\tadd_executable (vapor MACOSX_BUNDLE ${MACOSX_BUNDLE_ICON_FILE_PATH} ${SRCS} ${UIS})\n\tset (INSTALL_BIN_DIR \".\")\nelseif (WIN32)\n    set (ASSIMP_LIB assimp-vc140-mt)\n    set (TIFF_LIB libtiff)\n\n\tset (WINDOWS_ICON_PATH \"${CMAKE_SOURCE_DIR}/share/images/vapor-win-icon.ico\")\n\tconfigure_file (vapor.rc.in ${CMAKE_CURRENT_BINARY_DIR}/vaporgui.rc)\n\tadd_executable (vapor WIN32 ${SRCS} ${UIS} ${CMAKE_CURRENT_BINARY_DIR}/vaporgui.rc)\nelse ()\n\tadd_executable (vapor ${SRCS} ${UIS})\nendif()\n\ntarget_link_libraries (\n        vapor common vdc wasp render params jpeg\n        ${TIFF_LIB} geotiff ${ASSIMP_LIB} Qt5::Widgets Qt5::OpenGL Qt5::Core Qt5::Gui Qt5::DBus Qt5::Network\n        ${Python_LIBRARIES}\n)\n\nif (APPLE)\n\tfind_library (CORESERVICES CoreServices)\n\tfind_library (FOUNDATION Foundation)\n\tfind_library (COCOA Cocoa)\n\t# target_link_libraries (vapor \"-framework CoreServices\")\n\ttarget_link_libraries (vapor ${CORESERVICES} ${FOUNDATION} ${COCOA})\nelseif (UNIX AND NOT APPLE)\n\ttarget_link_libraries (vapor quadmath)\n\ttarget_compile_options(vapor PRIVATE -Wno-conversion-null)\n    target_link_options(vapor PRIVATE \"LINKER:--no-as-needed\")\nendif ()\n\nOpenMPInstall (\n\tTARGETS vapor\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT vaporgui\n\t)\n"
  },
  {
    "path": "apps/vaporgui/CaptureController.cpp",
    "content": "#include \"CaptureController.h\"\n\n#include <QMessageBox>\n#include <QFileDialog>\n#include <sstream>\n#include <iomanip>\n\n#include \"CitationReminder.h\"\n#include \"ErrorReporter.h\"\n\n#include \"vapor/ControlExecutive.h\"\n#include \"vapor/AnimationParams.h\"\n#include \"vapor/GUIStateParams.h\"\n#include \"vapor/FileUtils.h\"\n#include \"vapor/STLUtils.h\"\n\nconst std::string TiffStrings::FileFilter = \"TIFF (*.tif)\";\nconst std::string TiffStrings::FileSuffix = \"tif\";\n\nconst std::string PngStrings::FileFilter = \"PNG (*.png)\";\nconst std::string PngStrings::FileSuffix = \"png\";\n\nCaptureController::CaptureController(VAPoR::ControlExec *ce) : _ce(ce) {}\n\nstd::string CaptureController::GetCaptureFileName() {\n    ShowCitationReminder();\n\n    auto *ap = _ce->GetParams<AnimationParams>();\n    std::string filter = ap->GetValueLong(AnimationParams::CaptureTypeTag, AnimationParams::TIFF) == false ? TiffStrings::FileFilter : PngStrings::FileFilter;\n    std::string suffix = ap->GetValueLong(AnimationParams::CaptureTypeTag, AnimationParams::TIFF) == false ? TiffStrings::FileSuffix : PngStrings::FileSuffix;\n    std::string defaultPath = ap->GetValueString(AnimationParams::CaptureFileDirTag, FileUtils::HomeDir());\n\n    // - For this QFileDialog, QFileDialog::DontConfirmOverwrite is needed because we do file overwrite confirmation \n    //   manually after modifying the user's input filename for capturing time series\n    // \n    // - QFileDialog::DontUseNativeDialog is needed becuase QFileDialog::DontConfirmOverwrite will not work on MacOS without it\n    //\n    std::string file = QFileDialog::getSaveFileName(nullptr, \"Select Filename\", QString::fromStdString(defaultPath), QString::fromStdString(filter), nullptr, QFileDialog::DontConfirmOverwrite | QFileDialog::DontUseNativeDialog).toStdString();\n    if (file.empty()) return \"\";\n\n\n    // Qt does not always append the filetype to the selection from the QFileDialog, so manually add it if this happens\n    if (file.find(suffix) == std::string::npos)\n        file += \".\" + suffix;\n\n    // Add zero padding if we are capturing TimeSeries\n    if (ap->GetValueLong(AnimationParams::CaptureModeTag, AnimationParams::SingleImage) == AnimationParams::TimeSeries) {\n        std::ostringstream oss;\n        oss << FileUtils::RemoveExtension(FileUtils::Basename(file)) << std::setw(5) << std::setfill('0') << \".\" << FileUtils::Extension(file);\n        file = FileUtils::JoinPaths({FileUtils::Dirname(file), oss.str()});\n    }\n\n    // Warn user about overwriting file\n    if (FileUtils::Exists(file)) {\n        QMessageBox::StandardButton confirm = QMessageBox::question(nullptr, \"File exists\", QString::fromStdString(FileUtils::Basename(file) + \" exists. Overwrite?\"), QMessageBox::Yes | QMessageBox::No);\n        if (confirm == QMessageBox::No) return \"\";\n    }\n\n    ap->SetValueString(AnimationParams::CaptureFileDirTag, \"Capture animation file directory\", FileUtils::Dirname(file));\n    if (ap->GetValueLong(AnimationParams::CaptureModeTag, AnimationParams::SingleImage) == AnimationParams::SingleImage) {\n        ap->SetValueString(AnimationParams::CaptureFileNameTag, \"Capture animation file name\", FileUtils::Basename(file));\n        ap->SetValueString(AnimationParams::CaptureFileTimeTag, \"Capture file time\", STLUtils::GetCurrentDateTimestamp());\n    } else {\n        ap->SetValueString(AnimationParams::CaptureTimeSeriesFileNameTag, \"Capture animation file name\", FileUtils::Basename(file));\n        ap->SetValueString(AnimationParams::CaptureTimeSeriesTimeTag, \"Capture file time\", STLUtils::GetCurrentDateTimestamp());\n    }\n\n    return file;\n}\n\nbool CaptureController::EnableAnimationCapture(std::string baseFile) {\n    if (baseFile.empty())\n        baseFile = GetCaptureFileName();\n\n    if (baseFile.empty()) return false;\n\n    string vizName = _ce->GetParams<GUIStateParams>()->GetActiveVizName();\n    bool rc = _ce->EnableAnimationCapture(vizName, true, baseFile) >= 0;\n    if (rc) emit captureStarted();\n    return rc;\n}\n\nvoid CaptureController::CaptureSingleImage() {\n    std::string filePath = GetCaptureFileName();\n    if (filePath.empty()) return;\n\n    string vizName = _ce->GetParams<GUIStateParams>()->GetActiveVizName();\n    if (_ce->EnableImageCapture(filePath, vizName) < 0)\n        MSG_ERR(\"Error capturing image\");\n}\n\nvoid CaptureController::EndAnimationCapture() {\n    string vizName = _ce->GetParams<GUIStateParams>()->GetActiveVizName();\n    if (_ce->EnableAnimationCapture(vizName, false))\n        MSG_WARN(\"Image Capture Warning; active visualizer not capturing images\");\n}\n\nvoid CaptureController::ShowCitationReminder() {\n#ifndef NDEBUG\n    return;\n#endif\n    static bool askForCitation = true;\n    if (!askForCitation) return;\n    askForCitation = false;\n    CitationReminder::Show();\n}\n"
  },
  {
    "path": "apps/vaporgui/CaptureController.h",
    "content": "#pragma once\n    \n#include <QObject>\n#include <string>\n\nnamespace VAPoR {\n    class ControlExec;\n}\n\nstruct TiffStrings {\n    static const std::string FileFilter;\n    static const std::string FileSuffix;\n};\nstruct PngStrings {\n    static const std::string FileFilter;\n    static const std::string FileSuffix;\n};\n\nclass CaptureController : public QObject {\n    Q_OBJECT\n\n    VAPoR::ControlExec *_ce;\n\npublic:\n    explicit CaptureController(VAPoR::ControlExec *ce);\n\n    std::string GetCaptureFileName();\n    bool EnableAnimationCapture(std::string baseFile = \"\");\n    void CaptureSingleImage();\n    void EndAnimationCapture();\n    void ShowCitationReminder();\n\nsignals:\n    void captureStarted();\n};\n"
  },
  {
    "path": "apps/vaporgui/CheckForNotices.cpp",
    "content": "#include \"CheckForNotices.h\"\n#include <QNetworkAccessManager>\n#include <QNetworkRequest>\n#include <QNetworkReply>\n#include <QJsonDocument>\n#include <QJsonArray>\n#include <QJsonObject>\n#include <QDesktopServices>\n#include <iostream>\n#include <string>\n#include <stack>\n#include <vapor/Version.h>\n#include <vapor/STLUtils.h>\n\nusing std::cout;\nusing std::endl;\nusing std::function;\nusing std::string;\nusing Wasp::Version;\n\n\nvoid CheckForGHNotices(std::function<void(const std::vector<Notice> &)> callback)\n{\n    static QNetworkAccessManager *                          manager = nullptr;\n    static std::function<void(const std::vector<Notice> &)> _callback;\n    static std::vector<Notice>                              _notices;\n    static std::stack<Notice>                               _noticesToGet;\n    _callback = callback;\n\n\n    if (!manager) {\n        manager = new QNetworkAccessManager;\n\n        QObject::connect(manager, &QNetworkAccessManager::finished, manager, [&](QNetworkReply *reply) {\n            if (reply->error()) {\n#ifndef NDEBUG\n                printf(\"%s\\n\", reply->errorString().toStdString().c_str());\n#endif\n                return;\n            }\n\n#ifdef TESTING_API\n            if (STLUtils::Contains(reply->url().toString().toStdString(), \"list.json\")) {\n#else\n            if (STLUtils::Contains(reply->url().toString().toStdString(), \"api.github.com\")) {\n#endif\n                _notices.clear();\n                _noticesToGet = {};\n                QString       content = reply->readAll();\n                QJsonDocument json = QJsonDocument::fromJson(content.toUtf8());\n                QJsonArray    array = json.array();\n                for (const QJsonValue value : array) {\n                    QJsonObject file = value.toObject();\n                    Notice      notice;\n                    notice.url = file[\"download_url\"].toString().toStdString();\n\n                    if (STLUtils::Contains(notice.url, \"__example-notice\")) continue;\n\n                    _noticesToGet.push(notice);\n                }\n            } else {\n                QString     content = reply->readAll();\n                QJsonObject json = QJsonDocument::fromJson(content.toUtf8()).object();\n\n#define TIME_FORMAT \"yyyy-MM-dd\"\n\n                Notice notice;\n                notice.url = reply->url().toString().toStdString();\n                notice.content = json[\"content\"].toString().toStdString();\n                notice.date = QDate::fromString(json[\"date\"].toString(), TIME_FORMAT);\n                notice.until = QDate::fromString(json[\"until\"].toString(), TIME_FORMAT);\n\n                auto now = QDate::currentDate();\n\n                if (notice.date <= now && notice.until >= now) _notices.push_back(notice);\n            }\n\n            if (_noticesToGet.empty()) {\n                sort(_notices.begin(), _notices.end(), [](const Notice &a, const Notice &b) { return a.date > b.date; });\n                _callback(_notices);\n            } else {\n                QNetworkRequest req;\n                req.setUrl(QUrl(QString::fromStdString(_noticesToGet.top().url)));\n                _noticesToGet.pop();\n                manager->get(req);\n            }\n        });\n    }\n\n    QNetworkRequest req;\n#ifdef TESTING_API\n    req.setUrl(QUrl(\"http://localhost:8000/list.json\"));\n#else\n    req.setUrl(QUrl(\"https://api.github.com/repos/NCAR/VAPOR-SupportPage/contents/notices\"));\n#endif\n    manager->get(req);\n}\n"
  },
  {
    "path": "apps/vaporgui/CheckForNotices.h",
    "content": "#pragma once\n\n#include <string>\n#include <functional>\n#include <vector>\n#include <QDateTime>\n\nstruct Notice {\n    std::string url;\n    std::string content;\n\n    QDate date;\n    QDate until;\n};\n\n//! Uses the GitHub API to check for any notices which are json files on the main branch in share/notices.\n//! There is an example file there which specifies the format and features.\n\nvoid CheckForGHNotices(std::function<void(const std::vector<Notice> &)> callback);\n"
  },
  {
    "path": "apps/vaporgui/CheckForUpdate.cpp",
    "content": "#include \"CheckForUpdate.h\"\n#include <QNetworkAccessManager>\n#include <QNetworkRequest>\n#include <QNetworkReply>\n#include <QJsonDocument>\n#include <QJsonArray>\n#include <QJsonObject>\n#include <QDesktopServices>\n#include <iostream>\n#include <string>\n#include <vapor/Version.h>\n\nusing std::cout;\nusing std::endl;\nusing std::function;\nusing std::string;\nusing Wasp::Version;\n\nvoid CheckForUpdate(function<void(bool updateAvailable, UpdateInfo info)> callback)\n{\n    static QNetworkAccessManager *                               manager = nullptr;\n    static function<void(bool updateAvailable, UpdateInfo info)> _callback;\n    _callback = callback;\n\n    if (!manager) {\n        manager = new QNetworkAccessManager;\n\n        QObject::connect(manager, &QNetworkAccessManager::finished, manager, [&](QNetworkReply *reply) {\n            if (reply->error()) {\n#ifndef NDEBUG\n                printf(\"%s\\n\", reply->errorString().toStdString().c_str());\n#endif\n                UpdateInfo info;\n                info.error = true;\n                _callback(false, info);\n                return;\n            }\n\n            string     currentVersion = Version::GetVersionString();\n            bool       updateAvailable = false;\n            UpdateInfo info;\n\n            QString       content = reply->readAll();\n            QJsonDocument json = QJsonDocument::fromJson(content.toUtf8());\n            QJsonArray    array = json.array();\n            for (const QJsonValue value : array) {\n                QJsonObject release = value.toObject();\n                bool        preRelease = release[\"prerelease\"].toBool();\n                info.version = release[\"tag_name\"].toString().toStdString();\n                info.url = release[\"html_url\"].toString().toStdString();\n                updateAvailable = !preRelease && Version::Compare(currentVersion, info.version) < 0;\n\n                if (updateAvailable) break;\n            }\n\n            _callback(updateAvailable, info);\n        });\n    }\n\n    QNetworkRequest req;\n#ifdef TESTING_API\n    req.setUrl(QUrl(\"http://localhost:8000/api.json\"));\n#else\n    req.setUrl(QUrl(\"https://api.github.com/repos/NCAR/VAPOR/releases\"));\n#endif\n    manager->get(req);\n}\n\nvoid UpdateInfo::OpenURL() { QDesktopServices::openUrl(QUrl(QString::fromStdString(url))); }\n"
  },
  {
    "path": "apps/vaporgui/CheckForUpdate.h",
    "content": "#pragma once\n\n#include <string>\n#include <functional>\n\nclass QNetworkAccessManager;\n\nstruct UpdateInfo {\n    std::string version;\n    std::string url;\n    bool        error = false;\n\n    void OpenURL();\n};\n\n//! Uses the GitHub API to check Vapor's latest release version and compares it against the current version. If an update\n//! is available, info will be populated.\n\nvoid CheckForUpdate(std::function<void(bool updateAvailable, UpdateInfo info)> callback);\n"
  },
  {
    "path": "apps/vaporgui/CheckForUpdateUI.cpp",
    "content": "#include \"CheckForUpdateUI.h\"\n#include \"CheckForUpdate.h\"\n#include <QCheckBox>\n#include <QMessageBox>\n#include <QPushButton>\n#include <vapor/SettingsParams.h>\n#include <vapor/ControlExecutive.h>\n\n\nvoid CheckForAndShowUpdate(ControlExec *ce)\n{\n#ifndef NDEBUG\n    return;    // Don't check for updates in debug builds\n#endif\n\n    CheckForUpdate([ce](bool updateAvailable, UpdateInfo info) {\n        if (!updateAvailable) return;\n\n        QCheckBox *cb = new QCheckBox(\"Automatically check for updates\");\n        cb->setChecked(true);\n        QMessageBox popup;\n        popup.setText(QString::fromStdString(\"A newer version of Vapor is available: \" + info.version));\n        QPushButton *get = popup.addButton(\"Get Latest Version\", QMessageBox::ActionRole);\n        popup.addButton(\"Ok\", QMessageBox::AcceptRole);\n        popup.setCheckBox(cb);\n\n        popup.exec();\n        if (popup.clickedButton() == get) info.OpenURL();\n\n        if (!cb->isChecked()) {\n            ce->GetParams<SettingsParams>()->SetValueLong(SettingsParams::AutoCheckForUpdatesTag, \"\", false);\n            ce->GetParams<SettingsParams>()->SaveSettings();\n        }\n    });\n}"
  },
  {
    "path": "apps/vaporgui/CheckForUpdateUI.h",
    "content": "#pragma once\n#include <common.h>\n\nvoid CheckForAndShowUpdate(ControlExec *ce);\n"
  },
  {
    "path": "apps/vaporgui/CitationReminder.h",
    "content": "#pragma once\n\n#include <QMessageBox>\n\nclass CitationReminder {\npublic:\n    static void Show() {\n        QMessageBox msgBox;\n        QString     reminder(\"VAPOR is developed as an Open Source application by NCAR, \");\n        reminder.append(\"under the sponsorship of the National Science Foundation.\\n\\n\");\n        reminder.append(\"We depend on evidence of the software's value to the scientific community.  \");\n        reminder.append(\"You are free to use VAPOR as permitted under the terms and conditions of the licence.\\n\\n \");\n        reminder.append(\"Please cite VAPOR in your publications and presentations. \");\n        reminder.append(\"Citation details:\\n    https://www.vapor.ucar.edu/pages/vaporCitationPage.html\");\n        msgBox.setText(reminder);\n\n        msgBox.setStandardButtons(QMessageBox::Ok);\n        msgBox.setDefaultButton(QMessageBox::Ok);\n\n        msgBox.exec();\n    }\n};\n"
  },
  {
    "path": "apps/vaporgui/Combo.cpp",
    "content": "//////////////////////////////////////////////////////\n//\n// Combo\n//\n//////////////////////////////////////////////////////\n\n#include \"Combo.h\"\n#include <QDoubleValidator>\n#include <QIntValidator>\n#include \"vapor/VAssert.h\"\n\nCombo::Combo(QLineEdit *edit, QSlider *slider, bool intType)\n{\n    _minValid = 0.0;\n    _maxValid = 1.0;\n    _value = _minValid;\n    _intType = intType;\n\n    _floatPrecision = 6;    // 6 is default in QT\n\n    _lineEdit = NULL;\n    _lineEditValidator = NULL;\n    _slider = NULL;\n\n    _lineEdit = edit;\n\n    if (_intType)\n        _lineEditValidator = new QIntValidator(this);\n    else\n        _lineEditValidator = new QDoubleValidator(this);\n    _lineEdit->setValidator(_lineEditValidator);\n\n    // Set up slot for changes to _lineEdit\n    //\n    connect(_lineEdit, SIGNAL(returnPressed()), this, SLOT(setLineEdit()));\n\n    _slider = slider;\n    _slider->setFocusPolicy(Qt::StrongFocus);\n    _slider->setSingleStep(1);\n    _slider->setMinimum(0);\n    _slider->setMaximum(999);\n    _slider->setTracking(true);    // Get bizzare double sliders without this\n\n    // Set up slot for changes to _slider\n    //\n    connect(_slider, SIGNAL(sliderReleased()), this, SLOT(setSlider()));\n\n    // update values displayed in the _lineEdit without incurring any state upate.\n    connect(_slider, SIGNAL(sliderMoved(int)), this, SLOT(setSliderMini(int)));\n\n    // This is the aggregate slot that is fired when either the _slider\n    // or the _lineEdit  object change value\n    //\n    connect(this, SIGNAL(valueChanged(double)), this, SLOT(SetSliderLineEdit(double)));\n}\n\nvoid Combo::Update(double min, double max, double value)\n{\n    // Make sure all parameters are valid. If not make them valid\n    //\n    // Should we issue a signal to notify the change of input\n    // parameters?\n    //\n    if (min >= max) max = min;\n    if (value < min) value = min;\n    if (value > max) value = max;\n\n    _minValid = min;\n    _maxValid = max;\n    _value = value;\n\n    // Update validator\n    //\n    // Note: The QDoubleValidator has unexpected behavior and permits\n    // values outside of the the valid range. Possible to options to correct\n    // this are:\n    //\n    // 1. Subclass QDoubleValidator to perform the expected behavior\n    // 2. Use QDoubleValidator only to ensure that input is a double,\n    // and perform range checking inside the slot for returnPressed()\n    //\n    // Currently we use option (2)\n\n    // Update the GUI to reflect the new values\n    //\n    bool oldState = _lineEdit->blockSignals(true);\n    if (_intType) {\n        _lineEdit->setText(QString::number((int)value));\n    } else {\n        _lineEdit->setText(QString::number(value, 'g', _floatPrecision));\n    }\n    _lineEdit->blockSignals(oldState);\n\n    int pos = 0;\n    if (_minValid != _maxValid) { pos = (int)(((value - _minValid) / (_maxValid - _minValid)) * (_slider->maximum() - _slider->minimum()) + _slider->minimum()); }\n\n    oldState = _slider->blockSignals(true);\n    _slider->setSliderPosition(pos);\n    _slider->blockSignals(oldState);\n}\n\nvoid Combo::SetEnabled(bool on)\n{\n    _lineEdit->setEnabled(on);\n    _slider->setEnabled(on);\n}\n\nvoid Combo::setLineEdit()\n{\n    double value = _lineEdit->text().toDouble();\n\n    // The Qt QDoubleValidator class doesn't work as expected. Values\n    // outside of valid range (set with setTop() and setBottom()) do not\n    // trigger the returnPressed() slot, but the QLineEdit will still\n    // display the out-of-range value. Below, we force out of range\n    // values to be in range, and update the GUI to reflect the valid value\n    //\n    if (value < _minValid) {\n        value = _minValid;\n        if (_intType) {\n            _lineEdit->setText(QString::number((int)value));\n        } else {\n            _lineEdit->setText(QString::number(value, 'g', _floatPrecision));\n        }\n    }\n    if (value > _maxValid) {\n        value = _maxValid;\n        if (_intType) {\n            _lineEdit->setText(QString::number((int)value));\n        } else {\n            _lineEdit->setText(QString::number(value, 'g', _floatPrecision));\n        }\n    }\n\n    if (value == _value) return;\n\n    _value = value;\n    if (_intType) {\n        emit valueChanged((int)value);\n    } else {\n        emit valueChanged(value);\n    }\n}\n\nvoid Combo::setSlider()\n{\n    int pos = _slider->sliderPosition();\n    int min = _slider->minimum();\n    int max = _slider->maximum();\n\n    VAssert(min <= pos && max >= pos);\n\n    double value = ((double)(pos - min) / (double)(max - min)) * (_maxValid - _minValid) + _minValid;\n\n    if (value == _value) return;\n\n    _value = value;\n    if (_intType) {\n        emit valueChanged((int)value);\n    } else {\n        emit valueChanged(value);\n    }\n}\n\n// This mini version only changes the values displayed in _lineEdit,\n// but not emit any other signals.\nvoid Combo::setSliderMini(int pos)\n{\n    int min = _slider->minimum();\n    int max = _slider->maximum();\n\n    VAssert(min <= pos && max >= pos);\n\n    double value = ((double)(pos - min) / (double)(max - min)) * (_maxValid - _minValid) + _minValid;\n\n    bool oldState = _lineEdit->blockSignals(true);\n    if (_intType)\n        _lineEdit->setText(QString::number((int)value));\n    else\n        _lineEdit->setText(QString::number(value, 'g', _floatPrecision));\n    _lineEdit->blockSignals(oldState);\n}\n\nvoid Combo::SetSliderLineEdit(double value)\n{\n    // Update the class with the current min and max valid values,\n    // and the new value\n    //\n    Update(_minValid, _maxValid, value);\n}\n\nvoid Combo::SetPrecision(int precision)\n{\n    if (precision > 0) _floatPrecision = precision;\n}\n\nvoid Combo::SetIntType(bool val)\n{\n    if (val != _intType) {\n        _intType = val;\n        delete _lineEditValidator;\n\n        if (_intType)\n            _lineEditValidator = new QIntValidator(this);\n        else\n            _lineEditValidator = new QDoubleValidator(this);\n\n        _lineEdit->setValidator(_lineEditValidator);\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/Combo.h",
    "content": "#ifndef COMBO_H\n#define COMBO_H\n\n#include <QWidget>\n#include <QLineEdit>\n#include <QSlider>\n#include <QValidator>\n\n// Fix for Qt bug https://bugreports.qt.io/browse/QTBUG-98093\n// Apply a style sheet to QSlider to make it work on OSX Monterey\n#ifdef Darwin\n    #include \"QMontereySlider.h\"\n    #define QSlider QMontereySlider\n#endif\n\n// class Combo\n//\n// Manages a paired QSlider and QLineEdit class, synchronizing values\n// across both such that a single value is represented. The value\n// must be within a specified range.\n//\nclass Combo : public QWidget {\n    Q_OBJECT\n\npublic:\n    Combo(QLineEdit *edit, QSlider *slider, bool intType = false);\n\n    // This method must be called whenever the minimax or maximum allowable\n    // valid value changes, or the current value\n    // is changed externally. I.e. Update() provides a means to change\n    // the internal state of the class. If minValid > maxValid, maxValid\n    // will be set to minValid. If value is outside of minValid and maxValid\n    // it will be set to minValid.\n    //\n    void Update(double minValid, double maxValid, double value);\n\n    void Update(double value) { Update(_minValid, _maxValid, value); }\n\n    // Returns a pointer the QSlider object\n    //\n    QSlider *GetSlider() const { return (_slider); };\n\n    // Returns a pointer the QLineEdit object\n    //\n    QLineEdit *GetLineEdit() const { return (_lineEdit); };\n\n    // Returns the currently set value\n    //\n    double GetValue() const { return (_value); };\n\n    // Set how many digits to show for floating-point precision\n    // This setting won't change anything for displaying integers.\n    // The input precision value should be at least 1.\n    //\n    void SetPrecision(int precision);\n\n    // switch IntType\n    void SetIntType(bool);\n\n    void SetEnabled(bool);\n\nprivate slots:\n    // Slot for QLineEdit events\n    //\n    void setLineEdit();\n\n    // Slot for QSlider events\n    //\n    void setSlider();\n    void setSliderMini(int pos);\n\npublic slots:\n    // Public slot for changing the class's value\n    //\n    void SetSliderLineEdit(double);\n\nsignals:\n    // This signal is emitted whenever the value of the class changes\n    //\n    void valueChanged(double value);\n    void valueChanged(int value);\n\nprivate:\n    double _minValid;\n    double _maxValid;\n    double _value;\n    bool   _intType;\n    int    _floatPrecision;    // how many digits after the decimal point?\n\n    QLineEdit * _lineEdit;\n    QValidator *_lineEditValidator;\n    QSlider *   _slider;\n};\n\n#endif\n"
  },
  {
    "path": "apps/vaporgui/ContourEventRouter.cpp",
    "content": "#include \"ContourEventRouter.h\"\n#include \"vapor/ContourParams.h\"\n#include \"PWidgets.h\"\n#include \"PSliderEditHLI.h\"\n#include \"PConstantColorWidget.h\"\n#include \"PSliceController.h\"\n#include \"PMetadataClasses.h\"\n\nusing namespace VAPoR;\ntypedef ContourParams CP;\n\nstatic RenderEventRouterRegistrar<ContourEventRouter> registrar(ContourEventRouter::GetClassType());\n\nContourEventRouter::ContourEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, ContourParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PDimensionSelector,\n            new PScalarVariableSelector,\n            new PHeightVariableSelector,\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    AddAppearanceSubtab(new PGroup({\n        new PTFEditor(RenderParams::_variableNameTag, {\n            PTFEditor::Default,\n            PTFEditor::RegularIsoArray\n        }),\n        new PSection(\"Contour Lines\", {\n            _spacingSlider = new PDoubleSliderEditHLI<CP>(\"Spacing\", &CP::GetContourSpacing, &CP::SetContourSpacing),\n            (new PIntegerSliderEditHLI<CP>(\"Count\", &CP::GetContourCount, &CP::SetContourCount))->SetRange(1, 50),\n            _minValueSlider = new PDoubleSliderEditHLI<CP>(\"Minimum Value\", &CP::GetContourMin, &CP::SetContourMin),\n            new PConstantColorWidget\n        }),\n        (new PShowIf(\"\"))->DimensionEquals(3)->Then(new PGroup({\n            new PSection(\"Slice\", {\n                (new PDoubleSliderEdit(RenderParams::SampleRateTag, \"N Samples\"))->SetRange(32, 2000)\n            })\n        })),\n        new PCheckbox(RenderParams::DrawInFrontTag, \"Draw renderer in front\")\n    }));\n    \n    AddGeometrySubtab(new PGroup({\n        (new PShowIf(\"\"))->DimensionEquals(3)->Then(new PGroup({ new PSliceController })),\n        new PGeometrySubtab,\n    }));\n    \n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nvoid ContourEventRouter::Update()\n{\n    RenderParams *rp = GetActiveParams();\n    string        varname = rp->GetVariableName();\n    size_t        ts = rp->GetCurrentTimestep();\n    int           level = rp->GetRefinementLevel();\n    int           lod = rp->GetCompressionLevel();\n\n    CoordType minExt = {0.0, 0.0, 0.0};\n    CoordType maxExt = {0.0, 0.0, 0.0};\n    rp->GetBox()->GetExtents(minExt, maxExt);\n\n    vector<double> dataExts(2, 0);\n    GetActiveDataMgr()->GetDataRange(ts, varname, level, lod, minExt, maxExt, dataExts);\n\n    _spacingSlider->SetRange(0, dataExts[1] - dataExts[0]);\n    _minValueSlider->SetRange(dataExts[0], dataExts[1]);\n\n    RenderEventRouterGUI::Update();\n}\n\nstring ContourEventRouter::_getDescription() const\n{\n    return (\"Displays \"\n            \"a series of user defined contours along a two dimensional plane within the \"\n            \"user's domain.\\n\\nContours may hae constant coloration, or may be colored \"\n            \"according to a secondary variable.\\n\\nContours may be displaced by a height \"\n            \"variable.\\n\\n \");\n}\n"
  },
  {
    "path": "apps/vaporgui/ContourEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include \"vapor/ContourRenderer.h\"\n\nclass PDoubleSliderEdit;\n\n//! \\class ContourEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Contour renderer GUI\n//! \\author Stas Jaroszynski\n\nclass ContourEventRouter : public RenderEventRouterGUI {\npublic:\n    ContourEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    bool          Supports2DVariables() const { return true; }\n    bool          Supports3DVariables() const { return true; }\n    static string GetClassType() { return VAPoR::ContourRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    void Update();\n\nprotected:\n    virtual string _getDescription() const;\n    string         _getSmallIconImagePath() const { return \"Contours_small.png\"; }\n    string         _getIconImagePath() const { return \"Contours.png\"; }\n\nprivate:\n    PDoubleSliderEdit *_spacingSlider;\n    PDoubleSliderEdit *_minValueSlider;\n};\n"
  },
  {
    "path": "apps/vaporgui/CopyRegionAnnotationWidget.cpp",
    "content": "#include <sstream>\n#include <qwidget.h>\n#include <QFileDialog>\n#include \"vapor/Renderer.h\"\n#include \"vapor/ParamsMgr.h\"\n#include \"vapor/RenderParams.h\"\n#include <vapor/AnimationParams.h>\n#include \"vapor/DataMgrUtils.h\"\n#include <vapor/ControlExecutive.h>\n#include \"CopyRegionAnnotationWidget.h\"\n#include \"VLineItem.h\"\n\n#define X 0\n#define Y 1\n#define Z 2\n\nusing namespace VAPoR;\n\nnamespace {\ntemplate<typename Out> void split(const std::string &s, char delim, Out result)\n{\n    std::stringstream ss;\n    ss.str(s);\n    std::string item;\n    while (std::getline(ss, item, delim)) { *(result++) = item; }\n}\n\nstd::vector<std::string> split(const std::string &s, char delim)\n{\n    std::vector<std::string> elems;\n    split(s, delim, std::back_inserter(elems));\n    return elems;\n}\n}    // namespace\n\nCopyRegionAnnotationWidget::CopyRegionAnnotationWidget(VAPoR::ControlExec *ce) : CopyRegionWidget() { _controlExec = ce; }\n\nvoid CopyRegionAnnotationWidget::Update()\n{\n    _paramsMgr = _controlExec->GetParamsMgr();\n    VAssert(_paramsMgr);\n    updateCopyCombo();\n}\n\nvoid CopyRegionAnnotationWidget::copyRegion()\n{\n    string copyString = copyCombo->currentText().toStdString();\n    if (copyString != \"\") {\n        std::vector<std::string> elems = split(copyString, ':');\n        string                   visualizer = _visNames[elems[0]];\n        string                   dataSetName = elems[1];\n        string                   renType = _renTypeNames[elems[2]];\n        string                   renderer = elems[3];\n\n        RenderParams *copyParams = _paramsMgr->GetRenderParams(visualizer, dataSetName, renType, renderer);\n        VAssert(copyParams);\n\n        Box *               copyBox = copyParams->GetBox();\n        std::vector<double> minExtentsVec, maxExtentsVec;\n        copyBox->GetExtents(minExtentsVec, maxExtentsVec);\n\n        CoordType minExtents = {0.0, 0.0, 0.0};\n        CoordType maxExtents = {0.0, 0.0, 0.0};\n        Grid::CopyToArr3(minExtentsVec, minExtents);\n        Grid::CopyToArr3(maxExtentsVec, maxExtents);\n\n        AnnotationParams *a = _paramsMgr->GetAnnotationParams(visualizer);\n        AxisAnnotation *  aa = a->GetAxisAnnotation();\n\n        AnimationParams *aParams = dynamic_cast<AnimationParams *>(_paramsMgr->GetParams(AnimationParams::GetClassType()));\n        VAssert(aParams);\n        int timeStep = aParams->GetCurrentTimestep();\n\n        _scaleWorldCoordsToNormalized(minExtentsVec, maxExtentsVec, timeStep);\n\n        aa->SetAxisOrigin(minExtentsVec);\n        aa->SetMinTics(minExtentsVec);\n        aa->SetMaxTics(maxExtentsVec);\n\n        emit valueChanged();\n    }\n}\n\nvoid CopyRegionAnnotationWidget::_scaleWorldCoordsToNormalized(std::vector<double> &minCoords, std::vector<double> &maxCoords, int timeStep) {\n    VAssert(minCoords.size() == maxCoords.size());\n    VAPoR::CoordType    minDomainExts, maxDomainExts;\n    DataStatus *        dataStatus = _controlExec->GetDataStatus();\n    dataStatus->GetActiveExtents(_paramsMgr, timeStep, minDomainExts, maxDomainExts);\n\n    for (int i = 0; i < minCoords.size(); i++) {\n        double minPoint = minCoords[i] - minDomainExts[i];\n        double maxPoint = maxCoords[i] - minDomainExts[i];\n        double magnitude = maxDomainExts[i] - minDomainExts[i];\n        minCoords[i] = minPoint / magnitude;\n        maxCoords[i] = maxPoint / magnitude;\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/CopyRegionAnnotationWidget.h",
    "content": "#pragma once\n\n#include \"CopyRegionWidget.h\"\n\nnamespace VAPoR {\nclass ControlExec;\nclass RenderParams;\nclass ParamsMgr;\nclass DataMgr;\n}    // namespace VAPoR\n\nclass CopyRegionAnnotationWidget : public CopyRegionWidget {\n    Q_OBJECT\n\npublic:\n    CopyRegionAnnotationWidget(VAPoR::ControlExec *ce);\n\n    QString toolTip() const\n    {\n        return tr(\"A widget for copying one renderer's \"\n                  \"region to axis annotations\");\n    }\n\n    void Update();\n\nprotected slots:\n    void copyRegion() override;\n\nprivate:\n    void _scaleWorldCoordsToNormalized(std::vector<double> &minExts, std::vector<double> &maxExts, int timeStep);\n\n    VAPoR::ControlExec *_controlExec;\n};\n"
  },
  {
    "path": "apps/vaporgui/CopyRegionWidget.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t  *\n//\t   Copyright (C)  2017\t\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t  *\n//\t   All Rights Reserved\t\t\t\t\t*\n//\t\t\t\t\t\t\t  *\n//************************************************************************/\n//\n//  File:\t   CopyRegionWidget.cpp\n//\n//  Author:\t Scott Pearse\n//\t  National Center for Atmospheric Research\n//\t  PO 3000, Boulder, Colorado\n//\n//  Date:\t   March 2017\n//\n//  Description:\tImplements the CopyRegionWidget class.  This provides\n//  a widget that is inserted in the \"Appearance\" tab of various Renderer GUIs\n//\n#include <sstream>\n#include <qwidget.h>\n#include <QFileDialog>\n#include \"vapor/Renderer.h\"\n#include \"vapor/ParamsMgr.h\"\n#include \"vapor/RenderParams.h\"\n#include \"vapor/DataMgrUtils.h\"\n#include \"CopyRegionWidget.h\"\n#include \"VLineItem.h\"\n\n#define X 0\n#define Y 1\n#define Z 2\n\nusing namespace VAPoR;\n\nnamespace {\ntemplate<typename Out> void split(const std::string &s, char delim, Out result)\n{\n    std::stringstream ss;\n    ss.str(s);\n    std::string item;\n    while (std::getline(ss, item, delim)) { *(result++) = item; }\n}\n\nstd::vector<std::string> split(const std::string &s, char delim)\n{\n    std::vector<std::string> elems;\n    split(s, delim, std::back_inserter(elems));\n    return elems;\n}\n}    // namespace\n\nCopyRegionWidget::CopyRegionWidget(QWidget *parent) : VSectionGroup(\"Copy region from renderer\")\n{\n    Add(new VLineItem(\"Renderer\", copyCombo = new QComboBox));\n    Add(new VLineItem(\"\", copyButton = new QPushButton(\"Copy\")));\n\n    _paramsMgr = NULL;\n    _rParams = NULL;\n\n    connect(copyButton, SIGNAL(released()), this, SLOT(copyRegion()));\n}\n\nCopyRegionWidget::~CopyRegionWidget() {}\n\nvoid CopyRegionWidget::updateCopyCombo()\n{\n    copyCombo->clear();\n\n    std::vector<string> visNames = _paramsMgr->GetVisualizerNames();\n    _visNames.clear();\n\n    _dataSetNames = _paramsMgr->GetDataMgrNames();\n\n    for (int i = 0; i < visNames.size(); i++) {\n        for (int ii = 0; ii < _dataSetNames.size(); ii++) {\n            // Create a mapping of abreviated visualizer names to their\n            // actual string values.\n            //\n            string visAbb = \"Vis\" + std::to_string(i);\n            _visNames[visAbb] = visNames[i];\n\n            string dataSetName = _dataSetNames[ii];\n\n            std::vector<string> typeNames;\n            typeNames = _paramsMgr->GetRenderParamsClassNames(visNames[i]);\n\n            for (int j = 0; j < typeNames.size(); j++) {\n                // Abbreviate Params names by removing 'Params\" from them.\n                // Then store them in a map for later reference.\n                //\n                string typeAbb;\n                typeAbb = RendererFactory::Instance()->GetRenderClassFromParamsClass(typeNames[j]);\n\n                _renTypeNames[typeAbb] = typeNames[j];\n\n                std::vector<string> renNames;\n                renNames = _paramsMgr->GetRenderParamInstances(visNames[i], _dataSetNames[ii], typeNames[j]);\n\n                for (int k = 0; k < renNames.size(); k++) {\n                    string  displayName = visAbb + \":\" + dataSetName + \":\" + typeAbb + \":\" + renNames[k];\n                    QString qDisplayName = QString::fromStdString(displayName);\n                    copyCombo->addItem(qDisplayName);\n                }\n            }\n        }\n    }\n}\n\nvoid CopyRegionWidget::_configurePlanarBox(const VAPoR::Box *myBox, std::vector<double> *myMin, std::vector<double> *myMax) const\n{\n    VAssert((*myMin).size() == (*myMax).size());\n\n    int planarAxis;\n    int orientation = myBox->GetOrientation();\n    if (orientation == Box::XY)\n        planarAxis = Z;\n    else if (orientation == Box::XZ)\n        planarAxis = Y;\n    else if (orientation == Box::YZ)\n        planarAxis = X;\n    else\n        return;\n\n    // If our region is planar (IE SliceRenderer), then we need to set a\n    // reasonable Z coordinate, midway between the minimum and maximum.\n    // If we are dealing with a 2-D variable or renderer, there is no Z\n    // coordinate, so we don't do anything and return.\n    if (planarAxis < Z ||    // Not true for TwoD, Contour, and Image renderers\n        (*myMin).size() == 3) {\n        double min = (*myMin)[planarAxis];\n        double max = (*myMax)[planarAxis];\n        double plane = (min + max) / 2.f;\n        (*myMin)[planarAxis] = plane;\n        (*myMax)[planarAxis] = plane;\n    }\n}\n\nvoid CopyRegionWidget::copyRegion()\n{\n    string copyString = copyCombo->currentText().toStdString();\n    if (copyString != \"\") {\n        std::vector<std::string> elems = split(copyString, ':');\n        string                   visualizer = _visNames[elems[0]];\n        string                   dataSetName = elems[1];\n        string                   renType = _renTypeNames[elems[2]];\n        string                   renderer = elems[3];\n\n        RenderParams *copyParams = _paramsMgr->GetRenderParams(visualizer, dataSetName, renType, renderer);\n        VAssert(copyParams);\n\n        Box *               copyBox = copyParams->GetBox();\n        std::vector<double> minExtents, maxExtents;\n        copyBox->GetExtents(minExtents, maxExtents);\n\n        Box *               myBox = _rParams->GetBox();\n        std::vector<double> myMin, myMax;\n        myBox->GetExtents(myMin, myMax);\n        VAssert(minExtents.size() == maxExtents.size());\n        VAssert(myMin.size() == myMax.size());\n        for (int i = 0; i < myMin.size(); i++) {\n            myMin[i] = minExtents[i];\n            myMax[i] = maxExtents[i];\n        }\n\n        _configurePlanarBox(myBox, &myMin, &myMax);\n\n        myBox->SetExtents(myMin, myMax);\n\n        emit valueChanged();\n    }\n}\n\nvoid CopyRegionWidget::Update(ParamsMgr *paramsMgr, RenderParams *rParams)\n{\n    VAssert(paramsMgr);\n    VAssert(rParams);\n\n    _paramsMgr = paramsMgr;\n    _rParams = rParams;\n\n    updateCopyCombo();\n}\n"
  },
  {
    "path": "apps/vaporgui/CopyRegionWidget.h",
    "content": "#ifndef COPYREGIONWIDGET_H\n#define COPYREGIONWIDGET_H\n\n#include <vapor/Box.h>\n#include \"VSection.h\"\n#include <QPushButton>\n#include <QComboBox>\n\nnamespace VAPoR {\nclass RenderParams;\nclass ParamsMgr;\nclass DataMgr;\n}    // namespace VAPoR\n\nclass CopyRegionWidget : public VSectionGroup {\n    Q_OBJECT\n\npublic:\n    CopyRegionWidget(QWidget *parent = 0);\n\n    ~CopyRegionWidget();\n\n    QString name() const { return \"CopyRegionWidget\"; }\n    QString includeFile() const { return \"CopyRegionWidget.h\"; }\n    QString group() const { return tr(\"A widget for copying one renderer's region to another\"); }\n    QString toolTip() const\n    {\n        return tr(\"A widget for copying one renderer's \"\n                  \"region to another\");\n    }\n    QString whatsThis() const\n    {\n        return tr(\"This widget contains all widgets \"\n                  \"necessary for copying renderer regions\");\n    }\n    bool         isContainer() const { return true; }\n    virtual void Update(VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams);\n\nsignals:\n    void valueChanged();\n\nprotected slots:\n    virtual void copyRegion();\n\nprotected:\n    QPushButton *copyButton;\n    QComboBox *  copyCombo;\n\n    void updateCopyCombo();\n\n    // Configures a box to have equal minimum and maximum\n    // extents along an axis, if the box is planar.  If not,\n    // the function returns.\n    void _configurePlanarBox(const VAPoR::Box *myBox, std::vector<double> *myMin, std::vector<double> *myMax) const;\n\n    VAPoR::ParamsMgr *   _paramsMgr;\n    VAPoR::RenderParams *_rParams;\n\n    std::vector<std::string>           _dataSetNames;\n    std::map<std::string, std::string> _visNames;\n    std::map<std::string, std::string> _renTypeNames;\n};\n\n#endif    // COPYREGIONWIDGET_H\n"
  },
  {
    "path": "apps/vaporgui/Core3_2_context.h",
    "content": "#pragma once\n\n#include <QGLContext>\n\n#if defined(Q_OS_MAC)\n    #if QT_VERSION < 0x050000 && QT_VERSION >= 0x040800    // if less than 5.0.0\nvoid *select_3_2_mac_visual(GDHandle handle, int depthBufferSize);\n    #endif\n#endif\n\nstruct Core3_2_context : public QGLContext {\n    Core3_2_context(const QGLFormat &format, QPaintDevice *device) : QGLContext(format, device) {}\n    Core3_2_context(const QGLFormat &format) : QGLContext(format) {}\n\n#if defined(Q_OS_MAC)\n    #if QT_VERSION < 0x050000 && QT_VERSION >= 0x040800    // if less than 5.0.0\n    virtual void *chooseMacVisual(GDHandle handle) { return select_3_2_mac_visual(handle, this->format().depthBufferSize()); }\n    #endif\n#endif\n};\n"
  },
  {
    "path": "apps/vaporgui/DatasetImportController.cpp",
    "content": "#include \"DatasetImportController.h\"\n#include \"ErrorReporter.h\"\n#include \"DatasetTypeLookup.h\"\n\n#include \"vapor/ControlExecutive.h\"\n#include \"vapor/DataStatus.h\"\n#include \"vapor/GUIStateParams.h\"\n#include \"vapor/AnimationParams.h\"\n#include \"vapor/NavigationUtils.h\"\n#include \"vapor/FileUtils.h\"\n\n#include <QInputDialog>\n\nusing namespace std;\nusing namespace VAPoR;\n\nstd::string DatasetImportController::GetDatasetName(ParamsMgr *pm, std::string file, DatasetExistsAction existsAction) {\n    auto names = pm->GetDataMgrNames();\n    if (names.empty() || existsAction == DatasetExistsAction::AddNew)\n        return ControlExec::MakeStringConformant(FileUtils::Basename(file));\n    if (existsAction == DatasetExistsAction::ReplaceFirst)\n        return names[0];\n\n    QStringList items;\n    items << \"New Dataset\";\n    for (auto &n : names) items << QString::fromStdString(n);\n\n    bool ok;\n    QString choice = QInputDialog::getItem(nullptr, \"Load Data\", \"Load as new dataset or replace existing\", items, 0, false, &ok);\n    if (!ok || choice.isEmpty()) return \"\";\n\n    std::string name = choice.toStdString();\n    if (name == \"New Dataset\")\n        return ControlExec::MakeStringConformant(FileUtils::Basename(file));\n    return name;\n}\n\nbool DatasetImportController::ImportDataset(ControlExec *ce, const vector<string> &files, std::string format, DatasetExistsAction action) {\n    ParamsMgr *pm = ce->GetParamsMgr();\n    pm->BeginSaveStateGroup(\"Import Dataset\");\n\n    std::string name = GetDatasetName(pm, files[0], action);\n    if (name.empty()) {\n        pm->EndSaveStateGroup();\n        return false;\n    }\n\n    if (ce->OpenData(files, name, format) < 0) {\n        pm->EndSaveStateGroup();\n        MSG_ERR(\"Failed to load data\");\n        return false;\n    }\n\n    auto gsp = ce->GetParams<GUIStateParams>();\n    gsp->InsertOpenDataSet(name, format, files);\n\n    auto ds = ce->GetDataStatus();\n    auto ap = ce->GetParams<AnimationParams>();\n    ap->SetEndTimestep(ds->GetTimeCoordinates().size() - 1);\n\n    if (gsp->GetValueLong(GUIStateParams::SessionNewTag, false)) {\n        NavigationUtils::ViewAll(ce);\n        NavigationUtils::SetHomeViewpoint(ce);\n        gsp->SetProjectionString(ds->GetMapProjection());\n    }\n\n    gsp->SetValueLong(GUIStateParams::SessionNewTag, \"Reset SessionNewTag to false after data import\", false);\n\n    pm->EndSaveStateGroup();\n    emit datasetImported();\n    return true;\n}\n"
  },
  {
    "path": "apps/vaporgui/DatasetImportController.h",
    "content": "#pragma once\n\n#include <QObject>\n#include <vector>\n#include <string>\n\nnamespace VAPoR {\n    class ControlExec;\n    class ParamsMgr;\n}\n\nclass DatasetImportController : public QObject {\n    Q_OBJECT\n\npublic:\n    enum class DatasetExistsAction { Prompt, ReplaceFirst, AddNew };\n    bool ImportDataset(VAPoR::ControlExec *ce, const std::vector<std::string> &files, std::string format, DatasetExistsAction action);\n    std::string GetDatasetName(VAPoR::ParamsMgr *pm, std::string file, DatasetExistsAction existsAction);\n\n\nsignals:\n    void datasetImported();\n};\n"
  },
  {
    "path": "apps/vaporgui/DatasetInspector.cpp",
    "content": "#include \"DatasetInspector.h\"\n#include <vapor/ControlExecutive.h>\n#include <vapor/GUIStateParams.h>\n#include \"PTransformWidget.h\"\n#include \"VLabel.h\"\n#include <QTreeWidget>\n#include \"PMetadataClasses.h\"\n#include \"VScrollGroup.h\"\n\nusing namespace VAPoR;\n\nDatasetInspector::DatasetInspector(VAPoR::ControlExec *ce)\n: _ce(ce) {\n    VScrollGroup *g = new VScrollGroup;\n    g->Add(new VSectionGroup(\"Info\", {\n        _name = new VLabel,\n        _type = new VLabel,\n        _path = new VLabel\n    }));\n    g->Add(new VSectionGroup(\"Transform\", {_tw = new PTransformWidget}));\n\n    addTab(_dataTab = g, \"Dataset\");\n    addTab(_metaTab = new VScrollGroup({\n               _metaAttrs = new VGlobalAttributeMetadataTree,\n               _metaDims = new VDimensionMetadataTree,\n               _metaVars = new VVariableMetadataTree,\n               _metaCoords = new VCoordinateVariableMetadataTree,\n           }), \"Metadata\");\n\n    connect(this, &QTabWidget::currentChanged, this, &DatasetInspector::Update);\n}\n\nvoid DatasetInspector::Update()\n{\n    ParamsMgr *pm = _ce->GetParamsMgr();\n    GUIStateParams *guiParams = (GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType());\n    ViewpointParams *vp = pm->GetViewpointParams(guiParams->GetActiveVizName());\n    DataStatus *dataStatus = _ce->GetDataStatus();\n    string dataset = guiParams->GetActiveDataset();\n    if (!vp || dataset.empty()) return;\n\n    if (currentWidget() == _dataTab) {\n        _name->SetText(\"Name: \" + dataset);\n        _type->SetText(\"Type: \" + DatasetTypeDescriptiveName(guiParams->GetOpenDataSetFormat(dataset)));\n        _path->SetText(\"Path: \" + guiParams->GetOpenDataSetPaths(dataset)[0]);\n        Transform *transform = vp->GetTransform(dataset);\n        _tw->Update(transform);\n    }\n    else if (currentWidget() == _metaTab) {\n        auto dataMgr = dataStatus->GetDataMgr(dataset);\n        _metaAttrs->Update(guiParams, pm, dataMgr);\n        _metaDims->Update(guiParams, pm, dataMgr);\n        _metaVars->Update(guiParams, pm, dataMgr);\n        _metaCoords->Update(guiParams, pm, dataMgr);\n    }\n}\n\nstd::string DatasetInspector::DatasetTypeDescriptiveName(std::string type)\n{\n    if (type == \"vdc\") return \"VDC\";\n    if (type == \"wrf\") return \"WRF-ARW\";\n    if (type == \"cf\") return \"NetCDF-CF\";\n    if (type == \"mpas\") return \"MPAS\";\n    if (type == \"bov\") return \"Brick of Values (BOV)\";\n    if (type == \"dcp\") return \"Data Collection Particles (DCP)\";\n    if (type == \"ugrid\") return \"Unstructured Grid (UGRID)\";\n    return type;\n}"
  },
  {
    "path": "apps/vaporgui/DatasetInspector.h",
    "content": "#pragma once\n\n#include \"VSection.h\"\n\nnamespace VAPoR {\nclass ControlExec;\n}\nclass PTransformWidget;\nclass VLabel;\nclass QTreeWidget;\nclass VMetadataTree;\n\nclass DatasetInspector : public QTabWidget {\n    Q_OBJECT\n\n    VAPoR::ControlExec *_ce;\n    QWidget *_dataTab, *_metaTab;\n    PTransformWidget *_tw;\n    VLabel *_name, *_type, *_path;\n    VMetadataTree *_metaAttrs, *_metaDims, *_metaVars, *_metaCoords;\n\npublic:\n    DatasetInspector(VAPoR::ControlExec *ce);\n    void Update();\n\n    static std::string DatasetTypeDescriptiveName(std::string type);\n};\n"
  },
  {
    "path": "apps/vaporgui/DatasetTypeLookup.cpp",
    "content": "#include \"DatasetTypeLookup.h\"\n#include \"vapor/ParamsBase.h\"\n\nnamespace {\n    const std::vector<std::pair<std::string, std::string>> datasets =\n    {\n        { \"wrf\"   , \"WRF-ARW\" },\n        { \"cf\"    , \"NetCDF-CF\" },\n        { \"bov\"   , \"Brick of Values (BOV)\" },\n        { \"dcp\"   , \"Data Collection Particles (DCP)\" },\n        { \"mpas\"  , \"MPAS\" },\n        { \"ugrid\" , \"Unstructured Grid (UGRID)\" },\n        { \"vdc\"   , \"VDC\" }\n    };\n}\n\nconst std::vector<std::pair<std::string, std::string>>& GetDatasets() {\n    return datasets;\n}\n\nstd::vector<std::string> GetDatasetTypeDescriptions() {\n    std::vector<std::string> descriptions;\n    for (const auto& pair : datasets) descriptions.push_back(pair.second);\n    return descriptions;\n}\n\nstd::string DatasetTypeDescriptiveName(const std::string& type) {\n    auto it = std::find_if(datasets.begin(), datasets.end(), [&type](const auto& pair) {\n        return pair.first==type;\n    });\n    return (it != datasets.end()) ? it->second : \"No description for given data type \" + type ;\n}\n\nstd::string DatasetTypeShortName(const std::string& descriptiveName) {\n    auto it = std::find_if(datasets.begin(), datasets.end(), [&descriptiveName](const auto& pair) {\n        return pair.second==descriptiveName;\n    });\n    return (it != datasets.end()) ? it->first : \"No shortName for given description \" + descriptiveName;\n}\n"
  },
  {
    "path": "apps/vaporgui/DatasetTypeLookup.h",
    "content": "#pragma once\n\n#include <string>\n#include <vector>\n\nconst std::vector<std::pair<std::string, std::string>>& GetDatasets();\nstd::vector<std::string> GetDatasetTypeDescriptions();\nstd::string DatasetTypeDescriptiveName(const std::string& type);\nstd::string DatasetTypeShortName(const std::string& descriptiveName);\n"
  },
  {
    "path": "apps/vaporgui/ErrorReporter.cpp",
    "content": "//************************************************************************\n//                                                                       *\n//                        Copyright (C)  2017                            *\n//           University Corporation for Atmospheric Research             *\n//                        All Rights Reserved                            *\n//                                                                       *\n//************************************************************************\n//\n//\tFile:\t\t\tErrorReporter.cpp\n//\n//\tAuthor:\t\t\tStas Jaroszynski (stasj@ucar.edu)\n//\t\t\t\t\tNational Center for Atmospheric Research\n//\t\t\t\t\t1850 Table Mesa Drive\n//\t\t\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\t\tJuly 2017\n//\n//\tDescription:\tImplements the ErrorReporter class\n\n#include <stdio.h>\n#include <signal.h>\n#include <stdlib.h>\n#include <errno.h>\n\n#if !defined(WIN32)\n    #include <execinfo.h>\n    #include <unistd.h>\n#endif\n\n#if defined(Darwin)\n    #include <CoreServices/CoreServices.h>\n#elif defined(linux)\n    #include <sys/utsname.h>\n#elif defined(WIN32)\n    #include <windows.h>\n#endif\n\n#include <QWidget>\n#include <QMessageBox>\n#include <QFileDialog>\n#include <QTextStream>\n#include <QPushButton>\n#include <QApplication>\n\n#include \"vapor/MyBase.h\"\n#include \"vapor/Version.h\"\n\n#include \"ErrorReporter.h\"\n#include \"MainForm.h\"\n\nusing std::string;\nusing std::vector;\n\nErrorReporter *ErrorReporter::_instance = NULL;\n\nvoid _segFaultHandler(int sig)\n{\n    string details;\n#if !defined(WIN32)\n    void * array[128];\n    size_t size;\n    size = backtrace(array, 128);\n\n    backtrace_symbols_fd(array, size, STDERR_FILENO);\n    char **backtrace_str = backtrace_symbols(array, 128);\n\n    for (int i = 0; i < size; i++) {\n        if (strlen(backtrace_str[i]) == 0) break;\n        details += string(backtrace_str[i]) + \"\\n\";\n    }\n#endif\n\n    ErrorReporter::Report(\"A memory error occured\", ErrorReporter::Error, details);\n    exit(1);\n}\n\nvoid _myBaseErrorCallback(const char *msg, int err_code)\n{\n    ErrorReporter *e = ErrorReporter::GetInstance();\n    e->_log.push_back(ErrorReporter::Message(ErrorReporter::Error, string(msg), err_code));\n    e->_fullLog.push_back(ErrorReporter::Message(ErrorReporter::Error, string(msg), err_code));\n\n    if (e->_logFile) { fprintf(e->_logFile, \"Error[%i]: %s\\n\", err_code, msg); }\n}\n\nvoid _myBaseDiagCallback(const char *msg)\n{\n    ErrorReporter *e = ErrorReporter::GetInstance();\n    e->_fullLog.push_back(ErrorReporter::Message(ErrorReporter::Diagnostic, string(msg)));\n\n    if (e->_logFile) { fprintf(e->_logFile, \"Diagnostic: %s\\n\", msg); }\n}\n\n#define ErrorReporterPopup_OK_BUTTON_TEXT   \"Ok\"\n#define ErrorReporterPopup_SAVE_BUTTON_TEXT \"Save Log\"\n\nErrorReporterPopup::ErrorReporterPopup(QWidget *parent, int id, bool fatal) : QMessageBox(parent), dead(false), fatal(fatal)\n{\n    addButton(ErrorReporterPopup_OK_BUTTON_TEXT, QMessageBox::AcceptRole);\n    addButton(ErrorReporterPopup_SAVE_BUTTON_TEXT, QMessageBox::ApplyRole);\n    setText(\"An error has occured\");\n    connect(this, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(doAction(QAbstractButton *)));\n}\n\nvoid ErrorReporterPopup::doAction(QAbstractButton *button)\n{\n    dead = true;\n    if (ErrorReporterPopup_SAVE_BUTTON_TEXT == button->text().toStdString()) {\n        QString fileName = QFileDialog::getSaveFileName(NULL, \"Save Error Log\", QString(), \"Text (*.txt);;All Files (*)\");\n        if (fileName.isEmpty()) {\n            return;\n        } else {\n            QFile file(fileName);\n            if (!file.open(QIODevice::WriteOnly)) {\n                QMessageBox::information(NULL, \"Unable to open file\", file.errorString());\n                return;\n            }\n            QTextStream out(&file);\n            out << QString(_logText.c_str());\n        }\n    } else if (ErrorReporterPopup_OK_BUTTON_TEXT == button->text().toStdString()) {\n    } else {\n        printf(\"Unknown ErrorReporterPopup button pressed: [%s]\\n\", button->text().toStdString().c_str());\n    }\n    if (fatal) exit(1);\n}\n\nvoid ErrorReporterPopup::setLogText(std::string text) { _logText = text; }\n\nvoid ErrorReporter::ShowErrors() { Report(ERRORREPORTER_DEFAULT_MESSAGE); }\n\nvoid ErrorReporter::Report(string msg, Type severity, string details)\n{\n    ErrorReporter *e = GetInstance();\n    if (e->_logFile) { fprintf(e->_logFile, \"Report[%i]: %s\\n%s\\n\", (int)severity, msg.c_str(), details.c_str()); }\n\n    for (int i = 0; i < e->_boxes.size(); i++) {\n        if (e->_boxes[i]->isDead()) {\n            delete e->_boxes[i];\n            e->_boxes.erase(e->_boxes.begin() + i);\n            i--;\n        }\n    }\n\n    static int          i = 0;\n    ErrorReporterPopup *box = new ErrorReporterPopup(e->_parent, i++, severity == Fatal);\n    e->_boxes.push_back(box);\n    box->setInformativeText(msg.c_str());\n\n    if (details == \"\") {\n        while (e->_log.size()) {\n            details += e->_log.back().value + \"\\n\";\n            if (e->_log.back().type > severity) severity = e->_log.back().type;\n            e->_log.pop_back();\n        }\n    }\n\n    const string sysInfo = GetSystemInformation();\n    details += \"------------------\\n\";\n    details += sysInfo + \"\\n\";\n\n    box->setDetailedText(details.c_str());\n\n    switch (severity) {\n    case Diagnostic:\n    case Info: box->setIcon(QMessageBox::Information); break;\n    case Warning: box->setIcon(QMessageBox::Warning); break;\n    case Fatal:\n    case Error: box->setIcon(QMessageBox::Critical); break;\n    }\n\n    string logText;\n    logText = sysInfo + \"\\n\";\n    logText += \"-------------------\\n\";\n    logText += msg + \"\\n\";\n    logText += \"-------------------\\n\";\n    logText += details;\n    box->setLogText(logText);\n\n    box->show();    // This will immediately return\n}\n\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\nstring                 ErrorReporter::GetSystemInformation()\n{\n    string ret = \"Vapor \" + Wasp::Version::GetFullVersionString() + \"\\n\";\n#if defined(Darwin)\n    SInt32 major, minor, rev;\n    Gestalt(gestaltSystemVersionMajor, &major);\n    Gestalt(gestaltSystemVersionMinor, &minor);\n    Gestalt(gestaltSystemVersionBugFix, &rev);\n    ret += \"OS: Mac OS X \" + to_string(major) + \".\" + to_string(minor) + \".\" + to_string(rev) + \"\\n\";\n#elif defined(linux)\n    struct utsname info;\n    uname(&info);\n    ret += \"OS: \" + string(info.sysname) + \" \" + string(info.release) + \" \" + string(info.version) + \"\\n\";\n    ret += \"Distro:\\n\";\n    char  buffer[128];\n    FILE *pipe = popen(\"lsb_release\", \"r\");\n    if (pipe) {\n        while (!feof(pipe)) {\n            if (fgets(buffer, 128, pipe) != 0) { ret += string(buffer); }\n        }\n        pclose(pipe);\n    } else {\n        fprintf(stderr, \"popen failed\\n\");\n    }\n#elif defined(WIN32)\n    DWORD version = 0;\n    DWORD major = 0;\n    DWORD minor = 0;\n    DWORD build = 0;\n\n    version = GetVersion();\n\n    major = (DWORD)(LOBYTE(LOWORD(version)));\n    minor = (DWORD)(HIBYTE(LOWORD(version)));\n\n    if (version < 0x80000000) { build = (DWORD)(HIWORD(version)); }\n\n    ret += \"OS: Windows \" + to_string(major) + \".\" + to_string(minor) + \" (\" + to_string(build) + \")\\n\";\n#else\n    return \"Unsupported Platform\";\n#endif\n    return ret;\n}\n#pragma GCC diagnostic pop\n\nint ErrorReporter::OpenLogFile(std::string path)\n{\n    ErrorReporter *e = ErrorReporter::GetInstance();\n    e->_logFilePath = path;\n    e->_logFile = fopen(path.c_str(), \"w\");\n\n    if (!e->_logFile) {\n        Wasp::MyBase::SetErrMsg(errno, \"Failed to open log file \\\"%s\\\"\", path.c_str());\n        return -1;\n    }\n    return 0;\n}\n\nErrorReporter *ErrorReporter::GetInstance()\n{\n    if (!_instance)\n        _instance = new ErrorReporter(MainForm::Instance());\n    return _instance;\n}\n\nErrorReporter::ErrorReporter(QWidget *parent)\n{\n    VAssert(parent != NULL);\n\n    if (_instance) return;\n\n    _parent = parent;\n    _instance = this;\n    signal(SIGSEGV, _segFaultHandler);\n    Wasp::MyBase::SetErrMsgCB(_myBaseErrorCallback);\n    Wasp::MyBase::SetDiagMsgCB(_myBaseDiagCallback);\n\n    _logFilePath = \"\";\n    _logFile = NULL;\n}\n\nErrorReporter::~ErrorReporter()\n{\n    if (_logFile) fclose(_logFile);\n\n    for (int i = 0; i < _boxes.size(); i++) delete _boxes[i];\n}\n"
  },
  {
    "path": "apps/vaporgui/ErrorReporter.h",
    "content": "//************************************************************************\n//                                                                       *\n//                        Copyright (C)  2017                            *\n//           University Corporation for Atmospheric Research             *\n//                        All Rights Reserved                            *\n//                                                                       *\n//************************************************************************\n//\n//\tFile:\t\t\tErrorReporter.h\n//\n//\tAuthor:\t\t\tStas Jaroszynski (stasj@ucar.edu)\n//\t\t\t\t\tNational Center for Atmospheric Research\n//\t\t\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\t\tJuly 2017\n//\n//\tDescription:\tDefines the ErrorReporting class.  This is used for\n//\tposting various messages that can occur during the operation of the Vapor GUI\n//  This is a singleton class that registers callbacks with the Vapor error api\n//  and keeps tracks of errors that occur. The GUI can then invoke an error message\n//  which will display the GUI provided message and provide a details area which\n//  contains the full error log accumilated since the last error message  which can\n//  be saved to a text file.\n//  This class also registeres a signal handler for SIGSEGV and displays an error\n//  window with the current backtrace.\n\n#ifndef ERRORREPORTER_H\n#define ERRORREPORTER_H\n\n#include <string>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <QMessageBox>\n\n//! \\class ErrorReporterPopup\n//! \\ingroup Public_GUI\n//! \\brief A helper class for ErrorReporter that is neccessary because the Qt gui is in a separate thread\n//! \\author Stas Jaroszynski\n//! \\version 1.0\n//! \\date May 2018\n\nclass ErrorReporterPopup : public QMessageBox {\n    Q_OBJECT;\n\npublic:\n    ErrorReporterPopup(QWidget *parent, int id, bool fatal = false);\n    void setLogText(std::string text);\n    bool isDead() const { return dead; };\n\nprivate slots:\n    void doAction(QAbstractButton *button);\n\nprivate:\n    bool        dead, fatal;\n    std::string _logText;\n};\n\n#define ERRORREPORTER_DEFAULT_MESSAGE \"The action failed\"\n\n//! \\class ErrorReporter\n//! \\ingroup Public_GUI\n//! \\brief A utility singleton class that provides error reporting functinality\n//! \\author Stas Jaroszynski\n//! \\version 3.0\n//! \\date July 2017\n\n//! ErrorReporter class provides error reporting functionality. Registers error\n//! callbacks with MyBase and registers signal handler for SIGSEGV\n\n#define MSG_ERR(M) (ErrorReporter::GetInstance()->Report(M, ErrorReporter::Error))\n\n#define MSG_WARN(M) (ErrorReporter::GetInstance()->Report(M, ErrorReporter::Warning))\n\n#define MSG_DIAG(M) (ErrorReporter::GetInstance()->Report(M, ErrorReporter::Diagnostic))\n\n#define MSG_FATAL(M) (ErrorReporter::GetInstance()->Report(M, ErrorReporter::Fatal))\n\nclass ErrorReporter {\npublic:\n    enum Type { Diagnostic = 0, Info = 1, Warning = 2, Error = 3, Fatal = 4 };\n\n    struct Message {\n        Type        type;\n        std::string value;\n        int         err_code;\n\n        Message(Type type_, std::string value_, int err_code_ = 0) : type(type_), value(value_), err_code(err_code_) {}\n    };\n\n    ErrorReporter(QWidget *parent);\n\n    //! Returns the singleton instance of this class with lazy initialization\n    //! \\retval ErrorReporter instance\n    static ErrorReporter *GetInstance();\n\n    //! Displays the current log of errors with the default message ERRORREPORTER_DEFAULT_MESSAGE\n    static void ShowErrors();\n\n    //! Displays an error message with the log of errors and outputs the message to the log file\n    //! \\param string msg to display explaining error cause/implications\n    //! \\param Type severity of message\n    //! \\param string details of error. Default to current erros in log\n    static void Report(std::string msg, Type severity = Diagnostic, std::string details = \"\");\n\n    //! Returns basic system OS information\n    //! \\retval string containing OS information\n    static std::string GetSystemInformation();\n\n    //! Opens log file and begins logging error and diagnostic messages\n    //! \\retval int returns -1 on failure\n    static int OpenLogFile(std::string path);\n\nprotected:\n    ~ErrorReporter();\n\nprivate:\n    ErrorReporter();\n    static ErrorReporter *            _instance;\n    std::vector<Message>              _log;\n    std::vector<Message>              _fullLog;\n    std::string                       _logFilePath;\n    FILE *                            _logFile;\n    QWidget *                         _parent;\n    std::vector<ErrorReporterPopup *> _boxes;\n\n    friend void _myBaseErrorCallback(const char *msg, int err_code);\n    friend void _myBaseDiagCallback(const char *msg);\n};\n\n#endif\n"
  },
  {
    "path": "apps/vaporgui/ExportTab.cpp",
    "content": "#include \"ExportTab.h\"\n#include \"PCheckbox.h\"\n#include \"PIntegerInput.h\"\n#include \"PSliderEdit.h\"\n#include \"PCameraControlsSection.h\"\n#include \"POutputResolutionSection.h\"\n#include \"PTimestepSliderEdit.h\"\n#include \"PTotalTimestepsDisplay.h\"\n#include \"PCaptureWidget.h\"\n#include \"PMovingDomainSettings.h\"\n#include \"CaptureController.h\"\n#include <vapor/AnimationParams.h>\n#include <QLayout>\n\nExportTab::ExportTab(ControlExec *ce, CaptureController *captureController) : _ce(ce)\n{\n    _pg = new PGroup({\n        new PCaptureWidget(_ce, captureController),\n        new POutputResolutionSection(_ce),\n        new PCameraControlsSection(_ce),\n        _movingDomainSection = new PMovingDomainSettings(_ce),\n        new PGroup({\n            new PSection(\"Animation\", {\n                new PTimestepSliderEdit(_ce),\n                new PTotalTimestepsDisplay(_ce),\n            })\n        })\n    });\n\n    layout()->addWidget(_pg);\n}\n\nvoid ExportTab::Update()\n{\n    if (_pg) _pg->Update(_ce->GetParams<AnimationParams>());\n}\n"
  },
  {
    "path": "apps/vaporgui/ExportTab.h",
    "content": "#pragma once\n\n#include \"VaporFwd.h\"\n#include \"PWidgetsFwd.h\"\n#include \"Updatable.h\"\n#include \"VGroup.h\"\n\nclass CaptureController;\n\nclass ExportTab : public VGroup, public Updatable {\n    Q_OBJECT\n\n    ControlExec *_ce;\n    PWidget *_pg = nullptr;\n    PWidget *_movingDomainSection = nullptr;\n\npublic:\n    ExportTab(VAPoR::ControlExec *ce, CaptureController *captureController);\n    void Update() override;\n};\n"
  },
  {
    "path": "apps/vaporgui/FidelityWidget.cpp",
    "content": "//*************************************************************************\n//                                                                        *\n//           Copyright (C)  2015                                          *\n//   University Corporation for Atmospheric Research                      *\n//           All Rights Reserved                                          *\n//                                                                        *\n//************************************************************************/\n//\n//  File:       FidelityWidget.cpp\n//\n//      Author: John Clyne\n//          Scott Pearse\n//          Alan Norton\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:       December 2017\n//\n//  Description:    Implements the FidelityWidget class.\n//\n#include <sstream>\n#include <qwidget.h>\n#include <QFileDialog>\n#include <QDesktopWidget>\n#include <QButtonGroup>\n#include <qradiobutton.h>\n#include <qcolordialog.h>\n#include \"vapor/RenderParams.h\"\n#include \"vapor/ParamsMgr.h\"\n#include \"vapor/DataMgr.h\"\n#include \"FidelityWidget.h\"\n\nusing namespace VAPoR;\n\nFidelityWidget::FidelityWidget(QWidget *parent) : QWidget(parent), Ui_FidelityWidgetGUI()\n{\n    setupUi(this);\n\n    _fidelityButtons = new QButtonGroup(fidelityBox);\n    _fidelityButtons->setExclusive(true);\n\n    QHBoxLayout *hlay = new QHBoxLayout(fidelityBox);\n    hlay->setAlignment(Qt::AlignHCenter);\n    fidelityBox->setLayout(hlay);\n\n    int dpi = qApp->desktop()->logicalDpiX();\n    if (dpi > 96) fidelityFrame->setMinimumHeight(100);\n\n    connect(refinementCombo, SIGNAL(activated(int)), this, SLOT(setNumRefinements(int)));\n    connect(lodCombo, SIGNAL(activated(int)), this, SLOT(setCompRatio(int)));\n    connect(fidelityDefaultButton, SIGNAL(clicked()), this, SLOT(SetFidelityDefault()));\n    connect(_fidelityButtons, SIGNAL(buttonClicked(int)), this, SLOT(setFidelity(int)));\n}\n\nvoid FidelityWidget::setNumRefinements(int num)\n{\n    VAssert(_rParams);\n\n    _rParams->SetRefinementLevel(num);\n\n    // Fidelity settings no longer valid\n    //\n    uncheckFidelity();\n}\n\n// Occurs when user clicks a fidelity radio button\n//\nvoid FidelityWidget::setFidelity(int buttonID)\n{\n    VAssert(_rParams);\n\n    VAssert(buttonID >= 0 && buttonID < _fidelityLodIdx.size());\n\n    int lod = _fidelityLodIdx[buttonID];\n    int ref = _fidelityMultiresIdx[buttonID];\n\n    _paramsMgr->BeginSaveStateGroup(\"Set variable fidelity\");\n    _rParams->SetCompressionLevel(lod);\n    _rParams->SetRefinementLevel(ref);\n\n    _paramsMgr->EndSaveStateGroup();\n\n    // Need to update the GUI\n    //\n    lodCombo->setCurrentIndex(lod);\n    refinementCombo->setCurrentIndex(ref);\n}\n\nQButtonGroup *FidelityWidget::GetFidelityButtons() { return _fidelityButtons; }\n\nstd::vector<int> FidelityWidget::GetFidelityLodIdx() const { return _fidelityLodIdx; }\n\n// User clicks on SetDefault button, need to make current\n// fidelity settings the default.\n\nvoid FidelityWidget::SetFidelityDefault()\n{\n#ifdef VAPOR3_0_0_ALPHA\n    // Check current values of LOD and refinement and their combos.\n    _dataStatus->setFidelityDefault(rParams);\n    StartupParams *sParams = (StartupParams *)_paramsMgr->GetDefaultParams(StartupParams::_startupParamsTag);\n    _controlExec->SavePreferences(sParams->GetCurrentPrefsPath());\n    updateTab(rParams);\n#endif\n}\n\nvoid FidelityWidget::getCmpFactors(string varname, vector<float> &lodCF, vector<string> &lodStr, vector<float> &multiresCF, vector<string> &multiresStr) const\n{\n    VAssert(!varname.empty());\n\n    lodCF.clear();\n    lodStr.clear();\n    multiresCF.clear();\n    multiresStr.clear();\n\n    int numLevels = _dataMgr->GetNumRefLevels(varname);\n\n    // First get compression factors that are based on grid multiresolution\n    //\n\n    // Compute sorted list of number of grids points\n    // at each level in multiresolution hierarchy\n    //\n    vector<size_t> nGridPts;\n    for (int l = 0; l < numLevels; l++) {\n        vector<size_t> dims_at_level;\n        int            rc = _dataMgr->GetDimLensAtLevel(varname, l, dims_at_level, -1);\n        VAssert(rc >= 0);\n\n        size_t        n = 1;\n        ostringstream oss;\n        oss << l << \" (\";\n        for (int j = 0; j < dims_at_level.size(); j++) {\n            n *= dims_at_level[j];\n\n            oss << dims_at_level[j];\n            if (j < dims_at_level.size() - 1) oss << \"x\";\n        }\n        nGridPts.push_back(n);\n\n        oss << \")\";\n        multiresStr.push_back(oss.str());\n    }\n\n    for (int i = 0; i < nGridPts.size() - 1; i++) {\n        float cf = 1.0 / (nGridPts[nGridPts.size() - 1] / nGridPts[i]);\n        multiresCF.push_back(cf);\n    }\n    multiresCF.push_back(1.0);\n\n    // Now get the \"levels of detail\" compression factors\n    //\n    vector<size_t> cratios = _dataMgr->GetCRatios(varname);\n\n    for (int i = 0; i < cratios.size(); i++) {\n        ostringstream oss;\n        lodCF.push_back((float)1.0 / cratios[i]);\n\n        oss << i << \" (\" << cratios[i] << \":1)\";\n        lodStr.push_back(oss.str());\n    }\n}\n\nvoid FidelityWidget::uncheckFidelity()\n{\n    // Unset all fidelity buttons\n    //\n    if (!_fidelityButtons) return;\n\n    QList<QAbstractButton *> btns = _fidelityButtons->buttons();\n    for (int i = 0; i < btns.size(); i++) {\n        if (btns[i]->isChecked()) { btns[i]->setChecked(false); }\n    }\n}\n\nvoid FidelityWidget::setCompRatio(int num)\n{\n    VAssert(_rParams);\n\n    _rParams->SetCompressionLevel(num);\n\n    lodCombo->setCurrentIndex(num);\n\n    // Fidelity no longer valid\n    //\n    uncheckFidelity();\n}\n\nvoid FidelityWidget::Update(const DataMgr *dataMgr, ParamsMgr *paramsMgr, RenderParams *rParams)\n{\n    VAssert(dataMgr);\n    VAssert(paramsMgr);\n    VAssert(rParams);\n\n    _dataMgr = dataMgr;\n    _paramsMgr = paramsMgr;\n    _rParams = rParams;\n\n    string varname;\n    if (_variableFlags & SCALAR) {\n        varname = _rParams->GetVariableName();\n    } else if (_variableFlags & VECTOR) {\n        vector<string> varnames = _rParams->GetFieldVariableNames();\n        if (varnames.size() > 0) {\n            varname = varnames[0];\n            size_t vardim;\n            for (int i = 0; i < varnames.size(); i++) {\n                vardim = _dataMgr->GetNumDimensions(varnames[i]);\n                if (vardim == 3) {\n                    varname = varnames[i];\n                    break;\n                }\n            }\n        }\n    } else if (_variableFlags & HEIGHT) {\n        varname = _rParams->GetHeightVariableName();\n    } else if (_variableFlags & AUXILIARY) {\n        vector<string> varnames = _rParams->GetAuxVariableNames();\n        if (varnames.size() > 0) {\n            varname = varnames[0];\n            size_t vardim;\n            for (int i = 0; i < varnames.size(); i++) {\n                vardim = _dataMgr->GetNumDimensions(varnames[i]);\n                if (vardim == 3) {\n                    varname = varnames[i];\n                    break;\n                }\n            }\n        }\n    } else if (_variableFlags & COLOR) {\n        varname = _rParams->GetColorMapVariableName();\n    }\n\n    if (varname.empty()) {\n        fidelityTab->setEnabled(false);\n        return;\n    }\n\n    fidelityTab->setEnabled(true);\n    fidelityTab->show();\n\n    vector<size_t> cratios = _dataMgr->GetCRatios(varname);\n\n    // Get the effective compression rates as a floating point value,\n    // and as a string that can be displayed, for the LOD and refinement\n    // control\n    //\n    vector<float>  lodCFs, multiresCFs;\n    vector<string> lodStrs, multiresStrs;\n    getCmpFactors(varname, lodCFs, lodStrs, multiresCFs, multiresStrs);\n\n    int lodReq = _rParams->GetCompressionLevel();\n    int refLevelReq = _rParams->GetRefinementLevel();\n\n    int lod = lodReq < 0 ? 0 : lodReq;\n    lod = lodReq >= lodCFs.size() ? lodCFs.size() - 1 : lodReq;\n\n    int refLevel = refLevelReq < 0 ? 0 : refLevelReq;\n    refLevel = refLevelReq >= multiresCFs.size() ? multiresCFs.size() - 1 : refLevelReq;\n\n    // set up the refinement and LOD combos\n    //\n    lodCombo->blockSignals(true);\n    lodCombo->clear();\n    for (int i = 0; i < lodStrs.size(); i++) {\n        QString s = QString::fromStdString(lodStrs[i]);\n        lodCombo->addItem(s);\n    }\n    lodCombo->setCurrentIndex(lod);\n    _currentLodStr = lodStrs.at(lod);\n    lodCombo->blockSignals(false);\n\n    refinementCombo->blockSignals(true);\n    refinementCombo->clear();\n    for (int i = 0; i < multiresStrs.size(); i++) { refinementCombo->addItem(QString(multiresStrs[i].c_str())); }\n    refinementCombo->setCurrentIndex(refLevel);\n    _currentMultiresStr = multiresStrs.at(refLevel);\n    refinementCombo->blockSignals(false);\n\n    if (lodReq != lod) { _rParams->SetCompressionLevel(lod); }\n    if (refLevelReq != refLevel) { _rParams->SetRefinementLevel(refLevel); }\n\n    fidelityBox->adjustSize();\n\n    // Linearize the LOD and refinement compression ratios so that\n    // when combined they increase (decrease) monotonically\n    //\n    _fidelityLodIdx.clear();\n    _fidelityMultiresIdx.clear();\n    _fidelityLodStrs.clear();\n    _fidelityMultiresStrs.clear();\n\n    int l = 0;\n    int m = 0;\n    do {\n        _fidelityLodIdx.push_back(l);\n        _fidelityMultiresIdx.push_back(m);\n\n        _fidelityLodStrs.push_back(lodStrs[l]);\n        _fidelityMultiresStrs.push_back(multiresStrs[m]);\n\n        if (lodCFs[l] < multiresCFs[m]) {\n            l++;\n        } else {\n            m++;\n        }\n    } while (l < lodCFs.size() && m < multiresCFs.size());\n\n    _fidelityButtons->blockSignals(true);\n    // Remove buttons from the group\n    //\n    QList<QAbstractButton *> btns = _fidelityButtons->buttons();\n    for (int i = 0; i < btns.size(); i++) { _fidelityButtons->removeButton(btns[i]); }\n\n    // Remove and delete buttons from the layout\n    //\n    QHBoxLayout *hlay = (QHBoxLayout *)fidelityBox->layout();\n    QLayoutItem *child;\n    while ((child = hlay->takeAt(0)) != 0) {\n        delete child->widget();\n        delete child;\n    }\n\n    int numButtons = _fidelityLodStrs.size();\n    for (int i = 0; i < numButtons; i++) {\n        QRadioButton *rd = new QRadioButton();\n        hlay->addWidget(rd);\n\n        _fidelityButtons->addButton(rd, i);\n        QString qs = \"Refinement \" + QString::fromStdString(_fidelityMultiresStrs[i]) + \"\\nLOD \" + QString::fromStdString(_fidelityLodStrs[i]);\n\n        rd->setToolTip(qs);\n\n        if (lod == _fidelityLodIdx[i] && refLevel == _fidelityMultiresIdx[i]) { rd->setChecked(true); }\n    }\n    _fidelityButtons->blockSignals(false);\n}\n\nstd::string FidelityWidget::GetCurrentLodString() const { return _currentLodStr; }\n\nstd::string FidelityWidget::GetCurrentMultiresString() const { return _currentMultiresStr; }\n"
  },
  {
    "path": "apps/vaporgui/FidelityWidget.h",
    "content": "#ifndef FIDELITYWIDGET_H\n#define FIDELITYWIDGET_H\n\n#include <QObject>\n#include \"vapor/MyBase.h\"\n#include \"ui_FidelityWidgetGUI.h\"\n#include \"Flags.h\"\n\nQT_USE_NAMESPACE\n\nnamespace VAPoR {\nclass RenderParams;\nclass ParamsMgr;\nclass DataMgr;\n}    // namespace VAPoR\n\nclass RenderEventRouter;\n\n//!\n//! \\class FidelityWidget\n//! \\ingroup Public_GUI\n//! \\brief A Widget that can be reused to provide fidelity\n//! selection in any renderer EventRouter class\n//! \\author Scott Pearse\n//! \\version 3.0\n//! \\date  December 2017\n\nclass FidelityWidget : public QWidget, public Ui_FidelityWidgetGUI {\n    Q_OBJECT\n\npublic:\n    FidelityWidget(QWidget *parent);\n\n    void Reinit(VariableFlags variableFlags) { _variableFlags = variableFlags; }\n\n    virtual void Update(const VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams);\n\n    QButtonGroup *   GetFidelityButtons();\n    std::vector<int> GetFidelityLodIdx() const;\n\n    std::string GetCurrentLodString() const;\n    std::string GetCurrentMultiresString() const;\n\nprotected slots:\n    //! Connected to the image file text editor\n    void setNumRefinements(int num);\n\n    //! Connected to the compression ratio selector, setting the lod index.\n    void setCompRatio(int num);\n\n    //! Connected to the fidelity button selector, setting the fidelity index.\n    void setFidelity(int buttonID);\n\n    //! Connected to the fidelity setDefault button, setting current\n    //! fidelity as default\n    void SetFidelityDefault();\n\nprivate:\n    VariableFlags         _variableFlags;\n    const VAPoR::DataMgr *_dataMgr;\n    VAPoR::ParamsMgr *    _paramsMgr;\n    VAPoR::RenderParams * _rParams;\n\n    // Get the compression rates as a fraction for both the LOD and\n    // Refinment parameters. Also format these factors into a displayable\n    // string\n    //\n    void getCmpFactors(string varname, vector<float> &lodCF, vector<string> &lodStr, vector<float> &multiresCF, vector<string> &multiresStr) const;\n\n    void uncheckFidelity();\n\n    void setupFidelity(VAPoR::RenderParams *dParams);\n\n    QButtonGroup *_fidelityButtons;\n\n    // Support for fidelity settings\n    //\n    std::vector<int>    _fidelityLodIdx;\n    std::vector<int>    _fidelityMultiresIdx;\n    std::vector<string> _fidelityLodStrs;\n    std::vector<string> _fidelityMultiresStrs;\n    std::string         _currentLodStr;\n    std::string         _currentMultiresStr;\n};\n\n#endif    // FIDELITYWIDGET_H\n"
  },
  {
    "path": "apps/vaporgui/FidelityWidgetGUI.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>FidelityWidgetGUI</class>\n <widget class=\"QWidget\" name=\"FidelityWidgetGUI\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>421</width>\n    <height>187</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n   <property name=\"spacing\">\n    <number>0</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>0</number>\n   </property>\n   <item>\n    <widget class=\"QTabWidget\" name=\"fidelityTab\">\n     <property name=\"currentIndex\">\n      <number>0</number>\n     </property>\n     <widget class=\"QWidget\" name=\"tab\">\n      <attribute name=\"title\">\n       <string>Data Fidelity</string>\n      </attribute>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n       <property name=\"spacing\">\n        <number>0</number>\n       </property>\n       <property name=\"leftMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"topMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"rightMargin\">\n        <number>0</number>\n       </property>\n       <property name=\"bottomMargin\">\n        <number>0</number>\n       </property>\n       <item>\n        <widget class=\"QFrame\" name=\"fidelityFrame\">\n         <property name=\"frameShape\">\n          <enum>QFrame::NoFrame</enum>\n         </property>\n         <property name=\"frameShadow\">\n          <enum>QFrame::Raised</enum>\n         </property>\n         <layout class=\"QHBoxLayout\" name=\"horizontalLayout_4\">\n          <property name=\"topMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"bottomMargin\">\n           <number>0</number>\n          </property>\n          <item>\n           <widget class=\"QLabel\" name=\"label\">\n            <property name=\"statusTip\">\n             <string>Select either contours of 3D or 2D variables</string>\n            </property>\n            <property name=\"text\">\n             <string>Fidelity</string>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <spacer name=\"horizontalSpacer\">\n            <property name=\"orientation\">\n             <enum>Qt::Horizontal</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>197</width>\n              <height>20</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n          <item>\n           <widget class=\"QGroupBox\" name=\"fidelityBox\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>0</width>\n              <height>55</height>\n             </size>\n            </property>\n            <property name=\"whatsThis\">\n             <string>The fidelity setting controls both refinement levels and level of detail (LOD).  Click on the &quot;Set Default Fidelity&quot; button to establish a fidelity level that is interactive on the current platform.</string>\n            </property>\n            <property name=\"title\">\n             <string>low &lt; - - - &gt; high</string>\n            </property>\n            <property name=\"alignment\">\n             <set>Qt::AlignCenter</set>\n            </property>\n           </widget>\n          </item>\n         </layout>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QFrame\" name=\"frame_2\">\n         <property name=\"frameShape\">\n          <enum>QFrame::NoFrame</enum>\n         </property>\n         <property name=\"frameShadow\">\n          <enum>QFrame::Raised</enum>\n         </property>\n         <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n          <property name=\"topMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"bottomMargin\">\n           <number>0</number>\n          </property>\n          <item>\n           <widget class=\"QLabel\" name=\"label_2\">\n            <property name=\"text\">\n             <string>Level of Detail</string>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <spacer name=\"horizontalSpacer_2\">\n            <property name=\"orientation\">\n             <enum>Qt::Horizontal</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>139</width>\n              <height>20</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n          <item>\n           <widget class=\"QComboBox\" name=\"lodCombo\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>150</width>\n              <height>0</height>\n             </size>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify the approximation level (compression) for the data being used to calculate contour lines.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"whatsThis\">\n             <string>The refinement level parameter and (in the case of VDC2 data) the level of detail (LOD) parameter control the quality of the approximation used when visualizing a variable.  The Refinement parameter selects the grid resolutiion.  Coarser resolutions require less memory (RAM); less computation by the visualization algorithms; and for VDC1 data, less storage space on disk, therefore less time to read the data.  For VDC2 data the Refinement level has no impact on disk storage.  The LOD parameter, which is only available for VDC2 data sets, selects a compression level.  Variables with greater compression require less disk storage and can thus be read from disk by vaporgui more quickly, but have no impact on memory  (RAM) or computation time required by the visualziation algorithms.  For both LOD and Refinement, level 0 corresponds to the coarsest approximation available.</string>\n            </property>\n           </widget>\n          </item>\n         </layout>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QFrame\" name=\"frame_3\">\n         <property name=\"frameShape\">\n          <enum>QFrame::NoFrame</enum>\n         </property>\n         <property name=\"frameShadow\">\n          <enum>QFrame::Raised</enum>\n         </property>\n         <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n          <property name=\"topMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"bottomMargin\">\n           <number>0</number>\n          </property>\n          <item>\n           <widget class=\"QLabel\" name=\"label_3\">\n            <property name=\"text\">\n             <string>Refinement Level</string>\n            </property>\n           </widget>\n          </item>\n          <item>\n           <spacer name=\"horizontalSpacer_3\">\n            <property name=\"orientation\">\n             <enum>Qt::Horizontal</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>121</width>\n              <height>20</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n          <item>\n           <widget class=\"QComboBox\" name=\"refinementCombo\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>150</width>\n              <height>0</height>\n             </size>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select the refinement level (resolution) of the data used to calculate contour lines.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"whatsThis\">\n             <string>The refinement level parameter and (in the case of VDC2 data) the level of detail (LOD) parameter control the quality of the approximation used when visualizing a variable.  The Refinement parameter selects the grid resolutiion.  Coarser resolutions require less memory (RAM); less computation by the visualization algorithms; and for VDC1 data, less storage space on disk, therefore less time to read the data.  For VDC2 data the Refinement level has no impact on disk storage.  The LOD parameter, which is only available for VDC2 data sets, selects a compression level.  Variables with greater compression require less disk storage and can thus be read from disk by vaporgui more quickly, but have no impact on memory  (RAM) or computation time required by the visualziation algorithms.  For both LOD and Refinement, level 0 corresponds to the coarsest approximation available.</string>\n            </property>\n           </widget>\n          </item>\n         </layout>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QFrame\" name=\"frame_4\">\n         <property name=\"frameShape\">\n          <enum>QFrame::NoFrame</enum>\n         </property>\n         <property name=\"frameShadow\">\n          <enum>QFrame::Raised</enum>\n         </property>\n         <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n          <property name=\"topMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"bottomMargin\">\n           <number>0</number>\n          </property>\n          <item>\n           <spacer name=\"horizontalSpacer_4\">\n            <property name=\"orientation\">\n             <enum>Qt::Horizontal</enum>\n            </property>\n            <property name=\"sizeHint\" stdset=\"0\">\n             <size>\n              <width>231</width>\n              <height>20</height>\n             </size>\n            </property>\n           </spacer>\n          </item>\n          <item>\n           <widget class=\"QPushButton\" name=\"fidelityDefaultButton\">\n            <property name=\"minimumSize\">\n             <size>\n              <width>155</width>\n              <height>0</height>\n             </size>\n            </property>\n            <property name=\"toolTip\">\n             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Click to set default Fidelity to current LOD and refinement levels.  The default can optionally be saved in user preferences.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\n            </property>\n            <property name=\"whatsThis\">\n             <string>The fidelity setting controls both refinement levels and level of detail (LOD).  Click on the &quot;Set Default Fidelity&quot; button to establish a fidelity level that is interactive on the current platform.</string>\n            </property>\n            <property name=\"text\">\n             <string>Default</string>\n            </property>\n           </widget>\n          </item>\n         </layout>\n        </widget>\n       </item>\n      </layout>\n     </widget>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "apps/vaporgui/FileOperationChecker.cpp",
    "content": "#include <QFileInfo>\n#include \"FileOperationChecker.h\"\n\nQString FileOperationChecker::_message(\"\");\n\nbool FileOperationChecker::DirectoryGoodToRead(const QString &filename)\n{\n    QFileInfo fileInfo(filename);\n\n    // Test if this filename exists\n    if (!fileInfo.exists()) {\n        QString msg(\" The following input does not exist! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    // Test if this is a directory\n    if (!fileInfo.isDir()) {\n        QString msg(\" The following input is NOT a directory! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    // Test if this directory is readable\n    if (!fileInfo.isReadable()) {\n        QString msg(\" The following input is NOT readable! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    // Test if this directory is executable\n    if (!fileInfo.isExecutable()) {\n        QString msg(\" The following input is NOT executable! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    return true;\n}\n\nbool FileOperationChecker::FileGoodToRead(const QString &filename)\n{\n    QFileInfo fileInfo(filename);\n\n    // Test if this filename exists\n    if (!fileInfo.exists()) {\n        QString msg(\" The following input does not exist! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    // Test if this is a file\n    if (!fileInfo.isFile()) {\n        QString msg(\" The following input is NOT a file! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    // Test if this file is readable\n    if (!fileInfo.isReadable()) {\n        QString msg(\" The following input is NOT readable! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    return true;\n}\n\nbool FileOperationChecker::FileGoodToWrite(const QString &filename)\n{\n    QFileInfo fileInfo(filename);\n\n    // In case this file does not exist\n    if (!fileInfo.exists()) {\n        std::FILE *f = std::fopen(filename.toLatin1(), \"w\");\n        if (f)    // able to write\n        {\n            std::fclose(f);\n            std::remove(filename.toLatin1());\n            return true;\n        } else {\n            QString msg(\" The following file cannot be created! \\n\");\n            msg += filename;\n            _message = msg;\n            return false;\n        }\n    }\n\n    // The input exists when the program reaches here\n\n    // Test if this is a file\n    if (!fileInfo.isFile()) {\n        QString msg(\" The following is NOT a file! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    // Test if this file is readable\n    if (!fileInfo.isReadable()) {\n        QString msg(\" The following file is NOT readable! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    // Test if this file is writable\n    if (!fileInfo.isWritable()) {\n        QString msg(\" The following file is NOT writable! \\n\");\n        msg += filename;\n        _message = msg;\n        return false;\n    }\n\n    return true;\n}\n\nbool FileOperationChecker::FileHasCorrectSuffix(const QString &filename, const QString &expectedSuffix)\n{\n    QFileInfo fileInfo(filename);\n    if (fileInfo.suffix().compare(expectedSuffix) == 0)\n        return true;\n    else {\n        QString msg(\" The following input does NOT have the expected suffix: \");\n        msg += expectedSuffix;\n        msg += \"\\n\";\n        msg += filename;\n        _message = msg;\n\n        return false;\n    }\n}\n\nQString FileOperationChecker::GetLastErrorMessage() { return _message; }\n"
  },
  {
    "path": "apps/vaporgui/FileOperationChecker.h",
    "content": "/*\n * This class provides a set of functions that check if a file/directory\n * is good to read/write.\n *\n * The rational is recorded in this post:\n * https://github.com/NCAR/VAPOR/wiki/Robust-File-Operations-with-VAPOR-and-Qt\n *\n */\n\n#ifndef FILEOPERATIONCHECKER_H\n#define FILEOPERATIONCHECKER_H\n\n#include <QString>\n\nclass FileOperationChecker {\npublic:\n    static bool    DirectoryGoodToRead(const QString &filename);\n    static bool    FileGoodToRead(const QString &filename);\n    static bool    FileGoodToWrite(const QString &filename);\n    static bool    FileHasCorrectSuffix(const QString &filename, const QString &expectedSuffix);\n    static QString GetLastErrorMessage();\n\nprivate:\n    static QString _message;\n};\n\n#endif\n"
  },
  {
    "path": "apps/vaporgui/Flags.h",
    "content": "#ifndef FLAGS_H\n#define FLAGS_H\n\n//! Bit masks to indicate what type of variables are to be supported by\n//! a particular VariablesWidget instance. These flags correspond\n//! to variable names returned by methods:\n//!\n//! SCALAR : RenderParams::GetVariableName()\n//! VECTOR : RenderParams::GetFieldVariableNames()\n//! HGT : RenderParams::GetHeightVariableName()\n//! COLOR : RenderParams::GetColorMapVariableNames()\n//!\n\nenum VariableFlags {\n    SCALAR = (1u << 0),\n    VECTOR = (1u << 1),\n    COLOR = (1u << 2),\n    AUXILIARY = (1u << 3),\n    HEIGHT = (1u << 4),\n};\n\n//! Bit mask to indicate whether 2D, 3D, or 2D and 3D variables are to\n//! be supported\n//\nenum DimFlags {\n    TWOD = (1u << 0),\n    TWODXY = (1u << 1),\n    TWODXZ = (1u << 2),\n    TWODYZ = (1u << 3),\n    THREED = (1u << 4),\n};\n\n//! Bit mask to indicate whether the GeometryWidget should control a\n//! single point, or 3D extents with Min/Max controllers\nenum GeometryFlags {\n    PLANAR = (1u << 0),\n    RAKE_HACK = (1u << 1),\n};\n\n#endif\n"
  },
  {
    "path": "apps/vaporgui/FlowEventRouter.cpp",
    "content": "#include \"FlowEventRouter.h\"\n#include \"vapor/FlowParams.h\"\n#include \"PWidgets.h\"\n#include \"PFlowRakeRegionSelector.h\"\n#include \"PFlowIntegrationRegionSelector.h\"\n#include \"PMultiVarSelector.h\"\n#include \"PConstantColorWidget.h\"\n#include \"PMetadataClasses.h\"\n#include \"PSliderEditHLI.h\"\n\nusing namespace VAPoR;\ntypedef FlowParams FP;\n\nstatic RenderEventRouterRegistrar<FlowEventRouter> registrar(FlowEventRouter::GetClassType());\nconst string                                       FlowEventRouter::SeedingTabName = \"Seeding\";\nconst string                                       FlowEventRouter::IntegrationTabName = \"Integration\";\n\nFlowEventRouter::FlowEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, FlowParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PDimensionSelector,\n            new PXFieldVariableSelector,\n            new PYFieldVariableSelector,\n            (new PZFieldVariableSelector)->OnlyShowForDim(3),\n            new PColorMapVariableSelector,\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    _seedingTab =\n    AddSubtab(SeedingTabName, new PGroup({\n        new PSection(\"Flow Integration Settings\", {\n            new PEnumDropdown(FP::_isSteadyTag, {\"Streamlines\", \"Pathlines\"}, {true, false}, \"Flow Type\"),\n            (new PShowIf(FP::_isSteadyTag))->Equals(true)->Then({\n                new PEnumDropdown(FP::_flowDirectionTag, {\"Forward\", \"Backward\", \"Bi-Directional\"}, {(int)FlowDir::FORWARD, (int)FlowDir::BACKWARD, (int)FlowDir::BI_DIR}, \"Flow Direction\"),\n                (new PIntegerInput(FP::_steadyNumOfStepsTag, \"Integration Steps\"))->SetRange(0, 10000),\n            })->Else({\n                _pathlineLengthSlider = new PIntegerSliderEdit(FP::_pastNumOfTimeSteps, \"Pathline Length\"),\n                _pathlineInjectionSlider = new PIntegerSliderEdit(FP::_seedInjInterval, \"Injection Interval\"),\n            }),\n            new PCheckbox(FP::_xPeriodicTag, \"X axis periodicity\"),\n            new PCheckbox(FP::_yPeriodicTag, \"Y axis periodicity\"),\n            new PCheckbox(FP::_zPeriodicTag, \"Z axis periodicity\"),\n        }),\n        new PSection(\"Seed Distribution Settings\", {\n            new PEnumDropdown(FP::_seedGenModeTag, {\"Gridded\", \"Random\", \"Random w/ Bias\", \"List of seeds\"}, {(int)FlowSeedMode::UNIFORM, (int)FlowSeedMode::RANDOM, (int)FlowSeedMode::RANDOM_BIAS, (int)FlowSeedMode::LIST}, \"Seed distribution type\"),\n            (new PShowIf(FP::_seedGenModeTag))->Equals((int)FlowSeedMode::UNIFORM)->Then({\n                (new PIntegerSliderEdit(FP::_xGridNumOfSeedsTag, \"X axis seeds\"))->SetRange(1, 50),\n                (new PIntegerSliderEdit(FP::_yGridNumOfSeedsTag, \"Y axis seeds\"))->SetRange(1, 50),\n                (new PIntegerSliderEdit(FP::_zGridNumOfSeedsTag, \"Z axis seeds\"))->SetRange(1, 50),\n            }),\n            (new PShowIf(FP::_seedGenModeTag))->Equals((int)FlowSeedMode::RANDOM)->Then({\n                (new PIntegerSliderEdit(FP::_randomNumOfSeedsTag, \"Seed count\"))->SetRange(1, 2500)\n                 ->AllowUserRange(true),\n            }),\n            (new PShowIf(FP::_seedGenModeTag))->Equals((int)FlowSeedMode::RANDOM_BIAS)->Then({\n                (new PIntegerSliderEdit(FP::_randomNumOfSeedsTag, \"Seed count\"))->SetRange(1, 2500)\n                     ->AllowUserRange(true),\n                (new PIntegerSliderEdit(FP::_rakeBiasStrength, \"Bias weight\"))->SetRange(-10000, 10000)\n                     ->AllowUserRange(true),\n                new PVariableSelector(FP::_rakeBiasVariable, \"Bias Variable\")\n            }),\n            (new PShowIf(FP::_seedGenModeTag))->Equals((int)FlowSeedMode::LIST)->Then({\n                (new PFileOpenSelector(FP::_seedInputFilenameTag, \"List of seeds file\"))->SetTooltip(\n                    \"Seed injection points within your domain may be defined in this text file with the following definition: \\n\"\n                    \"1. Each line specifies the location of one seed. \\n\"\n                    \"2. Empty lines and lines starting with a pound sign is ignored. \\n\"\n                    \"3. Seed locations are specified using comma separated X,Y,Z coordinates. \\n\"\n                    \"4. A line with less than 3 comma separated values is invalid, which also invalidates the entire file. \\n\"\n                    \"5. A line can have more than 3 comma separated values, with additional values being ignored. \\n\"\n                    \"6. X, Y, Z coordinates use the same unit of the dataset's spatial domain. \\n\"\n                    \"    Note: lat-lon coordinates may be converted to meters via a map projection. \\n\"\n                    \"Finally, the listOfSeeds.txt demo file provides a starting point to specify your own seeds.\"\n                )\n            }),\n        }),\n        (new PShowIf(FP::_seedGenModeTag))->Not()->Equals((int)FlowSeedMode::LIST)->Then({\n            new PSection(\"Rake Region\", {\n                new PFlowRakeRegionSelector1D(0),\n                new PFlowRakeRegionSelector1D(1),\n                new PFlowRakeRegionSelector1D(2),\n            }),\n            (new PSection(\"Rake Center\", {\n                (_xRakeCenterSlider = new PDoubleSliderEditHLI<FlowParams>(\"X\", &FlowParams::GetXRakeCenter, &FlowParams::SetXRakeCenter))->AllowDynamicUpdate(),\n                (_yRakeCenterSlider = new PDoubleSliderEditHLI<FlowParams>(\"Y\", &FlowParams::GetYRakeCenter, &FlowParams::SetYRakeCenter))->AllowDynamicUpdate(),\n                (_zRakeCenterSlider = new PDoubleSliderEditHLI<FlowParams>(\"Z\", &FlowParams::GetZRakeCenter, &FlowParams::SetZRakeCenter))->AllowDynamicUpdate(),\n            }))->SetTooltip(\"Controls the location of the Rake's Center.  To control\\n the range of values that the Rake Center can traverse, adjust\\n the Flow Renderer's Region in the Geometry tab\"),\n        }),\n        \n        new PSection(\"Write Flowlines to File\", {\n            new PFileSaveSelector(FP::_flowlineOutputFilenameTag, \"Target file\"),\n            (new PButton(\"Write to file\", [](ParamsBase *p){p->SetValueLong(FP::_needFlowlineOutputTag, \"\", true);}))->DisableUndo(),\n            new PLabel(\"Specify variables to sample and output along the flowlines\"),\n            new PMultiVarSelector(FP::_flowOutputMoreVariablesTag)\n        }),\n\n        new PSection(\"Advanced Options\", {\n            (new PDoubleInput(FP::_velocityMultiplierTag, \"Vector Field Multiplier\"))->SetTooltip( \"Apply a multiplier to the velocity field.\"),\n            (new PDoubleInput(FP::_firstStepSizeMultiplierTag, \"First Step Size Multiplier\"))->SetTooltip( \"Apply a multiplier to the auto-calculated first step size. Very occasionally a value bigger than 1.0 is needed here.\"),\n            (new PCheckbox(FP::_fixedAdvectionStepTag, \"Use Fixed Advection Steps\"))->SetTooltip( \"The user may provide an advection step size, so that VAPOR disables dynamic step size adjustments and always uses the fixed step size.\"),\n            (new PShowIf(FP::_fixedAdvectionStepTag))->Then(new PDoubleInput(FP::_fixedAdvectionStepSizeTag, \"  |--- Fixed Advection Step Size\"))->SetTooltip( \"Use this specific value as the fixed advection step size.\"),\n        }),\n    }));\n    \n    AddAppearanceSubtab(new PGroup({\n        (new PTFEditor(RenderParams::_colorMapVariableNameTag)),\n        new PSection(\"Appearance\", {\n            new PConstantColorWidget,\n            new PEnumDropdown(FP::RenderTypeTag, {\"Tubes\", \"Samples\", \"KLGWTH\"}, {FP::RenderTypeStream, FP::RenderTypeSamples, FP::RenderTypeDensity}, \"Render Type\"),\n            (new PShowIf(FP::RenderTypeTag))->Equals(FP::RenderTypeStream)->Then({\n                new PCheckbox(FP::RenderGeom3DTag, \"3D Geometry\"),\n                (new PDoubleSliderEdit(FP::RenderRadiusScalarTag, \"Radius Scalar\"))->SetRange(0.1, 5)->EnableDynamicUpdate(),\n                new PCheckbox(FP::RenderShowStreamDirTag, \"Show Stream Direction\"),\n                (new PSubGroup({(new PIntegerSliderEdit(FP::RenderGlyphStrideTag, \"Every N Samples\"))->SetRange(1, 20)->EnableDynamicUpdate()}))->ShowBasedOnParam(FP::RenderShowStreamDirTag),\n            }),\n            (new PShowIf(FP::RenderTypeTag))->Equals(FP::RenderTypeSamples)->Then({\n                new PEnumDropdown(FP::RenderGlyphTypeTag, {\"Circle\", \"Arrow\"}, {FP::GlpyhTypeSphere, FP::GlpyhTypeArrow}, \"Glyph Type\"),\n                new PCheckbox(FP::RenderGeom3DTag, \"3D Geometry\"),\n                (new PDoubleSliderEdit(FP::RenderRadiusScalarTag, \"Radius Scalar\"))->SetRange(0.1, 5)->EnableDynamicUpdate(),\n                (new PIntegerSliderEdit(FP::RenderGlyphStrideTag, \"Every N Samples\"))->SetRange(1, 20)->EnableDynamicUpdate(),\n                new PCheckbox(FP::RenderGlyphOnlyLeadingTag, \"Only Show Leading Sample\"),\n            }),\n            (new PShowIf(FP::RenderTypeTag))->Equals(FP::RenderTypeDensity)->Then({\n                new PLabel(\"May not render correctly with other renderers\"),\n                (new PDoubleSliderEdit(FP::RenderRadiusScalarTag, \"Radius Scalar\"))->SetRange(0.1, 5)->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(FlowParams::RenderDensityFalloffTag, \"Density Falloff\"))->SetRange(0.5, 10)->EnableDynamicUpdate()->SetTooltip(\"The exponential factor at which the intensity falls off along the width of the line\"),\n                (new PDoubleSliderEdit(FlowParams::RenderDensityToneMappingTag, \"Tone Mapping\"))->SetRange(0, 1)->EnableDynamicUpdate()->SetTooltip(\"The overall color intensity of the line\"),\n                (new PCheckbox(\"Invert\"))->SetTooltip(\"For rendering on light backgrounds\"),\n            }),\n            (new PShowIf(FP::RenderTypeTag))->Not()->Equals(FP::RenderTypeSamples)->Then({\n                new PCheckbox(FP::RenderFadeTailTag, \"Fade Flow Tails\"),\n                (new PShowIf(FP::RenderFadeTailTag))->Equals(true)->Then(new PSubGroup({\n                    (new PIntegerSliderEdit(FP::RenderFadeTailStartTag, \"Fade Start Sample\"))->SetRange(0, 100)->EnableDynamicUpdate()->SetTooltip(\"How far behind leading sample fade begins.\"),\n                    (new PIntegerSliderEdit(FP::RenderFadeTailLengthTag, \"Fade Over N Samples\"))->SetRange(1, 100)->EnableDynamicUpdate()->SetTooltip(\"Number of samples from opaque to transparent.\"),\n                    (new PIntegerSliderEdit(FP::RenderFadeTailStopTag, \"Animate Steady\"))->SetRange(0, 200)->EnableDynamicUpdate()->SetTooltip(\"Temporary solution for animating steady flow particles.\"),\n                })),\n            }),\n        }),\n        (new PShowIf(FP::RenderGeom3DTag))->Then(new PSection(\"Lighting\", {\n            (new PDoubleSliderEdit(FP::PhongAmbientTag,   \"Ambient\"  ))->EnableDynamicUpdate(),\n            (new PDoubleSliderEdit(FP::PhongDiffuseTag,   \"Diffuse\"  ))->EnableDynamicUpdate(),\n            (new PDoubleSliderEdit(FP::PhongSpecularTag,  \"Specular\" ))->EnableDynamicUpdate(),\n            (new PDoubleSliderEdit(FP::PhongShininessTag, \"Shininess\"))->EnableDynamicUpdate(),\n        })),\n#ifndef NDEBUG\n        (new PSection(\"Debug\", {\n            new PCheckbox(\"old_render\", \"Old Render Code (Regressing Testing)\")\n        }))->SetTooltip(\"Only accessible in debug build.\"),\n#endif\n    }));\n    \n    AddSubtab(IntegrationTabName, new PGroup({\n        new PSection(\"Integration Settings\", {\n            new PCheckbox(FP::_doIntegrationTag, \"Integrate particle values along trajectory\"),\n            new PCheckbox(FP::_integrationSetAllToFinalValueTag, \"Set entire stream value to integrated total\"),\n            (new PVariableSelector(RenderParams::_colorMapVariableNameTag, \"Scalar to Integrate\"))->EnableBasedOnParam(FP::_doIntegrationTag),\n            (new PDoubleInput(FP::_integrationScalarTag, \"Integration distance scale\"))->EnableBasedOnParam(FP::_doIntegrationTag),\n        }),\n        (new PSection(\"Integration Region\", {\n            new PFlowIntegrationRegionSelector1D(0),\n            new PFlowIntegrationRegionSelector1D(1),\n            new PFlowIntegrationRegionSelector1D(2),\n        }))->EnableBasedOnParam(FP::_doIntegrationTag),\n    }));\n\n    AddGeometrySubtab(new PGeometrySubtab);\n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nvoid FlowEventRouter::Update()\n{\n    RenderEventRouterGUI::Update();\n\n    int numTS = GetActiveDataMgr()->GetNumTimeSteps();\n    _pathlineLengthSlider->SetRange(0, std::max(1, numTS - 1));\n    _pathlineInjectionSlider->SetRange(0, numTS);\n\n    VAPoR::CoordType min, max;\n    FlowParams *        fp = dynamic_cast<FlowParams *>(GetActiveParams());\n    fp->GetBox()->GetExtents(min, max);\n    double xCenter = fp->GetXRakeCenter();\n    double yCenter = fp->GetYRakeCenter();\n    double zCenter = fp->GetZRakeCenter();\n\n    if (xCenter > max[0]) fp->SetXRakeCenter(max[0]);\n    if (xCenter < min[0]) fp->SetXRakeCenter(min[0]);\n    _xRakeCenterSlider->SetRange(min[0], max[0]);\n\n    if (yCenter > max[1]) fp->SetYRakeCenter(max[1]);\n    if (yCenter < min[1]) fp->SetYRakeCenter(min[1]);\n    _yRakeCenterSlider->SetRange(min[1], max[1]);\n\n    if (zCenter > max[2]) fp->SetZRakeCenter(max[2]);\n    if (zCenter < min[2]) fp->SetZRakeCenter(min[2]);\n    _zRakeCenterSlider->SetRange(min[2], max[2]);\n}\n\nstring FlowEventRouter::_getDescription() const { return \"Computes and displays steady or unsteady flow trajectories.\\n\"; }\n"
  },
  {
    "path": "apps/vaporgui/FlowEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include <vapor/FlowRenderer.h>\n\nclass PIntegerSliderEdit;\nclass PDoubleSliderEdit;\n\n//! \\class FlowEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Flow renderer GUI\n//! \\author Stas Jaroszynski\n\nclass FlowEventRouter : public RenderEventRouterGUI {\n    QWidget *           _seedingTab;\n    PIntegerSliderEdit *_pathlineLengthSlider;\n    PIntegerSliderEdit *_pathlineInjectionSlider;\n    PDoubleSliderEdit * _xRakeCenterSlider;\n    PDoubleSliderEdit * _yRakeCenterSlider;\n    PDoubleSliderEdit * _zRakeCenterSlider;\n\npublic:\n    static const std::string SeedingTabName;\n    static const std::string IntegrationTabName;\n\n    FlowEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::FlowRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return true; }\n    bool          Supports3DVariables() const { return true; }\n    void          Update();\n\nprotected:\n    string _getDescription() const;\n    string _getSmallIconImagePath() const { return \"Flow_small.png\"; }\n    string _getIconImagePath() const { return \"Flow.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/GLWidget.cpp",
    "content": "//-- GLWidget.cpp -------------------------------------------------------\n//\n// Copyright (C) 2006 Kenny Gruchalla.  All rights reserved.\n//\n// Abstract base class for OpenGL-based widgets that provides a common\n// interface for selecting, moving, and drawing.\n//\n//----------------------------------------------------------------------------\n\n#include \"GLWidget.h\"\n\n#include <qwidget.h>\n\nusing namespace std;\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nGLWidget::GLWidget(QWidget *parent) : QObject(parent), _id(createId()), _selected(NONE), _enabled(true) {}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nGLWidget::~GLWidget() {}\n\n//----------------------------------------------------------------------------\n// Set the widget's geometry\n//----------------------------------------------------------------------------\nvoid GLWidget::setGeometry(float x0, float x1, float y0, float y1)\n{\n    _minX = x0 <= x1 ? x0 : x1;\n    _maxX = x1 > x0 ? x1 : x0;\n\n    _minY = y0 <= y1 ? y0 : y1;\n    _maxY = y1 > y0 ? y1 : y0;\n}\n\n//- static -------------------------------------------------------------------\n//\n// Generate a unique identifier.\n//----------------------------------------------------------------------------\nunsigned int GLWidget::createId()\n{\n    static unsigned int id = 1;\n\n    return id++;\n}\n"
  },
  {
    "path": "apps/vaporgui/GLWidget.h",
    "content": "//-- GLWidget.h ---------------------------------------------------------\n//\n// Copyright (C) 2006 Kenny Gruchalla.  All rights reserved.\n//\n// Abstract base class for OpenGL-based widgets that provides a common\n// interface for selecting, moving, and drawing.\n//\n//----------------------------------------------------------------------------\n\n#ifndef GLWidget_H\n#define GLWidget_H\n\n#include <qobject.h>\n\n#include <qnamespace.h>\n#include <list>\n\nclass QWidget;\n\nclass GLWidget : public QObject {\n    Q_OBJECT\n\nprotected:\n    enum { NONE = -1 };\n\npublic:\n    GLWidget(QWidget *parent = 0);\n    virtual ~GLWidget();\n\n    virtual int paintGL() = 0;\n\n    virtual void move(float dx, float dy = 0.0, float dz = 0.0) = 0;\n    virtual void drag(float dx, float dy = 0.0, float dz = 0.0) = 0;\n\n    virtual bool selected() { return _selected != NONE; }\n    virtual void deselect() { _selected = NONE; }\n    virtual void select(int handle, Qt::KeyboardModifiers) { _selected = handle; }\n\n    virtual bool enabled() const { return _enabled; }\n    virtual void enable(bool flag) { _enabled = flag; }\n\n    virtual void setGeometry(float x0, float x1, float y0, float y1);\n\n    int id() const { return _id; }\n\nsignals:\n\n    void startChange(QString);\n    void endChange();\n\nprotected:\n    static unsigned int createId();\n\n    unsigned int _id;\n    int          _selected;\n    bool         _enabled;\n\n    float _minX;\n    float _maxX;\n    float _minY;\n    float _maxY;\n};\n\n#endif    // GLWidget_H\n"
  },
  {
    "path": "apps/vaporgui/ImageEventRouter.cpp",
    "content": "#include <ImageEventRouter.h>\n#include <vapor/ImageParams.h>\n#include \"PWidgets.h\"\n#include \"PTMSLODInput.h\"\n#include \"PMetadataClasses.h\"\n\nusing namespace VAPoR;\ntypedef ImageParams IP;\n\nstatic RenderEventRouterRegistrar<ImageEventRouter> registrar(ImageEventRouter::GetClassType());\n\nImageEventRouter::ImageEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, ImageParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PHeightVariableSelector\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    AddAppearanceSubtab(new PSection(\"Image\", {\n        new PCheckbox(IP::_isGeoRefTag, \"Geo Reference\"),\n        new PCheckbox(IP::_ignoreTransparencyTag, \"Ignore Transparency\"),\n        (new PDoubleSliderEdit(IP::_constantOpacityTag, \"Opacity\"))->EnableDynamicUpdate(),\n        (new PFileOpenSelector(IP::_fileNameTag, \"Image File\"))->SetFileTypeFilter(\"TIFF files, tiled images (*.tiff *.tif *.gtif *.tms)\"),\n        new PTMSLODInput(),\n        new PCheckbox(IP::DrawInFrontTag, \"Draw renderer in front\")\n    }));\n    \n    AddGeometrySubtab(new PGeometrySubtab);\n\n    // clang-format on\n}\n\nstring ImageEventRouter::_getDescription() const\n{\n    return (\"Displays a \"\n            \"georeferenced image that is automatically reprojected and fit to the user's\"\n            \"data, as long as the data contains georeference metadata.  The image \"\n            \"renderer may be offset by a height variable to show bathymetry or mountainous\"\n            \" terrain.\\n\\n \");\n}\n"
  },
  {
    "path": "apps/vaporgui/ImageEventRouter.h",
    "content": "#pragma once\n\n#include <vapor/ImageRenderer.h>\n#include <RenderEventRouterGUI.h>\n\n//! \\class ImageEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Image Renderer GUI\n//! \\author Stas Jaroszynski\n\nclass ImageEventRouter : public RenderEventRouterGUI {\npublic:\n    ImageEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static std::string GetClassType() { return VAPoR::ImageRenderer::GetClassType(); }\n    std::string        GetType() const { return GetClassType(); }\n    bool               Supports2DVariables() const { return true; }\n    bool               Supports3DVariables() const { return true; }\n    bool               SupportsParticleVariables() const { return true; }\n\nprotected:\n    string _getDescription() const;\n    string _getSmallIconImagePath() const { return \"Image_small.png\"; }\n    string _getIconImagePath() const { return \"Image.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/ImportTab.cpp",
    "content": "#include \"ImportTab.h\"\n#include \"PImportDataWidget.h\"\n#include \"DatasetImportController.h\"\n#include \"PProjectionStringWidget.h\"\n#include \"VHyperlink.h\"\n#include \"VSection.h\"\n\n#include <vapor/GUIStateParams.h>\n#include <vapor/ControlExecutive.h>\n#include <QVBoxLayout>\n\nusing namespace VAPoR;\n\nImportTab::ImportTab(VAPoR::ControlExec *ce, DatasetImportController *datasetImportController) : _ce(ce)\n{\n    QVBoxLayout *l = new QVBoxLayout;\n    l->setContentsMargins(0, 0, 0, 0);\n\n    l->addWidget(new VSectionGroup(\"Import Data\", {_importer = new PImportDataWidget(_ce, datasetImportController)}));\n\n    VSectionGroup *sg = new VSectionGroup(\"Tips\", {\n        new VHyperlink(\n            \"How to convert Non-Compliant NetCDF Files?\",\n            \"https://vapordocumentationwebsite.readthedocs.io/en/latest/dataFormatRequirements/netCDF/nonCompliantNetCDF.html\",\n            true\n        ),\n        new VHyperlink(\n            \"Download example Datasets\",\n            \"https://vapordocumentationwebsite.readthedocs.io/en/latest/downloads/sampleData.html\",\n            true\n        ),\n        new VHyperlink(\n            \"Additional information on supported data formats\",\n            \"https://vapordocumentationwebsite.readthedocs.io/en/latest/dataFormatRequirements.html\",\n            true\n        ),\n        new VHyperlink(\n            \"Get Help\",\n            \"https://vapor.discourse.group/\",\n            true\n        ),\n    });\n    sg->setEnabled(true);\n    l->addWidget(sg);\n\n    l->addWidget(_projectionWidget = new PProjectionStringWidget(_ce));\n\n    l->addStretch(1);\n    setLayout(l);\n}\n\nvoid ImportTab::Update()\n{\n    GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType());\n    _importer->Update(guiParams);\n\n    bool noDatasetLoaded = guiParams->GetOpenDataSetNames().empty();\n    if (noDatasetLoaded) _projectionWidget->hide();\n    else _projectionWidget->Update(guiParams);\n}\n"
  },
  {
    "path": "apps/vaporgui/ImportTab.h",
    "content": "#pragma once\n\n#include \"Updatable.h\"\n#include <QWidget>\n\nclass PImportDataWidget;\nclass PProjectionStringWidget;\nclass DatasetImportController;\n\nclass ImportTab : public QWidget, public Updatable {\n    Q_OBJECT\n\n    VAPoR::ControlExec *_ce;\n    PImportDataWidget *_importer;\n    PProjectionStringWidget *_projectionWidget;\n\npublic:\n    ImportTab(VAPoR::ControlExec *ce, DatasetImportController *datasetImportController);\n    void Update() override;\n};\n"
  },
  {
    "path": "apps/vaporgui/LeftPanel.cpp",
    "content": "#include \"LeftPanel.h\"\n\n#include <QScrollArea>\n\n#include \"RenderersPanel.h\"\n#include \"ImportTab.h\"\n#include \"ExportTab.h\"\n#include \"CaptureController.h\"\n#include \"DatasetImportController.h\"\n#include \"AnnotationEventRouter.h\"\n\n#include \"vapor/ControlExecutive.h\"\n#include \"vapor/GUIStateParams.h\"\n\n\nLeftPanel::LeftPanel(ControlExec *ce, CaptureController *captureController, DatasetImportController *datasetImportController)\n{\n    auto add = [this](auto &&w, auto &&t) constexpr {\n        QScrollArea *scrollArea = new QScrollArea;\n        scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);\n        scrollArea->setWidget(w);\n        scrollArea->setWidgetResizable(true);\n        addTab(scrollArea, t);\n        _uTabs.push_back(w);\n    };\n   \n    _importTab = new ImportTab(ce, datasetImportController); \n    add(_importTab, \"Import\");\n    add(new RenderersPanel(ce), \"Render\");\n    add(new AnnotationEventRouter(ce), \"Annotate\");\n    add(new ExportTab(ce, captureController), \"Export\");\n\n    for (int i=1 ; i<count(); ++i) setTabEnabled(i, false);\n    setTabEnabled(0,true);\n\n    connect(this, &QTabWidget::currentChanged, this, &LeftPanel::tabChanged);\n}\n\nvoid LeftPanel::ConfigureEnabledState(bool widgetsEnabled) {\n    if (!widgetsEnabled) {\n        // Only enable the Import tab, which should always be enabled\n        _importTab->setEnabled(true);\n        setCurrentIndex(0);\n        for (int tabNum=1; tabNum < count(); tabNum++) setTabEnabled(tabNum, false);\n    }\n    else {\n        // Otherwise enable all tabs\n        for (int i = 0; i < count(); ++i) setTabEnabled(i, true);\n    }\n}\n\nvoid LeftPanel::Update()\n{\n    if (_uTabs.empty()) return;\n    _uTabs[currentIndex()]->Update();\n}\n\nvoid LeftPanel::tabChanged(int i)\n{\n    _uTabs[i]->Update();\n}\n\nvoid LeftPanel::GoToRendererTab() {\n    setCurrentIndex(1);\n}\n"
  },
  {
    "path": "apps/vaporgui/LeftPanel.h",
    "content": "#pragma once\n\n#include <QTabWidget>\n#include <common.h>\n\n#include \"Updatable.h\"\n#include \"VaporFwd.h\"\n\nclass ImportTab;\nclass CaptureController;\nclass DatasetImportController;\n\nclass LeftPanel : public QTabWidget, public Updatable {\n    Q_OBJECT\n    std::vector<Updatable *> _uTabs;\n    ImportTab* _importTab;\n\npublic:\n    LeftPanel(ControlExec *ce, CaptureController *captureController, DatasetImportController *datasetImportController);\n    void Update() override;\n    void GoToRendererTab();\n    void ConfigureEnabledState(bool enabled);\n\nprivate:\n    void tabChanged(int i);\n};\n"
  },
  {
    "path": "apps/vaporgui/MainForm.cpp",
    "content": "#include <vapor/glutil.h>    // Must be included first!!!\n#include \"vapor/VAssert.h\"\n#include <functional>\n#include <cmath>\n#include <memory>\n#ifndef _WIN32\n    #include <unistd.h>\n    #include \"windowsUtils.h\"\n#endif\n\n#include <QDesktopWidget>\n#include <QDockWidget>\n#include <QToolBar>\n#include <QMessageBox>\n#include <QFileDialog>\n#include <QUrl>\n#include <QDesktopServices>\n#include <QInputDialog>\n#include <QWhatsThis>\n#include <QStatusBar>\n#include <QDebug>\n#include <QScreen>\n#include <QDialog>\n#include <QVBoxLayout>\n\n#include <vapor/Version.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/ResourcePath.h>\n#include <vapor/FileUtils.h>\n#include <vapor/STLUtils.h>\n#include <vapor/Proj4API.h>\n\n#include <vapor/VDCNetCDF.h>\n#include <vapor/DCWRF.h>\n#include <vapor/DCMPAS.h>\n#include <vapor/DCP.h>\n#include <vapor/DCCF.h>\n#include <vapor/DCBOV.h>\n#include <vapor/DCUGRID.h>\n\n#include \"VizWinMgr.h\"\n#include \"BannerGUI.h\"\n#include \"Statistics.h\"\n#include \"PythonVariables.h\"\n#include \"PProjectionStringWidget.h\"\n#include \"VProjectionStringFrame.h\"\n#include \"Plot.h\"\n#include \"ErrorReporter.h\"\n#include \"MainForm.h\"\n#include \"FileOperationChecker.h\"\n#include \"ParamsWidgetDemo.h\"\n#include \"AppSettingsMenu.h\"\n#include \"CheckForUpdateUI.h\"\n#include \"NoticeBoard.h\"\n#include \"PVisualizerSelector.h\"\n#include \"QtVizWinGLContextManager.h\"\n#include \"ProgressStatusBar.h\"\n#include \"LeftPanel.h\"\n#include \"CLIToolInstaller.h\"\n#include \"Updatable.h\"\n#include \"CitationReminder.h\"\n#include \"BookmarkManager.h\"\n#include \"UCloseVDCMenu.h\"\n#include \"PTimestepInput.h\"\n#include \"NcarCasperUtils.h\"\n#include \"ViewpointToolbar.h\"\n#include \"DatasetTypeLookup.h\"\n#include \"CaptureController.h\"\n#include \"DatasetImportController.h\"\n\n#include <QStyle>\n#include <vapor/Progress.h>\n#include <vapor/OSPRay.h>\n\n#include <vapor/XmlNode.h>\n#include <vapor/NavigationUtils.h>\n\n\n#include \"images/vapor-icon-32.xpm\"\n#include \"images/playreverse.xpm\"\n#include \"images/playforward.xpm\"\n#include \"images/pauseimage.xpm\"\n#include \"images/stepfwd.xpm\"\n#include \"images/stepback.xpm\"\n\n\nusing namespace std;\nusing namespace VAPoR;\n\nconst QEvent::Type MainForm::ParamsChangeEvent = (QEvent::Type)QEvent::registerEventType();\nconst QEvent::Type MainForm::ParamsIntermediateChangeEvent = (QEvent::Type)QEvent::registerEventType();\nMainForm *MainForm::_instance = nullptr;\n\n\nMainForm::MainForm(vector<QString> files, QApplication *app, bool interactive, string filesType, QWidget *parent) : QMainWindow(parent)\n{\n    _App = app;\n    _begForCitation = true;\n\n    assert(!_instance);\n    _instance = this;\n\n    setWindowTitle(tr(\"VAPoR:  NCAR Visualization and Analysis Platform for Research\"));\n\n    setAttribute(Qt::WA_DeleteOnClose);\n\n    // For vertical screens, reverse aspect ratio for window size\n    QScreen *screen = QGuiApplication::primaryScreen();\n    QRect    screenSize = screen->geometry();\n\n    if (screenSize.width() < screenSize.height()) {\n        resize(screenSize.width() * .7, screenSize.width() * .7 * screenSize.width() / (float)screenSize.height());\n    } else {\n        resize(screenSize.width() * .7, screenSize.height() * .7);\n    }\n\n    setWindowIcon(QPixmap(vapor_icon___));\n\n    auto sideDockWidgetArea = new QDockWidget(this);\n    addDockWidget(Qt::LeftDockWidgetArea, sideDockWidgetArea);\n    sideDockWidgetArea->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);\n    sideDockWidgetArea->setFeatures(QDockWidget::NoDockWidgetFeatures);\n\n    vector<string> myParams;\n    myParams.push_back(GUIStateParams::GetClassType());\n    myParams.push_back(SettingsParams::GetClassType());\n    myParams.push_back(AnimationParams::GetClassType());\n    myParams.push_back(AnnotationParams::GetClassType());\n\n    vector<string> myRenParams;\n    myRenParams.push_back(StatisticsParams::GetClassType());\n    myRenParams.push_back(PlotParams::GetClassType());\n\n    _paramsMgr = new ParamsMgr(myParams, myRenParams);\n    _paramsMgr->RegisterStateChangeCB(std::bind(&MainForm::_stateChangeCB, this));\n    _paramsMgr->RegisterIntermediateStateChangeCB(std::bind(&MainForm::_intermediateStateChangedCB, this));\n    _paramsMgr->RegisterStateChangeFlag(&_stateChangeFlag);\n\n    _controlExec = new ControlExec(_paramsMgr);\n    _controlExec->SetSaveStateEnabled(false);\n\n    _appSettingsMenu = new AppSettingsMenu(this);\n\n    _vizWinMgr = new VizWinMgr(_controlExec);\n    _controlExec->SetVisualizerGLContextManager(_vizWinMgr->visualizerGLContextManager);\n    setCentralWidget(_vizWinMgr);\n    _dependOnLoadedData_insert(_vizWinMgr);\n\n    _animationController = new AnimationController(_controlExec);\n    connect(_animationController, SIGNAL(AnimationOnOffSignal(bool)), this, SLOT(_setAnimationOnOff(bool)));\n    connect(_animationController, &AnimationController::AnimationDrawSignal, [this]() {\n        setUpdatesEnabled(false);\n        _controlExec->SyncWithParams();\n        updateUI();\n        setUpdatesEnabled(true);\n        Render(false, true);\n    });\n\n    _captureController = new CaptureController(_controlExec);\n    connect(_captureController, &CaptureController::captureStarted, [this]() {\n        AnimationParams* ap = (AnimationParams*)_controlExec->GetParamsMgr()->GetParams(AnimationParams::GetClassType());\n        NavigationUtils::SetTimestep(_controlExec, ap->GetValueLong(AnimationParams::CaptureStartTag, ap->GetStartTimestep()));\n        _animationController->AnimationPlayForward();\n    });\n\n    _datasetImportController = new DatasetImportController();\n    connect(_datasetImportController, &DatasetImportController::datasetImported, this, [this](){_leftPanel->GoToRendererTab();});\n\n    _leftPanel = new LeftPanel(_controlExec, _captureController, _datasetImportController);\n    const int dpi = qApp->desktop()->logicalDpiX();\n    _leftPanel->setMinimumWidth(dpi > 96 ? 675 : 460);\n    _leftPanel->setMinimumHeight(500);\n    _updatableElements.insert(_leftPanel);\n\n    _status = new ProgressStatusBar;\n    _status->hide();\n\n    sideDockWidgetArea->setWidget(new VGroup({_leftPanel, _status}));\n    // Only this specific resize method works for dock widgets, all other resize methods are noops\n    resizeDocks({sideDockWidgetArea}, {_leftPanel->minimumWidth()}, Qt::Horizontal);\n\n    createMenus();\n    createToolBars();\n    _createProgressWidget();\n\n    // Force creation of the static error reporter, which registers\n    // callback's with the MyBase error logger used by the vapor render\n    // library.\n    //\n    new ErrorReporter(this);\n\n    GetSettingsParams()->FindDefaultSettingsPath();\n\n    setUpdatesEnabled(true);\n\n    // Command line options:\n    //\n    // - Session file\n    // - Session file + data file\n    // - data file\n    //\n\n    if (files.size() && files[0].endsWith(\".vs3\")) {\n        if (!FileUtils::Exists(files[0].toStdString())) {\n            fprintf(stderr, \"Session file \\\"%s\\\" does not exist\\n\", files[0].toStdString().c_str());\n            exit(1);\n        }\n        bool loadDatasetsFromSession = files.size() == 1;\n        openSession(files[0].toStdString(), loadDatasetsFromSession);\n        files.erase(files.begin());\n\n        if (!loadDatasetsFromSession && _controlExec->GetDataNames().size() > 1) {\n            fprintf(stderr, \"Cannot replace dataset from command line in session which contains multiple open datasets.\");\n            exit(1);\n        }\n    } else {\n        sessionNew();\n    }\n\n    if (files.size()) {\n        vector<string> paths;\n        for (auto &f : files) paths.push_back(f.toStdString());\n\n        string fmt;\n\n        if (filesType == \"auto\") {\n            if (!determineDatasetFormat(paths, &fmt)) {\n                fmt = \"\";\n                MSG_ERR(\"Could not determine dataset format for command line parameters\");\n            }\n        } else {\n            fmt = filesType;\n        }\n\n        if (!fmt.empty())\n            _datasetImportController->ImportDataset(_controlExec, paths, fmt, DatasetImportController::DatasetExistsAction::ReplaceFirst);\n    }\n\n    app->installEventFilter(this);\n\n    _controlExec->SetSaveStateEnabled(true);\n    _controlExec->RebaseStateSave();\n    _paramsMgr->TriggerManualStateChangeEvent(\"Init\");\n    _stateChangeFlag = false;\n\n    if (interactive && GetSettingsParams()->GetAutoCheckForUpdates()) CheckForAndShowUpdate(_controlExec);\n    if (interactive && GetSettingsParams()->GetAutoCheckForNotices()) NoticeBoard::CheckForAndShowNotices(_controlExec);\n    NcarCasperUtils::CheckForCasperVGL(_controlExec);\n}\n\n\nint MainForm::RenderAndExit(int start, int end, const std::string &baseFile, int width, int height)\n{\n    if (start == 0 && end == 0) end = INT_MAX;\n    start = std::max(0, start);\n\n    if (GetStateParams()->GetValueLong(GUIStateParams::SessionNewTag, false)) {\n        fprintf(stderr, \"No session loaded\\n\");\n        return -1;\n    }\n\n    QString   dir = QString::fromStdString(FileUtils::Dirname(baseFile));\n    QFileInfo dirInfo(dir);\n    if (!dirInfo.isWritable()) {\n        fprintf(stderr, \"Do not have write permissions\\n\");\n        return -1;\n    }\n\n    auto baseFileWithTS = FileUtils::RemoveExtension(baseFile) + \"-\" + to_string(start) + \".\" + FileUtils::Extension(baseFile);\n\n    auto ap = GetAnimationParams();\n    auto vpp = _paramsMgr->GetViewpointParams(GetStateParams()->GetActiveVizName());\n\n    _paramsMgr->BeginSaveStateGroup(\"test\");\n    ap->SetStartTimestep(start);\n    ap->SetEndTimestep(end);\n\n    vpp->SetValueLong(vpp->UseCustomFramebufferTag, \"\", true);\n    vpp->SetValueLong(vpp->CustomFramebufferWidthTag, \"\", width);\n    vpp->SetValueLong(vpp->CustomFramebufferHeightTag, \"\", height);\n\n    if (_captureController->EnableAnimationCapture(baseFileWithTS)) {\n        GUIStateParams *p = (GUIStateParams*)_paramsMgr->GetParams(GUIStateParams::GetClassType());\n        _capturingAnimationVizName = p->GetActiveVizName();\n        _animationController->AnimationPlayForward();\n    }\n\n    _paramsMgr->EndSaveStateGroup();\n\n    connect(_animationController, &AnimationController::AnimationOnOffSignal, this, [this]() {\n        _captureController->EndAnimationCapture();\n        _capturingAnimationVizName = \"\";\n        close();\n    });\n\n    connect(_animationController, &AnimationController::AnimationDrawSignal, this, [this]() { printf(\"Rendering timestep %li\\n\", GetAnimationParams()->GetCurrentTimestep()); });\n\n    return 0;\n}\n\nMainForm::~MainForm()\n{\n    QApplication::closeAllWindows();\n\n    if (_banner) delete _banner;\n    if (_controlExec) delete _controlExec;\n\n    // This is required since if the user quits during the progressbar update,\n    // qt will process the quit event and delete things, and then it will\n    // return to the original event loop.\n    // When Qt does recursive event loops like this, it has backend code that\n    // prevents users from quiting.\n    if (_insideMessedUpQtEventLoop) exit(0);\n}\n\ntemplate<class T> bool MainForm::isDatasetValidFormat(const std::vector<std::string> &paths) const\n{\n    T    dc;\n    bool errReportingEnabled = Wasp::MyBase::EnableErrMsg(false);\n    int  ret = dc.Initialize(paths);\n    Wasp::MyBase::EnableErrMsg(errReportingEnabled);\n    return ret == 0;\n}\n\nbool MainForm::determineDatasetFormat(const std::vector<std::string> &paths, std::string *fmt) const\n{\n    vector<pair<string, bool>> formats = {\n        {\"vdc\", isDatasetValidFormat<VDCNetCDF>(paths)}, {\"wrf\", isDatasetValidFormat<DCWRF>(paths)}, {\"mpas\", isDatasetValidFormat<DCMPAS>(paths)}, {\"dcp\", isDatasetValidFormat<DCP>(paths)},\n        {\"ugrid\", isDatasetValidFormat<DCUGRID>(paths)}, {\"cf\", isDatasetValidFormat<DCCF>(paths)},   {\"bov\", isDatasetValidFormat<DCBOV>(paths)},\n    };\n\n    int nOk = 0;\n    for (auto &f : formats) {\n        if (f.second) {\n            nOk++;\n            *fmt = f.first;\n        }\n    }\n    if (nOk == 1) return true;\n    MyBase::SetErrMsg(\"Unable to confidently determine the dataset format. Please load it manually in the GUI\");\n    return false;\n}\n\n\nvoid MainForm::_createAnimationToolBar()\n{\n    _animationToolBar = addToolBar(\"Animation Control\");\n\n    _timeStepEdit = (new PTimestepInput(_controlExec))->SetTooltip(\"Edit/Display current time step\");\n    _dependOnLoadedData_insert(_timeStepEdit);\n    _animationToolBar->addWidget(_timeStepEdit);\n    _dependOnLoadedData_insert(_animationToolBar);\n    _guiStateParamsUpdatableElements.insert(_timeStepEdit);\n\n    _playBackwardAction = _animationToolBar->addAction(QPixmap(playreverse), \"Play Backward\", _animationController, SLOT(AnimationPlayReverse()));\n    _stepBackAction = _animationToolBar->addAction(QPixmap(stepback), \"Step Backward\", _animationController, SLOT(AnimationStepReverse()));\n    _pauseAction = _animationToolBar->addAction(QPixmap(pauseimage), \"Pause\", _animationController, SLOT(AnimationPause()));\n    _stepForwardAction = _animationToolBar->addAction(QPixmap(stepfwd), \"Step Forward\", _animationController, SLOT(AnimationStepForward()));\n    _playForwardAction = _animationToolBar->addAction(QPixmap(playforward), \"Play Forward\", _animationController, SLOT(AnimationPlayForward()));\n\n    _playForwardAction->setCheckable(true);\n    _playBackwardAction->setCheckable(true);\n}\n\nvoid MainForm::createToolBars()\n{\n    _createAnimationToolBar();\n\n    auto vt = new ViewpointToolbar(this, _controlExec, _vizWinMgr);\n    _dependOnLoadedData_insert(vt);\n    _updatableElements.insert(vt);\n    addToolBar(vt);\n}\n\nvoid MainForm::_createProgressWidget()\n{\n#define MAX_UPDATES_PER_SEC    10\n#define MILLIS_BETWEEN_UPDATES (1000 / MAX_UPDATES_PER_SEC)\n    _progressLastUpdateTime = std::chrono::system_clock::now();\n\n    Progress::Update_t update = [this](long done, bool *cancelled) {\n        if (!_progressEnabled) return;\n\n        // Limit updates per second for perfomance reasons since this is on the same\n        // thread as the calculation\n        auto now = std::chrono::system_clock::now();\n        auto duration = chrono::duration_cast<chrono::milliseconds>(now - _progressLastUpdateTime);\n        if (duration.count() < MILLIS_BETWEEN_UPDATES || _insideMessedUpQtEventLoop) return;\n        _progressLastUpdateTime = now;\n\n        // Qt will clear the currently bound framebuffer for some reason\n        bool insideOpenGL = isOpenGLContextActive();\n        if (insideOpenGL && _progressSavedFB < 0) {\n            glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &_progressSavedFB);\n            glBindFramebuffer(GL_FRAMEBUFFER, 0);\n        }\n\n        _status->SetDone(done);\n        _disableUserInputForAllExcept = _status->GetCancelButtonObject();\n        _insideMessedUpQtEventLoop = true;\n        QCoreApplication::processEvents();\n        _disableUserInputForAllExcept = nullptr;\n        _insideMessedUpQtEventLoop = false;\n        *cancelled = _status->Cancelled();\n\n        if (insideOpenGL && _progressSavedFB >= 0) {\n            glBindFramebuffer(GL_FRAMEBUFFER, _progressSavedFB);\n            _progressSavedFB = -1;\n        }\n    };\n\n    Progress::Start_t start = [this, update](const std::string &name, long total, bool cancelable) {\n        if (!_progressEnabled) return;\n\n        _status->StartTask(name, total, cancelable);\n        update(0, &cancelable);\n    };\n\n    Progress::Finish_t finish = [this, update]() {\n        if (!_progressEnabled) return;\n\n        _status->Finish();\n        bool b;\n        update(0, &b);\n    };\n\n    Progress::SetHandlers(start, update, finish);\n    _status->show();\n    if (_progressEnabledMenuItem) _progressEnabledMenuItem->setChecked(true);\n}\n\nvoid MainForm::_disableProgressWidget()\n{\n    Progress::Finish();\n    Progress::SetHandlers([](const string &, long, bool) {}, [](long, bool *) {}, []() {});\n    _status->hide();\n    if (_progressEnabledMenuItem) _progressEnabledMenuItem->setChecked(false);\n}\n\n\nvoid MainForm::_createFileMenu()\n{\n    auto fileMenu = menuBar()->addMenu(tr(\"File\"));\n    fileMenu->addAction(\"New Session\", this, &MainForm::sessionNew, QKeySequence(\"Ctrl+N\"));\n    fileMenu->addAction(\"Open Session\", this, &MainForm::showOpenSessionGUI, QKeySequence(\"Ctrl+O\"));\n    fileMenu->addAction(\"Save Session\", this, qOverload<>(&MainForm::SaveSession), QKeySequence(\"Ctrl+S\"));\n    fileMenu->addAction(\"Save Session As...\", this, &MainForm::SaveSessionAs);\n\n    fileMenu->addSeparator();\n    auto importMenu = fileMenu->addMenu(\"Import Dataset\");\n    _updatableElements.insert(new UCloseVDCMenu(fileMenu, _controlExec));\n\n    auto addImport = [this, importMenu](const auto &fmt, const auto &label) { importMenu->addAction(label, this, [this, fmt]() { showImportDatasetGUI(fmt); }); };\n    addImport(\"vdc\", \"VDC\");\n    addImport(\"wrf\", \"WRF-ARW\");\n    addImport(\"cf\", \"NetCDF-CF\");\n    addImport(\"mpas\", \"MPAS\");\n    addImport(\"bov\", \"Brick of Values (BOV)\");\n    addImport(\"dcp\", \"Data Collection Particles (DCP)\");\n    addImport(\"ugrid\", \"Unstructured Grid (UGRID)\");\n\n    fileMenu->addSeparator();\n    fileMenu->addAction(\"Exit\", this, SLOT(close()));\n}\n\nvoid MainForm::_createEditMenu()\n{\n    auto editMenu = menuBar()->addMenu(tr(\"Edit\"));\n\n    _editUndoAction = editMenu->addAction(\"Undo\", this, [this](){ _paramsMgr->Undo(); }, QKeySequence(\"Ctrl+Z\"));\n    _editRedoAction = editMenu->addAction(\"Redo\", this, [this](){ _paramsMgr->Redo(); });\n#ifdef WIN32\n    _editRedoAction->setShortcut(QKeySequence(\"Ctrl+Y\"));\n#else\n    _editRedoAction->setShortcut(QKeySequence(\"Ctrl+Shift+Z\"));\n#endif\n\n    editMenu->addSeparator();\n    editMenu->addAction(\"Preferences\", _appSettingsMenu, &QDialog::open);\n\n    editMenu->addSeparator();\n    auto bm = new BookmarkManager(this, _controlExec, _vizWinMgr);\n    bm->RegisterToMenu(editMenu);\n    _updatableElements.insert(bm);\n}\n\nvoid MainForm::_createToolsMenu()\n{\n    auto toolMenu = menuBar()->addMenu(\"Tools\");\n    _dependOnLoadedData_insert(toolMenu->addAction(\"Plot Utility\", this, SLOT(launchPlotUtility())));\n    _dependOnLoadedData_insert(toolMenu->addAction(\"Data Statistics\", this, SLOT(launchStats())));\n    _dependOnLoadedData_insert(toolMenu->addAction(\"Python Variables\", this, SLOT(launchPythonVariables())));\n    _dependOnLoadedData_insert(toolMenu->addAction(\"Dataset Projection\", this, SLOT(launchProjectionFrame())));\n\n#ifdef WIN32\n    #define ADD_INSTALL_CLI_TOOLS_ACTION 1\n#endif\n#ifdef Darwin\n    #define ADD_INSTALL_CLI_TOOLS_ACTION 1\n#endif\n#ifdef ADD_INSTALL_CLI_TOOLS_ACTION\n    toolMenu->addSeparator();\n    auto installCLIToolsAction = toolMenu->addAction(\"Install Command Line Tools\", [](){ CLIToolInstaller::Install(); });\n    installCLIToolsAction->setToolTip(\"Add VAPOR_HOME to environment and add current utilities \"\n                                       \"location to path. Needs to updated if app bundle moved\");\n#endif\n}\n\nvoid MainForm::_createHelpMenu()\n{\n    auto helpMenu = menuBar()->addMenu(tr(\"Help\"));\n    helpMenu->addAction(\"Online Documentation\", [](){\n        bool success = QDesktopServices::openUrl(QString::fromStdString(\"https://ncar.github.io/VaporDocumentationWebsite/\"));\n        if (!success) { MSG_ERR(\"Unable to launch Web browser for URL\"); }\n    });\n    helpMenu->addSeparator();\n    helpMenu->addAction(\"About VAPOR\", this, &MainForm::helpAbout);\n}\n\nvoid MainForm::_createDeveloperMenu()\n{\n    _paramsWidgetDemo = new ParamsWidgetDemo;\n    _guiStateParamsUpdatableElements.insert(_paramsWidgetDemo);\n\n    _developerMenu = menuBar()->addMenu(\"Developer\");\n    _developerMenu->addAction(\"Show PWidget Demo\", _paramsWidgetDemo, &QWidget::show);\n\n    QAction *enableProgress = new QAction(QString(\"Enable Progress Bar\"), nullptr);\n    enableProgress->setCheckable(true);\n    QObject::connect(enableProgress, &QAction::toggled, [this](bool checked) {\n        if (checked)\n            _createProgressWidget();\n        else\n            _disableProgressWidget();\n    });\n    _developerMenu->addAction(enableProgress);\n    _progressEnabledMenuItem = enableProgress;\n\n#ifdef BUILD_OSPRAY\n    _developerMenu->addAction(QString::fromStdString(\"OSPRay \" + VOSP::Version()))->setDisabled(true);\n#endif\n}\n\nvoid MainForm::createMenus()\n{\n    _createFileMenu();\n    _createEditMenu();\n    _createToolsMenu();\n\n    _captureMenu = menuBar()->addMenu(tr(\"Capture\"));\n    QAction* a = new QAction(\"Image capture controls have been moved to the Export Tab\", _captureMenu);\n    a->setEnabled(false);\n    _captureMenu->addAction(a);\n\n    _createHelpMenu();\n#ifndef NDEBUG\n    _createDeveloperMenu();\n#endif\n    menuBar()->adjustSize();\n}\n\n\nvoid MainForm::openSession(const string &path, bool loadData)\n{\n    closeAllParamsDatasets();\n    closeProjectionFrame();\n\n    auto datasetConflictAction = loadData\n        ? ControlExec::LoadStateRelAndAbsPathsExistAction::Ask\n        : ControlExec::LoadStateRelAndAbsPathsExistAction::LoadAbs;\n\nretryLoad:\n    try {\n        int rc = _controlExec->LoadState(path, datasetConflictAction);\n        if (rc < 0) {\n            MSG_ERR(\"Failed to restore session from file\");\n            _controlExec->LoadState();\n            return;\n        }\n    } catch(ControlExec::RelAndAbsPathsExistException const &e) {\n        auto a = showSelectRelVAbsDataLoadGUI(e);\n        if (!a) {\n            sessionNew();\n            return;\n        }\n        datasetConflictAction = a.value();\n        goto retryLoad;\n    }\n\n    auto gsp = GetStateParams();\n    GetSettingsParams()->LoadFromSettingsFile();\n    gsp->SetCurrentSessionFile(path);\n    if (loadData)\n        checkSessionDatasetsExist();\n    else\n        for (auto name : gsp->GetOpenDataSetNames()) gsp->RemoveOpenDataSet(name);\n\n    _paramsMgr->UndoRedoClear();\n    gsp->SetValueLong(GUIStateParams::SessionNewTag, \"Open dataset as a new session\", false);\n    _stateChangeFlag = false;\n    _paramsMgr->TriggerManualStateChangeEvent(\"Session Opened\");\n\n    _leftPanel->GoToRendererTab();\n}\n\n\nvoid MainForm::showOpenSessionGUI()\n{\n    if (_stateChangeFlag) {\n        QMessageBox msgBox;\n        msgBox.setWindowTitle(\"Are you sure?\");\n        msgBox.setText(\"The current session settings are not saved. Do you want to continue? \\nYou can choose \\\"No\\\" now to go back and save the current session.\");\n        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);\n        msgBox.setDefaultButton(QMessageBox::No);\n        if (msgBox.exec() == QMessageBox::No) { return; }\n    }\n\n    string sessionDir = GetStateParams()->GetCurrentSessionFile();\n    if (sessionDir.empty())\n        sessionDir = GetSettingsParams()->GetSessionDir();\n\n    const vector<string> files = getUserFileSelection(\"Choose a VAPOR session file to restore a session\", sessionDir, \"Vapor 3 Session Save Files (*.vs3)\", false);\n    if (files.empty()) return;\n    const string path = files[0];\n    if (!FileOperationChecker::FileGoodToRead(path.c_str())) {\n        MSG_ERR(FileOperationChecker::GetLastErrorMessage().toStdString());\n        return;\n    }\n\n    openSession(path);\n}\n\n\noptional<ControlExec::LoadStateRelAndAbsPathsExistAction> MainForm::showSelectRelVAbsDataLoadGUI(const ControlExec::RelAndAbsPathsExistException &e)\n{\n    QStringList items({QString::fromStdString(e.AbsolutePath), QString::fromStdString(e.RelativePath)});\n    bool ok;\n    QString item = QInputDialog::getItem(this, tr(\"Load Data\"), tr(\"Multiple dataset options found. Select which to load.\"), items, 0, false, &ok);\n    if (!ok || item.isEmpty()) return {};\n    if (item.toStdString() == e.RelativePath) return ControlExec::LoadStateRelAndAbsPathsExistAction::LoadRel;\n    if (item.toStdString() == e.AbsolutePath) return ControlExec::LoadStateRelAndAbsPathsExistAction::LoadAbs;\n    return {};\n}\n\n\nvoid MainForm::checkSessionDatasetsExist()\n{\n    GUIStateParams *sp = GetStateParams();\n\n    for (const auto & dataset : sp->GetOpenDataSetNames()) {\n        vector<string> paths = sp->GetOpenDataSetPaths(dataset);\n        if (!std::all_of(paths.begin(), paths.end(), [](string path) { return FileUtils::Exists(path); })) {\n            sp->RemoveOpenDataSet(dataset);\n\n            string err = \"This session links to the dataset \" + dataset + \" which was not found. Please open this dataset if it is in a different location\";\n            string details;\n            for (const auto &path : paths)\n                if (!FileUtils::Exists(path)) details += \"\\\"\" + path + \"\\\" not found.\\n\";\n\n            ErrorReporter::GetInstance()->Report(err, ErrorReporter::Warning, details);\n        }\n    }\n}\n\n\nvoid MainForm::closeAllParamsDatasets()\n{\n    GUIStateParams *p = GetStateParams();\n    vector<string>  dataSetNames = p->GetOpenDataSetNames();\n    for (int i = 0; i < dataSetNames.size(); i++) { _controlExec->CloseData(dataSetNames[i]); }\n}\n\n\nvoid MainForm::SaveSession()\n{\n    const auto currentSessionPath = GetStateParams()->GetCurrentSessionFile();\n    if (currentSessionPath.empty())\n        SaveSessionAs();\n    else\n        SaveSession(currentSessionPath);\n}\n\n\nvoid MainForm::SaveSession(string path)\n{\n    assert(!path.empty());\n\n    if (!FileOperationChecker::FileGoodToWrite(QString::fromStdString(path))) {\n        MSG_ERR(FileOperationChecker::GetLastErrorMessage().toStdString());\n        return;\n    }\n\n    if (_controlExec->SaveSession(path) < 0) {\n        MSG_ERR(\"Saving session file failed\");\n        return;\n    }\n\n    GUIStateParams *p = GetStateParams();\n    _paramsMgr->PushSaveStateEnabled(false);\n    p->SetCurrentSessionFile(path);\n    _paramsMgr->PopSaveStateEnabled();\n\n    _stateChangeFlag = false;\n}\n\n\nvoid MainForm::SaveSessionAs()\n{\n    SettingsParams *sP = GetSettingsParams();\n    GUIStateParams *guiStateParams = GetStateParams();\n\n    string dir;\n    if (!guiStateParams->GetCurrentSessionFile().empty())\n        dir = guiStateParams->GetCurrentSessionFile();\n    else\n        dir = sP->GetSessionDir();\n\n    QFileDialog fileDialog(this, \"Save VAPOR session file\", QString::fromStdString(dir), QString(\"Vapor 3 Session Save file (*.vs3)\"));\n\n    fileDialog.setAcceptMode(QFileDialog::AcceptSave);\n    fileDialog.setDefaultSuffix(QString(\"vs3\"));\n    if (fileDialog.exec() != QDialog::Accepted) return;\n\n    QStringList files = fileDialog.selectedFiles();\n    if (files.isEmpty() || files.size() > 1) return;\n\n    SaveSession(files[0].toStdString());\n}\n\n\nvoid MainForm::_stateChangeCB()\n{\n    if (_paramsEventQueued) return;\n    _paramsEventQueued = true;\n\n    QEvent *event = new QEvent(ParamsChangeEvent);\n    QApplication::postEvent(this, event);\n\n    _eventsSinceLastSave++;\n}\n\nvoid MainForm::_intermediateStateChangedCB()\n{\n    if (_paramsEventQueued) return;\n    _paramsEventQueued = true;\n\n    QEvent *event = new QEvent(ParamsIntermediateChangeEvent);\n    QApplication::postEvent(this, event);\n}\n\n\nvoid MainForm::helpAbout()\n{\n    std::string banner_file_name = \"vapor_banner.png\";\n    if (_banner) delete _banner;\n    std::string banner_text = \"Visualization and Analysis Platform for atmospheric, Oceanic and \"\n                              \"solar Research.\\n\\n\"\n                              \"Developed by the National Center for Atmospheric Research's (NCAR) \\n\"\n                              \"Computational and Information Systems Lab. \\n\\n\"\n                              \"Boulder, Colorado 80305, U.S.A.\\n\"\n                              \"Web site: http://www.vapor.ucar.edu\\n\"\n                              \"Contact: vapor@ucar.edu\\n\"\n                              \"Version: \"\n                            + string(Version::GetFullVersionString().c_str());\n\n    _banner = new BannerGUI(this, banner_file_name, -1, true, banner_text.c_str(), \"http://www.vapor.ucar.edu\");\n}\n\nvoid MainForm::showImportDatasetGUI(string format)\n{\n    static vector<pair<string, string>> prompts = GetDatasets();\n\n    string defaultPath;\n    auto openDatasets = GetStateParams()->GetOpenDataSetNames();\n    if (!openDatasets.empty())\n        defaultPath = GetStateParams()->GetOpenDataSetPaths(openDatasets.back())[0];\n    else\n        defaultPath = GetSettingsParams()->GetMetadataDir();\n\n    auto files = getUserFileSelection(DatasetTypeDescriptiveName(format), defaultPath, \"\", format!=\"vdc\");\n    if (files.empty()) return;\n\n    _datasetImportController->ImportDataset(_controlExec, files, format, DatasetImportController::DatasetExistsAction::Prompt);\n}\n\n\nbool MainForm::doesQStringContainNonASCIICharacter(const QString &s)\n{\n    for (int i = 0; i < s.length(); i++)\n        if (s.at(i).unicode() > 127) return true;\n    return false;\n}\n\nint MainForm::checkQStringContainsNonASCIICharacter(const QString &s)\n{\n    if (doesQStringContainNonASCIICharacter(s)) {\n#ifdef WIN32\n        MyBase::SetErrMsg(\"Windows will convert a colon (common in WRF timestamps) to a non-ASCII dot character. This needs to be renamed.\\n\");\n#endif\n        MyBase::SetErrMsg(\"Vapor does not support paths with non-ASCII characters.\\n\");\n        MSG_ERR(\"Non ASCII Character in path\");\n        return -1;\n    }\n    return 0;\n}\n\nvector<string> MainForm::getUserFileSelection(string prompt, string dir, string filter, bool multi)\n{\n    QString qPrompt(prompt.c_str());\n    QString qDir(dir.c_str());\n    QString qFilter(filter.c_str());\n\n    vector<string> files;\n    if (multi) {\n        QStringList           fileNames = QFileDialog::getOpenFileNames(this, qPrompt, qDir, qFilter);\n        QStringList           list = fileNames;\n        QStringList::Iterator it = list.begin();\n        while (it != list.end()) {\n            if (!it->isNull()) {\n                if (checkQStringContainsNonASCIICharacter(*it) < 0)\n                    return {};\n                files.push_back((*it).toStdString());\n            }\n            ++it;\n        }\n    } else {\n        QString fileName = QFileDialog::getOpenFileName(this, qPrompt, qDir, qFilter);\n        if (!fileName.isNull()) {\n            if (checkQStringContainsNonASCIICharacter(fileName) < 0)\n                return {};\n            files.push_back(fileName.toStdString());\n        }\n    }\n\n    for (int i = 0; i < files.size(); i++) {\n        QFileInfo fInfo(files[i].c_str());\n        if (!fInfo.isReadable() || !fInfo.isFile()) {\n            MyBase::SetErrMsg(\"File %s not readable\", files[i].c_str());\n            MSG_ERR(\"Invalid file selection\");\n            return {};\n        }\n    }\n    return (files);\n}\n\nvoid MainForm::sessionNew()\n{\n    // Disable \"Are you sure?\" popup in debug build\n#ifdef NDEBUG\n    if (_stateChangeFlag) {\n        QMessageBox msgBox;\n        msgBox.setWindowTitle(\"Are you sure?\");\n        msgBox.setText(\"The current session settings are not saved. Do you want to continue? \\nYou can choose \\\"No\\\" now to go back and save the current session.\");\n        msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);\n        msgBox.setDefaultButton(QMessageBox::No);\n        if (msgBox.exec() == QMessageBox::No) { return; }\n    }\n#endif\n\n    closeProjectionFrame();\n    _controlExec->LoadState();\n    GetStateParams()->SetActiveVizName(_paramsMgr->CreateVisualizerParamsInstance());\n    _paramsMgr->UndoRedoClear();\n\n    _stateChangeFlag = false;\n    GetStateParams()->SetValueLong(GUIStateParams::SessionNewTag, \"Toggle SessionNewTag to true for a new session\", true);\n}\n\nvoid MainForm::_setAnimationOnOff(bool on)\n{\n    if (on) {\n        enableAnimationWidgets(false);\n        _App->removeEventFilter(this);\n    } else {\n        _playForwardAction->setChecked(false);\n        _playBackwardAction->setChecked(false);\n        enableAnimationWidgets(true);\n        _App->installEventFilter(this);\n        _paramsEventQueued = false;\n    }\n}\n\nvoid MainForm::showCitationReminder()\n{\n    // Disable citation reminder in Debug build\n#ifndef NDEBUG\n    return;\n#endif\n    if (!_begForCitation) return;\n    _begForCitation = false;\n    CitationReminder::Show();\n}\n\nvoid MainForm::Render(bool fast, bool skipSync)\n{\n    bool wasMenuBarEnabled = menuBar()->isEnabled();\n    bool wasProgressEnabled = _progressEnabled;\n    menuBar()->setEnabled(false);\n    _progressEnabled = true;\n\n    if (!skipSync) {\n        setUpdatesEnabled(false);\n        _controlExec->SyncWithParams();\n        setUpdatesEnabled(true);\n    }\n\n    _vizWinMgr->Update(fast);\n    _progressEnabled = wasProgressEnabled;\n    menuBar()->setEnabled(wasMenuBarEnabled);\n}\n\nbool MainForm::eventFilter(QObject *obj, QEvent *event)\n{\n    VAssert(_controlExec && _vizWinMgr);\n\n    if (event->type() == ParamsChangeEvent || event->type() == ParamsIntermediateChangeEvent) {\n        _controlExec->EnforceDefaultAppState();\n        _paramsEventQueued = false;\n    }\n\n    if (_insideMessedUpQtEventLoop) {\n        // Prevent menu item actions from running\n        if (event->type() == QEvent::MetaCall) return true;\n        // Prevent queued ParamsChangedEvents from recursively running\n        if (event->type() == ParamsChangeEvent || event->type() == ParamsIntermediateChangeEvent)\n            return true;\n        // Prevent user input for all widgets except the cancel button. This is essentially\n        // the same behavior as we had before because the application would\n        // freeze during a render so all user input was essentially blocked.\n        // Since the events are processed top-down, we need to check to check\n        // if this is not only the cancel button, but any of its parents\n        if (_disableUserInputForAllExcept != nullptr && obj->isWidgetType()) {\n            if (dynamic_cast<QInputEvent *>(event)) {\n                const QObject *test = _disableUserInputForAllExcept;\n                do {\n                    if (obj == test) return false;    // Approve input\n                } while (test = test->parent());\n                return true;    // Reject input\n            }\n        }\n    }\n\n    if (event->type() == ParamsChangeEvent) {\n        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));\n\n        setUpdatesEnabled(false);\n        _controlExec->SyncWithParams();\n        updateUI();\n        setUpdatesEnabled(true);\n\n        Render(false, true);\n\n        QApplication::restoreOverrideCursor();\n        return true;\n    }\n\n    if (event->type() == ParamsIntermediateChangeEvent) {\n        // Rendering the GUI becomes a bottleneck and generally should not be affected by intermediate changes\n        // updateUI();\n#ifndef NDEBUG\n        // Normally GUI doesn't get intermediate changes but this is for testing only\n        _paramsWidgetDemo->Update(GetStateParams(), _paramsMgr);\n#endif\n\n        Render(true);\n\n        return true;\n    }\n\n    return false;\n}\n\nvoid MainForm::updateMenus()\n{\n    _editUndoAction->setEnabled((bool)_paramsMgr->UndoSize());\n    _editRedoAction->setEnabled((bool)_paramsMgr->RedoSize());\n}\n\nvoid MainForm::_performSessionAutoSave()\n{\n    if (_paramsMgr == NULL) return;\n\n    SettingsParams *sParams = GetSettingsParams();\n    if (sParams == NULL) return;\n\n    int eventCountForAutoSave = sParams->GetChangesPerAutoSave();\n\n    if (eventCountForAutoSave == 0) return;\n    if (!sParams->GetSessionAutoSaveEnabled()) return;\n\n    if (_eventsSinceLastSave >= eventCountForAutoSave) {\n        string autoSaveFile = sParams->GetAutoSaveSessionFile();\n        int    rc = _paramsMgr->SaveToFile(autoSaveFile);\n        if (rc < 0) { MSG_ERR(\"Unable to write settings file \" + autoSaveFile); }\n        _eventsSinceLastSave = 0;\n    }\n}\n\nvoid MainForm::updateUI()\n{\n    VAssert(_controlExec);\n\n    _widgetsEnabled = !GetStateParams()->GetOpenDataSetNames().empty();\n\n    for (auto &e : _dependOnLoadedData) e->setEnabled(_widgetsEnabled);\n\n    _leftPanel->ConfigureEnabledState(_widgetsEnabled);\n\n    for (const auto &e : _updatableElements) \n        e->Update();\n\n    auto sp= _widgetsEnabled ? GetStateParams() : nullptr;\n    for (const auto &e : _guiStateParamsUpdatableElements)\n        e->Update(sp, _paramsMgr);\n\n\n    _timeStepEdit->Update(GetStateParams()); // TODO this needs special handling for animation playback\n    updateMenus();\n    _appSettingsMenu->Update(GetSettingsParams());\n\n    _performSessionAutoSave();\n}\n\nvoid MainForm::enableAnimationWidgets(bool on)\n{\n    if (on) {\n        _playBackwardAction->setEnabled(true);\n        _stepBackAction->setEnabled(true);\n        _stepForwardAction->setEnabled(true);\n        _playForwardAction->setEnabled(true);\n    } else {\n        _animationToolBar->setEnabled(true);\n        _playBackwardAction->setEnabled(false);\n        _stepBackAction->setEnabled(false);\n        _stepForwardAction->setEnabled(false);\n        _playForwardAction->setEnabled(false);\n    }\n}\n\nvoid MainForm::launchStats()\n{\n    if (!_stats) {\n        _stats = new Statistics(this);\n        _updatableElements.insert(_stats);\n        connect(_stats, &QDialog::finished, this, &MainForm::_statsClosed);\n    }\n    if (_controlExec) { _stats->initControlExec(_controlExec); }\n    _stats->showMe();\n}\n\nvoid MainForm::_statsClosed()\n{\n    _updatableElements.erase(_stats);\n    delete _stats;\n    _stats = nullptr;\n}\n\nvoid MainForm::launchPlotUtility()\n{\n    if (!_plot) {\n        _plot = new Plot(_controlExec->GetDataStatus(), _controlExec->GetParamsMgr(), this);\n        _updatableElements.insert(_plot);\n        connect(_plot, &QDialog::finished, this, &MainForm::_plotClosed);\n    }\n    _plot->Update();\n    _plot->open();\n}\n\nvoid MainForm::_plotClosed()\n{\n    _updatableElements.erase(_plot);\n    delete _plot;\n    _plot = nullptr;\n}\n\nvoid MainForm::launchPythonVariables()\n{\n    if (!_pythonVariables){\n        _pythonVariables = new PythonVariables(this);\n        _updatableElements.insert(_pythonVariables);\n    }\n    _pythonVariables->InitControlExec(_controlExec);\n    _pythonVariables->ShowMe();\n}\n\nvoid MainForm::launchProjectionFrame()\n{\n    if (_projectionFrame == nullptr){\n        _projectionFrame = new VProjectionStringFrame(new PProjectionStringWidget(_controlExec));\n        connect(_projectionFrame, &VProjectionStringFrame::closed, this, &MainForm::closeProjectionFrame);\n        _projectionFrame->adjustSize();\n        _projectionFrame->Update(GetStateParams());\n        _guiStateParamsUpdatableElements.insert(_projectionFrame);\n    }\n    _projectionFrame->raise();\n}\n\nvoid MainForm::closeProjectionFrame() {\n    if (_projectionFrame != nullptr) {\n        _guiStateParamsUpdatableElements.erase(_projectionFrame);\n        _projectionFrame->close();\n        _projectionFrame = nullptr;\n    }\n}\n\nvoid MainForm::AnimationPlayForward() const {\n    _animationController->AnimationPlayForward();\n}\n"
  },
  {
    "path": "apps/vaporgui/MainForm.h",
    "content": "#pragma once\n\n#include \"vapor/VAssert.h\"\n#include <qvariant.h>\n#include <qmainwindow.h>\n#include <qstring.h>\n#include <QPaintEvent>\n#include <QActionGroup>\n#include <QLabel>\n#include <QComboBox>\n#include <QIcon>\n#include <QLineEdit>\n#include <QWidgetAction>\n#include <chrono>\n#include <set>\n#include <optional>\n#include <vapor/ControlExecutive.h>\n#include <vapor/GUIStateParams.h>\n#include <vapor/SettingsParams.h>\n#include <vapor/AnimationParams.h>\n#include \"AnimationController.h\"\n#include \"PWidgetsFwd.h\"\n#include \"QEnableable.h\"\n\nclass QApplication;\nclass QSpacerItem;\nclass QMenu;\nclass QToolBar;\nclass QWidget;\nclass QMdiArea;\nclass QLabel;\nclass QSpinBox;\nclass ProgressStatusBar;\nclass QTimer;\nclass QDialog;\n\nclass VizWinMgr;\nclass Updatable;\nclass ParamsUpdatable;\n\nclass BannerGUI;\nclass Statistics;\nclass Plot;\nclass PythonVariables;\nclass VProjectionStringFrame;\nclass ErrorReporter;\nclass ParamsWidgetDemo;\nclass AppSettingsMenu;\nclass CaptureController;\nclass DatasetImportController;\n\nclass LeftPanel;\n\nusing namespace VAPoR;\nusing std::optional;\n\nclass MainForm : public QMainWindow {\n    Q_OBJECT\n\npublic:\n    MainForm(vector<QString> files, QApplication *app, bool interactive = true, string filesType = \"auto\", QWidget *parent = 0);\n    ~MainForm();\n\n    int RenderAndExit(int start, int end, const std::string &baseFile, int width, int height);\n    static QWidget* Instance() { assert(_instance); return _instance; }\n\n    // Needed for Export/Capture widget\n    void AnimationPlayForward() const;\n\nprotected:\n    void Render(bool fast=false, bool skipSync=false);\n    bool eventFilter(QObject *obj, QEvent *event);\n\nprivate:\n    static const QEvent::Type ParamsChangeEvent;\n    static const QEvent::Type ParamsIntermediateChangeEvent;\n\n    QApplication *_App;\n    static MainForm *_instance;\n\n    QAction *_playForwardAction;\n    QAction *_playBackwardAction;\n    QAction *_pauseAction;\n\n    QAction * _editUndoAction;\n    QAction * _editRedoAction;\n    PWidget * _timeStepEdit;\n\n    QMenu *    _captureMenu;\n    QMenu *    _developerMenu;\n\n    QToolBar *_animationToolBar;\n\n    QAction *_stepForwardAction;\n    QAction *_stepBackAction;\n\n    int      _progressSavedFB = -1;\n    bool     _progressEnabled = false;\n    QAction *_progressEnabledMenuItem = nullptr;\n\n    ProgressStatusBar *                                _status = nullptr;\n    std::chrono::time_point<std::chrono::system_clock> _progressLastUpdateTime;\n    const QObject *                                    _disableUserInputForAllExcept = nullptr;\n    bool                                               _insideMessedUpQtEventLoop = false;\n\n    LeftPanel           *_leftPanel;\n    Statistics *        _stats = nullptr;\n    Plot *              _plot = nullptr;\n    PythonVariables *   _pythonVariables = nullptr;\n    VProjectionStringFrame* _projectionFrame = nullptr;\n    AppSettingsMenu *   _appSettingsMenu = nullptr;\n    BannerGUI *         _banner = nullptr;\n    std::set<Updatable *> _updatableElements;\n    std::set<ParamsUpdatable *> _guiStateParamsUpdatableElements;\n    std::set<std::unique_ptr<QEnableableI>> _dependOnLoadedData;\n    template<typename T> void _dependOnLoadedData_insert(T *o) { _dependOnLoadedData.insert(std::make_unique<QEnableable<T>>(o)); }\n\n    VAPoR::ControlExec *_controlExec;\n    VAPoR::ParamsMgr *  _paramsMgr;\n    CaptureController *_captureController;\n    DatasetImportController *_datasetImportController;\n    AnimationController *_animationController;\n    VizWinMgr *         _vizWinMgr;\n    string              _capturingAnimationVizName;\n\n    bool _stateChangeFlag = false;\n    bool _sessionNewFlag = false;\n    bool _begForCitation = false;\n    int  _eventsSinceLastSave = 0;\n    bool _paramsEventQueued = false;\n    bool _widgetsEnabled;\n\n    ParamsWidgetDemo *_paramsWidgetDemo = nullptr;\n\n    void _performSessionAutoSave();\n    void _stateChangeCB();\n    void _intermediateStateChangedCB();\n\n    QApplication *getApp() { return _App; }\n\n    void setPause()\n    {\n        _playForwardAction->setChecked(false);\n        _playBackwardAction->setChecked(false);\n        _pauseAction->setChecked(true);\n    }\n\n    void showCitationReminder();\n\n    GUIStateParams *GetStateParams() const { return ((GUIStateParams *)_paramsMgr->GetParams(GUIStateParams::GetClassType())); }\n    SettingsParams *GetSettingsParams() const { return ((SettingsParams *)_paramsMgr->GetParams(SettingsParams::GetClassType())); }\n    AnimationParams *GetAnimationParams() const { return ((AnimationParams *)_paramsMgr->GetParams(AnimationParams::GetClassType())); }\n\n    void                updateMenus();\n    void                updateUI();\n    static bool         doesQStringContainNonASCIICharacter(const QString &s);\n    static int          checkQStringContainsNonASCIICharacter(const QString &s);\n    std::vector<string> getUserFileSelection(string prompt, string dir, string filter, bool multi);\n\n    void showImportDatasetGUI(string format);\n    void openSession(const string &path, bool loadData=true);\n    void showOpenSessionGUI();\n    optional<ControlExec::LoadStateRelAndAbsPathsExistAction> showSelectRelVAbsDataLoadGUI(const ControlExec::RelAndAbsPathsExistException &e);\n    void checkSessionDatasetsExist();\n    void         _createToolsMenu();\n    void         _createEditMenu();\n    void         _createFileMenu();\n    void         _createHelpMenu();\n    void         _createDeveloperMenu();\n    void         createMenus();\n    void         _createAnimationToolBar();\n    void         createToolBars();\n    void         _createProgressWidget();\n    void         _disableProgressWidget();\n    void         closeAllParamsDatasets();\n\n    template<class T> bool isDatasetValidFormat(const std::vector<std::string> &paths) const;\n    bool                   determineDatasetFormat(const std::vector<std::string> &paths, std::string *fmt) const;\n\n    bool isOpenGLContextActive() const;\n    void enableAnimationWidgets(bool onOff);\n    void SaveSession();\n    void SaveSession(string path);\n    void SaveSessionAs();\n\nprivate slots:\n    void _plotClosed();\n    void _statsClosed();\n    void closeProjectionFrame();\n    void helpAbout();\n    void sessionNew();\n    void launchStats();\n    void launchPlotUtility();\n    void launchPythonVariables();\n    void launchProjectionFrame();\n    void _setAnimationOnOff(bool onOff);\n};\n"
  },
  {
    "path": "apps/vaporgui/MainForm_isOpenGLContextActive.cpp",
    "content": "#include \"MainForm.h\"\n#include <QOpenGLContext>\n\n// This is to address a warning caused by QOpenGLContext and vapor/glutil.h\n// being imported in the same file.\n\nbool MainForm::isOpenGLContextActive() const { return (bool)QOpenGLContext::currentContext(); }\n"
  },
  {
    "path": "apps/vaporgui/Manip.cpp",
    "content": "/************************************************************************/\n//\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2005\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tManip.cpp\n//\n//\tAuthor:\t\tAlan Norton, Scott Pearse\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune, 2018\n//\n//\tDescription:\tImplements the Manip class and some of its subclasses\n\n#include <iterator>\n#include <iomanip>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n\n#include \"Manip.h\"\n#include \"vapor/GLManager.h\"\n#include \"vapor/LegacyGL.h\"\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n\n#include <glm/glm.hpp>\nusing glm::vec3;\n\nusing namespace VAPoR;\n\nconst float Manip::_faceSelectionColor[4] = {0.8f, 0.8f, 0.0f, 0.5f};\nconst float Manip::_unselectedFaceColor[4] = {0.8f, 0.2f, 0.0f, 0.5f};\n\n#ifndef M_PI\n    #define M_PI (3.14159265358979323846)\n#endif\n\n// X, Y, and Z axes are indexed 0, 1, and 2\n#define X 0\n#define Y 1\n#define Z 2\n\n// 6 element arrays that describe 3D extents have the ordering\n//   MINX, MINY, MINZ, MAXX, MAXY, MAXZ\n#define MINX 0\n#define MINY 1\n#define MINZ 2\n#define MAXX 3\n#define MAXY 4\n#define MAXZ 5\n\n// Handle mapping\n#define X_Neg          2\n#define X_Pos          3\n#define Y_Neg          4\n#define Y_Pos          1\n#define Z_Neg          0\n#define Z_Pos          5\n#define INVALID_HANDLE -1\n\nTranslateStretchManip::TranslateStretchManip(GLManager *glManager) : Manip(glManager)\n{\n    _buttonNum = 0;\n    _selectedHandle = -1;\n    _isStretching = false;\n    _tempRotation = 0.f;\n    _tempRotAxis = -1;\n    _handleSizeInScene = 1.;\n    _dragDistance = 0.f;\n    _mouseDownHere = false;\n\n    for (int i = 0; i < 3; i++) {\n        _initialSelectionRay[i] = 0.;\n        _cameraPosition[i] = 0.;\n        _handleMid[i] = 0.f;\n\n        _selection[i] = 0.;\n        _selection[i + 3] = 0.;\n        _extents[i] = 0.;\n        _extents[i + 3] = 0.;\n    }\n}\n\nvoid TranslateStretchManip::transformMatrix(VAPoR::Transform *transform, std::vector<double> parentScales)\n{\n    MatrixManager *mm = _glManager->matrixManager;\n\n    mm->MatrixModeModelView();\n\n    // Use the ModelViewMatrix passed in upon Update(),\n    // not what is currently held in the gl state\n    mm->LoadMatrixd(_modelViewMatrix);\n\n    mm->PushMatrix();\n\n    if (transform == NULL) return;\n\n    vector<double> translations = transform->GetTranslations();\n    vector<double> rotations = transform->GetRotations();\n    vector<double> scales = transform->GetScales();\n    vector<double> origin = transform->GetOrigin();\n    VAssert(translations.size() == 3);\n    VAssert(rotations.size() == 3);\n    VAssert(scales.size() == 3);\n    VAssert(origin.size() == 3);\n\n\n    mm->Translate(translations[0], translations[1], translations[2]);\n    mm->Scale(1 / parentScales[0], 1 / parentScales[1], 1 / parentScales[2]);\n    mm->Translate(origin[0], origin[1], origin[2]);\n    mm->Rotate(glm::radians(rotations[0]), 1, 0, 0);\n    mm->Rotate(glm::radians(rotations[1]), 0, 1, 0);\n    mm->Rotate(glm::radians(rotations[2]), 0, 0, 1);\n    mm->Scale(scales[0], scales[1], scales[2]);\n    mm->Translate(-origin[0], -origin[1], -origin[2]);\n\n    mm->Scale(parentScales[0], parentScales[1], parentScales[2]);\n\n    // Retrieve the transformed matrix and stick it back into\n    // our _modelViewMatrix array\n    mm->GetDoublev(MatrixManager::Mode::ModelView, _modelViewMatrix);\n}\n\nvoid TranslateStretchManip::Update(std::vector<double> llc, std::vector<double> urc, std::vector<double> minExts, std::vector<double> maxExts, VAPoR::Transform *rpTransform,\n                                   VAPoR::Transform *dmTransform, bool constrain)\n{\n    MatrixManager *mm = _glManager->matrixManager;\n    mm->GetDoublev(MatrixManager::Mode::Projection, _projectionMatrix);\n    mm->GetDoublev(MatrixManager::Mode::ModelView, _modelViewMatrix);\n\n    GLint viewport[4];\n    glGetIntegerv(GL_VIEWPORT, viewport);\n    _windowSize[0] = viewport[2];\n    _windowSize[1] = viewport[3];\n\n    double minv[16];\n    int    rc = minvert(_modelViewMatrix, minv);\n    VAssert(rc >= 0);\n\n    _cameraPosition[X] = minv[12];\n    _cameraPosition[Y] = minv[13];\n    _cameraPosition[Z] = minv[14];\n\n    double defaultZ = 0;\n    if (llc.size() == 2) llc.push_back(defaultZ);\n    if (urc.size() == 2) urc.push_back(defaultZ);\n    if (minExts.size() == 2) minExts.push_back(defaultZ);\n    if (maxExts.size() == 2) maxExts.push_back(defaultZ);\n\n    std::copy(llc.begin(), llc.end(), _selection);\n    std::copy(urc.begin(), urc.end(), _selection + 3);\n    std::copy(minExts.begin(), minExts.end(), _extents);\n    std::copy(maxExts.begin(), maxExts.end(), _extents + 3);\n\n    _rpTransform = rpTransform;\n    _dmTransform = dmTransform;\n\n    _constrain = constrain;\n}\n\nvoid TranslateStretchManip::GetBox(std::vector<double> &llc, std::vector<double> &urc) const\n{\n    llc.resize(3);\n    urc.resize(3);\n    llc[X] = _selection[MINX];\n    llc[Y] = _selection[MINY];\n    llc[Z] = _selection[MINZ];\n    urc[X] = _selection[MAXX];\n    urc[Y] = _selection[MAXY];\n    urc[Z] = _selection[MAXZ];\n}\n\nbool TranslateStretchManip::MouseEvent(int buttonNum, std::vector<double> vscreenCoords, double handleMidpoint[3], bool release)\n{\n    double screenCoords[2] = {vscreenCoords[0], vscreenCoords[1]};\n\n    if (_selectedHandle < 0) _selectedHandle = _mouseIsOverHandle(screenCoords, handleMidpoint);\n\n    if (_selectedHandle < 0) return false;\n\n    if (release) {    // Release\n        _mouseRelease(screenCoords);\n    } else if (buttonNum == _buttonNum) {    // Dragging\n        if (!_mouseDownHere) return false;\n        _mouseDrag(screenCoords, handleMidpoint);\n    } else if (_buttonNum == 0) {    // Press\n        _mousePress(screenCoords, handleMidpoint, buttonNum);\n    }\n\n    return true;\n}\n\nvoid TranslateStretchManip::_mouseDrag(double screenCoords[2], double handleMidpoint[3])\n{\n    if (_selectedHandle >= 0) {\n        double projScreenCoords[2];\n        bool   success = projectPointToLine(screenCoords, projScreenCoords);\n        if (success) {\n            double dirVec[3];\n            double mouseWorldPos[3];\n            pixelToVector(projScreenCoords, dirVec, handleMidpoint, mouseWorldPos);\n\n            vec3 norm(0, 0, 1);\n            if (_selectedHandle == X_Neg || _selectedHandle == X_Pos) norm = vec3(1, 0, 0);\n            if (_selectedHandle == Y_Neg || _selectedHandle == Y_Pos) norm = vec3(0, 1, 0);\n\n            vec3 mouseWorld(mouseWorldPos[0], mouseWorldPos[1], mouseWorldPos[2]);\n            vec3 handleWorld(handleMidpoint[0], handleMidpoint[1], handleMidpoint[2]);\n\n            float handleProjToNorm = glm::dot(norm, handleWorld);\n            float mouseProjToNorm = glm::dot(norm, mouseWorld);\n\n            _dragDistance = mouseProjToNorm - handleProjToNorm;\n\n            if (_buttonNum == 3) {    // Don't restrict movement if using the manip to drag\n                // Copied from old code\n                // Prevent handle from going through opposite handle\n                int oppositeHandle = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3);\n                if (_selectedHandle < 3) {\n                    if (_dragDistance + _selection[oppositeHandle] > _selection[oppositeHandle + 3]) { _dragDistance = _selection[oppositeHandle + 3] - _selection[oppositeHandle]; }\n                } else {    // Moving \"high\" handle:\n                    if (_dragDistance + _selection[oppositeHandle + 3] < _selection[oppositeHandle]) { _dragDistance = _selection[oppositeHandle] - _selection[oppositeHandle + 3]; }\n                }\n            }\n        }\n    }\n}\n\nvoid TranslateStretchManip::_mousePress(double screenCoords[2], double handleMidpoint[3], int buttonNum)\n{\n    double dirVec[3];\n    pixelToVector(screenCoords, dirVec, handleMidpoint);\n    _captureMouseDown(_selectedHandle, buttonNum, handleMidpoint);\n    startHandleSlide(screenCoords, _selectedHandle);\n    setMouseDown(true);\n}\n\nvoid TranslateStretchManip::_mouseRelease(double screenCoords[2])\n{\n    if (_selectedHandle >= 0) {\n        int axis = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3);\n        // Convert _dragDistance to world coords:\n        float dist = _dragDistance;\n\n        // Check if we are stretching.  If so, only move coords associated with\n        // handle:\n        if (_isStretching) {\n            // boxMin gets changed for nearHandle, boxMax for farHandle\n            if (_selectedHandle < 3) {\n                _selection[axis] += dist;\n            } else {\n                _selection[axis + 3] += dist;\n            }\n        } else {\n            // boxMin gets changed for nearHandle, boxMax for farHandle\n            _selection[axis] += dist;\n            _selection[axis + 3] += dist;\n        }\n    }\n\n    if (_constrain) _constrainExtents();\n\n    _dragDistance = 0.f;\n    _selectedHandle = -1;\n    _buttonNum = 0;\n    setMouseDown(false);\n}\n\nint TranslateStretchManip::_mouseIsOverHandle(const double screenCoords[2], double handleMid[3]) const\n{\n    double handle[8][3];\n\n    int octant = 0;\n    int face, handleNum;\n    for (int axis = 0; axis < 3; axis++) {\n        double axisBoundary = 0.5f * (_selection[axis] + _selection[axis + 3]);\n        if (_cameraPosition[axis] > axisBoundary) { octant |= 1 << axis; }\n    }\n\n    // Front handles\n    for (int sortNum = 0; sortNum < 3; sortNum++) {\n        handleNum = makeHandleFaces(sortNum, handle, octant, _selection);\n        if ((face = pointIsOnBox(handle, screenCoords)) >= 0) {\n            for (int i = 0; i < 3; i++) {\n                handleMid[i] = 0.;\n                for (int k = 0; k < 8; k++) handleMid[i] += handle[k][i];\n                handleMid[i] /= 8.;\n            }\n            return handleNum;\n        }\n    }\n\n    // Back handles\n    for (int sortNum = 3; sortNum < 6; sortNum++) {\n        handleNum = makeHandleFaces(sortNum, handle, octant, _selection);\n        if ((face = pointIsOnBox(handle, screenCoords)) >= 0) {\n            for (int i = 0; i < 3; i++) {\n                handleMid[i] = 0.;\n                for (int k = 0; k < 8; k++) handleMid[i] += handle[k][i];\n                handleMid[i] /= 8.;\n            }\n            return handleNum;\n        }\n    }\n    return -1;\n}\n\nvoid TranslateStretchManip::_constrainExtents()\n{\n    for (int i = 0; i < 3; i++) {\n        // correct selection minimum\n        if (_selection[i] < _extents[i]) _selection[i] = _extents[i];\n        if (_selection[i] > _extents[i + 3]) _selection[i] = _extents[i + 3];\n\n        // correct selection maximum\n        if (_selection[i + 3] < _extents[i]) _selection[i + 3] = _extents[i];\n        if (_selection[i + 3] > _extents[i + 3]) _selection[i + 3] = _extents[i + 3];\n    }\n}\n\nbool TranslateStretchManip::pointIsOnQuad(double cor1[3], double cor2[3], double cor3[3], double cor4[3], const double pickPt[2]) const\n{\n    double winCoord1[2];\n    double winCoord2[2];\n    double winCoord3[2];\n    double winCoord4[2];\n    bool   returnValue = true;\n    if (!_projectPointToWin(cor1, winCoord1)) returnValue = false;\n    if (!_projectPointToWin(cor2, winCoord2)) returnValue = false;\n    if (pointOnRight(winCoord1, winCoord2, pickPt)) returnValue = false;\n    if (!_projectPointToWin(cor3, winCoord3)) returnValue = false;\n    if (pointOnRight(winCoord2, winCoord3, pickPt)) returnValue = false;\n    if (!_projectPointToWin(cor4, winCoord4)) returnValue = false;\n    if (pointOnRight(winCoord3, winCoord4, pickPt)) returnValue = false;\n    if (pointOnRight(winCoord4, winCoord1, pickPt)) returnValue = false;\n\n#ifdef DEBUG\n    drawHitBox(winCoord1, winCoord2, winCoord3, winCoord4);\n#endif\n\n    return returnValue;\n}\n\nint TranslateStretchManip::pointIsOnBox(double corners[8][3], const double pickPt[2]) const\n{\n    // front (-Z)\n    if (pointIsOnQuad(corners[0], corners[1], corners[3], corners[2], pickPt)) return 2;\n    // back (+Z)\n    if (pointIsOnQuad(corners[4], corners[6], corners[7], corners[5], pickPt)) return 3;\n    // right (+X)\n    if (pointIsOnQuad(corners[1], corners[5], corners[7], corners[3], pickPt)) return 5;\n    // left (-X)\n    if (pointIsOnQuad(corners[0], corners[2], corners[6], corners[4], pickPt)) return 0;\n    // top (+Y)\n    if (pointIsOnQuad(corners[2], corners[3], corners[7], corners[6], pickPt)) return 4;\n    // bottom (-Y)\n    if (pointIsOnQuad(corners[0], corners[4], corners[5], corners[1], pickPt)) return 1;\n    return -1;\n}\n\n// Construct one of 6 cube-handles.  The first 3 (0,1,2) are those in front of the probe\n// the octant (between 0 and 7) is a binary representation of the viewer relative to\n// the probe center.  In binary, this value is ZYX, where Z is 1 if the viewer is above,\n// 0 if the viewer is below, similarly for Y and X.  The handles are numbered from 0 to 5,\n// in the order -X, +X, -Y, +Y, -Z, +Z.\n//\n// We provide the handle in the appropriate sort order, based on the octant\n// in which the viewer is located.  The sort position of a handle is either\n// N or (5-N) where N is the order sorted on x,y,z axes.  It is 5-N if the\n// corresponding bit in the octant is 1.  Octant is between 0 and 7\n// with a bit for each axis (Z,Y,X order).\n// Return value is the absolute handle index, which may differ from the sort order.\n// If you want the faces in absolute order, just specify octant = 0\n//\n// We make the handles in cube coords, since rendering and picking use that system.\n// This requires that we have boxCenter and boxWidth in cube coords.\n// HANDLE_DIAMETER is measured in pixels\n// These can be calculated from the boxRegion\nint TranslateStretchManip::makeHandleFaces(int sortPosition, double handle[8][3], int octant, const double boxRegion[6]) const\n{\n    // Identify the axis this handle is on:\n    int axis = (sortPosition < 3) ? (2 - sortPosition) : (sortPosition - 3);\n    int newPosition = sortPosition;\n\n    // If octant and axis share their sign, we invert the sortPosition to get newPosition...?\n    if ((octant >> axis) & 1) newPosition = 5 - sortPosition;\n\n    // Now create the cube associated with newPosition.  It's just the handle translated\n    // in the direction associated with newPosition\n    float translateSign = (newPosition > 2) ? 1.f : -1.f;\n    for (int vertex = 0; vertex < 8; vertex++) {\n        for (int coord = 0; coord < 3; coord++) {\n            float worldHandleDiameter = _handleSizeInScene;\n\n            // Obtain the coordinate of unit cube corner.  It's either +0.5 or -0.5\n            // multiplied by the handle diameter, then translated along the\n            // specific axis corresponding to\n            double fltCoord = (((double)((vertex >> coord) & 1) - 0.5f) * worldHandleDiameter);    //_handleSizeInScene);\n            // First offset it from the probeCenter:\n            fltCoord += 0.5f * (boxRegion[coord + 3] + boxRegion[coord]);\n\n            deScaleScalarOnAxis(worldHandleDiameter, coord);\n\n            // Displace all the c - coords of this handle if this handle is on the c-axis\n            if (coord == axis) {\n                double boxWidth = (boxRegion[coord + 3] - boxRegion[coord]);\n                // Note we are putting the handle 2 diameters from the box edge\n                fltCoord += translateSign * (boxWidth * 0.5f + 2.f * worldHandleDiameter);    //_handleSizeInScene);\n            }\n            handle[vertex][coord] = fltCoord;\n        }\n    }\n    deScaleExtents(handle);\n    return newPosition;\n}\n\nbool TranslateStretchManip::startHandleSlide(const double mouseCoords[2], int handleNum)\n{\n    // When the mouse is first pressed over a handle,\n    // need to save the\n    // windows coordinates of the click, as well as\n    // calculate a 2D unit vector in the direction of the slide,\n    // projected into the window.\n\n    _mouseDownPoint[0] = mouseCoords[0];\n    _mouseDownPoint[1] = mouseCoords[1];\n\n    // Get the cube coords of the rotation center:\n    double boxCtr[3];\n    double winCoords[2] = {0., 0.};\n    double dispCoords[2];\n\n    if (handleNum > 2)\n        handleNum = handleNum - 3;\n    else\n        handleNum = 2 - handleNum;\n\n    for (int i = 0; i < 3; i++) { boxCtr[i] = (_selection[i] + _selection[i + 3]) * 0.5f; }\n    // project the boxCtr and one more point, to get a direction vector\n\n    if (!_projectPointToWin(boxCtr, winCoords)) return false;\n\n    boxCtr[handleNum] *= 1.1f;\n\n    if (!_projectPointToWin(boxCtr, dispCoords)) return false;\n\n    // Direction vector is difference:\n    _handleProjVec[0] = dispCoords[0] - winCoords[0];\n    _handleProjVec[1] = dispCoords[1] - winCoords[1];\n    float vecNorm = sqrt(_handleProjVec[0] * _handleProjVec[0] + _handleProjVec[1] * _handleProjVec[1]);\n\n    if (vecNorm == 0.f) return false;\n\n    _handleProjVec[0] /= vecNorm;\n    _handleProjVec[1] /= vecNorm;\n    return true;\n}\n\n// Project the current mouse coordinates to a line in screen space.\n// The line starts at the mouseDownPosition, and points in the\n// direction resulting from projecting to the screen the axis\n// associated with the dragHandle.  Returns false on error.\nbool TranslateStretchManip::projectPointToLine(const double mouseCoords[2], double projCoords[2])\n{\n    //  State saved at a mouse press is:\n    //\tmouseDownPoint[2] = P\n    //  _handleProjVec[2] unit vector (U)\n    //\n    // When the mouse is moved, project to the line:\n    // point Q projects to P + aU, where a = (Q-P).U = dotprod\n    double diff[2];\n    if (!_mouseDownHere) return false;\n    diff[0] = mouseCoords[0] - _mouseDownPoint[0];\n    diff[1] = mouseCoords[1] - _mouseDownPoint[1];\n    double dotprod = diff[0] * _handleProjVec[0] + diff[1] * _handleProjVec[1];\n    projCoords[0] = _mouseDownPoint[0] + dotprod * _handleProjVec[0];\n    projCoords[1] = _mouseDownPoint[1] + dotprod * _handleProjVec[1];\n\n    return true;\n}\n\n// Convert a screen coord to a vector, representing the displacedment\n// from the camera associated with the screen coords.  Note screen coords\n// are OpenGL style.  strHandleMid is in stretched coordinates.\n//\nbool TranslateStretchManip::pixelToVector(double winCoords[2], double dirVec[3], const double strHandleMid[3], double mouseWorldPos[3])\n{\n    GLdouble pt[3];\n    // Project handleMid to find its z screen coordinate:\n    GLdouble screenz;\n\n    GLint viewport[4];\n    glGetIntegerv(GL_VIEWPORT, viewport);\n\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\n//    gluProject(strHandleMid[0], strHandleMid[1], strHandleMid[2], _modelViewMatrix, _projectionMatrix, viewport, &screenx, &screeny, &screenz);\n    glm::vec3 obj(strHandleMid[0], strHandleMid[1], strHandleMid[2]);\n    glm::mat4 model, proj;\n    for (int i = 0; i < 16; i++) ((float *)glm::value_ptr(model))[i] = _modelViewMatrix[i];\n    for (int i = 0; i < 16; i++) ((float *)glm::value_ptr(proj ))[i] = _projectionMatrix[i];\n    glm::vec4 vp(viewport[0], viewport[1], viewport[2], viewport[3]);\n    \n    vec3 screen = glm::project(obj, model, proj, vp);\n    screenz = screen.z;\n    // Obtain the coords of a point in view:\n//    bool success = (0 != gluUnProject((GLdouble)winCoords[0], (GLdouble)winCoords[1], screenz, _modelViewMatrix, _projectionMatrix, viewport, pt, pt + 1, pt + 2));\n    glm::vec3 win(winCoords[0], winCoords[1], screenz);\n    auto r = glm::unProject(win, model, proj, vp);\n    pt[0] = r.x;\n    pt[1] = r.y;\n    pt[2] = r.z;\n    _dragDistance = pt[2] - strHandleMid[2];\n    if (mouseWorldPos) memcpy(mouseWorldPos, pt, sizeof(double) * 3);\n#pragma GCC diagnostic pop\n    // Subtract camera coords to get a direction vector:\n    vsub(pt, _cameraPosition, dirVec);\n    GL_ERR_BREAK();\n    return true;\n}\n\n// Find the handle extents using the boxExtents in world coords\n// Set the octant to be 0 if the sortPosition is just the\n// handleNum\n// If this is on the same axis as the selected handle it is displaced by _dragDistance\n//\n\nvoid TranslateStretchManip::makeHandleExtents(int sortPosition, double handleExtents[6], int octant, double boxExtents[6])\n{\n    // Identify the axis this handle is on:\n    int axis = (sortPosition < 3) ? (2 - sortPosition) : (sortPosition - 3);\n    int newPosition = sortPosition;\n    if ((octant >> axis) & 1) newPosition = 5 - sortPosition;\n\n    // Now create the cube associated with newPosition.  It's just the handle translated\n    // up or down in the direction associated with newPosition\n    for (int coord = 0; coord < 3; coord++) {\n        float worldHandleDiameter = _handleSizeInScene;\n        // Start at the box center position\n        handleExtents[coord] = .5f * (-worldHandleDiameter + (boxExtents[coord + 3] + boxExtents[coord]));\n        handleExtents[coord + 3] = .5f * (worldHandleDiameter + (boxExtents[coord + 3] + boxExtents[coord]));\n\n        deScaleScalarOnAxis(worldHandleDiameter, coord);\n\n        if (coord == axis) {    // Translate up or down along this axis\n            // The translation is 2 handles + .5 box thickness\n            double boxWidth = (boxExtents[coord + 3] - boxExtents[coord]);\n            if (newPosition < 3) {    //\"low\" handles are shifted down in the coord:\n                handleExtents[coord] -= (boxWidth * 0.5f + 2.f * worldHandleDiameter);\n                handleExtents[coord + 3] -= (boxWidth * 0.5f + 2.f * worldHandleDiameter);\n            } else {\n                handleExtents[coord] += (boxWidth * 0.5f + 2.f * worldHandleDiameter);\n                handleExtents[coord + 3] += (boxWidth * 0.5f + 2.f * worldHandleDiameter);\n            }\n        }\n    }\n    deScaleExtents(handleExtents);\n    return;\n}\n\nvoid TranslateStretchManip::deScaleScalarOnAxis(float &whd, int axis) const\n{\n    if (_dmTransform == NULL) return;\n    if (_rpTransform == NULL) return;\n\n    vector<double> dmScales = _dmTransform->GetScales();\n    vector<double> rpScales = _rpTransform->GetScales();\n\n    whd /= dmScales[axis];\n    // whd /= rpScales[axis];\n}\n\n// If we are deScaling a cube of the form extents[8][3], then that\n// cube will (apparently) contain its corner coordinates in the following form:\n//\t\tj = 0   1   2   (XYZ)\n//\t  i\n//\t  0\t   min min min\n//\t  1\t   max min min\n//\t  2\t   min max min\n//\t  3\t   max max min\n//\t  4\t   min min max\n//\t  5\t   max min max\n//\t  6\t   min max max\n//\t  7\t   max max max\n//\n//  This lookup table is how the extents are being rescaled in the for\n//  loop below.\n//\nvoid TranslateStretchManip::deScaleExtents(double extents[8][3]) const\n{\n    if (_dmTransform == NULL) return;\n    if (_rpTransform == NULL) return;\n\n    vector<double> dmScales = _dmTransform->GetScales();\n    vector<double> rpScales = _rpTransform->GetScales();\n\n    VAssert(rpScales.size() == 3);\n    VAssert(dmScales.size() == 3);\n\n    double size, midpoint, min, max;\n\n    for (int i = 0; i < 3; i++) {\n        // Vertex 0 contains the XYZ minimum coordinates\n        // Vertex 7 contains the XYZ maximum coordinates\n        size = extents[7][i] - extents[0][i];\n        size /= dmScales[i];\n        size /= rpScales[i];\n        midpoint = (extents[7][i] + extents[0][i]) / 2.f;\n\n        min = midpoint - size / 2.f;\n        max = midpoint + size / 2.f;\n\n        for (int j = 0; j < 8; j++) {\n            if (i == 0) {    // X axis\n                if (j % 2)\n                    extents[j][i] = min;\n                else\n                    extents[j][i] = max;\n            } else if (i == 1) {    // Y axis\n                if (j / 2 % 2)\n                    extents[j][i] = min;\n                else\n                    extents[j][i] = max;\n            } else if (i == 2) {    // Z axis\n                if (j < 4)\n                    extents[j][i] = min;\n                else\n                    extents[j][i] = max;\n            }\n        }\n    }\n}\n\nvoid TranslateStretchManip::deScaleExtents(double *extents) const\n{\n    if (_dmTransform == NULL) return;\n    if (_rpTransform == NULL) return;\n\n    vector<double> dmScales = _dmTransform->GetScales();\n    vector<double> rpScales = _rpTransform->GetScales();\n\n    VAssert(rpScales.size() == 3);\n    VAssert(dmScales.size() == 3);\n\n    double size, midpoint;\n    for (int i = 0; i < 3; i++) {\n        size = extents[i + 3] - extents[i];\n        midpoint = (extents[i + 3] + extents[i]) / 2.f;\n        size /= dmScales[i];\n        size /= rpScales[i];\n        extents[i] = midpoint - size / 2.f;\n        extents[i + 3] = midpoint + size / 2.f;\n    }\n}\n\n// Draw all the faces of a cube with specified extents.\n// Currently just used for handles.\nvoid TranslateStretchManip::drawCubeFaces(double *extents, bool isSelected)\n{\n    LegacyGL *lgl = _glManager->legacy;\n\n    GLfloat lineWidthRange[2] = {0.0f, 0.0f};\n    glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, lineWidthRange);\n    glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\n    // Do left (x=0)\n    if (isSelected)\n        lgl->Color4fv(_faceSelectionColor);\n    else\n        lgl->Color4fv(_unselectedFaceColor);\n    lgl->Begin(LGL_QUADS);\n    lgl->Vertex3f(extents[MINX], extents[MINY], extents[MINZ]);\n    lgl->Vertex3f(extents[MINX], extents[MINY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MINZ]);\n    lgl->End();\n\n    // do right\n    if (isSelected)\n        lgl->Color4fv(_faceSelectionColor);\n    else\n        lgl->Color4fv(_unselectedFaceColor);\n    lgl->Begin(LGL_QUADS);\n    lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MINZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MINZ]);\n    lgl->End();\n\n    // top\n    if (isSelected)\n        lgl->Color4fv(_faceSelectionColor);\n    else\n        lgl->Color4fv(_unselectedFaceColor);\n    lgl->Begin(LGL_QUADS);\n    lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MINZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MINZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MAXZ]);\n    lgl->End();\n\n    // bottom\n    if (isSelected)\n        lgl->Color4fv(_faceSelectionColor);\n    else\n        lgl->Color4fv(_unselectedFaceColor);\n    lgl->Begin(LGL_QUADS);\n    lgl->Vertex3f(extents[MINX], extents[MINY], extents[MINZ]);\n    lgl->Vertex3f(extents[MINX], extents[MINY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MINZ]);\n    lgl->End();\n\n    // back\n    if (isSelected)\n        lgl->Color4fv(_faceSelectionColor);\n    else\n        lgl->Color4fv(_unselectedFaceColor);\n    lgl->Begin(LGL_QUADS);\n    lgl->Vertex3f(extents[MINX], extents[MINY], extents[MINZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MINZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MINZ]);\n    lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MINZ]);\n    lgl->End();\n\n    // do the front:\n    //\n    if (isSelected)\n        lgl->Color4fv(_faceSelectionColor);\n    else\n        lgl->Color4fv(_unselectedFaceColor);\n    lgl->Begin(LGL_QUADS);\n    lgl->Vertex3f(extents[MINX], extents[MINY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MINY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MAXX], extents[MAXY], extents[MAXZ]);\n    lgl->Vertex3f(extents[MINX], extents[MAXY], extents[MAXZ]);\n    lgl->End();\n\n    lgl->Color4f(1, 1, 1, 1);\n    glDisable(GL_BLEND);\n}\n\n// Renders handles and box\n// If it is stretching, it only moves the one handle that is doing the stretching\nvoid TranslateStretchManip::Render()\n{\n    transformMatrix(_dmTransform);\n    if (_rpTransform != NULL) transformMatrix(_rpTransform, _dmTransform->GetScales());\n\n    _handleSizeInScene = getPixelSize() * (float)HANDLE_DIAMETER;\n\n    double handleExtents[6];\n    for (int handleNum = 0; handleNum < 6; handleNum++) {\n        makeHandleExtents(handleNum, handleExtents, 0 /*octant*/, _selection);\n\n        if (_selectedHandle >= 0) {\n            int axis = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3);\n            // displace handleExtents appropriately\n            if (_isStretching) {\n                // modify the extents for the one grabbed handle\n                if (_selectedHandle == handleNum) {\n                    handleExtents[axis] += _dragDistance;\n                    handleExtents[axis + 3] += _dragDistance;\n                }    // and make the handles on the non-grabbed axes move half as far:\n                else if (handleNum != (5 - _selectedHandle)) {\n                    handleExtents[axis] += 0.5f * _dragDistance;\n                    handleExtents[axis + 3] += 0.5f * _dragDistance;\n                }\n            } else {\n                handleExtents[axis] += _dragDistance;\n                handleExtents[axis + 3] += _dragDistance;\n            }\n        }\n        drawCubeFaces(handleExtents, (handleNum == _selectedHandle));\n        drawHandleConnector(handleNum, handleExtents, _selection);\n    }\n    // Then render the full box, unhighlighted and displaced\n    drawBoxFaces();\n\n    MatrixManager *mm = _glManager->matrixManager;\n\n    mm->PopMatrix();             // Pop the matrix applied for the DataMgr's transform\n    if (_rpTransform != NULL)    // Pop the matrix applied for the RenderParams' transform\n        mm->PopMatrix();\n}\n\ndouble TranslateStretchManip::getPixelSize() const\n{\n    double temp[3];\n\n    // Window height is subtended by viewing angle (45 degrees),\n    // at viewer distance (dist from camera to view center)\n\n    size_t height = _windowSize[1];\n\n    double              origin[3];\n    std::vector<double> vorigin(3, 0.f);\n    if (_dmTransform != NULL) vorigin = _dmTransform->GetOrigin();\n\n    for (int i = 0; i < 3; i++) { origin[i] = vorigin[i]; }\n\n    vsub(origin, _cameraPosition, temp);\n\n    float distToScene = vlength(temp);\n    // tan(45 deg *0.5) is ratio between half-height and dist to scene\n    double halfHeight = tan(M_PI * 0.125) * distToScene;\n    return (2.f * halfHeight / (double)height);\n}\n\n// Draw the main box, just rendering the lines.\n// the highlightedFace is not the same as the selectedFace!!\n//\n\nvoid TranslateStretchManip::drawBoxFaces() const\n{\n    double corners[8][3];\n\n    // -X -Y -Z\n    corners[0][X] = _selection[MINX];\n    corners[0][Y] = _selection[MINY];\n    corners[0][Z] = _selection[MINZ];\n\n    // -X -Y +Z\n    corners[1][X] = _selection[MINX];\n    corners[1][Y] = _selection[MINY];\n    corners[1][Z] = _selection[MAXZ];\n\n    // -X +Y -Z\n    corners[2][X] = _selection[MINX];\n    corners[2][Y] = _selection[MAXY];\n    corners[2][Z] = _selection[MINZ];\n\n    // -X +Y +Z\n    corners[3][X] = _selection[MINX];\n    corners[3][Y] = _selection[MAXY];\n    corners[3][Z] = _selection[MAXZ];\n\n    // +X -Y -Z\n    corners[4][X] = _selection[MAXX];\n    corners[4][Y] = _selection[MINY];\n    corners[4][Z] = _selection[MINZ];\n\n    // +X -Y +Z\n    corners[5][X] = _selection[MAXX];\n    corners[5][Y] = _selection[MINY];\n    corners[5][Z] = _selection[MAXZ];\n\n    // +X +Y -Z\n    corners[6][X] = _selection[MAXX];\n    corners[6][Y] = _selection[MAXY];\n    corners[6][Z] = _selection[MINZ];\n\n    // +X +Y +Z\n    corners[7][X] = _selection[MAXX];\n    corners[7][Y] = _selection[MAXY];\n    corners[7][Z] = _selection[MAXZ];\n\n    if (_selectedHandle >= 0) {\n        if (_isStretching)\n            _stretchCorners(corners);\n        else if (_dragDistance != 0.)\n            _translateCorners(corners);\n    }\n\n    // Now render the edges:\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glEnable(GL_BLEND);\n    // glLineWidth( 2.0 );\n\n    LegacyGL *lgl = _glManager->legacy;\n\n    lgl->Color3f(1.f, 0.f, 0.f);\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3dv(corners[0]);\n    lgl->Vertex3dv(corners[1]);\n    lgl->Vertex3dv(corners[0]);\n    lgl->Vertex3dv(corners[2]);\n    lgl->Vertex3dv(corners[0]);\n    lgl->Vertex3dv(corners[4]);\n\n    lgl->Vertex3dv(corners[1]);\n    lgl->Vertex3dv(corners[3]);\n    lgl->Vertex3dv(corners[1]);\n    lgl->Vertex3dv(corners[5]);\n\n    lgl->Vertex3dv(corners[2]);\n    lgl->Vertex3dv(corners[3]);\n    lgl->Vertex3dv(corners[2]);\n    lgl->Vertex3dv(corners[6]);\n\n    lgl->Vertex3dv(corners[3]);\n    lgl->Vertex3dv(corners[7]);\n\n    lgl->Vertex3dv(corners[4]);\n    lgl->Vertex3dv(corners[5]);\n    lgl->Vertex3dv(corners[4]);\n    lgl->Vertex3dv(corners[6]);\n\n    lgl->Vertex3dv(corners[5]);\n    lgl->Vertex3dv(corners[7]);\n\n    lgl->Vertex3dv(corners[6]);\n    lgl->Vertex3dv(corners[7]);\n    lgl->End();\n\n    glDisable(GL_BLEND);\n    glDepthMask(GL_TRUE);\n}\n\nvoid TranslateStretchManip::_stretchCorners(double corners[8][3]) const\n{\n    int axis = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3);\n\n    // X axis\n    if (axis == 0) {\n        if (_selectedHandle == 2)\n            _moveMinusXCorners(corners);\n        else if (_selectedHandle == 3)\n            _movePlusXCorners(corners);\n    }\n    // Y axis\n    else if (axis == 1) {\n        if (_selectedHandle == 4)\n            _moveMinusYCorners(corners);\n        else if (_selectedHandle == 1)\n            _movePlusYCorners(corners);\n    }\n    // Z axis\n    else if (axis == 2) {\n        if (_selectedHandle == 0)\n            _moveMinusZCorners(corners);\n        else if (_selectedHandle == 5)\n            _movePlusZCorners(corners);\n    }\n}\n\nvoid TranslateStretchManip::_translateCorners(double corners[8][3]) const\n{\n    int axis = (_selectedHandle < 3) ? (2 - _selectedHandle) : (_selectedHandle - 3);\n\n    if (axis == 0) {\n        _moveMinusXCorners(corners);\n        _movePlusXCorners(corners);\n    } else if (axis == 1) {\n        _moveMinusYCorners(corners);\n        _movePlusYCorners(corners);\n    } else if (axis == 2) {\n        _moveMinusZCorners(corners);\n        _movePlusZCorners(corners);\n    }\n}\n\nvoid TranslateStretchManip::_moveMinusXCorners(double corners[8][3]) const\n{\n    corners[2][X] += _dragDistance;\n    corners[0][X] += _dragDistance;\n    corners[1][X] += _dragDistance;\n    corners[3][X] += _dragDistance;\n}\n\nvoid TranslateStretchManip::_movePlusXCorners(double corners[8][3]) const\n{\n    corners[4][X] += _dragDistance;\n    corners[5][X] += _dragDistance;\n    corners[6][X] += _dragDistance;\n    corners[7][X] += _dragDistance;\n}\n\nvoid TranslateStretchManip::_moveMinusYCorners(double corners[8][3]) const\n{\n    corners[2][Y] += _dragDistance;\n    corners[3][Y] += _dragDistance;\n    corners[6][Y] += _dragDistance;\n    corners[7][Y] += _dragDistance;\n}\n\nvoid TranslateStretchManip::_movePlusYCorners(double corners[8][3]) const\n{\n    corners[0][Y] += _dragDistance;\n    corners[1][Y] += _dragDistance;\n    corners[4][Y] += _dragDistance;\n    corners[5][Y] += _dragDistance;\n}\n\nvoid TranslateStretchManip::_moveMinusZCorners(double corners[8][3]) const\n{\n    corners[0][Z] += _dragDistance;\n    corners[2][Z] += _dragDistance;\n    corners[4][Z] += _dragDistance;\n    corners[6][Z] += _dragDistance;\n}\n\nvoid TranslateStretchManip::_movePlusZCorners(double corners[8][3]) const\n{\n    corners[1][Z] += _dragDistance;\n    corners[3][Z] += _dragDistance;\n    corners[5][Z] += _dragDistance;\n    corners[7][Z] += _dragDistance;\n}\n\n// Note: This is performed in local (unstretched) world coordinates!\nvoid TranslateStretchManip::_captureMouseDown(int handleNum, int buttonNum, const double strHandleMid[3])\n{\n    _buttonNum = buttonNum;\n\n    // Grab a probe handle\n    _selectedHandle = handleNum;\n    _dragDistance = 0.f;\n\n    // Calculate intersection of ray with specified plane in unstretched coords\n    // The selection ray is the vector from the camera to the intersection point\n    for (int i = 0; i < 3; i++) _initialSelectionRay[i] = strHandleMid[i] - _cameraPosition[i];\n\n    if (buttonNum > 1)\n        _isStretching = true;\n    else\n        _isStretching = false;\n    // Reset any active rotation\n    _tempRotation = 0.f;\n    _tempRotAxis = -1;\n}\n\n// Draw a line connecting the specified handle to the box center.\n// Highlight both ends of the line to the selected handle\n// Note that handleExtents have already been displaced.\n// if _isStretching is true,\n// the box center only moves half as far.\nvoid TranslateStretchManip::drawHandleConnector(int handleNum, double *handleExtents, double *boxExtents)\n{\n    LegacyGL *lgl = _glManager->legacy;\n    // Determine the side of the handle and the side of the box that is connected:\n    int    axis = (handleNum < 3) ? (2 - handleNum) : (handleNum - 3);\n    bool   posSide = (handleNum > 2);\n    double handleDisp[3], boxDisp[3];\n    // Every handle gets a line from its inside face to the center of the box.\n    for (int i = 0; i < 3; i++) {\n        // determine the box displacement, based on dimension:\n        if ((i == (2 - _selectedHandle)) || (i == (_selectedHandle - 3))) {\n            if (_isStretching)\n                boxDisp[i] = 0.5f * _dragDistance;\n            else\n                boxDisp[i] = _dragDistance;\n        } else\n            boxDisp[i] = 0.f;\n        // The line to the handle is displaced according to what axis the\n        // handle is on (independent of the _dragDistance)\n        //\n        if (i == axis) {\n            if (posSide) {    // displace to lower (in-) side of handle\n                handleDisp[i] = -0.5f * (handleExtents[i + 3] - handleExtents[i]);\n            } else {    // displace to upper (out-) side of handle\n                handleDisp[i] = 0.5f * (handleExtents[i + 3] - handleExtents[i]);\n            }\n        } else {    // don't displace other coordinates\n            handleDisp[i] = 0.f;\n        }\n    }\n    // glLineWidth( 2.0 );\n    glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n    if ((handleNum == _selectedHandle) || (handleNum == (5 - _selectedHandle)))\n        lgl->Color4fv(_faceSelectionColor);\n    else\n        lgl->Color4fv(_unselectedFaceColor);\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3f(0.5f * (handleExtents[MAXX] + handleExtents[MINX]) + handleDisp[X], 0.5f * (handleExtents[MAXY] + handleExtents[MINY]) + handleDisp[Y],\n                  0.5f * (handleExtents[MAXZ] + handleExtents[MINZ]) + handleDisp[Z]);\n    lgl->Vertex3f(0.5f * (boxExtents[MAXX] + boxExtents[MINX]) + boxDisp[X], 0.5f * (boxExtents[MAXY] + boxExtents[MINY]) + boxDisp[Y], 0.5f * (boxExtents[MAXZ] + boxExtents[MINZ]) + boxDisp[Z]);\n    lgl->End();\n    glDisable(GL_BLEND);\n}\n\n// This is a utility to draw the hitbox over the handle.  It can be\n// called from TranslateStretchManip::pointIsOnQuad(), but with a caveat.\n// Hitboxes are calculated during mouse events, at which time we are not\n// in a good state to perform rendering.\n//\n// VizWin has an openGL setup and cleanup sequence which must be applied\n// during VizWin::_mousePressEvent().  When done as shown below, the hitboxes\n// will be colored green during mouse press events.  Hold the mouse to\n// illuminate the boxes.\n//\n// VizWin setup sequence:\n//\n// void VizWin:;_mousePressEvent(QMouseEvent* e) {\n// \t\t...\n// \t\t...\n// \t\tglMatrixMode(GL_PROJECTION);\t// Begin setup sequence\n//\t\tglPushMatrix();\n//\t\t_setUpProjMatrix();\n//\t\tglMatrixMode(GL_MODELVIEW);\n//\t\tglPushMatrix();\n//\t\t_setUpModelViewMatrix();\t\t\t// End setup sequence\n//\n//\t    std::vector<double> screenCoords = getScreenCoords(e);\n//\t\tbool mouseOnManip = _manip->MouseEvent(\n//\t\t\t_buttonNum, screenCoords, _strHandleMid\n//\t\t);\n//\n//\t\tswapBuffers();\t\t\t\t\t// Begin cleanup sequence\n//\t\tglMatrixMode(GL_PROJECTION);\n//\t\tglPopMatrix();\n//\t\tglMatrixMode(GL_MODELVIEW);\n//\t\tglPopMatrix();\t\t\t\t\t// End cleanup sequence\n//\t\t...\n//\t\t...\n//\n\n#ifdef DEBUG\nvoid TranslateStretchManip::drawHitBox(double winCoord1[2], double winCoord2[2], double winCoord4[2], double winCoord3[2]) const\n{\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    glLoadIdentity();\n    glMatrixMode(GL_MODELVIEW);\n    glPushMatrix();\n    glLoadIdentity();\n    glPushAttrib(GL_ALL_ATTRIB_BITS);\n\n    GLint dims[4] = {0};\n    glGetIntegerv(GL_VIEWPORT, dims);\n    GLint width = dims[2];\n    GLint height = dims[3];\n\n    gluOrtho2D(0, width, 0, height);\n\n    glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\n    glBegin(GL_QUADS);    // Each set of 4 vertices form a quad\n    glColor3f(0.0f, 1.0f, 0.0f);\n    glVertex2f(winCoord1[0], winCoord1[1]);\n    glVertex2f(winCoord2[0], winCoord2[1]);\n    glVertex2f(winCoord3[0], winCoord3[1]);\n    glVertex2f(winCoord4[0], winCoord4[1]);\n\n    glEnd();\n    glFlush();\n    glPopAttrib();\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n    glMatrixMode(GL_MODELVIEW);\n    glPopMatrix();\n    glDisable(GL_BLEND);\n}\n#endif\n\n//_projectPointToWin returns true if point is in front of camera\n// resulting screen coords returned in 2nd argument.  Note that\n// OpenGL coords are 0 at bottom of window!\n//\nbool TranslateStretchManip::_projectPointToWin(const double cubeCoords[3], double winCoords[2]) const\n{\n    double   depth;\n    GLdouble wCoords[2];\n    GLdouble cbCoords[3];\n    for (int i = 0; i < 3; i++) cbCoords[i] = (double)cubeCoords[i];\n\n    GLint viewport[4];\n    glGetIntegerv(GL_VIEWPORT, viewport);\n\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\n//    bool success = (0 != gluProject(cbCoords[0], cbCoords[1], cbCoords[2], _modelViewMatrix, _projectionMatrix, viewport, wCoords, (wCoords + 1), (GLdouble *)(&depth)));\n    glm::vec3 obj(cbCoords[0], cbCoords[1], cbCoords[2]);\n    glm::mat4 model, proj;\n    for (int i = 0; i < 16; i++) ((float *)glm::value_ptr(model))[i] = _modelViewMatrix[i];\n    for (int i = 0; i < 16; i++) ((float *)glm::value_ptr(proj ))[i] = _projectionMatrix[i];\n    glm::vec4 vp(viewport[0], viewport[1], viewport[2], viewport[3]);\n    auto r = glm::project(obj, model, proj, vp);\n    wCoords[0] = r.x;\n    wCoords[1] = r.y;\n    depth = r.z;\n#pragma GCC diagnostic pop\n\n//    if (!success) return false;\n    winCoords[0] = wCoords[0];\n    winCoords[1] = wCoords[1];\n    return (depth > 0.0);\n}\n"
  },
  {
    "path": "apps/vaporgui/Manip.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2004\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tManip.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\t\tScott Pearse\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\tVapor3 implementation - May 2018\n//\t\t\tVapor2 implementation - November 2005\n//\n//\tDescription:\tDefines the pure virtual Manip class\n//\t\tSubclasses of this class provide in-scene manipulators\n//\t\tfor positioning and setting properties of objects\n//\t\tin the scene.\n\n#ifndef MANIP_H\n#define MANIP_H\n\n#include <vapor/glutil.h>\n#include \"vapor/Transform.h\"\n\n// Handle diameter in pixels:\n#define HANDLE_DIAMETER 15\n//#define HANDLE_DIAMETER 3\nnamespace VAPoR {\n\nstruct GLManager;\n\n// class Visualizer;\n// class DataStatus;\n//! \\class Manip\n//! \\ingroup Public_Render\n//! \\brief A class that supports manipulators in in a VAPOR Visualizer\n//! \\author Alan Norton, Scott Pearse\n//! \\version 3.0\n//! \\date\tJuly 2015, June 2018\n//!\n//! Manip class is a pure virtual class that supports\n//! manipulators in the VAPOR Visualizer scene\n//!\nclass Manip {\npublic:\n    Manip(GLManager *glManager) : _glManager(glManager){};\n    virtual ~Manip() {}\n\n    //! Pure virtual function renders the geometry of the Manip.\n    virtual void Render() = 0;\n\n    //! Update the box manipulator's extents\n    //! \\param[in] llc : The lower-left corner to update the manipulator with\n    //! \\param[in] urc : The upper-right corner to update the manipulator with\n    //! \\param[in] minExtents : The minimum extents that the manipulator can draw to\n    //! \\param[in] maxExtents : The maximum extents that the manipulator can draw to\n    /*! \\param[in] rpTransform: The current scene transform used by the current\n     *  RenderParams\n     */\n    /*! \\param[in] dmTransform: The current scene transform used by the current\n     *  DataMgr\n     */\n    /*! \\param[in] constrain: Indicates whether the manipulator box is bound by\n     *  domain extents\n     */\n    virtual void Update(std::vector<double> llc, std::vector<double> urc, std::vector<double> minExtents, std::vector<double> maxExtents, VAPoR::Transform *rpTransform, VAPoR::Transform *dmTransform,\n                        bool constrain) = 0;\n\n    //! Notify that manipulator that is being moved with the mouse\n    //! \\param[in] buttonNum - The mouse button being used to move the manipulator\n    //! \\param[in] screenCoords - The current coordinates of the mouse cursor\n    virtual bool MouseEvent(int buttonNum, std::vector<double> screenCoords, double handleMidpoint[3], bool release = false) = 0;\n\n    //! Method to retrieve the manipulator's current extents\n    //! \\param[out] llc - The lower-left coordinates of the manipulator\n    //! \\param[out] urc - The upper-right coordinates of the manipulator\n    virtual void GetBox(std::vector<double> &llc, std::vector<double> &urc) const = 0;\n\nprotected:\n    //! Pure virtual method: Determine which handle (if any) is under mouse\n    //! \\param[in] mouse coordinates in screen\n    /*! \\param[out] handleMid is the coordinates of the center of the selected\n     * handle (if selected).\n     */\n    //! \\return handle index, or -1 if no intersection\n    virtual int _mouseIsOverHandle(const double screenCoords[2], double handleMid[3]) const = 0;\n\n    //! General utility function for drawing axis-aligned cubes.\n    //! \\param[in] extents : extents of box to be drawn\n    /*! \\param[in] isSelected indicates if this box is to be drawn with the\n     * selection color or not\n     */\n    void _drawCubeFaces(double *extents, bool isSelected);\n\n    //! Handles logic for a mouse-press event on one of the manip handles\n    //! \\param[in] screenCoords is a pixel location on the visualizer window\n    /*! \\param[in] handleMidpoint is the center of a handle to test that gets\n     *\ttested against the screenCoords array.\n     */\n    /*! param[in] buttonNum is the button of the mouse that is clicked, which\n     *  determines whether we are moving or stretching the manipulator.\n     */\n    virtual void _mousePress(double screenCoords[2], double handleMidpoint[3], int buttonNum) = 0;\n\n    //! Handles logic for moving a handle while a mouse button is held down.\n    //! param[in] screenCoords is the current position of the mouse cursor\n    //! param[in] handleMidpoint is the center of the handle being moved\n    virtual void _mouseDrag(double screenCoords[2], double handleMidpoint[3]) = 0;\n\n    /*! Handles logic to set the current extents of the manipulator, held in\n     *  the _selection array\n     */\n    //! param[in] screenCoords - coordinates of the cursor upon mose release\n    virtual void _mouseRelease(double screenCoords[2]) = 0;\n\n    //! Adjust the corners of the manipulator extents according to _dragDistance\n    //! param[in] corners describes the bounding box of the manipulator\n    virtual void _stretchCorners(double corners[8][3]) const = 0;\n\n    GLManager *        _glManager;\n    int                _buttonNum;\n    int                _selectedHandle;\n    double             _dragDistance;\n    double             _handleMid[3];\n    double             _selection[6];\n    double             _extents[6];\n    double             _cameraPosition[3];\n    static const float _faceSelectionColor[4];\n    static const float _unselectedFaceColor[4];\n};\n\n//! \\class TranslateStretchManip\n//! \\ingroup Public_Render\n//! \\brief A Manip subclass for manipulators that stretch and translate\n//! \\author Alan Norton, Scott Pearse\n//! \\version 3.0\n//! \\date\tJuly 2015, June 2018\n\n//! This subclass handles translation and stretching manip.  Works\n//! with ArrowParams (rake).\n//! When you slide a handle with the right mouse it stretches the region\nclass TranslateStretchManip : public Manip {\npublic:\n    TranslateStretchManip(GLManager *glManager);\n    virtual ~TranslateStretchManip() {}\n    virtual void Render();\n\n    //! @copydoc Manip::Update(std::vector<double>, std::vector<double> std::vector<double>, std::vector<double>)\n    virtual void Update(std::vector<double> llc, std::vector<double> urc, std::vector<double> minExtents, std::vector<double> maxExtents, VAPoR::Transform *rpTransform, VAPoR::Transform *dmTransform,\n                        bool constrain);\n\n    //! @copydoc Manip::MoveEvent(int, std::vector<double>)\n    virtual bool MouseEvent(int buttonNum, std::vector<double> screenCoords, double handleMidpoint[3], bool release = false);\n\n    //! @copydoc Manip::GetBox(std::vector<double>, std::vector<double>);\n    virtual void GetBox(std::vector<double> &llc, std::vector<double> &urc) const;\n\nprivate:\n    //! Determine if the mouse is over one of the manip handles.\n    //! \\param[in] screenCoords x,y screen position of mouse\n    //! \\param[out] handleMid coordinates of handle selected\n    //! \\return index of handle, or -1 if none.\n    int _mouseIsOverHandle(const double screenCoords[2], double handleMid[3]) const;\n\n    //! Method to be invoked when the mouse if first pressed over a handle.\n    //! \\param[in] handleNum is handle index 0..5\n    //! \\param[in] buttonNum indicates which mouse button was pressed.\n    /*! \\param[out] strHandleMid specified 3D coordinates of handle middle in\n     * stretched coordinates.\n     */\n    void _captureMouseDown(int handleNum, int buttonNum, const double strHandleMid[3]);\n\n    //! Method invoked when manip handle drag begins, invoked from VizWin.\n    //! \\param[in] mouseCoords coordinates where mouse is pressed.\n    //! \\param[in] handleNum index over which the mouse is pressed\n    //! \\return true if successful\n    bool startHandleSlide(const double mouseCoords[2], int handleNum);\n\n    /*! Set the status of the mouse, invoked when the mouse is pressed or\n     * released.\n     */\n    //! \\param downUp true is the mouse is pressed for this manipulator.\n    void setMouseDown(bool downUp) { _mouseDownHere = downUp; }\n\n    //! Project the current mouse coordinates to a line in screen space.\n    //! The line starts at the mouseDownPosition, and points in the\n    //! direction resulting from projecting to the screen the axis\n    //! associated with the dragHandle.  Returns false on error.\n    //! Invoked during mouseMoveEvent, uses values of mouseDownPoint(),\n    //! handleProjVec(), mouseDownHere()\n    //! \\param[in] mouseCoords coordinates of mouse\n    //! \\param[out] projCoords coordinates of projected point.\n    bool projectPointToLine(const double mouseCoords[2], double projCoords[2]);\n\n    //! Determine a vector associated with a pixel, pointing from the\n    //! camera, through the pixel into the scene to a manip handle.  Uses OpenGL\n    //! screencoords.\n    //! I.e. y = 0 at bottom.  Returns false on failure.  Used during mouse Events.\n    //! \\param[in] winCoords  pixel coordinates (converted to double)\n    //! \\param[out] dirVec resulting vector, from camera to handle\n    //! \\param[in] strHandleMid is middle of handle in stretched coordinates.\n    //! \\return true if successful\n    bool pixelToVector(double winCoords[2], double dirVec[3], const double strHandleMid[3], double mouseWorldPos[3] = NULL);\n\n    //! Method to render the faces of the manipulator handlebars\n    virtual void drawBoxFaces() const;\n\n    //! Method to indicate whether a screencoordinate that is projected\n    //! into the scene intersects the coordinates of a cube face\n    //! \\param[in] cor1 first corner\n    //! \\param[in] cor2 second corner\n    //! \\param[in] cor3 third corner\n    //! \\param[in] cor4 fourth corner\n    //! \\param[in] pickPt the screen coordinate being projected into the scene\n    //! \\return true if the projected point intesects the quad\n    virtual bool pointIsOnQuad(double cor1[3], double cor2[3], double cor3[3], double cor4[3], const double pickPt[2]) const;\n\n    //! Method to indicate whether a screencoordinate that is projected\n    //! into the scene intersects the coordinates of a 3D cube\n    //! \\param[in] corners The corners constraining the extents of a handlebar\n    //! \\param[in] pickPt the screen coordinate being projected into the scene\n    virtual int pointIsOnBox(double corners[8][3], const double pkPt[2]) const;\n\n    double getPixelSize() const;\n\n    //! Method to scale, translate, or rotate the coordinates of the manipulator\n    //! param[in] - the current dataset or renderer transform to operate upon\n    void transformMatrix(VAPoR::Transform *transform, std::vector<double> parentScales = {1, 1, 1});\n\n    //! Method to remove the scaling of the manipulator extents\n    //! param[in] extents are the current region of the manipulator\n    void deScaleExtents(double *extents) const;\n\n    //! Method to remove the scaling of the manipulator extents\n    //! param[in] extents are the current region of the manipulator\n    void deScaleExtents(double extents[8][3]) const;\n\n    //! Method to apply the inverse-scaling factor to the worldHandleDiameter\n    //! used in makeHandleExtents()\n    //! param[in] worldHandleDiameter - the size of the manipulator handle\n    //! param[in] axis - The axis to descale the manipulator handle size upon\n    void deScaleScalarOnAxis(float &scalar, int axis) const;\n\n    //! Debug tool to draw the hitbox of a manipulator handle.  This should\n    //! align with the window-coordinates of the actual handle.\n    //! param[in] winCoord1 - first corner of a 2D quad on the screen\n    //! param[in] winCoord2 - secdond corner of a 2D quad on the screen\n    //! param[in] winCoord3 - third corner of a 2D quad on the screen\n    //! param[in] winCoord4 - fourth corner of a 2D quad on the screen\n    void drawHitBox(double winCoord1[2], double winCoord2[2], double winCoord3[2], double winCoord4[2]) const;\n\n    //! Method that draws a line connecting a handle to the box center\n    //! \\param[in] handleNum index of handle\n    //! \\param[in] handleExtents are extents of handle being drawn\n    //! \\param[in] extents are the full box extents\n    void drawHandleConnector(int handleNum, double *handleExtents, double *extents);\n\n    //! Utility to construct the extents of a handle\n    //! \\param[in] handleNum handle index\n    //! \\param[out] handleExtents the extents of the specified handle\n    //! \\param[in] octant The octant (0-7) associated with the handle\n    //! \\param[in] extents The extents of the full box.\n    void makeHandleExtents(int handleNum, double *handleExtents, int octant, double *extents);\n\n    //! Method to draw the faces of a cube (used as a handle)\n    //! \\param[in] handleExtents are the extents of the handle\n    /*! \\param[in] isSelected indicates if the handle should be drawn using\n     * selected color.\n     */\n    void drawCubeFaces(double *handleExtents, bool isSelected);\n\n    //! Construct the vertices of a handle, to be used to draw its faces.\n    //! \\param[in] handleNum is the index of the handle\n    //! \\param[out] handle are the 8 3D coordinates of the handle's vertices\n    //! \\param[in] octant is the handle octant (between 0 and 5)\n    //! \\param[in] boxExtents are the extents of the full box.\n    //! \\return absolute handle index\n    int makeHandleFaces(int handleNum, double handle[8][3], int octant, const double *boxExtents) const;\n\n    //! Project a 3D point (in user coord system) to window coords.\n    /*! Return true if in front of camera.  Used by pointIsOnQuad, as well as\n     * in building Axis labels.\n     */\n    //! \\param[in] userCoords[3] coordinates of point\n    //! \\param[out] winCoords[2] window coordinates of projection\n    //! \\return true if point is in front of camera.\n    bool _projectPointToWin(const double cubeCoords[3], double winCoords[2]) const;\n\n    void _mousePress(double screenCoords[2], double handleMidpoint[3], int buttonNum);\n    void _mouseDrag(double screenCoords[2], double handleMidpoint[3]);\n    void _mouseRelease(double screenCoords[2]);\n    void _stretchCorners(double corners[8][3]) const;\n    void _translateCorners(double corners[8][3]) const;\n    void _moveMinusXCorners(double corners[8][3]) const;\n    void _moveMinusYCorners(double corners[8][3]) const;\n    void _moveMinusZCorners(double corners[8][3]) const;\n    void _movePlusXCorners(double corners[8][3]) const;\n    void _movePlusYCorners(double corners[8][3]) const;\n    void _movePlusZCorners(double corners[8][3]) const;\n    void _constrainExtents();\n\n    bool              _isStretching;\n    bool              _constrain;\n    double            _handleSizeInScene;\n    double            _cameraPosition[3];\n    double            _modelViewMatrix[16];\n    double            _projectionMatrix[16];\n    int               _windowSize[2];\n    VAPoR::Transform *_rpTransform;\n    VAPoR::Transform *_dmTransform;\n\n    // screen coords where mouse is pressed:\n    float _mouseDownPoint[2];\n\n    // unit vector in direction of handle\n    float _handleProjVec[2];\n\n    bool _mouseDownHere;\n\n    // Vector from camera to handle, when mouse is initially clicked.\n    double _initialSelectionRay[3];\n\n    // Following only used by rotating manip subclasses:\n    double _tempRotation;\n    int    _tempRotAxis;\n};\n};    // namespace VAPoR\n\n#endif    // MANIP_H\n"
  },
  {
    "path": "apps/vaporgui/ModelEventRouter.cpp",
    "content": "#include \"ModelEventRouter.h\"\n#include \"vapor/ModelParams.h\"\n#include \"PWidgets.h\"\n\nusing namespace VAPoR;\n\nstatic RenderEventRouterRegistrar<ModelEventRouter> registrar(ModelEventRouter::GetClassType());\n\nModelEventRouter::ModelEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, ModelParams::GetClassType())\n{\n    // clang-format off\n\n    AddSubtab(\"Model\", new PGroup({\n        new PSection(\"Model File\", {\n            (new PFileOpenSelector(ModelParams::FileTag, \"Model/Scene File\"))\n                ->SetFileTypeFilter(\"3D Models/Scenes (*.vms *.3d *.3ds *.3mf *.ac *.ac3d *.acc *.amj *.ase *.ask *.b3d *.blend *.bvh *.cms *.cob *.dae *.dxf *.enff *.fbx *.hmb *.ifc *.irr *.lwo *.lws *.lxo *.md2 *.md3 *.md5 *.mdc *.mdl *.mesh *.mot *.ms3d *.ndo *.nff *.obj *.off *.ogex *.ply *.pmx *.prj *.q3o *.q3s *.raw *.scn *.sib *.smd *.stp *.stl *.ter *.uc *.vta *.x *.x3d *.xml *.xgl *.zgl)\")\n        }),\n        new PRendererTransformSection,\n    }));\n\n    // clang-format on\n}\n\nstring ModelEventRouter::_getDescription() const\n{\n    return (\"Allows the import of 3D model files as well as more complex scenes that \"\n            \"can be modified per timestep by using .vms files\");\n}\n"
  },
  {
    "path": "apps/vaporgui/ModelEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include \"vapor/ModelRenderer.h\"\n\n//! \\class ModelEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Model renderer GUI\n//! \\author Stas Jaroszynski\n\nclass ModelEventRouter : public RenderEventRouterGUI {\npublic:\n    ModelEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::ModelRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return true; }\n    bool          Supports3DVariables() const { return true; }\n    bool          SupportsParticleVariables() const { return true; }\n\nprotected:\n    string _getDescription() const;\n    string _getSmallIconImagePath() const { return \"Model_small.png\"; }\n    string _getIconImagePath() const { return \"Model.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/NcarCasperUtils.cpp",
    "content": "#include \"NcarCasperUtils.h\"\n#include <QMessageBox>\n#include <QCheckBox>\n#include <QApplication>\n#include <vapor/STLUtils.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/SettingsParams.h>\n#include \"ErrorReporter.h\"\n#ifndef _WIN32\n    #include <unistd.h>\n#endif\n\nvoid NcarCasperUtils::CheckForCasperVGL(VAPoR::ControlExec *ce)\n{\n#ifndef Darwin\n#ifndef WIN32\n    auto sp = ce->GetParams<SettingsParams>();\n    char hostname[1024];\n    hostname[1023] = '\\0';\n    gethostname(hostname, 1023);\n    if (!STLUtils::BeginsWith(hostname, \"casper\")) return;\n    if (getenv(\"VGL_ISACTIVE\")) return;\n\n    const char *message = \"In order to utilize Casper's GPU fully, Vapor needs to be launched using vglrun. The button below will relaunch Vapor with vglrun.\";\n    printf(\"WARNING: %s\\n\", message);\n    if (!sp->GetCasperCheckForVGL()) return;\n\n    printf(\"\\t Displaying warning popup in GUI\\n\");\n    QMessageBox *popup = new QMessageBox(\n        QMessageBox::Icon::Warning,\n        \"Warning\",\n        message\n    );\n    QCheckBox *cb = new QCheckBox(\"Don't show again\");\n    cb->setChecked(false);\n    popup->addButton(\"Dismiss\", QMessageBox::RejectRole);\n    popup->addButton(\"Relaunch\", QMessageBox::AcceptRole);\n    popup->setCheckBox(cb);\n\n    auto finish = [sp, cb](int result) {\n        if (cb->isChecked()) {\n            sp->SetCasperCheckForVGL(false);\n            sp->SaveSettings();\n        }\n\n        if (result == QMessageBox::Rejected)\n            return;\n\n        auto qtArgs = QApplication::instance()->arguments();\n\n        string appPath; // This information is supposed to be in qtArgs but AppImage will overwrite it.\n        if (getenv(\"APPIMAGE\"))\n            appPath = getenv(\"APPIMAGE\");\n        else\n            appPath = QApplication::instance()->applicationFilePath().toStdString();\n\n        vector<const char*> prepend = {\"vglrun\"};\n        char ** args = new char*[prepend.size() + qtArgs.size() + 1];\n        for (int i = 0; i < prepend.size(); i++)\n            args[i] = strdup(prepend[i]);\n        args[0+prepend.size()] = strdup(appPath.c_str());\n        for (int i = 1; i < qtArgs.size(); i++)\n            args[i+prepend.size()] = strdup(qtArgs[i].toStdString().c_str());\n        args[prepend.size() + qtArgs.size()] = nullptr;\n\n\n        // string s = \"\";\n        // for (int i=0; i < prepend.size() + qtArgs.size(); i++)\n        //     s += string() + args[i] + \" \";\n        // printf(\"COMMAND = %s\\n\", s.c_str());\n\n        execvp(args[0], args);\n        MSG_WARN(\"Failed to restart vapor using vglrun\");\n    };\n\n    QObject::connect(popup, &QMessageBox::finished, finish);\n    popup->show();\n#endif\n#endif\n}"
  },
  {
    "path": "apps/vaporgui/NcarCasperUtils.h",
    "content": "#pragma once\n#include <common.h>\n\nclass NcarCasperUtils {\npublic:\n    static void CheckForCasperVGL(ControlExec *ce);\n};\n"
  },
  {
    "path": "apps/vaporgui/NewRendererDialog.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<ui version=\"4.0\">\r\n <class>NewRendererDialog</class>\r\n <widget class=\"QDialog\" name=\"NewRendererDialog\">\r\n  <property name=\"geometry\">\r\n   <rect>\r\n    <x>0</x>\r\n    <y>0</y>\r\n    <width>628</width>\r\n    <height>630</height>\r\n   </rect>\r\n  </property>\r\n  <property name=\"windowTitle\">\r\n   <string>Select New Renderer</string>\r\n  </property>\r\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\r\n   <item>\r\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\r\n     <property name=\"topMargin\">\r\n      <number>0</number>\r\n     </property>\r\n     <item>\r\n      <widget class=\"QLabel\" name=\"label_3\">\r\n       <property name=\"text\">\r\n        <string>Data Source:</string>\r\n       </property>\r\n      </widget>\r\n     </item>\r\n     <item>\r\n      <widget class=\"QComboBox\" name=\"dataMgrCombo\">\r\n       <property name=\"sizePolicy\">\r\n        <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\r\n         <horstretch>0</horstretch>\r\n         <verstretch>0</verstretch>\r\n        </sizepolicy>\r\n       </property>\r\n       <property name=\"minimumSize\">\r\n        <size>\r\n         <width>0</width>\r\n         <height>0</height>\r\n        </size>\r\n       </property>\r\n       <property name=\"frame\">\r\n        <bool>true</bool>\r\n       </property>\r\n      </widget>\r\n     </item>\r\n    </layout>\r\n   </item>\r\n   <item>\r\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_4\">\r\n     <property name=\"topMargin\">\r\n      <number>0</number>\r\n     </property>\r\n     <item>\r\n      <widget class=\"QLabel\" name=\"label\">\r\n       <property name=\"text\">\r\n        <string>Renderer Name:</string>\r\n       </property>\r\n      </widget>\r\n     </item>\r\n     <item>\r\n      <widget class=\"QLineEdit\" name=\"rendererNameEdit\">\r\n       <property name=\"sizePolicy\">\r\n        <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\r\n         <horstretch>0</horstretch>\r\n         <verstretch>0</verstretch>\r\n        </sizepolicy>\r\n       </property>\r\n       <property name=\"minimumSize\">\r\n        <size>\r\n         <width>0</width>\r\n         <height>0</height>\r\n        </size>\r\n       </property>\r\n       <property name=\"maximumSize\">\r\n        <size>\r\n         <width>16777215</width>\r\n         <height>16777215</height>\r\n        </size>\r\n       </property>\r\n       <property name=\"toolTip\">\r\n        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Type in proposed name of renderer.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>\r\n       </property>\r\n      </widget>\r\n     </item>\r\n    </layout>\r\n   </item>\r\n   <item>\r\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\r\n     <property name=\"spacing\">\r\n      <number>20</number>\r\n     </property>\r\n     <property name=\"topMargin\">\r\n      <number>0</number>\r\n     </property>\r\n     <item>\r\n      <widget class=\"QFrame\" name=\"\">\r\n       <property name=\"sizePolicy\">\r\n        <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\r\n         <horstretch>0</horstretch>\r\n         <verstretch>0</verstretch>\r\n        </sizepolicy>\r\n       </property>\r\n       <property name=\"minimumSize\">\r\n        <size>\r\n         <width>0</width>\r\n         <height>0</height>\r\n        </size>\r\n       </property>\r\n       <layout class=\"QVBoxLayout\" name=\"_buttonLayoutHolder\" stretch=\"1,0\">\r\n        <property name=\"leftMargin\">\r\n         <number>0</number>\r\n        </property>\r\n        <property name=\"topMargin\">\r\n         <number>0</number>\r\n        </property>\r\n        <property name=\"rightMargin\">\r\n         <number>0</number>\r\n        </property>\r\n        <property name=\"bottomMargin\">\r\n         <number>0</number>\r\n        </property>\r\n        <item>\r\n         <layout class=\"QGridLayout\" name=\"buttonHolderGridLayout\"/>\r\n        </item>\r\n        <item>\r\n         <spacer name=\"verticalSpacer\">\r\n          <property name=\"orientation\">\r\n           <enum>Qt::Vertical</enum>\r\n          </property>\r\n          <property name=\"sizeHint\" stdset=\"0\">\r\n           <size>\r\n            <width>20</width>\r\n            <height>40</height>\r\n           </size>\r\n          </property>\r\n         </spacer>\r\n        </item>\r\n       </layout>\r\n      </widget>\r\n     </item>\r\n     <item>\r\n      <widget class=\"QFrame\" name=\"\">\r\n       <property name=\"sizePolicy\">\r\n        <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\r\n         <horstretch>0</horstretch>\r\n         <verstretch>0</verstretch>\r\n        </sizepolicy>\r\n       </property>\r\n       <property name=\"maximumSize\">\r\n        <size>\r\n         <width>16777215</width>\r\n         <height>16777215</height>\r\n        </size>\r\n       </property>\r\n       <layout class=\"QVBoxLayout\" name=\"verticalLayout\" stretch=\"2,0,2,1\">\r\n        <property name=\"spacing\">\r\n         <number>-1</number>\r\n        </property>\r\n        <property name=\"leftMargin\">\r\n         <number>0</number>\r\n        </property>\r\n        <property name=\"topMargin\">\r\n         <number>0</number>\r\n        </property>\r\n        <property name=\"rightMargin\">\r\n         <number>0</number>\r\n        </property>\r\n        <property name=\"bottomMargin\">\r\n         <number>0</number>\r\n        </property>\r\n        <item>\r\n         <widget class=\"QLabel\" name=\"bigDisplay\">\r\n          <property name=\"sizePolicy\">\r\n           <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\r\n            <horstretch>0</horstretch>\r\n            <verstretch>0</verstretch>\r\n           </sizepolicy>\r\n          </property>\r\n          <property name=\"minimumSize\">\r\n           <size>\r\n            <width>0</width>\r\n            <height>0</height>\r\n           </size>\r\n          </property>\r\n          <property name=\"maximumSize\">\r\n           <size>\r\n            <width>16777215</width>\r\n            <height>16777215</height>\r\n           </size>\r\n          </property>\r\n          <property name=\"text\">\r\n           <string>Image</string>\r\n          </property>\r\n          <property name=\"alignment\">\r\n           <set>Qt::AlignCenter</set>\r\n          </property>\r\n         </widget>\r\n        </item>\r\n        <item>\r\n         <widget class=\"QLabel\" name=\"titleLabel\">\r\n          <property name=\"sizePolicy\">\r\n           <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\r\n            <horstretch>0</horstretch>\r\n            <verstretch>0</verstretch>\r\n           </sizepolicy>\r\n          </property>\r\n          <property name=\"maximumSize\">\r\n           <size>\r\n            <width>300</width>\r\n            <height>16777215</height>\r\n           </size>\r\n          </property>\r\n          <property name=\"font\">\r\n           <font>\r\n            <weight>75</weight>\r\n            <bold>true</bold>\r\n           </font>\r\n          </property>\r\n          <property name=\"text\">\r\n           <string>TextLabel</string>\r\n          </property>\r\n          <property name=\"alignment\">\r\n           <set>Qt::AlignCenter</set>\r\n          </property>\r\n         </widget>\r\n        </item>\r\n        <item>\r\n         <widget class=\"QScrollArea\" name=\"scrollArea\">\r\n          <property name=\"sizePolicy\">\r\n           <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\r\n            <horstretch>0</horstretch>\r\n            <verstretch>0</verstretch>\r\n           </sizepolicy>\r\n          </property>\r\n          <property name=\"maximumSize\">\r\n           <size>\r\n            <width>300</width>\r\n            <height>16777215</height>\r\n           </size>\r\n          </property>\r\n          <property name=\"frameShape\">\r\n           <enum>QFrame::NoFrame</enum>\r\n          </property>\r\n          <property name=\"widgetResizable\">\r\n           <bool>true</bool>\r\n          </property>\r\n          <widget class=\"QWidget\" name=\"scrollAreaWidgetContents\">\r\n           <property name=\"geometry\">\r\n            <rect>\r\n             <x>0</x>\r\n             <y>0</y>\r\n             <width>291</width>\r\n             <height>181</height>\r\n            </rect>\r\n           </property>\r\n           <property name=\"sizePolicy\">\r\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\r\n             <horstretch>0</horstretch>\r\n             <verstretch>0</verstretch>\r\n            </sizepolicy>\r\n           </property>\r\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\r\n            <item>\r\n             <widget class=\"QLabel\" name=\"descriptionLabel\">\r\n              <property name=\"sizePolicy\">\r\n               <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\r\n                <horstretch>0</horstretch>\r\n                <verstretch>0</verstretch>\r\n               </sizepolicy>\r\n              </property>\r\n              <property name=\"minimumSize\">\r\n               <size>\r\n                <width>0</width>\r\n                <height>0</height>\r\n               </size>\r\n              </property>\r\n              <property name=\"maximumSize\">\r\n               <size>\r\n                <width>16777215</width>\r\n                <height>16777215</height>\r\n               </size>\r\n              </property>\r\n              <property name=\"text\">\r\n               <string>Description</string>\r\n              </property>\r\n              <property name=\"alignment\">\r\n               <set>Qt::AlignCenter</set>\r\n              </property>\r\n              <property name=\"wordWrap\">\r\n               <bool>true</bool>\r\n              </property>\r\n             </widget>\r\n            </item>\r\n           </layout>\r\n          </widget>\r\n         </widget>\r\n        </item>\r\n        <item>\r\n         <spacer name=\"verticalSpacer_3\">\r\n          <property name=\"orientation\">\r\n           <enum>Qt::Vertical</enum>\r\n          </property>\r\n          <property name=\"sizeHint\" stdset=\"0\">\r\n           <size>\r\n            <width>20</width>\r\n            <height>40</height>\r\n           </size>\r\n          </property>\r\n         </spacer>\r\n        </item>\r\n       </layout>\r\n      </widget>\r\n     </item>\r\n    </layout>\r\n   </item>\r\n   <item>\r\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\r\n     <item>\r\n      <widget class=\"QDialogButtonBox\" name=\"buttonBox\">\r\n       <property name=\"orientation\">\r\n        <enum>Qt::Horizontal</enum>\r\n       </property>\r\n       <property name=\"standardButtons\">\r\n        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>\r\n       </property>\r\n       <property name=\"centerButtons\">\r\n        <bool>false</bool>\r\n       </property>\r\n      </widget>\r\n     </item>\r\n    </layout>\r\n   </item>\r\n  </layout>\r\n </widget>\r\n <resources/>\r\n <connections>\r\n  <connection>\r\n   <sender>buttonBox</sender>\r\n   <signal>accepted()</signal>\r\n   <receiver>NewRendererDialog</receiver>\r\n   <slot>accept()</slot>\r\n   <hints>\r\n    <hint type=\"sourcelabel\">\r\n     <x>248</x>\r\n     <y>254</y>\r\n    </hint>\r\n    <hint type=\"destinationlabel\">\r\n     <x>157</x>\r\n     <y>274</y>\r\n    </hint>\r\n   </hints>\r\n  </connection>\r\n  <connection>\r\n   <sender>buttonBox</sender>\r\n   <signal>rejected()</signal>\r\n   <receiver>NewRendererDialog</receiver>\r\n   <slot>reject()</slot>\r\n   <hints>\r\n    <hint type=\"sourcelabel\">\r\n     <x>316</x>\r\n     <y>260</y>\r\n    </hint>\r\n    <hint type=\"destinationlabel\">\r\n     <x>286</x>\r\n     <y>274</y>\r\n    </hint>\r\n   </hints>\r\n  </connection>\r\n </connections>\r\n</ui>\r\n"
  },
  {
    "path": "apps/vaporgui/NewRendererDialogManager.cpp",
    "content": "#include \"NewRendererDialogManager.h\"\n#include <vapor/ControlExecutive.h>\n#include <QApplication>\n#include \"ErrorReporter.h\"\n\nNewRendererDialogManager::NewRendererDialogManager(VAPoR::ControlExec *ce, QWidget *parent)\n: _ce(ce), _nrd(ConstructNewRendererDialog(ce)){\n    _nrd->setVisible(false);\n    _nrd->setParent(parent);\n    _nrd->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);\n    connect(_nrd, &NewRendererDialog::accepted, this, [this](){RenderHolder::_newRendererDialogAccepted(_ce, _nrd);});\n}\n\nvoid NewRendererDialogManager::Show()\n{\n    _nrd->InitializeDataSources(_ce);\n    _nrd->open();\n}\n\nNewRendererDialog* NewRendererDialogManager::ConstructNewRendererDialog(vector<RenderEventRouter*> routers)\n{\n    vector<string>    widgetNames;\n    vector<string>    descriptions;\n    vector<string>    iconPaths;\n    vector<string>    smallIconPaths;\n    vector<bool>      dim2dSupport;\n    vector<bool>      dim3dSupport;\n    vector<bool>      particleSupport;\n\n    for (int i = 0; i < routers.size(); i++) {\n        RenderEventRouter *re = routers[i];\n\n        widgetNames.push_back(re->GetType());\n        descriptions.push_back(re->GetDescription());\n        iconPaths.push_back(re->GetIconImagePath());\n        smallIconPaths.push_back(re->GetSmallIconImagePath());\n\n        dim2dSupport.push_back(re->Supports2DVariables());\n        dim3dSupport.push_back(re->Supports3DVariables());\n        particleSupport.push_back(re->SupportsParticleVariables());\n    }\n\n    return new NewRendererDialog(nullptr, widgetNames, descriptions, iconPaths, smallIconPaths, dim2dSupport, dim3dSupport, particleSupport);\n}\n\nNewRendererDialog *NewRendererDialogManager::ConstructNewRendererDialog(ControlExec *ce)\n{\n    vector<string> rendererNames = RenderEventRouterFactory::Instance()->GetFactoryNames();\n    vector<std::unique_ptr<RenderEventRouter>> routersOwner;\n    vector<RenderEventRouter*> routers;\n\n    for (auto name : rendererNames) {\n        RenderEventRouter *re = RenderEventRouterFactory::Instance()->CreateInstance(name, NULL, ce);\n        routersOwner.push_back(std::unique_ptr<RenderEventRouter>(re));\n        routers.push_back(re);\n    }\n\n    return ConstructNewRendererDialog(routers);\n}"
  },
  {
    "path": "apps/vaporgui/NewRendererDialogManager.h",
    "content": "#pragma once\n\n#include \"RenderHolder.h\"\n#include \"RenderEventRouter.h\"\n\nnamespace VAPoR {class ControlExec;}\nusing namespace VAPoR;\n\nclass NewRendererDialogManager : public QObject {\n    Q_OBJECT\n\n    ControlExec *_ce;\n    NewRendererDialog *_nrd;\n\npublic:\n    NewRendererDialogManager(ControlExec *ce, QWidget *parent);\n\npublic slots:\n    void Show();\n\nprivate:\n    static NewRendererDialog* ConstructNewRendererDialog(vector<RenderEventRouter*> routers);\n    static NewRendererDialog* ConstructNewRendererDialog(ControlExec *ce);\n};"
  },
  {
    "path": "apps/vaporgui/NoticeBoard.cpp",
    "content": "#include \"NoticeBoard.h\"\n#include \"CheckForNotices.h\"\n#include <QVBoxLayout>\n#include <QTextBrowser>\n#include <QDialogButtonBox>\n#include <QLabel>\n#include <QCheckBox>\n#include <cassert>\n#include \"VPushButton.h\"\n#include \"VGroup.h\"\n\nNoticeBoard::NoticeBoard(const std::vector<Notice> &notices) : _notices(notices)\n{\n    setWindowTitle(\"Notice Board\");\n    setBaseSize(500, 500);\n    auto *layout = new QVBoxLayout;\n    setLayout(layout);\n\n    _browser = new QTextBrowser;\n    layout->addWidget(_browser);\n    _browser->setOpenExternalLinks(true);\n\n    auto *check = new QCheckBox(\"Don't check for notices on startup\");\n    layout->addWidget(check);\n    connect(check, &QCheckBox::stateChanged, this, [this](int b) { this->_wasDisableCheckingRequested = b; });\n\n    // Qt provides a \"QDialogButtonBox\" but it is buggy.\n    // For example the following:\n    // auto *disableButton = box->addButton(\"Check\", QDialogButtonBox::RejectRole);\n    // box->addButton(QDialogButtonBox::StandardButton::Close);\n    // box->addButton(\"<\", QDialogButtonBox::YesRole);\n    // box->addButton(\">\", QDialogButtonBox::YesRole);\n    // Results in:\n    // [*Close*] [Check] [>] [<]\n    // While if you swap the first 2 lines you get:\n    // [*Check*] [Close] [>] [<]\n    // While in itself, the above behaviour is unintuative and confusing,\n    // the kicker is that the behavior is not consistent between systems.\n\n    auto *buttonsWidget = new QWidget;\n    auto *buttons = new QHBoxLayout;\n    buttons->setMargin(0);\n    buttonsWidget->setLayout(buttons);\n    layout->addWidget(buttonsWidget);\n\n    auto *prev = new QPushButton(\"<\");\n    auto *disp = new QLabel(\"1/2\");\n    auto *next = new QPushButton(\">\");\n    auto *clos = new QPushButton(\"Close\");\n    clos->setDefault(true);\n    _numberDisplay = disp;\n\n    buttons->addWidget(prev);\n    buttons->addWidget(disp);\n    buttons->addWidget(next);\n    buttons->addStretch();\n    buttons->addWidget(clos);\n\n    connect(clos, &QPushButton::clicked, this, &QWidget::close);\n    connect(prev, &QPushButton::clicked, this, [this]() { showNotice(_displayedNotice - 1); });\n    connect(next, &QPushButton::clicked, this, [this]() { showNotice(_displayedNotice + 1); });\n\n    if (notices.size() == 1) {\n        prev->hide();\n        disp->hide();\n        next->hide();\n    }\n\n    showNotice(0);\n}\n\n\nvoid NoticeBoard::showNotice(int i)\n{\n    if (i < 0) i = _notices.size() - 1;\n    if (i >= _notices.size()) i = 0;\n\n    _browser->setText(QString::fromStdString(_notices[i].content));\n    _numberDisplay->setText(QString(\"%1/%2\").arg(i + 1).arg(_notices.size()));\n    _displayedNotice = i;\n}\n\n\n#include <vapor/ControlExecutive.h>\n#include <vapor/SettingsParams.h>\n\n\nvoid NoticeBoard::CheckForAndShowNotices(ControlExec *ce)\n{\n#ifndef NDEBUG\n    return;    // Don't check for notices in debug builds\n#endif\n\n    CheckForGHNotices([ce](const std::vector<Notice> &notices) {\n        if (notices.empty()) return;\n\n        NoticeBoard board(notices);\n        board.exec();\n\n        if (board.WasDisableCheckingRequested()) {\n            ce->GetParams<SettingsParams>()->SetAutoCheckForNotices(false);\n            ce->GetParams<SettingsParams>()->SaveSettings();\n        }\n    });\n}\n"
  },
  {
    "path": "apps/vaporgui/NoticeBoard.h",
    "content": "#pragma once\n\n#include <QDialog>\n#include <common.h>\n\nstruct Notice;\nclass QTextBrowser;\nclass QLabel;\n\nclass NoticeBoard : public QDialog {\n    bool                      _wasDisableCheckingRequested = false;\n    const std::vector<Notice> _notices;\n    int                       _displayedNotice;\n\n    QTextBrowser *_browser;\n    QLabel *      _numberDisplay;\n\n    void showNotice(int i);\n\npublic:\n    NoticeBoard(const std::vector<Notice> &notices);\n    bool WasDisableCheckingRequested() const { return _wasDisableCheckingRequested; }\n\n    static void CheckForAndShowNotices(ControlExec *ce);\n};\n"
  },
  {
    "path": "apps/vaporgui/PAnnotationColorbarWidget.cpp",
    "content": "#include \"PAnnotationColorbarWidget.h\"\n#include \"PWidgets.h\"\n#include \"PCornerSelector.h\"\n#include \"PColorSelector.h\"\n#include <vapor/ColorbarPbase.h>\n#include <vapor/RenderParams.h>\n\nusing VAPoR::ColorbarPbase;\nusing VAPoR::RenderParams;\ntypedef ColorbarPbase CBP;\n\nPAnnotationColorbarWidget::PAnnotationColorbarWidget() : PWidget(\"\", _pSection = new PSection(\"Colorbar Settings\"))\n{\n    // clang-format off\n    _pSection->Add({\n        new PColorbarCornerSelector,\n        new PCheckbox(CBP::_colorbarEnabledTag, \"Show Colorbar\"),\n        (new PDoubleSliderEdit(CBP::_colorbarPositionXTag, \"X Position\"))->EnableDynamicUpdate(),\n        (new PDoubleSliderEdit(CBP::_colorbarPositionYTag, \"Y Position\"))->EnableDynamicUpdate(),\n        (new PDoubleSliderEdit(CBP::_colorbarSizeYTag, \"Height\"))->EnableDynamicUpdate(),\n        (new PDoubleSliderEdit(CBP::_colorbarSizeXTag, \"Scale\"))->EnableDynamicUpdate(),\n        (new PIntegerSliderEdit(CBP::_colorbarNumTicksTag, \"Ticks\"))->SetRange(2, 20)->EnableDynamicUpdate(),\n        new PStringInput(CBP::_colorbarTitleTag, \"Title\"),\n        new PCheckbox(CBP::UseScientificNotationTag, \"Scientific Notation\"),\n        (new PIntegerInput(CBP::_colorbarNumDigitsTag, \"Significant Figures\"))->SetRange(1, 7),\n        new PColorSelector(CBP::_colorbarFrontColorTag, \"Font Color\"),\n        (new PColorSelector(CBP::_colorbarBackColorTag, \"Background Color\"))->ShowAlpha(),\n#ifdef MANUAL_FONT_CONTROL\n        new PCheckbox(\"manual_font\", \"Manual Font Size\"),\n        (new PShowIf(\"manual_font\"))->Equals(true)->Then(new PSubGroup({\n            (new PIntegerInput(CBP::_colorbarFontSizeTag, \"Font Size\"))->SetRange(6, 80),\n        })),\n#endif\n    });\n    // clang-format on\n}\n\nvoid PAnnotationColorbarWidget::updateGUI() const\n{\n    RenderParams * rp = getParams<RenderParams>();\n    ColorbarPbase *cbp = rp->GetColorbarPbase();\n    _pSection->Update(cbp, getParamsMgr(), getDataMgr());\n}\n"
  },
  {
    "path": "apps/vaporgui/PAnnotationColorbarWidget.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nclass PSection;\n\n//! \\class PAnnotationColorbarWidget\n//! \\brief Widget that provides controls for configuring the colorbar legend.\n//! \\author Stas Jaroszynski\n\nclass PAnnotationColorbarWidget : public PWidget {\n    PSection *_pSection;\n\npublic:\n    PAnnotationColorbarWidget();\n\nprotected:\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PAxisAnnotationWidget.cpp",
    "content": "#include <QLabel>\n#include <vapor/ControlExecutive.h>\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgrUtils.h>\n#include \"PAxisAnnotationWidget.h\"\n#include \"VSection.h\"\n#include \"V3DInput.h\"\n#include \"V3DIntInput.h\"\n#include \"VLineItem.h\"\n#include <vapor/AnimationParams.h>\n#include \"ErrorReporter.h\"\n\nPAxisAnnotationWidget::PAxisAnnotationWidget(VAPoR::ControlExec *controlExec) : PWidget(\"\", _group = new VGroup())\n{\n    _controlExec = controlExec;\n\n    _group->Add(new VLineItem(\"# tics \", _numTics = new V3DIntInput));\n    _group->Add(new VLineItem(\"Size   \", _size = new V3DInput));\n    _group->Add(new VLineItem(\"Min    \", _min = new V3DInput));\n    _group->Add(new VLineItem(\"Max    \", _max = new V3DInput));\n    _group->Add(new VLineItem(\"Origin \", _origin = new V3DInput));\n\n    QObject::connect(_numTics, &V3DIntInput::ValueChangedVec, this, &PAxisAnnotationWidget::_numTicsChanged);\n    QObject::connect(_size, &V3DInput::ValueChangedVec, this, &PAxisAnnotationWidget::_sizeChanged);\n    QObject::connect(_min, &V3DInput::ValueChangedVec, this, &PAxisAnnotationWidget::_minChanged);\n    QObject::connect(_max, &V3DInput::ValueChangedVec, this, &PAxisAnnotationWidget::_maxChanged);\n    QObject::connect(_origin, &V3DInput::ValueChangedVec, this, &PAxisAnnotationWidget::_originChanged);\n}\n\nvoid PAxisAnnotationWidget::updateGUI() const\n{\n    VAPoR::AxisAnnotation *aa = getParams<VAPoR::AxisAnnotation>();\n\n    std::vector<double> dTics = aa->GetNumTics();\n    std::vector<int>    iTics(dTics.begin(), dTics.end());\n    _numTics->SetValue(iTics);\n    _size->SetValue(aa->GetTicSize());\n\n    std::vector<double> minTics = aa->GetMinTics();\n    std::vector<double> maxTics = aa->GetMaxTics();\n    std::vector<double> origin = aa->GetAxisOrigin();\n    _scaleNormalizedCoordsToWorld(minTics);\n    _scaleNormalizedCoordsToWorld(maxTics);\n    _scaleNormalizedCoordsToWorld(origin);\n\n    if (aa->GetLatLonAxesEnabled()) {\n        _convertPCSToLonLat(minTics[0], minTics[1]);\n        _convertPCSToLonLat(maxTics[0], maxTics[1]);\n        _convertPCSToLonLat(origin[0], origin[1]);\n    }\n\n    _min->SetValue(minTics);\n    _max->SetValue(maxTics);\n    _origin->SetValue(origin);\n}\n\nvoid PAxisAnnotationWidget::_numTicsChanged(const std::vector<int> xyz)\n{\n    std::vector<double> dTics(xyz.begin(), xyz.end());\n    getParams<VAPoR::AxisAnnotation>()->SetNumTics(dTics);\n}\n\nvoid PAxisAnnotationWidget::_sizeChanged(const std::vector<double> xyz) { getParams<VAPoR::AxisAnnotation>()->SetTicSize(xyz); }\n\nvoid PAxisAnnotationWidget::_minChanged(std::vector<double> xyz)\n{\n    VAPoR::AxisAnnotation *aa = getParams<VAPoR::AxisAnnotation>();\n    if (aa->GetLatLonAxesEnabled()) _convertLonLatToPCS(xyz[0], xyz[1]);\n\n    _scaleWorldCoordsToNormalized(xyz);\n    getParams<VAPoR::AxisAnnotation>()->SetMinTics(xyz);\n}\n\nvoid PAxisAnnotationWidget::_maxChanged(std::vector<double> xyz)\n{\n    VAPoR::AxisAnnotation *aa = getParams<VAPoR::AxisAnnotation>();\n    if (aa->GetLatLonAxesEnabled()) _convertLonLatToPCS(xyz[0], xyz[1]);\n\n    _scaleWorldCoordsToNormalized(xyz);\n    getParams<VAPoR::AxisAnnotation>()->SetMaxTics(xyz);\n}\n\nvoid PAxisAnnotationWidget::_originChanged(std::vector<double> xyz)\n{\n    VAPoR::AxisAnnotation *aa = getParams<VAPoR::AxisAnnotation>();\n    if (aa->GetLatLonAxesEnabled()) _convertLonLatToPCS(xyz[0], xyz[1]);\n\n    _scaleWorldCoordsToNormalized(xyz);\n    getParams<VAPoR::AxisAnnotation>()->SetAxisOrigin(xyz);\n}\n\nvoid PAxisAnnotationWidget::_scaleNormalizedCoordsToWorld(std::vector<double> &coords) const\n{\n    std::vector<double> extents = _getDomainExtents();\n    int                 size = extents.size() / 2;\n    for (int i = 0; i < size; i++) {\n        double offset = coords[i] * (extents[i + 3] - extents[i]);\n        double minimum = extents[i];\n        coords[i] = offset + minimum;\n    }\n}\n\nvoid PAxisAnnotationWidget::_scaleWorldCoordsToNormalized(std::vector<double> &coords) const\n{\n    std::vector<double> extents = _getDomainExtents();\n    int                 size = extents.size() / 2;\n    for (int i = 0; i < size; i++) {\n        double point = coords[i] - extents[i];\n        double magnitude = extents[i + 3] - extents[i];\n        coords[i] = point / magnitude;\n    }\n}\n\nstd::vector<double> PAxisAnnotationWidget::_getDomainExtents() const\n{\n    VAPoR::ParamsMgr *paramsMgr = _controlExec->GetParamsMgr();\n    AnimationParams * aParams = dynamic_cast<AnimationParams *>(paramsMgr->GetParams(AnimationParams::GetClassType()));\n    VAssert(aParams);\n    int                 ts = aParams->GetCurrentTimestep();\n    VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus();\n    VAPoR::CoordType    minExts, maxExts;\n    dataStatus->GetActiveExtents(paramsMgr, ts, minExts, maxExts);\n\n    std::vector<double> extents = {minExts[0], minExts[1], minExts[2], maxExts[0], maxExts[1], maxExts[2]};\n    return extents;\n}\n\nvoid PAxisAnnotationWidget::_convertPCSToLonLat(double &xCoord, double &yCoord) const\n{\n    VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus();\n    string             projString = dataStatus->GetMapProjection();\n    double             coords[2] = {xCoord, yCoord};\n    double             coordsForError[2] = {coords[0], coords[1]};\n\n    int rc = VAPoR::DataMgrUtils::ConvertPCSToLonLat(projString, coords, 1);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Could not convert point %f, %f to Lon/Lat\", coordsForError[0], coordsForError[1]);\n        MSG_ERR(\"Error converting PCS to Lat-Lon coordinates\");\n    }\n\n    xCoord = coords[0];\n    yCoord = coords[1];\n}\n\nvoid PAxisAnnotationWidget::_convertLonLatToPCS(double &xCoord, double &yCoord) const\n{\n    VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus();\n    string             projString = dataStatus->GetMapProjection();\n    double             coords[2] = {xCoord, yCoord};\n    double             coordsForError[2] = {coords[0], coords[1]};\n\n    int rc = VAPoR::DataMgrUtils::ConvertLonLatToPCS(projString, coords, 1);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Could not convert point %f, %f to PCS\", coordsForError[0], coordsForError[1]);\n        MSG_ERR(\"Error converting from Lat-Lon to PCS coordinates\");\n    }\n\n    xCoord = coords[0];\n    yCoord = coords[1];\n}\n"
  },
  {
    "path": "apps/vaporgui/PAxisAnnotationWidget.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n#include <vector>\n\nclass V3DInput;\nclass V3DIntInput;\nclass VGroup;\n\nnamespace VAPoR {\nclass ControlExec;\n}\n\nclass PAxisAnnotationWidget : public PWidget {\n    VAPoR::ControlExec *_controlExec;\n    VGroup *            _group;\n    V3DIntInput *       _numTics;\n    V3DInput *          _size;\n    V3DInput *          _min;\n    V3DInput *          _max;\n    V3DInput *          _origin;\n\npublic:\n    PAxisAnnotationWidget(VAPoR::ControlExec *controlExec);\n\nprotected:\n    void updateGUI() const override;\n\nprivate:\n    void _numTicsChanged(const std::vector<int> xyz);\n    void _sizeChanged(const std::vector<double> xyz);\n    void _minChanged(const std::vector<double> xyz);\n    void _maxChanged(const std::vector<double> xyz);\n    void _originChanged(const std::vector<double> xyz);\n\n    std::vector<double> _getDomainExtents() const;\n    void                _convertPCSToLonLat(double &xCoord, double &yCoord) const;\n    void                _convertLonLatToPCS(double &xCoord, double &yCoord) const;\n    void                _scaleNormalizedCoordsToWorld(std::vector<double> &coords) const;\n    void                _scaleWorldCoordsToNormalized(std::vector<double> &coords) const;\n};\n"
  },
  {
    "path": "apps/vaporgui/PButton.cpp",
    "content": "#include \"PButton.h\"\n#include \"VPushButton.h\"\n#include <vapor/ParamsMgr.h>\n\nPButton::PButton(std::string label, Callback cb) : PWidget(\"\", _button = new VPushButton(label)), _cb(cb) { QObject::connect(_button, &VPushButton::ButtonClicked, this, &PButton::clicked); }\n\nPButton *PButton::DisableUndo()\n{\n    _disableUndo = true;\n    return this;\n}\n\nvoid PButton::clicked()\n{\n    if (_disableUndo) {\n        auto pm = getParamsMgr();\n        bool state = pm->GetSaveStateUndoEnabled();\n        pm->SetSaveStateUndoEnabled(false);\n        _cb(getParams());\n        pm->SetSaveStateUndoEnabled(state);\n    } else {\n        _cb(getParams());\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/PButton.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n#include <functional>\n\nclass VPushButton;\n\n//! \\class PButton\n//! \\brief PWidget wrapper for VPushButton.\n//! \\author Stas Jaroszynski\n//!\n//! Calls the callback when clicked.\n//! Please don't capture in the callback.\n\nclass PButton : public PWidget {\n    typedef std::function<void(VAPoR::ParamsBase *)> Callback;\n    VPushButton *                                    _button;\n    const Callback                                   _cb;\n    bool                                             _disableUndo = false;\n\npublic:\n    PButton(std::string label, Callback cb);\n    // @copydoc VAPoR::ParamsMgr::SetSaveStateUndoEnabled(bool)\n    PButton *DisableUndo();\n\nprotected:\n    void updateGUI() const override {}\n    bool requireParamsMgr() const override { return _disableUndo; }\n\nprivate:\n    void clicked();\n};\n"
  },
  {
    "path": "apps/vaporgui/PCameraControlsSection.cpp",
    "content": "#include <vapor/ViewpointParams.h>\n#include \"ErrorReporter.h\"\n#include \"PCameraControlsSection.h\"\n#include \"PFileButton.h\"\n#include \"VLineItem.h\"\n#include \"V3DInput.h\"\n#include \"VGroup.h\"\n\n// =====================================\n//           PTrackballWidget\n// =====================================\n\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nPCameraFileGroup::PCameraFileGroup(ControlExec *ce) : PGroup(), _ce(ce) {\n    Add((new PFileWriter(\"Save camera settings to file\", [this](std::string path) { NavigationUtils::GetActiveViewpointParams(this->_ce)->SaveCameraToFile(path); }))->SetFileTypeFilter(\"Vapor Camera File (*.vc3)\"));\n    Add((new PFileReader(\"Load camera settings from file\", [this](std::string path) { PCameraFileGroup::SetAllCameras(path); }))->SetFileTypeFilter(\"Vapor Camera File (*.vc3)\"));\n}\n\nvoid PCameraFileGroup::updateGUI() const {\n    auto params = NavigationUtils::GetActiveViewpointParams(_ce);\n    for (PWidget *child : _children) child->Update(params);\n}\n\nvoid PCameraFileGroup::SetAllCameras(std::string &fileName) {\n    XmlParser xmlparser;\n    XmlNode *node = new XmlNode();\n\n    int rc = xmlparser.LoadFromFile(node, fileName);\n    if (rc < 0) {\n        MSG_ERR(\"Failed to read file \" + fileName);\n        return;\n    }\n\n    // Ensure ModelViewMatrix and RotationCenter tags exist\n    const std::string mvmTag = \"ModelViewMatrix\";\n    const std::string rcTag  = \"RotationCenter\";\n    if (!node->HasElementDouble(mvmTag)) {\n        MSG_ERR(\"Invalid camera file\" + fileName + \".  Missing XML node: \" + mvmTag);\n        return;\n    }\n    if (!node->HasElementDouble(rcTag)) {\n        MSG_ERR(\"Invalid camera file\" + fileName + \".  Missing XML node: \" + rcTag);\n        return;\n    }\n\n    // Check for valid matrix and origin values\n    std::vector<double> matrix = node->GetElementDouble(mvmTag);\n    std::vector<double> origin = node->GetElementDouble(rcTag);\n    if (matrix.size() != 16) {\n        MSG_ERR(\"Invalid camera file\" + fileName + \".  Tag \" + mvmTag + \" must have 16 elements.\");\n        return;\n    }\n    if (origin.size() != 3) {\n        MSG_ERR(\"Invalid camera file\" + fileName + \".  Tag \" + rcTag + \" must have 3 elements.\");\n        return;\n    }\n\n    NavigationUtils::SetAllCameras(_ce, matrix, origin);\n}\n\nPTrackballWidget::PTrackballWidget(ControlExec *ce) : PWidget(\"\", _group = new VGroup()), _ce(ce)\n{\n    _group->Add(new VLineItem(\"Direction\", _direction = new V3DInput));\n    _group->Add(new VLineItem(\"Up Vector\", _up = new V3DInput));\n    _group->Add(new VLineItem(\"Position  \", _position = new V3DInput));\n    _group->Add(new VLineItem(\"Origin     \", _origin = new V3DInput));\n\n    connect(_direction, &V3DInput::ValueChanged, this, &PTrackballWidget::cameraChanged);\n    connect(_up, &V3DInput::ValueChanged, this, &PTrackballWidget::cameraChanged);\n    connect(_position, &V3DInput::ValueChanged, this, &PTrackballWidget::cameraChanged);\n    connect(_origin, &V3DInput::ValueChanged, this, &PTrackballWidget::cameraChanged);\n}\n\n\nvoid PTrackballWidget::updateGUI() const\n{\n    ViewpointParams *vp = NavigationUtils::GetActiveViewpointParams(_ce);\n    double           m[16], position[3], up[3], direction[3], origin[3];\n    vp->GetModelViewMatrix(m);\n    bool status = vp->ReconstructCamera(m, position, up, direction);\n    vp->GetRotationCenter(origin);\n    if (!status) {\n        MSG_ERR(\"Failed to get camera parameters\");\n        return;\n    }\n\n    _position->SetValue(position);\n    _up->SetValue(up);\n    _direction->SetValue(direction);\n    _origin->SetValue(origin);\n}\n\n\nvoid PTrackballWidget::cameraChanged() { NavigationUtils::SetAllCameras(_ce, _position->GetValue(), _direction->GetValue(), _up->GetValue(), _origin->GetValue()); }\n\n\n\n// =====================================\n//        PCameraProjectionWidget\n// =====================================\n\n\n\n#include \"VComboBox.h\"\n#include <vapor/GUIStateParams.h>\n\n\nconst string PCameraProjectionWidget::Perspective = \"Perspective\";\nconst string PCameraProjectionWidget::MapOrthographic = \"Map Orthographic\";\n\n\nPCameraProjectionWidget::PCameraProjectionWidget(ControlExec *ce) : PWidget(\"\", new VLineItem(\"Projection Mode\", _dropdown = new VComboBox({Perspective, MapOrthographic}))), _ce(ce)\n{\n    connect(_dropdown, &VComboBox::ValueChanged, this, &PCameraProjectionWidget::dropdownChanged);\n}\n\n\nvoid PCameraProjectionWidget::updateGUI() const\n{\n    ViewpointParams::ProjectionType t = NavigationUtils::GetActiveViewpointParams(_ce)->GetProjectionType();\n\n    if (t == ViewpointParams::Perspective)\n        _dropdown->SetValue(Perspective);\n    else if (t == ViewpointParams::MapOrthographic)\n        _dropdown->SetValue(MapOrthographic);\n}\n\n\nvoid PCameraProjectionWidget::dropdownChanged(string s)\n{\n    ViewpointParams::ProjectionType type;\n    if (s == Perspective)\n        type = ViewpointParams::Perspective;\n    else if (s == MapOrthographic)\n        type = ViewpointParams::MapOrthographic;\n    else\n        type = ViewpointParams::Perspective;\n\n    ParamsMgr *pm = _ce->GetParamsMgr();\n    auto       vizNames = pm->GetVisualizerNames();\n\n    pm->BeginSaveStateGroup(\"Projection Mode Set\");\n    for (auto &viz : vizNames) {\n        ViewpointParams *vp = pm->GetViewpointParams(viz);\n        vp->SetProjectionType(type);\n    }\n    NavigationUtils::ViewAll(_ce);\n    NavigationUtils::SetHomeViewpoint(_ce);\n    pm->EndSaveStateGroup();\n}\n"
  },
  {
    "path": "apps/vaporgui/PCameraControlsSection.h",
    "content": "#pragma once\n\n\n// =====================================\n//           PTrackballWidget\n// =====================================\n\n\n#include \"PWidget.h\"\n#include \"PGroup.h\"\n#include <vapor/NavigationUtils.h>\n\nclass VGroup;\nclass V3DInput;\n\nclass PTrackballWidget : public PWidget {\n    ControlExec *_ce;\n    VGroup *     _group;\n    V3DInput *   _direction;\n    V3DInput *   _up;\n    V3DInput *   _position;\n    V3DInput *   _origin;\n\npublic:\n    PTrackballWidget(ControlExec *ce);\n\nprotected:\n    void updateGUI() const override;\n    void cameraChanged();\n};\n\n\n// =====================================\n//        PCameraProjectionWidget\n// =====================================\n\n\nclass VComboBox;\n\nclass PCameraProjectionWidget : public PWidget {\n    ControlExec *       _ce;\n    VComboBox *         _dropdown;\n    static const string Perspective;\n    static const string MapOrthographic;\n\npublic:\n    PCameraProjectionWidget(ControlExec *ce);\n\nprotected:\n    void updateGUI() const override;\n    void dropdownChanged(string s);\n};\n\n\nclass PCameraFileGroup : public PGroup {\n    ControlExec* _ce;\n\npublic:\n    PCameraFileGroup(ControlExec* ce);\n    void SetAllCameras(std::string& path);\n\nprotected:\n    void updateGUI() const override;\n};\n\n// =====================================\n//        PCameraControlsSection\n// =====================================\n\n\n#include \"PSection.h\"\nclass PCameraControlsSection : public PSection {\npublic:\n    // clang-format off\n    PCameraControlsSection(ControlExec *ce)\n    :\n    PSection(\"Camera Controls\", {\n        new PTrackballWidget(ce),\n        new PCameraProjectionWidget(ce),\n        new PCameraFileGroup(ce)\n    }) {}\n    // clang-format on\n};\n"
  },
  {
    "path": "apps/vaporgui/PCaptureWidget.cpp",
    "content": "#include \"CaptureController.h\"\n#include \"PCaptureWidget.h\"\n#include \"PTimeRangeSelector.h\"\n#include \"PRadioButtons.h\"\n#include \"PButton.h\"\n#include \"PSection.h\"\n#include \"PEnumDropdown.h\"\n#include \"VComboBox.h\"\n#include \"VLabel.h\"\n#include \"VHBoxWidget.h\"\n\n#include \"vapor/AnimationParams.h\"\n#include \"vapor/ControlExecutive.h\"\n#include \"vapor/STLUtils.h\"\n#include \"vapor/FileUtils.h\"\n#include \"vapor/NavigationUtils.h\"\n\n#include <QFileDialog>\n#include <QHBoxLayout>\n\nPCaptureHBox::PCaptureHBox(VAPoR::ControlExec *ce, CaptureController *captureController)\n    : PWidget(\"\", _hBox = new VHBoxWidget()), _ce(ce), _captureController(captureController)\n{\n    _hBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);\n\n    _typeCombo = new PEnumDropdownStandalone(AnimationParams::CaptureTypeTag, {\"TIFF\", \"PNG\"}, {0, 1});\n\n    _fileLabel = new VLabel(\"\");\n    _fileLabel->MakeSelectable();\n\n    _captureButton = new PButton(\"Export\", [this](VAPoR::ParamsBase*){_captureController->CaptureSingleImage();});\n    _captureButton->ShowBasedOnParam(AnimationParams::CaptureModeTag, AnimationParams::SingleImage);\n\n    _captureTimeSeriesButton = new PButton(\"Export\", [this](VAPoR::ParamsBase*){_captureController->EnableAnimationCapture();});\n    _captureTimeSeriesButton->ShowBasedOnParam(AnimationParams::CaptureModeTag, AnimationParams::TimeSeries);\n\n    QHBoxLayout* layout = qobject_cast<QHBoxLayout*>(_hBox->layout());\n    layout->addWidget(_typeCombo,1);\n    layout->addWidget(_fileLabel,3);\n    layout->addWidget(_captureButton,1);\n    layout->addWidget(_captureTimeSeriesButton,1);\n}\n\nvoid PCaptureHBox::_dropdownIndexChanged(int index) {\n    int value;\n    if (_enumMap.empty()) value = index; \n    else value = _enumMap[index];\n    setParamsLong(value);\n}\n\nvoid PCaptureHBox::updateGUI() const {\n    AnimationParams* ap = (AnimationParams*)_ce->GetParamsMgr()->GetParams(AnimationParams::GetClassType());\n    _typeCombo->Update(ap);\n\n    // Format the label for the saved file\n    std::string file, time;\n    std::string dir = ap->GetValueString(AnimationParams::CaptureFileDirTag, \"\");\n    if (ap->GetValueLong(AnimationParams::CaptureModeTag, AnimationParams::SingleImage) == AnimationParams::SingleImage) { // Capture signle frame\n        file = ap->GetValueString(AnimationParams::CaptureFileNameTag, \"\");\n        time = ap->GetValueString(AnimationParams::CaptureFileTimeTag, \"\");\n    }\n    else { // Capture timeseries\n        file = ap->GetValueString(AnimationParams::CaptureTimeSeriesFileNameTag, \"\");\n        if (file != \"\") {\n            file = FileUtils::Basename(ap->GetValueString(AnimationParams::CaptureTimeSeriesFileNameTag, \"\"));\n            size_t pos = file.rfind(\"0000\");\n            if (pos != std::string::npos) file.replace(pos, 4, \"####\"); // Replace last instance of 0000 with #### for file label\n            time = ap->GetValueString(AnimationParams::CaptureTimeSeriesTimeTag, \"\");\n        }\n    }\n    if (!file.empty()) file = \"Saved: \" + file + \"\\nDir: \" + dir + \"\\nOn: \" + time;\n    _fileLabel->SetText(file);\n\n    _captureButton->Update(ap);\n    _captureTimeSeriesButton->Update(ap);\n}\n\nPCaptureWidget::PCaptureWidget(VAPoR::ControlExec *ce, CaptureController *captureController)\n    : PWidget(\"\", _section = new PSection(\"Image(s)\")), _ce(ce)\n{\n    _section->Add(new PRadioButtons(AnimationParams::CaptureModeTag, {\"Current frame\", \"Time series range\"}));\n\n    PTimeRangeSelector *t = new PTimeRangeSelector(_ce);\n    t->EnableBasedOnParam(AnimationParams::CaptureModeTag, 1);\n    _section->Add(t);\n\n    _section->Add(new PCaptureHBox(ce, captureController));\n}\n\nvoid PCaptureWidget::updateGUI() const {    \n    AnimationParams* ap = (AnimationParams*)_ce->GetParamsMgr()->GetParams(AnimationParams::GetClassType());\n    _section->Update(ap);\n}\n"
  },
  {
    "path": "apps/vaporgui/PCaptureWidget.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nnamespace VAPoR {\nclass ControlExec;\n}\n\nclass PSection;\nclass PEnumDropdownStandalone;\nclass VLabel;\nclass PButton;\nclass VHBoxWidget;\nclass VComboBox;\nclass VLabel;\nclass CaptureController;\n\nclass PCaptureHBox : public PWidget {\n    Q_OBJECT;\n\n    ControlExec *_ce;\n    CaptureController *_captureController;\n    VHBoxWidget *_hBox;\n    PStringDropdown *_fileTypeSelector;\n    const std::vector<long> _enumMap;\n\n    PEnumDropdownStandalone *_typeCombo;\n    VLabel *_fileLabel;\n    PButton *_captureButton;\n    PButton *_captureTimeSeriesButton;\n\npublic:\n    PCaptureHBox(VAPoR::ControlExec *ce, CaptureController *captureController);\n\nprotected:\n    virtual void updateGUI() const;\n\nprivate slots:\n    void _dropdownIndexChanged(int index);\n};\n    \nclass PCaptureWidget : public PWidget {\n    Q_OBJECT\n\n    ControlExec *_ce;\n    PSection *_section;\n\npublic:\n    PCaptureWidget(VAPoR::ControlExec *ce, CaptureController *captureController);\n\nprotected:\n    virtual void updateGUI() const;\n};\n"
  },
  {
    "path": "apps/vaporgui/PCheckbox.cpp",
    "content": "#include \"PCheckbox.h\"\n#include \"VCheckBox.h\"\n#include \"VLineItem.h\"\n#include <vapor/ParamsBase.h>\n\nPCheckbox::PCheckbox(const std::string &tag, const std::string &label) : PLineItem(tag, label, _vcheckbox = new VCheckBox)\n{\n    connect(_vcheckbox, &VCheckBox::ValueChanged, this, &PCheckbox::checkboxStateChanged);\n}\n\nvoid PCheckbox::updateGUI() const\n{\n    bool on = getParamsLong();\n\n    _vcheckbox->SetValue(on);\n}\n\nvoid PCheckbox::checkboxStateChanged(bool on) { setParamsLong(on); }\n"
  },
  {
    "path": "apps/vaporgui/PCheckbox.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n\nclass VCheckBox;\n\n//! \\class PCheckbox\n//! Creates a Qt Checkbox synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PCheckbox : public PLineItem {\n    Q_OBJECT\n\n    VCheckBox *_vcheckbox;\n\npublic:\n    PCheckbox(const std::string &tag, const std::string &label = \"\");\n\nprotected:\n    void updateGUI() const override;\n\nprivate slots:\n    void checkboxStateChanged(bool on);\n};\n"
  },
  {
    "path": "apps/vaporgui/PCheckboxHLI.h",
    "content": "#pragma once\n\n#include \"PWidgetHLI.h\"\n#include \"PCheckbox.h\"\n\nCreateHLI(PCheckbox, bool);\n"
  },
  {
    "path": "apps/vaporgui/PColorSelector.cpp",
    "content": "#include \"PColorSelector.h\"\n#include \"QColorWidget.h\"\n#include <vector>\n#include <vapor/ParamsBase.h>\n\nPColorSelector::PColorSelector(const std::string &tag, const std::string &label) : PLineItem(tag, label, _colorWidget = new QColorWidget)\n{\n    connect(_colorWidget, SIGNAL(colorChanged(QColor)), this, SLOT(colorChanged(QColor)));\n}\n\nPColorSelector *PColorSelector::ShowAlpha()\n{\n    _colorWidget->ShowAlpha = true;\n    return this;\n}\n\nQColor PColorSelector::VectorToQColor(const std::vector<double> &v)\n{\n    if (v.size() == 3) return QColor::fromRgbF(v[0], v[1], v[2]);\n    if (v.size() == 4) return QColor::fromRgbF(v[0], v[1], v[2], v[3]);\n    return QColor::fromRgbF(0, 0, 0);\n}\n\nstd::vector<double> PColorSelector::QColorToVector(const QColor &c)\n{\n    std::vector<double> v(4, 0);\n    v[0] = c.redF();\n    v[1] = c.greenF();\n    v[2] = c.blueF();\n    v[3] = c.alphaF();\n    return v;\n}\n\nvoid PColorSelector::updateGUI() const\n{\n    QColor color = VectorToQColor(getParams()->GetValueDoubleVec(getTag()));\n    _colorWidget->setColor(color);\n}\n\nvoid PColorSelector::colorChanged(QColor color) { getParams()->SetValueDoubleVec(getTag(), \"\", QColorToVector(color)); }\n"
  },
  {
    "path": "apps/vaporgui/PColorSelector.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n\nclass QColorWidget;\n\n//! \\class PColorSelector\n//! Creates a Qt Color Selector synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PColorSelector : public PLineItem {\n    Q_OBJECT\n\n    QColorWidget *_colorWidget;\n\npublic:\n    PColorSelector(const std::string &tag, const std::string &label = \"\");\n    PColorSelector *ShowAlpha();\n\nprotected:\n    void updateGUI() const override;\n\n    static QColor              VectorToQColor(const std::vector<double> &v);\n    static std::vector<double> QColorToVector(const QColor &c);\n\nprivate slots:\n    void colorChanged(QColor color);\n};\n"
  },
  {
    "path": "apps/vaporgui/PConstantColorWidget.cpp",
    "content": "#include \"PConstantColorWidget.h\"\n#include \"PCheckbox.h\"\n#include \"PColorSelector.h\"\n#include <vapor/RenderParams.h>\n\nusing VAPoR::RenderParams;\n\nPConstantColorWidget::PConstantColorWidget()\n{\n    Add(new PCheckbox(RenderParams::_useSingleColorTag, \"Use Constant Color\"));\n    Add((new PSubGroup({new PColorSelector(RenderParams::_constantColorTag, \"Constant Color\")}))->ShowBasedOnParam(RenderParams::_useSingleColorTag));\n}\n"
  },
  {
    "path": "apps/vaporgui/PConstantColorWidget.h",
    "content": "#pragma once\n\n#include \"PGroup.h\"\n\nclass PConstantColorWidget : public PGroup {\npublic:\n    PConstantColorWidget();\n};\n"
  },
  {
    "path": "apps/vaporgui/PCopyRegionAnnotationWidget.cpp",
    "content": "#include \"PCopyRegionAnnotationWidget.h\"\n#include \"CopyRegionAnnotationWidget.h\"\n#include <vapor/ControlExecutive.h>\n#include <vapor/RenderParams.h>\n\nusing namespace VAPoR;\n\nPCopyRegionAnnotationWidget::PCopyRegionAnnotationWidget(ControlExec *ce) : PWidget(\"\", _widget = new CopyRegionAnnotationWidget(ce)) {}\n\nvoid PCopyRegionAnnotationWidget::updateGUI() const { _widget->Update(); }\n"
  },
  {
    "path": "apps/vaporgui/PCopyRegionAnnotationWidget.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nnamespace VAPoR {\nclass ControlExec;\n}\n\nclass CopyRegionAnnotationWidget;\n\n//! \\class PPCopyRegionAnnotationWidget\n//! \\brief PWidget wrapper for the PCopyRegionAnnotationWidget\n\nclass PCopyRegionAnnotationWidget : public PWidget {\n    CopyRegionAnnotationWidget *_widget;\n\npublic:\n    PCopyRegionAnnotationWidget(VAPoR::ControlExec *ce);\n\nprivate:\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PCopyRegionWidget.cpp",
    "content": "#include \"PCopyRegionWidget.h\"\n#include \"CopyRegionWidget.h\"\n#include <vapor/RenderParams.h>\n\nPCopyRegionWidget::PCopyRegionWidget() : PWidget(\"\", _widget = new CopyRegionWidget) {}\n\nvoid PCopyRegionWidget::updateGUI() const { _widget->Update(getParamsMgr(), getParams<VAPoR::RenderParams>()); }\n"
  },
  {
    "path": "apps/vaporgui/PCopyRegionWidget.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nclass CopyRegionWidget;\n\n//! \\class PCopyRegionWidget\n//! \\brief PWidget wrapper for the CopyRegionWidget\n//! \\author Stas Jaroszynski\n\nclass PCopyRegionWidget : public PWidget {\n    CopyRegionWidget *_widget;\n\npublic:\n    PCopyRegionWidget();\n\nprotected:\n    void updateGUI() const override;\n    bool requireParamsMgr() const override { return true; }\n};\n"
  },
  {
    "path": "apps/vaporgui/PCornerSelector.cpp",
    "content": "#include \"PCornerSelector.h\"\n#include \"VCheckBox.h\"\n#include <vapor/ColorbarPbase.h>\n#include <QFrame>\n#include <cassert>\n#include <QGridLayout>\n\n\nusing VAPoR::ColorbarPbase;\n\n\nclass PCornerSelector::Check : public VCheckBox {\npublic:\n    float x, y;\n    Check(float x, float y) : x(x), y(y) { setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Minimum); }\n};\n\n\ntemplate<QFrame::Shape T> class Line : public QFrame {\npublic:\n    Line()\n    {\n        setFrameShape(T);\n        setFrameShadow(QFrame::Sunken);\n    }\n};\ntypedef Line<QFrame::HLine> HLine;\ntypedef Line<QFrame::VLine> VLine;\n\n\nPCornerSelector::PCornerSelector(std::string tag, std::string title) : PLineItem(tag, title, _w = new QWidget)\n{\n    QGridLayout *l = new QGridLayout;\n    //        l->setSpacing(0); This breaks the layout whereas setting H and V manually works... Thanks Qt.\n    l->setVerticalSpacing(0);\n    l->setHorizontalSpacing(0);\n    _w->setLayout(l);\n\n    auto add = [&](int x, int y, QWidget *w) {\n        l->addWidget(w, y, x);\n        w->setContentsMargins(0, 0, 0, 0);\n        if (auto c = dynamic_cast<Check *>(w))\n            _checks.push_back(c);\n        else if (dynamic_cast<VLine *>(w))\n            l->setAlignment(w, Qt::AlignHCenter);\n    };\n\n    add(0, 0, new Check(0, 1));\n    add(1, 0, new HLine);\n    add(2, 0, new Check(0.5, 1));\n    add(3, 0, new HLine);\n    add(4, 0, new Check(1, 1));\n\n    add(0, 1, new VLine);\n    add(4, 1, new VLine);\n\n    add(0, 2, new Check(0, 0.5));\n    add(4, 2, new Check(1, 0.5));\n\n    add(0, 3, new VLine);\n    add(4, 3, new VLine);\n\n    add(0, 4, new Check(0, 0));\n    add(1, 4, new HLine);\n    add(2, 4, new Check(0.5, 0));\n    add(3, 4, new HLine);\n    add(4, 4, new Check(1, 0));\n\n    l->setRowMinimumHeight(1, l->itemAtPosition(0, 0)->minimumSize().height() / 1.618);\n    l->setRowMinimumHeight(3, l->itemAtPosition(0, 0)->minimumSize().height() / 1.618);\n\n    for (auto c : _checks) connect(c, &VCheckBox::ValueChanged, this, &PCornerSelector::checked);\n}\n\n\nvoid PCornerSelector::updateGUI() const\n{\n    auto d = getValue();\n    if (d.size() != 2) return;\n    float x = d[0], y = d[1];\n\n    for (auto c : _checks) {\n        float cx = c->x - (c->x - 0.5) * 2 * padding;\n        float cy = c->y - (c->y - 0.5) * 2 * padding;\n        c->SetValue(equalsf(cx, x) && equalsf(cy, y));\n    }\n}\n\n\nvoid PCornerSelector::checked(bool on)\n{\n    Check *c = dynamic_cast<Check *>(sender());\n    assert(c);\n    if (!c) return;\n\n    if (!on) c->SetValue(true);\n\n    float cx = c->x - (c->x - 0.5) * 2 * padding;\n    float cy = c->y - (c->y - 0.5) * 2 * padding;\n    setValue({cx, cy});\n}\n\n\nstd::vector<double> PCornerSelector::getValue() const { return getParams()->GetValueDoubleVec(getTag()); }\n\n\nvoid PCornerSelector::setValue(const std::vector<double> &v) { getParams()->SetValueDoubleVec(getTag(), \"\", v); }\n\n\nPColorbarCornerSelector::PColorbarCornerSelector() : PCornerSelector(\"\", \"Position\") {}\n\nstd::vector<double> PColorbarCornerSelector::getValue() const { return getParams<ColorbarPbase>()->GetCornerPosition(); }\n\nvoid PColorbarCornerSelector::setValue(const std::vector<double> &v) { getParams<ColorbarPbase>()->SetCornerPosition(v); }\n"
  },
  {
    "path": "apps/vaporgui/PCornerSelector.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n#include <cmath>\n\n//! \\class PCornerSelector\n//! \\brief Widget for selecting a corner or side of a square\n//! \\author Stas Jaroszynski\n//!\n//! Widget that presents a collection of checkboxes orientated in a square, allowing the user to\n//! to select either a corner or side.\n\nclass PCornerSelector : public PLineItem {\n    class Check;\n    QWidget *            _w;\n    std::vector<Check *> _checks;\n    float                padding = 0.03;\n\npublic:\n    PCornerSelector(std::string tag, std::string title);\n\nprotected:\n    static bool equalsf(float a, float b) { return (std::abs(b - a) <= 0.05); }\n\n    void                        updateGUI() const override;\n    void                        checked(bool on);\n    virtual std::vector<double> getValue() const;\n    virtual void                setValue(const std::vector<double> &v);\n};\n\n//! \\class PColorbarCornerSelector\n//! \\brief Specialization of PCornerSelector for ColorbarPbase\n//! \\author Stas Jaroszynski\n//! \\copydoc PCornerSelector\n\nclass PColorbarCornerSelector : public PCornerSelector {\npublic:\n    PColorbarCornerSelector();\n    virtual std::vector<double> getValue() const override;\n    virtual void                setValue(const std::vector<double> &v) override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PDatasetTransformWidget.cpp",
    "content": "#include \"PDatasetTransformWidget.h\"\n#include <vapor/ControlExecutive.h>\n#include <vapor/STLUtils.h>\n#include <vapor/GUIStateParams.h>\n#include \"VSection.h\"\n#include \"PStringDropdown.h\"\n#include \"PTransformWidget.h\"\n\nusing namespace VAPoR;\n\nconst std::string PDatasetTransformWidget::SelectedDatasetTag = \"transformWidgetDatasetTag\";\n\nPDatasetTransformWidget::PDatasetTransformWidget(VAPoR::ControlExec *ce)\n: PWidget(\"\", _section = new VSectionGroup(\"Transform\",\n                                           {\n                                               _twDataset = new PStringDropdown(SelectedDatasetTag, {}, \"Dataset\"),\n                                               _tw = new PTransformWidget,\n                                           })),\n  _ce(ce)\n{\n}\n\n\nvoid PDatasetTransformWidget::updateGUI() const\n{\n    ParamsMgr *      pm = _ce->GetParamsMgr();\n    auto             stateParams = ((GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType()));\n    auto             activeViz = stateParams->GetActiveVizName();\n    ViewpointParams *vp = pm->GetViewpointParams(activeViz);\n    if (!vp) return;\n\n    DataStatus *   dataStatus = _ce->GetDataStatus();\n    vector<string> datasets = dataStatus->GetDataMgrNames();\n    if (datasets.empty()) {\n        _section->setEnabled(false);\n        return;\n    } else {\n        _section->setEnabled(true);\n    }\n\n    _twDataset->SetItems(datasets);\n    _twDataset->Update(vp);\n\n    string dataset = vp->GetValueString(SelectedDatasetTag, datasets[0]);\n    if (!STLUtils::Contains(datasets, dataset)) dataset = datasets[0];\n    Transform *transform = vp->GetTransform(dataset);\n    _tw->Update(transform);\n}\n"
  },
  {
    "path": "apps/vaporgui/PDatasetTransformWidget.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nnamespace VAPoR {\nclass ControlExec;\n}\nclass VSection;\nclass PStringDropdown;\nclass PTransformWidget;\n\n\nclass PDatasetTransformWidget : public PWidget {\n    VAPoR::ControlExec *     _ce;\n    VSection *               _section;\n    PStringDropdown *        _twDataset;\n    PTransformWidget *       _tw;\n    static const std::string SelectedDatasetTag;\n\npublic:\n    PDatasetTransformWidget(VAPoR::ControlExec *ce);\n\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PDimensionSelector.cpp",
    "content": "#include \"PDimensionSelector.h\"\n#include <vapor/RenderParams.h>\n#include \"VComboBox.h\"\n\nusing namespace VAPoR;\n\nPDimensionSelector::PDimensionSelector() : PLineItem(\"\", \"Variable Dimension\", _vComboBox = new VComboBox({\"2D\", \"3D\"}))\n{\n    connect(_vComboBox, &VComboBox::ValueChanged, this, &PDimensionSelector::dropdownTextChanged);\n}\n\nvoid PDimensionSelector::updateGUI() const\n{\n    if (getParams<RenderParams>()->GetRenderDim() == 3)\n        _vComboBox->SetValue(\"3D\");\n    else\n        _vComboBox->SetValue(\"2D\");\n}\n\nvoid PDimensionSelector::dropdownTextChanged(std::string text)\n{\n    RenderParams *rp = getParams<RenderParams>();\n    int           dim = text == \"2D\" ? 2 : 3;\n\n    rp->BeginGroup(\"Change dim\");\n    if (dim == 2) {\n        rp->GetBox()->SetPlanar(true);\n        rp->GetBox()->SetOrientation(VAPoR::Box::XY);\n    } else {\n        rp->GetBox()->SetPlanar(false);\n        rp->GetBox()->SetOrientation(VAPoR::Box::XYZ);\n    }\n    rp->SetDefaultVariables(dim, true);\n    rp->EndGroup();\n}\n"
  },
  {
    "path": "apps/vaporgui/PDimensionSelector.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n\nclass VComboBox;\n\nclass PDimensionSelector : public PLineItem {\n    VComboBox *_vComboBox;\n\npublic:\n    PDimensionSelector();\n\nprotected:\n    virtual void updateGUI() const override;\n    bool         requireDataMgr() const override { return true; }\n\nprivate:\n    void dropdownTextChanged(std::string text);\n};\n"
  },
  {
    "path": "apps/vaporgui/PDisplay.cpp",
    "content": "#include \"PDisplay.h\"\n#include \"VCheckBox.h\"\n#include \"VLineItem.h\"\n#include \"VLabel.h\"\n#include <vapor/ParamsBase.h>\n\nPDisplay::PDisplay(const std::string &tag, const std::string &label) : PWidget(tag, new VLineItem(label == \"\" ? tag : label, _label = new VLabel)) {}\n\nPDisplay *PDisplay::Selectable()\n{\n    _label->MakeSelectable();\n    return this;\n}\n\nvoid PDisplay::setText(std::string text) const\n{\n    if (text.empty())\n        setText(\"<empty>\");\n    else\n        _label->SetText(text);\n}\n\nvoid PStringDisplay::updateGUI() const\n{\n    std::string text = getParamsString();\n    setText(text);\n}\n\nvoid PIntegerDisplay::updateGUI() const\n{\n    long value = getParamsLong();\n    setText(QString::number(value).toStdString());\n}\n\nvoid PDoubleDisplay::updateGUI() const\n{\n    double value = getParamsDouble();\n    setText(QString::number(value).toStdString());\n}\n\nvoid PBooleanDisplay::updateGUI() const\n{\n    bool on = getParamsLong();\n    setText(on ? \"True\" : \"False\");\n}\n"
  },
  {
    "path": "apps/vaporgui/PDisplay.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nclass VLabel;\n\n//! @class PDisplay\n//! Creates a label that displays a value in the params database.\n//! Does not allow for editing of said value.\n\nclass PDisplay : public PWidget {\n    Q_OBJECT\n\npublic:\n    PDisplay(const std::string &tag, const std::string &label = \"\");\n    PDisplay *Selectable();\n\nprotected:\n    VLabel *_label;\n\n    void setText(std::string text) const;\n};\n\n//! @class PStringDisplay\n//! @copydoc PDisplay\n\nclass PStringDisplay : public PDisplay {\n    Q_OBJECT\n\npublic:\n    using PDisplay::PDisplay;\n\nprotected:\n    void updateGUI() const override;\n};\n\n//! @class PIntegerDisplay\n//! @copydoc PDisplay\n\nclass PIntegerDisplay : public PDisplay {\n    Q_OBJECT\n\npublic:\n    using PDisplay::PDisplay;\n\nprotected:\n    void updateGUI() const override;\n};\n\n//! @class PDoubleDisplay\n//! @copydoc PDisplay\n\nclass PDoubleDisplay : public PDisplay {\n    Q_OBJECT\n\npublic:\n    using PDisplay::PDisplay;\n\nprotected:\n    void updateGUI() const override;\n};\n\n//! @class PBooleanDisplay\n//! @copydoc PDisplay\n\nclass PBooleanDisplay : public PDisplay {\n    Q_OBJECT\n\npublic:\n    using PDisplay::PDisplay;\n\nprotected:\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PDisplayHLI.h",
    "content": "#pragma once\n\n#include \"PWidgetHLI.h\"\n#include \"PDisplay.h\"\n\nCreateHLI(PStringDisplay, std::String);\nCreateHLI(PIntegerDisplay, long);\nCreateHLI(PDoubleDisplay, double);\nCreateHLI(PBooleanDisplay, bool);\n"
  },
  {
    "path": "apps/vaporgui/PDoubleInput.cpp",
    "content": "#include \"PDoubleInput.h\"\n#include \"VLineItem.h\"\n#include <vapor/ParamsBase.h>\n#include \"VLineEdit_Deprecated.h\"\n\nPDoubleInput::PDoubleInput(const std::string &tag, const std::string &label) : PLineItem(tag, label, _doubleInput = new VLineEdit_Deprecated)\n{\n    _doubleInput->SetIsDouble(true);\n    connect(_doubleInput, &VLineEdit_Deprecated::ValueChanged, this, &PDoubleInput::doubleInputValueChanged);\n}\n\nvoid PDoubleInput::updateGUI() const\n{\n    double value = getParamsDouble();\n    _doubleInput->SetValue(to_string(value));\n}\n\nvoid PDoubleInput::doubleInputValueChanged(const std::string &v)\n{\n    double d = stod(v);\n    setParamsDouble(d);\n}\n"
  },
  {
    "path": "apps/vaporgui/PDoubleInput.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n//#include \"VaporWidgetsFwd.h\"\n\nclass VLineEdit_Deprecated;\n\n//! \\class PDoubleInput\n//! Creates a Qt text input for double values synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PDoubleInput : public PLineItem {\n    Q_OBJECT\n\n    VLineEdit_Deprecated *_doubleInput;\n\npublic:\n    PDoubleInput(const std::string &tag, const std::string &label = \"\");\n\nprotected:\n    void updateGUI() const override;\n\nprivate slots:\n    void doubleInputValueChanged(const std::string &v);\n};\n"
  },
  {
    "path": "apps/vaporgui/PDoubleInputHLI.h",
    "content": "#pragma once\n\n#include \"PWidgetHLI.h\"\n#include \"PDoubleInput.h\"\n\nCreateHLI(PDoubleInput, double);\n"
  },
  {
    "path": "apps/vaporgui/PDynamicMixin.cpp",
    "content": "#include \"PDynamicMixin.h\"\n#include <vapor/VAssert.h>\n#include \"PWidget.h\"\n#include <vapor/ParamsBase.h>\n\nPWidget *PDynamicMixin::EnableDynamicUpdate(bool enabled)\n{\n    PWidget *pw = getPWidget();\n    pw->_dynamicUpdateIsOn = enabled;\n    return pw;\n}\n\nvoid PDynamicMixin::dynamicSetParamsDouble(double v)\n{\n    PWidget *pw = getPWidget();\n    if (pw->_dynamicUpdateIsOn) {\n        pw->dynamicUpdateBegin();\n        pw->_setParamsDouble(v);\n        pw->getParams()->IntermediateChange();\n    }\n}\n\nvoid PDynamicMixin::dynamicSetParamsLong(long v)\n{\n    PWidget *pw = getPWidget();\n    if (pw->_dynamicUpdateIsOn) {\n        pw->dynamicUpdateBegin();\n        pw->_setParamsLong(v);\n        pw->getParams()->IntermediateChange();\n    }\n}\n\nvoid PDynamicMixin::dynamicSetParamsString(const std::string &v)\n{\n    PWidget *pw = getPWidget();\n    if (pw->_dynamicUpdateIsOn) {\n        pw->dynamicUpdateBegin();\n        pw->_setParamsString(v);\n        pw->getParams()->IntermediateChange();\n    }\n}\n\nPWidget *PDynamicMixin::getPWidget()\n{\n    PWidget *pw = dynamic_cast<PWidget *>(this);\n    VAssert(pw != nullptr);\n    return pw;\n}\n"
  },
  {
    "path": "apps/vaporgui/PDynamicMixin.h",
    "content": "#pragma once\n\n#include <string>\nclass PWidget;\n\n//! \\class PDynamicMixin\n//! Internal class for PWidgets. Enables dynamic updating of the params database\n//! as the user edits a value through intermediate updates.\n\nclass PDynamicMixin {\npublic:\n    //! Turns on dynamic update.\n    PWidget *EnableDynamicUpdate(bool enabled=true);\n    virtual ~PDynamicMixin() = default;\n\nprotected:\n    void dynamicSetParamsDouble(double v);\n    void dynamicSetParamsLong(long v);\n    void dynamicSetParamsString(const std::string &v);\n\nprivate:\n    PWidget *getPWidget();\n};\n"
  },
  {
    "path": "apps/vaporgui/PEnumDropdown.cpp",
    "content": "#include \"PEnumDropdown.h\"\n#include <vapor/ParamsBase.h>\n#include <vapor/VAssert.h>\n#include \"VComboBox.h\"\n\nPEnumDropdownStandalone::PEnumDropdownStandalone(const std::string &tag, const std::vector<std::string> &items, const std::vector<long> &itemValues)\n: PWidget(tag, _vComboBox = new VComboBox(items)), _enumMap(itemValues)\n{\n    VAssert(itemValues.empty() || items.size() == itemValues.size());\n    connect(_vComboBox, &VComboBox::IndexChanged, this, &PEnumDropdownStandalone::dropdownIndexChanged);\n}\n\nvoid PEnumDropdownStandalone::updateGUI() const\n{\n    int value = getParamsLong();\n\n    int index = value;\n    for (int i = 0; i < _enumMap.size(); i++) {\n        if (_enumMap[i] == value) {\n            index = i;\n            break;\n        }\n    }\n\n    _vComboBox->SetIndex(index);\n}\n\nvoid PEnumDropdownStandalone::dropdownIndexChanged(int index)\n{\n    int value;\n    if (_enumMap.empty()) {\n        value = index;\n    } else {\n        VAssert(index >= 0 && index < _enumMap.size());\n        value = _enumMap[index];\n    }\n    setParamsLong(value);\n}\n\nPEnumDropdown::PEnumDropdown(const std::string &tag, const std::vector<std::string> &items, const std::vector<long> &itemValues, const std::string &label)\n: PLineItem(label, new PEnumDropdownStandalone(tag, items, itemValues)) {}\n"
  },
  {
    "path": "apps/vaporgui/PEnumDropdown.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n#include <vector>\n//#include \"VaporWidgetsFwd.h\"\n\nclass VComboBox;\n\n//! \\class PEnumDropdownStandalone\n//! Creates a Qt dropdown for selecting enum values synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PEnumDropdownStandalone : public PWidget {\n    Q_OBJECT\n    \n    VComboBox *             _vComboBox;\n    const std::vector<long> _enumMap;\n\npublic:\n    PEnumDropdownStandalone(const std::string& tag, const std::vector<std::string> &items, const std::vector<long> &itemValues = {});\n\nprotected:\n    void updateGUI() const override;\n\nprivate slots:\n    void dropdownIndexChanged(int index);\n};\n\n//! \\class PEnumDropdown\n//! Creates a Qt dropdown in a PLineItem for selecting enum values synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PEnumDropdown : public PLineItem {\n    Q_OBJECT\n\npublic:\n    //! If itemValues is empty, the item values will be initialized to the index of each item.\n    PEnumDropdown(const std::string &tag, const std::vector<std::string> &items, const std::vector<long> &itemValues = {}, const std::string &label = \"\");\n};\n"
  },
  {
    "path": "apps/vaporgui/PEnumDropdownHLI.h",
    "content": "#pragma once\n\n#include \"PWidgetHLI.h\"\n#include \"PEnumDropdown.h\"\n\ntemplate<class P> class PEnumDropdownHLI : public PEnumDropdown, public PWidgetHLIBase<P, long> {\npublic:\n    PEnumDropdownHLI(const std::string &label, const std::vector<std::string> &items, const std::vector<long> &values, typename PWidgetHLIBase<P, long>::GetterType getter,\n                     typename PWidgetHLIBase<P, long>::SetterType setter)\n    : PEnumDropdown(\"\", items, values, label), PWidgetHLIBase<P, long>((PWidget *)this, getter, setter)\n    {\n    }\n};\n"
  },
  {
    "path": "apps/vaporgui/PFidelitySection.cpp",
    "content": "#include \"PFidelitySection.h\"\n#include \"VComboBox.h\"\n#include \"PCheckbox.h\"\n#include <vapor/RenderParams.h>\n\nusing namespace VAPoR;\n\n// ==================================\n//          PFidelitySection\n// ==================================\n\nPFidelitySection::PFidelitySection() : PSection(\"Data Fidelity\")\n{\n    Add(new PQuickFidelitySelector);\n    Add(new PCheckbox(\"FidelityUseAdvanced\", \"Advanced\"));\n    Add((new PLODSelector)->EnableBasedOnParam(\"FidelityUseAdvanced\"));\n    Add((new PRefinementSelector)->EnableBasedOnParam(\"FidelityUseAdvanced\"));\n}\n\n// ==================================\n//      PQuickFidelitySelector\n// ==================================\n\nPQuickFidelitySelector::PQuickFidelitySelector() : PLineItem(\"\", \"Fidelity\", _vComboBox = new VComboBox({\"Medium\"}))\n{\n    connect(_vComboBox, &VComboBox::ValueChanged, this, &PQuickFidelitySelector::dropdownTextChanged);\n}\n\nvoid PQuickFidelitySelector::updateGUI() const\n{\n    RenderParams *rp = dynamic_cast<RenderParams *>(getParams());\n    VAssert(rp && \"Params must be RenderParams\");\n\n    auto dm = getDataMgr();\n    auto vn = rp->GetFirstVariableName();\n    int  nLod = dm->GetCRatios(vn).size();\n    int  nRef = dm->GetNumRefLevels(vn);\n    int  minOptions = vn.empty() ? 0 : max(nLod, nRef);\n\n    vector<string> items;\n    if (minOptions >= 2) items.push_back(\"Low\");\n    if (minOptions >= 3) items.push_back(\"Medium\");\n    if (minOptions >= 1)\n        items.push_back(\"High\");\n    else\n        items.push_back(\"<none>\");\n\n    _vComboBox->SetOptions(items);\n\n    int lod = rp->GetCompressionLevel();\n    int ref = rp->GetRefinementLevel();\n    int n = items.size();\n\n    _vComboBox->SetIndex(paramsToSimple(n, nLod, nRef, lod, ref));\n\n    long ts = rp->GetCurrentTimestep();\n    for (int i = 0; i < n; i++) {\n        simpleToParams(n, nLod, nRef, i, &lod, &ref);\n        bool exists = dm->VariableExists(ts, vn, 0, ref);\n        if (!exists) _vComboBox->SetItemEnabled(i, false);\n    }\n}\n\nvoid PQuickFidelitySelector::dropdownTextChanged(std::string)\n{\n    auto *rp = (RenderParams *)getParams();\n    auto  dm = getDataMgr();\n    auto  vn = rp->GetFirstVariableName();\n    int   nLod = dm->GetCRatios(vn).size();\n    int   nRef = dm->GetNumRefLevels(vn);\n    int   lod, ref;\n    simpleToParams(_vComboBox->GetCount(), nLod, nRef, _vComboBox->GetCurrentIndex(), &lod, &ref);\n\n    rp->BeginGroup(\"Change lod/cRatio\");\n    rp->SetCompressionLevel(lod);\n    rp->SetRefinementLevel(ref);\n    rp->EndGroup();\n}\n\nvoid PQuickFidelitySelector::simpleToParams(int nSimple, int nLod, int nRef, int simple, int *lod, int *ref)\n{\n    if (nSimple == 1) {\n        *lod = 0;\n        *ref = 0;\n    } else {\n        *lod = simple * (nLod - 1) / (nSimple - 1);\n        *ref = simple * (nRef - 1) / (nSimple - 1);\n    }\n}\n\nint PQuickFidelitySelector::paramsToSimple(int nSimple, int nLod, int nRef, int lod, int ref)\n{\n    int div = nLod + nRef - 2;\n    if (div == 0) return 0;\n    return (1 + lod + ref) * (nSimple - 1) / div;\n}\n\n// ==================================\n//           PLODSelector\n// ==================================\n\nPLODSelector::PLODSelector() : PLineItem(\"\", \"Level of Detail\", _vComboBox = new VComboBox({\"0 (1000:1)\"}))\n{\n    connect(_vComboBox, &VComboBox::IndexChanged, this, &PLODSelector::dropdownIndexChanged);\n}\n\nvoid PLODSelector::updateGUI() const\n{\n    RenderParams *rp = dynamic_cast<RenderParams *>(getParams());\n    VAssert(rp && \"Params must be RenderParams\");\n\n    auto varName = rp->GetFirstVariableName();\n    auto dm = getDataMgr();\n    auto cr = dm->GetCRatios(varName);\n    long timestep = rp->GetCurrentTimestep();\n\n    vector<string> items;\n    for (int i = 0; i < cr.size(); i++) items.push_back(to_string(i) + \" (\" + to_string(cr[i]) + \":1)\");\n\n    _vComboBox->SetOptions(items);\n    _vComboBox->SetIndex(rp->GetCompressionLevel());\n\n    for (int i = 0; i < cr.size(); i++) {\n        bool exists = dm->VariableExists(timestep, varName, 0, i);\n        if (!exists) _vComboBox->SetItemEnabled(i, false);\n    }\n}\n\nvoid PLODSelector::dropdownIndexChanged(int i)\n{\n    RenderParams *rp = (RenderParams *)getParams();\n    rp->SetCompressionLevel(i);\n}\n\n// ==================================\n//        PRefinementSelector\n// ==================================\n\nPRefinementSelector::PRefinementSelector() : PLineItem(\"\", \"Refinement Level\", _vComboBox = new VComboBox({\"0 (100x100x100)\"}))\n{\n    connect(_vComboBox, &VComboBox::IndexChanged, this, &PRefinementSelector::dropdownIndexChanged);\n}\n\nvoid PRefinementSelector::updateGUI() const\n{\n    RenderParams *rp = dynamic_cast<RenderParams *>(getParams());\n    VAssert(rp && \"Params must be RenderParams\");\n\n    auto varName = rp->GetFirstVariableName();\n    auto dm = getDataMgr();\n    int  nrf = dm->GetNumRefLevels(varName);\n\n    vector<string> items;\n\n    for (int i = 0; i < nrf; i++) {\n        vector<size_t> dims;\n        dm->GetDimLensAtLevel(varName, i, dims, rp->GetCurrentTimestep());\n        if (dims.empty()) continue;\n        auto   itr = dims.begin();\n        string item = to_string(i) + \" (\" + to_string(*itr++);\n        for (; itr != dims.end(); ++itr) item += \"x\" + to_string(*itr);\n        item += \")\";\n        items.push_back(item);\n    }\n\n    _vComboBox->SetOptions(items);\n    _vComboBox->SetIndex(rp->GetRefinementLevel());\n}\n\nvoid PRefinementSelector::dropdownIndexChanged(int i)\n{\n    RenderParams *rp = (RenderParams *)getParams();\n    rp->SetRefinementLevel(i);\n}\n"
  },
  {
    "path": "apps/vaporgui/PFidelitySection.h",
    "content": "#pragma once\n\n#include \"vapor/RenderParams.h\"\n\n#include \"PSection.h\"\n#include \"PLineItem.h\"\n#include \"PWidgetHLI.h\"\n\nclass VComboBox;\n\nclass PFidelitySection : public PSection {\npublic:\n    PFidelitySection();\n};\n\nclass PQuickFidelitySelector : public PLineItem {\n    Q_OBJECT\n    VComboBox *_vComboBox;\n\npublic:\n    PQuickFidelitySelector();\n\nprotected:\n    virtual void updateGUI() const override;\n    bool         requireDataMgr() const override { return true; }\n\nprivate:\n    void dropdownTextChanged(std::string);\n\n    static void simpleToParams(int nSimple, int nLod, int nRef, int simple, int *lod, int *ref);\n    static int  paramsToSimple(int nSimple, int nLod, int nRef, int lod, int ref);\n};\n\nclass PLODSelector : public PLineItem {\n    Q_OBJECT\n    VComboBox *_vComboBox;\n\npublic:\n    PLODSelector();\n\nprotected:\n    virtual void updateGUI() const override;\n    bool         requireDataMgr() const override { return true; }\n\nprivate slots:\n    void dropdownIndexChanged(int i);\n};\n\nclass PRefinementSelector : public PLineItem {\n    Q_OBJECT\n    VComboBox *_vComboBox;\n\npublic:\n    PRefinementSelector();\n\nprotected:\n    virtual void updateGUI() const override;\n    bool         requireDataMgr() const override { return true; }\n\nprivate slots:\n    void dropdownIndexChanged(int i);\n};\n"
  },
  {
    "path": "apps/vaporgui/PFileButton.cpp",
    "content": "#include \"PFileButton.h\"\n#include \"VPushButton.h\"\n#include <QFileDialog>\n#include <vapor/ParamsBase.h>\n#include <vapor/FileUtils.h>\n\nPFileButton::PFileButton(const std::string label, Callback cb) : PWidget(\"\", _button= new VPushButton(label)), _cb(cb)\n{\n    QObject::connect(_button, &VPushButton::ButtonClicked, this, &PFileButton::clicked);\n}\n\nvoid PFileButton::updateGUI() const {}\n\nPFileButton *PFileButton::SetFileTypeFilter(const std::string &filter)\n{\n    _fileTypeFilter = QString::fromStdString(filter);\n    return this;\n}\n\nvoid PFileButton::clicked()\n{\n    std::string defaultPath = Wasp::FileUtils::HomeDir();\n\n    QString qSelectedPath = selectPath(defaultPath);\n    if (qSelectedPath.isNull()) return;\n\n    _cb(qSelectedPath.toStdString());\n}\n\nbool PFileButton::requireParamsMgr() const { return false; }\n\nQString PFileWriter::selectPath(const std::string &defaultPath) const { return QFileDialog::getSaveFileName(nullptr, \"Select a file\", QString::fromStdString(defaultPath), _fileTypeFilter); }\n\nQString PFileReader::selectPath(const std::string &defaultPath) const { return QFileDialog::getOpenFileName(nullptr, \"Select a save file\", QString::fromStdString(defaultPath), _fileTypeFilter); }\n"
  },
  {
    "path": "apps/vaporgui/PFileButton.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nclass VPushButton;\nclass QString;\n\n\n//! \\class PFileButton\n//! Creates a Qt text box and select button that allows users to pick a file path synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PFileButton : public PWidget {\n    Q_OBJECT\n\nprivate:\n    typedef std::function<void(std::string)> Callback;\n    Callback _cb;\n    VPushButton* _button;\n\npublic:\n    PFileButton(const std::string label, Callback cb);\n    //! Sets the fileTypeFilter parameter in the QFileDialog popup functions.\n    PFileButton *SetFileTypeFilter(const std::string &filter);\n    //    PFileButton *UseDefaultPathSetting(const std::string &tag);\n\nprotected:\n    QString _fileTypeFilter = \"All Files (*)\";\n\n    void            updateGUI() const override;\n    bool            requireParamsMgr() const override;\n    virtual QString selectPath(const std::string &defaultPath) const = 0;\n\n//private slots:\n    void clicked();\n};\n\n//! \\class PFileOpenSelector\n//! A PFileButton that provides an Open File dialog\n//! \\copydoc PFileReader\n\nclass PFileReader : public PFileButton {\n    Q_OBJECT\npublic:\n    using PFileButton::PFileButton;\n\nprotected:\n    virtual QString selectPath(const std::string &defaultPath) const override;\n};\n\n//! \\class PFileSaveSelector\n//! A PFileButton that provides a Save File dialog\n//! \\copydoc PFileReader\n\nclass PFileWriter : public PFileButton {\n    Q_OBJECT\npublic:\n    using PFileButton::PFileButton;\n\nprotected:\n    virtual QString selectPath(const std::string &defaultPath) const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PFileSelector.cpp",
    "content": "#include \"PFileSelector.h\"\n#include \"VPushButton.h\"\n#include \"VLineEdit_Deprecated.h\"\n#include <QFileDialog>\n#include <vapor/ParamsBase.h>\n#include <vapor/FileUtils.h>\n#include <vapor/SettingsParams.h>\n\nPFileSelector::PFileSelector(const std::string &tag, const std::string &label) : PLineItem(tag, label, _pathTexbox = new VLineEdit_Deprecated, _button = new VPushButton(\"Select\"))\n{\n    _pathTexbox->SetReadOnly(true);\n    _pathTexbox->setSizePolicy(QSizePolicy::Expanding, _pathTexbox->sizePolicy().verticalPolicy());\n    connect(_button, &VPushButton::ButtonClicked, this, &PFileSelector::buttonClicked);\n}\n\nvoid PFileSelector::updateGUI() const\n{\n    const string path = getParamsString();\n    _pathTexbox->SetValue(path);\n    _pathTexbox->setToolTip(QString::fromStdString(path));\n}\n\nPFileSelector *PFileSelector::SetFileTypeFilter(const std::string &filter)\n{\n    _fileTypeFilter = QString::fromStdString(filter);\n    return this;\n}\n\n// PFileSelector *PFileSelector::UseDefaultPathSetting(const std::string &tag)\n//{\n//    _syncWithSettings = true;\n//    _syncWithSettingsTag = tag;\n//    return this;\n//}\n\nvoid PFileSelector::buttonClicked()\n{\n    string defaultPath;\n    string selectedFile = getParamsString();\n\n    if (_syncWithSettings) {\n        // Too hardcoded in settings params to bother\n    } else {\n        if (Wasp::FileUtils::Exists(selectedFile))\n            defaultPath = Wasp::FileUtils::Dirname(selectedFile);\n        else\n            defaultPath = Wasp::FileUtils::HomeDir();\n    }\n\n    QString qSelectedPath = selectPath(defaultPath);\n    if (qSelectedPath.isNull()) return;\n\n    setParamsString(qSelectedPath.toStdString());\n}\n\nbool PFileSelector::requireParamsMgr() const { return _syncWithSettings; }\n\nQString PFileOpenSelector::selectPath(const std::string &defaultPath) const { return QFileDialog::getOpenFileName(nullptr, \"Select a file\", QString::fromStdString(defaultPath), _fileTypeFilter); }\n\nQString PFileSaveSelector::selectPath(const std::string &defaultPath) const { return QFileDialog::getSaveFileName(nullptr, \"Select save file\", QString::fromStdString(defaultPath), _fileTypeFilter); }\n\nQString PDirectorySelector::selectPath(const std::string &defaultPath) const { return QFileDialog::getExistingDirectory(nullptr, \"Select a directory\", QString::fromStdString(defaultPath)); }\n"
  },
  {
    "path": "apps/vaporgui/PFileSelector.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n\nclass VPushButton;\nclass VLineEdit_Deprecated;\nclass QString;\n\n//! \\class PFileSelector\n//! Creates a Qt text box and select button that allows users to pick a file path synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PFileSelector : public PLineItem {\n    Q_OBJECT\n\n    VPushButton *         _button;\n    VLineEdit_Deprecated *_pathTexbox;\n\n    bool        _syncWithSettings = false;\n    std::string _syncWithSettingsTag;\n\npublic:\n    PFileSelector(const std::string &tag, const std::string &label = \"\");\n    //! Sets the fileTypeFilter parameter in the QFileDialog popup functions.\n    PFileSelector *SetFileTypeFilter(const std::string &filter);\n    //    PFileSelector *UseDefaultPathSetting(const std::string &tag);\n\nprotected:\n    QString _fileTypeFilter = \"All Files (*)\";\n\n    void            updateGUI() const override;\n    bool            requireParamsMgr() const override;\n    virtual QString selectPath(const std::string &defaultPath) const = 0;\n\nprivate slots:\n    void buttonClicked();\n};\n\n//! \\class PFileOpenSelector\n//! A PFileSelector that provides an Open File dialog\n//! \\copydoc PFileSelector\n\nclass PFileOpenSelector : public PFileSelector {\n    Q_OBJECT\npublic:\n    using PFileSelector::PFileSelector;\n\nprotected:\n    virtual QString selectPath(const std::string &defaultPath) const override;\n};\n\n//! \\class PFileSaveSelector\n//! A PFileSelector that provides a Save File dialog\n//! \\copydoc PFileSelector\n\nclass PFileSaveSelector : public PFileSelector {\n    Q_OBJECT\npublic:\n    using PFileSelector::PFileSelector;\n\nprotected:\n    virtual QString selectPath(const std::string &defaultPath) const override;\n};\n\n//! \\class PDirectorySelector\n//! A PFileSelector that provides a  Select Directory dialog\n//! \\copydoc PFileSelector\n\nclass PDirectorySelector : public PFileSelector {\n    Q_OBJECT\npublic:\n    using PFileSelector::PFileSelector;\n    PFileSelector *SetFileTypeFilter(const std::string &filter) = delete;\n\nprotected:\n    virtual QString selectPath(const std::string &defaultPath) const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PFileSelectorHLI.h",
    "content": "#pragma once\n\n#include \"PFileSelector.h\"\n#include \"PWidgetHLI.h\"\n\nCreateHLI(PFileOpenSelector, std::string);\nCreateHLI(PFileSaveSelector, std::string);\nCreateHLI(PDirectorySelector, std::string);\n"
  },
  {
    "path": "apps/vaporgui/PFlowIntegrationRegionSelector.cpp",
    "content": "#include \"PFlowIntegrationRegionSelector.h\"\n#include <vapor/FlowParams.h>\n\nusing VAPoR::FlowParams;\n\nVAPoR::Box *PFlowIntegrationRegionSelector1D::getBox() const { return getParams<FlowParams>()->GetIntegrationBox(); }\n"
  },
  {
    "path": "apps/vaporgui/PFlowIntegrationRegionSelector.h",
    "content": "#pragma once\n\n#include \"PRegionSelector.h\"\n\nclass PFlowIntegrationRegionSelector1D : public PRegionSelector1D {\npublic:\n    using PRegionSelector1D::PRegionSelector1D;\n\nprotected:\n    VAPoR::Box *getBox() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PFlowRakeRegionSelector.cpp",
    "content": "#include \"PFlowRakeRegionSelector.h\"\n#include <vapor/FlowParams.h>\n\nusing VAPoR::FlowParams;\n\nVAPoR::Box *PFlowRakeRegionSelector1D::getBox() const { return getParams<FlowParams>()->GetRakeBox(); }\n"
  },
  {
    "path": "apps/vaporgui/PFlowRakeRegionSelector.h",
    "content": "#pragma once\n\n#include \"PRegionSelector.h\"\n\nclass PFlowRakeRegionSelector1D : public PRegionSelector1D {\npublic:\n    using PRegionSelector1D::PRegionSelector1D;\n\nprotected:\n    VAPoR::Box *getBox() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PGeometrySubtab.cpp",
    "content": "#include \"PGeometrySubtab.h\"\n#include \"PRegionSelector.h\"\n#include \"PCopyRegionWidget.h\"\n#include \"PTransformWidget.h\"\n\nPGeometrySubtab::PGeometrySubtab() : PGroup({new PRegionSelector, new PCopyRegionWidget, new PRendererTransformSection}) {}\n"
  },
  {
    "path": "apps/vaporgui/PGeometrySubtab.h",
    "content": "#pragma once\n\n#include \"PGroup.h\"\n\nclass PGeometrySubtab : public PGroup {\npublic:\n    PGeometrySubtab();\n};\n"
  },
  {
    "path": "apps/vaporgui/PGroup.cpp",
    "content": "#include \"PGroup.h\"\n#include <vapor/ParamsBase.h>\n#include <QVBoxLayout>\n#include \"VGroup.h\"\n\nPGroup::PGroup() : PGroup(new VGroup()) {}\n\nPGroup::PGroup(const List &widgets) : PGroup() { AddM(widgets); }\n\nPGroup::PGroup(VGroup *w) : PWidget(\"\", _widget = w), WidgetGroupWrapper(w) {}\n\nvoid PGroup::updateGUI() const\n{\n    auto params = getParams();\n    auto paramsMgr = getParamsMgr();\n    auto dataMgr = getDataMgr();\n\n    for (PWidget *child : _children) child->Update(params, paramsMgr, dataMgr);\n}\n\nPSubGroup::PSubGroup() : PGroup(new VSubGroup()) {}\n\nPSubGroup::PSubGroup(const List &widgets) : PSubGroup() { AddM(widgets); }\n"
  },
  {
    "path": "apps/vaporgui/PGroup.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n#include \"AbstractWidgetGroup.h\"\n#include <vector>\n#include \"VGroup.h\"\n\nclass VGroup;\n\n//! \\class PGroup\n//! Groups together PWidgets. See ParamsWidgetDemo for example use cases.\n//! \\copydoc PWidget\n\nclass PGroup : public PWidget, public WidgetGroupWrapper<PGroup, PWidget, VGroup> {\n    Q_OBJECT\n\n    VGroup *_widget;\n\npublic:\n    PGroup();\n    PGroup(const List &widgets);\n\nprotected:\n    PGroup(VGroup *w);\n    void updateGUI() const override;\n};\n\n//! \\class PSubGroup\n//! Groups together PWidgets in a subgroup.\n//! \\copydoc PGroup\n\nclass PSubGroup : public PGroup {\n    Q_OBJECT\n\npublic:\n    PSubGroup();\n    PSubGroup(const List &widgets);\n};\n"
  },
  {
    "path": "apps/vaporgui/PImportDataButton.cpp",
    "content": "#include \"PImportDataButton.h\"\n#include \"DatasetImportController.h\"\n#include \"VHBoxWidget.h\"\n#include \"VLabel.h\"\n#include \"DatasetTypeLookup.h\"\n#include \"vapor/ControlExecutive.h\"\n#include \"vapor/GUIStateParams.h\"\n#include \"vapor/FileUtils.h\"\n\n#include <QFileDialog>\n#include <QPushButton>\n\nPImportDataButton::PImportDataButton(VAPoR::ControlExec* ce, DatasetImportController *datasetImportController) : PWidget(\"\", _hBox = new VHBoxWidget()), _ce(ce), _datasetImportController(datasetImportController) {\n    _hBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);\n\n    QHBoxLayout* layout = qobject_cast<QHBoxLayout*>(_hBox->layout());\n\n    QPushButton *button = new QPushButton(\"Select File(s)\", this);\n    connect(button, &QPushButton::clicked, this, &PImportDataButton::_importDataset);\n    layout->addWidget(button, 1);\n    layout->addWidget(_fileLabel = new VLabel(\"\"),3);\n\n    _fileLabel->MakeSelectable();\n}\n\nvoid PImportDataButton::_importDataset() {\n    GUIStateParams* gsp = dynamic_cast<GUIStateParams *>(getParams());\n    std::vector<std::string> dataSetNames = gsp->GetOpenDataSetNames();\n    std::string defaultPath = dataSetNames.size() ? gsp->GetOpenDataSetPaths(dataSetNames.back())[0] : FileUtils::HomeDir();\n    \n    QStringList qfileNames = QFileDialog::getOpenFileNames(this, \"Select Filename Prefix\", QString::fromStdString(defaultPath));\n    std::vector<std::string> fileNames;\n    for (const QString &qStr : qfileNames) fileNames.push_back(qStr.toStdString());\n    if (fileNames.empty()) return;\n\n    std::string format = GetDatasets()[getParams()->GetValueLong(GUIStateParams::ImportDataTypeTag, 0)].first;\n    _datasetImportController->ImportDataset(_ce, fileNames, format, DatasetImportController::DatasetExistsAction::Prompt);\n}\n\nvoid PImportDataButton::updateGUI() const {\n    GUIStateParams* gsp = dynamic_cast<GUIStateParams *>(getParams());\n\n    std::vector<std::string> dataSetNames = gsp->GetOpenDataSetNames();\n    if (!dataSetNames.size()) {\n        _fileLabel->SetText(\"\");\n        return;\n    }\n\n    std::vector<std::string> paths = gsp->GetOpenDataSetPaths(dataSetNames[0]);\n    int count = paths.size();\n\n    if (count > 0) {\n        std::string dir = FileUtils::Dirname(paths[0]);\n        _fileLabel->SetText(\"Imported: \" + std::to_string(count) + \" file(s)\\nFrom: \" + dir);\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/PImportDataButton.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n\nnamespace VAPoR {\n    class ControlExec;\n}\n\nclass DatasetImportController;\nclass VHBoxWidget;\nclass VLabel;\nclass PButton;\n\nclass PImportDataButton : public PWidget {\n    Q_OBJECT\n\n    VAPoR::ControlExec *_ce;\n    DatasetImportController *_datasetImportController;\n    VHBoxWidget *_hBox;\n    VLabel *_fileLabel;\n    PButton *_importButton;\n\n    void _importDataset();\n\npublic:\n    PImportDataButton(VAPoR::ControlExec* ce, DatasetImportController *datasetImportController);\n\nprotected:\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PImportDataWidget.cpp",
    "content": "#include \"DatasetTypeLookup.h\"\n#include \"DatasetImportController.h\"\n#include \"PImportDataWidget.h\"\n#include \"PImportDataButton.h\"\n#include \"PRadioButtons.h\"\n#include \"PGroup.h\"\n\n#include \"vapor/ControlExecutive.h\"\n#include \"vapor/GUIStateParams.h\"\n\nPImportDataWidget::PImportDataWidget(VAPoR::ControlExec* ce, DatasetImportController *datasetImportController) : PGroup() {\n    std::vector<std::string> types = GetDatasetTypeDescriptions();\n    PRadioButtons* prb = new PRadioButtons(GUIStateParams::ImportDataTypeTag, types);\n    Add(prb);\n    \n    Add(new PImportDataButton(ce, datasetImportController));\n}\n"
  },
  {
    "path": "apps/vaporgui/PImportDataWidget.h",
    "content": "#pragma once\n\n#include \"PGroup.h\"\n#include \"PSection.h\"\n#include \"PLineItem.h\"\n\nnamespace VAPoR {\n    class ControlExec;\n}\n\nclass DatasetImportController;\n\nclass PImportDataWidget : public PGroup {\n    Q_OBJECT\n\npublic:\n    PImportDataWidget(VAPoR::ControlExec* ce, DatasetImportController *datasetImportController);\n};\n"
  },
  {
    "path": "apps/vaporgui/PIntegerInput.cpp",
    "content": "#include <iostream>\n#include \"PIntegerInput.h\"\n#include \"VLineItem.h\"\n#include <vapor/ParamsBase.h>\n#include \"VIntSpinBox.h\"\n\nPIntegerInput::PIntegerInput(const std::string &tag, const std::string &label) : PLineItem(tag, label, _spinbox = new VIntSpinBox(INT_MIN, INT_MAX))\n{\n    connect(_spinbox, &VIntSpinBox::ValueChanged, this, &PIntegerInput::spinboxValueChanged);\n    connect(_spinbox, &VIntSpinBox::ValueChangedIntermediate, this, &PIntegerInput::valueChangedIntermediate);\n}\n\nPIntegerInput *PIntegerInput::SetRange(int min, int max)\n{\n    _spinbox->SetRange(min, max);\n    return this;\n}\n\nvoid PIntegerInput::updateGUI() const\n{\n    int value = getParamsLong();\n    _spinbox->SetValue(value);\n}\n\nvoid PIntegerInput::spinboxValueChanged(int i) { setParamsLong(i); }\n\nvoid PIntegerInput::valueChangedIntermediate(int v) { dynamicSetParamsLong(v); }\n"
  },
  {
    "path": "apps/vaporgui/PIntegerInput.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n#include \"PDynamicMixin.h\"\n\nclass VIntSpinBox;\n\n//! \\class PIntegerInput\n//! Creates a Qt text input for double values using a spinbox synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PIntegerInput : public PLineItem, public PDynamicMixin {\n    Q_OBJECT\n\n    VIntSpinBox *_spinbox;\n\npublic:\n    PIntegerInput(const std::string &tag, const std::string &label = \"\");\n    //! @copydoc VIntSpinBox::SetRange\n    PIntegerInput *SetRange(int min, int max);\n\nprotected:\n    void updateGUI() const override;\n\nprivate slots:\n    void spinboxValueChanged(int i);\n    void valueChangedIntermediate(int i);\n};\n"
  },
  {
    "path": "apps/vaporgui/PIntegerInputHLI.h",
    "content": "#pragma once\n\n#include \"PWidgetHLI.h\"\n#include \"PIntegerInput.h\"\n\nCreateHLI(PIntegerInput, long);\n"
  },
  {
    "path": "apps/vaporgui/PLabel.cpp",
    "content": "#include \"PLabel.h\"\n#include \"VLabel.h\"\n\nPLabel::PLabel(const std::string &text) : PWidget(\"\", _label = new VLabel(text)) {}\n"
  },
  {
    "path": "apps/vaporgui/PLabel.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nclass VLabel;\n\n//! \\class PLabel\n//! \\brief Displays static text.\n//! \\author Stas Jaroszynski\n\nclass PLabel : public PWidget {\n    VLabel *_label;\n\npublic:\n    PLabel(const std::string &text);\n    void updateGUI() const override {}\n};\n"
  },
  {
    "path": "apps/vaporgui/PLineItem.cpp",
    "content": "#include \"PLineItem.h\"\n#include \"VLineItem.h\"\n#include <cassert>\n\nPLineItem::PLineItem(const std::string &tag, const std::string &label, QWidget *centerWidget, QWidget *rightWidget)\n: PWidget(tag, new VLineItem(label.empty() ? tag : label, centerWidget, rightWidget))\n{\n}\n\nPLineItem::PLineItem(const std::string &tag, const std::string &label, QWidget *rightWidget) : PWidget(tag, new VLineItem(label.empty() ? tag : label, rightWidget)) {}\n\nPLineItem::PLineItem(const std::string &label, PWidget *rightWidget) : PLineItem(\"\", label, rightWidget) { _child = rightWidget; }\n\nvoid PLineItem::updateGUI() const\n{\n    assert(_child);\n    _child->Update(getParams(), getParamsMgr(), getDataMgr());\n}\n"
  },
  {
    "path": "apps/vaporgui/PLineItem.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\n//! \\class PLineItem\n//! Internal PWidget class. Standardizes PWidgets that take up a single line with a label, spacer, input.\n//! \\copydoc PWidget\n\nclass PLineItem : public PWidget {\n    Q_OBJECT\n    PWidget *_child = nullptr;\n\npublic:\n    PLineItem(const std::string &tag, const std::string &label, QWidget *centerWidget, QWidget *rightWidget);\n    PLineItem(const std::string &tag, const std::string &label, QWidget *rightWidget);\n    PLineItem(const std::string &label, PWidget *rightWidget);\n\nprotected:\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PMetadataClasses.cpp",
    "content": "#include <QTreeWidget>\n#include <QHeaderView>\n#include <sstream>\n\n#include \"ErrorReporter.h\"\n#include \"PMetadataClasses.h\"\n#include \"PSection.h\"\n#include \"PStringDropdown.h\"\n#include \"PSliderEdit.h\"\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n#include <vapor/DC.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/GUIStateParams.h>\n#include <vapor/STLUtils.h>\n\nnamespace {\n    std::vector<std::string> xtypeLookup = { \"INVALID\", \"FLOAT\", \"DOUBLE\", \"UINT8\", \"INT8\", \"INT32\", \"INT64\", \"TEXT\" };\n    std::vector<std::string> axisLookup  = { \"X\", \"Y\", \"Z\", \"T\"};\n}\n\nconst std::string PMetadataSection::SelectedDatasetTag  = \"metadataDatasetTag\";\nconst std::string PMetadataSection::MetadataTimestepTag = \"metadataTimestepTag\";\n\nPOpenVariableMetadataWidget::POpenVariableMetadataWidget()\n: PWidget(\"\", _varTree = new VOpenVariableMetadataTree())\n{}\n\nvoid POpenVariableMetadataWidget::updateGUI() const {\n    _varTree->Update(getParams(),nullptr,getDataMgr());\n}\n\nPMetadataSection::PMetadataSection(VAPoR::ControlExec* ce)\n: PWidget(\"\", _section = new VSectionGroup(\"Dataset Metadata\",\n                                           {\n                                                _metadataDataset = new PStringDropdown(SelectedDatasetTag, {}, \"Dataset\"),\n                                                (_metadataTimestep = new PIntegerSliderEdit(MetadataTimestepTag, \"Generate metadata\\nfor timestep #\"))->AllowUserRange(false),\n                                                _dimTree = new VDimensionMetadataTree(),\n                                                _varTree = new VVariableMetadataTree(),\n                                                _coordTree = new VCoordinateVariableMetadataTree(),\n                                                _globalTree = new VGlobalAttributeMetadataTree(),\n                                            })\n) {\n    VAssert(ce != nullptr);\n    _ce = ce;\n\n    connect(_varTree, &VVariableMetadataTree::_timestepRejected, this, &PMetadataSection::updateGUI);\n}\n\nvoid PMetadataSection::updateGUI() const {\n\n    VAPoR::ParamsMgr *      pm = _ce->GetParamsMgr();\n    auto                    stateParams = ((GUIStateParams*)pm->GetParams(GUIStateParams::GetClassType()));\n    auto                    activeViz = stateParams->GetActiveVizName();\n    VAPoR::ViewpointParams *vp = pm->GetViewpointParams(activeViz);\n    if (!vp) return;\n\n    VAPoR::DataStatus *   dataStatus = _ce->GetDataStatus();\n    vector<string> datasets = dataStatus->GetDataMgrNames();\n    if (datasets.empty()) {\n        _metadataDataset->setEnabled(false);\n        _metadataTimestep->setEnabled(false);\n        _varTree->setEnabled(false);\n        _coordTree->setEnabled(false);\n        return;\n    } else {\n        _metadataDataset->setEnabled(true);\n        _metadataTimestep->setEnabled(true);\n        _varTree->setEnabled(true);\n        _coordTree->setEnabled(true);\n    }\n\n    _metadataDataset->SetItems(datasets);\n    _metadataDataset->SetItems(datasets);\n    _metadataDataset->Update(vp);\n\n    VAPoR::DataMgr* dm;\n    string dataset = vp->GetValueString(SelectedDatasetTag, datasets[0]);\n    if (!STLUtils::Contains(datasets, dataset)) dataset = datasets[0];\n    dm = _ce->GetDataStatus()->GetDataMgr(dataset);\n\n    _dimTree->Update(getParams(), nullptr, dm);\n    _varTree->Update(getParams(), nullptr, dm);\n    _coordTree->Update(getParams(), nullptr, dm);\n    _globalTree->Update(getParams(), nullptr, dm);\n    \n    _metadataTimestep->SetRange(0,dm->GetNumTimeSteps()-1);\n    _metadataTimestep->Update(getParams());\n}\n\nVMetadataTree::VMetadataTree()\n: VSectionGroup(\"\"), ParamsUpdatable(),\n  _tree(new QTreeWidget),\n  _dm(nullptr),\n  _ts(-1),\n  _topLevelBranches({})\n{\n    _group->AddM({_tree});\n    _tree->setHeaderHidden(true);\n    _tree->header()->setStretchLastSection(false);\n    _tree->setColumnCount(2);\n    _tree->header()->setSectionResizeMode(QHeaderView::ResizeToContents);\n\n    connect(_tree, &QTreeWidget::itemExpanded, this, &VMetadataTree::_generateMetadata);\n}\n\nvoid VMetadataTree::Update(VAPoR::ParamsBase* p, VAPoR::ParamsMgr* pm, VAPoR::DataMgr* dm) {\n    // Check if we need to update our tree.\n    // Note: This function also generates the _topLevelBranches variable list, who's metadata will be shown.\n    if (!_checkNeedUpdate(p, dm)) return;\n\n    QStringList qbranches;\n    for (auto branch : _topLevelBranches)\n        qbranches << QString::fromStdString(branch);\n    qbranches.removeDuplicates();\n    qbranches.removeAll(QString(\"\"));\n\n    _tree->clear();\n    for (auto qbranch : qbranches){\n        QTreeWidgetItem* varItem = new QTreeWidgetItem(_tree, {qbranch});\n        // Add a blank \"leaf\" on each branch so they can be expanded (and therefore populated)\n        QTreeWidgetItem* leaf = new QTreeWidgetItem(varItem, {\"\"});\n        (void)leaf; // Silence unused variable warning\n        _tree->insertTopLevelItem(0,varItem);\n    }\n}\n\nvoid VVariableMetadataTree::_generateMetadata(QTreeWidgetItem* item) const {\n    if (item->childCount() > 1) return; // This branch contains more than an empty leaf, and has already been computed\n\n    QTreeWidgetItem* leaf = item->takeChild(0);\n    if (leaf != 0) delete leaf;\n\n    QString qvar = item->text(0);\n    std::vector<double> range;\n    int rc = _dm->GetDataRange(_ts, qvar.toStdString(), -1, -1, range);\n    if (rc < 0) return;\n\n    QTreeWidgetItem* varItem = item;\n\n    new QTreeWidgetItem(varItem, {\"Min:\", QString::number(range[0])});\n    new QTreeWidgetItem(varItem, {\"Max:\", QString::number(range[1])});\n\n    std::vector<size_t> dims;\n    _dm->GetDimLensAtLevel(qvar.toStdString(), -1, dims, _ts);\n    QString qDims = QString::number(dims[0]);\n    if (dims.size()>1) \n        qDims = qDims + \":\" + QString::number(dims[1]);\n    if (dims.size()>2) \n        qDims = qDims + \":\" + QString::number(dims[2]);\n    new QTreeWidgetItem(varItem, {\"Dims (XYZ):\", qDims});\n\n    VAPoR::DC::Mesh mesh;\n    QTreeWidgetItem* coords = new QTreeWidgetItem(varItem, {\"Coordinates\"});\n\n    VAPoR::DC::DataVar dataVar;\n    _dm->GetDataVarInfo(qvar.toStdString(), dataVar);\n    _dm->GetMesh(dataVar.GetMeshName(), mesh);\n    std::vector<std::string> coordVars = mesh.GetCoordVars();\n    QStringList qCoordVars;\n    for (auto coordVar : coordVars)\n        qCoordVars << QString::fromStdString(coordVar);\n    qCoordVars.removeDuplicates();\n    qCoordVars.removeAll(QString(\"\"));\n    for (auto qCoordVar : qCoordVars )\n        _generateCoordVarInfo(coords, qCoordVar);\n\n    _generateAttributeInfo(varItem, dataVar);\n}\n\nbool VMetadataTree::_checkNeedUpdate(VAPoR::ParamsBase* p, VAPoR::DataMgr* dm) {\n    bool needsUpdate = false;\n   \n    if (dm != _dm ) {\n        _dm = dm;\n        needsUpdate = true;\n    }\n    \n    VAPoR::RenderParams* rp = dynamic_cast<VAPoR::RenderParams*>(p);\n    size_t ts;\n    if (rp != nullptr) {\n        ts = rp->GetCurrentTimestep();\n    }\n    else {\n        ts = p->GetValueLong(PMetadataSection::MetadataTimestepTag, 0);\n    }\n    if (ts != _ts ) {\n        _ts=ts;\n        needsUpdate = true;\n    }\n    if (ts > _dm->GetNumTimeSteps()-1) {\n        _ts = _dm->GetNumTimeSteps()-1;\n        needsUpdate = true;\n    }\n    \n    std::vector<std::string> topLevelBranches;\n    _gatherBranches(topLevelBranches, p);\n\n    // Sort branches alphabetically\n    std::sort(\n        topLevelBranches.begin(), \n        topLevelBranches.end(), \n        [](const std::string& a, const std::string& b) -> bool { return a<b; }\n    );\n\n    if (topLevelBranches!= _topLevelBranches) {\n        _topLevelBranches = topLevelBranches;\n        needsUpdate = true;\n    }\n  \n    return needsUpdate;\n}\n\nvoid VVariableMetadataTree::_generateCoordVarInfo(QTreeWidgetItem* parent, const QString& qCoordVar) const {\n    VAPoR::DC::CoordVar coordVar;\n    if (!_dm->GetCoordVarInfo(qCoordVar.toStdString(), coordVar)) return;\n\n    QTreeWidgetItem* coordItem;\n    if (parent->text(0) == qCoordVar)\n        coordItem = parent;\n    else\n        coordItem = new QTreeWidgetItem(parent, {qCoordVar});\n\n    std::vector<std::string> dimNames = coordVar.GetDimNames();\n    QString qDimNames;\n    for (auto dimName : dimNames)\n        qDimNames += QString::fromStdString(dimName) + \" \";\n    new QTreeWidgetItem(coordItem, {\"Dimension name(s):\", qDimNames});\n    \n    std::vector<size_t> dims = {1};\n    _dm->GetDimLensAtLevel(qCoordVar.toStdString(), -1, dims, _ts);\n    QString qDims = QString::number(dims[0]);\n    if (dims.size()>1) \n        qDims = qDims + \":\" + QString::number(dims[1]);\n    if (dims.size()>2) \n        qDims = qDims + \":\" + QString::number(dims[2]);\n    new QTreeWidgetItem(coordItem, {\"Dimension size(s):\", qDims});\n\n    new QTreeWidgetItem(coordItem, {\"Unit:\", QString::fromStdString(coordVar.GetUnits())});\n    new QTreeWidgetItem(coordItem, {\"Axis:\", QString::fromStdString(axisLookup[coordVar.GetAxis()])});\n    new QTreeWidgetItem(coordItem, {\"Time dim:\", QString::fromStdString(coordVar.GetTimeDimName())});\n    new QTreeWidgetItem(coordItem, {\"Data type:\", QString::fromStdString(xtypeLookup[coordVar.GetXType()+1])});\n    new QTreeWidgetItem(coordItem, {\"Uniform sampling:\", QVariant(coordVar.GetUniform()).toString()});\n}\n\nvoid VVariableMetadataTree::_generateAttributeInfo(QTreeWidgetItem* parent, const VAPoR::DC::BaseVar baseVar) const {\n    QTreeWidgetItem* attrs = new QTreeWidgetItem(parent, {\"Attributes\"});\n    std::map<std::string, VAPoR::DC::Attribute> attributes = baseVar.GetAttributes();\n    std::map<std::string, VAPoR::DC::Attribute>::iterator it;\n    std::stringstream s;\n    for(auto const& attribute : attributes) {\n        s.str(std::string());\n        VAPoR::DC::XType xType = attribute.second.GetXType();\n        if ( xType == VAPoR::DC::XType::INVALID ) continue;\n        else if ( xType == VAPoR::DC::XType::TEXT ) {\n            std::string values;\n            attribute.second.GetValues(values);\n            s.str(values);\n        }\n        else if (xType == VAPoR::DC::XType::FLOAT ||\n                 xType == VAPoR::DC::XType::DOUBLE ) {\n            std::vector<double> values;\n            attribute.second.GetValues(values);\n            copy(values.begin(), values.end(), ostream_iterator<int>(s,\" \"));\n        }\n        else {\n            std::vector<long> values;\n            attribute.second.GetValues(values);\n            copy(values.begin(), values.end(), ostream_iterator<int>(s,\" \"));\n        }\n            \n        new QTreeWidgetItem(attrs, {QString::fromStdString(attribute.first), QString::fromStdString(s.str())});\n    }\n}\n\nVOpenVariableMetadataTree::VOpenVariableMetadataTree() : VVariableMetadataTree() {\n    setTabText(0,\"Open Variable Metadata\");\n}\n\nvoid VOpenVariableMetadataTree::_gatherBranches(std::vector<std::string> &vars, VAPoR::ParamsBase* p) const {\n    VAPoR::RenderParams* rp = dynamic_cast<VAPoR::RenderParams*>(p);\n    vars.clear();\n    vars.push_back( rp->GetVariableName() );\n    vars.push_back( rp->GetXFieldVariableName() );\n    vars.push_back( rp->GetYFieldVariableName() );\n    vars.push_back( rp->GetZFieldVariableName() );\n    vars.push_back( rp->GetHeightVariableName() );\n    vars.push_back( rp->GetColorMapVariableName() );\n    std::vector<std::string> auxs = rp->GetAuxVariableNames();\n    vars.insert(vars.end(), auxs.begin(), auxs.end());\n}\n\nVVariableMetadataTree::VVariableMetadataTree() : VMetadataTree() {\n    setTabText(0,\"Variable Metadata\");\n}\n\nvoid VVariableMetadataTree::_gatherBranches(std::vector<std::string> &vars, VAPoR::ParamsBase* p /*unused*/) const {\n    vars.clear();\n    std::vector<std::string> v = _dm->GetDataVarNames();\n    vars.insert(vars.end(),v.begin(),v.end());\n}\n\nVCoordinateVariableMetadataTree::VCoordinateVariableMetadataTree() : VVariableMetadataTree() {\n    setTabText(0,\"Coordinate Variable Metadata\");\n}\n\nvoid VCoordinateVariableMetadataTree::_generateMetadata(QTreeWidgetItem* item) const {\n    if (item->childCount() > 1) return; // This branch has already been computed\n    QTreeWidgetItem* leaf = item->takeChild(0);\n    if (leaf != 0) delete leaf;\n    QString qvar = item->text(0);\n    _generateCoordVarInfo(item, qvar);\n}\n\nvoid VCoordinateVariableMetadataTree::_gatherBranches(std::vector<std::string> &vars, VAPoR::ParamsBase* p /*unused*/) const {\n    vars.clear();\n    std::vector<std::string> v = _dm->GetCoordVarNames();\n    vars.insert(vars.end(),v.begin(),v.end());\n}\n\nVGlobalAttributeMetadataTree::VGlobalAttributeMetadataTree() : VMetadataTree() {\n    setTabText(0,\"Global Attributes\");\n}\n\nvoid VGlobalAttributeMetadataTree::_generateMetadata(QTreeWidgetItem* item) const {\n    if (item->childCount() > 1) return; // This branch contains more than an empty leaf, and has already been computed\n\n    QTreeWidgetItem* leaf = item->takeChild(0);\n    if (leaf != 0) delete leaf;\n\n    QString qattribute = item->text(0);\n\n    VAPoR::DC::XType xType = _dm->GetAttType(\"\",qattribute.toStdString());\n    QString qvalue;\n    if (xType == VAPoR::DC::XType::INVALID) {\n        return;\n    }\n    if (xType == VAPoR::DC::XType::TEXT) {\n        std::string values;\n        if (!_dm->GetAtt(\"\", qattribute.toStdString(), values)) return;\n        qvalue = QString::fromStdString(values);\n    }\n    else if (xType == VAPoR::DC::XType::FLOAT ||\n        xType == VAPoR::DC::XType::DOUBLE ) {\n        std::vector<double> values;\n        if (!_dm->GetAtt(\"\", qattribute.toStdString(), values)) return;\n        for (auto value : values)\n            qvalue += QString::number(value) + \" \";\n    }\n    else {  // UINT8, INT8, INT32, INT64\n        std::vector<long> values;\n        if (!_dm->GetAtt(\"\", qattribute.toStdString(), values)) return;\n        for (auto value : values)\n            qvalue += QString::number(value) + \" \";\n    }\n\n    new QTreeWidgetItem(item, {\"Value:\", qvalue});\n    new QTreeWidgetItem(item, {\"Type:\", QString::fromStdString(xtypeLookup[_dm->GetAttType(\"\",qattribute.toStdString())+1])});\n}\n\nvoid VGlobalAttributeMetadataTree::_gatherBranches(std::vector<std::string> &vars, VAPoR::ParamsBase* p /*unused*/) const {\n    vars.clear();\n    std::vector<std::string> v = _dm->GetAttNames(\"\");\n    vars.insert(vars.end(),v.begin(),v.end());\n}\n\nVDimensionMetadataTree::VDimensionMetadataTree() : VMetadataTree() {\n    setTabText(0,\"Dimension Metadata\");\n}\n\nvoid VDimensionMetadataTree::_generateMetadata(QTreeWidgetItem* item) const {\n    if (item->childCount() > 1) return; // This branch contains more than an empty leaf, and has already been computed\n    QTreeWidgetItem* leaf = item->takeChild(0);\n    if (leaf != 0) delete leaf;\n\n    VAPoR::DC::Dimension dim;\n    _dm->GetDimension(item->text(0).toStdString(), dim, _ts);\n\n    new QTreeWidgetItem(item, {\"Length:\", QString::number(dim.GetLength())});\n    new QTreeWidgetItem(item, {\"Is time varying:\", QVariant(dim.IsTimeVarying()).toString()});\n\n    /*std::vector<size_t> dims;\n    _dm->GetDimLens(item->text(0).toStdString(), dims, _ts);\n\n    QString dimLens;\n    if (dims.size())\n        dimLens = \" = \" + QString::number(dims[0]);\n    else if (item->text(0).toStdString() == \"Time\" || item->text(0).toStdString() == \"time\")\n        dimLens = \" = UNLIMITED\";\n\n    item->setText(1,dimLens);*/\n}\n\nvoid VDimensionMetadataTree::_gatherBranches(std::vector<std::string> &dims, VAPoR::ParamsBase* p /*unused*/) const {\n    dims.clear();\n    std::vector<std::string> d = _dm->GetDimensionNames();\n    dims.insert(dims.end(),d.begin(),d.end());\n}\n"
  },
  {
    "path": "apps/vaporgui/PMetadataClasses.h",
    "content": "#pragma once\n\n#include \"PSection.h\"\n#include \"VContainer.h\"\n#include \"VSection.h\"\n#include <vapor/DC.h>\n\nclass QTreeWidget;\nclass QTreeWidgetItem;\nclass PStringDropdown;\nclass PIntegerSliderEdit;\nclass VDimensionMetadataTree;\nclass VVariableMetadataTree;\nclass VOpenVariableMetadataTree;\nclass VCoordinateVariableMetadataTree;\nclass VGlobalAttributeMetadataTree;\n\nnamespace VAPoR {\n    class ControlExec;\n    class RenderParams;\n    class DataMgr;\n}\n\n//! \\class POpenVariableMetadataWidget\n//! Allows the user view variable metadata that is currently\n//! in use by an instantiated renderer.\nclass POpenVariableMetadataWidget : public PWidget {\n    Q_OBJECT\n\n    VOpenVariableMetadataTree*    _varTree;\n\npublic:\n    POpenVariableMetadataWidget();\n\nprotected:\n    bool requireDataMgr() const override { return true; }\n    void updateGUI() const override;\n};\n\n//! \\class PMetadataSection\n//! Allows the user view all variable metadata that is in the\n//! dataset selected by a drop-down menu.  It also displays\n//! coordinate variable metadata and global attributes for the\n//! given dataset, at the given timestep.\nclass PMetadataSection : public PWidget {\n    Q_OBJECT\n\n    VAPoR::ControlExec*              _ce;\n    VSection*                        _section;\n    VDimensionMetadataTree*          _dimTree;\n    VVariableMetadataTree*           _varTree;\n    VCoordinateVariableMetadataTree* _coordTree;\n    VGlobalAttributeMetadataTree*    _globalTree;\n    PStringDropdown*                 _metadataDataset;\n    PIntegerSliderEdit*              _metadataTimestep;\n\npublic:\n    PMetadataSection(VAPoR::ControlExec* ce);\n\n    static const std::string SelectedDatasetTag;\n    static const std::string MetadataTimestepTag;\n\nprotected:\n    void updateGUI() const override;\n};\n\n//! \\class VMetadataTree\n//! Abstract base class for VWidgets that wrap QTreeWidgets.\n//! Only updates QTreeWidgets when the user's selected DataMgr,\n//! timestep, or variable list change.\nclass VMetadataTree : public VSectionGroup, public ParamsUpdatable {\n    Q_OBJECT\n\npublic:\n    VMetadataTree();\n    virtual void Update(VAPoR::ParamsBase* p, VAPoR::ParamsMgr* pm, VAPoR::DataMgr* dm) override;\n\nsignals:\n    void _timestepRejected();\n\nprotected:\n\n    QTreeWidget*    _tree;\n    VAPoR::DataMgr* _dm;\n    size_t          _ts;\n    bool            _needUpdate;\n    std::vector<std::string> _topLevelBranches;\n\n    virtual void _gatherBranches(std::vector<std::string> &branches, VAPoR::ParamsBase* rp = nullptr) const = 0;\n    virtual void _generateMetadata(QTreeWidgetItem* item) const = 0;\n    bool _checkNeedUpdate(VAPoR::ParamsBase* p, VAPoR::DataMgr* dm);\n};\n\n//! \\class VVariableMetadataTree\n//! Displays metadata for all variables in a given DataMgr instance.\nclass VVariableMetadataTree : public VMetadataTree {\n    Q_OBJECT\n\npublic:\n    VVariableMetadataTree();\n\nprotected:\n    void _gatherBranches(std::vector<std::string> &branches, VAPoR::ParamsBase* p = nullptr) const override;\n    void _generateMetadata(QTreeWidgetItem* item) const override;\n\n    void _generateCoordVarInfo(QTreeWidgetItem* parent, const QString& qCoordVar) const;\n    void _generateAttributeInfo(QTreeWidgetItem* parent, const VAPoR::DC::BaseVar baseVar) const;\n};\n\n//! \\class VVariableMetadataTree\n//! Displays metadata for all variables open in a given RenderParams instance.\nclass VOpenVariableMetadataTree : public VVariableMetadataTree {\n    Q_OBJECT\n\npublic:\n    VOpenVariableMetadataTree();\n\nprotected:\n    void _gatherBranches(std::vector<std::string> &branches, VAPoR::ParamsBase* p = nullptr) const override;\n};\n\n//! \\class VVariableMetadataTree\n//! Displays metadata for all coordinate variables in a given DataMgr instance.\nclass VCoordinateVariableMetadataTree : public VVariableMetadataTree {\n    Q_OBJECT\n\npublic:\n    VCoordinateVariableMetadataTree();\n\nprotected:\n    void _gatherBranches(std::vector<std::string> &branches, VAPoR::ParamsBase* p) const override;\n    void _generateMetadata(QTreeWidgetItem* item) const override;\n};\n\n//! \\class VDimensionMetadataTree\n//! Displays dimension metadata for a given DataMgr instance.\nclass VDimensionMetadataTree : public VMetadataTree {\n    Q_OBJECT\n\npublic:\n    VDimensionMetadataTree();\n    //void Update(VAPoR::ParamsBase* p, VAPoR::ParamsMgr* pm, VAPoR::DataMgr* dm) override;\n\nprotected:\n    void _gatherBranches(std::vector<std::string> &dims, VAPoR::ParamsBase* p) const override;\n    void _generateMetadata(QTreeWidgetItem* item) const override;\n};\n\n//! \\class VVariableMetadataTree\n//! Displays global attribute metadata for a given DataMgr instance.\nclass VGlobalAttributeMetadataTree : public VMetadataTree {\n    Q_OBJECT\n\npublic:\n    VGlobalAttributeMetadataTree();\n\nprotected:\n    void _gatherBranches(std::vector<std::string> &vars, VAPoR::ParamsBase* p) const override;\n    void _generateMetadata(QTreeWidgetItem* item) const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PMovingDomainSettings.cpp",
    "content": "#include \"PMovingDomainSettings.h\"\n#include \"PCheckbox.h\"\n#include <vapor/ControlExecutive.h>\n#include <vapor/GUIStateParams.h>\n\nPMovingDomainSettings::PMovingDomainSettings(ControlExec *ce)\n    : PSection(\"Moving Domain\", {\n        (new PCheckbox(GUIStateParams::MovingDomainTrackCameraTag, \"Track Camera\"))->SetTooltip(\"Camera should follow the moving domain\"),\n        (new PCheckbox(GUIStateParams::MovingDomainTrackRenderRegionsTag, \"Track Rendered Regions\"))->SetTooltip(\"Renderer regions should be relative to the moving domain\"),\n    }), _ce(ce) \n{\n    SetTooltip(\"Control behaviors related to moving domains. Disabled if dataset does not contain a moving domain.\");\n}\n\nbool PMovingDomainSettings::isEnabled() const {\n    for (auto name : _ce->GetDataStatus()->GetDataMgrNames())\n        if (_ce->GetDataStatus()->GetDataMgr(name)->HasMovingDomain())\n            return true;\n    return false;\n}\n"
  },
  {
    "path": "apps/vaporgui/PMovingDomainSettings.h",
    "content": "#pragma once\n\n#include \"PSection.h\"\n\n//! \\class PMovingDomainSettings\n//! Applies parameters for moving domains\n//! \\copydoc PSection\n\nclass PMovingDomainSettings : public PSection {\n    ControlExec *_ce;\n\npublic:\n    PMovingDomainSettings(ControlExec *ce);\n\nprotected:\n    bool isEnabled() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PMultiVarSelector.cpp",
    "content": "#include \"PMultiVarSelector.h\"\n#include <QListWidget>\n#include <cassert>\n#include <vapor/RenderParams.h>\n\nusing VAPoR::RenderParams;\n\nPMultiVarSelector::PMultiVarSelector(std::string tag) : PWidget(tag, _listWidget = new QListWidget)\n{\n    _listWidget->setSelectionMode(QAbstractItemView::NoSelection);\n    connect(_listWidget, &QListWidget::itemChanged, this, &PMultiVarSelector::_itemChanged);\n}\n\nPMultiVarSelector *PMultiVarSelector::DisplayVars(Mode mode)\n{\n    _mode = mode;\n    return this;\n}\n\nvoid PMultiVarSelector::updateGUI() const\n{\n    vector<string> varNames;\n    const auto     nDims = getParams<RenderParams>()->GetRenderDim();\n\n    switch (_mode) {\n    default:\n    case Auto: varNames = getDataMgr()->GetDataVarNames(nDims); break;\n    case D2: varNames = getDataMgr()->GetDataVarNames(2); break;\n    case D3: varNames = getDataMgr()->GetDataVarNames(3); break;\n    case Both:\n        varNames = getDataMgr()->GetDataVarNames(2);\n        const auto other = getDataMgr()->GetDataVarNames(3);\n        varNames.insert(varNames.end(), other.begin(), other.end());\n        break;\n    }\n\n    _listWidget->blockSignals(true);\n    _listWidget->clear();\n    for (const auto &var : varNames) _addVarToList(var);\n\n    const auto selectedVars = getParams()->GetValueStringVec(getTag());\n    for (const auto &var : selectedVars) {\n        const auto       items = _listWidget->findItems(QString::fromStdString(var), Qt::MatchExactly);\n        QListWidgetItem *item;\n        if (items.isEmpty())\n            item = _addVarToList(var);\n        else\n            item = items[0];\n        item->setCheckState(Qt::Checked);\n    }\n    _listWidget->blockSignals(false);\n}\n\nQSize PMultiVarSelector::minimumSizeHint() const\n{\n    QSize s = PWidget::minimumSizeHint();\n    int   count = _listWidget->count();\n    int   rowHeight = _listWidget->sizeHintForRow(0);\n    int   height = count * rowHeight;\n    s.setHeight(std::max(s.height(), std::min(s.height() * 3, height)));\n    return s;\n}\n\nQListWidgetItem *PMultiVarSelector::_addVarToList(const std::string &var) const\n{\n    QListWidgetItem *item = new QListWidgetItem(QString::fromStdString(var));\n    item->setFlags(item->flags() | Qt::ItemIsUserCheckable);\n    item->setCheckState(Qt::Unchecked);\n    _listWidget->addItem(item);\n    return item;\n}\n\nvoid PMultiVarSelector::_itemChanged(QListWidgetItem *)\n{\n    std::vector<std::string> selected;\n    for (int i = 0; i < _listWidget->count(); i++) {\n        QListWidgetItem *item = _listWidget->item(i);\n        if (item->checkState() == Qt::Checked) selected.push_back(item->text().toStdString());\n    }\n\n    getParams()->SetValueStringVec(getTag(), \"\", selected);\n}\n"
  },
  {
    "path": "apps/vaporgui/PMultiVarSelector.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nclass QListWidget;\nclass QListWidgetItem;\n\n//! \\class PMultiVarSelector\n//! \\brief Allows the selection of multiple variables. To add a title, use a PLabel.\n//! \\author Stas Jaroszynski\n//! By default this shows the vars with the same dimension as the renderer. This can be changed\n//! with DisplayVars(Mode)\n\nclass PMultiVarSelector : public PWidget {\npublic:\n    enum Mode { Auto, D2, D3, Both };\n\n    PMultiVarSelector(std::string tag);\n    PMultiVarSelector *DisplayVars(Mode mode);\n\nprotected:\n    void  updateGUI() const override;\n    QSize minimumSizeHint() const override;\n    bool  requireDataMgr() const override { return true; }\n\nprivate:\n    QListWidget *_listWidget;\n    Mode         _mode = Auto;\n\n    QListWidgetItem *_addVarToList(const std::string &var) const;\n    void             _itemChanged(QListWidgetItem *);\n};\n"
  },
  {
    "path": "apps/vaporgui/POrientationSelector.cpp",
    "content": "#include \"POrientationSelector.h\"\n#include \"PEnumDropdown.h\"\n#include <vapor/RenderParams.h>\n#include <assert.h>\n\nusing namespace VAPoR;\n\nPOrientationSelector::POrientationSelector() : PWidget(\"\", _dropdown = new PEnumDropdown(Box::m_orientationTag, {\"XY\", \"XZ\", \"YZ\"}, {Box::XY, Box::XZ, Box::YZ}, \"Orientation\")) {}\n\nvoid POrientationSelector::updateGUI() const\n{\n    RenderParams *rp = dynamic_cast<RenderParams *>(getParams());\n    VAssert(rp);\n    _dropdown->Update(rp->GetBox(), getParamsMgr(), getDataMgr());\n}\n"
  },
  {
    "path": "apps/vaporgui/POrientationSelector.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nclass PEnumDropdown;\n\n//! \\class POrientationSelector\n//! \\brief Widget provides the user the option of switching a renderer between 2D and 3D.\n//! \\author Stas Jaroszynski\n\nclass POrientationSelector : public PWidget {\n    PEnumDropdown *_dropdown;\n\npublic:\n    POrientationSelector();\n\nprotected:\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/POutputResolutionSection.cpp",
    "content": "#include \"POutputResolutionSection.h\"\n#include \"PWidgets.h\"\n#include <vapor/ViewpointParams.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/NavigationUtils.h>\n\n\ntypedef VAPoR::ViewpointParams VP;\n\n\n// clang-format off\nPOutputResolutionSection::POutputResolutionSection(VAPoR::ControlExec *ce)\n: PWidgetWrapper(\n    new PSection(\"Output Resolution\", {\n        new PCheckbox(VP::UseCustomFramebufferTag, \"Use Custom Output Size\"),\n        (new PIntegerInput(VP::CustomFramebufferWidthTag,  \"Output Width (px)\"))->SetRange(1, 16384)->EnableBasedOnParam(VP::UseCustomFramebufferTag),\n        (new PIntegerInput(VP::CustomFramebufferHeightTag, \"Output Height (px)\"))->SetRange(1, 16384)->EnableBasedOnParam(VP::UseCustomFramebufferTag),\n    }\n)), _ce(ce) {}\n// clang-format on\n\n\nVAPoR::ParamsBase *POutputResolutionSection::getWrappedParams() const { return NavigationUtils::GetActiveViewpointParams(_ce); }\n"
  },
  {
    "path": "apps/vaporgui/POutputResolutionSection.h",
    "content": "#pragma once\n\n#include \"PWidgetWrapper.h\"\n\n\nnamespace VAPoR {\nclass ControlExec;\n}\n\n\nclass POutputResolutionSection : public PWidgetWrapper {\n    VAPoR::ControlExec *_ce;\n\npublic:\n    POutputResolutionSection(VAPoR::ControlExec *ce);\n\nprotected:\n    VAPoR::ParamsBase *getWrappedParams() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PProjectionStringWidget.cpp",
    "content": "#include \"PProjectionStringWidget.h\"\n\n#include <QLabel>\n#include <QPlainTextEdit>\n#include \"VSection.h\"\n#include \"VLineItem.h\"\n#include \"VComboBox.h\"\n#include \"VPushButton.h\"\n#include \"PDisplay.h\"\n\n#include <vapor/ControlExecutive.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/GUIStateParams.h>\n#include \"VLabel.h\"\n\nusing namespace VAPoR;\n\nPProjectionStringWidget::PProjectionStringWidget(ControlExec *ce)\n: PWidget(\"\", new VSectionGroup(\"Data Projection\",\n                                {\n                                    _currentProjDisp = (new PStringDisplay(GUIStateParams::m_proj4StringTag, \"Current Projection String\"))->Selectable(),\n                                    new VLabel(\"\"),\n                                    new VLabel(\"Change Projection String\"),\n                                    new VLineItem(\"Change projection to\", _datasetDropdown = new VComboBox),\n                                    new VLineItem(\"Selected Projection String\", _selectedProjDisp = new VLabel),\n                                    _customStrEdit = new QPlainTextEdit,\n                                    _applyButton = new VPushButton(\"Apply\"),\n                                })),\n  _ce(ce)\n{\n    _selectedProjDisp->MakeSelectable();\n    connect(_datasetDropdown, &VComboBox::ValueChanged, this, &PProjectionStringWidget::datasetDropdownChanged);\n    connect(_applyButton, &VPushButton::ButtonClicked, this, &PProjectionStringWidget::applyClicked);\n}\n\n\nvoid PProjectionStringWidget::updateGUI() const\n{\n    ParamsMgr *pm = _ce->GetParamsMgr();\n    auto       stateParams = ((GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType()));\n    auto       activeViz = stateParams->GetActiveVizName();\n\n    DataStatus *   dataStatus = _ce->GetDataStatus();\n    vector<string> datasets = dataStatus->GetDataMgrNames();\n    vector<string> datasetProjStrs;\n    string         currentProjStr = dataStatus->GetMapProjection();\n\n    for (auto &dataset : datasets) datasetProjStrs.push_back(dataStatus->GetMapProjectionDefault(dataset));\n\n    datasets.push_back(\"Custom\");\n    _datasetDropdown->SetOptions(datasets);\n\n    _datasetDropdown->SetValue(\"Custom\");\n    if (_changeToDataset.empty()) {\n        for (int i = 0; i < datasetProjStrs.size(); i++)\n            if (datasetProjStrs[i] == currentProjStr) _datasetDropdown->SetIndex(i);\n    } else {\n        _datasetDropdown->SetValue(_changeToDataset);\n    }\n\n    _currentProjDisp->Update(stateParams);\n\n    auto selected = _datasetDropdown->GetValue();\n    if (selected == \"Custom\") {\n        _customStrEdit->setVisible(true);\n        _selectedProjDisp->setVisible(false);\n    } else {\n        auto proj = dataStatus->GetMapProjectionDefault(selected);\n        _selectedProjDisp->SetText(proj.size() ? proj : \"<empty>\");\n        _customStrEdit->setVisible(false);\n        _selectedProjDisp->setVisible(true);\n    }\n}\n\n\nvoid PProjectionStringWidget::datasetDropdownChanged(std::string value)\n{\n    _changeToDataset = value;\n    updateGUI();\n}\n\n\nvoid PProjectionStringWidget::applyClicked()\n{\n    DataStatus * dataStatus = _ce->GetDataStatus();\n    const string selected = _datasetDropdown->GetValue();\n    string       proj;\n    if (selected == \"Custom\") {\n        proj = _customStrEdit->toPlainText().toStdString();\n    } else {\n        proj = dataStatus->GetMapProjectionDefault(selected);\n    }\n\n    ParamsMgr *pm = _ce->GetParamsMgr();\n    auto       p = ((GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType()));\n    if (proj == p->GetProjectionString()) return;\n\n    p->SetProjectionString(proj);\n}\n"
  },
  {
    "path": "apps/vaporgui/PProjectionStringWidget.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n#include \"PWidgetsFwd.h\"\n#include \"VFrame.h\"\n#include \"Updatable.h\"\n\nnamespace VAPoR {\nclass ControlExec;\n};\nusing VAPoR::ControlExec;\nclass QLabel;\nclass QPlainTextEdit;\nclass VComboBox;\nclass VPushButton;\nclass VLabel;\n\nclass PProjectionStringWidget : public PWidget {\n    Q_OBJECT\n    ControlExec *   _ce;\n    PDisplay *      _currentProjDisp;\n    VLabel *        _selectedProjDisp;\n    VComboBox *     _datasetDropdown;\n    QPlainTextEdit *_customStrEdit;\n    VPushButton *   _applyButton;\n    std::string     _changeToDataset;\n\npublic:\n    PProjectionStringWidget(ControlExec *ce);\n\nprotected:\n    void updateGUI() const override;\n    void datasetDropdownChanged(std::string value);\n    void applyClicked();\n};\n"
  },
  {
    "path": "apps/vaporgui/PRadioButtons.cpp",
    "content": "#include \"PRadioButtons.h\"\n#include \"VRadioButton.h\"\n#include \"VGroup.h\"\n\nPRadioButtons::PRadioButtons(const std::string &tag, const std::vector<std::string> labels) : PWidget(tag, _vg = new VGroup()), _labels(labels)\n{\n    bool first = true;\n    for (auto l : _labels) {\n        VRadioButton *rb = new VRadioButton(l, false);\n        if (first) {\n            rb->SetValue(true);\n            first = false;\n        }\n        connect(rb, &VRadioButton::ValueChanged, this, &PRadioButtons::radioButtonStateChanged);\n        _vg->Add(rb);\n    }\n}\n\nvoid PRadioButtons::updateGUI() const\n{\n    for (int i =0; i< _vg->layout()->count(); i++) {\n        VRadioButton *rb = dynamic_cast<VRadioButton*>(_vg->layout()->itemAt(i)->widget());\n        if (_labels[getParamsLong()] == rb->GetText()) rb->SetValue(true);\n        else rb->SetValue(false);\n    }\n}\n\nvoid PRadioButtons::radioButtonStateChanged() { \n    VRadioButton *rb = dynamic_cast<VRadioButton*>(sender());\n    auto it = std::find(_labels.begin(), _labels.end(), rb->GetText());\n    int index = std::distance(_labels.begin(), it);\n    setParamsLong(index); \n}\n"
  },
  {
    "path": "apps/vaporgui/PRadioButtons.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\n//class VRadioButton;\nclass VGroup;\n\n//! \\class PRadioButtons\n//! Creates a Qt RadioButton synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PRadioButtons : public PWidget {\n    Q_OBJECT\n\n    VGroup *_vg;\n    std::vector<std::string> _labels;\n    int _paramValue;\n\npublic:\n    PRadioButtons(const std::string &tag, const std::vector<std::string> labels);\n\nprotected:\n    void updateGUI() const override;\n\nprivate slots:\n    void radioButtonStateChanged();\n};\n"
  },
  {
    "path": "apps/vaporgui/PRegionSelector.cpp",
    "content": "#include <string>\n#include \"PRegionSelector.h\"\n#include \"QRangeSliderTextCombo.h\"\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgrUtils.h>\n#include <assert.h>\n#include \"POrientationSelector.h\"\n\nusing namespace VAPoR;\n\nPRegionSelector::PRegionSelector(const std::string &label) : PSection(label)\n{\n    Add(new PRegionSelectorX);\n    Add(new PRegionSelectorY);\n    Add(new PRegionSelectorZ);\n}\n\nPRegionSelector1D::PRegionSelector1D(int dim) : PLineItem(\"\", dim == 0 ? \"X\" : dim == 1 ? \"Y\" : \"Z\", _slider = new QRangeSliderTextCombo), _dim(dim)\n{\n    QObject::connect(_slider, &QRangeSliderTextCombo::ValueChanged, this, &PRegionSelector1D::sliderValueChanged);\n    _slider->AllowCustomRange();\n}\n\nvoid PRegionSelector1D::updateGUI() const\n{\n    RenderParams *rp = getParams<RenderParams>();\n\n    VAPoR::CoordType min, max;\n    size_t         ts = rp->GetCurrentTimestep();\n    int            level = rp->GetRefinementLevel();\n    int            lod = rp->GetCompressionLevel();\n    string         varName = rp->GetFirstVariableName();\n\n    Box *box = getBox();\n\n    // In some cases (ImageRenderer), there may be no 2D variable to configure extents with.\n    // Therefore, configure the sliders with the extents of a random 3D variable\n    if (varName == \"\") {\n        string varName;\n        VAPoR::DataMgrUtils::GetFirstExistingVariable(getDataMgr(), 0, 0, 0, 3, varName);\n        std::vector<int> axes;\n        VAPoR::CoordType minExts, maxExts;\n        vector<string> vvarName = {varName};\n        VAPoR::DataMgrUtils::GetExtents(getDataMgr(), 0, vvarName, 0, 0, minExts, maxExts, axes);\n        \n        box->GetExtents(min, max);\n        _slider->SetValue(min[_dim], max[_dim]);\n        _slider->SetRange(minExts[_dim], maxExts[_dim]);\n\n        return;\n    }\n\n    int ret = getDataMgr()->GetVariableExtents(ts, varName, level, lod, min, max);\n    if (ret < 0) {\n        _slider->SetRange(0, 0);\n        _slider->SetValue(0, 0);\n        return;\n    }\n\n    _slider->SetRange(min[_dim], max[_dim]);\n\n    box->GetExtents(min, max);\n    _slider->SetValue(min[_dim], max[_dim]);\n}\n\nbool PRegionSelector1D::isShown() const\n{\n    Box *box = getBox();\n\n    const Box::Orientation o = (Box::Orientation)box->GetOrientation();\n    const int              d = _dim;\n\n    switch (o) {\n    case Box::XYZ: return true;\n    case Box::XY: return d == 0 || d == 1;\n    case Box::XZ: return d == 0 || d == 2;\n    case Box::YZ: return d == 1 || d == 2;\n    default: assert(0);\n    }\n\n    return false;\n}\n\nVAPoR::Box *PRegionSelector1D::getBox() const { return getParams<RenderParams>()->GetBox(); }\n\nvoid PRegionSelector1D::sliderValueChanged(float v0, float v1)\n{\n    Box *box = getBox();\n\n    CoordType min, max;\n    box->GetExtents(min, max);\n    min[_dim] = v0;\n    max[_dim] = v1;\n    box->SetExtents(min, max);\n}\n"
  },
  {
    "path": "apps/vaporgui/PRegionSelector.h",
    "content": "#pragma once\n\n#include \"PSection.h\"\n#include \"PLineItem.h\"\n\nclass QRangeSliderTextCombo;\n\nnamespace VAPoR {\nclass Box;\n}\n\n//! \\class PRegionSelector\nclass PRegionSelector : public PSection {\npublic:\n    PRegionSelector(const std::string &label = \"Region\");\n};\n\nclass PRegionSelector1D : public PLineItem {\n    QRangeSliderTextCombo *_slider;\n    const int              _dim;\n\npublic:\n    PRegionSelector1D(int dim);\n\nprotected:\n    virtual void        updateGUI() const override;\n    virtual bool        isShown() const override;\n    virtual bool        requireDataMgr() const override { return true; }\n    virtual VAPoR::Box *getBox() const;\n\nprivate:\n    void sliderValueChanged(float v0, float v1);\n};\n\ntemplate<int dim> class __PRegionSelector1D : public PRegionSelector1D {\npublic:\n    __PRegionSelector1D() : PRegionSelector1D(dim) {}\n};\ntypedef __PRegionSelector1D<0> PRegionSelectorX;\ntypedef __PRegionSelector1D<1> PRegionSelectorY;\ntypedef __PRegionSelector1D<2> PRegionSelectorZ;\n"
  },
  {
    "path": "apps/vaporgui/PSection.cpp",
    "content": "#include \"PSection.h\"\n#include \"VSection.h\"\n#include \"PGroup.h\"\n#include <vapor/ParamsBase.h>\n\nPSection::PSection(const std::string &label, const PGroup::List &widgets) : PWidget(\"\", _vsection = new VSection(label))\n{\n    _pgroup = new PGroup;\n    _vsection->layout()->addWidget(_pgroup);\n    _pgroup->AddM(widgets);\n}\n\nvoid PSection::updateGUI() const { _pgroup->Update(getParams(), getParamsMgr(), getDataMgr()); }\n\nPSection *PSection::Add(PWidget *pw)\n{\n    _pgroup->Add(pw);\n    return this;\n}\n\nPSection *PSection::Add(const PGroup::List &widgets)\n{\n    _pgroup->AddM(widgets);\n    return this;\n}\n"
  },
  {
    "path": "apps/vaporgui/PSection.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n#include \"PGroup.h\"\n\nclass VSection;\n\n//! \\class PSection\n//! Same as a PGroup however collated inside of a VSection\n//! \\copydoc PGroup\n//! \\copydoc VSection\n\nclass PSection : public PWidget {\n    Q_OBJECT\n\n    VSection *_vsection;\n    PGroup *  _pgroup;\n\npublic:\n    PSection(const std::string &label = \"\", const PGroup::List &widgets = {});\n    //! @copydoc PGroup::Add\n    PSection *Add(PWidget *pw);\n    PSection *Add(const PGroup::List &widgets);\n\nprotected:\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PShowIf.cpp",
    "content": "#include \"PShowIf.h\"\n#include \"PGroup.h\"\n#include <vapor/ParamsBase.h>\n#include <vapor/VAssert.h>\n\nPShowIf::PShowIf(std::string tag) : PWidgetWrapper(tag, _group = new PGroup) { _test = std::unique_ptr<Test>(new TestLongEquals(getTag(), true)); }\n\nPShowIf *PShowIf::Equals(long l)\n{\n    _test = std::unique_ptr<Test>(new TestLongEquals(getTag(), l));\n    return this;\n}\n\nPShowIf *PShowIf::Equals(std::string s)\n{\n    _test = std::unique_ptr<Test>(new TestStringEquals(getTag(), s));\n    return this;\n}\n\nPShowIf *PShowIf::DimensionEquals(unsigned int dim)\n{\n    _test = std::unique_ptr<Test>(new TestDimensionEquals(dim));\n    return this;\n}\n\nPShowIf *PShowIf::Not()\n{\n    _negate = !_negate;\n    return this;\n}\n\nPShowIf *PShowIf::Then(PWidget *p)\n{\n    _hasThen = true;\n    _group->Add(new Helper(this, p));\n    return this;\n}\n\nPShowIf *PShowIf::Else(PWidget *p)\n{\n    _hasElse = true;\n    _group->Add(new Helper(this, p, true));\n    return this;\n}\n\nPShowIf *PShowIf::Then(const PGroup::List &list) { return Then(new PGroup(list)); }\n\nPShowIf *PShowIf::Else(const PGroup::List &list) { return Else(new PGroup(list)); }\n\nbool PShowIf::isShown() const\n{\n    bool result = evaluate();\n    return (result && _hasThen) || (!result && _hasElse);\n}\n\nbool PShowIf::evaluate() const\n{\n    VAssert(_test);\n    return _test->Evaluate(getParams()) != _negate;\n}\n\nPShowIf::Helper::Helper(PShowIf *parent, PWidget *widget, bool negate) : PWidgetWrapper(widget), _parent(parent), _negate(negate) {}\n\nbool PShowIf::Helper::isShown() const { return _parent->evaluate() != _negate; }\n\nbool PShowIf::TestLongEquals::Evaluate(VAPoR::ParamsBase *params) const { return params->GetValueLong(_tag, 0) == _val; }\n\nbool PShowIf::TestStringEquals::Evaluate(VAPoR::ParamsBase *params) const { return params->GetValueString(_tag, \"\") == _val; }\n\n#include <vapor/RenderParams.h>\n\nbool PShowIf::TestDimensionEquals::Evaluate(VAPoR::ParamsBase *params) const\n{\n    VAPoR::RenderParams *rp = dynamic_cast<VAPoR::RenderParams *>(params);\n    return rp->GetRenderDim() == _val;\n}\n"
  },
  {
    "path": "apps/vaporgui/PShowIf.h",
    "content": "#pragma once\n\n#include \"PWidgetWrapper.h\"\n#include \"PGroup.h\"\n#include <memory>\n\n//! \\class PShowIf\n//! \\brief Shows and hides PWidgets based on a logic test.\n//! \\author Stas Jaroszynski\n//!\n//! For example:\n//! (new PShowIf(\"param_tag\"))->Not()->Equals(\"Hi\")->Then(\n//!     PWidgets here will only show if param_tag != \"Hi\"\n//! )->Else(\n//!     PWidgets here will only show if param_tag == \"Hi\"\n//! );\n\nclass PShowIf : public PWidgetWrapper {\n    PGroup *_group;\n    bool    _negate = false;\n    bool    _hasThen = false;\n    bool    _hasElse = false;\n\npublic:\n    PShowIf(std::string tag);\n    PShowIf *Equals(long l);\n    PShowIf *Equals(std::string s);\n    PShowIf *DimensionEquals(unsigned int dim);\n    //    PShowIf *Or(PShowIf *);\n    PShowIf *Not();\n    PShowIf *Then(PWidget *p);\n    PShowIf *Else(PWidget *p);\n    PShowIf *Then(const PGroup::List &list);\n    PShowIf *Else(const PGroup::List &list);\n\nprotected:\n    bool isShown() const override;\n\nprivate:\n    bool evaluate() const;\n\n    class Helper : public PWidgetWrapper {\n        const PShowIf *_parent;\n        const bool     _negate;\n\n    public:\n        Helper(PShowIf *parent, PWidget *widget, bool negate = false);\n\n    protected:\n        bool isShown() const override;\n    };\n\n    struct Test {\n        const std::string _tag;\n        Test(std::string tag) : _tag(tag) {}\n        virtual bool Evaluate(VAPoR::ParamsBase *params) const = 0;\n        virtual ~Test() {}\n    };\n\n    struct TestLongEquals : public Test {\n        const long _val;\n        TestLongEquals(std::string tag, long val) : Test(tag), _val(val) {}\n        bool Evaluate(VAPoR::ParamsBase *params) const override;\n    };\n\n    struct TestStringEquals : public Test {\n        const std::string _val;\n        TestStringEquals(std::string tag, std::string val) : Test(tag), _val(val) {}\n        bool Evaluate(VAPoR::ParamsBase *params) const override;\n    };\n\n    struct TestDimensionEquals : public Test {\n        const long _val;\n        TestDimensionEquals(long val) : Test(\"\"), _val(val) {}\n        bool Evaluate(VAPoR::ParamsBase *params) const override;\n    };\n\n    std::unique_ptr<Test> _test;\n};\n"
  },
  {
    "path": "apps/vaporgui/PSliceController.cpp",
    "content": "#include \"PSliceController.h\"\n#include \"PEnumDropdown.h\"\n#include \"PSliderEditHLI.h\"\n#include \"PLabel.h\"\n#include \"PShowIf.h\"\n#include \"PCheckbox.h\"\n#include <vapor/SliceParams.h>\n#include <assert.h>\n\nusing namespace VAPoR;\n\nPSliceController::PSliceController() : PGroup()\n{\n    Add(new PSliceOrientationSelector);\n    Add(new PSliceOffsetSelector);\n    Add(new PSliceOriginSelector);\n}\n\nPSliceOrientationSelector::PSliceOrientationSelector() : PSection(\"Slice Orientation\")\n{\n    Add(new PEnumDropdown(RenderParams::SlicePlaneOrientationModeTag, {\"Rotation\", \"Normal\"},\n                          {(int)RenderParams::SlicePlaneOrientationMode::Rotation, (int)RenderParams::SlicePlaneOrientationMode::Normal}, \"Orientation Mode\"));\n    Add((new PShowIf(RenderParams::SlicePlaneOrientationModeTag))\n            ->Equals((int)RenderParams::SlicePlaneOrientationMode::Rotation)\n            ->Then({\n                (new PDoubleSliderEdit(RenderParams::XSlicePlaneRotationTag, \"X\"))->SetRange(-90., 90.)->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(RenderParams::YSlicePlaneRotationTag, \"Y\"))->SetRange(-90., 90.)->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(RenderParams::ZSlicePlaneRotationTag, \"Z\"))->SetRange(-90., 90.)->EnableDynamicUpdate(),\n            })\n            ->Else({\n                (new PDoubleSliderEdit(RenderParams::SlicePlaneNormalXTag, \"X\"))->SetRange(-1, 1)->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(RenderParams::SlicePlaneNormalYTag, \"Y\"))->SetRange(-1, 1)->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(RenderParams::SlicePlaneNormalZTag, \"Z\"))->SetRange(-1, 1)->EnableDynamicUpdate(),\n            }));\n    SetTooltip(\"The plane normal of the slice. The offset will move the slice along this normal as well.\");\n}\n\nPSliceOriginSelector::PSliceOriginSelector() : PSection(\"Slice Origin\")\n{\n    _xSlider = new PDoubleSliderEditHLI<RenderParams>(\"X\", &RenderParams::GetXSlicePlaneOrigin, &RenderParams::SetXSlicePlaneOrigin);\n    _ySlider = new PDoubleSliderEditHLI<RenderParams>(\"Y\", &RenderParams::GetYSlicePlaneOrigin, &RenderParams::SetYSlicePlaneOrigin);\n    _zSlider = new PDoubleSliderEditHLI<RenderParams>(\"Z\", &RenderParams::GetZSlicePlaneOrigin, &RenderParams::SetZSlicePlaneOrigin);\n\n    _xSlider->EnableDynamicUpdate();\n    _ySlider->EnableDynamicUpdate();\n    _zSlider->EnableDynamicUpdate();\n\n    Add({\n        new PLabel(\"Slice origin is shown in-scene as a yellow crosshair\"),\n        new PCheckbox(\"GUI_ShowOrigin\", \"Show Origin Controls\"),\n        (new PShowIf(\"GUI_ShowOrigin\"))\n            ->Then({\n                _xSlider,\n                _ySlider,\n                _zSlider,\n            }),\n    });\n    SetTooltip(\"The slice plane will pass through this point. \\nThe plane can be offset from this point along the plane normal determined by the orientation.\");\n}\n\nvoid PSliceOriginSelector::updateGUI() const\n{\n    RenderParams *rp = getParams<RenderParams>();\n\n    CoordType min, max;\n    size_t    ts = rp->GetCurrentTimestep();\n    int       level = rp->GetRefinementLevel();\n    int       lod = rp->GetCompressionLevel();\n    string    varName = rp->GetVariableName();\n\n    int ret = getDataMgr()->GetVariableExtents(ts, varName, level, lod, min, max);\n    if (ret) return;\n\n    _xSlider->SetRange(min[0], max[0]);\n    _ySlider->SetRange(min[1], max[1]);\n    _zSlider->SetRange(min[2], max[2]);\n\n    PSection::updateGUI();\n}\n\n\n\n#include <vapor/ArbitrarilyOrientedRegularGrid.h>\n\nPSliceOffsetSelector::PSliceOffsetSelector() : PSection(\"Slice Offset\")\n{\n    _offsetSlider = new PDoubleSliderEdit(RenderParams::SliceOffsetTag, \"Offset\");\n    _offsetSlider->EnableDynamicUpdate();\n    Add(_offsetSlider);\n    SetTooltip(\"Offset the plane from its origin \\n along its normal (set by the orientation).\");\n}\n\nvoid PSliceOffsetSelector::updateGUI() const\n{\n    RenderParams *rp = getParams<RenderParams>();\n\n    planeDescription pd;\n    size_t           ts = rp->GetCurrentTimestep();\n    int              level = rp->GetRefinementLevel();\n    int              lod = rp->GetCompressionLevel();\n    string           varName = rp->GetVariableName();\n\n    int ret = getDataMgr()->GetVariableExtents(ts, varName, level, lod, pd.boxMin, pd.boxMax);\n    if (ret) return;\n    pd.origin = rp->GetSlicePlaneOrigin();\n    if (rp->GetValueLong(rp->SlicePlaneOrientationModeTag, 0) == (int)RenderParams::SlicePlaneOrientationMode::Normal) {\n        pd.normal = rp->GetSlicePlaneNormal();\n    } else {\n        auto n = ArbitrarilyOrientedRegularGrid::GetNormalFromRotations(rp->GetSlicePlaneRotation());\n        pd.normal = {n[0], n[1], n[2]};\n    }\n\n    auto range = ArbitrarilyOrientedRegularGrid::GetOffsetRange(pd);\n    _offsetSlider->SetRange(range.first, range.second);\n\n    PSection::updateGUI();\n}\n"
  },
  {
    "path": "apps/vaporgui/PSliceController.h",
    "content": "#pragma once\n\n#include \"PSection.h\"\n\n//! \\class PSliceController\n//! \\brief Provides controls for rotating slices, offsetting them, and positioning their origin\n\nclass PDoubleSliderEdit;\n\nclass PSliceController : public PGroup {\npublic:\n    PSliceController();\n};\n\nclass PSliceOrientationSelector : public PSection {\npublic:\n    PSliceOrientationSelector();\n};\n\nclass PSliceOriginSelector : public PSection {\npublic:\n    PSliceOriginSelector();\n\nprotected:\n    PDoubleSliderEdit *_xSlider;\n    PDoubleSliderEdit *_ySlider;\n    PDoubleSliderEdit *_zSlider;\n\n    virtual void updateGUI() const override;\n    virtual bool requireDataMgr() const override { return true; }\n};\n\n\n\nclass PSliceOffsetSelector : public PSection {\npublic:\n    PSliceOffsetSelector();\n\nprotected:\n    PDoubleSliderEdit *_offsetSlider;\n\n    virtual void updateGUI() const override;\n    virtual bool requireDataMgr() const override { return true; }\n};\n"
  },
  {
    "path": "apps/vaporgui/PSliderEdit.cpp",
    "content": "#include \"PSliderEdit.h\"\n#include \"VLineItem.h\"\n#include <vapor/ParamsBase.h>\n#include \"VSliderEdit.h\"\n#include \"VDoubleSliderEdit.h\"\n#include \"VIntSliderEdit.h\"\n\n#define USER_RANGE_MIN_TAG \"_PWidget_UserRangeMinimum\"\n#define USER_RANGE_MAX_TAG \"_PWidget_UserRangeMaximum\"\n\n// ===============================\n//        PDoubleSliderEdit\n// ===============================\n\nPDoubleSliderEdit::PDoubleSliderEdit(const std::string &tag, const std::string &label) : PLineItem(tag, label, _sliderEdit = new VDoubleSliderEdit(0, 1, 0, true))\n{\n    connect(_sliderEdit, &VDoubleSliderEdit::ValueChanged, this, &PDoubleSliderEdit::valueChanged);\n    connect(_sliderEdit, &VDoubleSliderEdit::ValueChangedIntermediate, this, &PDoubleSliderEdit::valueChangedIntermediate);\n    connect(_sliderEdit, &VDoubleSliderEdit::MinimumChanged, this, &PDoubleSliderEdit::minimumChanged);\n    connect(_sliderEdit, &VDoubleSliderEdit::MaximumChanged, this, &PDoubleSliderEdit::maximumChanged);\n    connect(_sliderEdit, &VDoubleSliderEdit::DynamicUpdateChanged, this, &PDoubleSliderEdit::_enableDynamicUpdate);\n}\n\nPDoubleSliderEdit *PDoubleSliderEdit::SetRange(double min, double max)\n{\n    _defaultRangeMin = min;\n    _defaultRangeMax = max;\n    _sliderEdit->SetMinimum(min);\n    _sliderEdit->SetMaximum(max);\n    return this;\n}\n\nPDoubleSliderEdit *PDoubleSliderEdit::AllowUserRange(bool allowed)\n{\n    _sliderEdit->AllowUserRange(allowed);\n    return this;\n}\n\nPDoubleSliderEdit* PDoubleSliderEdit::AllowDynamicUpdate() {\n    _sliderEdit->AllowDynamicUpdate();\n    return this;\n}\n\nvoid PDoubleSliderEdit::_enableDynamicUpdate(bool enabled) {\n    EnableDynamicUpdate(enabled);\n}\n\nvoid PDoubleSliderEdit::updateGUI() const\n{\n    auto p = getParams();\n    _sliderEdit->SetMinimum(p->GetValueDouble(getTag() + USER_RANGE_MIN_TAG, _defaultRangeMin));\n    _sliderEdit->SetMaximum(p->GetValueDouble(getTag() + USER_RANGE_MAX_TAG, _defaultRangeMax));\n    _sliderEdit->SetValue(getParamsDouble());\n}\n\nvoid PDoubleSliderEdit::valueChanged(double v) { setParamsDouble(v); }\n\nvoid PDoubleSliderEdit::valueChangedIntermediate(double v) { dynamicSetParamsDouble(v); }\n\nvoid PDoubleSliderEdit::minimumChanged(double v)\n{\n    auto p = getParams();\n    p->SetValueDouble(getTag() + USER_RANGE_MIN_TAG, \"\", v);\n}\n\nvoid PDoubleSliderEdit::maximumChanged(double v)\n{\n    auto p = getParams();\n    p->SetValueDouble(getTag() + USER_RANGE_MAX_TAG, \"\", v);\n}\n\n// ===============================\n//       PIntegerSliderEdit\n// ===============================\n\nPIntegerSliderEdit::PIntegerSliderEdit(const std::string &tag, const std::string &label) : PLineItem(tag, label, _sliderEdit = new VIntSliderEdit(0, 1, 0, true))\n{\n    connect(_sliderEdit, &VIntSliderEdit::ValueChanged, this, &PIntegerSliderEdit::valueChanged);\n    connect(_sliderEdit, &VIntSliderEdit::ValueChangedIntermediate, this, &PIntegerSliderEdit::valueChangedIntermediate);\n    connect(_sliderEdit, &VIntSliderEdit::MinimumChanged, this, &PIntegerSliderEdit::minimumChanged);\n    connect(_sliderEdit, &VIntSliderEdit::MaximumChanged, this, &PIntegerSliderEdit::maximumChanged);\n    connect(_sliderEdit, &VIntSliderEdit::DynamicUpdateChanged, this, &PIntegerSliderEdit::_enableDynamicUpdate);\n}\n\nPIntegerSliderEdit *PIntegerSliderEdit::SetRange(int min, int max)\n{\n    _defaultRangeMin = min;\n    _defaultRangeMax = max;\n    _sliderEdit->SetMinimum(min);\n    _sliderEdit->SetMaximum(max);\n    return this;\n}\n\nPIntegerSliderEdit *PIntegerSliderEdit::AllowUserRange(bool allowed)\n{\n    _sliderEdit->AllowUserRange(allowed);\n    return this;\n}\n\nPIntegerSliderEdit* PIntegerSliderEdit::AllowDynamicUpdate() {\n    _sliderEdit->AllowDynamicUpdate();\n    return this;\n}\n\nvoid PIntegerSliderEdit::_enableDynamicUpdate(bool enabled) {\n    EnableDynamicUpdate(enabled);\n}\n\nvoid PIntegerSliderEdit::updateGUI() const\n{\n    auto p = getParams();\n    _sliderEdit->SetMinimum(p->GetValueLong(getTag() + USER_RANGE_MIN_TAG, _defaultRangeMin));\n    _sliderEdit->SetMaximum(p->GetValueLong(getTag() + USER_RANGE_MAX_TAG, _defaultRangeMax));\n    _sliderEdit->SetValue(getParamsLong());\n}\n\nvoid PIntegerSliderEdit::valueChanged(int v) { setParamsLong(v); }\n\nvoid PIntegerSliderEdit::valueChangedIntermediate(int v) { dynamicSetParamsLong(v); }\n\nvoid PIntegerSliderEdit::minimumChanged(int v)\n{\n    auto p = getParams();\n    p->SetValueLong(getTag() + USER_RANGE_MIN_TAG, \"\", v);\n}\n\nvoid PIntegerSliderEdit::maximumChanged(int v)\n{\n    auto p = getParams();\n    p->SetValueLong(getTag() + USER_RANGE_MAX_TAG, \"\", v);\n}\n"
  },
  {
    "path": "apps/vaporgui/PSliderEdit.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n#include \"PDynamicMixin.h\"\n\nclass VDoubleSliderEdit;\nclass VIntSliderEdit;\n\n//! \\class PDoubleSliderEdit\n//! Creates a slider and text input combo synced with the paramsdatabase.\n//! Due to the way VDoubleSliderEdit and VIntSliderEdit are implemented,\n//! duplicating the code was simpler than templatizing.\n\nclass PDoubleSliderEdit : public PLineItem, public PDynamicMixin {\n    VDoubleSliderEdit *_sliderEdit;\n    double             _defaultRangeMin = 0, _defaultRangeMax = 1;\n\npublic:\n    PDoubleSliderEdit(const std::string &tag, const std::string &label = \"\");\n    //! @copydoc VSliderEdit::SetRange\n    PDoubleSliderEdit *SetRange(double min, double max);\n    PDoubleSliderEdit *AllowUserRange(bool allowed = true);\n    PDoubleSliderEdit *AllowDynamicUpdate();\n\nprotected:\n    void updateGUI() const override;\n\nprivate:\n    void valueChanged(double v);\n    void valueChangedIntermediate(double v);\n    void minimumChanged(double v);\n    void maximumChanged(double v);\n\nprivate slots:\n    void _enableDynamicUpdate(bool enabled);\n};\n\n//! \\class PIntegerSliderEdit\n//! Creates a slider and text input combo synced with the paramsdatabase.\n//! Due to the way VDoubleSliderEdit and VIntSliderEdit are implemented,\n//! duplicating the code was simpler than templatizing.\n\nclass PIntegerSliderEdit : public PLineItem, public PDynamicMixin {\n    VIntSliderEdit *_sliderEdit;\n    int             _defaultRangeMin = 0, _defaultRangeMax = 1;\n\npublic:\n    PIntegerSliderEdit(const std::string &tag, const std::string &label = \"\");\n    //! @copydoc VSliderEdit::SetRange\n    PIntegerSliderEdit *SetRange(int min, int max);\n    PIntegerSliderEdit *AllowUserRange(bool allowed = true);\n    PIntegerSliderEdit *AllowDynamicUpdate();\n\nprotected:\n    void updateGUI() const override;\n\nprivate:\n    void valueChanged(int v);\n    void valueChangedIntermediate(int v);\n    void minimumChanged(int v);\n    void maximumChanged(int v);\n\nprivate slots:\n    void _enableDynamicUpdate(bool enabled);\n};\n"
  },
  {
    "path": "apps/vaporgui/PSliderEditHLI.h",
    "content": "#pragma once\n\n#include \"PWidgetHLI.h\"\n#include \"PSliderEdit.h\"\n\nCreateHLI(PDoubleSliderEdit, double);\nCreateHLI(PIntegerSliderEdit, long);\n"
  },
  {
    "path": "apps/vaporgui/PStringDropdown.cpp",
    "content": "#include \"PStringDropdown.h\"\n#include <vapor/ParamsBase.h>\n#include <vapor/VAssert.h>\n#include \"VComboBox.h\"\n\nPStringDropdown::PStringDropdown(const std::string &tag, const std::vector<std::string> &items, const std::string &label) : PLineItem(tag, label, _vComboBox = new VComboBox(items))\n{\n    connect(_vComboBox, &VComboBox::ValueChanged, this, &PStringDropdown::dropdownTextChanged);\n}\n\nvoid PStringDropdown::SetItems(const std::vector<std::string> &items) const { _vComboBox->SetOptions(items); }\n\nvoid PStringDropdown::updateGUI() const\n{\n    auto val = getParamsString();\n    if (val.empty())\n        val = _customBlankText;\n    _vComboBox->SetValue(val);\n}\n\nvoid PStringDropdown::setCustomBlankText(std::string text) { _customBlankText = text; }\n\nvoid PStringDropdown::dropdownTextChanged(std::string text) { setParamsString(text); }\n"
  },
  {
    "path": "apps/vaporgui/PStringDropdown.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n#include <vector>\n//#include \"VaporWidgetsFwd.h\"\n\nclass VComboBox;\n\n//! \\class PStringDropdown same as PEnumDropdown except it sets the param\n//! to directly reflect the string in the drowdown.\n//! \\copydoc PEnumDropdown\n\nclass PStringDropdown : public PLineItem {\n    Q_OBJECT\n\n    VComboBox *_vComboBox;\n    std::string _customBlankText;\n\npublic:\n    PStringDropdown(const std::string &tag, const std::vector<std::string> &items, const std::string &label = \"\");\n    //! Sets the items presented in the dropdown\n    void SetItems(const std::vector<std::string> &items) const;\n\nprotected:\n    virtual void updateGUI() const override;\n    void setCustomBlankText(std::string text);\n\nprotected slots:\n    virtual void dropdownTextChanged(std::string text);\n};\n"
  },
  {
    "path": "apps/vaporgui/PStringDropdownHLI.h",
    "content": "#pragma once\n\n#include \"PWidgetHLI.h\"\n#include \"PStringDropdown.h\"\n\ntemplate<class P> class PStringDropdownHLI : public PStringDropdown, public PWidgetHLIBase<P, std::string> {\npublic:\n    PStringDropdownHLI(const std::string &label, const std::vector<std::string> &items, typename PWidgetHLIBase<P, std::string>::GetterType getter,\n                       typename PWidgetHLIBase<P, std::string>::SetterType setter)\n    : PStringDropdown(\"\", items, label), PWidgetHLIBase<P, std::string>((PWidget *)this, getter, setter)\n    {\n    }\n};\n"
  },
  {
    "path": "apps/vaporgui/PStringInput.cpp",
    "content": "#include \"PStringInput.h\"\n#include \"VLineItem.h\"\n#include <vapor/ParamsBase.h>\n#include \"VStringLineEdit.h\"\n\nPStringInput::PStringInput(const std::string &tag, const std::string &label) : PLineItem(tag, label, _stringLineEdit = new VStringLineEdit)\n{\n    connect(_stringLineEdit, &VStringLineEdit::ValueChanged, this, &PStringInput::inputValueChanged);\n}\n\nvoid PStringInput::updateGUI() const\n{\n    const string value = getParamsString();\n    _stringLineEdit->SetValueString(value);\n}\n\nvoid PStringInput::inputValueChanged(const std::string &v) { setParamsString(v); }\n"
  },
  {
    "path": "apps/vaporgui/PStringInput.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n//#include \"VaporWidgetsFwd.h\"\n\nclass VStringLineEdit;\n\n//! \\class PStringInput\n//! Creates a Qt text input for string values synced with the paramsdatabase using the PWidget interface.\n//! \\copydoc PWidget\n\nclass PStringInput : public PLineItem {\n    VStringLineEdit *_stringLineEdit;\n\npublic:\n    PStringInput(const std::string &tag, const std::string &label = \"\");\n\nprotected:\n    void updateGUI() const override;\n\nprivate:\n    void inputValueChanged(const std::string &v);\n};\n"
  },
  {
    "path": "apps/vaporgui/PTFEditor.cpp",
    "content": "#include \"PTFEditor.h\"\n#include <vapor/RenderParams.h>\n#include <vapor/GUIStateParams.h>\n#include \"TFColorWidget.h\"\n#include \"TFOpacityWidget.h\"\n#include \"TFHistogramWidget.h\"\n#include \"TFIsoValueWidget.h\"\n#include \"TFMappingRangeSelector.h\"\n#include \"TFMapGroupWidget.h\"\n#include \"VSection.h\"\n#include \"PDisplay.h\"\n#include \"mac_helpers.h\"\n\nusing VAPoR::RenderParams;\n\ntemplate<typename T> PTFMapWidget<T>::PTFMapWidget(const std::string &tag) : PWidget(tag, _tfWidget = new TFColorWidget(tag)) {}\n\ntemplate<typename T> void PTFMapWidget<T>::updateGUI() const\n{\n    RenderParams *rp = dynamic_cast<RenderParams *>(getParams());\n    VAssert(rp);\n\n    _tfWidget->Update(getDataMgr(), getParamsMgr(), rp);\n}\n\ntemplate class PTFMapWidget<TFColorWidget>;\ntemplate class PTFMapWidget<TFOpacityWidget>;\ntemplate class PTFMapWidget<TFHistogramWidget>;\ntemplate class PTFMapWidget<TFIsoValueWidget>;\n\nPTFEditor::PTFEditor() : PTFEditor(RenderParams::_variableNameTag) {}\n\nPTFEditor::PTFEditor(const std::string &tag, const std::set<Element> elements, const std::string &label, bool expandable) : PWidget(tag, _section = new VSection(label.empty() ? tag : label)), _expandable(expandable)\n{\n    setMaximumSize(1200,720);\n    _maps = new TFMapGroupWidget;\n    _histogram = new TFHistogramMap(tag);\n    _opacityMap = new TFOpacityMap(tag);\n    _colorMap = new TFColorMap(tag);\n    _isoMap = new TFIsoValueMap(tag);\n    _range = new TFMappingRangeSelector(tag);\n    _elements = elements;\n\n    _maps->Add({_opacityMap, _histogram});\n    _maps->Add(_isoMap);\n    _maps->Add(_colorMap);\n\n    _section->layout()->addWidget(_maps, 1);\n    _section->layout()->addWidget(_mapsInfo = _maps->CreateInfoGroup());\n    _section->layout()->addWidget(_range, 0);\n    connect(_range, SIGNAL(ValueChangedIntermediate(float, float)), _histogram, SLOT(update()));\n\n    int    start = 0;\n    QMenu *menu = new QMenu;\n    _colorMap->PopulateSettingsMenu(menu);\n    for (int i = start; i < menu->actions().size(); i++) _colorMapActions.push_back(menu->actions()[i]);\n\n    menu->addSeparator();\n\n    start = menu->actions().size();\n    _opacityMap->PopulateSettingsMenu(menu);\n    for (int i = start; i < menu->actions().size(); i++) _opacityMapActions.push_back(menu->actions()[i]);\n\n    menu->addSeparator();\n\n    start = menu->actions().size();\n    _histogram->PopulateSettingsMenu(menu);\n    for (int i = start; i < menu->actions().size(); i++) _histogramActions.push_back(menu->actions()[i]);\n\n    if (_expandable) {\n        _section->enableExpandedSection();\n        connect(_section, &VSection::expandButtonClicked, this, &PTFEditor::showExpandedPTFEditor);\n    }\n\n    _section->setMenu(menu);\n\n    _histogram->hide();\n    _opacityMap->hide();\n    _colorMap->hide();\n    _isoMap->hide();\n\n    if (elements.count(Opacity)) _opacityMap->show();\n    if (elements.count(Colormap)) _colorMap->show();\n    if (elements.count(Histogram)) _histogram->show();\n    if (elements.count(IsoValues) || elements.count(RegularIsoArray)) _isoMap->show();\n\n    if (elements.count(RegularIsoArray))\n        _isoMap->SetEquidistantIsoValues(true);\n    else\n        _isoMap->SetEquidistantIsoValues(false);\n\n    if (elements.count(Default)) {\n        _histogram->show();\n        _opacityMap->show();\n        _colorMap->show();\n        _isoMap->show();\n    }\n}\n\nPTFEditor *PTFEditor::ShowOpacityBasedOnParam(const std::string &tag, int value)\n{\n    _showOpacityBasedOnParam = true;\n    _showOpacityBasedOnParamTag = tag;\n    _showOpacityBasedOnParamValue = value;\n    return this;\n}\n\nPTFEditor *PTFEditor::ShowColormapBasedOnParam(const std::string &tag, int value)\n{\n    _showColormapBasedOnParam = true;\n    _showColormapBasedOnParamTag = tag;\n    _showColormapBasedOnParamValue = value;\n    return this;\n}\n\nvoid PTFEditor::updateGUI() const\n{\n    VAPoR::DataMgr *     dm = getDataMgr();\n    VAPoR::ParamsMgr *   pm = getParamsMgr();\n    VAPoR::RenderParams *rp = dynamic_cast<VAPoR::RenderParams *>(getParams());\n    VAssert(rp);\n\n    _maps->Update(dm, pm, rp);\n    _mapsInfo->Update(rp);\n    _range->Update(dm, pm, rp);\n\n    if (_showOpacityBasedOnParam) {\n        if (rp->GetValueLong(_showOpacityBasedOnParamTag, 0) == _showOpacityBasedOnParamValue)\n            _opacityMap->show();\n        else\n            _opacityMap->hide();\n    }\n\n    if (_showColormapBasedOnParam) {\n        if (rp->GetValueLong(_showColormapBasedOnParamTag, 0) == _showColormapBasedOnParamValue)\n            _colorMap->show();\n        else\n            _colorMap->hide();\n    }\n\n    for (auto a : _colorMapActions) a->setEnabled(_colorMap->IsShown());\n    for (auto a : _opacityMapActions) a->setEnabled(_opacityMap->IsShown());\n    for (auto a : _histogramActions) a->setEnabled(_histogram->IsShown());\n}\n\nvoid PTFEditor::Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr, VAPoR::DataMgr *dataMgr) {\n    if (getParams() != params) {\n        closeExpandedPTFEditor();\n    }\n    PWidget::Update(params, paramsMgr, dataMgr);\n    if (_expandable==true) {\n        std::string name, inst;\n        getExpandedPTFEditorInfo(name, inst);\n\n        if (_expandedPTFEditor!=nullptr) {\n            _expandedPTFEditor->setWindowTitle(QString::fromStdString(name));\n            _expandedPTFEditor->Update(params, paramsMgr, dataMgr);\n        }\n    }\n}\n\nvoid PTFEditor::getExpandedPTFEditorInfo(std::string &name, std::string& type) {\n    ParamsMgr* pm = getParamsMgr();\n    GUIStateParams* p = dynamic_cast<GUIStateParams *>(pm->GetParams(GUIStateParams::GetClassType()));\n    type = p->GetActiveRendererInst();\n    p->GetActiveRenderer(p->GetActiveVizName(), type, name);\n    if (dynamic_cast<PColormapTFEditor*>(this)) {\n        name+=\"_Colormap\";\n        type+=\"_Colormap\";\n    }\n}\n\nvoid PTFEditor::showExpandedPTFEditor() {\n    if (_expandedPTFEditor==nullptr) {\n        _expandedPTFEditor = new ExpandedPTFEditor(getTag(), _elements, _section->getTitle(), false);\n        connect(_expandedPTFEditor, SIGNAL(closed()), this, SLOT(closeExpandedPTFEditor()));\n\n        if (_showColormapBasedOnParam==true) _expandedPTFEditor->ShowColormapBasedOnParam(_showColormapBasedOnParamTag, _showColormapBasedOnParamValue);\n        if (_showOpacityBasedOnParam==true) _expandedPTFEditor->ShowOpacityBasedOnParam(_showOpacityBasedOnParamTag, _showOpacityBasedOnParamValue);\n\n        _expandedPTFEditor->setAttribute(Qt::WA_ShowWithoutActivating);\n        _expandedPTFEditor->setAttribute(Qt::WA_DeleteOnClose);\n    }\n    _expandedPTFEditor->raise();\n\n    Update(getParams(), getParamsMgr(), getDataMgr());\n}\n\nvoid PTFEditor::closeExpandedPTFEditor() {\n    if (_expandedPTFEditor != nullptr) {\n        _expandedPTFEditor->close();\n        _expandedPTFEditor=nullptr;\n    }\n}\n\nvoid PTFEditor::hideEvent(QHideEvent* event) {\n    closeExpandedPTFEditor();\n}\n\nPColormapTFEditor::PColormapTFEditor() : PTFEditor(RenderParams::_colorMapVariableNameTag, {PTFEditor::Histogram, PTFEditor::Colormap}, \"Colormap Transfer Function\") {}\n\nExpandedPTFEditor::ExpandedPTFEditor(const std::string &tag, const std::set<Element> elements, const std::string &label, bool expandable) : PTFEditor(tag, elements, label, expandable) {\n#ifdef Q_OS_MAC\n    DisableMacFullscreen(this);\n#endif\n}\n\nvoid ExpandedPTFEditor::closeEvent(QCloseEvent *event) {\n    emit closed();\n    QWidget::closeEvent(event);\n}\n"
  },
  {
    "path": "apps/vaporgui/PTFEditor.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n#include <set>\n\nclass TFMap;\nclass TFColorMap;\nclass TFOpacityMap;\nclass TFHistogramMap;\nclass TFIsoValueMap;\nclass TFMapWidget;\nclass TFColorWidget;\nclass TFOpacityWidget;\nclass TFHistogramWidget;\nclass TFIsoValueWidget;\n\n//! \\class PTFMapWidget\n//! Wrapper class that allows TFMapsWidgets to be used as PWidgets\n//! \\copydoc TFMapsWidget\n\ntemplate<typename T> class PTFMapWidget : public PWidget {\n    TFMapWidget *_tfWidget;\n\npublic:\n    PTFMapWidget(const std::string &tag);\n\nprotected:\n    virtual void updateGUI() const override;\n    virtual bool requireParamsMgr() const override { return true; }\n    virtual bool requireDataMgr() const override { return true; }\n};\n\ntypedef PTFMapWidget<TFColorWidget>     PTFColorWidget;\ntypedef PTFMapWidget<TFOpacityWidget>   PTFOpacityWidget;\ntypedef PTFMapWidget<TFHistogramWidget> PTFHistogramWidget;\ntypedef PTFMapWidget<TFIsoValueWidget>  PTFIsoValueWidget;\n\nclass VSection;\nclass TFMappingRangeSelector;\nclass TFMapGroupWidget;\nclass TFMapInfoGroupWidget;\nclass PStringDisplay;\n\n//! \\class PTFEditor\n//! PWidget wrapper for TFEditor\n//! \\copydoc TFEditor\n\nclass PTFEditor : public PWidget {\n    Q_OBJECT;\n\n    VSection *              _section;\n    TFMapGroupWidget *      _maps;\n    TFMapInfoGroupWidget *  _mapsInfo;\n    TFHistogramMap *        _histogram;\n    TFOpacityMap *          _opacityMap;\n    TFColorMap *            _colorMap;\n    TFIsoValueMap *         _isoMap;\n    TFMappingRangeSelector *_range;\n    PTFEditor*              _expandedPTFEditor = nullptr;\n    bool                    _expandable;\n\n    std::vector<QAction *> _colorMapActions;\n    std::vector<QAction *> _opacityMapActions;\n    std::vector<QAction *> _histogramActions;\n\n    bool        _showOpacityBasedOnParam = false;\n    std::string _showOpacityBasedOnParamTag;\n    int         _showOpacityBasedOnParamValue;\n    bool        _showColormapBasedOnParam = false;\n    std::string _showColormapBasedOnParamTag;\n    bool        _showColormapBasedOnParamValue;\n\npublic:\n    enum Element { Opacity, Histogram, Colormap, IsoValues, RegularIsoArray, Default };\n\n    PTFEditor();\n    PTFEditor(const std::string &tag, const std::set<Element> elements = {Default}, const std::string &label = \"Transfer Function\", bool expandable = true);\n    //! Behaves the same as PWidget::ShowBasedOnParam except shows/hides the opacity controls.\n    //! @copydoc PWidget::ShowBasedOnParam\n    PTFEditor *ShowOpacityBasedOnParam(const std::string &tag, int value);\n    //! Behaves the same as PWidget::ShowBasedOnParam except shows/hides the colormap controls.\n    //! @copydoc PWidget::ShowBasedOnParam\n    PTFEditor *ShowColormapBasedOnParam(const std::string &tag, int value);\n\nprotected:\n    std::set<Element> _elements;\n    std::string _label;\n\n    void hideEvent(QHideEvent *event) override;\n    void updateGUI() const override;\n    void Update(VAPoR::ParamsBase* p, VAPoR::ParamsMgr* pm, VAPoR::DataMgr* dm) override;\n    void getExpandedPTFEditorInfo(std::string &name, std::string &type);\n\nprivate slots:\n    void showExpandedPTFEditor();\n    void closeExpandedPTFEditor();\n};\n\nclass PColormapTFEditor : public PTFEditor {\npublic:\n    PColormapTFEditor();\n};\n\n//! \\class Expanded PTFEditor\n//! A sublcass of PTFEditor that emits a signal when closed\n//! \\copydoc PTFEditor\n\nclass ExpandedPTFEditor : public PTFEditor {\n    Q_OBJECT\n\npublic:\n    ExpandedPTFEditor(const std::string &tag, const std::set<Element> elements = {Default}, const std::string &label = \"Transfer Function\", bool expandable = false);\n\nsignals:\n    void closed();\n\nprotected:\n    void closeEvent(QCloseEvent *event) override;\n};\n\n"
  },
  {
    "path": "apps/vaporgui/PTMSLODInput.h",
    "content": "#pragma once\n\n#include <QFileDialog>\n#include \"vapor/ImageParams.h\"\n#include \"vapor/GeoImageTMS.h\"\n#include \"vapor/TMSUtils.h\"\n#include \"PGroup.h\"\n#include \"VComboBox.h\"\n\n//\n// PWidget for selecting TMS file level-of-detail\n//\n\nclass PTMSLODInput : public PLineItem {\n    Q_OBJECT\n    VComboBox *_vComboBox;\n\npublic:\n    PTMSLODInput() : PLineItem(\"\", \"TMS level of detail\", _vComboBox = new VComboBox({\"0\"}))\n    {\n        QString tooltip = \"TMS images can be displayed at varying resolutions.\\n\"\n                          \"This setting allows for manual resolution selection.\";\n        _vComboBox->setToolTip(tooltip);\n        connect(_vComboBox, &VComboBox::IndexChanged, this, &PTMSLODInput::dropdownIndexChanged);\n    }\n\nprotected:\n    virtual void updateGUI() const override\n    {\n        VAPoR::ImageParams *rp = dynamic_cast<VAPoR::ImageParams *>(getParams());\n        VAssert(rp && \"Params must be ImageParams\");\n\n        std::string imageFile = rp->GetImagePath();\n        if (Wasp::TMSUtils::IsTMSFile(imageFile)) {\n            _vComboBox->setEnabled(true);\n        } else {\n            _vComboBox->setEnabled(false);    // Disable if not using a TMS image\n            return;\n        }\n\n        std::vector<std::string> options{\"default\"};\n        int                      lods = rp->GetNumTMSLODs();\n        for (int i = 0; i < lods; i++) { options.push_back(std::to_string(i)); }\n        _vComboBox->SetOptions(options);\n        _vComboBox->SetIndex(rp->GetTMSLOD() + 1);\n    };\n\nprivate slots:\n    void dropdownIndexChanged(int i)\n    {\n        VAPoR::ImageParams *rp = dynamic_cast<VAPoR::ImageParams *>(getParams());\n        VAssert(rp && \"Params must be ImageParams\");\n        rp->SetTMSLOD(i - 1);\n    }\n};\n"
  },
  {
    "path": "apps/vaporgui/PTimeRangeSelector.cpp",
    "content": "#include \"PTimeRangeSelector.h\"\n#include \"vapor/ControlExecutive.h\"\n#include \"vapor/AnimationParams.h\"\n#include \"QRangeSliderTextCombo.h\"\n#include \"VLabelPair.h\"\n\n#include <cmath>\n\nPTimeRangeSelector::PTimeRangeSelector(ControlExec* ce) \n    : PWidget(\"\", \n        new VGroup({\n            _slider = new QRangeSliderTextCombo(),\n            _timeStampPair = new VLabelPair(),\n        })\n      ),\n      _ce(ce)\n{\n    _slider->SetNumDigits(0);\n    connect(_slider, SIGNAL(ValueChanged(float, float)), this, SLOT(setTimes(float, float)));\n}\n\nvoid PTimeRangeSelector::updateGUI() const {\n    _slider->SetRange(0, _ce->GetDataStatus()->GetTimeCoordinates().size()-1);\n\n    AnimationParams* ap = dynamic_cast<AnimationParams*>(getParams());\n    size_t start = ap->GetValueLong(AnimationParams::CaptureStartTag, ap->GetStartTimestep());\n    size_t end = ap->GetValueLong(AnimationParams::CaptureEndTag, ap->GetEndTimestep());\n    _slider->SetValue(start, end);\n\n    std::vector<std::string> timeCoords = _ce->GetDataStatus()->GetTimeCoordsFormatted();\n    _timeStampPair->SetLeftText(timeCoords[start]);\n    \n    _timeStampPair->SetRightText(timeCoords[end]);\n}\n\nvoid PTimeRangeSelector::setTimes(float start, float end) {\n    start = std::round(start);\n    end = std::round(end);\n    _slider->SetValue(start, end);\n\n    AnimationParams* ap = dynamic_cast<AnimationParams*>(getParams());\n    ap->SetValueLong(AnimationParams::CaptureStartTag, \"Set value for capturing imagery start time\", start);\n    ap->SetValueLong(AnimationParams::CaptureEndTag, \"Set value for capturing imagery end time\", end);\n}\n"
  },
  {
    "path": "apps/vaporgui/PTimeRangeSelector.h",
    "content": "#pragma once\n\n#include \"PGroup.h\"\n#include \"VContainer.h\"\n#include \"ParamsUpdatable.h\"\n#include \"VHBoxWidget.h\"\n\nnamespace VAPoR {\n    class ControlExec;\n}\nclass QRangeSliderTextCombo;\nclass VLabelPair;\nclass VLineItem;\n\n//! \\class PTimeRangeSelector\n//! \\brief A PWidget that maintains a TimeRangeSelector\n\nclass PTimeRangeSelector : public PWidget {\n    Q_OBJECT\n\n    ControlExec* _ce;\n    QRangeSliderTextCombo* _slider;\n    VLabelPair* _timeStampPair;\n\npublic:\n    PTimeRangeSelector(ControlExec* ce);\n    void updateGUI() const override;\n\nprivate slots:\n    void setTimes(float start, float end);\n};\n"
  },
  {
    "path": "apps/vaporgui/PTimestepInput.cpp",
    "content": "#include \"PTimestepInput.h\"\n#include <vapor/NavigationUtils.h>\n#include \"VIntSpinBox.h\"\n#include <vapor/AnimationParams.h>\n\n\nPTimestepInput::PTimestepInput(VAPoR::ControlExec *ce)\n: PWidget(\"\", _input = new VIntSpinBox(0, 1)), _ce(ce)\n{\n    connect(_input, &VIntSpinBox::ValueChangedIntermediate, this, &PTimestepInput::inputChanged);\n    _input->setMinimumWidth(40);\n}\n\n\nvoid PTimestepInput::updateGUI() const\n{\n    auto      p = NavigationUtils::GetAnimationParams(_ce);\n    const int start = p->GetStartTimestep();\n    const int end = p->GetEndTimestep();\n    const int ts = p->GetCurrentTimestep();\n\n//    int end = _ce->GetDataStatus()->GetTimeCoordinates().size() - 1;\n\n    _input->SetRange(start, end);\n    _input->SetValue(ts);\n}\n\n\nvoid PTimestepInput::inputChanged(int v) {\n    NavigationUtils::SetTimestep(_ce, v);\n}\n"
  },
  {
    "path": "apps/vaporgui/PTimestepInput.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nnamespace VAPoR {\nclass ControlExec;\n}\nclass VIntSpinBox;\n\n\nclass PTimestepInput : public PWidget {\n    VAPoR::ControlExec *_ce;\n    VIntSpinBox *       _input;\n\npublic:\n    PTimestepInput(VAPoR::ControlExec *ce);\n\nprotected:\n    void updateGUI() const override;\n    void inputChanged(int v);\n};\n"
  },
  {
    "path": "apps/vaporgui/PTimestepSliderEdit.cpp",
    "content": "#include \"PTimestepSliderEdit.h\"\n#include \"VLineItem.h\"\n#include <vapor/ParamsBase.h>\n#include \"VIntSliderEdit.h\"\n#include <vapor/AnimationParams.h>\n#include <vapor/NavigationUtils.h>\n\n// ===============================\n//       PTimestepSliderEdit\n// ===============================\n\nPTimestepSliderEdit::PTimestepSliderEdit(VAPoR::ControlExec *ce) : PLineItem(\"\", \"Current Timestep\", _sliderEdit = new VIntSliderEdit(0, 1, 0, false))\n{\n    _ce = ce;\n    connect(_sliderEdit, &VIntSliderEdit::ValueChanged, this, &PTimestepSliderEdit::valueChanged);\n}\n\nvoid PTimestepSliderEdit::updateGUI() const\n{\n    auto      p = NavigationUtils::GetAnimationParams(_ce);\n    const int start = p->GetStartTimestep();\n    const int end = p->GetEndTimestep();\n    const int ts = p->GetCurrentTimestep();\n\n    _sliderEdit->SetMinimum(start);\n    _sliderEdit->SetMaximum(end);\n    _sliderEdit->SetValue(ts);\n}\n\nvoid PTimestepSliderEdit::valueChanged(int v) { NavigationUtils::SetTimestep(_ce, v); }\n"
  },
  {
    "path": "apps/vaporgui/PTimestepSliderEdit.h",
    "content": "#pragma once\n\n#include \"PLineItem.h\"\n\nclass VIntSliderEdit;\n\nnamespace VAPoR {\nclass ControlExec;\n};\n\n//! \\class PTimestepSliderEdit\n//! Creates a timestep slider input\n\nclass PTimestepSliderEdit : public PLineItem {\n    VIntSliderEdit *    _sliderEdit;\n    VAPoR::ControlExec *_ce;\n\npublic:\n    PTimestepSliderEdit(VAPoR::ControlExec *ce);\n\nprotected:\n    void updateGUI() const override;\n\nprivate:\n    void valueChanged(int v);\n};\n"
  },
  {
    "path": "apps/vaporgui/PTotalTimestepsDisplay.cpp",
    "content": "#include \"PTotalTimestepsDisplay.h\"\n#include <vapor/ControlExecutive.h>\n#include \"VLabel.h\"\n\n\nPTotalTimestepsDisplay::PTotalTimestepsDisplay(VAPoR::ControlExec *ce) : PWidget(\"\", _label = new VLabel), _ce(ce) {}\n\n\nvoid PTotalTimestepsDisplay::updateGUI() const\n{\n    size_t totalTs = _ce->GetDataStatus()->GetTimeCoordinates().size();\n    _label->SetText(\"Total timesteps:   \" + std::to_string(totalTs));\n}\n"
  },
  {
    "path": "apps/vaporgui/PTotalTimestepsDisplay.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\nnamespace VAPoR {\nclass ControlExec;\n}\nclass VLabel;\n\n\nclass PTotalTimestepsDisplay : public PWidget {\n    VAPoR::ControlExec *_ce;\n    VLabel *            _label;\n\npublic:\n    PTotalTimestepsDisplay(VAPoR::ControlExec *ce);\n\nprotected:\n    void updateGUI() const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/PTransformWidget.cpp",
    "content": "#include \"PTransformWidget.h\"\n#include \"VSection.h\"\n#include \"V3DInput.h\"\n#include \"VLineItem.h\"\n#include <vapor/RenderParams.h>\n#include <QLabel>\n\nusing VAPoR::RenderParams;\nusing VAPoR::Transform;\n\nPTransformWidget::PTransformWidget() : PWidget(\"\", _group = new VGroup())\n{\n    _group->Add(new VLineItem(\"Translate\", _translate = new V3DInput));\n    _group->Add(new VLineItem(\"Scale      \", _scale = new V3DInput));\n    _group->Add(new VLineItem(\"Origin     \", _origin = new V3DInput));\n\n    QObject::connect(_translate, &V3DInput::ValueChangedVec, this, &PTransformWidget::translateChanged);\n    QObject::connect(_scale, &V3DInput::ValueChangedVec, this, &PTransformWidget::scaleChanged);\n    QObject::connect(_origin, &V3DInput::ValueChangedVec, this, &PTransformWidget::originChanged);\n}\n\nvoid PTransformWidget::updateGUI() const\n{\n    Transform *t = getParams<Transform>();\n\n    _translate->SetValue(t->GetTranslations());\n    _scale->SetValue(t->GetScales());\n    _origin->SetValue(t->GetOrigin());\n}\n\nvoid PTransformWidget::translateChanged(const std::vector<double> xyz) { getParams<Transform>()->SetTranslations(xyz); }\n\nvoid PTransformWidget::scaleChanged(const std::vector<double> xyz) { getParams<Transform>()->SetScales(xyz); }\n\nvoid PTransformWidget::originChanged(const std::vector<double> xyz) { getParams<Transform>()->SetOrigin(xyz); }\n\nPRendererTransformWidget::PRendererTransformWidget() : PWidget(\"\", _widget = new PTransformWidget) {}\n\nvoid PRendererTransformWidget::updateGUI() const\n{\n    RenderParams *rp = getParams<RenderParams>();\n    Transform *   t = rp->GetTransform();\n    _widget->Update(t, getParamsMgr(), getDataMgr());\n}\n\n\n#include \"PSection.h\"\n\nPRendererTransformSection::PRendererTransformSection() : PWidgetWrapper(new PSection(\"Transform\", {new PRendererTransformWidget})) {}\n"
  },
  {
    "path": "apps/vaporgui/PTransformWidget.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n#include <vector>\n\nclass V3DInput;\nclass VGroup;\nnamespace VAPoR {\nclass Transform;\n}\n\nclass PTransformWidget : public PWidget {\n    VGroup *       _group;\n    V3DInput *     _translate;\n    V3DInput *     _scale;\n    V3DInput *     _origin;\n\npublic:\n    PTransformWidget();\n\nprotected:\n    void updateGUI() const override;\n\nprivate:\n    void translateChanged(const std::vector<double> xyz);\n    void scaleChanged(const std::vector<double> xyz);\n    void originChanged(const std::vector<double> xyz);\n};\n\nclass PRendererTransformWidget : public PWidget {\n    PTransformWidget *_widget;\n\npublic:\n    PRendererTransformWidget();\n\nprotected:\n    void updateGUI() const override;\n};\n\n\n#include \"PWidgetWrapper.h\"\n\n\nclass PRendererTransformSection : public PWidgetWrapper {\npublic:\n    PRendererTransformSection();\n};\n"
  },
  {
    "path": "apps/vaporgui/PVariableSelector.cpp",
    "content": "#include \"PVariableSelector.h\"\n#include <vapor/RenderParams.h>\n#include <assert.h>\n\nusing VAPoR::Box;\nusing VAPoR::RenderParams;\ntypedef VAPoR::DataMgr::VarType VarType;\n\n#define NULL_TEXT \"<none>\"\n\nPVariableSelector::PVariableSelector(const std::string &tag, const std::string &label)\n: PStringDropdown(tag, {}, label) { setCustomBlankText(NULL_TEXT); }\n\nvoid PVariableSelector::updateGUI() const\n{\n    int nDims = getDimensionality();\n\n    auto varNames = getDataMgr()->GetDataVarNames(nDims, (VarType)getVarType());\n\n    if (_addNull || getParamsString().empty()) varNames.insert(varNames.begin(), NULL_TEXT);\n\n    SetItems(varNames);\n    PStringDropdown::updateGUI();\n}\n\nbool PVariableSelector::isShown() const\n{\n    if (_onlyShowForDim > 0) return getRendererDimension() == _onlyShowForDim;\n    return true;\n}\n\nint PVariableSelector::getVarType() const\n{\n    if (_showParticleVars)\n        return (int)VarType::Particle;\n    else\n        return (int)VarType::Scalar;\n}\n\nint PVariableSelector::getRendererDimension() const { return getParams<RenderParams>()->GetRenderDim(); }\n\nint PVariableSelector::getDimensionality() const { return getRendererDimension(); }\n\nvoid PVariableSelector::dropdownTextChanged(std::string text)\n{\n    if (_addNull && text == NULL_TEXT) text = \"\";\n\n    PStringDropdown::dropdownTextChanged(text);\n}\n\nPScalarVariableSelector::PScalarVariableSelector() : PVariableSelector(RenderParams::_variableNameTag, \"Variable Name\") {}\nPColorMapVariableSelector::PColorMapVariableSelector() : PVariableSelector(RenderParams::_colorMapVariableNameTag, \"Color mapped variable\") {}\nPHeightVariableSelector::PHeightVariableSelector() : PVariableSelector2D(RenderParams::_heightVariableNameTag, \"Height variable\")\n{\n    AddNullOption();\n    OnlyShowForDim(2);\n}\nPXFieldVariableSelector::PXFieldVariableSelector() : PVariableSelector(RenderParams::_xFieldVariableNameTag, \"X Field\") { AddNullOption(); }\nPYFieldVariableSelector::PYFieldVariableSelector() : PVariableSelector(RenderParams::_yFieldVariableNameTag, \"Y Field\") { AddNullOption(); }\nPZFieldVariableSelector::PZFieldVariableSelector() : PVariableSelector(RenderParams::_zFieldVariableNameTag, \"Z Field\") { AddNullOption(); }\n"
  },
  {
    "path": "apps/vaporgui/PVariableSelector.h",
    "content": "#pragma once\n\n#include \"PStringDropdown.h\"\n\n//! \\class PVariableSelector\n//! \\author Stas Jaroszynski\n//! Allows the user to select variables. Automatically switches between 2D and 3D\n//! based on the currently selected variable.\n//!\n//! Designed to be used with a RenderParams object.\n\nclass PVariableSelector : public PStringDropdown {\n    bool _addNull = false;\n    int  _onlyShowForDim = -1;\n    bool _showParticleVars = false;\n\npublic:\n    PVariableSelector(const std::string &tag, const std::string &label = \"\");\n    PVariableSelector *AddNullOption()\n    {\n        _addNull = true;\n        return this;\n    }\n    PVariableSelector *OnlyShowForDim(int dim)\n    {\n        _onlyShowForDim = dim;\n        return this;\n    }\n    PVariableSelector *ShowParticleVars()\n    {\n        _showParticleVars = true;\n        return this;\n    }\n\nprotected:\n    void         updateGUI() const override;\n    bool         isShown() const override;\n    bool         requireDataMgr() const override { return true; }\n    int          getVarType() const;\n    int          getRendererDimension() const;\n    virtual int  getDimensionality() const;\n    virtual void dropdownTextChanged(std::string text) override;\n};\n\n//! \\class PVariableSelector2D\n//! \\author Stas Jaroszynski\n//! 2D only version of PVariableSelector\n//! \\copydoc PVariableSelector\n\nclass PVariableSelector2D : public PVariableSelector {\npublic:\n    using PVariableSelector::PVariableSelector;\n\nprotected:\n    int getDimensionality() const override { return 2; }\n};\n\n//! \\class PVariableSelector3D\n//! \\author Stas Jaroszynski\n//! 3D only version of PVariableSelector\n//! \\copydoc PVariableSelector\n\nclass PVariableSelector3D : public PVariableSelector {\npublic:\n    using PVariableSelector::PVariableSelector;\n\nprotected:\n    int getDimensionality() const override { return 3; }\n};\n\nclass PScalarVariableSelector : public PVariableSelector {\npublic:\n    PScalarVariableSelector();\n};\nclass PColorMapVariableSelector : public PVariableSelector {\npublic:\n    PColorMapVariableSelector();\n};\nclass PHeightVariableSelector : public PVariableSelector2D {\npublic:\n    PHeightVariableSelector();\n};\nclass PXFieldVariableSelector : public PVariableSelector {\npublic:\n    PXFieldVariableSelector();\n};\nclass PYFieldVariableSelector : public PVariableSelector {\npublic:\n    PYFieldVariableSelector();\n};\nclass PZFieldVariableSelector : public PVariableSelector {\npublic:\n    PZFieldVariableSelector();\n};\n"
  },
  {
    "path": "apps/vaporgui/PVisualizerSelector.cpp",
    "content": "#include \"PVisualizerSelector.h\"\n#include \"VComboBox.h\"\n#include \"vapor/ParamsMgr.h\"\n#include \"vapor/GUIStateParams.h\"\n#ifndef NDEBUG\n    #include \"vapor/STLUtils.h\"\n#endif\n\nPVisualizerSelector::PVisualizerSelector()\n: PWidget(\"\", _dropdown = new VComboBox)\n{\n    connect(_dropdown, &VComboBox::ValueChanged, this, &PVisualizerSelector::dropdownTextChanged);\n}\n\nvoid PVisualizerSelector::updateGUI() const\n{\n    GUIStateParams *gsp = (GUIStateParams*)getParamsMgr()->GetParams(GUIStateParams::GetClassType());\n\n    auto options = getParamsMgr()->GetVisualizerNames();\n    options.push_back(\"New Visualizer\");\n    _dropdown->SetOptions(options);\n    _dropdown->SetValue(gsp->GetActiveVizName());\n\n#ifndef NDEBUG\n    if (!STLUtils::Contains(options, gsp->GetActiveVizName())) {\n        options.push_back(\"ERR: \\\"\" + gsp->GetActiveVizName() + \"\\\"\");\n        _dropdown->SetOptions(options);\n        _dropdown->SetValue(\"ERR: \\\"\" + gsp->GetActiveVizName() + \"\\\"\");\n    }\n#endif\n}\n\nvoid PVisualizerSelector::dropdownTextChanged(std::string text)\n{\n    GUIStateParams *gsp = (GUIStateParams*)getParamsMgr()->GetParams(GUIStateParams::GetClassType());\n\n    if (text == \"New Visualizer\") {\n        getParamsMgr()->BeginSaveStateGroup(\"New Visualizer\");\n        text = getParamsMgr()->CreateVisualizerParamsInstance();\n        gsp->SetActiveVizName(text);\n        getParamsMgr()->EndSaveStateGroup();\n    } else {\n        gsp->SetActiveVizName(text);\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/PVisualizerSelector.h",
    "content": "#pragma once\n#include \"PWidget.h\"\n\nclass VComboBox;\n\nclass PVisualizerSelector : public PWidget {\n    Q_OBJECT\n\n    VComboBox *_dropdown;\n\npublic:\n    PVisualizerSelector();\n\nprotected:\n    void updateGUI() const override;\n    bool requireParamsMgr() const override { return true; }\n\nprivate:\n    void dropdownTextChanged(std::string text);\n};\n"
  },
  {
    "path": "apps/vaporgui/PWidget.cpp",
    "content": "#include \"PWidget.h\"\n#include <assert.h>\n#include <vapor/VAssert.h>\n#include <vapor/ParamsBase.h>\n#include <vapor/ParamsMgr.h>\n#include <QHBoxLayout>\n#include <vapor/SettingsParams.h>\n\nPWidget::PWidget(const std::string &tag, QWidget *widget) : UWidget(widget), _tag(tag) { this->setDisabled(true); }\n\nvoid PWidget::Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr, VAPoR::DataMgr *dataMgr)\n{\n    _params = params;\n    _paramsMgr = paramsMgr;\n    _dataMgr = dataMgr;\n\n    if (_dynamicUpdateInsideGroup) return;\n\n    if (params == nullptr) {\n        this->setDisabled(true);\n        return;\n    }\n    if (requireDataMgr() && !dataMgr) VAssert(!\"Data manager required but missing\");\n    if (requireParamsMgr() && !paramsMgr) VAssert(!\"Params manager required but missing\");\n\n    bool paramsVisible = isShown();\n    if (paramsVisible && _showBasedOnParam) paramsVisible = _showBasedOnParamValue == params->GetValueLong(_showBasedOnParamTag, 0);\n    if (paramsVisible) {\n        setVisible(true);\n    } else {\n        setVisible(false);\n        return;\n    }\n\n    bool enabled = isEnabled();\n    if (enabled && _enableBasedOnParam)\n        enabled = params->GetValueLong(_enableBasedOnParamTag, 0) == _enableBasedOnParamValue;\n    setEnabled(enabled);\n\n    updateGUI();\n}\n\nconst std::string &PWidget::getTag() const { return _tag; }\n\nPWidget *PWidget::ShowBasedOnParam(const std::string &tag, int whenEqualTo)\n{\n    _showBasedOnParam = true;\n    _showBasedOnParamTag = tag;\n    _showBasedOnParamValue = whenEqualTo;\n    return this;\n}\n\nPWidget *PWidget::EnableBasedOnParam(const std::string &tag, int whenEqualTo)\n{\n    _enableBasedOnParam = true;\n    _enableBasedOnParamTag = tag;\n    _enableBasedOnParamValue = whenEqualTo;\n    return this;\n}\n\nPWidget *PWidget::SetTooltip(const std::string &text)\n{\n    QWidget::setToolTip(QString::fromStdString(text));\n    return this;\n}\n\nVAPoR::ParamsBase *PWidget::getParams() const { return _params; }\nVAPoR::ParamsMgr * PWidget::getParamsMgr() const { return _paramsMgr; }\nVAPoR::DataMgr *   PWidget::getDataMgr() const { return _dataMgr; }\n\nSettingsParams *PWidget::getSettingsParams() const\n{\n    VAssert(requireParamsMgr());\n    return (SettingsParams *)_paramsMgr->GetParams(SettingsParams::GetClassType());\n}\n\nvoid PWidget::setParamsDouble(double v)\n{\n    dynamicUpdateFinish();\n    _setParamsDouble(v);\n}\n\nvoid PWidget::setParamsLong(long v)\n{\n    dynamicUpdateFinish();\n    _setParamsLong(v);\n}\n\nvoid PWidget::setParamsString(const std::string &v)\n{\n    dynamicUpdateFinish();\n    _setParamsString(v);\n}\n\ndouble PWidget::getParamsDouble() const\n{\n    if (_usingHLI)\n        return _getterDouble(_params);\n    else\n        return _params->GetValueDouble(_tag, 0.0);\n}\n\nlong PWidget::getParamsLong() const\n{\n    if (_usingHLI)\n        return _getterLong(_params);\n    else\n        return _params->GetValueLong(_tag, 0);\n}\n\nstd::string PWidget::getParamsString() const\n{\n    if (_usingHLI)\n        return _getterString(_params);\n    else\n        return _params->GetValueString(_tag, \"\");\n}\n\nvoid PWidget::dynamicUpdateBegin()\n{\n    assert(_dynamicUpdateIsOn);\n    if (!_dynamicUpdateInsideGroup) {\n        getParams()->BeginGroup(getTag() + \" dynamic change\");\n        _dynamicUpdateInsideGroup = true;\n    }\n}\n\nvoid PWidget::dynamicUpdateFinish()\n{\n    if (_dynamicUpdateIsOn && _dynamicUpdateInsideGroup) {\n        getParams()->EndGroup();\n        _dynamicUpdateInsideGroup = false;\n    }\n}\n\nvoid PWidget::_setParamsDouble(double v)\n{\n    if (_usingHLI)\n        _setterDouble(_params, v);\n    else\n        getParams()->SetValueDouble(getTag(), \"\", v);\n}\n\nvoid PWidget::_setParamsLong(long v)\n{\n    if (_usingHLI)\n        _setterLong(_params, v);\n    else\n        getParams()->SetValueLong(getTag(), \"\", v);\n}\n\nvoid PWidget::_setParamsString(const std::string &v)\n{\n    if (_usingHLI)\n        _setterString(_params, v);\n    else\n        getParams()->SetValueString(getTag(), \"\", v);\n}\n"
  },
  {
    "path": "apps/vaporgui/PWidget.h",
    "content": "#pragma once\n\n#include <string>\n#include <functional>\n#include \"UWidget.h\"\n#include <vapor/VAssert.h>\n#include <common.h>\n\n//! \\class PWidget\n//! A Qt Widget that is automatically synced with the Params database.\n//! The Update method must be called as per Vapor's convensions\n//! All other public methods are self-explanitory. To see a demo and example\n//! of how to use these widgets, see ParamsWidgetDemo\n\nclass PWidget : public UWidget {\n    Q_OBJECT\n\n    VAPoR::ParamsBase *_params = nullptr;\n    VAPoR::ParamsMgr * _paramsMgr = nullptr;\n    VAPoR::DataMgr *   _dataMgr = nullptr;\n    const std::string  _tag;\n\n    bool        _showBasedOnParam = false;\n    std::string _showBasedOnParamTag = \"\";\n    int         _showBasedOnParamValue;\n\n    bool        _enableBasedOnParam = false;\n    std::string _enableBasedOnParamTag = \"\";\n    int         _enableBasedOnParamValue;\n\n    bool _dynamicUpdateIsOn = false;\n    bool _dynamicUpdateInsideGroup = false;\n\n    bool                                             _usingHLI = false;\n    std::function<void(void *, long)>                _setterLong;\n    std::function<long(void *)>                      _getterLong;\n    std::function<void(void *, double)>              _setterDouble;\n    std::function<double(void *)>                    _getterDouble;\n    std::function<void(void *, const std::string &)> _setterString;\n    std::function<std::string(void *)>               _getterString;\n\npublic:\n    PWidget(const std::string &tag, QWidget *widget);\n    //! Follows the Vapor GUI update function convention. Update the element.\n    void Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr = nullptr, VAPoR::DataMgr *dataMgr = nullptr) override;\n\n    //! tag must be a key referencing a long value in the Params Database. If the associated value is equal\n    //! to whenEqualTo, the current widget will be shown/enabled, and hidden/disabled otherwise.\n    PWidget *ShowBasedOnParam(const std::string &tag, int whenEqualTo = true);\n    //! @copydoc PWidget::ShowBasedOnParam()\n    PWidget *EnableBasedOnParam(const std::string &tag, int whenEqualTo = true);\n    //! Wrapping QWidget::setToolTip in case we want to add additional functionality such as automatic tool-tips\n    //! without having to refactor.\n    PWidget *SetTooltip(const std::string &text);\n    void     setToolTip(const QString &) = delete;\n\nprotected:\n    virtual void updateGUI() const = 0;\n    virtual bool requireParamsMgr() const { return false; }\n    virtual bool requireDataMgr() const { return false; }\n    virtual bool isShown() const { return true; }\n    virtual bool isEnabled() const { return true; }\n\n    const std::string &getTag() const;\n    VAPoR::ParamsBase *getParams() const;\n    VAPoR::ParamsMgr * getParamsMgr() const;\n    VAPoR::DataMgr *   getDataMgr() const;\n    SettingsParams *   getSettingsParams() const;\n\n    void        setParamsDouble(double v);\n    void        setParamsLong(long v);\n    void        setParamsString(const std::string &v);\n    double      getParamsDouble() const;\n    long        getParamsLong() const;\n    std::string getParamsString() const;\n\nprivate:\n    void dynamicUpdateBegin();\n    void dynamicUpdateFinish();\n    void _setParamsDouble(double v);\n    void _setParamsLong(long v);\n    void _setParamsString(const std::string &v);\n\n    friend class PDynamicMixin;\n    template<class, typename> friend class PWidgetHLIBase;\n\nprotected:\n    template<class T> T *getParams() const\n    {\n        T *p = dynamic_cast<T *>(getParams());\n        VAssert(p);\n        return p;\n    }\n};\n"
  },
  {
    "path": "apps/vaporgui/PWidgetHLI.h",
    "content": "#pragma once\n\n//! Creates the framework for creating Params Widgets that use the Params Database high level interface.\n\n#define CreateHLIBase(T, LT)                                                \\\n    template<class P> class PWidgetHLIBase<P, T> {                          \\\n    protected:                                                              \\\n        typedef std::function<T(P *)>       GetterType;                     \\\n        typedef std::function<void(P *, T)> SetterType;                     \\\n                                                                            \\\n    public:                                                                 \\\n        PWidgetHLIBase(PWidget *w, GetterType getter, SetterType setter)    \\\n        {                                                                   \\\n            w->_usingHLI = true;                                            \\\n            w->_setter##LT = [setter](void *p, T v) { setter((P *)p, v); }; \\\n            w->_getter##LT = [getter](void *p) { return getter((P *)p); };  \\\n        }                                                                   \\\n    };\n\n#define CreateInferredTemplateConstructor(className, T, constModifier) \\\n    template<class P> className##HLI<P> *new_##className##HLI(const std::string &label, T (P::*getter)() constModifier, void (P::*setter)(T)) { return new className##HLI<P>(label, getter, setter); }\n\n#define CreateHLI(className, T)                                                                                                                      \\\n    template<class P> class className##HLI final : public className, public PWidgetHLIBase<P, T> {                                                   \\\n    public:                                                                                                                                          \\\n        className##HLI(const std::string &label, typename PWidgetHLIBase<P, T>::GetterType getter, typename PWidgetHLIBase<P, T>::SetterType setter) \\\n        : className(\"\", label), PWidgetHLIBase<P, T>((PWidget *)this, getter, setter)                                                                \\\n        {                                                                                                                                            \\\n        }                                                                                                                                            \\\n    };                                                                                                                                               \\\n    CreateInferredTemplateConstructor(className, T, );                                                                                               \\\n    CreateInferredTemplateConstructor(className, T, const);\n\nCreateHLIBase(long, Long);\nCreateHLIBase(bool, Long);\nCreateHLIBase(int, Long);\nCreateHLIBase(double, Double);\nCreateHLIBase(float, Double);\nCreateHLIBase(std::string, String);\n\n//\n// My attempt at implementing this using purely function templates and no defines. Below is pretty close.\n// It works but requires too much specilization code so I stopped working on it for now.\n//\n\n#ifdef SAVED_FOR_LATER\ntemplate<class Base, class Derived> void AssertInheritance() { (void)static_cast<Base *>((Derived *)0); }\n\ntemplate<class PW, typename T, class P, typename... Args> class PWidgetHLI : public PW {\n    typedef std::function<T(P *)>       GetterType;\n    typedef std::function<void(P *, T)> SetterType;\n\n    GetterType _getter;\n    SetterType _setter;\n\npublic:\n    PWidgetHLI(std::string label, Args... args, GetterType getter, SetterType setter) : PW(\"\", args..., label)\n    {\n        printf(\"PWidgetHLI Constructor (%s)\\n\", label.c_str());\n        AssertInheritance<PWidget, PW>();\n        AssertInheritance<VAPoR::ParamsBase, P>();\n\n        this->_usingHLI = true;\n\n        this->_getter = getter;\n        this->_setter = setter;\n    }\n\n    virtual long getParamsLong() const override\n    {\n        static_assert(std::is_convertible<T, long>(), \"\");\n        //        return this->_getterLong(this->getParams());\n        return this->_getter((P *)this->getParams());\n    }\n\n    virtual void _setParamsLong(long v) override\n    {\n        static_assert(std::is_convertible<T, long>(), \"\");\n        //        return this->_setterLong(this->getParams(), v);\n        this->_setter((P *)this->getParams(), v);\n    }\n\n    //    template <typename=typename std::enable_if<std::is_convertible<T, std::string>::type>>\n    virtual std::string getParamsString() const override\n    {\n        static_assert(std::is_convertible<T, std::string>(), \"\");\n        //        return this->_getterLong(this->getParams());\n        return this->_getter((P *)this->getParams());\n    }\n\n    virtual void _setParamsString(const std::string &v) override\n    {\n        static_assert(std::is_convertible<T, std::string>(), \"\");\n        //        return this->_setterLong(this->getParams(), v);\n        this->_setter((P *)this->getParams(), v);\n    }\n};\n\ntemplate<class PW, typename T, class P, typename... Args> class PWidgetHLI2 : public PWidgetHLI<PW, T, P, Args...> {\n    using PWidgetHLI<PW, T, P, Args...>::PWidgetHLI;\n};\n\ntemplate<class PW, class P, typename... Args> class PWidgetHLI2<PW, std::string, P, Args...> : public PWidgetHLI<PW, std::string, P, Args...> {\n    using PWidgetHLI<PW, std::string, P, Args...>::PWidgetHLI;\n    virtual std::string getParamsString() const override {}\n};\n\ntemplate<class PW, typename T, class P, typename... Args> typename std::enable_if<std::is_same<T, bool>::value, T>::type class PWidgetHLI2 : public PWidgetHLI<PW, T, P, Args...> {\n    virtual long getParamsLong() const override {}\n};\n\n// template <class PW, class P, typename... Args>\n// class PWidgetHLI2<PW, std::string, P, Args...> : public PWidgetHLI<PW, std::string, P, Args...> {\n\n//\n//};\n#endif\n"
  },
  {
    "path": "apps/vaporgui/PWidgetWrapper.cpp",
    "content": "#include \"PWidgetWrapper.h\"\n\nPWidgetWrapper::PWidgetWrapper(PWidget *p) : PWidgetWrapper(\"\", p) {}\n\nPWidgetWrapper::PWidgetWrapper(std::string tag, PWidget *p) : PWidget(tag, _child = p) {}\n\nvoid PWidgetWrapper::updateGUI() const { _child->Update(getWrappedParams(), getParamsMgr(), getDataMgr()); }\n\nVAPoR::ParamsBase *PWidgetWrapper::getWrappedParams() const { return getParams(); }\n"
  },
  {
    "path": "apps/vaporgui/PWidgetWrapper.h",
    "content": "#pragma once\n\n#include \"PWidget.h\"\n\n//! \\class PWidgetWrapper\n//! \\brief Provides a streamlined interface for a PWidget that wraps another PWidget.\n//! \\author Stas Jaroszynski\n\nclass PWidgetWrapper : public PWidget {\n    PWidget *_child;\n\npublic:\n    PWidgetWrapper(PWidget *p);\n    PWidgetWrapper(std::string tag, PWidget *p);\n\nprotected:\n    void updateGUI() const override;\n    virtual VAPoR::ParamsBase *getWrappedParams() const;\n};\n"
  },
  {
    "path": "apps/vaporgui/PWidgets.h",
    "content": "#pragma once\n\n#include \"PWidgetsFwd.h\"\n#include \"PTransformWidget.h\"\n#include \"PAnnotationColorbarWidget.h\"\n#include \"PButton.h\"\n#include \"PCheckbox.h\"\n#include \"PColorSelector.h\"\n#include \"PCopyRegionWidget.h\"\n#include \"PDisplay.h\"\n#include \"PDoubleInput.h\"\n#include \"PEnumDropdown.h\"\n#include \"PFidelitySection.h\"\n#include \"PFileSelector.h\"\n#include \"PGeometrySubtab.h\"\n#include \"PGroup.h\"\n#include \"PIntegerInput.h\"\n#include \"PLabel.h\"\n#include \"PMultiVarSelector.h\"\n#include \"POrientationSelector.h\"\n#include \"PRegionSelector.h\"\n#include \"PSection.h\"\n#include \"PSliderEdit.h\"\n#include \"PStringDropdown.h\"\n#include \"PStringInput.h\"\n#include \"PTFEditor.h\"\n#include \"PShowIf.h\"\n#include \"PDimensionSelector.h\"\n#include \"PVariableSelector.h\"\n"
  },
  {
    "path": "apps/vaporgui/PWidgetsFwd.h",
    "content": "#pragma once\n\nclass PWidget;\nclass PTransformWidget;\nclass PAnnotationColorbarWidget;\nclass PButton;\nclass PCheckbox;\nclass PColorSelector;\nclass PCopyRegionWidget;\nclass PDisplay;\nclass PDoubleInput;\nclass PEnumDropdown;\nclass PFidelitySection;\nclass PFileSelector;\nclass PGeometrySubtab;\nclass PGroup;\nclass PIntegerInput;\nclass PLabel;\nclass PMultiVarSelector;\nclass POrientationSelector;\nclass PRegionSelector;\nclass PSection;\nclass PSliderEdit;\nclass PStringDropdown;\nclass PStringInput;\nclass PTFEditor;\nclass PVariableWidgets;\nclass PShowIf;\n"
  },
  {
    "path": "apps/vaporgui/ParamsMenuItems.cpp",
    "content": "#include \"ParamsMenuItems.h\"\n#include <QMenu>\n#include <vapor/ParamsBase.h>\n\nusing namespace VAPoR;\n\n// ******************************\n//        ParamsMenuItem\n// ******************************\n\nParamsMenuItem::ParamsMenuItem(QObject *parent, const std::string &tag, const std::string &label) : QAction(parent)\n{\n    assert(!tag.empty());\n    _tag = tag;\n\n    if (label.empty())\n        _label = tag;\n    else\n        _label = label;\n\n    setText(QString::fromStdString(_label));\n}\n\n// ******************************\n//     ParamsCheckboxMenuItem\n// ******************************\n\nParamsCheckboxMenuItem::ParamsCheckboxMenuItem(QObject *parent, const std::string &tag, const std::string &label) : ParamsMenuItem(parent, tag, label)\n{\n    this->setCheckable(true);\n    connect(this, SIGNAL(toggled(bool)), this, SLOT(wasToggled(bool)));\n}\n\nvoid ParamsCheckboxMenuItem::Update(VAPoR::ParamsBase *p)\n{\n    _params = p;\n    blockSignals(true);\n    setChecked(p->GetValueLong(_tag, 0));\n    blockSignals(false);\n}\n\nvoid ParamsCheckboxMenuItem::wasToggled(bool b)\n{\n    if (_params) _params->SetValueLong(_tag, _tag, b);\n}\n\n// ******************************\n//     ParamsDropdownMenuItem\n// ******************************\n\nParamsDropdownMenuItem::ParamsDropdownMenuItem(QObject *parent, const std::string &tag, const std::vector<std::string> &items, const std::vector<int> &itemValues, const std::string &labelText)\n: ParamsMenuItem(parent, tag, labelText)\n{\n    QMenu *menu = new QMenu;\n\n    for (string item : items) {\n        QAction *action = menu->addAction(QString::fromStdString(item), this, SLOT(itemSelected()));\n        action->setCheckable(true);\n        _items.push_back(action);\n    }\n\n    if (!itemValues.empty()) {\n        assert(itemValues.size() == items.size());\n        _itemValues = itemValues;\n    }\n\n    this->setMenu(menu);\n}\n\nvoid ParamsDropdownMenuItem::Update(VAPoR::ParamsBase *p)\n{\n    _params = p;\n\n    int value = p->GetValueLong(_tag, 0);\n    _selectIndex(_getIndexForValue(value));\n}\n\nvoid ParamsDropdownMenuItem::itemSelected()\n{\n    if (!_params) return;\n\n    int index = -1;\n    for (int i = 0; i < _items.size(); i++) {\n        if (_items[i] == sender()) {\n            index = i;\n            break;\n        }\n    }\n\n    VAssert(index != -1);\n\n    _selectIndex(index);\n    _params->SetValueLong(_tag, _tag, _getValueForIndex(index));\n}\n\nvoid ParamsDropdownMenuItem::_selectIndex(int index)\n{\n    assert(index >= 0 && index < _items.size());\n    if (!(index >= 0 && index < _items.size())) return;\n\n    for (int i = 0; i < _items.size(); i++) _items[i]->setChecked(false);\n    _items[index]->setChecked(true);\n}\n\nint ParamsDropdownMenuItem::_getValueForIndex(int index) const\n{\n    if (_itemValues.empty()) return index;\n\n    if (index >= _itemValues.size() || index < 0) VAssert(\"Invalid menu index\");\n\n    return _itemValues[index];\n}\n\nint ParamsDropdownMenuItem::_getIndexForValue(int value) const\n{\n    if (_itemValues.empty()) return value;\n\n    const int N = _itemValues.size();\n    for (int i = 0; i < N; i++)\n        if (_itemValues[i] == value) return i;\n\n    VAssert(\"Invalid params value\");\n    return -1;\n}\n"
  },
  {
    "path": "apps/vaporgui/ParamsMenuItems.h",
    "content": "#pragma once\n\n#include <vector>\n#include <cassert>\n#include <QAction>\n\nnamespace VAPoR {\nclass ParamsBase;\n}\n\n// ******************************\n//        ParamsMenuItem\n// ******************************\n\n//! \\class ParamsMenuItem\n//! Provides the same functionality as ParamsWidget except inside of a QMenu\n\nclass ParamsMenuItem : public QAction {\n    Q_OBJECT\n\npublic:\n    ParamsMenuItem(QObject *parent, const std::string &tag, const std::string &label = \"\");\n    virtual void Update(VAPoR::ParamsBase *p) = 0;\n\nprotected:\n    VAPoR::ParamsBase *_params = nullptr;\n    std::string        _tag;\n    std::string        _label;\n};\n\n// ******************************\n//     ParamsCheckboxMenuItem\n// ******************************\n\nclass ParamsCheckboxMenuItem : public ParamsMenuItem {\n    Q_OBJECT\n\npublic:\n    ParamsCheckboxMenuItem(QObject *parent, const std::string &tag, const std::string &label = \"\");\n    void Update(VAPoR::ParamsBase *p);\n\nprivate slots:\n    void wasToggled(bool b);\n};\n\n// ******************************\n//     ParamsDropdownMenuItem\n// ******************************\n\nclass ParamsDropdownMenuItem : public ParamsMenuItem {\n    Q_OBJECT\n\n    std::vector<int>       _itemValues;\n    std::vector<QAction *> _items;\n\npublic:\n    ParamsDropdownMenuItem(QObject *parent, const std::string &tag, const std::vector<std::string> &items, const std::vector<int> &itemValues = {}, const std::string &label = \"\");\n    void Update(VAPoR::ParamsBase *p);\n\nprivate:\n    void _selectIndex(int index);\n    int  _getValueForIndex(int index) const;\n    int  _getIndexForValue(int value) const;\n\nprivate slots:\n    void itemSelected();\n};\n"
  },
  {
    "path": "apps/vaporgui/ParamsUpdatable.cpp",
    "content": "#include \"ParamsUpdatable.h\"\n"
  },
  {
    "path": "apps/vaporgui/ParamsUpdatable.h",
    "content": "#pragma once\n\nnamespace VAPoR {\nclass ParamsBase;\nclass ParamsMgr;\nclass DataMgr;\n}    // namespace VAPoR\n\n//! \\class ParamsUpdatable\n//! \\brief Provides an interface that standardizes objects that support params updates.\n//! \\author Stas Jaroszynski\n\nclass ParamsUpdatable {\npublic:\n    virtual void Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr = nullptr, VAPoR::DataMgr *dataMgr = nullptr) = 0;\n};\n"
  },
  {
    "path": "apps/vaporgui/ParamsWidgetDemo.cpp",
    "content": "#include \"ParamsWidgetDemo.h\"\n#include <vapor/VAssert.h>\n#include <vapor/ParamsBase.h>\n#include <vapor/ParamsMgr.h>\n#include <QVBoxLayout>\n#include <vapor/GUIStateParams.h>\n\n#include \"PGroup.h\"\n#include \"PSection.h\"\n#include \"PCheckbox.h\"\n#include \"PIntegerInput.h\"\n#include \"PDoubleInput.h\"\n#include \"PSliderEdit.h\"\n#include \"PFileSelector.h\"\n#include \"PDisplay.h\"\n#include \"PColorSelector.h\"\n#include \"PEnumDropdown.h\"\n#include \"PStringDropdown.h\"\n#include \"PFileSelectorHLI.h\"\n#include \"PEnumDropdownHLI.h\"\n\nParamsWidgetDemo::ParamsWidgetDemo()\n{\n    setWindowTitle(\"Params Widget Demo\");\n    setLayout(new QVBoxLayout);\n    layout()->addWidget(pg = new PGroup);\n\n    PSection *section;\n\n    section = new PSection(\"Numbers\");\n    section->Add(new PIntegerInput(\"demo_int\", \"PIntegerInput\"));\n    section->Add(new PDoubleInput(\"demo_double\", \"PDoubleInput\"));\n    section->Add((new PIntegerSliderEdit(\"demo_int\", \"PIntegerSliderEdit\"))->SetRange(0, 100));\n    section->Add((new PDoubleSliderEdit(\"demo_double\", \"Dynamic Double\"))->EnableDynamicUpdate());\n    pg->Add(section);\n\n    section = new PSection(\"Files\");\n    section->Add(new PFileOpenSelector(\"demo_path\", \"Open File\"));\n    section->Add(new PFileSaveSelector(\"demo_path\", \"Save File\"));\n    section->Add(new PDirectorySelector(\"demo_path\", \"Select Directory\"));\n    pg->Add(section);\n\n    section = new PSection(\"Show or Enable\");\n    section->Add(new PCheckbox(\"demo_bool\", \"Enable Dropdown\"));\n    section->Add((new PEnumDropdown(\"demo_drop\", {\"Double Input\", \"Color Input\"}, {}, \"Show Widget\"))->EnableBasedOnParam(\"demo_bool\"));\n    section->Add((new PDoubleSliderEdit(\"demo_double\", \"Double\"))->ShowBasedOnParam(\"demo_drop\", 0));\n    section->Add((new PColorSelector(\"demo_color\", \"Color\"))->ShowBasedOnParam(\"demo_drop\", 1));\n    pg->Add(section);\n\n    section = new PSection(\"Other\");\n    section->Add(new PColorSelector(\"demo_color\", \"Color\"));\n    section->Add(new PStringDropdown(\"demo_path\", {\"One\", \"Two\", \"Three\"}, \"String Dropdown\"));\n    section->Add(new PStringDropdown(\"demo_var\", {\"Automatically\", \"presents\", \"2D or 3D\", \"Variables\", \"----------\", \"Only works for\", \"RenderParams\", \"so cannot\", \"demo\"}, \"PVariableSelector\"));\n    section->Add((new PCheckbox(\"demo_bool\", \"Tooltips\"))->SetTooltip(\"This is a tooltip\"));\n    pg->Add(section);\n\n    section = new PSection(\"Labels\");\n    section->Add(new PIntegerDisplay(\"demo_int\", \"PIntegerDisplay\"));\n    section->Add(new PDoubleDisplay(\"demo_double\", \"PDoubleDisplay\"));\n    section->Add(new PStringDisplay(\"demo_path\", \"PStringDisplay\"));\n    section->Add(new PBooleanDisplay(\"demo_bool\", \"PBooleanDisplay\"));\n    pg->Add(section);\n\n    section = new PSection(\"High Level Interface\");\n    section->Add(new_PDirectorySelectorHLI(\"Image Output Dir\", &GUIStateParams::GetCurrentImagePath, &GUIStateParams::SetCurrentImagePath));\n    section->Add(new PEnumDropdownHLI<GUIStateParams>(\"Flow Dimensions\", {\"2\", \"3\"}, {2, 3}, &GUIStateParams::GetFlowDimensionality, &GUIStateParams::SetFlowDimensionality));\n    pg->Add(section);\n}\n\nvoid ParamsWidgetDemo::Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr, VAPoR::DataMgr *dataMgr) { pg->Update(params, paramsMgr); }\n"
  },
  {
    "path": "apps/vaporgui/ParamsWidgetDemo.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include \"ParamsUpdatable.h\"\n\nnamespace VAPoR {\nclass ParamsBase;\nclass ParamsMgr;\nclass DataMgr;\n}    // namespace VAPoR\n\nclass PGroup;\n\n//! \\class ParamsWidgetDemo\n//! Shows a demo kitchen sink for Params Widgets\n//! To view, from the menu bar press Developer > Show PWidget Demo\n\nclass ParamsWidgetDemo : public QWidget, public ParamsUpdatable {\n    Q_OBJECT\n\n    PGroup *pg;\n\npublic:\n    ParamsWidgetDemo();\n    void Update(VAPoR::ParamsBase *params, VAPoR::ParamsMgr *paramsMgr = nullptr, VAPoR::DataMgr *dataMgr = nullptr);\n};\n"
  },
  {
    "path": "apps/vaporgui/ParticleEventRouter.cpp",
    "content": "#include \"ParticleEventRouter.h\"\n#include \"vapor/BarbParams.h\"\n#include \"PWidgets.h\"\n#include \"PConstantColorWidget.h\"\n#include \"PCheckbox.h\"\n\nusing namespace VAPoR;\n\nstatic RenderEventRouterRegistrar<ParticleEventRouter> registrar(ParticleEventRouter::GetClassType());\n\nstruct PParticleRadiusVariableSelector : public PVariableSelector {\n    PParticleRadiusVariableSelector()\n    : PVariableSelector(ParticleParams::RenderRadiusVariableTag, \"Particle Radius Scalar\") {\n        AddNullOption();\n        ShowParticleVars();\n    }\n};\n\nParticleEventRouter::ParticleEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, BarbParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            (new PScalarVariableSelector)->ShowParticleVars(),\n            (new PXFieldVariableSelector)->ShowParticleVars(),\n            (new PYFieldVariableSelector)->ShowParticleVars(),\n            (new PZFieldVariableSelector)->ShowParticleVars(),\n            (new PParticleRadiusVariableSelector()),\n        }),\n        new PSection(\"Data Fidelity\", {\n            (new PIntegerInput(ParticleParams::StrideTag, \"Stride\"))->SetRange(1, 1000)\n        }),\n    }));\n\n    AddAppearanceSubtab(new PGroup({\n        new PTFEditor,\n            new PSection(\"Particles\", {\n                (new PDoubleSliderEdit(ParticleParams::RenderRadiusScalarTag, \"Radius\"))->SetRange(0.5, 25)->AllowUserRange(true)->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false),\n                (new PParticleRadiusVariableSelector()),\n//                (new PShowIf(ParticleParams::RenderRadiusVariableTag))->Not()->Equals(\"\")->Then({\n//                    (new PDoubleSliderEdit(ParticleParams::RenderRadiusVariableStrengthTag, \"Radius Variable Strength\"))->SetRange(0.001, 1)->AllowUserRange(true)->EnableDynamicUpdate()\n//                }),\n                (new PButton(\"Recalculate Base Radius\", [](ParamsBase *p){ p->SetValueLong(ParticleParams::RecalculateRadiusBaseRequestTag, \"\", true); })),\n                new PCheckbox(ParticleParams::ShowDirectionTag, \"Show direction\"),\n                    (new PDoubleSliderEdit(ParticleParams::DirectionScaleTag, \"Length scale\"))->SetRange(0.0001, 10)->AllowUserRange(true)->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::ShowDirectionTag),\n                    (new PXFieldVariableSelector)->ShowParticleVars()->EnableBasedOnParam(ParticleParams::ShowDirectionTag),\n                    (new PYFieldVariableSelector)->ShowParticleVars()->EnableBasedOnParam(ParticleParams::ShowDirectionTag),\n                    (new PZFieldVariableSelector)->ShowParticleVars()->EnableBasedOnParam(ParticleParams::ShowDirectionTag),\n            }),\n            new PSection(\"Lighting\", {\n                (new PCheckbox(ParticleParams::LightingEnabledTag,\"Enable Lighting\"))->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false),\n                (new PDoubleSliderEdit(ParticleParams::PhongAmbientTag,   \"Ambient\"  ))->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false),\n                (new PDoubleSliderEdit(ParticleParams::PhongDiffuseTag,   \"Diffuse\"  ))->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false),\n                (new PDoubleSliderEdit(ParticleParams::PhongSpecularTag,  \"Specular\" ))->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false),\n                (new PDoubleSliderEdit(ParticleParams::PhongShininessTag, \"Shininess\"))->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false)\n            }),\n            new PSection(\"Legacy code\", {\n                new PCheckbox(ParticleParams::RenderLegacyTag,\"Enable legacy renderer\")\n            }),\n    }));\n    \n    AddGeometrySubtab(new PGeometrySubtab);\n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nstring ParticleEventRouter::_getDescription() const { return (\"Render particle data\"); }\n"
  },
  {
    "path": "apps/vaporgui/ParticleEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include \"vapor/ParticleRenderer.h\"\n\n//! \\class ParticleEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Particle renderer GUI\n//! \\author Stas Jaroszynski\n\nclass ParticleEventRouter : public RenderEventRouterGUI {\npublic:\n    ParticleEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::ParticleRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return false; }\n    bool          Supports3DVariables() const { return false; }\n    bool          SupportsParticleVariables() const { return true; }\n\nprotected:\n    virtual string _getDescription() const;\n    virtual string _getSmallIconImagePath() const { return \"Particles_small.png\"; }\n    virtual string _getIconImagePath() const { return \"Particles.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/Plot.cpp",
    "content": "//************************************************************************\n//                                                                      *\n//           Copyright (C)  2016                                        *\n//     University Corporation for Atmospheric Research                  *\n//           All Rights Reserved                                        *\n//                                                                      *\n//************************************************************************/\n//\n//  Author:     Samuel Li\n//              National Center for Atmospheric Research\n//              PO 3000, Boulder, Colorado\n//\n//  Date:       January 2018\n//\n\n#include <vapor/MyPython.h>\n#include <vapor/DC.h>\n\n#include <QLineEdit>\n#include <QTemporaryFile>\n#include <vapor/GUIStateParams.h>\n#include <vapor/DataMgrUtils.h>\n#include \"ErrorReporter.h\"\n#include \"Plot.h\"\n#include \"Flags.h\"\n#include \"VPushButton.h\"\n\n// Constructor\nPlot::Plot(VAPoR::DataStatus *status, VAPoR::ParamsMgr *manager, QWidget *parent) : QDialog(parent), Ui_PlotWindow()\n{\n    _dataStatus = status;\n    _paramsMgr = manager;\n\n    // Get the active dataset name\n    std::string              currentDatasetName;\n    std::vector<std::string> dmNames = _dataStatus->GetDataMgrNames();\n    if (dmNames.empty())\n        MSG_ERR(\"No data set chosen yet. Plot shouldn't run into this condition.\");\n    else {\n        GUIStateParams *guiParams = dynamic_cast<GUIStateParams *>(_paramsMgr->GetParams(GUIStateParams::GetClassType()));\n        currentDatasetName = guiParams->GetPlotDatasetName();\n        if (currentDatasetName == \"\" || currentDatasetName == \"NULL\")    // not initialized yet\n        {\n            currentDatasetName = dmNames[0];\n            guiParams->SetPlotDatasetName(currentDatasetName);\n        }\n    }\n\n    // Do some static QT stuff\n    setupUi(this);\n    setWindowTitle(\"Plot Utility\");\n    myFidelityWidget->Reinit((VariableFlags)AUXILIARY);\n    spaceTimeTab->setCurrentIndex(0);    // default to load space tab\n\n    timeTabSinglePoint->SetMainLabel(QString(\"Select one data point in space:\"));\n    timeTabTimeRange->SetMainLabel(QString(\"Select the minimum and maximum time steps:\"));\n    timeTabTimeRange->SetIntType(true);\n\n    spaceTabP1->SetMainLabel(QString(\"Select spatial location of Point 1\"));\n    spaceTabP2->SetMainLabel(QString(\"Select spatial location of Point 2\"));\n    spaceTabTimeSelector->SetLabel(QString(\"T\"));\n    spaceTabTimeSelector->SetIntType(true);\n\n    // set widget extents\n    _setInitialExtents();\n    _validator = new QIntValidator(numOfSamplesLineEdit);\n    numOfSamplesLineEdit->setValidator(_validator);\n\n    // Connect signals with slots\n    connect(newVarCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_newVarChanged(int)));\n    connect(removeVarCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_removeVarChanged(int)));\n    connect(dataMgrCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_dataSourceChanged(int)));\n    connect(timeTabSinglePoint, SIGNAL(pointUpdated()), this, SLOT(_timeModePointChanged()));\n    connect(timeTabTimeRange, SIGNAL(rangeChanged()), this, SLOT(_timeModeT1T2Changed()));\n    connect(spaceTabTimeSelector, SIGNAL(valueChanged(int)), this, SLOT(_spaceModeTimeChanged(int)));\n    connect(spaceTabP1, SIGNAL(pointUpdated()), this, SLOT(_spaceModeP1Changed()));\n    connect(spaceTabP2, SIGNAL(pointUpdated()), this, SLOT(_spaceModeP2Changed()));\n    connect(spaceTabPlotButton, SIGNAL(clicked()), this, SLOT(_spaceTabPlotClicked()));\n    connect(timeTabPlotButton, SIGNAL(clicked()), this, SLOT(_timeTabPlotClicked()));\n    connect(numOfSamplesLineEdit, SIGNAL(editingFinished()), this, SLOT(_numberOfSamplesChanged()));\n    connect(xlock, SIGNAL(stateChanged(int)), this, SLOT(_axisLocksChanged(int)));\n    connect(ylock, SIGNAL(stateChanged(int)), this, SLOT(_axisLocksChanged(int)));\n    connect(zlock, SIGNAL(stateChanged(int)), this, SLOT(_axisLocksChanged(int)));\n\n    // Create widgets for the plot window\n    _plotDialog = new QDialog(this);\n    _plotLabel = new QLabel(this);\n    _plotLabel->setText(QString(\"  Plot is on disk:  \"));\n    _plotPathEdit = new QLineEdit(this);\n    _plotPathEdit->setReadOnly(true);\n    _plotPathEdit->setTextMargins(6, 0, 6, 0);\n    _plotImageLabel = new QLabel(this);\n    _plotLayout = new QVBoxLayout();\n    _plotDialog->setLayout(_plotLayout);\n    _plotLayout->addWidget(_plotLabel);\n    _plotLayout->addWidget(_plotPathEdit);\n    _plotLayout->addWidget(_plotImageLabel);\n\n    VPushButton *close = new VPushButton(\"Close Window\");\n    connect(close, &VPushButton::ButtonClicked, this, &QDialog::accept);\n    layout()->addWidget(close);\n\n    // Put the current window on top\n    show();\n    raise();\n    activateWindow();\n}\n\n// Destructor\nPlot::~Plot()\n{\n    _dataStatus = NULL;\n    _paramsMgr = NULL;\n}\n\nvoid Plot::Update()\n{\n    // Doesn't do anything if the current window isn't visible.\n    if (!(this->isVisible())) return;\n\n    // Initialize pointers\n    std::vector<std::string> dmNames = _dataStatus->GetDataMgrNames();\n    if (dmNames.empty()) {\n        this->close();\n        return;\n    }\n    GUIStateParams *guiParams = dynamic_cast<GUIStateParams *>(_paramsMgr->GetParams(GUIStateParams::GetClassType()));\n    std::string     currentDatasetName = guiParams->GetPlotDatasetName();\n    VAssert(currentDatasetName != \"\" && currentDatasetName != \"NULL\");\n    int currentIdx = -1;\n    for (int i = 0; i < dmNames.size(); i++)\n        if (currentDatasetName == dmNames[i]) {\n            currentIdx = i;\n            break;\n        }\n    if (currentIdx == -1)    // currentDatasetName is closed!!!\n    {\n        currentDatasetName = dmNames[0];\n        currentIdx = 0;\n        guiParams->SetPlotDatasetName(currentDatasetName);\n        _setInitialExtents();\n    }\n    VAPoR::DataMgr *         currentDmgr = _dataStatus->GetDataMgr(currentDatasetName);\n    VAPoR::PlotParams *      plotParams = dynamic_cast<VAPoR::PlotParams *>(_paramsMgr->GetAppRenderParams(currentDatasetName, VAPoR::PlotParams::GetClassType()));\n    std::vector<std::string> enabledVars = plotParams->GetAuxVariableNames();\n\n    // Update DataMgrCombo\n    dataMgrCombo->blockSignals(true);\n    dataMgrCombo->clear();\n    for (int i = 0; i < dmNames.size(); i++) dataMgrCombo->addItem(QString::fromStdString(dmNames[i]));\n    dataMgrCombo->setCurrentIndex(currentIdx);\n    dataMgrCombo->blockSignals(false);\n\n    // Update \"Add a Variable\"\n    std::vector<std::string> availVars = currentDmgr->GetDataVarNames();\n    for (int i = 0; i < enabledVars.size(); i++)\n        for (int rmIdx = 0; rmIdx < availVars.size(); rmIdx++)\n            if (availVars[rmIdx] == enabledVars[i]) {\n                availVars.erase(availVars.begin() + rmIdx);\n                break;\n            }\n    std::sort(availVars.begin(), availVars.end());\n    newVarCombo->blockSignals(true);\n    newVarCombo->clear();\n    newVarCombo->blockSignals(false);\n    newVarCombo->addItem(QString(\"Add a Variable\"));\n    for (std::vector<std::string>::iterator it = availVars.begin(); it != availVars.end(); ++it) newVarCombo->addItem(QString::fromStdString(*it));\n    newVarCombo->setCurrentIndex(0);\n\n    // Update \"Remove a Variable\"\n    std::sort(enabledVars.begin(), enabledVars.end());\n    removeVarCombo->blockSignals(true);\n    removeVarCombo->clear();\n    removeVarCombo->blockSignals(false);\n    removeVarCombo->addItem(QString(\"Remove a Variable\"));\n    for (int i = 0; i < enabledVars.size(); i++) removeVarCombo->addItem(QString::fromStdString(enabledVars[i]));\n    removeVarCombo->setCurrentIndex(0);\n\n    // Update \"Variable Table\"\n    variablesTable->clear();    // This also deletes the items properly.\n    QStringList header;         // Start from the header\n    header << \"Enabled Variables\";\n    variablesTable->setColumnCount(header.size());\n    variablesTable->setHorizontalHeaderLabels(header);\n    variablesTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);\n    variablesTable->horizontalHeader()->setFixedHeight(30);\n    variablesTable->verticalHeader()->setFixedWidth(30);\n\n    variablesTable->setRowCount(enabledVars.size());    // Then work on the cells\n    for (int row = 0; row < enabledVars.size(); row++) {\n        QTableWidgetItem *item = new QTableWidgetItem(QString::fromStdString(enabledVars[row]));\n        item->setFlags(Qt::NoItemFlags);\n        item->setTextAlignment(Qt::AlignCenter);\n        variablesTable->setItem(row, 0, item);\n    }\n    variablesTable->update();\n    variablesTable->repaint();\n    variablesTable->viewport()->update();\n\n    // If there are variables selected, update the extents based on the selected variables.\n    if (enabledVars.size() > 0) {\n        std::vector<double> min, max;\n        std::vector<int>    axes;\n\n        // First update the space tab\n        min = plotParams->GetMinExtents();\n        max = plotParams->GetMaxExtents();\n        size_t dimensionality = min.size();\n\n        spaceTabP1->SetDimensionality(dimensionality);\n        spaceTabP2->SetDimensionality(dimensionality);\n        spaceTabP1->SetExtents(min, max);\n        spaceTabP2->SetExtents(min, max);\n\n        std::vector<double> pt = plotParams->GetPoint1();\n        if (pt.size() == 0)    // 1st time open Plot\n            pt = min;\n        else if (pt.size() == 2 && dimensionality == 3)\n            pt.push_back(min.at(2));\n        else if (pt.size() == 3 && dimensionality == 2)\n            pt.pop_back();\n\n        spaceTabP1->SetValue(pt);\n        plotParams->SetPoint1(pt);\n\n        pt = plotParams->GetPoint2();\n        if (pt.size() == 0)\n            pt = max;\n        else if (pt.size() == 2 && dimensionality == 3)\n            pt.push_back(max.at(2));\n        else if (pt.size() == 3 && dimensionality == 2)\n            pt.pop_back();\n\n        spaceTabP2->SetValue(pt);\n        plotParams->SetPoint2(pt);\n\n        // Second update the time tab\n        timeTabSinglePoint->SetDimensionality(dimensionality);\n        timeTabSinglePoint->SetExtents(min, max);\n\n        pt = plotParams->GetSinglePoint();\n        if (pt.size() == 0) {\n            for (size_t i = 0; i < min.size(); i++) pt.push_back(min.at(i) + 0.5 * (max.at(i) - min.at(i)));\n        } else if (pt.size() == 2 && dimensionality == 3)\n            pt.push_back(min.at(2) + 0.5 * (max.at(2) - min.at(2)));\n        else if (pt.size() == 3 && dimensionality == 2)\n            pt.pop_back();\n        timeTabSinglePoint->SetValue(pt);\n        plotParams->SetSinglePoint(pt);\n    }\n\n    // Update LOD, Refinement\n    myFidelityWidget->Update(currentDmgr, _paramsMgr, plotParams);\n\n    // Update time dimension\n    spaceTabTimeSelector->SetValue(plotParams->GetCurrentTimestep());\n    std::vector<long> range = plotParams->GetMinMaxTS();\n    VAssert(range.size() > 0);\n    timeTabTimeRange->SetValue((double)range[0], (double)range[1]);\n\n    // Update number of samples\n    numOfSamplesLineEdit->setText(QString::number(plotParams->GetNumOfSamples(), 10));\n\n    // Update axis locks\n    std::vector<bool> locks = plotParams->GetAxisLocks();\n    xlock->setChecked(locks[0]);\n    ylock->setChecked(locks[1]);\n    zlock->setChecked(locks[2]);\n    if (spaceTabP1->GetDimensionality() == 3)\n        zlock->setVisible(true);\n    else\n        zlock->setVisible(false);\n    _spaceModeP1Changed();    // if any axis is locked, this function syncs them\n}\n\nvoid Plot::_newVarChanged(int index)\n{\n    if (index == 0)    // not selecting any variable\n        return;\n\n    std::string varName = newVarCombo->itemText(index).toStdString();\n\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n    VAPoR::DataMgr *   dataMgr = this->_getCurrentDataMgr();\n    int                refinementLevel = plotParams->GetRefinementLevel();\n    int                compressLevel = plotParams->GetCompressionLevel();\n    int                currentTS = (int)plotParams->GetCurrentTimestep();\n\n    // Test if the selected variable available at the specific time step,\n    //   compression level, etc.\n    if (!dataMgr->VariableExists(currentTS, varName, refinementLevel, compressLevel)) {\n        MSG_WARN(\"Selected variable not available at this settings!\");\n        newVarCombo->setCurrentIndex(0);\n        return;\n    } else    // Add this variable to parameter\n    {\n        std::vector<std::string> vars = plotParams->GetAuxVariableNames();\n        vars.push_back(varName);\n        plotParams->SetAuxVariableNames(vars);\n        _updateExtents();\n    }\n}\n\nvoid Plot::_removeVarChanged(int index)\n{\n    if (index == 0) return;\n\n    std::string        varName = removeVarCombo->itemText(index).toStdString();\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n\n    // Remove this variable from parameter\n    std::vector<std::string> vars = plotParams->GetAuxVariableNames();\n    int                      rmIdx = -1;\n    for (int i = 0; i < vars.size(); i++)\n        if (vars[i] == varName) {\n            rmIdx = i;\n            break;\n        }\n    VAssert(rmIdx != -1);\n    vars.erase(vars.begin() + rmIdx);\n    plotParams->SetAuxVariableNames(vars);\n}\n\nvoid Plot::_spaceModeP1Changed()\n{\n    std::vector<double> pt, pt2;\n    spaceTabP1->GetCurrentPoint(pt);\n    VAssert(pt.size() == 2 || pt.size() == 3);\n\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n    plotParams->SetPoint1(pt);\n\n    spaceTabP2->GetCurrentPoint(pt2);\n    std::vector<bool> locks = plotParams->GetAxisLocks();\n    bool              lockFlag = false;\n    if (locks[0]) {\n        pt2[0] = pt[0];\n        lockFlag = true;\n    }\n    if (locks[1]) {\n        pt2[1] = pt[1];\n        lockFlag = true;\n    }\n    if (spaceTabP1->GetDimensionality() == 3 && locks[2]) {\n        pt2[2] = pt[2];\n        lockFlag = true;\n    }\n    if (lockFlag) {\n        spaceTabP2->SetValue(pt2);\n        plotParams->SetPoint2(pt2);\n    }\n}\n\nvoid Plot::_spaceModeP2Changed()\n{\n    std::vector<double> pt, pt1;\n    spaceTabP2->GetCurrentPoint(pt);\n    VAssert(pt.size() == 2 || pt.size() == 3);\n\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n    plotParams->SetPoint2(pt);\n\n    spaceTabP1->GetCurrentPoint(pt1);\n    std::vector<bool> locks = plotParams->GetAxisLocks();\n    bool              lockFlag = false;\n    if (locks[0]) {\n        pt1[0] = pt[0];\n        lockFlag = true;\n    }\n    if (locks[1]) {\n        pt1[1] = pt[1];\n        lockFlag = true;\n    }\n    if (spaceTabP2->GetDimensionality() == 3 && locks[2]) {\n        pt1[2] = pt[2];\n        lockFlag = true;\n    }\n    if (lockFlag) {\n        spaceTabP1->SetValue(pt1);\n        plotParams->SetPoint1(pt1);\n    }\n}\n\nvoid Plot::_spaceModeTimeChanged(int val)\n{\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n    plotParams->SetCurrentTimestep(val);\n    std::string emptyStr;\n    _updateExtents();\n}\n\nvoid Plot::_timeModePointChanged()\n{\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n\n    std::vector<double> currentPoint;\n    timeTabSinglePoint->GetCurrentPoint(currentPoint);\n    VAssert(currentPoint.size() == 2 || currentPoint.size() == 3);\n\n    plotParams->SetSinglePoint(currentPoint);\n}\n\nvoid Plot::_timeModeT1T2Changed()\n{\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n\n    double smallVal, bigVal;\n    timeTabTimeRange->GetValue(smallVal, bigVal);\n    std::vector<long int> rangeInt;\n    rangeInt.push_back((long int)smallVal);\n    rangeInt.push_back((long int)bigVal);\n\n    plotParams->SetMinMaxTS(rangeInt);\n    std::string emptyStr;\n    _updateExtents();\n}\n\nvoid Plot::_dataSourceChanged(int index)\n{\n    std::string newDataSourceName = dataMgrCombo->itemText(index).toStdString();\n\n    // Inform GUIStateParams the change of data source.\n    GUIStateParams *guiParams = dynamic_cast<GUIStateParams *>(_paramsMgr->GetParams(GUIStateParams::GetClassType()));\n\n    guiParams->SetPlotDatasetName(newDataSourceName);\n\n    _setInitialExtents();\n}\n\nVAPoR::PlotParams *Plot::_getCurrentPlotParams() const\n{\n    GUIStateParams *guiParams = dynamic_cast<GUIStateParams *>(_paramsMgr->GetParams(GUIStateParams::GetClassType()));\n    std::string     dsName = guiParams->GetPlotDatasetName();\n    return (dynamic_cast<VAPoR::PlotParams *>(_paramsMgr->GetAppRenderParams(dsName, VAPoR::PlotParams::GetClassType())));\n}\n\nVAPoR::DataMgr *Plot::_getCurrentDataMgr() const\n{\n    GUIStateParams *guiParams = dynamic_cast<GUIStateParams *>(_paramsMgr->GetParams(GUIStateParams::GetClassType()));\n    std::string     currentDatasetName = guiParams->GetPlotDatasetName();\n    VAssert(currentDatasetName != \"\" && currentDatasetName != \"NULL\");\n\n    return (_dataStatus->GetDataMgr(currentDatasetName));\n}\n\nvoid Plot::_setInitialExtents()\n{\n    // Set spatial extents\n    VAPoR::CoordType minExt, maxExt;\n    _dataStatus->GetActiveExtents(_paramsMgr, 0, minExt, maxExt);\n\n    std::vector<double> minActiveExtents = {minExt[0], minExt[1], minExt[2]};\n    std::vector<double> maxActiveExtents = {maxExt[0], maxExt[1], maxExt[2]};\n\n    int dimensionality = 3;\n    _getCurrentPlotParams()->SetMinExtents(minActiveExtents);\n    _getCurrentPlotParams()->SetMaxExtents(maxActiveExtents);\n\n    int                   numOfTimeSteps = this->_getCurrentDataMgr()->GetNumTimeSteps();\n    std::vector<long int> rangeInt;\n    rangeInt.push_back((long int)0);\n    rangeInt.push_back((long int)(numOfTimeSteps - 1));\n    _getCurrentPlotParams()->SetMinMaxTS(rangeInt);\n\n    // Set space tab extents\n    spaceTabP1->SetDimensionality(dimensionality);\n    spaceTabP2->SetDimensionality(dimensionality);\n    spaceTabP1->SetExtents(minActiveExtents, maxActiveExtents);\n    spaceTabP2->SetExtents(minActiveExtents, maxActiveExtents);\n    spaceTabP1->SetValue(minActiveExtents);\n    spaceTabP2->SetValue(maxActiveExtents);\n    spaceTabTimeSelector->SetExtents(0.0, (double)(numOfTimeSteps - 1));\n    spaceTabTimeSelector->SetValue(0.0);\n\n    // Set time tab extents\n    timeTabSinglePoint->SetDimensionality(dimensionality);\n    timeTabSinglePoint->SetExtents(minActiveExtents, maxActiveExtents);\n    timeTabSinglePoint->SetValue(minActiveExtents);\n    timeTabTimeRange->SetExtents(0.0, (double)(numOfTimeSteps - 1));\n}\n\nvoid Plot::_spaceTabPlotClicked()\n{\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n    VAPoR::DataMgr *   dataMgr = this->_getCurrentDataMgr();\n\n    int                      refinementLevel = plotParams->GetRefinementLevel();\n    int                      compressLevel = plotParams->GetCompressionLevel();\n    int                      currentTS = (int)plotParams->GetCurrentTimestep();\n    std::vector<double>      point1 = plotParams->GetPoint1();\n    std::vector<double>      point2 = plotParams->GetPoint2();\n    std::vector<std::string> enabledVars = plotParams->GetAuxVariableNames();\n    int                      numOfSamples = plotParams->GetNumOfSamples();\n\n    // Do nothing if no variable is enabled\n    if (enabledVars.size() == 0) return;\n\n    std::vector<double> p1p2span;\n    for (int i = 0; i < point1.size(); i++) p1p2span.push_back(point2[i] - point1[i]);\n\n    std::vector<std::vector<float>> sequences;\n    for (int v = 0; v < enabledVars.size(); v++) {\n        std::vector<float> seq(numOfSamples, 0.0);\n        VAPoR::Grid *      grid = dataMgr->GetVariable(currentTS, enabledVars[v], refinementLevel, compressLevel);\n        if (grid) {\n            float missingVal = grid->GetMissingValue();\n            for (int i = 0; i < numOfSamples; i++) {\n                std::vector<double> sample;\n                if (i == 0)\n                    sample = point1;\n                else if (i == numOfSamples - 1)\n                    sample = point2;\n                else {\n                    for (int j = 0; j < point1.size(); j++) sample.push_back((double)i / (double)(numOfSamples - 1) * p1p2span[j] + point1[j]);\n                }\n                float fieldVal = grid->GetValue(sample);\n                if (fieldVal == missingVal)\n                    seq[i] = std::nanf(\"1\");\n                else\n                    seq[i] = fieldVal;\n            }\n            sequences.push_back(seq);\n        }\n\n        delete grid;\n    }\n\n    // Decide X label and values\n    std::string        xLabel = _getXLabel();\n    std::vector<float> xValues;\n    if (!xLabel.empty())    // If xLabel isn't empty, we calculate the actual distances\n    {\n        float dist = 0.0f;\n        for (int i = 0; i < p1p2span.size(); i++) dist += p1p2span[i] * p1p2span[i];\n        dist = std::sqrt(dist);\n        float stepsize = dist / (float)(numOfSamples - 1);\n        for (int i = 0; i < numOfSamples; i++) xValues.push_back((float)i * stepsize);\n    } else {\n        for (int i = 0; i < numOfSamples; i++) xValues.push_back((float)i);\n    }\n\n    // Decide Y label and values\n    std::string yLabel = _getYLabel();\n\n    // Call python routines.\n    QTemporaryFile file;\n    if (file.open()) {\n        QString filename = file.fileName() + QString(\".png\");\n\n        _invokePython(filename, enabledVars, sequences, xValues, xLabel, yLabel);\n\n        QImage plot(filename);\n        _plotPathEdit->setText(filename);\n        _plotImageLabel->setPixmap(QPixmap::fromImage(plot));\n        _plotDialog->show();\n        _plotDialog->raise();\n        _plotDialog->activateWindow();\n\n        file.close();\n    } else\n        MSG_ERR(\"QT temporary file not able to open\");\n}\n\nvoid Plot::_timeTabPlotClicked()\n{\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n    VAPoR::DataMgr *   dataMgr = this->_getCurrentDataMgr();\n\n    int                      refinementLevel = plotParams->GetRefinementLevel();\n    int                      compressLevel = plotParams->GetCompressionLevel();\n    std::vector<double>      singlePt = plotParams->GetSinglePoint();\n    std::vector<long int>    minMaxTS = plotParams->GetMinMaxTS();\n    std::vector<std::string> enabledVars = plotParams->GetAuxVariableNames();\n\n    // Do nothing if no variable is enabled\n    if (enabledVars.size() == 0) return;\n\n    std::vector<std::vector<float>> sequences;\n    for (int v = 0; v < enabledVars.size(); v++) {\n        std::vector<float> seq;\n        for (int t = minMaxTS[0]; t <= minMaxTS[1]; t++) {\n            VAPoR::Grid *grid = dataMgr->GetVariable(t, enabledVars[v], refinementLevel, compressLevel);\n            if (grid) {\n                float fieldVal = grid->GetValue(singlePt);\n                if (fieldVal != grid->GetMissingValue())\n                    seq.push_back(fieldVal);\n                else\n                    seq.push_back(std::nanf(\"1\"));\n            }\n\n            delete grid;\n        }\n        sequences.push_back(seq);\n    }\n\n    std::vector<float> xValues;\n    if (minMaxTS.size() > 0)\n        for (int i = minMaxTS[0]; i <= minMaxTS[1]; i++) xValues.push_back((float)i);\n\n    // Decide Y label and values\n    std::string yLabel = _getYLabel();\n\n    // Call python routines.\n    QTemporaryFile file;\n    if (file.open()) {\n        QString filename = file.fileName() + QString(\".png\");\n\n        const std::string xLabel = \"Time Steps\";\n        _invokePython(filename, enabledVars, sequences, xValues, xLabel, yLabel);\n\n        QImage plot(filename);\n        _plotPathEdit->setText(filename);\n        _plotImageLabel->setPixmap(QPixmap::fromImage(plot));\n        _plotDialog->show();\n        _plotDialog->raise();\n        _plotDialog->activateWindow();\n\n        file.close();\n    } else\n        MSG_ERR(\"QT temporary file not able to open\");\n}\n\nvoid Plot::_invokePython(const QString &outFile, const std::vector<std::string> &enabledVars, const std::vector<std::vector<float>> &sequences, const std::vector<float> &xValues,\n                         const std::string &xLabel, const std::string &yLabel)\n{\n    /* Adopted from documentation: https://docs.python.org/2/extending/embedding.html */\n    PyObject *pName = NULL;\n    PyObject *pModule = NULL;\n    PyObject *pFunc = NULL;\n    PyObject *pArgs = NULL;\n    PyObject *pValue = NULL;\n    Wasp::MyPython::Instance()->Initialize();\n    VAssert(Py_IsInitialized());\n\n    pName = PyUnicode_FromString(\"plot\");\n    pModule = PyImport_Import(pName);\n\n    if (pModule == NULL) {\n        MSG_ERR(\"pModule NULL!!\");\n        PyErr_Print();\n        return;\n    }\n    pFunc = PyObject_GetAttrString(pModule, \"plotSequences\");\n    if (pFunc && PyCallable_Check(pFunc)) {\n        pArgs = PyTuple_New(6);\n\n        // Set the 1st argument: output file name\n        pValue = PyUnicode_FromString(outFile.toLocal8Bit());\n        PyTuple_SetItem(pArgs, 0, pValue);    // pValue is stolen!\n\n        // Set the 2nd argument: variable names\n        PyObject *pListOfStrings = PyList_New(enabledVars.size());\n        VAssert(pListOfStrings);\n        for (int i = 0; i < enabledVars.size(); i++) {\n            pValue = PyUnicode_FromString(enabledVars[i].c_str());\n            int rt = PyList_SetItem(pListOfStrings, i, pValue);    // pValue is stolen!\n            VAssert(rt == 0);\n        }\n        PyTuple_SetItem(pArgs, 1, pListOfStrings);    // pListOfStrings is stolen!\n\n        // Set the 3rd argument: sequence values (Y axis)\n        PyObject *pListOfLists = PyList_New(sequences.size());\n        VAssert(pListOfLists);\n        for (int i = 0; i < sequences.size(); i++)    // for each sequence\n        {\n            PyObject *pList = PyList_New(sequences[i].size());\n            VAssert(pList);\n            for (int j = 0; j < sequences[i].size(); j++) {\n                int rt = PyList_SetItem(pList, j, PyFloat_FromDouble(sequences[i][j]));\n                VAssert(rt == 0);\n            }\n            PyList_SetItem(pListOfLists, i, pList);\n        }\n        PyTuple_SetItem(pArgs, 2, pListOfLists);\n\n        // Set the 4th argument: X axis values\n        PyObject *pListOfFloats = PyList_New(xValues.size());\n        VAssert(pListOfFloats);\n        for (int i = 0; i < xValues.size(); i++) {\n            int rt = PyList_SetItem(pListOfFloats, i, PyFloat_FromDouble(xValues[i]));\n            VAssert(rt == 0);\n        }\n        PyTuple_SetItem(pArgs, 3, pListOfFloats);\n\n        // Set the 5th argument: X axis label\n        pValue = PyUnicode_FromString(xLabel.c_str());\n        PyTuple_SetItem(pArgs, 4, pValue);\n\n        // Set the 6th argument: Y axis label\n        pValue = PyUnicode_FromString(yLabel.c_str());\n        PyTuple_SetItem(pArgs, 5, pValue);\n\n        pValue = PyObject_CallObject(pFunc, pArgs);\n        if (pValue == NULL) {\n            MSG_ERR(\"pFunc failed to execute\");\n            PyErr_Print();\n        }\n    } else {\n        MSG_ERR(\"pFunc NULL\");\n        PyErr_Print();\n    }\n\n    Py_XDECREF(pName);\n    Py_XDECREF(pArgs);\n    Py_XDECREF(pValue);\n    Py_XDECREF(pFunc);\n    Py_XDECREF(pModule);\n}\n\nvoid Plot::_numberOfSamplesChanged()\n{\n    long val = numOfSamplesLineEdit->text().toLong();\n    long minSamples = 50;\n    if (val < minSamples) {\n        val = minSamples;\n        numOfSamplesLineEdit->setText(QString::number(val, 10));\n    }\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n    plotParams->SetNumOfSamples(val);\n}\n\nstd::string Plot::_getXLabel()\n{\n    VAPoR::PlotParams *      plotParams = this->_getCurrentPlotParams();\n    VAPoR::DataMgr *         dataMgr = this->_getCurrentDataMgr();\n    std::vector<std::string> enabledVars = plotParams->GetAuxVariableNames();\n    std::vector<std::string> units;\n\n    for (int i = 0; i < enabledVars.size(); i++) {\n        VAPoR::DC::DataVar dataVar;\n        dataMgr->GetDataVarInfo(enabledVars[i], dataVar);\n        std::string     meshName = dataVar.GetMeshName();\n        VAPoR::DC::Mesh mesh;\n        dataMgr->GetMesh(meshName, mesh);\n        std::vector<std::string> coordVarNames = mesh.GetCoordVars();\n        for (int j = 0; j < coordVarNames.size(); j++) {\n            VAPoR::DC::CoordVar coordVar;\n            dataMgr->GetCoordVarInfo(coordVarNames[j], coordVar);\n            units.push_back(coordVar.GetUnits());\n        }\n    }\n\n    std::string empty;\n    if (units.size() == 0)\n        return empty;\n    else {\n        std::string label = units[0];\n        for (int i = 1; i < units.size(); i++)\n            if (units[i] != label) return empty;\n\n        return label;\n    }\n}\n\nstd::string Plot::_getYLabel()\n{\n    VAPoR::PlotParams *      plotParams = this->_getCurrentPlotParams();\n    VAPoR::DataMgr *         dataMgr = this->_getCurrentDataMgr();\n    std::vector<std::string> enabledVars = plotParams->GetAuxVariableNames();\n    std::vector<std::string> units;\n\n    for (int i = 0; i < enabledVars.size(); i++) {\n        VAPoR::DC::DataVar dataVar;\n        dataMgr->GetDataVarInfo(enabledVars[i], dataVar);\n        units.push_back(dataVar.GetUnits());\n    }\n\n    std::string empty;\n    if (units.size() == 0)\n        return empty;\n    else {\n        std::string label = units[0];\n        for (int i = 1; i < units.size(); i++)\n            if (units[i] != label) return empty;\n\n        return label;\n    }\n}\n\nvoid Plot::_axisLocksChanged(int val)\n{\n    std::vector<bool> locks(3, false);\n    locks[0] = (bool)xlock->isChecked();\n    locks[1] = (bool)ylock->isChecked();\n    locks[2] = (bool)zlock->isChecked();\n\n    VAPoR::PlotParams *plotParams = this->_getCurrentPlotParams();\n    plotParams->SetAxisLocks(locks);\n    _spaceModeP1Changed();\n}\n\nvoid Plot::_updateExtents()\n{\n    VAPoR::DataMgr *         currentDmgr = this->_getCurrentDataMgr();\n    VAPoR::PlotParams *      plotParams = this->_getCurrentPlotParams();\n    int                      refinementLevel = plotParams->GetRefinementLevel();\n    int                      compressLevel = plotParams->GetCompressionLevel();\n    std::vector<std::string> enabledVars = plotParams->GetAuxVariableNames();\n\n    // Retrieve extents of all variables at 3 different time steps.\n    VAPoR::CoordType    min, max, minT1, maxT1, minT2, maxT2;\n    std::vector<int>    axes;\n    std::vector<long>   TSToExamine;\n    TSToExamine.push_back(plotParams->GetCurrentTimestep());\n    TSToExamine.push_back(plotParams->GetMinMaxTS().at(0));\n    TSToExamine.push_back(plotParams->GetMinMaxTS().at(1));\n\n    // TSToExamine[0] definitely needs to be evaluated.\n    VAPoR::DataMgrUtils::GetExtents(currentDmgr, TSToExamine[0], enabledVars, refinementLevel, compressLevel, min, max, axes);\n\n    // TSToExamine[1] and TSToExamine[2] are evaluated only when not duplicate\n    if (TSToExamine[1] != TSToExamine[0]) {\n        VAPoR::DataMgrUtils::GetExtents(currentDmgr, TSToExamine[1], enabledVars, refinementLevel, compressLevel, minT1, maxT1, axes);\n    } else {\n        minT1 = min;\n        maxT1 = max;\n    }\n    if ((TSToExamine[2] != TSToExamine[1]) && (TSToExamine[2] != TSToExamine[0])) {\n        VAPoR::DataMgrUtils::GetExtents(currentDmgr, TSToExamine[2], enabledVars, refinementLevel, compressLevel, minT2, maxT2, axes);\n    } else {\n        minT2 = min;\n        maxT2 = max;\n    }\n\n    // Find the union of the 3 extents\n    for (int i = 0; i < min.size(); i++) {\n        if (minT1[i] < min[i]) min[i] = minT1[i];\n        if (maxT1[i] > max[i]) max[i] = maxT1[i];\n        if (minT2[i] < min[i]) min[i] = minT2[i];\n        if (maxT2[i] > max[i]) max[i] = maxT2[i];\n    }\n\n    vector<double> minVec = {min[0], min[1], min[2]};\n    vector<double> maxVec = {max[0], max[1], max[2]};\n    plotParams->SetMinExtents(minVec);\n    plotParams->SetMaxExtents(maxVec);\n}\n"
  },
  {
    "path": "apps/vaporgui/Plot.h",
    "content": "//************************************************************************\n//                                                                      *\n//           Copyright (C)  2016                                        *\n//     University Corporation for Atmospheric Research                  *\n//           All Rights Reserved                                        *\n//                                                                      *\n//************************************************************************/\n//\n//  Author:     Samuel Li\n//              National Center for Atmospheric Research\n//              PO 3000, Boulder, Colorado\n//\n//  Date:       January 2018\n//\n\n#ifndef PLOT_H\n#define PLOT_H\n\n#include <vector>\n#include <QWidget>\n#include \"ui_plotWindow.h\"\n#include <vapor/ParamsMgr.h>\n#include <vapor/DataStatus.h>\n#include \"PlotParams.h\"\n#include \"Updatable.h\"\n\nclass Plot : public QDialog, public Ui_PlotWindow, public Updatable {\n    Q_OBJECT\n\npublic:\n    Plot(VAPoR::DataStatus *status, VAPoR::ParamsMgr *manager, QWidget *parent = 0);\n    ~Plot();\n\n    /// This is called whenever there's a change to the parameters.\n    void Update();\n\nprivate slots:\n    /// Update list of enabled variables upon add/remove events\n    void _newVarChanged(int);\n    void _removeVarChanged(int);\n\n    /// Clean up everything when data source is changed\n    void _dataSourceChanged(int);\n\n    /// Clean up data points for plotting when the following events happen\n    void _spaceModeP1Changed();\n    void _spaceModeP2Changed();\n    void _spaceModeTimeChanged(int);\n    void _timeModePointChanged();\n    void _timeModeT1T2Changed();\n    void _numberOfSamplesChanged();\n    void _axisLocksChanged(int);\n\n    /// Plot when the plot button is clicked\n    void _spaceTabPlotClicked();\n    void _timeTabPlotClicked();\n\nprivate:\n    VAPoR::DataStatus *_dataStatus;\n    VAPoR::ParamsMgr * _paramsMgr;\n    QDialog *          _plotDialog;\n    QLabel *           _plotLabel;\n    QLineEdit *        _plotPathEdit;\n    QLabel *           _plotImageLabel;\n    QVBoxLayout *      _plotLayout;\n    QIntValidator *    _validator;\n\n    /// Access functions to other pointers\n    VAPoR::PlotParams *_getCurrentPlotParams() const;\n    VAPoR::DataMgr *   _getCurrentDataMgr() const;\n\n    void _setInitialExtents();\n\n    /// All the python stuff happens here; no python outside this method\n    void _invokePython(const QString &, const std::vector<std::string> &, const std::vector<std::vector<float>> &, const std::vector<float> &, const std::string &, const std::string &);\n\n    // Returns a string with the proper X label if all variables share the same coordinate unit.\n    //   Otherwise returns an empty string.\n    //\n    std::string _getXLabel();\n\n    // Returns a string with the proper Y label if all variables share the same unit.\n    //   Otherwise returns an empty string.\n    //\n    std::string _getYLabel();\n\n    // Update the min and max extents based on all enabled variables.\n    //\n    void _updateExtents();\n};\n\n#endif    // PLOT_H\n"
  },
  {
    "path": "apps/vaporgui/PlotParams.cpp",
    "content": "//************************************************************************\n//                                                                       *\n//           Copyright (C)  2014                                         *\n//   University Corporation for Atmospheric Research                     *\n//           All Rights Reserved                                         *\n//                                                                       *\n//************************************************************************/\n//\n//  File:       PlotParams.cpp\n//\n//  Author:     Samuel Li\n//              National Center for Atmospheric Research\n//              PO 3000, Boulder, Colorado\n//\n//  Date:       January 2018\n//\n//  Description:    Implements the PlotParams class.\n//\n#include <iostream>\n#include <sstream>\n#include <string>\n#include \"vapor/VAssert.h\"\n#include \"PlotParams.h\"\n\nusing namespace VAPoR;\n\nconst string PlotParams::_minMaxTSTag = \"MinMaxTS\";\nconst string PlotParams::_p1Tag = \"Point2\";\nconst string PlotParams::_p2Tag = \"Point1\";\nconst string PlotParams::_numSamplesTag = \"NumberOfSamplesTag\";\nconst string PlotParams::_singlePtTag = \"SinglePoint\";\nconst string PlotParams::_lockAxisTag = \"LockAxis\";\nconst string PlotParams::_minExtentTag = \"MinExtentTag\";\nconst string PlotParams::_maxExtentTag = \"MaxExtentTag\";\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<PlotParams> registrar(PlotParams::GetClassType());\n\nPlotParams::PlotParams(DataMgr *dmgr, ParamsBase::StateSave *ssave) : RenderParams(dmgr, ssave, PlotParams::GetClassType()) {}\n\nPlotParams::PlotParams(DataMgr *dmgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dmgr, ssave, node)\n{\n    // If node isn't tagged correctly we correct the tag and reinitialize from scratch;\n    //\n    if (node->GetTag() != PlotParams::GetClassType()) node->SetTag(PlotParams::GetClassType());\n}\n\nPlotParams::~PlotParams() { MyBase::SetDiagMsg(\"PlotParams::~PlotParams() this=%p\", this); }\n\nstd::vector<long int> PlotParams::GetMinMaxTS() const { return GetValueLongVec(_minMaxTSTag); }\n\nvoid PlotParams::SetMinMaxTS(const std::vector<long int> &minmax) { SetValueLongVec(_minMaxTSTag, \"Time range in the Time mode\", minmax); }\n\nstd::vector<double> PlotParams::GetSinglePoint() const { return GetValueDoubleVec(_singlePtTag); }\n\nvoid PlotParams::SetSinglePoint(const std::vector<double> &point) { SetValueDoubleVec(_singlePtTag, \"Single point in the time mode\", point); }\n\nstd::vector<double> PlotParams::GetPoint1() const { return GetValueDoubleVec(_p1Tag); }\n\nvoid PlotParams::SetPoint1(const std::vector<double> &point) { SetValueDoubleVec(_p1Tag, \"Point 1 in the space mode\", point); }\n\nstd::vector<double> PlotParams::GetPoint2() const { return GetValueDoubleVec(_p2Tag); }\n\nvoid PlotParams::SetPoint2(const std::vector<double> &point) { SetValueDoubleVec(_p2Tag, \"Point 2 in the space mode\", point); }\n\nvoid PlotParams::SetNumOfSamples(long val) { SetValueLong(_numSamplesTag, \"Set number of samples\", (long)val); }\n\nlong PlotParams::GetNumOfSamples() const { return GetValueLong(_numSamplesTag, 100); }\n\nvoid PlotParams::SetAxisLocks(const std::vector<bool> &locks)\n{\n    std::vector<long> locksL(3, 0);\n    for (int i = 0; i < 3; i++) locksL[i] = (long int)locks[i];\n    SetValueLongVec(_lockAxisTag, \"Lock values along x, y, or z axes\", locksL);\n}\n\nstd::vector<bool> PlotParams::GetAxisLocks()\n{\n    std::vector<long> defaultVal(3, 0);\n    std::vector<long> locksL = GetValueLongVec(_lockAxisTag, defaultVal);\n    std::vector<bool> locks(3, false);\n    for (int i = 0; i < 3; i++) locks[i] = (bool)locksL[i];\n\n    return locks;\n}\n\nstd::vector<double> PlotParams::GetMinExtents() const { return GetValueDoubleVec(_minExtentTag); }\n\nvoid PlotParams::SetMinExtents(const std::vector<double> &point) { SetValueDoubleVec(_minExtentTag, \"Minimal extent\", point); }\n\nstd::vector<double> PlotParams::GetMaxExtents() const { return GetValueDoubleVec(_maxExtentTag); }\n\nvoid PlotParams::SetMaxExtents(const std::vector<double> &point) { SetValueDoubleVec(_maxExtentTag, \"Maximal Extent\", point); }\n"
  },
  {
    "path": "apps/vaporgui/PlotParams.h",
    "content": "//************************************************************************\n//                                                                       *\n//           Copyright (C)  2004                                         *\n//     University Corporation for Atmospheric Research                   *\n//           All Rights Reserved                                         *\n//                                                                       *\n//************************************************************************\n//\n//  File:       PlotParams.h\n//\n//  Author:     Samuel Li\n//              National Center for Atmospheric Research\n//              PO 3000, Boulder, Colorado\n//\n//  Date:       December 2017\n//\n//  Description:    Defines the PlotParams class.\n//\n\n#ifndef PLOTPARAMS_H\n#define PLOTPARAMS_H\n\n#include <vapor/RenderParams.h>\n\nnamespace VAPoR {\n\n/// PlotParams inherits RenderParams.\nclass PlotParams : public RenderParams {\npublic:\n    /// Constructor 1\n    PlotParams(DataMgr *dmgr, ParamsBase::StateSave *ssave);\n    /// Constructor 2\n    PlotParams(DataMgr *dmgr, ParamsBase::StateSave *ssave, XmlNode *node);\n    /// Destructor\n    ~PlotParams();\n\n    /// In ``time mode,'' these 2 methods get/set the time range.\n    std::vector<long int> GetMinMaxTS() const;\n    void                  SetMinMaxTS(const std::vector<long int> &);\n\n    /// In ``time mode,'' these 2 methods get/set the single point position\n    std::vector<double> GetSinglePoint() const;\n    void                SetSinglePoint(const std::vector<double> &point);\n\n    /// In ``space mode,'' these 4 methods get/set the point 1 and point 2 positions\n    std::vector<double> GetPoint1() const;\n    std::vector<double> GetPoint2() const;\n    void                SetPoint1(const std::vector<double> &point);\n    void                SetPoint2(const std::vector<double> &point);\n\n    /// These 4 methods get/set the up-to-date extents.\n    std::vector<double> GetMinExtents() const;\n    std::vector<double> GetMaxExtents() const;\n    void                SetMinExtents(const std::vector<double> &point);\n    void                SetMaxExtents(const std::vector<double> &point);\n\n    long GetNumOfSamples() const;\n    void SetNumOfSamples(long);\n\n    void              SetAxisLocks(const std::vector<bool> &locks);\n    std::vector<bool> GetAxisLocks();\n\n    static string  GetClassType() { return (\"PlotParams\"); }\n    virtual size_t GetRenderDim() const override { return (0); }\n    virtual string GetActualColorMapVariableName() const override { return \"\"; }\n\nprivate:\n    static const string _minMaxTSTag;\n    static const string _p1Tag;            // point1 in space mode\n    static const string _p2Tag;            // point2 in space mode\n    static const string _numSamplesTag;    // number of samples in space mode\n    static const string _singlePtTag;      // a single point in time mode\n    static const string _lockAxisTag;      // if we lock x, y, or z axis\n    static const string _minExtentTag;     // minimal extent we've seen so far\n    static const string _maxExtentTag;     // maximal extent we've seen so far\n};\n\n};    // End namespace VAPoR\n#endif\n"
  },
  {
    "path": "apps/vaporgui/ProgressStatusBar.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include <QProgressBar>\n#include <QHBoxLayout>\n#include <QToolButton>\n#include <QLabel>\n\n\nclass ProgressStatusBar : public QWidget {\n    QLabel *      _titleLabel = new QLabel;\n    QProgressBar *_progressBar = new QProgressBar;\n    QToolButton * _cancelButton = new QToolButton;\n\n    bool _canceled = false;\n\npublic:\n    ProgressStatusBar()\n    {\n        QHBoxLayout *layout = new QHBoxLayout;\n        layout->setMargin(4);\n        setLayout(layout);\n\n        _cancelButton->setIcon(_cancelButton->style()->standardIcon(QStyle::StandardPixmap::SP_DialogCancelButton));\n        QObject::connect(_cancelButton, &QAbstractButton::clicked, this, [this]() {\n            _canceled = true;\n            Finish();\n            SetTitle(\"Cancelled.\");\n        });\n\n        QSizePolicy sp = _cancelButton->sizePolicy();\n        sp.setRetainSizeWhenHidden(true);\n        _cancelButton->setSizePolicy(sp);\n        _cancelButton->setIconSize(_cancelButton->iconSize() * 0.7);\n        _cancelButton->setToolTip(\"Cancel\");\n\n        layout->addWidget(_titleLabel);\n        layout->addWidget(_progressBar);\n        layout->addWidget(_cancelButton);\n\n        Finish();\n    }\n    void SetTitle(const string &title) { _titleLabel->setText(QString::fromStdString(title)); }\n    void SetTotal(long total) { _progressBar->setRange(0, total); }\n    void SetCancelable(bool b) { _cancelButton->setEnabled(b); }\n    void SetDone(long done) { _progressBar->setValue(done); }\n    bool Cancelled() { return _canceled; }\n    void StartTask(const string &title, long total, bool cancelable)\n    {\n        Reset();\n        SetTitle(title);\n        SetTotal(total);\n        SetCancelable(cancelable);\n        _progressBar->show();\n        _cancelButton->show();\n    }\n    void Finish()\n    {\n        _progressBar->hide();\n        _cancelButton->hide();\n        SetTitle(\"\");\n    }\n    void Reset()\n    {\n        _canceled = false;\n        _progressBar->reset();\n    }\n    const QObject *GetCancelButtonObject() const { return _cancelButton; }\n};\n"
  },
  {
    "path": "apps/vaporgui/PythonVariables.cpp",
    "content": "#include \"PythonVariables.h\"\n#include \"ui_PythonVariablesGUI.h\"\n\n#include <ctime>\n#include <fstream>\n\n#include <QDebug>\n#include <QLineEdit>\n#include <QThread>\n#include <QFileDialog>\n#include <QStandardItemModel>\n\n#include <vapor/DC.h>\n#include <vapor/DataStatus.h>\n#include \"vapor/ResourcePath.h\"\n#include \"ErrorReporter.h\"\n#include \"FileOperationChecker.h\"\n\n#define READ  true\n#define WRITE false\n\n#define TWOD   2\n#define THREED 3\n\nusing namespace VAPoR;\n\ntemplate<typename T> static void printVector(std::vector<T> v)\n{\n    for (int i = 0; i < v.size(); i++) cout << v[i] << \" \";\n    cout << endl;\n}\n\nusing namespace PythonVariables_;\n\nPythonVariables::PythonVariables(QWidget *parent) : QDialog(parent), Ui_PythonVariablesGUI()\n{\n    setupUi(this);\n\n    _importScriptButton->hide();\n    _exportScriptButton->hide();\n\n    setWindowTitle(\"Derived variables with Python\");\n\n    _script = \"\";\n    _scriptName = \"\";\n    _dataMgrName = \"\";\n\n    _newItemDialog = new ::NewItemDialog(this);\n    _openAndDeleteDialog = new ::OpenAndDeleteDialog(this);\n\n    _justSaved = false;\n\n    string pythonImagePath = Wasp::GetSharePath(string(\"images\") + string(\"/PythonLogo.png\"));\n\n    QPixmap thumbnail(pythonImagePath.c_str());\n    _pythonLabel->setPixmap(thumbnail);\n\n    _includeCoordVars = false;\n    _variableTabs->removeTab(0);\n    ;\n\n    _coordInputVarTable = new VaporTable(_coordVarTable, false, true);\n    bool checkboxesEnabled = false;\n    _coordInputVarTable->EnableDisableCheckboxes(checkboxesEnabled);\n    _coordInputVarTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(0));\n\n    _2DInputVarTable = new VaporTable(_2DVarTable, false, true);\n    _2DInputVarTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(0));\n\n    _3DInputVarTable = new VaporTable(_3DVarTable, false, true);\n    _3DInputVarTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(0));\n\n    _summaryTable = new VaporTable(_varSummaryTable);\n    _summaryTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(0));\n\n    _outputVarTable = new VaporTable(_outputVariablesTable);\n    _outputVarTable->Reinit((VaporTable::ValidatorFlags)(0), (VaporTable::MutabilityFlags)(VaporTable::IMMUTABLE), (VaporTable::HighlightFlags)(VaporTable::ROWS));\n\n    _connectWidgets();\n\n    setModal(true);\n}\n\nPythonVariables::~PythonVariables()\n{\n    if (_coordInputVarTable) {\n        delete _coordInputVarTable;\n        _coordInputVarTable = nullptr;\n    }\n    if (_2DInputVarTable) {\n        delete _2DInputVarTable;\n        _2DInputVarTable = nullptr;\n    }\n    if (_3DInputVarTable) {\n        delete _3DInputVarTable;\n        _3DInputVarTable = nullptr;\n    }\n    if (_varSummaryTable) {\n        delete _varSummaryTable;\n        _varSummaryTable = nullptr;\n    }\n    if (_outputVariablesTable) {\n        delete _outputVariablesTable;\n        _outputVariablesTable = nullptr;\n    }\n}\n\nvoid PythonVariables::Update()\n{\n    VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus();\n    std::vector<string> dataMgrNames = dataStatus->GetDataMgrNames();\n\n    if ((_scriptName == \"\") || (_dataMgrName == \"\") || ((std::find(dataMgrNames.begin(), dataMgrNames.end(), _dataMgrName) == dataMgrNames.end()))) {\n        _reset();\n        _setGUIEnabled(false);\n    } else {\n        _setGUIEnabled(true);\n        if (_includeCoordVars) {\n            _coordVarsEnabled.clear();\n            _coordVarsEnabled.resize(_coordVars.size(), false);\n            _findEnabledCoordinateVariables(_2DVars, _2DVarsEnabled);\n            _findEnabledCoordinateVariables(_3DVars, _3DVarsEnabled);\n        }\n    }\n\n    _scriptNameLabel->setText(QString::fromStdString(_scriptName));\n    _dataMgrNameLabel->setText(QString::fromStdString(_dataMgrName));\n    _scriptEdit->setText(QString::fromStdString(_script));\n\n    int                 numRows;\n    int                 numCols = 2;\n    std::vector<string> tableValuesCoords, tableValues2D;\n    std::vector<string> tableValues3D, summaryValues;\n    _makeInputTableValues(tableValuesCoords, tableValues2D, tableValues3D, summaryValues);\n\n    _coordInputVarTable->blockSignals(true);\n    _2DInputVarTable->blockSignals(true);\n    _3DInputVarTable->blockSignals(true);\n    _summaryTable->blockSignals(true);\n    _outputVarTable->blockSignals(true);\n\n    numRows = _coordVars.size();\n    _coordInputVarTable->Update(numRows, numCols, tableValuesCoords);\n\n    numRows = _2DVars.size();\n    _2DInputVarTable->Update(numRows, numCols, tableValues2D);\n\n    numRows = _3DVars.size();\n    _3DInputVarTable->Update(numRows, numCols, tableValues3D);\n\n    numRows = summaryValues.size() / 2;\n    _summaryTable->Update(numRows, numCols, summaryValues);\n\n    std::vector<string> outputValues;\n    _makeOutputTableValues(outputValues);\n    numRows = outputValues.size() / 2;\n    _outputVarTable->Update(numRows, numCols, outputValues);\n    _outputVarTable->StretchToColumn(1);\n\n    _coordInputVarTable->blockSignals(false);\n    _2DInputVarTable->blockSignals(false);\n    _3DInputVarTable->blockSignals(false);\n    _summaryTable->blockSignals(false);\n    _outputVarTable->blockSignals(false);\n}\n\nvoid PythonVariables::_connectWidgets()\n{\n    connect(_newScriptButton, SIGNAL(clicked()), this, SLOT(_newScript()));\n    connect(_openScriptButton, SIGNAL(clicked()), this, SLOT(_openScript()));\n    connect(_deleteScriptButton, SIGNAL(clicked()), this, SLOT(_deleteScript()));\n    connect(_importScriptButton, SIGNAL(clicked()), this, SLOT(_importScript()));\n    connect(_exportScriptButton, SIGNAL(clicked()), this, SLOT(_exportScript()));\n    connect(_testScriptButton, SIGNAL(clicked()), this, SLOT(_testScript()));\n    connect(_saveScriptButton, SIGNAL(clicked()), this, SLOT(_saveScript()));\n    connect(_closeButton, SIGNAL(clicked()), this, SLOT(_closeScript()));\n\n    connect(_coordInputVarTable, SIGNAL(valueChanged(int, int)), this, SLOT(_coordInputVarChanged(int, int)));\n    connect(_2DInputVarTable, SIGNAL(valueChanged(int, int)), this, SLOT(_2DInputVarChanged(int, int)));\n    connect(_3DInputVarTable, SIGNAL(valueChanged(int, int)), this, SLOT(_3DInputVarChanged(int, int)));\n\n    connect(_coordinatesCheckbox, SIGNAL(stateChanged(int)), this, SLOT(_coordinatesCheckboxClicked(int)));\n\n    connect(_scriptEdit, SIGNAL(textChanged()), this, SLOT(_scriptChanged()));\n\n    connect(_newOutVarButton, SIGNAL(clicked()), this, SLOT(_createNewVariable()));\n    connect(_deleteOutVarButton, SIGNAL(clicked()), this, SLOT(_deleteVariable()));\n}\n\nvoid PythonVariables::_setGUIEnabled(bool enabled)\n{\n    _variableSelectionFrame->setEnabled(enabled);\n    _scriptEdit->setEnabled(enabled);\n    _testScriptButton->setEnabled(enabled);\n    _saveScriptButton->setEnabled(enabled);\n    _exportScriptButton->setEnabled(enabled);\n    _importScriptButton->setEnabled(enabled);\n    _exportScriptButton->setEnabled(enabled);\n}\n\nvoid PythonVariables::_updateNewItemDialog()\n{\n    VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus();\n    std::vector<string> dataMgrNames = dataStatus->GetDataMgrNames();\n    _newItemDialog->Update(::NewItemDialog::SCRIPT, dataMgrNames);\n}\n\nvoid PythonVariables::_newScript()\n{\n    VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus();\n    std::vector<string> dataMgrNames = dataStatus->GetDataMgrNames();\n    _newItemDialog->Update(::NewItemDialog::SCRIPT, dataMgrNames);\n\n    _newItemDialog->exec();\n    int rc = _newItemDialog->result();\n\n    if (rc > 0) {\n        string scriptName = _newItemDialog->GetItemName();\n        if (scriptName == \"\") return;\n\n        scriptName = _controlExec->MakeStringConformant(scriptName);\n\n        _reset();\n        _scriptName = scriptName;\n        _dataMgrName = _newItemDialog->GetOptionName();\n\n        _scriptNameLabel->setText(QString::fromStdString(_scriptName));\n        _dataMgrNameLabel->setText(QString::fromStdString(_dataMgrName));\n\n        VAPoR::DataMgr *dataMgr = dataStatus->GetDataMgr(_dataMgrName);\n        _coordVars = dataMgr->GetCoordVarNames();\n        _coordVarsEnabled.resize(_coordVars.size());\n        std::fill(_coordVarsEnabled.begin(), _coordVarsEnabled.end(), false);\n\n        _2DVars = dataMgr->GetDataVarNames(TWOD);\n        _2DVarsEnabled.resize(_2DVars.size());\n        std::fill(_2DVarsEnabled.begin(), _2DVarsEnabled.end(), false);\n\n        _3DVars = dataMgr->GetDataVarNames(THREED);\n        _3DVarsEnabled.resize(_3DVars.size());\n        std::fill(_3DVarsEnabled.begin(), _3DVarsEnabled.end(), false);\n\n        Update();\n    }\n}\n\nvoid PythonVariables::_reset()\n{\n    _script = \"\";\n    _scriptName = \"\";\n    _dataMgrName = \"\";\n    _justSaved = false;\n    _coordVars.clear();\n    _coordVarsEnabled.clear();\n    _2DVars.clear();\n    _2DVarsEnabled.clear();\n    _3DVars.clear();\n    _3DVarsEnabled.clear();\n    _outputVars.clear();\n    _outputGrids.clear();\n    _inputGrids.clear();\n    _otherGrids.clear();\n}\n\nvoid PythonVariables::_openScript()\n{\n    int rc = _openAndDeleteDialog->Update(OpenAndDeleteDialog::_OPEN, _controlExec);\n\n    if (rc < 0) return;\n\n    _openAndDeleteDialog->exec();\n\n    rc = _openAndDeleteDialog->result();\n\n    if (rc > 0) {\n        _reset();\n\n        string scriptName = _openAndDeleteDialog->GetScriptName();\n        string dataMgrName = _openAndDeleteDialog->GetDataMgrName();\n\n        std::vector<string> inputVars;\n\n        bool coordFlag;    // TODO: add support for coordinate flag\n        bool rc2 = _controlExec->GetFunction(_scriptType, dataMgrName, scriptName, _script, inputVars, _outputVars, _outputGrids, coordFlag);\n        if (rc2 == false) {\n            MSG_ERR(\"Invalid script: \" + scriptName);\n            return;\n        }\n\n        _dataMgrName = dataMgrName;\n        _scriptName = scriptName;\n\n        VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus();\n        VAPoR::DataMgr *   dataMgr = dataStatus->GetDataMgr(_dataMgrName);\n\n        _coordVars = dataMgr->GetCoordVarNames();\n        _coordVarsEnabled.resize(_coordVars.size(), false);\n        _2DVars = dataMgr->GetDataVarNames(TWOD);\n        _2DVarsEnabled.resize(_2DVars.size(), false);\n        _3DVars = dataMgr->GetDataVarNames(THREED);\n        _3DVarsEnabled.resize(_3DVars.size(), false);\n\n        std::vector<string>::iterator it;\n\n        for (int i = 0; i < inputVars.size(); i++) {\n            string inVar = inputVars[i];\n\n            it = std::find(_coordVars.begin(), _coordVars.end(), inVar);\n            if (it != _coordVars.end()) {\n                int index = it - _coordVars.begin();\n                _coordVarsEnabled[index] = true;\n            }\n\n            it = std::find(_2DVars.begin(), _2DVars.end(), inVar);\n            if (it != _2DVars.end()) {\n                int index = it - _2DVars.begin();\n                _2DVarsEnabled[index] = true;\n            }\n\n            it = std::find(_3DVars.begin(), _3DVars.end(), inVar);\n            if (it != _3DVars.end()) {\n                int index = it - _3DVars.begin();\n                _3DVarsEnabled[index] = true;\n            }\n        }\n\n        _inputGrids.clear();\n        _otherGrids.clear();\n\n        Update();\n    }\n}\n\nvoid PythonVariables::_deleteScript()\n{\n    int rc = _openAndDeleteDialog->Update(OpenAndDeleteDialog::_DELETE, _controlExec);\n\n    if (rc < 0) return;\n\n    _openAndDeleteDialog->exec();\n\n    rc = _openAndDeleteDialog->result();\n    if (rc < 1) return;\n\n    string scriptName = _openAndDeleteDialog->GetScriptName();\n    string dataMgrName = _openAndDeleteDialog->GetDataMgrName();\n\n    _controlExec->RemoveFunction(_scriptType, dataMgrName, scriptName);\n\n    if (scriptName == _scriptName) _reset();\n\n    Update();\n}\n\nbool PythonVariables::_getFilePath(QString &filePath, bool operation)\n{\n    QFileDialog::AcceptMode acceptMode = QFileDialog::AcceptOpen;\n    QFileDialog::FileMode   fileMode = QFileDialog::ExistingFile;\n    QString                 title = \"Import Python script from file\";\n\n    if (operation == WRITE) {\n        acceptMode = QFileDialog::AcceptSave;\n        fileMode = QFileDialog::AnyFile;\n        title = \"Export your Python script to a file\";\n    }\n\n    string      pythonPath = Wasp::GetSharePath(\"python\");\n    QFileDialog fileDialog(this, \"Import Python script from file\", QString::fromStdString(pythonPath), QString(\"Python file (*.py)\"));\n\n    fileDialog.setAcceptMode(acceptMode);\n    fileDialog.setDefaultSuffix(QString(\"py\"));\n    fileDialog.setFileMode(fileMode);\n    if (fileDialog.exec() != QDialog::Accepted) return false;\n\n    QStringList files = fileDialog.selectedFiles();\n    if (files.size() != 1) return false;\n\n    filePath = files[0];\n\n    bool operable;\n    if (operation == READ)\n        operable = FileOperationChecker::FileGoodToRead(filePath);\n    else\n        operable = FileOperationChecker::FileGoodToWrite(filePath);\n    if (!operable) {\n        MSG_ERR(FileOperationChecker::GetLastErrorMessage().toStdString());\n        return false;\n    }\n\n    return true;\n}\n\nvoid PythonVariables::_importScript()\n{\n    QString filePath;\n    if (!_getFilePath(filePath, READ)) return;\n\n    _script.clear();\n    std::ifstream file;\n    file.open(filePath.toStdString());\n    if (file.is_open()) {\n        std::string line;\n        while (getline(file, line)) {\n            _script += line;\n            _script += \"\\n\";\n        }\n    }\n\n    Update();\n}\n\nvoid PythonVariables::_exportScript()\n{\n    QString filePath;\n    if (!_getFilePath(filePath, WRITE)) return;\n\n    qDebug() << filePath;\n\n    std::ofstream file;\n    file.open(filePath.toStdString());\n    file << _script;\n    file.close();\n}\n\nvoid PythonVariables::_testScript()\n{\n    string script = _scriptEdit->toPlainText().toStdString();\n\n    std::vector<string> inputVars = _buildInputVars();\n\n    if (inputVars.empty() || _outputVars.empty()) {\n        MSG_ERR(\"At least one Input Variable and one \"\n                \"Output Variable must be defined\");\n        return;\n    }\n\n    int rc = _controlExec->AddFunction(_scriptType, _dataMgrName, _scriptName, script, inputVars, _outputVars, _outputGrids, _includeCoordVars);\n\n    if (rc < 0) {\n        MSG_ERR(\"Failed to add script\");\n        return;\n    }\n\n    DataMgr *dataMgr = _controlExec->GetDataStatus()->GetDataMgr(_dataMgrName);\n\n    string varname = _outputVars[0];\n    Grid * g = dataMgr->GetVariable(0, varname, 0, 0);\n    if (!g) {\n        MSG_ERR(\"Failed to calculate variable \" + varname);\n        return;\n    }\n\n    //\n    // Get any output from script\n    //\n    string      s = _controlExec->GetFunctionStdout(_scriptType, _dataMgrName, _scriptName);\n    QMessageBox msgBox;\n    if (!s.empty()) {\n        msgBox.setText(\"Script output:\");\n        msgBox.setInformativeText(s.c_str());\n        msgBox.exec();\n    }\n\n    msgBox.setText(\"Test passed.\");\n    msgBox.exec();\n}\n\nvoid PythonVariables::_saveScript()\n{\n    string script = _scriptEdit->toPlainText().toStdString();\n\n    std::vector<string> inputVars = _buildInputVars();\n\n    int rc = _controlExec->AddFunction(_scriptType, _dataMgrName, _scriptName, script, inputVars, _outputVars, _outputGrids, _includeCoordVars);\n\n    if (rc < 0) {\n        MSG_ERR(\"Invalid syntax\");\n        return;\n    }\n\n    QMessageBox msgBox;\n    msgBox.setText(\"Script saved to session.\");\n    msgBox.exec();\n}\n\nstd::vector<string> PythonVariables::_buildInputVars() const\n{\n    std::vector<string> inputVars;\n    for (int i = 0; i < _2DVars.size(); i++) {\n        if (_2DVarsEnabled[i] == true) inputVars.push_back(_2DVars[i]);\n    }\n    for (int i = 0; i < _3DVars.size(); i++) {\n        if (_3DVarsEnabled[i] == true) inputVars.push_back(_3DVars[i]);\n    }\n\n    return inputVars;\n}\n\nvoid PythonVariables::_closeScript() { close(); }\n\nvoid PythonVariables::_coordInputVarChanged(int row, int col)\n{\n    if (col == 0) return;\n\n    string value = _coordInputVarTable->GetValue(row, col);\n    if (value == \"1\")\n        _coordVarsEnabled[row] = true;\n    else\n        _coordVarsEnabled[row] = false;\n\n    Update();\n}\n\nvoid PythonVariables::_2DInputVarChanged(int row, int col)\n{\n    if (col == 0) return;\n\n    string value = _2DInputVarTable->GetValue(row, col);\n    if (value == \"1\")\n        _2DVarsEnabled[row] = true;\n    else\n        _2DVarsEnabled[row] = false;\n\n    Update();\n}\n\nvoid PythonVariables::_3DInputVarChanged(int row, int col)\n{\n    if (col == 0) return;\n\n    string value = _3DInputVarTable->GetValue(row, col);\n    if (value == \"1\")\n        _3DVarsEnabled[row] = true;\n    else\n        _3DVarsEnabled[row] = false;\n\n    Update();\n}\n\nvoid PythonVariables::_coordinatesCheckboxClicked(int state)\n{\n    if (state == Qt::Unchecked) {\n        _includeCoordVars = false;\n        _variableTabs->removeTab(0);\n        _coordVarsEnabled.resize(_coordVars.size());\n        std::fill(_coordVarsEnabled.begin(), _coordVarsEnabled.end(), false);\n    } else {\n        _includeCoordVars = true;\n        _variableTabs->insertTab(0, _coordTab, \"Coordinates\");\n    }\n    Update();\n}\n\nvoid PythonVariables::_findEnabledCoordinateVariables(const std::vector<string> vars, const std::vector<bool> varsEnabled)\n{\n    VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus();\n    VAPoR::DataMgr *   dataMgr = dataStatus->GetDataMgr(_dataMgrName);\n    if (dataMgr == NULL) { MSG_ERR(\"Invalid DataMgr \" + _dataMgrName); }\n\n    std::vector<string> enabledCoordVarNames;\n    std::vector<string> tmpCoordVarNames;\n    VAPoR::DC::DataVar  dataVar;\n    VAPoR::DC::Mesh     mesh;\n\n    // Gather the currently used coord variables\n    for (int i = 0; i < vars.size(); i++) {\n        if (varsEnabled[i] == false) continue;\n\n        string varName = vars[i];\n        dataMgr->GetDataVarInfo(varName, dataVar);\n        string meshName = dataVar.GetMeshName();\n        dataMgr->GetMesh(meshName, mesh);\n        tmpCoordVarNames = mesh.GetCoordVars();\n\n        std::move(tmpCoordVarNames.begin(), tmpCoordVarNames.end(), std::back_inserter(enabledCoordVarNames));\n    }\n\n    // Set current coord variables to be enabled\n    for (int i = 0; i < _coordVars.size(); i++) {\n        for (int j = 0; j < enabledCoordVarNames.size(); j++) {\n            if (_coordVars[i] == enabledCoordVarNames[j]) { _coordVarsEnabled[i] = true; }\n        }\n    }\n}\n\nvoid PythonVariables::_createNewVariable()\n{\n    VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus();\n    VAPoR::DataMgr *   dataMgr = dataStatus->GetDataMgr(_dataMgrName);\n    if (dataMgr == NULL) MSG_ERR(\"Invalid DataMgr \" + _dataMgrName);\n\n    std::vector<string> grids = dataMgr->GetMeshNames();\n\n    std::vector<string> options = _makeDialogOptions(grids);\n\n    std::vector<int> cateogryIndices;\n    cateogryIndices.push_back(0);\n    cateogryIndices.push_back(_inputGrids.size() + 1);\n\n    _newItemDialog->Update(::NewItemDialog::OUTVAR, options, cateogryIndices);\n    _newItemDialog->exec();\n\n    int rc = _newItemDialog->result();\n    if (rc < 1) return;\n\n    string outputVar = _newItemDialog->GetItemName();\n\n    if (outputVar == \"\") return;\n\n    rc = _checkForDuplicateNames(_outputVars, outputVar);\n    if (rc < 1) return;\n\n    _outputVars.push_back(outputVar);\n    string outputGrid = _newItemDialog->GetOptionName();\n    _outputGrids.push_back(outputGrid);\n\n    Update();\n}\n\nstd::vector<string> PythonVariables::_makeDialogOptions(std::vector<string> grids)\n{\n    std::vector<string> options;\n    string              inputVarGrid;\n    bool                gridSelected;\n\n    _inputGrids.clear();\n    _otherGrids.clear();\n\n    for (int i = 0; i < grids.size(); i++) {\n        string grid = grids[i];\n        gridSelected = _isGridSelected(grid, _2DVars, _2DVarsEnabled);\n        if (gridSelected) {\n            _inputGrids.push_back(grid);\n            continue;\n        }\n\n        gridSelected = _isGridSelected(grid, _3DVars, _3DVarsEnabled);\n        if (gridSelected) {\n            _inputGrids.push_back(grid);\n            continue;\n        }\n\n        _otherGrids.push_back(grids[i]);\n    }\n\n    options.push_back(\"Input variable grids:\");\n    for (int i = 0; i < _inputGrids.size(); i++) { options.push_back(_inputGrids[i]); }\n    options.push_back(\"Other grids:\");\n    for (int i = 0; i < _otherGrids.size(); i++) { options.push_back(_otherGrids[i]); }\n\n    return options;\n}\n\nbool PythonVariables::_isGridSelected(string grid, std::vector<string> variables, std::vector<bool> varEnabled) const\n{\n    VAPoR::DC::DataVar dataVar;\n    string             inputVarGrid;\n    bool               isInputGrid = false;\n\n    for (int j = 0; j < variables.size(); j++) {\n        if (varEnabled[j] == false) { continue; }\n\n        VAPoR::DataStatus *dataStatus = _controlExec->GetDataStatus();\n        VAPoR::DataMgr *   dataMgr = dataStatus->GetDataMgr(_dataMgrName);\n        int                rc = dataMgr->GetDataVarInfo(variables[j], dataVar);\n        if (!rc) { continue; }\n\n        inputVarGrid = dataVar.GetMeshName();\n        if (grid == inputVarGrid) {\n            isInputGrid = true;\n            break;\n        }\n    }\n    return isInputGrid;\n}\n\nvoid PythonVariables::_deleteVariable()\n{\n    int activeRow = _outputVarTable->GetActiveRow();\n    if (activeRow < 0) return;\n\n    string varName = _outputVarTable->GetValue(activeRow, 0);\n    auto   it = std::find(_outputVars.begin(), _outputVars.end(), varName);\n    int    index = std::distance(_outputVars.begin(), it);\n\n    _outputVars.erase(_outputVars.begin() + index);\n    _outputGrids.erase(_outputGrids.begin() + index);\n    Update();\n}\n\nvoid PythonVariables::_scriptChanged() { _script = _scriptEdit->toPlainText().toStdString(); }\n\nvoid PythonVariables::_makeInputTableValues(std::vector<string> &tableValuesCoords, std::vector<string> &tableValues2D, std::vector<string> &tableValues3D, std::vector<string> &summaryValues) const\n{\n    string onOff;\n    for (int i = 0; i < _2DVars.size(); i++) {\n        tableValues2D.push_back(_2DVars[i]);\n\n        onOff = \"0\";\n        if (_2DVarsEnabled[i]) {\n            onOff = \"1\";\n            summaryValues.push_back(_2DVars[i]);\n            summaryValues.push_back(\"2D\");\n        }\n        tableValues2D.push_back(onOff);\n    }\n\n    for (int i = 0; i < _3DVars.size(); i++) {\n        tableValues3D.push_back(_3DVars[i]);\n\n        onOff = \"0\";\n        if (_3DVarsEnabled[i]) {\n            onOff = \"1\";\n            summaryValues.push_back(_3DVars[i]);\n            summaryValues.push_back(\"3D\");\n        }\n        tableValues3D.push_back(onOff);\n    }\n\n    for (int i = 0; i < _coordVars.size(); i++) {\n        tableValuesCoords.push_back(_coordVars[i]);\n\n        onOff = \"0\";\n        if (_coordVarsEnabled[i]) {\n            onOff = \"1\";\n            summaryValues.push_back(_coordVars[i]);\n            summaryValues.push_back(\"Coordinate\");\n        }\n        tableValuesCoords.push_back(onOff);\n    }\n}\n\nvoid PythonVariables::_makeOutputTableValues(std::vector<string> &outputValues) const\n{\n    for (int i = 0; i < _outputVars.size(); i++) {\n        outputValues.push_back(_outputVars[i]);\n        outputValues.push_back(_outputGrids[i]);\n    }\n}\n\nint PythonVariables::_checkForDuplicateNames(std::vector<string> names, string name)\n{\n    std::vector<string>::iterator it;\n    it = std::find(names.begin(), names.end(), name);\n    if (it == names.end())\n        return 1;\n    else {\n        MSG_ERR(\"Names must be unique\");\n        return 0;\n    }\n}\n\nvoid PythonVariables::InitControlExec(VAPoR::ControlExec *ce)\n{\n    VAssert(ce);\n    _controlExec = ce;\n}\n\nvoid PythonVariables::ShowMe()\n{\n    Update();\n    open();\n}\n\nNewItemDialog::NewItemDialog(QWidget *parent) : QDialog(parent)\n{\n    setModal(true);\n\n    _itemNameLabel = new QLabel(tr(\"Script name:\"));\n    _itemNameEdit = new QLineEdit();\n    _optionNameLabel = new QLabel(tr(\"Data Set:\"));\n    _optionNameCombo = new QComboBox();\n    _okButton = new QPushButton(tr(\"Ok\"));\n    _cancelButton = new QPushButton(tr(\"Cancel\"));\n\n    _okButton->setAutoDefault(true);\n    _cancelButton->setAutoDefault(false);\n\n    _setupGUI();\n\n    _connectWidgets();\n\n    _itemNameEdit->setFocus();\n}\n\nvoid NewItemDialog::_connectWidgets()\n{\n    connect(_okButton, SIGNAL(clicked()), this, SLOT(_okClicked()));\n    connect(_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));\n}\n\nvoid NewItemDialog::_setupGUI()\n{\n    QVBoxLayout *topLeftLayout = new QVBoxLayout;\n    QVBoxLayout *topRightLayout = new QVBoxLayout;\n    QHBoxLayout *topLayout = new QHBoxLayout;\n    QHBoxLayout *bottomLayout = new QHBoxLayout;\n    QVBoxLayout *mainLayout = new QVBoxLayout;\n\n    topLeftLayout->addWidget(_itemNameLabel);\n    topLeftLayout->addWidget(_optionNameLabel);\n\n    topRightLayout->addWidget(_itemNameEdit);\n    topRightLayout->addWidget(_optionNameCombo);\n\n    topLayout->addLayout(topLeftLayout);\n    topLayout->addLayout(topRightLayout);\n\n    bottomLayout->addWidget(_cancelButton);\n    bottomLayout->addWidget(_okButton);\n\n    mainLayout->addLayout(topLayout);\n    mainLayout->addLayout(bottomLayout);\n\n    setLayout(mainLayout);\n}\n\nvoid NewItemDialog::Update(int type, std::vector<string> optionNames, std::vector<int> categoryIndices)\n{\n    _adjustToType(type);\n\n    _itemName = \"\";\n    _optionName = \"\";\n\n    _itemNameEdit->clear();\n    _optionNameCombo->clear();\n    for (int i = 0; i < optionNames.size(); i++) {\n        QString qName = QString::fromStdString(optionNames[i]);\n        _optionNameCombo->addItem(qName);\n    }\n\n    bool nextIndexIsInvalid = true;\n    int  size = categoryIndices.size();\n    for (int i = 0; i < size; i++) {\n        _disableComboItem(categoryIndices[i]);\n\n        if (nextIndexIsInvalid && categoryIndices[i] + 1 != categoryIndices[i + 1] && i != size) {\n            nextIndexIsInvalid = false;\n            _optionNameCombo->setCurrentIndex(categoryIndices[i] + 1);\n        }\n    }\n}\n\nvoid NewItemDialog::_disableComboItem(int index)\n{\n    QStandardItemModel *model = qobject_cast<QStandardItemModel *>(_optionNameCombo->model());\n    bool                disabled = true;\n    QStandardItem *     item = model->item(index);\n    item->setFlags(disabled ? item->flags() & ~Qt::ItemIsEnabled : item->flags() | Qt::ItemIsEnabled);\n}\n\nvoid NewItemDialog::_adjustToType(int type)\n{\n    if (type == SCRIPT) {\n        setWindowTitle(\"Create new script\");\n        _itemNameLabel->setText(\"Script name:\");\n        _optionNameLabel->setText(\"Data Set:\");\n    } else if (type == OUTVAR) {\n        setWindowTitle(\"Create new variable\");\n        _itemNameLabel->setText(\"Variable name:\");\n        _optionNameLabel->setText(\"Output Grid:\");\n    }\n}\n\nvoid ::NewItemDialog::_okClicked()\n{\n    _itemName = _itemNameEdit->text().toStdString();\n    _optionName = _optionNameCombo->currentText().toStdString();\n\n    _itemNameEdit->clear();\n\n    accept();\n}\n\nstring NewItemDialog::GetItemName() const { return _itemName; }\n\nstring NewItemDialog::GetOptionName() const { return _optionName; }\n\nOpenAndDeleteDialog::OpenAndDeleteDialog(QWidget *parent)\n{\n    setModal(true);\n\n    _dataMgrNameLabel = new QLabel(tr(\"Data Set name:\"));\n    _dataMgrNameCombo = new QComboBox();\n    _scriptNameLabel = new QLabel(tr(\"Script:\"));\n    _scriptNameCombo = new QComboBox();\n    _okButton = new QPushButton(tr(\"Ok\"));\n    _cancelButton = new QPushButton(tr(\"Cancel\"));\n\n    _okButton->setAutoDefault(true);\n    _cancelButton->setAutoDefault(false);\n\n    _setupGUI();\n\n    _dataMgrNameCombo->setFocus();\n\n    connect(_okButton, SIGNAL(clicked()), this, SLOT(_okClicked()));\n    connect(_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));\n    connect(_dataMgrNameCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_updateOptions(int)));\n}\n\nvoid OpenAndDeleteDialog::_updateOptions(int index)\n{\n    string              dataSetName = _dataMgrNameCombo->itemText(index).toStdString();\n    std::vector<string> functionNames;\n    functionNames = _controlExec->GetFunctionNames(_scriptType, dataSetName);\n\n    _scriptNameCombo->clear();\n    for (int i = 0; i < functionNames.size(); i++) {\n        QString qName = QString::fromStdString(functionNames[i]);\n        _scriptNameCombo->addItem(qName);\n    }\n}\n\nvoid OpenAndDeleteDialog::_setupGUI()\n{\n    QVBoxLayout *topLeftLayout = new QVBoxLayout;\n    QVBoxLayout *topRightLayout = new QVBoxLayout;\n    QHBoxLayout *topLayout = new QHBoxLayout;\n    QHBoxLayout *bottomLayout = new QHBoxLayout;\n    QVBoxLayout *mainLayout = new QVBoxLayout;\n\n    topLeftLayout->addWidget(_dataMgrNameLabel);\n    topLeftLayout->addWidget(_scriptNameLabel);\n\n    topRightLayout->addWidget(_dataMgrNameCombo);\n    topRightLayout->addWidget(_scriptNameCombo);\n\n    topLayout->addLayout(topLeftLayout);\n    topLayout->addLayout(topRightLayout);\n\n    bottomLayout->addWidget(_cancelButton);\n    bottomLayout->addWidget(_okButton);\n\n    mainLayout->addLayout(topLayout);\n    mainLayout->addLayout(bottomLayout);\n\n    setLayout(mainLayout);\n}\n\nint OpenAndDeleteDialog::Update(int type, VAPoR::ControlExec *controlExec)\n{\n    _controlExec = controlExec;\n\n    string errMsg;\n    if (type == _OPEN) {\n        setWindowTitle(\"Open saved script\");\n        errMsg = \"There are no scripts to open in this session\";\n    } else if (type == _DELETE) {\n        setWindowTitle(\"Delete saved script\");\n        errMsg = \"There are no scripts to delete in this session\";\n    }\n\n    _dataMgrNameCombo->clear();\n    _scriptNameCombo->clear();\n\n    VAPoR::DataStatus * dataStatus = _controlExec->GetDataStatus();\n    std::vector<string> dataMgrNames = dataStatus->GetDataMgrNames();\n    std::vector<string> scriptNames;\n    for (int i = 0; i < dataMgrNames.size(); i++) {\n        QString qName = QString::fromStdString(dataMgrNames[i]);\n        _dataMgrNameCombo->addItem(qName);\n\n        if (scriptNames.empty()) {\n            scriptNames = controlExec->GetFunctionNames(_scriptType, dataMgrNames[i]);\n            _dataMgrNameCombo->setCurrentIndex(i);\n            _dataMgrName = dataMgrNames[i];\n        }\n    }\n\n    if (scriptNames.empty()) {\n        MSG_ERR(errMsg);\n        return -1;\n    }\n\n    _scriptName = _scriptNameCombo->currentText().toStdString();\n\n    return 0;\n}\n\nvoid OpenAndDeleteDialog::_okClicked()\n{\n    _dataMgrName = _dataMgrNameCombo->currentText().toStdString();\n    _scriptName = _scriptNameCombo->currentText().toStdString();\n\n    accept();\n}\n\nstring OpenAndDeleteDialog::GetDataMgrName() const { return _dataMgrName; }\n\nstring OpenAndDeleteDialog::GetScriptName() const { return _scriptName; }\n"
  },
  {
    "path": "apps/vaporgui/PythonVariables.h",
    "content": "#ifndef PYTHOVARIABLES_H\n#define PYTHOVARIABLES_H\n\n#include <vapor/ControlExecutive.h>\n\n#include \"ui_PythonVariablesGUI.h\"\n#include \"PythonVariablesParams.h\"\n#include \"VaporTable.h\"\n#include \"Updatable.h\"\n\n#include <QThread>\n#include <QDialog>\n#include <QMenuBar>\n#include <QComboBox>\n#include <QMenu>\n\n//\n// QObjects do not support nested classes, so use a namespace\n//\nnamespace PythonVariables_ {\nclass NewItemDialog;\nclass OpenAndDeleteDialog;\n\nstatic const string _scriptType = \"Python\";\n}    // namespace PythonVariables_\n\nclass PythonVariables : public QDialog, public Updatable, Ui_PythonVariablesGUI {\n    Q_OBJECT\n\npublic:\n    PythonVariables(QWidget *parent);\n    ~PythonVariables();\n    void Update();\n    void InitControlExec(VAPoR::ControlExec *ce);\n    void ShowMe();\n\nprivate slots:\n    void _newScript();\n    void _openScript();\n    void _deleteScript();\n    void _importScript();\n    void _exportScript();\n    bool _getFilePath(QString &filePath, bool operation = true);\n    void _testScript();\n    void _saveScript();\n    void _closeScript();\n\n    void _createNewVariable();\n    void _deleteVariable();\n    void _scriptChanged();\n\n    void _coordInputVarChanged(int row, int col);\n    void _2DInputVarChanged(int row, int col);\n    void _3DInputVarChanged(int row, int col);\n\n    void _findEnabledCoordinateVariables(const std::vector<string> variables, const std::vector<bool> variablesEnabled);\n    void _coordinatesCheckboxClicked(int state);\n\nprivate:\n    const QColor *_background;\n\n    VAPoR::ControlExec *_controlExec;\n\n    PythonVariables_::NewItemDialog *      _newItemDialog;\n    PythonVariables_::OpenAndDeleteDialog *_openAndDeleteDialog;\n\n    VaporTable *_coordInputVarTable;\n    VaporTable *_2DInputVarTable;\n    VaporTable *_3DInputVarTable;\n    VaporTable *_summaryTable;\n    VaporTable *_outputVarTable;\n\n    string _script;\n    string _scriptName;\n    string _dataMgrName;\n\n    bool _justSaved;\n    bool _includeCoordVars;\n\n    std::vector<string> _coordVars;\n    std::vector<bool>   _coordVarsEnabled;\n    std::vector<string> _2DVars;\n    std::vector<bool>   _2DVarsEnabled;\n    std::vector<string> _3DVars;\n    std::vector<bool>   _3DVarsEnabled;\n    std::vector<string> _outputVars;\n    std::vector<string> _outputGrids;\n    std::vector<string> _inputGrids;\n    std::vector<string> _otherGrids;\n\n    void                _connectWidgets();\n    void                _setGUIEnabled(bool enabled);\n    void                _makeInputTableValues(std::vector<string> &tableValuesCoords, std::vector<string> &tableValues2D, std::vector<string> &tableValues3D, std::vector<string> &summaryValues) const;\n    void                _makeOutputTableValues(std::vector<string> &outputValues) const;\n    std::vector<string> _makeDialogOptions(std::vector<string> grids);\n    std::vector<string> _buildInputVars() const;\n    int                 _checkForDuplicateNames(std::vector<string> names, string name);\n    bool                _isGridSelected(string grid, std::vector<string> selectedVars, std::vector<bool> varEnabled) const;\n    void                _saveToSession();\n\n    void _updateNewItemDialog();\n    void _updateLabelColor(int r, int g, int b, QLabel *label);\n\n    void _reset();\n};\n\nnamespace PythonVariables_ {\n\nclass NewItemDialog : public QDialog {\n    Q_OBJECT\n\npublic:\n    enum { SCRIPT = 0, OUTVAR = 1 };\n\n    NewItemDialog(QWidget *parent = 0);\n    ~NewItemDialog(){};\n\n    void   Update(int type, std::vector<string> optionNames, std::vector<int> categoryItems = std::vector<int>());\n    string GetItemName() const;\n    string GetOptionName() const;\n\nprivate:\n    void _connectWidgets();\n    void _setupGUI();\n    void _adjustToType(int type);\n    void _disableComboItem(int index);\n\n    string _itemName;\n    string _optionName;\n\n    QLabel *     _itemNameLabel;\n    QLineEdit *  _itemNameEdit;\n    QLabel *     _optionNameLabel;\n    QComboBox *  _optionNameCombo;\n    QPushButton *_okButton;\n    QPushButton *_cancelButton;\n\nprivate slots:\n    void _okClicked();\n};\n\nclass OpenAndDeleteDialog : public QDialog {\n    Q_OBJECT\n\npublic:\n    enum {\n        _OPEN = 0,\n        _DELETE = 1    // DELETE is a reserved keyword on Windows\n    };\n\n    OpenAndDeleteDialog(QWidget *parent = 0);\n    ~OpenAndDeleteDialog(){};\n\n    int Update(int type, VAPoR::ControlExec *controlExec);\n\n    string GetDataMgrName() const;\n    string GetScriptName() const;\n\nprivate:\n    void _setupGUI();\n\n    string _dataMgrName;\n    string _scriptName;\n\n    QLabel *     _dataMgrNameLabel;\n    QComboBox *  _dataMgrNameCombo;\n    QLabel *     _scriptNameLabel;\n    QComboBox *  _scriptNameCombo;\n    QPushButton *_okButton;\n    QPushButton *_cancelButton;\n\n    VAPoR::ControlExec *_controlExec;\n\nprivate slots:\n    void _okClicked();\n    void _updateOptions(int index);\n};\n\n}    // namespace PythonVariables_\n\n#endif    // PYTHOVARIABLES_H\n"
  },
  {
    "path": "apps/vaporgui/PythonVariablesGUI.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>PythonVariablesGUI</class>\n <widget class=\"QDialog\" name=\"PythonVariablesGUI\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>591</width>\n    <height>685</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Dialog</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\" stretch=\"0,0,0,1,0\">\n   <property name=\"spacing\">\n    <number>-1</number>\n   </property>\n   <item>\n    <widget class=\"QFrame\" name=\"frame_6\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"frameShape\">\n      <enum>QFrame::NoFrame</enum>\n     </property>\n     <property name=\"frameShadow\">\n      <enum>QFrame::Raised</enum>\n     </property>\n     <layout class=\"QHBoxLayout\" name=\"horizontalLayout_9\" stretch=\"0,1,0\">\n      <property name=\"spacing\">\n       <number>-1</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <widget class=\"QFrame\" name=\"frame_18\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"frameShape\">\n         <enum>QFrame::NoFrame</enum>\n        </property>\n        <property name=\"frameShadow\">\n         <enum>QFrame::Raised</enum>\n        </property>\n        <layout class=\"QVBoxLayout\" name=\"verticalLayout_8\">\n         <property name=\"spacing\">\n          <number>0</number>\n         </property>\n         <property name=\"leftMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"topMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"rightMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"bottomMargin\">\n          <number>0</number>\n         </property>\n         <item>\n          <spacer name=\"verticalSpacer_5\">\n           <property name=\"orientation\">\n            <enum>Qt::Vertical</enum>\n           </property>\n           <property name=\"sizeType\">\n            <enum>QSizePolicy::Maximum</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>20</width>\n             <height>40</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n         <item>\n          <widget class=\"QLabel\" name=\"_pythonLabel\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"text\">\n            <string>PythonImage</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"verticalSpacer\">\n           <property name=\"orientation\">\n            <enum>Qt::Vertical</enum>\n           </property>\n           <property name=\"sizeType\">\n            <enum>QSizePolicy::Maximum</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>20</width>\n             <height>40</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n        </layout>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QFrame\" name=\"frame_14\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"frameShape\">\n         <enum>QFrame::NoFrame</enum>\n        </property>\n        <property name=\"frameShadow\">\n         <enum>QFrame::Raised</enum>\n        </property>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_10\" stretch=\"0,1\">\n         <property name=\"spacing\">\n          <number>0</number>\n         </property>\n         <property name=\"leftMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"topMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"rightMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"bottomMargin\">\n          <number>0</number>\n         </property>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_19\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_7\">\n            <item>\n             <spacer name=\"verticalSpacer_6\">\n              <property name=\"orientation\">\n               <enum>Qt::Vertical</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::Maximum</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>20</width>\n                <height>40</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n            <item>\n             <widget class=\"QLabel\" name=\"label\">\n              <property name=\"sizePolicy\">\n               <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n                <horstretch>0</horstretch>\n                <verstretch>0</verstretch>\n               </sizepolicy>\n              </property>\n              <property name=\"text\">\n               <string>Script Name:</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QLabel\" name=\"label_2\">\n              <property name=\"sizePolicy\">\n               <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n                <horstretch>0</horstretch>\n                <verstretch>0</verstretch>\n               </sizepolicy>\n              </property>\n              <property name=\"text\">\n               <string>Data Set:</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <spacer name=\"verticalSpacer_7\">\n              <property name=\"orientation\">\n               <enum>Qt::Vertical</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::Maximum</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>20</width>\n                <height>40</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_17\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_14\">\n            <item>\n             <spacer name=\"verticalSpacer_4\">\n              <property name=\"orientation\">\n               <enum>Qt::Vertical</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::Maximum</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>20</width>\n                <height>40</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n            <item>\n             <widget class=\"QLabel\" name=\"_scriptNameLabel\">\n              <property name=\"sizePolicy\">\n               <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n                <horstretch>0</horstretch>\n                <verstretch>0</verstretch>\n               </sizepolicy>\n              </property>\n              <property name=\"text\">\n               <string>Script Name</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QLabel\" name=\"_dataMgrNameLabel\">\n              <property name=\"sizePolicy\">\n               <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n                <horstretch>0</horstretch>\n                <verstretch>0</verstretch>\n               </sizepolicy>\n              </property>\n              <property name=\"text\">\n               <string>DataMgr Name</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <spacer name=\"verticalSpacer_3\">\n              <property name=\"orientation\">\n               <enum>Qt::Vertical</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::Maximum</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>20</width>\n                <height>40</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n           </layout>\n          </widget>\n         </item>\n        </layout>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QFrame\" name=\"frame\">\n        <property name=\"sizePolicy\">\n         <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n          <horstretch>0</horstretch>\n          <verstretch>0</verstretch>\n         </sizepolicy>\n        </property>\n        <property name=\"frameShape\">\n         <enum>QFrame::NoFrame</enum>\n        </property>\n        <property name=\"frameShadow\">\n         <enum>QFrame::Raised</enum>\n        </property>\n        <layout class=\"QVBoxLayout\" name=\"verticalLayout_12\">\n         <property name=\"spacing\">\n          <number>0</number>\n         </property>\n         <property name=\"leftMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"topMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"rightMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"bottomMargin\">\n          <number>0</number>\n         </property>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_15\">\n           <property name=\"sizePolicy\">\n            <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n             <horstretch>0</horstretch>\n             <verstretch>0</verstretch>\n            </sizepolicy>\n           </property>\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QHBoxLayout\" name=\"horizontalLayout_12\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_16\">\n              <property name=\"sizePolicy\">\n               <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n                <horstretch>0</horstretch>\n                <verstretch>0</verstretch>\n               </sizepolicy>\n              </property>\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n               <property name=\"spacing\">\n                <number>5</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>6</number>\n               </property>\n               <item>\n                <widget class=\"QPushButton\" name=\"_newScriptButton\">\n                 <property name=\"sizePolicy\">\n                  <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Maximum\">\n                   <horstretch>0</horstretch>\n                   <verstretch>0</verstretch>\n                  </sizepolicy>\n                 </property>\n                 <property name=\"minimumSize\">\n                  <size>\n                   <width>100</width>\n                   <height>0</height>\n                  </size>\n                 </property>\n                 <property name=\"text\">\n                  <string>New</string>\n                 </property>\n                 <property name=\"autoDefault\">\n                  <bool>true</bool>\n                 </property>\n                </widget>\n               </item>\n               <item>\n                <widget class=\"QPushButton\" name=\"_openScriptButton\">\n                 <property name=\"sizePolicy\">\n                  <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Maximum\">\n                   <horstretch>0</horstretch>\n                   <verstretch>0</verstretch>\n                  </sizepolicy>\n                 </property>\n                 <property name=\"text\">\n                  <string>Open from Session</string>\n                 </property>\n                 <property name=\"autoDefault\">\n                  <bool>false</bool>\n                 </property>\n                </widget>\n               </item>\n               <item>\n                <widget class=\"QPushButton\" name=\"_deleteScriptButton\">\n                 <property name=\"sizePolicy\">\n                  <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Maximum\">\n                   <horstretch>0</horstretch>\n                   <verstretch>0</verstretch>\n                  </sizepolicy>\n                 </property>\n                 <property name=\"text\">\n                  <string>Delete</string>\n                 </property>\n                 <property name=\"autoDefault\">\n                  <bool>false</bool>\n                 </property>\n                 <property name=\"default\">\n                  <bool>false</bool>\n                 </property>\n                 <property name=\"flat\">\n                  <bool>false</bool>\n                 </property>\n                </widget>\n               </item>\n              </layout>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"verticalSpacer_2\">\n           <property name=\"orientation\">\n            <enum>Qt::Vertical</enum>\n           </property>\n           <property name=\"sizeType\">\n            <enum>QSizePolicy::Maximum</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>20</width>\n             <height>40</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n        </layout>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QFrame\" name=\"frame_28\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"frameShape\">\n      <enum>QFrame::NoFrame</enum>\n     </property>\n     <property name=\"frameShadow\">\n      <enum>QFrame::Raised</enum>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_20\">\n      <property name=\"spacing\">\n       <number>0</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <widget class=\"QFrame\" name=\"_variableSelectionFrame\">\n        <property name=\"frameShape\">\n         <enum>QFrame::NoFrame</enum>\n        </property>\n        <property name=\"frameShadow\">\n         <enum>QFrame::Raised</enum>\n        </property>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_13\" stretch=\"0,1\">\n         <property name=\"spacing\">\n          <number>-1</number>\n         </property>\n         <property name=\"leftMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"topMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"rightMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"bottomMargin\">\n          <number>0</number>\n         </property>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_4\">\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_9\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_8\">\n              <property name=\"sizePolicy\">\n               <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n                <horstretch>0</horstretch>\n                <verstretch>0</verstretch>\n               </sizepolicy>\n              </property>\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QHBoxLayout\" name=\"horizontalLayout_5\">\n               <property name=\"spacing\">\n                <number>0</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"topMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"rightMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"bottomMargin\">\n                <number>5</number>\n               </property>\n               <item>\n                <spacer name=\"horizontalSpacer_7\">\n                 <property name=\"orientation\">\n                  <enum>Qt::Horizontal</enum>\n                 </property>\n                 <property name=\"sizeHint\" stdset=\"0\">\n                  <size>\n                   <width>40</width>\n                   <height>0</height>\n                  </size>\n                 </property>\n                </spacer>\n               </item>\n               <item>\n                <widget class=\"QLabel\" name=\"label_5\">\n                 <property name=\"sizePolicy\">\n                  <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n                   <horstretch>0</horstretch>\n                   <verstretch>0</verstretch>\n                  </sizepolicy>\n                 </property>\n                 <property name=\"text\">\n                  <string>Input Variables</string>\n                 </property>\n                </widget>\n               </item>\n               <item>\n                <spacer name=\"horizontalSpacer_5\">\n                 <property name=\"orientation\">\n                  <enum>Qt::Horizontal</enum>\n                 </property>\n                 <property name=\"sizeHint\" stdset=\"0\">\n                  <size>\n                   <width>40</width>\n                   <height>0</height>\n                  </size>\n                 </property>\n                </spacer>\n               </item>\n              </layout>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QTabWidget\" name=\"_variableTabs\">\n              <property name=\"currentIndex\">\n               <number>0</number>\n              </property>\n              <widget class=\"QWidget\" name=\"_coordTab\">\n               <attribute name=\"title\">\n                <string>Coordinates</string>\n               </attribute>\n               <layout class=\"QVBoxLayout\" name=\"verticalLayout_19\">\n                <property name=\"spacing\">\n                 <number>0</number>\n                </property>\n                <property name=\"leftMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"topMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"rightMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"bottomMargin\">\n                 <number>0</number>\n                </property>\n                <item>\n                 <widget class=\"QTableWidget\" name=\"_coordVarTable\"/>\n                </item>\n               </layout>\n              </widget>\n              <widget class=\"QWidget\" name=\"_2DTab\">\n               <attribute name=\"title\">\n                <string>2D</string>\n               </attribute>\n               <layout class=\"QVBoxLayout\" name=\"verticalLayout_5\">\n                <property name=\"spacing\">\n                 <number>0</number>\n                </property>\n                <property name=\"leftMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"topMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"rightMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"bottomMargin\">\n                 <number>0</number>\n                </property>\n                <item>\n                 <widget class=\"QTableWidget\" name=\"_2DVarTable\"/>\n                </item>\n               </layout>\n              </widget>\n              <widget class=\"QWidget\" name=\"_3DTab\">\n               <attribute name=\"title\">\n                <string>3D</string>\n               </attribute>\n               <layout class=\"QVBoxLayout\" name=\"verticalLayout_10\">\n                <property name=\"spacing\">\n                 <number>0</number>\n                </property>\n                <property name=\"leftMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"topMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"rightMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"bottomMargin\">\n                 <number>0</number>\n                </property>\n                <item>\n                 <widget class=\"QTableWidget\" name=\"_3DVarTable\"/>\n                </item>\n               </layout>\n              </widget>\n              <widget class=\"QWidget\" name=\"_summaryTab\">\n               <attribute name=\"title\">\n                <string>Summary</string>\n               </attribute>\n               <layout class=\"QVBoxLayout\" name=\"verticalLayout_11\">\n                <property name=\"spacing\">\n                 <number>0</number>\n                </property>\n                <property name=\"leftMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"topMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"rightMargin\">\n                 <number>0</number>\n                </property>\n                <property name=\"bottomMargin\">\n                 <number>0</number>\n                </property>\n                <item>\n                 <widget class=\"QTableWidget\" name=\"_varSummaryTable\"/>\n                </item>\n               </layout>\n              </widget>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_25\">\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QHBoxLayout\" name=\"horizontalLayout_11\">\n               <property name=\"spacing\">\n                <number>0</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"topMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"rightMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"bottomMargin\">\n                <number>0</number>\n               </property>\n               <item>\n                <widget class=\"QLabel\" name=\"label_3\">\n                 <property name=\"text\">\n                  <string>Include Coordinate Variables</string>\n                 </property>\n                </widget>\n               </item>\n               <item>\n                <spacer name=\"horizontalSpacer_2\">\n                 <property name=\"orientation\">\n                  <enum>Qt::Horizontal</enum>\n                 </property>\n                 <property name=\"sizeType\">\n                  <enum>QSizePolicy::Expanding</enum>\n                 </property>\n                 <property name=\"sizeHint\" stdset=\"0\">\n                  <size>\n                   <width>40</width>\n                   <height>20</height>\n                  </size>\n                 </property>\n                </spacer>\n               </item>\n               <item>\n                <widget class=\"QCheckBox\" name=\"_coordinatesCheckbox\">\n                 <property name=\"text\">\n                  <string/>\n                 </property>\n                </widget>\n               </item>\n              </layout>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_10\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>0</width>\n             <height>20</height>\n            </size>\n           </property>\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_6\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_12\">\n              <property name=\"sizePolicy\">\n               <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n                <horstretch>0</horstretch>\n                <verstretch>0</verstretch>\n               </sizepolicy>\n              </property>\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n               <property name=\"spacing\">\n                <number>0</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"topMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"rightMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"bottomMargin\">\n                <number>0</number>\n               </property>\n               <item>\n                <widget class=\"QFrame\" name=\"frame_9\">\n                 <property name=\"sizePolicy\">\n                  <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n                   <horstretch>0</horstretch>\n                   <verstretch>0</verstretch>\n                  </sizepolicy>\n                 </property>\n                 <property name=\"frameShape\">\n                  <enum>QFrame::NoFrame</enum>\n                 </property>\n                 <property name=\"frameShadow\">\n                  <enum>QFrame::Raised</enum>\n                 </property>\n                 <layout class=\"QHBoxLayout\" name=\"horizontalLayout_6\">\n                  <property name=\"spacing\">\n                   <number>0</number>\n                  </property>\n                  <property name=\"leftMargin\">\n                   <number>0</number>\n                  </property>\n                  <property name=\"topMargin\">\n                   <number>0</number>\n                  </property>\n                  <property name=\"rightMargin\">\n                   <number>0</number>\n                  </property>\n                  <property name=\"bottomMargin\">\n                   <number>0</number>\n                  </property>\n                  <item>\n                   <spacer name=\"horizontalSpacer_8\">\n                    <property name=\"orientation\">\n                     <enum>Qt::Horizontal</enum>\n                    </property>\n                    <property name=\"sizeHint\" stdset=\"0\">\n                     <size>\n                      <width>40</width>\n                      <height>0</height>\n                     </size>\n                    </property>\n                   </spacer>\n                  </item>\n                  <item>\n                   <widget class=\"QLabel\" name=\"_outputVariablesLabel\">\n                    <property name=\"sizePolicy\">\n                     <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n                      <horstretch>0</horstretch>\n                      <verstretch>0</verstretch>\n                     </sizepolicy>\n                    </property>\n                    <property name=\"text\">\n                     <string>Output Variables</string>\n                    </property>\n                   </widget>\n                  </item>\n                  <item>\n                   <spacer name=\"horizontalSpacer_6\">\n                    <property name=\"orientation\">\n                     <enum>Qt::Horizontal</enum>\n                    </property>\n                    <property name=\"sizeHint\" stdset=\"0\">\n                     <size>\n                      <width>40</width>\n                      <height>0</height>\n                     </size>\n                    </property>\n                   </spacer>\n                  </item>\n                 </layout>\n                </widget>\n               </item>\n               <item>\n                <widget class=\"QFrame\" name=\"frame_5\">\n                 <property name=\"sizePolicy\">\n                  <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n                   <horstretch>0</horstretch>\n                   <verstretch>0</verstretch>\n                  </sizepolicy>\n                 </property>\n                 <property name=\"frameShape\">\n                  <enum>QFrame::NoFrame</enum>\n                 </property>\n                 <property name=\"frameShadow\">\n                  <enum>QFrame::Raised</enum>\n                 </property>\n                 <layout class=\"QHBoxLayout\" name=\"horizontalLayout_7\">\n                  <property name=\"spacing\">\n                   <number>-1</number>\n                  </property>\n                  <property name=\"leftMargin\">\n                   <number>0</number>\n                  </property>\n                  <property name=\"topMargin\">\n                   <number>0</number>\n                  </property>\n                  <property name=\"rightMargin\">\n                   <number>0</number>\n                  </property>\n                  <property name=\"bottomMargin\">\n                   <number>0</number>\n                  </property>\n                  <item>\n                   <widget class=\"QPushButton\" name=\"_newOutVarButton\">\n                    <property name=\"text\">\n                     <string>New</string>\n                    </property>\n                    <property name=\"autoDefault\">\n                     <bool>false</bool>\n                    </property>\n                    <property name=\"flat\">\n                     <bool>false</bool>\n                    </property>\n                   </widget>\n                  </item>\n                  <item>\n                   <widget class=\"QPushButton\" name=\"_deleteOutVarButton\">\n                    <property name=\"text\">\n                     <string>Delete</string>\n                    </property>\n                    <property name=\"autoDefault\">\n                     <bool>false</bool>\n                    </property>\n                   </widget>\n                  </item>\n                 </layout>\n                </widget>\n               </item>\n              </layout>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QTableWidget\" name=\"_outputVariablesTable\"/>\n            </item>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_7\">\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QHBoxLayout\" name=\"horizontalLayout_4\">\n               <property name=\"spacing\">\n                <number>0</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"topMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"rightMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"bottomMargin\">\n                <number>0</number>\n               </property>\n               <item>\n                <spacer name=\"horizontalSpacer_3\">\n                 <property name=\"orientation\">\n                  <enum>Qt::Horizontal</enum>\n                 </property>\n                 <property name=\"sizeHint\" stdset=\"0\">\n                  <size>\n                   <width>278</width>\n                   <height>20</height>\n                  </size>\n                 </property>\n                </spacer>\n               </item>\n              </layout>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n        </layout>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QFrame\" name=\"frame_26\">\n        <property name=\"frameShape\">\n         <enum>QFrame::NoFrame</enum>\n        </property>\n        <property name=\"frameShadow\">\n         <enum>QFrame::Raised</enum>\n        </property>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_14\">\n         <property name=\"spacing\">\n          <number>0</number>\n         </property>\n         <property name=\"leftMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"topMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"rightMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"bottomMargin\">\n          <number>0</number>\n         </property>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_27\">\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QHBoxLayout\" name=\"horizontalLayout_15\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n           </layout>\n          </widget>\n         </item>\n        </layout>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QLabel\" name=\"label_6\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"text\">\n      <string>Script Editor</string>\n     </property>\n     <property name=\"alignment\">\n      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QTextEdit\" name=\"_scriptEdit\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Expanding\" vsizetype=\"MinimumExpanding\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"lineWrapMode\">\n      <enum>QTextEdit::NoWrap</enum>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QFrame\" name=\"frame_3\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"frameShape\">\n      <enum>QFrame::NoFrame</enum>\n     </property>\n     <property name=\"frameShadow\">\n      <enum>QFrame::Raised</enum>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_13\">\n      <property name=\"spacing\">\n       <number>0</number>\n      </property>\n      <property name=\"leftMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"topMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"rightMargin\">\n       <number>0</number>\n      </property>\n      <property name=\"bottomMargin\">\n       <number>0</number>\n      </property>\n      <item>\n       <widget class=\"QFrame\" name=\"_testFrame\">\n        <property name=\"frameShape\">\n         <enum>QFrame::NoFrame</enum>\n        </property>\n        <property name=\"frameShadow\">\n         <enum>QFrame::Raised</enum>\n        </property>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n         <property name=\"spacing\">\n          <number>0</number>\n         </property>\n         <property name=\"leftMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"topMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"rightMargin\">\n          <number>0</number>\n         </property>\n         <property name=\"bottomMargin\">\n          <number>0</number>\n         </property>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_2\">\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_17\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_24\">\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n               <property name=\"spacing\">\n                <number>-1</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"topMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"rightMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"bottomMargin\">\n                <number>0</number>\n               </property>\n               <item>\n                <widget class=\"QPushButton\" name=\"_importScriptButton\">\n                 <property name=\"text\">\n                  <string>Import file</string>\n                 </property>\n                 <property name=\"autoDefault\">\n                  <bool>false</bool>\n                 </property>\n                </widget>\n               </item>\n               <item>\n                <widget class=\"QPushButton\" name=\"_exportScriptButton\">\n                 <property name=\"text\">\n                  <string>Export file</string>\n                 </property>\n                </widget>\n               </item>\n              </layout>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_23\">\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QVBoxLayout\" name=\"verticalLayout_18\">\n               <property name=\"spacing\">\n                <number>0</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"topMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"rightMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"bottomMargin\">\n                <number>0</number>\n               </property>\n               <item>\n                <widget class=\"QLabel\" name=\"label_4\">\n                 <property name=\"text\">\n                  <string/>\n                 </property>\n                </widget>\n               </item>\n              </layout>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_13\">\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_15\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_22\">\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QHBoxLayout\" name=\"horizontalLayout_8\">\n               <property name=\"spacing\">\n                <number>0</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"topMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"rightMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"bottomMargin\">\n                <number>0</number>\n               </property>\n               <item>\n                <widget class=\"QPushButton\" name=\"_testScriptButton\">\n                 <property name=\"text\">\n                  <string>Test</string>\n                 </property>\n                 <property name=\"autoDefault\">\n                  <bool>false</bool>\n                 </property>\n                </widget>\n               </item>\n              </layout>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QFrame\" name=\"frame_20\">\n           <property name=\"frameShape\">\n            <enum>QFrame::NoFrame</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Raised</enum>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_16\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>0</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QFrame\" name=\"frame_21\">\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Raised</enum>\n              </property>\n              <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n               <property name=\"spacing\">\n                <number>-1</number>\n               </property>\n               <property name=\"leftMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"topMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"rightMargin\">\n                <number>0</number>\n               </property>\n               <property name=\"bottomMargin\">\n                <number>0</number>\n               </property>\n               <item>\n                <widget class=\"QPushButton\" name=\"_saveScriptButton\">\n                 <property name=\"text\">\n                  <string>Save</string>\n                 </property>\n                </widget>\n               </item>\n               <item>\n                <widget class=\"QPushButton\" name=\"_closeButton\">\n                 <property name=\"text\">\n                  <string>Close</string>\n                 </property>\n                </widget>\n               </item>\n              </layout>\n             </widget>\n            </item>\n           </layout>\n          </widget>\n         </item>\n        </layout>\n       </widget>\n      </item>\n     </layout>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "apps/vaporgui/PythonVariablesParams.cpp",
    "content": "#include \"PythonVariablesParams.h\"\n\nconst string PythonVariablesParams::_pythonScriptsTag = \"PythonScripts\";\n\nconst string PythonScript::_pythonScriptTag = \"PythonScript\";\nconst string PythonScript::_scritpNameTag = \"PythonScriptName\";\nconst string PythonScript::_dataMgrNameTag = \"DataMgrName\";\nconst string PythonScript::_dataMgrGridsTag = \"DataMgrGrids\";\nconst string PythonScript::_inputVarsTag = \"InputVars\";\nconst string PythonScript::_outputVarsTag = \"OutputVars\";\nconst string PythonScript::_outputVarGridsTag = \"OutputVarGrids\";\nconst string PythonScript::_dataMgrNameTag = \"DataMgrName\";\n\nstatic ParamsRegistrar<PythonVariablesParams> registrar(PythonVariablesParams::GetClassType());\n\nstatic ParamsRegistrar<PythonScript> registrar_ps(PythonScript::GetClassType());\n\nPythonVariablesParams::PythonVariablesParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : ParamsBase(ssave, GetClassType())\n{\n    _pythonScripts = new ParamsContainer(ssave, _pythonScriptsTag);\n    _pythonScripts->SetParent(this);\n}\n\nPythonVariablesParams::PythonVariablesParams(DataMgr *dataMgr, XmlNode *node) : ParamsBase(ssave, node)\n{\n    if (node->HasChild(_pythonScriptsTag)) {\n        _pythonScripts = new ParamsContainer(ssave, node->GetChild(_pythonScriptsTag));\n    } else {\n        _pythonScripts = new ParamsContainer(ssave, _pythonScriptsTag);\n    }\n}\n\nPythonScript::PythonScript(VAPoR::ParamsBase::StateSave *ssave) : ParamsBase(ssave, PythonScript::GetClassType()) {}\n\nPythonScript::PythonScript(VAPOR::ParamsBase::StateSave *ssave, VAPOR::XmlNode *node) : ParamsBase(ssave, node){};\n\nstring PythonScript::GetScript() const\n{\n    string defaultScript = \"\";\n    script = GetValueString(_pythonScriptTag, defaultScript);\n}\n\nvoid PythonScript::SetScript(string script) { SetValueString(_pythonScriptTag, \"Set Python Script\", script); }\n\nstring PythonScript::GetScriptName() const\n{\n    string defaultName = \"default.py\";\n    GetValueString(_pythonScriptName, defaultName);\n}\n\nvoid PythonScript::SetScriptName(string scriptName) { SetValueString(_pythonScriptName, \"Set Python Script Name\", scriptName); }\n\nstd::vector<string> PythonScript::GetOutputVars() const { return GetValueStringVec(_outputVarsTag); }\n\nvoid PythonScript::SetOutputVars(std::vector<string> vars) { SetValueStringVec(_outputVarsTag, \"Set Python output variables\", vars); }\n\nstd::vector<string> PythonScript::GetOutputVars() const { return GetValueStringVec(_outputVarsTag); }\n\nvoid PythonScript::SetOutputGrids(std::vector<string> grids) { SetValueStringVec(_outputGridsTag, \"Set Python output grids\", grids); }\n\nstd::vector<string> PythonScript::GetOutputGrids() const { return GetValueStringVec(_outputGridsTag); }\n\nvoid PythonScript::SetInputVars(std::vector<string> vars) { SetValueStringVec(_inputVarsTag, \"Set Python input variables\", vars); }\n\nstd::vector<string> PythonScript::GetInputVars() const { return GetValueStringVec(_inputVarsTag); }\n\nvoid PythonScript::SetInputGrids(std::vector<string> grids) { SetValueStringVec(_inputGridsTag, \"Set Python input grids\", grids); }\n\nstd::vector<string> PythonScript::GetInputGrids() const { return GetValueStringVec(_inputGridsTag); }\n\nstring GetDataMgr() const { return GetValueString(_dataMgrNameTag, \"\"); }\n\nvoid PythonScript::SetDataMgr(string dataMgrName) { SetValueString(_dataMgrNameTag, \"Set DataMgr name for Python script\", dataMgrName); }\n"
  },
  {
    "path": "apps/vaporgui/PythonVariablesParams.h",
    "content": "#ifndef PYTHONVARIABLESPARAMS_H\n#define PYTHONVARIABLESPARAMS_H\n\n#include <vapor/ParamsBase.h>\n\nnamespace VAPoR {\n\nclass PythonScript;\n\nclass PythonVariablesParams : public ParamsBase {\npublic:\n    PythonVariablesParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n\n    PythonVariablesParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n\n    ~PythonVariablesParams() {}\n\n    static string GetClassType() { return (\"PythonVariablesParams\"); }\n\n    std::vector<string> GetPythonScripts() const;\n\n    std::vector<string> GetPythonScriptNames();\n\n    void AddPythonScript(string scriptName);\n    void RemovePythonScript(string scriptName);\n\nprivate:\n    VAPoR::ParamsContainer *_pythonScripts;\n\n    static const string _pythonScriptsTag;\n};\n\nclass PythonScript : public ParamsBase {\npublic:\n    PythonScript(VAPoR::ParamsBase::StateSave *ssave);\n\n    PythonScript(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node);\n\n    ~PythonScript() {}\n\n    static string GetClassType() { return (\"PythonScript\"); }\n\n    string GetScript() const;\n    void   SetScript(string script);\n\n    string GetScriptName() const;\n    void   SetScriptName(string scriptName);\n\n    std::vector<string> GetOutputVars() const;\n    void                SetOutputVars(std::vector<string> outputVars);\n\n    std::vector<string> GetOutputGrids() const;\n    void                SetOutputGrids(std::vector<string> grids);\n\n    std::vector<string> GetInputVars() const;\n    void                SetInputVars(std::vector<string> inputVars);\n\n    std::vector<string> GetInputGrids() const;\n    void                SetInputGrids(std::vector<string> inputGrids);\n\n    string GetDataMgr() const;\n    void   SetDataMgr(string dataMgrName);\n\nprivate:\n    // string _pythonScript;\n    // string _scriptName;\n    // string _dataMgrName;\n    DataMgr *           _dataMgr;\n    std::vector<string> _grids;\n    std::vector<string> _inputVars;\n    std::vector<string> _outputVars;\n    std::vector<string> _outputVarGrids;\n\n    static const string _pythonScriptTag;\n    static const string _scriptNameTag;\n    static const string _dataMgrNameTag;\n    static const string _dataMgrGridsTag;\n    static const string _inputVarsTag;\n    static const string _outputVarsTag;\n    static const string _outputVarGridsTag;\n};\n\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "apps/vaporgui/QColorWidget.cpp",
    "content": "#include \"QColorWidget.h\"\n#include <QApplication>\n#include <QColorDialog>\n\nQColorWidget::QColorWidget()\n{\n    setColor(Qt::blue);\n    setReadOnly(true);\n    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    setFixedSize(minimumSizeHint());\n}\n\nQSize QColorWidget::minimumSizeHint() const\n{\n    //    How Qt buttons determine size\n    //    QSize fontSize = fontMetrics().size(Qt::TextShowMnemonic, QString(\"XXXX\"));\n\n    float height = QLineEdit::minimumSizeHint().height();\n\n    return QSize(height * 1.618, height);\n}\n\nvoid QColorWidget::setColor(const QColor &color)\n{\n    _color = color;\n    QPalette pal = palette();\n    //    pal.setColor(QPalette::Background, color);\n    pal.setColor(QPalette::Base, color);\n    pal.setColor(QPalette::Disabled, QPalette::Base, Qt::white);\n    setAutoFillBackground(true);\n    setPalette(pal);\n}\n\nQColor QColorWidget::getColor() const { return _color; }\n\nvoid QColorWidget::mouseReleaseEvent(QMouseEvent *event)\n{\n    QColorDialog::ColorDialogOptions options = QColorDialog::ColorDialogOptions();\n    if (ShowAlpha)\n        options |= QColorDialog::ShowAlphaChannel;\n\n    QColor newColor = QColorDialog::getColor(_color, nullptr, \"\", options);\n    QApplication::restoreOverrideCursor();\n\n    if (newColor.isValid() && newColor != _color) {\n        setColor(newColor);\n        emit colorChanged(newColor);\n    }\n}\n\nvoid QColorWidget::enterEvent(QEvent *event)\n{\n    if (isEnabled()) {\n        QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));\n        setToolTip(_color.name());\n    } else {\n        setToolTip(\"\");\n    }\n}\n\nvoid QColorWidget::leaveEvent(QEvent *event) { QApplication::restoreOverrideCursor(); }\n"
  },
  {
    "path": "apps/vaporgui/QColorWidget.h",
    "content": "#pragma once\n\n#include <QLineEdit>\n#include <QColor>\n\nclass QStylePainter;\n\n//! \\class QColorWidget\n//!\n//! Displays a color and allows the user to modify said color\n\nclass QColorWidget : public QLineEdit {\n    Q_OBJECT\n\n    QColor _color;\n\npublic:\n    bool ShowAlpha = false;\n\n    QColorWidget();\n    QSize minimumSizeHint() const;\n\n    void   setColor(const QColor &color);\n    QColor getColor() const;\n\nsignals:\n    void colorChanged(QColor color);\n\nprotected:\n    void mouseReleaseEvent(QMouseEvent *event);\n    void enterEvent(QEvent *event);\n    void leaveEvent(QEvent *event);\n};\n"
  },
  {
    "path": "apps/vaporgui/QCustomIconSizeProxyStyle.h",
    "content": "#pragma once\n\n#include <QProxyStyle>\n\nclass QCustomIconSizeProxyStyle : public QProxyStyle {\n    const int _size;\n\npublic:\n    QCustomIconSizeProxyStyle(int size) : _size(size) {}\n    virtual int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const override\n    {\n        if (metric == PM_SmallIconSize)\n            return _size;\n        else\n            return QCommonStyle::pixelMetric(metric, option, widget);\n    }\n};\n"
  },
  {
    "path": "apps/vaporgui/QEnableable.h",
    "content": "#pragma once\n\n\nclass QEnableableI {\npublic:\n//    virtual bool isEnabled() const = 0;\n    virtual void setEnabled(bool enabled) = 0;\n    virtual ~QEnableableI() {}\n};\n\n\ntemplate <class T>\nclass QEnableable : public QEnableableI {\npublic:\n    QEnableable(T *o) : _o(o) {}\n//    bool isEnabled() const override { return _o->isEnabled(); }\n    void setEnabled(bool enabled) override { _o->setEnabled(enabled); }\nprivate:\n    T* const _o;\n};\n"
  },
  {
    "path": "apps/vaporgui/QIntValidatorWithFixup.cpp",
    "content": "#include \"QIntValidatorWithFixup.h\"\n\nvoid QIntValidatorWithFixup::fixup(QString &input) const\n{\n    QIntValidator::fixup(input);    // make sure the locale is correct\n\n    int val = input.toInt();\n    if (val > top()) {\n        val = top();\n        input = QString::number(val);\n    } else if (val < bottom()) {\n        val = bottom();\n        input = QString::number(val);\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/QIntValidatorWithFixup.h",
    "content": "#ifndef QINTVALIDATORWITHFIXUP_H\n#define QINTVALIDATORWITHFIXUP_H\n\n//\n// This is a derived QIntValidator that implements the fixup function.\n//\n\n#include <QIntValidator>\n\nclass QIntValidatorWithFixup : public QIntValidator {\npublic:\n    explicit QIntValidatorWithFixup(QObject *parent = 0) : QIntValidator(parent = 0) {}\n    explicit QIntValidatorWithFixup(int bottom, int top, QObject *parent = 0) : QIntValidator(bottom, top, parent = 0) {}\n\n    //\n    // overload fixup() from QIntValidator\n    //\n    virtual void fixup(QString &input) const override;\n};\n\n#endif\n"
  },
  {
    "path": "apps/vaporgui/QMontereySlider.h",
    "content": "#pragma once\n\n#include <QStylePainter>\n#include <QStyleOptionSlider>\n#include <QStyleOptionComplex>\n#include <QSlider>\n#include <QColor>\n#include \"math.h\"\n\nclass QMontereySlider : public QSlider {\npublic:\n    explicit QMontereySlider(Qt::Orientation orientation, QWidget *parent = nullptr) : QSlider(orientation, parent){};\n    explicit QMontereySlider(QWidget *parent = nullptr) : QSlider(parent)\n    {\n        this->setStyleSheet(\"\\\n            QSlider::groove:horizontal {\\\n            height: 8px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */ \\\n            background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);\\\n            margin: 2px 0;\\\n        }\\\n        \\\n        QSlider::handle:horizontal {\\\n            background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);\\\n            border: 1px solid #5c5c5c;\\\n            width: 18px;\\\n            margin: -2px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ \\\n            border-radius: 3px;\\\n        }\");\n    };\n};\n"
  },
  {
    "path": "apps/vaporgui/QPaintUtils.cpp",
    "content": "#include \"QPaintUtils.h\"\n#include <QPicture>\n#include <QBitmap>\n#include <QPixmap>\n#include <QPainter>\n\nQT_BEGIN_NAMESPACE\nextern void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0);\nQT_END_NAMESPACE\n\nvoid QPaintUtils::DropShadow(QPainter &p, QPicture &picture, float radius, QColor color)\n{\n    // Why is this code so weird?\n    // Turns out this part of Qt's API is broken (in 4.8 at least)\n\n    float opacity = color.alphaF();\n    color.setAlphaF(1.0);\n\n    QRect pictureBB = picture.boundingRect();\n    QRect pixmapBB = pictureBB.adjusted(-radius, -radius, radius, radius);\n\n    QPixmap pixmap(pixmapBB.size());\n    pixmap.fill(Qt::transparent);\n    QPainter pixmapPainter(&pixmap);\n    pixmapPainter.setRenderHint(QPainter::Antialiasing);\n    pixmapPainter.drawPicture(-pixmapBB.topLeft(), picture);\n\n    QPixmap shadowLayer(pixmapBB.size());\n    shadowLayer.fill(color);\n    shadowLayer.setMask(pixmap.mask());\n\n    QImage shadowImage = shadowLayer.toImage();\n    pixmap.fill(Qt::transparent);\n    pixmapPainter.setRenderHints((QPainter::Antialiasing | QPainter::SmoothPixmapTransform));    //?\n    qt_blurImage(&pixmapPainter, shadowImage, radius, false, false);\n    p.setOpacity(opacity);\n    p.drawPixmap(pixmapBB.topLeft(), pixmap);\n    p.setOpacity(1.0);\n}\n\nvoid QPaintUtils::InnerShadow(QPainter &p, QPicture &picture, float radius, QColor color)\n{\n    // Why is this code so weird?\n    // Turns out this part of Qt's API is broken (in 4.8 at least)\n\n    float opacity = color.alphaF();\n    color.setAlphaF(1.0);\n\n    QRect pictureBB = picture.boundingRect();\n    QRect pixmapBB = pictureBB.adjusted(-radius, -radius, radius, radius);\n\n    QPixmap pixmap(pixmapBB.size());\n    pixmap.fill(Qt::transparent);\n    QPainter pixmapPainter(&pixmap);\n    pixmapPainter.setRenderHint(QPainter::Antialiasing);\n    pixmapPainter.drawPicture(-pixmapBB.topLeft(), picture);\n\n    QPixmap shadowLayer(pixmapBB.size());\n    shadowLayer.fill(color);\n\n    QBitmap mask = pixmap.mask();\n    shadowLayer.setMask(pixmap.createMaskFromColor(Qt::transparent, Qt::MaskOutColor));\n\n    QImage shadowImage = shadowLayer.toImage();\n    pixmap.fill(Qt::transparent);\n    qt_blurImage(&pixmapPainter, shadowImage, radius, false, false);\n    QPainter sp(&shadowLayer);\n    sp.setCompositionMode(QPainter::CompositionMode_SourceOut);\n    sp.drawPixmap(0, 0, pixmap);\n    p.setBrush(Qt::NoBrush);\n    p.setPen(Qt::NoPen);\n    p.setOpacity(opacity);\n    p.drawPixmap(pixmapBB.topLeft(), shadowLayer);\n    p.setOpacity(1.0);\n}\n\nvoid QPaintUtils::BoxDropShadow(QPainter &p, QRect box, float radius, QColor color)\n{\n    QPicture picture;\n    QPainter pp(&picture);\n    pp.fillRect(box, QBrush(Qt::black));\n    pp.end();\n\n    DropShadow(p, picture, radius, color);\n}\n\nvoid QPaintUtils::BoxInnerShadow(QPainter &p, QRect box, float radius, QColor color)\n{\n    QPicture picture;\n    QPainter pp(&picture);\n    pp.fillRect(box, QBrush(Qt::black));\n    pp.end();\n\n    InnerShadow(p, picture, radius, color);\n}\n"
  },
  {
    "path": "apps/vaporgui/QPaintUtils.h",
    "content": "#pragma once\n\n#include <QColor>\nclass QPicture;\nclass QPainter;\nclass QRect;\n\n//! \\namespace QPaintUtils\n//! Provides functionality to be used when painting a QWidget that behaves the same\n//! as CSS's drop-shadow and inner-shadow\nnamespace QPaintUtils {\nvoid DropShadow(QPainter &p, QPicture &picture, float radius, QColor color = Qt::black);\nvoid InnerShadow(QPainter &p, QPicture &picture, float radius, QColor color = Qt::black);\n\nvoid BoxDropShadow(QPainter &p, QRect box, float radius, QColor color = Qt::black);\nvoid BoxInnerShadow(QPainter &p, QRect box, float radius, QColor color = Qt::black);\n}    // namespace QPaintUtils\n"
  },
  {
    "path": "apps/vaporgui/QPushButtonWithDoubleClick.h",
    "content": "#pragma once\n\nclass QPushButtonWithDoubleClick : public QPushButton {\n    Q_OBJECT\n    using QPushButton::QPushButton;\n    void mouseDoubleClickEvent(QMouseEvent *e) { emit doubleClicked(); }\n\nsignals:\n    void doubleClicked();\n};\n"
  },
  {
    "path": "apps/vaporgui/QRange.cpp",
    "content": "#include \"QRange.h\"\n#include \"ui_QRange.h\"\n\nQRange::QRange(QWidget *parent) : QWidget(parent), _ui(new Ui::QRange)\n{\n    _ui->setupUi(this);\n\n    _ui->minSliderEdit->SetLabel(QString(\"Min:\"));\n    _ui->maxSliderEdit->SetLabel(QString(\"Max:\"));\n\n    connect(_ui->minSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_minChanged(double)));\n    connect(_ui->maxSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_maxChanged(double)));\n    connect(_ui->minSliderEdit, SIGNAL(valueChanged(int)), this, SLOT(_minChanged(int)));\n    connect(_ui->maxSliderEdit, SIGNAL(valueChanged(int)), this, SLOT(_maxChanged(int)));\n}\n\nQRange::~QRange() { delete _ui; }\n\nvoid QRange::SetExtents(double min, double max)\n{\n    _ui->minSliderEdit->SetExtents(min, max);\n    _ui->maxSliderEdit->SetExtents(min, max);\n    _ui->minSliderEdit->SetValue(min);\n    _ui->maxSliderEdit->SetValue(max);\n}\n\nvoid QRange::GetValue(double &min, double &max)\n{\n    min = _ui->minSliderEdit->GetCurrentValue();\n    max = _ui->maxSliderEdit->GetCurrentValue();\n}\n\nvoid QRange::_minChanged(double value)\n{\n    if (value > _ui->maxSliderEdit->GetCurrentValue()) _ui->maxSliderEdit->SetValue(value);\n    emit rangeChanged();\n}\n\nvoid QRange::_maxChanged(double value)\n{\n    if (value < _ui->minSliderEdit->GetCurrentValue()) _ui->minSliderEdit->SetValue(value);\n    emit rangeChanged();\n}\n\nvoid QRange::_minChanged(int value)\n{\n    if ((double)value > _ui->maxSliderEdit->GetCurrentValue()) _ui->maxSliderEdit->SetValue((double)value);\n    emit rangeChanged();\n}\n\nvoid QRange::_maxChanged(int value)\n{\n    if ((double)value < _ui->minSliderEdit->GetCurrentValue()) _ui->minSliderEdit->SetValue((double)value);\n    emit rangeChanged();\n}\n\nvoid QRange::SetMainLabel(const QString &label) { _ui->mainLabel->setText(label); }\n\nvoid QRange::SetDecimals(int dec)\n{\n    _ui->minSliderEdit->SetDecimals(dec);\n    _ui->maxSliderEdit->SetDecimals(dec);\n}\n\nvoid QRange::SetIntType(bool val)\n{\n    _ui->minSliderEdit->SetIntType(val);\n    _ui->maxSliderEdit->SetIntType(val);\n}\n\nvoid QRange::SetValue(double smallVal, double bigVal)\n{\n    _ui->minSliderEdit->SetValue(smallVal);\n    _ui->maxSliderEdit->SetValue(bigVal);\n}\n"
  },
  {
    "path": "apps/vaporgui/QRange.h",
    "content": "#ifndef QRANGE_H\n#define QRANGE_H\n\n#include <QWidget>\n\nnamespace Ui {\nclass QRange;\n}\n\n// Note:\n//   One might think it's a good idea for this QRange class to use a RangeCombo.\n//   But it violates the principles of object oriented programming.\n//   That's because a RangeCombo requires two Combos to keep them in sync.\n//   However, as a private member, Combo is hidden by QSliderEdit, and\n//   QRange simply cannot access Combos.\n\nclass QRange : public QWidget {\n    Q_OBJECT\n\npublic:\n    explicit QRange(QWidget *parent = 0);\n    ~QRange();\n\n    void SetExtents(double min, double max);\n    void GetValue(double &smallVal, double &bigVal);\n    void SetValue(double smallVal, double bigVal);\n    void SetMainLabel(const QString &);\n    void SetDecimals(int dec);    // how many digits after the decimal point\n    void SetIntType(bool);        // how many digits after the decimal point\n\nsignals:\n    void rangeChanged();\n\nprivate slots:\n    void _minChanged(double);\n    void _maxChanged(double);\n    void _minChanged(int);\n    void _maxChanged(int);\n\nprivate:\n    Ui::QRange *_ui;\n};\n\n#endif    // QRANGE_H\n"
  },
  {
    "path": "apps/vaporgui/QRange.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QRange</class>\n <widget class=\"QWidget\" name=\"QRange\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>527</width>\n    <height>126</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <item>\n    <widget class=\"QFrame\" name=\"frame\">\n     <property name=\"frameShape\">\n      <enum>QFrame::StyledPanel</enum>\n     </property>\n     <property name=\"frameShadow\">\n      <enum>QFrame::Raised</enum>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\" stretch=\"1,2,2\">\n      <item>\n       <widget class=\"QLabel\" name=\"mainLabel\">\n        <property name=\"text\">\n         <string>A Range</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSliderEdit\" name=\"minSliderEdit\" native=\"true\"/>\n      </item>\n      <item>\n       <widget class=\"QSliderEdit\" name=\"maxSliderEdit\" native=\"true\"/>\n      </item>\n     </layout>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QSliderEdit</class>\n   <extends>QWidget</extends>\n   <header location=\"global\">QSliderEdit.h</header>\n   <container>1</container>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "apps/vaporgui/QRangeSlider.cpp",
    "content": "#include \"QRangeSlider.h\"\n#include <QStylePainter>\n#include <QStyleOptionSlider>\n#include <QMouseEvent>\n#include <QBitmap>\n#include <QProxyStyle>\n\n// An arbitrary large number as the number of stops for a continuous qslider\n#define QT_STOPS 1000000000\n\n// Dragging the selected region currently requires AbsoluteSetButtons to be enabled\n// For some OS styles, such as linux, this is disabled by default so we need to manually enable it\nclass QForceAbsoluteSetButtonsEnabledStyle : public QProxyStyle {\npublic:\n    using QProxyStyle::QProxyStyle;\n\n    int styleHint(QStyle::StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const\n    {\n        if (hint == QStyle::SH_Slider_AbsoluteSetButtons) return Qt::LeftButton;\n        return QProxyStyle::styleHint(hint, option, widget, returnData);\n    }\n};\n\nQRangeSlider::QRangeSlider() : QRangeSlider(Qt::Orientation::Horizontal) {}\n\nQRangeSlider::QRangeSlider(Qt::Orientation orientation) : QSlider(orientation)\n{\n    _position[0] = 0;\n    _value[0] = 0;\n    _position[1] = QT_STOPS - 1;\n    _value[1] = QT_STOPS - 1;\n    this->setRange(0, QT_STOPS);\n    this->setTracking(true);\n    this->QSlider::setStyle(new QForceAbsoluteSetButtonsEnabledStyle(style()));\n\n// Fix for Qt bug https://bugreports.qt.io/browse/QTBUG-98093\n// Apply a style sheet to QSlider to make it work on OSX Monterey\n// Note: Inheriting from QMontereySlider does not work, so we manually apply the styleSheet\n#ifdef Darwin\n    this->setStyleSheet(\"\\\n        QSlider::groove:horizontal {\\\n            background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);\\\n\t\t\theight: 8px; \\\n            margin: 2px 0;\\\n\t\t}\\\n\t\tQSlider::handle:horizontal {\\\n            background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);\\\n            border: 1px solid #5c5c5c;\\\n            width: 18px;\\\n            margin: -2px 0; \\\n            border-radius: 3px;\\\n\t\t}\");\n#endif\n}\n\nQSize QRangeSlider::minimumSizeHint() const { return QSlider::minimumSizeHint(); }\n\nvoid QRangeSlider::SetValue(float min, float max)\n{\n    _isOutOfBounds[0] = false;\n    _isOutOfBounds[1] = false;\n\n    if (min < 0 || min > 1) {\n        _isOutOfBounds[0] = true;\n        _outOfBoundValue[0] = min;\n        min = 0;\n    }\n    if (max < 0 || max > 1) {\n        _isOutOfBounds[1] = true;\n        _outOfBoundValue[1] = max;\n        max = 1;\n    }\n    _position[0] = min * (QT_STOPS - 1);\n    _value[0] = min * (QT_STOPS - 1);\n    _position[1] = max * (QT_STOPS - 1);\n    _value[1] = max * (QT_STOPS - 1);\n    update();\n}\n\nvoid QRangeSlider::paintEvent(QPaintEvent *event)\n{\n    QStylePainter p(this);\n\n    paintTrack(p);\n\n    int drawId = (_lastSelectedControl + 1) % 2;\n    paintHandle(p, drawId);\n    drawId = (drawId + 1) % 2;\n    paintHandle(p, drawId);\n}\n\nvoid QRangeSlider::paintHandle(QStylePainter &p, int i)\n{\n    QStyleOptionSlider option;\n    this->initStyleOption(&option);\n\n    option.subControls = QStyle::SC_SliderHandle;\n    option.sliderValue = _value[i];\n    option.sliderPosition = _position[i];\n    if (_isOutOfBounds[i]) { option.state &= ~QStyle::State_Enabled; }\n    if (isSliderDown(i)) {\n        option.activeSubControls = QStyle::SC_SliderHandle;\n        option.state |= QStyle::State_Sunken;\n    }\n    p.drawComplexControl(QStyle::CC_Slider, option);\n}\n\nvoid QRangeSlider::paintTrack(QStylePainter &p)\n{\n    QStyleOptionSlider option;\n    this->initStyleOption(&option);\n\n    option.sliderPosition = 0;\n    option.subControls = QStyle::SC_SliderGroove;\n    p.drawComplexControl(QStyle::CC_Slider, option);\n\n    QRect groove = this->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this);\n    groove.adjust(0, 0, -1, 0);\n\n    QPixmap pixmap(width(), height());\n    pixmap.fill(Qt::transparent);\n    QStylePainter pixStylePainter(&pixmap, this);\n    pixStylePainter.drawComplexControl(QStyle::CC_Slider, option);\n\n    option.sliderPosition = _position[0];\n    const QRect left = style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, this);\n    option.sliderPosition = _position[1];\n    const QRect right = style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, this);\n\n    QRect highlight(0, 0, width(), height());\n    if (option.orientation == Qt::Horizontal) {\n        highlight.setLeft(left.center().x());\n        highlight.setRight(right.center().x());\n    } else {\n        highlight.setBottom(left.center().y());\n        highlight.setTop(right.center().y());\n    }\n\n    p.setClipRegion(QRegion(pixmap.mask()));\n    p.fillRect(highlight, QPalette::Highlight);\n    p.setClipRegion(QRegion(), Qt::NoClip);\n}\n\nvoid QRangeSlider::mousePressEvent(QMouseEvent *event)\n{\n    for (int i = 0, id = _lastSelectedControl; i < 2; i++, id = (id + 1) % 2) {\n        if (doesHandleContainPixel(id, event->pos())) {\n            _grabbedControl = id;\n            _lastSelectedControl = id;\n            _isOutOfBounds[id] = false;\n            setValue(_value[id]);\n            QSlider::mousePressEvent(event);\n            emit ValueChangedBegin();\n            return;\n        }\n    }\n\n    if (doesGrooveContainPixel(event->pos())) {\n        setValue(-QT_STOPS);\n        QSlider::mousePressEvent(event);\n        int selectedPosition = sliderPosition();\n\n        if (selectedPosition > _position[0] && selectedPosition < _position[1]) {\n            _grabbedBar = true;\n            _grabbedBarStartPosition = selectedPosition;\n            _grabbedBarPosition = selectedPosition;\n            _grabbedBarControlStartPositions[0] = _position[0];\n            _grabbedBarControlStartPositions[1] = _position[1];\n            _isOutOfBounds[0] = _isOutOfBounds[1] = false;\n            emit ValueChangedBegin();\n        }\n    }\n}\n\nvoid QRangeSlider::mouseReleaseEvent(QMouseEvent *event)\n{\n    QSlider::mouseReleaseEvent(event);\n\n    if (_grabbedControl >= 0 || _grabbedBar) emitValueChanged();\n\n    _grabbedControl = -1;\n    _grabbedBar = false;\n}\n\nvoid QRangeSlider::mouseMoveEvent(QMouseEvent *event)\n{\n    if (_grabbedControl >= 0) {\n        setValue(_value[_grabbedControl]);\n        QSlider::mouseMoveEvent(event);\n\n        if (_grabbedControl == 0)\n            if (sliderPosition() > _position[1]) swapSliders();\n        if (_grabbedControl == 1)\n            if (sliderPosition() < _position[0]) swapSliders();\n\n        _value[_grabbedControl] = value();\n        _position[_grabbedControl] = sliderPosition();\n        _isOutOfBounds[_grabbedControl] = false;\n\n        if (hasTracking()) emitValueChanged(true);\n    }\n\n    if (_grabbedBar) {\n        setValue(_grabbedBarPosition);\n        QSlider::mouseMoveEvent(event);\n\n        _grabbedBarPosition = sliderPosition();\n\n        int diff = _grabbedBarPosition - _grabbedBarStartPosition;\n\n        for (int i = 0; i < 2; i++) {\n            _position[i] = _grabbedBarControlStartPositions[i] + diff;\n            _position[i] = _position[i] < 0 ? 0 : _position[i];\n            _position[i] = _position[i] > QT_STOPS - 1 ? QT_STOPS - 1 : _position[i];\n            _isOutOfBounds[i] = false;\n            if (hasTracking()) _value[i] = _position[i];\n        }\n\n        if (hasTracking()) emitValueChanged(true);\n    }\n}\n\nbool QRangeSlider::doesHandleContainPixel(int handle, const QPoint &pixel) const\n{\n    QStyleOptionSlider option;\n    initStyleOption(&option);\n    option.sliderValue = _value[handle];\n    option.sliderPosition = _position[handle];\n\n    QStyle::SubControl selected = style()->hitTestComplexControl(QStyle::CC_Slider, &option, pixel, this);\n\n    return selected == QStyle::SC_SliderHandle;\n}\n\nbool QRangeSlider::doesGrooveContainPixel(const QPoint &pixel) const\n{\n    QStyleOptionSlider option;\n    initStyleOption(&option);\n    option.sliderValue = _value[0];\n    option.sliderPosition = _position[0];\n\n    QStyle::SubControl selected = style()->hitTestComplexControl(QStyle::CC_Slider, &option, pixel, this);\n\n    return selected == QStyle::SC_SliderGroove;\n}\n\nbool QRangeSlider::isSliderDown(int i) const { return _grabbedControl == i; }\n\nvoid QRangeSlider::swapSliders()\n{\n    std::swap(_value[0], _value[1]);\n    std::swap(_position[0], _position[1]);\n    std::swap(_isOutOfBounds[0], _isOutOfBounds[1]);\n    std::swap(_outOfBoundValue[0], _outOfBoundValue[1]);\n    _lastSelectedControl = (_lastSelectedControl + 1) % 2;\n    switch (_grabbedControl) {\n    case 0: _grabbedControl = 1; break;\n    case 1: _grabbedControl = 0; break;\n    case -1: break;\n    }\n}\n\nvoid QRangeSlider::emitValueChanged(bool intermediate)\n{\n    float left = _isOutOfBounds[0] ? _outOfBoundValue[0] : _value[0] / (float)QT_STOPS;\n    float right = _isOutOfBounds[1] ? _outOfBoundValue[1] : _value[1] / (float)QT_STOPS;\n\n    if (intermediate)\n        emit ValueChangedIntermediate(left, right);\n    else\n        emit ValueChanged(left, right);\n}\n"
  },
  {
    "path": "apps/vaporgui/QRangeSlider.h",
    "content": "#pragma once\n\n#include <QSlider>\n\nclass QStylePainter;\n\n//! \\class QRangeSlider\n//! It is the same as a QSlider except it has two independent slider controls\nclass QRangeSlider : public QSlider {\n    Q_OBJECT\n\npublic:\n    QRangeSlider();\n    QRangeSlider(Qt::Orientation orientation);\n    QSize minimumSizeHint() const;\n    void  SetValue(float min, float max);\n    void  setStyle(QStyle *style) = delete;\n\nsignals:\n    //! User began to change the value.\n    void ValueChangedBegin();\n    //! User changed the value but they have not finalized it.\n    void ValueChangedIntermediate(float min, float max);\n    //! User finalized changing the value.\n    void ValueChanged(float min, float max);\n\nprotected:\n    void paintEvent(QPaintEvent *event);\n    void mousePressEvent(QMouseEvent *event);\n    void mouseReleaseEvent(QMouseEvent *event);\n    void mouseMoveEvent(QMouseEvent *event);\n    //    void mouseDoubleClickEvent(QMouseEvent *event);\n\nprivate:\n    int   _position[2];\n    int   _value[2];\n    bool  _isOutOfBounds[2] = {false};\n    float _outOfBoundValue[2];\n    int   _grabbedControl = -1;\n    int   _lastSelectedControl = 0;\n\n    bool _grabbedBar = false;\n    int  _grabbedBarPosition;\n    int  _grabbedBarStartPosition;\n    int  _grabbedBarControlStartPositions[2];\n\n    void paintHandle(QStylePainter &p, int i);\n    void paintTrack(QStylePainter &p);\n    bool doesHandleContainPixel(int handle, const QPoint &pixel) const;\n    bool doesGrooveContainPixel(const QPoint &pixel) const;\n    bool isSliderDown(int i) const;\n    void swapSliders();\n    void emitValueChanged(bool intermediate = false);\n};\n"
  },
  {
    "path": "apps/vaporgui/QRangeSliderTextCombo.cpp",
    "content": "#include \"QRangeSliderTextCombo.h\"\n#include <QBoxLayout>\n#include \"VDoubleValidator.h\"\n#include <vapor/VAssert.h>\n#include <cfloat>\n#include <cmath>\n#include <QAction>\n#include \"VDoubleLineEdit.h\"\n#include \"VDoubleRangeMenu.h\"\n\nQRangeSliderTextCombo::QRangeSliderTextCombo()\n{\n    QBoxLayout *layout = new QHBoxLayout;\n    layout->setMargin(0);\n    layout->setSpacing(0);\n    setLayout(layout);\n\n    layout->addWidget(_leftText = new VDoubleLineEdit, 20);\n    layout->addWidget(_slider = new QRangeSlider, 60);\n    layout->addWidget(_rightText = new VDoubleLineEdit, 20);\n\n    _min = 0;\n    _max = 1;\n    SetValue(0, 1);\n\n    connect(_slider, SIGNAL(ValueChanged(float, float)), this, SLOT(sliderChanged(float, float)));\n    connect(_slider, SIGNAL(ValueChangedIntermediate(float, float)), this, SLOT(sliderChangedIntermediate(float, float)));\n    connect(_slider, SIGNAL(ValueChangedBegin()), this, SIGNAL(ValueChangedBegin()));\n    connect(_leftText, SIGNAL(ValueChanged(double)), this, SLOT(leftTextChanged(double)));\n    connect(_rightText, SIGNAL(ValueChanged(double)), this, SLOT(rightTextChanged(double)));\n\n    _leftText->RemoveContextMenu();\n    _rightText->RemoveContextMenu();\n\n    _leftText->SetAutoTooltip(false);\n    _rightText->SetAutoTooltip(false);\n\n    _menu = new VDoubleRangeMenu(this, _leftText->GetSciNotation(), _leftText->GetNumDigits(), _min, _max, _allowCustomRange);\n    connect(_menu, &VDoubleRangeMenu::MinChanged, this, &QRangeSliderTextCombo::minChanged);\n    connect(_menu, &VDoubleRangeMenu::MaxChanged, this, &QRangeSliderTextCombo::maxChanged);\n    connect(_menu, &VDoubleRangeMenu::SciNotationChanged, _leftText, &VDoubleLineEdit::SetSciNotation);\n    connect(_menu, &VDoubleRangeMenu::SciNotationChanged, _rightText, &VDoubleLineEdit::SetSciNotation);\n    connect(_menu, &VDoubleRangeMenu::DecimalDigitsChanged, _leftText, &VDoubleLineEdit::SetNumDigits);\n    connect(_menu, &VDoubleRangeMenu::DecimalDigitsChanged, _rightText, &VDoubleLineEdit::SetNumDigits);\n\n    setContextMenuPolicy(Qt::ContextMenuPolicy::CustomContextMenu);\n    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenu(const QPoint &)));\n}\n\nvoid QRangeSliderTextCombo::SetRange(float min, float max)\n{\n    if (min <= max) {\n        _min = min;\n        _max = max;\n    }\n\n    SetValue(_left, _right);\n    _menu->SetMinimum(_min);\n    _menu->SetMaximum(_max);\n\n    setToolTip(QString::fromStdString(\"Min: \" + std::to_string(_min) + \"\\n\" + \"Max: \" + std::to_string(_max)));\n}\n\nvoid QRangeSliderTextCombo::SetValue(float left, float right)\n{\n    if (left > right) std::swap(left, right);\n    if (!_allowCustomRange) {\n        left = std::max(_min, left);\n        right = std::min(_max, right);\n    }\n    _left = left;\n    _right = right;\n    setTextboxes(left, right);\n    if (std::abs(_max - _min) < FLT_EPSILON)\n        _slider->SetValue(0, 1);\n    else\n        _slider->SetValue((left - _min) / (_max - _min), (right - _min) / (_max - _min));\n}\n\nvoid QRangeSliderTextCombo::SetNumDigits(int digits) {\n    _leftText->SetNumDigits(digits);\n    _rightText->SetNumDigits(digits);\n}\n\nvoid QRangeSliderTextCombo::AllowCustomRange()\n{\n    if (_allowCustomRange) return;\n\n    _allowCustomRange = true;\n    _menu->AllowUserRange();\n}\n\nvoid QRangeSliderTextCombo::setTextboxes(float left, float right)\n{\n    _leftText->SetValueDouble(left);\n    _rightText->SetValueDouble(right);\n}\n\nfloat QRangeSliderTextCombo::getRange() const\n{\n    float range = _max - _min;\n    if (range < FLT_EPSILON)\n        return 1;\n    else\n        return range;\n}\n\nvoid QRangeSliderTextCombo::sliderChangedIntermediate(float leftNorm, float rightNorm)\n{\n    float left = (_max - _min) * leftNorm + _min;\n    float right = (_max - _min) * rightNorm + _min;\n    setTextboxes(left, right);\n    emit ValueChangedIntermediate(left, right);\n}\n\nvoid QRangeSliderTextCombo::sliderChanged(float leftNorm, float rightNorm)\n{\n    float left = (_max - _min) * leftNorm + _min;\n    float right = (_max - _min) * rightNorm + _min;\n    SetValue(left, right);\n    emit ValueChanged(_left, _right);\n}\n\nvoid QRangeSliderTextCombo::leftTextChanged(double left)\n{\n    SetValue(left, _right);\n    emit ValueChanged(_left, _right);\n}\n\nvoid QRangeSliderTextCombo::rightTextChanged(double right)\n{\n    SetValue(_left, right);\n    emit ValueChanged(_left, _right);\n}\n\nvoid QRangeSliderTextCombo::minChanged(double min)\n{\n    SetRange(min, _max);\n    emit RangeChanged(_min, _max);\n}\n\nvoid QRangeSliderTextCombo::maxChanged(double max)\n{\n    SetRange(_min, max);\n    emit RangeChanged(_min, _max);\n}\n\nvoid QRangeSliderTextCombo::showContextMenu(const QPoint &pos)\n{\n    QPoint globalPos = mapToGlobal(pos);\n    _menu->exec(globalPos);\n}\n"
  },
  {
    "path": "apps/vaporgui/QRangeSliderTextCombo.h",
    "content": "#pragma once\n\n#include \"QRangeSlider.h\"\n#include <QWidget>\n#include <QFrame>\n\nclass VDoubleLineEdit;\nclass VDoubleRangeMenu;\n\n//! \\class QRangeSliderTextCombo\n//! Combines a QRangeSlider with two text inputs that represent the values of\n//! the min/max sliders. The two are automatically synced.\n\nclass QRangeSliderTextCombo : public QWidget {\n    Q_OBJECT\n\n    QRangeSlider *    _slider;\n    VDoubleLineEdit * _leftText;\n    VDoubleLineEdit * _rightText;\n    VDoubleRangeMenu *_menu;\n    float             _min, _max;\n    float             _left, _right;\n    bool              _allowCustomRange = false;\n\npublic:\n    QRangeSliderTextCombo();\n\n    void SetRange(float min, float max);\n    void SetValue(float left, float right);\n\n    //! Allows the user to input values outside of the range and allows them to change the range.\n    void AllowCustomRange();\n\n    void SetNumDigits(int digits);\n\nprivate:\n    void  setTextboxes(float left, float right);\n    float getRange() const;\n\nprivate slots:\n    void sliderChangedIntermediate(float min, float max);\n    void sliderChanged(float min, float max);\n    void leftTextChanged(double left);\n    void rightTextChanged(double right);\n    void minChanged(double min);\n    void maxChanged(double max);\n    void showContextMenu(const QPoint &pos);\n\nsignals:\n    //! User began to change the value.\n    void ValueChangedBegin();\n    //! User finalized changing the value.\n    void ValueChanged(float min, float max);\n    //! User changed the value but they have not finalized it.\n    void ValueChangedIntermediate(float min, float max);\n\n    void RangeChanged(float min, float max);\n    void RangeDefaultRequested();\n};\n"
  },
  {
    "path": "apps/vaporgui/QSinglePoint.cpp",
    "content": "#include \"QSinglePoint.h\"\n#include \"ui_QSinglePoint.h\"\n\n// for debug\n#include <iostream>\n#include \"vapor/VAssert.h\"\n\nQSinglePoint::QSinglePoint(QWidget *parent) : QWidget(parent), _ui(new Ui::QSinglePoint)\n{\n    _ui->setupUi(this);\n\n    SetDimensionality(3);    // default to have 3 dimensions\n\n    _ui->xSliderEdit->SetLabel(QString(\"X\"));\n    _ui->ySliderEdit->SetLabel(QString(\"Y\"));\n    _ui->zSliderEdit->SetLabel(QString(\"Z\"));\n    _ui->tSliderEdit->SetLabel(QString(\"T\"));\n\n    // Connect signals and slots\n    connect(_ui->xSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_coordinateChanged(double)));\n    connect(_ui->ySliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_coordinateChanged(double)));\n    connect(_ui->zSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_coordinateChanged(double)));\n    connect(_ui->tSliderEdit, SIGNAL(valueChanged(double)), this, SLOT(_coordinateChanged(double)));\n}\n\nQSinglePoint::~QSinglePoint() { delete _ui; }\n\nvoid QSinglePoint::_coordinateChanged(double value)    // value isn't used though\n{\n    emit pointUpdated();\n}\n\nvoid QSinglePoint::SetDimensionality(int dim)\n{\n    VAssert(dim >= 2 && dim <= 4);\n    _dimensionality = dim;\n    _ui->xSliderEdit->setVisible(true);\n    _ui->ySliderEdit->setVisible(true);\n    _ui->zSliderEdit->setVisible(false);\n    _ui->tSliderEdit->setVisible(false);\n    if (dim >= 3) _ui->zSliderEdit->setVisible(true);\n    if (dim == 4) _ui->tSliderEdit->setVisible(true);\n}\n\nint QSinglePoint::GetDimensionality() { return _dimensionality; }\n\nvoid QSinglePoint::GetCurrentPoint(std::vector<double> &point)\n{\n    point.clear();\n    point.push_back(_ui->xSliderEdit->GetCurrentValue());\n    point.push_back(_ui->ySliderEdit->GetCurrentValue());\n    if (_dimensionality >= 3) point.push_back(_ui->zSliderEdit->GetCurrentValue());\n    if (_dimensionality >= 4) point.push_back(_ui->tSliderEdit->GetCurrentValue());\n}\n\nvoid QSinglePoint::SetExtents(const std::vector<double> &min, const std::vector<double> &max)\n{\n    _ui->xSliderEdit->SetExtents(min[0], max[0]);\n    _ui->ySliderEdit->SetExtents(min[1], max[1]);\n    if (_dimensionality >= 3) _ui->zSliderEdit->SetExtents(min[2], max[2]);\n    if (_dimensionality >= 4) _ui->tSliderEdit->SetExtents(min[3], max[3]);\n}\n\nvoid QSinglePoint::SetMainLabel(const QString &label) { _ui->mainLabel->setText(label); }\n\nvoid QSinglePoint::SetDecimals(int dec)\n{\n    _ui->xSliderEdit->SetDecimals(dec);\n    _ui->ySliderEdit->SetDecimals(dec);\n    _ui->zSliderEdit->SetDecimals(dec);\n    _ui->tSliderEdit->SetDecimals(dec);\n}\n\nvoid QSinglePoint::SetValue(const std::vector<double> &point)\n{\n    _ui->xSliderEdit->SetValue(point[0]);\n    _ui->ySliderEdit->SetValue(point[1]);\n    if (_dimensionality >= 3) _ui->zSliderEdit->SetValue(point[2]);\n    if (_dimensionality >= 4) _ui->tSliderEdit->SetValue(point[3]);\n}\n"
  },
  {
    "path": "apps/vaporgui/QSinglePoint.h",
    "content": "#ifndef QSINGLEPOINT_H\n#define QSINGLEPOINT_H\n\n#include <QWidget>\n\nnamespace Ui {\nclass QSinglePoint;\n}\n\nclass QSinglePoint : public QWidget {\n    Q_OBJECT\n\npublic:\n    explicit QSinglePoint(QWidget *parent = 0);\n    ~QSinglePoint();\n\n    void SetExtents(const std::vector<double> &min, const std::vector<double> &max);\n\n    void SetDimensionality(int);\n    int  GetDimensionality();\n    void GetCurrentPoint(std::vector<double> &);\n    void SetMainLabel(const QString &);\n    void SetDecimals(int dec);    // how many digits after the decimal point\n    void SetValue(const std::vector<double> &);\n\nsignals:\n    void pointUpdated();\n\nprivate slots:\n    void _coordinateChanged(double);\n\nprivate:\n    Ui::QSinglePoint *_ui;\n    int               _dimensionality;\n};\n\n#endif    // QSINGLEPOINT_H\n"
  },
  {
    "path": "apps/vaporgui/QSinglePoint.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QSinglePoint</class>\n <widget class=\"QWidget\" name=\"QSinglePoint\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>400</width>\n    <height>300</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QGridLayout\" name=\"gridLayout\">\n   <item row=\"0\" column=\"0\">\n    <widget class=\"QFrame\" name=\"frame\">\n     <property name=\"frameShape\">\n      <enum>QFrame::StyledPanel</enum>\n     </property>\n     <property name=\"frameShadow\">\n      <enum>QFrame::Raised</enum>\n     </property>\n     <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\" stretch=\"1,2,2,2,2\">\n      <item>\n       <widget class=\"QLabel\" name=\"mainLabel\">\n        <property name=\"maximumSize\">\n         <size>\n          <width>16777215</width>\n          <height>35</height>\n         </size>\n        </property>\n        <property name=\"text\">\n         <string>Single Point</string>\n        </property>\n       </widget>\n      </item>\n      <item>\n       <widget class=\"QSliderEdit\" name=\"xSliderEdit\" native=\"true\"/>\n      </item>\n      <item>\n       <widget class=\"QSliderEdit\" name=\"ySliderEdit\" native=\"true\"/>\n      </item>\n      <item>\n       <widget class=\"QSliderEdit\" name=\"zSliderEdit\" native=\"true\"/>\n      </item>\n      <item>\n       <widget class=\"QSliderEdit\" name=\"tSliderEdit\" native=\"true\"/>\n      </item>\n     </layout>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QSliderEdit</class>\n   <extends>QWidget</extends>\n   <header location=\"global\">QSliderEdit.h</header>\n   <container>1</container>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "apps/vaporgui/QSliderEdit.cpp",
    "content": "#include \"QSliderEdit.h\"\n#include \"ui_QSliderEdit.h\"\n\n#include <cmath>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n\nQSliderEdit::QSliderEdit(QWidget *parent) : QWidget(parent), _ui(new Ui::QSliderEdit)\n{\n    _ui->setupUi(this);\n\n    _combo = new Combo(_ui->myLineEdit, _ui->mySlider);\n    _combo->SetPrecision(5);\n\n    connect(_combo, SIGNAL(valueChanged(double)), this, SLOT(_comboValueChanged(double)));\n    connect(_combo, SIGNAL(valueChanged(int)), this, SLOT(_comboValueChanged(int)));\n}\n\nQSliderEdit::~QSliderEdit()\n{\n    delete _combo;\n    delete _ui;\n}\n\nvoid QSliderEdit::SetLabel(const QString &text) { _ui->myLabel->setText(text); }\n\nvoid QSliderEdit::SetExtents(double min, double max)\n{\n    double value = GetCurrentValue();\n    _combo->Update(min, max, value);\n}\n\nvoid QSliderEdit::SetDecimals(int dec) { _combo->SetPrecision(dec); }\n\ndouble QSliderEdit::GetCurrentValue() { return _combo->GetValue(); }\n\nvoid QSliderEdit::SetValue(double value) { _combo->SetSliderLineEdit(value); }\n\nvoid QSliderEdit::_comboValueChanged(double val) { emit valueChanged(val); }\n\nvoid QSliderEdit::_comboValueChanged(int val) { emit valueChanged(val); }\n\nvoid QSliderEdit::SetIntType(bool val) { _combo->SetIntType(val); }\n"
  },
  {
    "path": "apps/vaporgui/QSliderEdit.h",
    "content": "#ifndef QSLIDEREDIT_H\n#define QSLIDEREDIT_H\n\n#include <QWidget>\n#include <QDoubleValidator>\n\n#include \"Combo.h\"\n\nnamespace Ui {\nclass QSliderEdit;\n}\n\nclass QSliderEdit : public QWidget {\n    Q_OBJECT\n\npublic:\n    explicit QSliderEdit(QWidget *parent = 0);\n    ~QSliderEdit();\n\n    void   SetLabel(const QString &text);\n    void   SetDecimals(int dec);    // how many digits after the decimal point\n    void   SetExtents(double min, double max);\n    double GetCurrentValue();\n    void   SetValue(double);\n    void   SetIntType(bool);    // default is false, which means double type\n\nsignals:\n    // This is the signal a QSliderEdit emits.\n    void valueChanged(double);\n    void valueChanged(int);\n\nprivate slots:\n    void _comboValueChanged(double);\n    void _comboValueChanged(int);\n\nprivate:\n    Ui::QSliderEdit *_ui;\n    Combo *          _combo;    // keeps the slider and lineEdit in sync\n};\n\n#endif    // QSLIDEREDIT_H\n"
  },
  {
    "path": "apps/vaporgui/QSliderEdit.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>QSliderEdit</class>\n <widget class=\"QWidget\" name=\"QSliderEdit\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>373</width>\n    <height>25</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QHBoxLayout\" name=\"horizontalLayout\" stretch=\"0,0,1,1\">\n   <property name=\"spacing\">\n    <number>-1</number>\n   </property>\n   <property name=\"leftMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>0</number>\n   </property>\n   <item>\n    <widget class=\"QLabel\" name=\"myLabel\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"text\">\n      <string>TextLabel</string>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <spacer name=\"horizontalSpacer\">\n     <property name=\"orientation\">\n      <enum>Qt::Horizontal</enum>\n     </property>\n     <property name=\"sizeHint\" stdset=\"0\">\n      <size>\n       <width>40</width>\n       <height>20</height>\n      </size>\n     </property>\n    </spacer>\n   </item>\n   <item>\n    <widget class=\"QMontereySlider\" name=\"mySlider\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"minimumSize\">\n      <size>\n       <width>0</width>\n       <height>0</height>\n      </size>\n     </property>\n     <property name=\"maximumSize\">\n      <size>\n       <width>100</width>\n       <height>16777215</height>\n      </size>\n     </property>\n     <property name=\"orientation\">\n      <enum>Qt::Horizontal</enum>\n     </property>\n    </widget>\n   </item>\n   <item>\n    <widget class=\"QLineEdit\" name=\"myLineEdit\">\n     <property name=\"sizePolicy\">\n      <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n       <horstretch>0</horstretch>\n       <verstretch>0</verstretch>\n      </sizepolicy>\n     </property>\n     <property name=\"minimumSize\">\n      <size>\n       <width>0</width>\n       <height>0</height>\n      </size>\n     </property>\n     <property name=\"maximumSize\">\n      <size>\n       <width>100</width>\n       <height>16777215</height>\n      </size>\n     </property>\n    </widget>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QMontereySlider</class>\n   <extends>QSlider</extends>\n   <header>QMontereySlider.h</header>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n <slots>\n  <signal>valueChanged(double)</signal>\n </slots>\n</ui>\n"
  },
  {
    "path": "apps/vaporgui/QtVizWinGLContextManager.cpp",
    "content": "#include \"QtVizWinGLContextManager.h\"\n#include \"VizWinMgr.h\"\n#include \"VizWin.h\"\n\nvoid QtVizWinGLContextManager::Activate(const string &visualizerName)\n{\n    _vizWinMgr->Get(visualizerName)->makeCurrent();\n}"
  },
  {
    "path": "apps/vaporgui/QtVizWinGLContextManager.h",
    "content": "#pragma once\n#include <vapor/VisualizerGLContextManager.h>\n\nclass VizWinMgr;\nclass VizWin;\n\nclass QtVizWinGLContextManager : public VAPoR::VisualizerGLContextManager {\n    VizWinMgr *_vizWinMgr;\npublic:\n    QtVizWinGLContextManager(VizWinMgr *vizWinMgr) : _vizWinMgr(vizWinMgr) {}\n    void Activate(const string &visualizerName) override;\n};\n"
  },
  {
    "path": "apps/vaporgui/RangeCombos.cpp",
    "content": "#include <QtGui>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n\nusing namespace std;\n\n#include \"RangeCombos.h\"\n\n//////////////////////////////////////////////////////\n//\n// RangeCombo\n//\n//////////////////////////////////////////////////////\n\nRangeCombo::RangeCombo(Combo *minWidget, Combo *maxWidget)\n{\n    _minWidget = minWidget;\n    _maxWidget = maxWidget;\n\n    connect(_minWidget, SIGNAL(valueChanged(double)), this, SLOT(setValueMin(double)));\n\n    connect(_maxWidget, SIGNAL(valueChanged(double)), this, SLOT(setValueMax(double)));\n}\n\nvoid RangeCombo::Update(double minValid, double maxValid, double minValue, double maxValue)\n{\n    _minWidget->Update(minValid, maxValid, minValue);\n    _maxWidget->Update(minValid, maxValid, maxValue);\n}\n\nvoid RangeCombo::setValueMin(double minValue)\n{\n    double maxValue = _maxWidget->GetValue();\n\n    // If minValue is greater than maxValue we change the maxValue to\n    // minValue\n    //\n    if (minValue > maxValue) {\n        maxValue = minValue;\n        _maxWidget->SetSliderLineEdit(maxValue);\n    }\n\n    emit valueChanged(minValue, maxValue);\n}\n\nvoid RangeCombo::setValueMax(double maxValue)\n{\n    double minValue = _minWidget->GetValue();\n\n    if (maxValue < minValue) {\n        minValue = maxValue;\n        _minWidget->SetSliderLineEdit(minValue);\n    }\n\n    emit valueChanged(minValue, maxValue);\n}\n"
  },
  {
    "path": "apps/vaporgui/RangeCombos.h",
    "content": "#ifdef WIN32\n    #pragma warning(disable : 4100)\n#endif\n\n#ifndef RANGECOMBOS_H\n    #define RANGECOMBOS_H\n\n    #include <QWidget>\n    #include \"Combo.h\"\n\n    // Fix for Qt bug https://bugreports.qt.io/browse/QTBUG-98093\n    // Apply a style sheet to QSlider to make it work on OSX Monterey\n    #ifdef Darwin\n        #include \"QMontereySlider.h\"\n        #define QSlider QMontereySlider\n    #endif\n\nQT_BEGIN_NAMESPACE\nclass QComboBox;\nclass QGroupBox;\nclass QLineEdit;\nclass QSlider;\nclass QValidator;\nQT_END_NAMESPACE\n\n//\n// class RangeCombo\n//\n// This class manages a pair of Combo objects, one for\n// a minimum value and one for a maximum value. The class ensures that\n// the minimum is always less than or equal to the maximum by making\n// adjustments as necessary.\n//\nclass RangeCombo : public QWidget {\n    Q_OBJECT\n\npublic:\n    RangeCombo(Combo *minWidget, Combo *maxWidget);\n\n    // This method must be called whenever the minimax or maximum allowable\n    // valid value changes, or the current minimum or maximum value\n    // is changed externally. I.e. Update() provides a means to change\n    // the internal state of the class. If minValid > maxValid, maxValid\n    // will be set to minValid. If minValue or maxValid is outside of\n    // minValid and maxValid it will be set to minValid. if minValue is\n    // greater than maxValue, maxValue will be set to minValue\n    //\n    void Update(double minValid, double maxValid, double minValue, double maxValue);\n\n    QSlider *  GetSliderMin() const { return (_minWidget->GetSlider()); };\n    QLineEdit *GetLineEditMin() const { return (_minWidget->GetLineEdit()); };\n\n    QSlider *  GetSliderMax() const { return (_maxWidget->GetSlider()); };\n    QLineEdit *GetLineEditMax() const { return (_maxWidget->GetLineEdit()); };\n\npublic slots:\n    void setValueMin(double);\n    void setValueMax(double);\n\nsignals:\n    void valueChanged(double minValue, double maxValue);\n\nprivate:\n    Combo *_minWidget;\n    Combo *_maxWidget;\n};\n\n#endif\n"
  },
  {
    "path": "apps/vaporgui/RenderEventRouter.cpp",
    "content": "#include <QFileDialog>\n#include <vapor/ResourcePath.h>\n#include <vapor/DataMgrUtils.h>\n#include \"RenderEventRouter.h\"\n#include <vapor/Renderer.h>\n#include <vapor/DataStatus.h>\n#include <vapor/NavigationUtils.h>\n#include <vapor/ControlExecutive.h>\n\nusing namespace VAPoR;\n\nRenderParams *RenderEventRouter::GetActiveParams() const\n{\n    VAssert(!_instName.empty());\n\n    ParamsMgr *paramsMgr = _controlExec->GetParamsMgr();\n\n    string winName, dataSetName, paramsType;\n    bool   status = paramsMgr->RenderParamsLookup(_instName, winName, dataSetName, paramsType);\n    if (!status)\n        return nullptr;\n\n    string renderType = RendererFactory::Instance()->GetRenderClassFromParamsClass(paramsType);\n\n    return (_controlExec->GetRenderParams(winName, dataSetName, renderType, _instName));\n}\n\nDataMgr *RenderEventRouter::GetActiveDataMgr() const\n{\n    VAssert(!_instName.empty());\n\n    ParamsMgr *paramsMgr = _controlExec->GetParamsMgr();\n\n    string winName, dataSetName, paramsType;\n\n    bool status = paramsMgr->RenderParamsLookup(_instName, winName, dataSetName, paramsType);\n    VAssert(status);\n\n    DataStatus *dataStatus = _controlExec->GetDataStatus();\n    DataMgr *   dataMgr = dataStatus->GetDataMgr(dataSetName);\n    VAssert(dataMgr);\n\n    return (dataMgr);\n}\n\nstring RenderEventRouter::GetSmallIconImagePath() const\n{\n    string imageName = _getSmallIconImagePath();\n    if (imageName.empty()) return (imageName);\n\n    return (GetSharePath(\"images/\" + imageName));\n}\n\nstring RenderEventRouter::GetIconImagePath() const\n{\n    string imageName = _getIconImagePath();\n    if (imageName.empty()) return (imageName);\n\n    return (GetSharePath(\"images/\" + imageName));\n}\n\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RenderEventRouterFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\n\nRenderEventRouter *RenderEventRouterFactory::CreateInstance(string className, QWidget *parent, VAPoR::ControlExec *ce)\n{\n    RenderEventRouter *instance = NULL;\n\n    auto it = _factoryFunctionRegistry.find(className);\n    if (it != _factoryFunctionRegistry.end()) instance = it->second(parent, ce);\n\n    return instance;\n}\n\nvector<string> RenderEventRouterFactory::GetFactoryNames() const\n{\n    vector<string> names;\n    map<string, function<RenderEventRouter *(QWidget *, VAPoR::ControlExec *)>>::const_iterator itr;\n\n    for (itr = _factoryFunctionRegistry.begin(); itr != _factoryFunctionRegistry.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n"
  },
  {
    "path": "apps/vaporgui/RenderEventRouter.h",
    "content": "#pragma once\n\n#include \"VaporFwd.h\"\n#include \"Updatable.h\"\n#include <common.h>\n#include <functional>\n#include <QObject>\n\nusing std::vector;\nusing std::string;\n\nusing std::function;\n\nclass RenderEventRouter : public Updatable {\npublic:\n    RenderEventRouter(ControlExec *ce) : _controlExec(ce) {}\n    virtual ~RenderEventRouter() {}\n    void SetActive(string instName) { _instName = instName; }\n\n    virtual string GetType() const = 0;\n    virtual bool Supports2DVariables() const = 0;\n    virtual bool Supports3DVariables() const = 0;\n    virtual bool SupportsParticleVariables() const { return false; }\n\n    VAPoR::RenderParams *GetActiveParams() const;\n    VAPoR::DataMgr *GetActiveDataMgr() const;\n    string GetDescription() const { return _getDescription(); }\n    string GetSmallIconImagePath() const;\n    string GetIconImagePath() const;\n\nprotected:\n    ControlExec *_controlExec;\n\n    virtual string _getDescription() const = 0;\n    virtual string _getSmallIconImagePath() const = 0;\n    virtual string _getIconImagePath() const = 0;\n\nprivate:\n    string _instName;\n};\n\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RenderEventRouterFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nclass RenderEventRouterFactory {\npublic:\n    static RenderEventRouterFactory *Instance()\n    {\n        static RenderEventRouterFactory instance;\n        return &instance;\n    }\n\n    void RegisterFactoryFunction(string name, function<RenderEventRouter *(QWidget *, VAPoR::ControlExec *)> classFactoryFunction)\n    {\n        _factoryFunctionRegistry[name] = classFactoryFunction;\n    }\n\n    RenderEventRouter *CreateInstance(string classType, QWidget *, VAPoR::ControlExec *);\n    vector<string> GetFactoryNames() const;\n\nprivate:\n    std::map<string, function<RenderEventRouter *(QWidget *, VAPoR::ControlExec *)>> _factoryFunctionRegistry;\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// Register RenderEventRouter derived class with:\n//\n//\tstatic RenderEventRouterRegistrar<RERClass> registrar(\"myclassname\");\n//\n// where 'RERClass' is a class derived from 'RenderEventRouter', and\n// \"myclassname\" is the name of the class\n//\n/////////////////////////////////////////////////////////////////////////\n\ntemplate<class T> class RenderEventRouterRegistrar {\npublic:\n    RenderEventRouterRegistrar(string classType)\n    {\n        RenderEventRouterFactory::Instance()->RegisterFactoryFunction(classType, [](QWidget *parent, VAPoR::ControlExec *ce) -> RenderEventRouter * { return new T(parent, ce); });\n    }\n};\n\n"
  },
  {
    "path": "apps/vaporgui/RenderEventRouterGUI.cpp",
    "content": "#include \"RenderEventRouterGUI.h\"\n#include \"UWidget.h\"\n#include <QScrollArea>\n#include \"VContainer.h\"\n#include <vapor/ControlExecutive.h>\n\nconst std::string RenderEventRouterGUI::VariablesTabName = \"Variables\";\nconst std::string RenderEventRouterGUI::AppearanceTabName = \"Appearance\";\nconst std::string RenderEventRouterGUI::GeometryTabName = \"Geometry\";\nconst std::string RenderEventRouterGUI::ColorbarTabName = \"Colorbar\";\n\nRenderEventRouterGUI::RenderEventRouterGUI(VAPoR::ControlExec *ce, string paramsType)\n: RenderEventRouter(ce)\n{\n    connect(this, &QTabWidget::currentChanged, this, &RenderEventRouterGUI::tabChanged);\n}\n\n\nQWidget *RenderEventRouterGUI::AddSubtab(string title, UWidget *subtab)\n{\n    VContainer *container = new VContainer(subtab);\n    container->AddBottomStretch();\n    container->SetPadding(0, 6, 0, 0);\n\n    QScrollArea *scrollArea = new QScrollArea;\n    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);\n    scrollArea->setWidget(container);\n    scrollArea->setWidgetResizable(true);\n\n    addTab(scrollArea, QString::fromStdString(title));\n    _subtabs.push_back(subtab);\n\n    return scrollArea;\n}\n\nvoid RenderEventRouterGUI::Update()\n{\n    auto *params = GetActiveParams();\n    auto *paramsMgr = _controlExec->GetParamsMgr();\n    auto *dataMgr = GetActiveDataMgr();\n    if (!(params && paramsMgr && dataMgr)) return;\n\n    auto       gp = getGUIStateParams();\n    bool       hasTab = false;\n    const auto activeTab = QString::fromStdString(gp->ActiveTab());\n    for (int i = 0; i <= count(); i++) {\n        if (activeTab == tabText(i)) {\n            hasTab = true;\n            setTab(i);\n            break;\n        }\n    }\n    if (!hasTab) { setTab(0); }\n\n    for (ParamsUpdatable *subtab : _subtabs) subtab->Update(params, paramsMgr, dataMgr);\n}\n\nvoid RenderEventRouterGUI::setTab(int i)\n{\n    blockSignals(true);\n    setCurrentIndex(i);\n    blockSignals(false);\n}\n\nvoid RenderEventRouterGUI::tabChanged(int i)\n{\n    getGUIStateParams()->SetActiveTab(tabText(i).toStdString());\n}\n\nGUIStateParams *RenderEventRouterGUI::getGUIStateParams() const { return (GUIStateParams *)_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()); }\n"
  },
  {
    "path": "apps/vaporgui/RenderEventRouterGUI.h",
    "content": "#pragma once\n\n#include \"RenderEventRouter.h\"\n#include <vapor/GUIStateParams.h>\n#include <QTabWidget>\n\nclass ParamsUpdatable;\nclass UWidget;\n\n//! \\class RenderEventRouterGUI\n//! \\ingroup Public_GUI\n//! \\brief Tab manager for renderer subtabs\n//! \\author Stas Jaroszynski\n\nclass RenderEventRouterGUI : public QTabWidget, public RenderEventRouter {\n    Q_OBJECT\n\n    vector<ParamsUpdatable *> _subtabs;\n\npublic:\n    static const std::string VariablesTabName;\n    static const std::string AppearanceTabName;\n    static const std::string GeometryTabName;\n    static const std::string ColorbarTabName;\n\n    RenderEventRouterGUI(VAPoR::ControlExec *ce, string paramsType);\n    QWidget *AddSubtab(string title, UWidget *subtab);\n    QWidget *AddVariablesSubtab(UWidget *subtab) { return AddSubtab(VariablesTabName, subtab); }\n    QWidget *AddAppearanceSubtab(UWidget *subtab) { return AddSubtab(AppearanceTabName, subtab); }\n    QWidget *AddGeometrySubtab(UWidget *subtab) { return AddSubtab(GeometryTabName, subtab); }\n    QWidget *AddColorbarSubtab(UWidget *subtab) { return AddSubtab(ColorbarTabName, subtab); }\n\n\nprotected:\n    void Update() override;\n\nprivate:\n    void            setTab(int i);\n    void            tabChanged(int i);\n    GUIStateParams *getGUIStateParams() const;\n};\n"
  },
  {
    "path": "apps/vaporgui/RenderHolder.cpp",
    "content": "\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2014\t\t\t\t\t\t\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t\t\t\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tRenderHolder.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tOctober 2014\n//\n//\tDescription:\tImplements the RenderHolder class\n\n#include \"vapor/VAssert.h\"\n#include <qcombobox.h>\n#include <QStringList>\n#include <QTableWidget>\n#include <QCheckBox>\n#include <QList>\n#include <qpushbutton.h>\n#include <sstream>\n#include <vapor/ControlExecutive.h>\n#include <vapor/ParamsMgr.h>\n#include \"qdialog.h\"\n#include \"ui_NewRendererDialog.h\"\n#include \"ErrorReporter.h\"\n#include \"RenderHolder.h\"\n#include \"QPushButtonWithDoubleClick.h\"\n#include <vapor/SettingsParams.h>\n#include <vapor/VolumeRenderer.h>\n#include <vapor/VolumeIsoRenderer.h>\n#include <vapor/DataStatus.h>\n\nusing namespace VAPoR;\n\nnamespace {\nconst string DuplicateInStr = \"Duplicate in:\";\n};\n\nCBWidget::CBWidget(QWidget *parent, QString text) : QWidget(parent), QTableWidgetItem(text){};\n\nNewRendererDialog::NewRendererDialog(QWidget *parent, std::vector<string> rendererNames, std::vector<string> descriptions, std::vector<string> iconPaths, std::vector<string> smallIconPaths,\n                                     std::vector<bool> dim2DSupport, std::vector<bool> dim3DSupport, vector<bool> particleSupport)\n: QDialog(parent), Ui_NewRendererDialog()\n{\n    setupUi(this);\n\n    _rendererNames = rendererNames;\n    _descriptions = descriptions;\n    _iconPaths = iconPaths;\n    _smallIconPaths = smallIconPaths;\n    _dim2DSupport = dim2DSupport;\n    _dim3DSupport = dim3DSupport;\n    _particleSupport = particleSupport;\n\n    rendererNameEdit->setValidator(new QRegExpValidator(QRegExp(\"[a-zA-Z0-9_]{1,64}\")));\n    dataMgrCombo->clear();\n\n    _createButtons();\n\n    connect(dataMgrCombo, SIGNAL(activated(int)), this, SLOT(_showRelevantRenderers()));\n};\n\nvoid NewRendererDialog::_createButtons()\n{\n    int size = _rendererNames.size();\n    _buttons.clear();\n    for (int i = 0; i < size; i++) {\n        QString      iconPath = QString::fromStdString(_smallIconPaths[i]);\n        QIcon        icon(iconPath);\n        QString      name = QString::fromStdString(_rendererNames[i]);\n        QPushButton *button = _createButton(icon, name, i);\n\n        buttonHolderGridLayout->addWidget(button, i, 0);\n        _buttons.push_back(button);\n\n        QPixmap thumbnail(_smallIconPaths[i].c_str());\n        QLabel *label = new QLabel();\n        label->setPixmap(thumbnail);\n        label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);\n        buttonHolderGridLayout->addWidget(label, i, 1);\n\n        if (i == 0) button->setChecked(true);\n    }\n}\n\nQPushButton *NewRendererDialog::_createButton(QIcon icon, QString name, int index)\n{\n    QPushButton *button = new QPushButtonWithDoubleClick(name, this);\n    button->setIconSize(QSize(50, 50));\n    button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);\n    button->setLayoutDirection(Qt::RightToLeft);\n    button->setCheckable(true);\n    button->setProperty(\"index\", index);\n\n    connect(button, SIGNAL(toggled(bool)), this, SLOT(_buttonChecked()));\n    connect(button, SIGNAL(doubleClicked()), this, SLOT(_buttonDoubleClicked()));\n    return button;\n}\n\nvoid NewRendererDialog::InitializeDataSources(VAPoR::ControlExec *ce)\n{\n    VAPoR::DataStatus *dataStatus = ce->GetDataStatus();\n    _dataStatus = dataStatus;\n    const vector<string> datasets = dataStatus->GetDataMgrNames();\n\n    const auto gsp = ce->GetParams<GUIStateParams>();\n    string activeDataset = gsp->GetActiveDataset();\n    if (activeDataset.empty()) {\n        string _1, _2;\n        ce->RenderLookup(gsp->GetActiveRendererInst(), _1, activeDataset, _2);\n    }\n\n    dataMgrCombo->blockSignals(true);\n    dataMgrCombo->clear();\n    for (int i = 0; i < datasets.size(); i++) { dataMgrCombo->addItem(QString::fromStdString(datasets[i])); }\n    dataMgrCombo->setCurrentText(QString::fromStdString(activeDataset));\n    dataMgrCombo->blockSignals(false);\n\n    _showRelevantRenderers();\n}\n\nvoid NewRendererDialog::_showRelevantRenderers()\n{\n    const string datasetName = dataMgrCombo->currentText().toStdString();\n    DataMgr *    dm = _dataStatus->GetDataMgr(datasetName);\n    VAssert(dm);\n\n    bool has2D = dm->GetDataVarNames(2, DataMgr::VarType::Scalar).size();\n    bool has3D = dm->GetDataVarNames(3, DataMgr::VarType::Scalar).size();\n    bool hasParticle = dm->GetDataVarNames(3, DataMgr::VarType::Particle).size();\n\n    for (int i = 0; i < _buttons.size(); i++) {\n        if ((has2D && _dim2DSupport[i]) || (has3D && _dim3DSupport[i]) || (hasParticle && _particleSupport[i])) {\n            _buttons[i]->setEnabled(true);\n            _buttons[i]->setToolTip(\"\");\n        } else {\n            _buttons[i]->setEnabled(false);\n            _buttons[i]->setToolTip(QString::fromStdString(\"Dataset \\\"\" + datasetName + \"\\\" does not have data supported by this renderer\"));\n        }\n    }\n    _selectFirstValidRenderer();\n}\n\nvoid NewRendererDialog::_selectFirstValidRenderer()\n{\n    for (int i = 0; i < _buttons.size(); i++) {\n        if (_buttons[i]->isEnabled()) {\n            _buttons[i]->click();\n            return;\n        }\n    }\n}\n\nvoid NewRendererDialog::_setUpImage(std::string imageName, QLabel *label)\n{\n    QPixmap thumbnail(imageName.c_str());\n    label->setPixmap(thumbnail);\n}\n\nvoid NewRendererDialog::_buttonChecked()\n{\n    QPushButton *button = (QPushButton *)sender();\n    int          index = button->property(\"index\").toInt();\n\n    _uncheckAllButtons();\n    button->blockSignals(true);\n    button->setChecked(true);\n    button->blockSignals(false);\n\n    string icon = _iconPaths[index];\n    _setUpImage(icon, bigDisplay);\n\n    QString title = \"\\n\" + QString::fromStdString(_rendererNames[index]) + \" Renderer\";\n    titleLabel->setText(title);\n\n    QString description = QString::fromStdString(_descriptions[index]);\n    descriptionLabel->setText(description);\n\n    _selectedRenderer = _rendererNames[index];\n}\n\nvoid NewRendererDialog::_buttonDoubleClicked()\n{\n    _buttonChecked();\n    this->accept();\n}\n\nvoid NewRendererDialog::_uncheckAllButtons()\n{\n    int count = buttonHolderGridLayout->count() / 2;\n    for (int i = 0; i < count; i++) {\n        QPushButton *button;\n        button = (QPushButton *)buttonHolderGridLayout->itemAt(i * 2)->widget();\n        button->blockSignals(true);\n        button->setChecked(false);\n        button->blockSignals(false);\n    }\n}\n\nvoid RenderHolder::_showIntelDriverWarning(ControlExec *_controlExec, const string &rendererType)\n{\n    if (_controlExec->GetGPUVendor() != GLManager::Vendor::Intel) return;\n    if (rendererType != VolumeRenderer::GetClassType() && rendererType != VolumeIsoRenderer::GetClassType()) return;\n\n    ParamsMgr *     paramsMgr = _controlExec->GetParamsMgr();\n    SettingsParams *sp = (SettingsParams *)paramsMgr->GetParams(SettingsParams::GetClassType());\n    if (sp->GetDontShowIntelDriverWarning()) return;\n\n    // Qt will automatically delete this for us apparently\n    QCheckBox *dontShowAgain = new QCheckBox(\"Don't show again\");\n    dontShowAgain->blockSignals(true);\n\n    QMessageBox warning;\n    warning.setIcon(QMessageBox::Warning);\n    warning.setText(\"Warning\");\n    warning.setInformativeText(\"Regular grid renderer is used by default. \"\n                               \"If your data is non-regular, it can result in an image that misrepresents your data. \"\n                               \"\\n\\n\"\n                               \"To get correct results for non-regular data, select the curvilinear grid rendering algorithm. \"\n                               \"This can be changed under the renderer's Apperance tab under the transfer function editor. \"\n                               \"\\n\\n\"\n                               \"Your computer uses an Intel GPU which has poor support for the curvilinear renderer. \"\n                               \"It could potentially result in Vapor hanging or crashing. \"\n                               \"In this case, we recommend you use a computer with an AMD or Nvidia GPU. \");\n    warning.addButton(dontShowAgain, QMessageBox::ActionRole);\n    warning.addButton(QMessageBox::Ok);\n    warning.exec();\n\n    if (dontShowAgain->checkState() == Qt::Checked) sp->SetDontShowIntelDriverWarning(true);\n}\n\nvoid RenderHolder::_newRendererDialogAccepted(ControlExec *_controlExec, NewRendererDialog *_newRendererDialog)\n{\n    ParamsMgr *    paramsMgr = _controlExec->GetParamsMgr();\n    vector<string> dataSetNames = _controlExec->GetDataStatus()->GetDataMgrNames();\n\n    string rendererType = _newRendererDialog->GetSelectedRenderer();\n    _showIntelDriverWarning(_controlExec, rendererType);\n\n    int    selection = _newRendererDialog->dataMgrCombo->currentIndex();\n    string dataSetName = dataSetNames[selection];\n\n    GUIStateParams *p = (GUIStateParams *)_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType());\n    string          activeViz = p->GetActiveVizName();\n\n    // figure out the name\n    //\n    QString qname = _newRendererDialog->rendererNameEdit->text();\n    string  rendererName = qname.toStdString();\n\n    // Check that it's not all blanks:\n    //\n    if (rendererName.find_first_not_of(' ') == string::npos) { rendererName = rendererType; }\n\n    rendererName = _controlExec->MakeRendererNameUnique(rendererName);\n    qname = QString(rendererName.c_str());\n\n    paramsMgr->BeginSaveStateGroup(\"Activate Renderer\");\n\n    int rc = _controlExec->ActivateRender(activeViz, dataSetName, rendererType, rendererName, false);\n    if (rc < 0) {\n        MSG_ERR(\"Can't create renderer\");\n        paramsMgr->EndSaveStateGroup();\n        return;\n    }\n\n    // Save current instance to state\n    //\n    p->SetActiveRenderer(activeViz, rendererType, rendererName);\n\n//    Update();\n\n//    emit newRendererSignal(activeViz, rendererType, rendererName);\n    paramsMgr->EndSaveStateGroup();\n}"
  },
  {
    "path": "apps/vaporgui/RenderHolder.h",
    "content": "#ifndef RENDERHOLDER_H\n#define RENDERHOLDER_H\n\n#include <qobject.h>\n#include <qstackedwidget.h>\n#include <qpushbutton.h>\n#include <qtableview.h>\n#include <vapor/MyBase.h>\n#include <QMessageBox>\n#include <vapor/GUIStateParams.h>\n#include \"ui_NewRendererDialog.h\"\n#include \"VaporTable.h\"\n#include <vapor/ControlExecutive.h>\n\nQT_USE_NAMESPACE\n\nclass RendererList;\nnamespace VAPoR {\nclass ControlExec;\nclass ParamsMgr;\nclass DataStatus;\nclass RenderParams;\n}    // namespace VAPoR\n\nclass NewRendererDialog : public QDialog, public Ui_NewRendererDialog {\n    Q_OBJECT\n\npublic:\n    NewRendererDialog(QWidget *parent, std::vector<string> rendererNames, std::vector<string> descriptions, std::vector<string> iconPaths, std::vector<string> smallIconPaths,\n                      std::vector<bool> dim2DSupport, std::vector<bool> dim3DSupport, vector<bool> particleSupport);\n\n    std::string GetSelectedRenderer() { return _selectedRenderer; }\n    void        InitializeDataSources(VAPoR::ControlExec *ce);\n\nprivate slots:\n    void _buttonChecked();\n    void _buttonDoubleClicked();\n    void _showRelevantRenderers();\n\nprivate:\n    void         _createButtons();\n    void         _setUpImage(std::string imageName, QLabel *label);\n    void         _uncheckAllButtons();\n    void         _selectFirstValidRenderer();\n    QPushButton *_createButton(QIcon icon, QString name, int index);\n\n    std::vector<string>        _rendererNames;\n    std::vector<string>        _descriptions;\n    std::vector<string>        _iconPaths;\n    std::vector<string>        _smallIconPaths;\n    std::vector<bool>          _dim2DSupport;\n    std::vector<bool>          _dim3DSupport;\n    std::vector<bool>          _particleSupport;\n    std::vector<QPushButton *> _buttons;\n\n    VAPoR::DataStatus *_dataStatus;\n\n    std::string  _selectedRenderer;\n    QMessageBox *_msgBox;\n};\n\nclass CBWidget : public QWidget, public QTableWidgetItem {\npublic:\n    CBWidget(QWidget *parent, QString type);\n};\n\n//! \\class RenderHolder\n//! \\ingroup Public_GUI\n//! \\brief A class that manages the display of Renderer parameters\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date April 2015\n\n//! This is class manages a QTableWidget that indicates the currently\n//! available Renderers, and a\n//! QStackedWidget that displays the various parameters associated\n//! with the selected renderer.\n//!\nclass RenderHolder {\npublic:\n    static void _showIntelDriverWarning(VAPoR::ControlExec *_controlExec, const string &rendererType);\n    static void _newRendererDialogAccepted(VAPoR::ControlExec *_controlExec, NewRendererDialog *_newRendererDialog);\n};\n\n#endif    // RENDERHOLDER_H\n"
  },
  {
    "path": "apps/vaporgui/RendererInspector.cpp",
    "content": "#include \"RendererInspector.h\"\n#include \"RenderEventRouter.h\"\n#include <QDebug>\n#include <vapor/GUIStateParams.h>\n#include <vapor/ControlExecutive.h>\n\nusing namespace VAPoR;\nusing std::vector;\nusing std::string;\n#include \"QTabWidget\"\n\nRendererInspector::RendererInspector(VAPoR::ControlExec *ce)\n: _ce(ce)\n{\n    vector<string> rendererNames = RenderEventRouterFactory::Instance()->GetFactoryNames();\n\n    for (auto name : rendererNames) {\n        RenderEventRouter *re = RenderEventRouterFactory::Instance()->CreateInstance(name, NULL, _ce);\n        QWidget *w = dynamic_cast<QWidget*>(re);\n        VAssert(w);\n        VRouter::Add(w);\n        _classToInspectorMap[name] = std::pair<RenderEventRouter*,QWidget*>(re, w);\n    }\n}\n\nvoid RendererInspector::Update()\n{\n    ParamsMgr *paramsMgr = _ce->GetParamsMgr();\n    GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n    string currentViz = guiParams->GetActiveVizName();\n    string renClass, renInst, _;\n    guiParams->GetActiveRenderer(currentViz, renClass, renInst);\n\n    if (renInst.empty() || _classToInspectorMap.count(renClass) == 0 || !paramsMgr->RenderParamsLookup(renInst, _, _, _)) {\n        Show(nullptr);\n        return;\n    }\n\n    Show(_classToInspectorMap[renClass].second);\n    _classToInspectorMap[renClass].first->SetActive(renInst);\n    _classToInspectorMap[renClass].first->Update();\n}\n\nstd::vector<RenderEventRouter *> RendererInspector::GetRenderEventRouters() const\n{\n    vector<RenderEventRouter*> v;\n    for (auto it = _classToInspectorMap.begin(); it != _classToInspectorMap.end(); ++it)\n        v.push_back(it->second.first);\n    return v;\n}"
  },
  {
    "path": "apps/vaporgui/RendererInspector.h",
    "content": "#pragma once\n\n#include \"VRouter.h\"\n\nnamespace VAPoR {\nclass ControlExec;\n}\nclass RenderEventRouter;\n\nclass RendererInspector : public VRouter {\n    VAPoR::ControlExec *_ce;\n    std::map<std::string, std::pair<RenderEventRouter*, QWidget*>> _classToInspectorMap;\n\npublic:\n    RendererInspector(VAPoR::ControlExec *ce);\n    void Update();\n\n    // Addresses legacy deps\n    std::vector<RenderEventRouter*> GetRenderEventRouters() const;\n};\n"
  },
  {
    "path": "apps/vaporgui/RendererList.cpp",
    "content": "#include \"RendererList.h\"\n\n#include <QDebug>\n#include <QScrollBar>\n#include <QToolButton>\n#include <QMenu>\n#include <QInputDialog>\n#include <vapor/STLUtils.h>\n#include <vapor/DataStatus.h>\n#include <vapor/Renderer.h>\n#include \"VGroup.h\"\n#include \"VVisibilityCheckbox.h\"\n#include \"RenderEventRouter.h\"\n#include \"NewRendererDialogManager.h\"\n\nstd::map<string, RendererList::RendererMetadata> RendererList::_rendererMetadata;\nbool RendererList::AllowInspectDataset = true;\n\n// Fixes a bug in Qt.\nclass DisableDatasetClickEventFilter: public QObject {\n    QListWidget *_w;\npublic:\n    DisableDatasetClickEventFilter(QListWidget *w) : _w(w) {}\nprotected:\n    bool eventFilter(QObject* object, QEvent* event)\n    {\n        if(event->type() == QEvent::MouseButtonRelease ||\n           event->type() == QEvent::MouseButtonPress ||\n           event->type() == QEvent::MouseButtonDblClick) {\n            auto pos = _w->mapFromGlobal(QCursor::pos());\n            auto *item = _w->itemAt(pos);\n            if (item) {\n                if (item->type() == RendererList::DatasetType) {\n                    return true;\n                }\n            }\n        }\n        return QObject::eventFilter(object, event);\n    }\n};\n\nclass DisableDragFilter: public QObject {\n//    QListWidget *_w;\npublic:\n    DisableDragFilter(QListWidget *w)\n//    : _w(w)\n    {}\nprotected:\n    bool eventFilter(QObject* object, QEvent* event)\n    {\n        // This event filter is ignored by disabled items.\n//        if (event->type() == QEvent::MouseButtonPress) {\n//            auto pos = _w->mapFromGlobal(QCursor::pos());\n//            auto *item = _w->itemAt(pos);\n//            if (item && !(item->flags() & Qt::ItemIsEnabled))\n//                return true;\n//        }\n        if(event->type() == QEvent::MouseMove)\n            return true;\n        return QObject::eventFilter(object, event);\n    }\n};\n\nRendererList::RendererList(ControlExec *ce) : VContainer(_lw = new QListWidget), _ce(ce)\n{\n    installEventFilter(new DisableDragFilter(_lw));\n    // itemSelectionChanged signal specifically needs to be used. currentItemChanged is slightly different from selectedItem.\n    connect(_lw, &QListWidget::itemSelectionChanged, this, &RendererList::itemSelectionChanged);\n    _lw->setContextMenuPolicy(Qt::CustomContextMenu);\n    connect(_lw, &QListWidget::customContextMenuRequested, this, &RendererList::showContextMenu);\n    \n    if (_rendererMetadata.empty()) {\n        auto eventRouterNames = RenderEventRouterFactory::Instance()->GetFactoryNames();\n        for (auto &rendererType : eventRouterNames) {\n            auto router = std::unique_ptr<RenderEventRouter>(RenderEventRouterFactory::Instance()->CreateInstance(rendererType, nullptr, _ce));\n            _rendererMetadata[rendererType] = {\n                router->Supports2DVariables(),\n                router->Supports3DVariables(),\n                router->SupportsParticleVariables(),\n                router->GetDescription(),\n                router->GetSmallIconImagePath(),\n                router->GetIconImagePath()\n            };\n        }\n    }\n\n    if (!AllowInspectDataset)\n        _lw->viewport()->installEventFilter(new DisableDatasetClickEventFilter(_lw));\n\n    \n    _toolbar = new VHGroup;\n    _toolbar->layout()->setSpacing(0);\n    _toolbar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\n    _toolbar->setParent(this);\n    _toolbar->show();\n    \n    QToolButton *tb = new QToolButton;\n    _deleteToolButton = tb;\n    _toolbar->Add(tb);\n    tb->setText(\"-\");\n    tb->setStyleSheet(\"QToolButton{font-size: 15pt;font-weight:bold; } QToolButton:enabled{color:#bf0206;}\");\n    connect(tb, &QToolButton::clicked, this, [=](){\n        auto item = _lw->currentItem();\n        if (item && item->type() == RendererType) {\n            RendererItem *rItem = dynamic_cast<RendererItem*>(item);\n            deleteRenderer(rItem->Id);\n        }\n    });\n\n    _nrd = new NewRendererDialogManager(ce, this);\n    tb = new QToolButton;\n    _toolbar->Add(tb);\n    tb->setText(\"+\");\n    connect(tb, &QToolButton::clicked, _nrd, &NewRendererDialogManager::Show);\n    tb->setStyleSheet(\"QToolButton{font-size: 15pt;font-weight:bold;} QToolButton:enabled{color:#2b822b;}\");\n}\n\nvoid RendererList::Update()\n{\n    auto paramsMgr = _ce->GetParamsMgr();\n    GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n    string currentViz = guiParams->GetActiveVizName();\n    string activeRenderClass, activeRenderInst;\n    guiParams->GetActiveRenderer(currentViz, activeRenderClass, activeRenderInst);\n    string activeDataset = guiParams->GetActiveDataset();\n\n    const auto allViz = paramsMgr->GetVisualizerNames();\n\n    _lw->blockSignals(true);\n    int scrollY = _lw->verticalScrollBar()->value();\n    _lw->clear();\n\n    auto datasets = guiParams->GetOpenDataSetNames();\n    for (int i = 0; i < datasets.size(); i++) {\n        auto dataset = datasets[i];\n        if (i != 0) {\n            QListWidgetItem *spacerItem = new QListWidgetItem();\n            // These flags only sortof work\n            spacerItem->setFlags(spacerItem->flags() & ~Qt::ItemIsEnabled & ~Qt::ItemIsSelectable & ~Qt::ItemIsDragEnabled);\n            _lw->addItem(spacerItem);\n        }\n\n        QListWidgetItem *datasetItem = new DatasetItem(dataset);\n        datasetItem->setFlags(datasetItem->flags() & ~Qt::ItemIsDragEnabled);\n        QLabel *datasetLabel = new QLabel(QString::fromStdString(dataset));\n        datasetLabel->setStyleSheet(\"QLabel { font-weight: 500; }\");\n        if (!AllowInspectDataset)\n            datasetItem->setFlags(datasetItem->flags() & ~Qt::ItemIsEnabled);\n        _lw->addItem(datasetItem);\n        _lw->setItemWidget(datasetItem, datasetLabel);\n        if (AllowInspectDataset && dataset == activeDataset)\n            _lw->setCurrentRow(_lw->count()-1);\n\n        vector<string> rendererNames;\n        paramsMgr->GetRenderParamNames(currentViz, dataset, rendererNames);\n        \n        for (auto rName : rendererNames) {\n            const auto className = getClassName(rName);\n            RenderParams *rp = _ce->GetRenderParams(currentViz, dataset, className, rName);\n            \n            VHGroup *line = new VHGroup;\n            auto vc = new VVisibilityCheckbox;\n            line->Add(vc);\n            const auto vars = getHintVariables(rp);\n            line->Add(new QLabel(QString::fromStdString(rp->GetValueString(rp->UserNameTag, rName) + (vars.empty() ? \"\" : \" (\" + STLUtils::Join(vars, \", \") + \")\"))));\n\n            vc->SetValue(rp->IsEnabled());\n            \n            connect(vc, &VVisibilityCheckbox::ValueChanged, this, [=](bool on){\n                RenderParams *rp = _ce->GetRenderParams(currentViz, dataset, className, rName);\n                if (rp) {\n                    rp->SetEnabled(on);\n                }\n            });\n            \n            QListWidgetItem *item = new RendererItem(rName, className, dataset);\n            item->setFlags(item->flags() & ~Qt::ItemIsDragEnabled);\n            _lw->addItem(item);\n            _lw->setItemWidget(item, line);\n            \n            if (rName == activeRenderInst) {\n                _lw->setCurrentRow(_lw->count()-1);\n            }\n        }\n    }\n    // _lw->scroll scrolls container, not the actual scroll area\n    _lw->verticalScrollBar()->setValue(scrollY);\n    _lw->blockSignals(false);\n\n    _deleteToolButton->setEnabled(!activeRenderInst.empty());\n}\n\nstring RendererList::getCurrentViz()\n{\n    GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType());\n    return guiParams->GetActiveVizName();\n}\n\nstring RendererList::getClassName(string instName)\n{\n    auto classes = _ce->GetRenderClassNames(getCurrentViz());\n    for (auto c : classes) {\n        if (STLUtils::Contains(_ce->GetRenderInstances(getCurrentViz(), c), instName)) {\n            return c;\n        }\n    }\n    return \"\";\n}\n\nvoid RendererList::itemSelectionChanged()\n{\n    if (_lw->selectedItems().empty())  // This will trigger with nothing semi-randomly if\n        return Update();               // empty space between multiple loaded datasets clicked\n\n    QListWidgetItem *item = _lw->selectedItems()[0];\n    if (item->type() == RendererType) {\n        RendererItem *rItem = dynamic_cast<RendererItem*>(item);\n        inspectRenderer(rItem);\n    }\n    else if (item->type() == DatasetType) {\n        DatasetItem *dItem = dynamic_cast<DatasetItem*>(item);\n        inspectDataset(dItem);\n    }\n}\n\nvoid RendererList::inspectRenderer(RendererItem *rItem)\n{\n    GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType());\n    guiParams->SetActiveRenderer(guiParams->GetActiveVizName(), rItem->Class, rItem->Id);\n}\n\nvoid RendererList::inspectDataset(DatasetItem *item)\n{\n    GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType());\n    guiParams->SetActiveDataset(item->Id);\n}\n\nvoid RendererList::showContextMenu(const QPoint& localPos)\n{\n    auto currentViz = getCurrentViz();\n    \n    QMenu _menu;\n    QMenu *menu = &_menu;\n    \n    QListWidgetItem *item = _lw->itemAt(localPos);\n    if (item && item->type() == RendererType) {\n        string id, dataset, Class;\n        { // Cannot capture rItem since after update caused by click may be recreated\n            RendererItem *rItem = dynamic_cast<RendererItem *>(item);\n            id = rItem->Id, dataset = rItem->Dataset, Class = rItem->Class;\n        }\n        RenderParams *rp = _ce->GetRenderParams(currentViz, dataset, Class, id);\n        menu->addAction(rp->IsEnabled() ? \"Hide\" : \"Show\", [=](){rp->SetEnabled(!rp->IsEnabled());});\n        menu->addAction(\"Delete\", [=](){deleteRenderer(id);});\n        menu->addAction(\"Rename\", [=](){renameRenderer(id);});\n        \n        QMenu *duplicateMenu = menu->addMenu(\"Duplicate in\");\n        for (auto viz : _ce->GetVisualizerNames()) {\n            duplicateMenu->addAction(QString::fromStdString(viz), [=](){\n                auto newName = _ce->MakeRendererNameUnique(id);\n                _ce->GetParamsMgr()->BeginSaveStateGroup(\"Duplicate Ren\");\n                auto newParams = _ce->GetRenderParams(currentViz, dataset, Class, id);\n                _ce->GetParamsMgr()->CreateRenderParamsInstance(viz, dataset, newName, newParams);\n\n                _ce->ActivateRender(viz, dataset, Class, newName, false);\n                auto p = _ce->GetRenderParams(viz, dataset, Class, newName);\n                if (!p->GetValueString(p->UserNameTag, \"\").empty())\n                    p->SetValueString(p->UserNameTag, \"\", p->GetValueString(p->UserNameTag, \"\") + \" (copy)\");\n                _ce->GetParamsMgr()->EndSaveStateGroup();\n            });\n        }\n    }\n    \n    \n    auto eventRouterNames = RenderEventRouterFactory::Instance()->GetFactoryNames();\n    auto datasets = _ce->GetParamsMgr()->GetDataMgrNames();\n    \n    QMenu *newRendererMenu = menu->addMenu(\"New Renderer\");\n    \n    for (const auto &dataset : datasets) {\n        DataMgr *dm = _ce->GetDataStatus()->GetDataMgr(dataset);\n        bool has2D = dm->GetDataVarNames(2, DataMgr::VarType::Scalar).size();\n        bool has3D = dm->GetDataVarNames(3, DataMgr::VarType::Scalar).size();\n        bool hasParticle = dm->GetDataVarNames(3, DataMgr::VarType::Particle).size();\n        QMenu *datasetMenu = newRendererMenu;\n        if (datasets.size() > 1)\n            datasetMenu = newRendererMenu->addMenu(QString::fromStdString(dataset));\n        for (const auto &rendererType : eventRouterNames) {\n            QAction *action = datasetMenu->addAction(QString::fromStdString(rendererType), [=](){\n                _ce->ActivateRender(currentViz, dataset, rendererType, _ce->MakeRendererNameUnique(rendererType), false);\n                // TODO renderer creation using params\n                // _ce->GetParamsMgr()->CreateRenderParamsInstance(currentViz, dataset, RendererFactory::Instance()->GetParamsClassFromRenderClass(rendererType), _ce->MakeRendererNameUnique(rendererType));\n            });\n            const auto &meta = _rendererMetadata[rendererType];\n            if (!((has2D && meta.supports2D) || (has3D && meta.supports3D) || (hasParticle && meta.supportsParticle))) {\n                action->setEnabled(false);\n                action->setToolTip(QString::fromStdString(\"Dataset \\\"\" + dataset + \"\\\" does not have data supported by this renderer\"));\n            }\n        }\n    }\n    \n    menu->exec(_lw->viewport()->mapToGlobal(localPos));\n}\n\nvoid RendererList::deleteRenderer(std::string id)\n{\n    string rWin, rDataset, rClass;\n    _ce->RenderLookup(id, rWin, rDataset, rClass);\n\n    ParamsMgr *paramsMgr = _ce->GetParamsMgr();\n    GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n    paramsMgr->BeginSaveStateGroup(\"Remove Renderer\");\n    _ce->RemoveRenderer(rWin, rDataset, rClass, id, false);\n    guiParams->SetActiveRenderer(getCurrentViz(), \"\", \"\");\n\n    vector<string> otherInsts;\n    paramsMgr->GetRenderParamNames(rWin, otherInsts);\n\n    // Need to set any other renderer otherwise other GUI code will break.\n    for (auto &other : otherInsts) {\n        if (other == id) continue;\n        _ce->RenderLookup(other, rWin, rDataset, rClass);\n        guiParams->SetActiveRenderer(guiParams->GetActiveVizName(), rClass, other);\n        break;\n    }\n    paramsMgr->EndSaveStateGroup();\n}\n\n#include <vapor/ImageParams.h>\n#include <vapor/FlowParams.h>\n#include <vapor/BarbParams.h>\n#include <vapor/ModelParams.h>\n#include <vapor/ParticleParams.h>\nstd::vector<string> RendererList::getHintVariables(VAPoR::RenderParams *rp)\n{\n    auto helper = [](RenderParams *rp) -> vector<string> {\n        if (dynamic_cast<FlowParams*>(rp) || dynamic_cast<BarbParams*>(rp) || dynamic_cast<ParticleParams*>(rp))\n            return rp->GetFieldVariableNames();\n        if (dynamic_cast<ImageParams*>(rp))\n            return {rp->GetHeightVariableName()};\n        if (dynamic_cast<ModelParams*>(rp))\n            return {};\n        return {rp->GetFirstVariableName()};\n    };\n    return STLUtils::Filter<string>(helper(rp), [](const string &v){return !v.empty();});\n}\n\nvoid RendererList::renameRenderer(std::string id)\n{\n    string rWin, rDataset, rClass;\n    _ce->RenderLookup(id, rWin, rDataset, rClass);\n    RenderParams *rp = _ce->GetRenderParams(rWin, rDataset, rClass, id);\n    bool ok;\n    string newName = QInputDialog::getText(this, \"Rename Renderer\", \"\", QLineEdit::Normal, QString::fromStdString(rp->GetValueString(rp->UserNameTag, id)), &ok).toStdString();\n    if (ok)\n        rp->SetValueString(rp->UserNameTag, \"\", newName);\n}\n\nvoid RendererList::resizeEvent(QResizeEvent *event)\n{\n    _toolbar->setFixedSize(_toolbar->sizeHint());\n    auto p = size() - _toolbar->size();\n    _toolbar->move(p.width(), p.height());\n}\n"
  },
  {
    "path": "apps/vaporgui/RendererList.h",
    "content": "#pragma once\n\n#include \"VContainer.h\"\n#include <QListWidget>\n\nnamespace VAPoR{\nclass ControlExec;\nclass RenderParams;\n}\nusing namespace VAPoR;\nusing std::string;\nclass DisableDatasetClickEventFilter;\nclass NewRendererDialogManager;\nclass VHGroup;\nclass QToolButton;\n\nclass RendererList : public VContainer {\n    Q_OBJECT\n    QListWidget *_lw;\n    QToolButton *_deleteToolButton;\n    ControlExec *_ce;\n    NewRendererDialogManager *_nrd;\n    \n    struct RendererMetadata {\n        bool supports2D, supports3D, supportsParticle;\n        string description;\n        string iconPath;\n        string imagePath;\n    };\n    static bool AllowInspectDataset;\n    static std::map<string, RendererMetadata> _rendererMetadata;\n    static const int DatasetType = QListWidgetItem::UserType;\n    static const int RendererType = QListWidgetItem::UserType+1;\n\n    class RendererItem : public QListWidgetItem {\n    public:\n        const std::string Id;\n        const std::string Class;\n        const std::string Dataset;\n        RendererItem(const std::string &instName, const std::string &className, const std::string &datasetName)\n        : QListWidgetItem(nullptr, RendererType), Id(instName), Class(className), Dataset(datasetName) {}\n    };\n    class DatasetItem : public QListWidgetItem {\n    public:\n        const std::string Id;\n        DatasetItem(const std::string &name)\n        : QListWidgetItem(nullptr, DatasetType), Id(name) {}\n    };\n\npublic:\n    RendererList(ControlExec *ce);\n    void Update();\n    string getCurrentViz();\n    string getClassName(string instName);\n    void itemSelectionChanged();\n    void inspectRenderer(RendererItem *item);\n    void inspectDataset(DatasetItem *item);\n    void showContextMenu(const QPoint& localPos);\n    void deleteRenderer(string id);\n    static std::vector<string> getHintVariables(RenderParams *rp);\n    void renameRenderer(string inst);\n\nprotected:\n    VHGroup *_toolbar;\n    void resizeEvent(QResizeEvent *event);\n\n    friend class DisableDatasetClickEventFilter;\n};\n\n\n\n\n"
  },
  {
    "path": "apps/vaporgui/RenderersPanel.cpp",
    "content": "#include \"RenderersPanel.h\"\n#include <QSplitter>\n#include <vapor/GUIStateParams.h>\n#include <vapor/ControlExecutive.h>\n#include \"RendererList.h\"\n#include \"RendererInspector.h\"\n#include \"DatasetInspector.h\"\n#include \"VRouter.h\"\n\nusing namespace VAPoR;\n\nRenderersPanel::RenderersPanel(VAPoR::ControlExec *ce)\n: VContainer(_splitter = new QSplitter(Qt::Orientation::Vertical)),\n  _ce(ce)\n{\n    _splitter->addWidget(_renList = new RendererList(_ce));\n    _splitter->addWidget(_inspectorRouter = new VRouter);\n    _splitter->setChildrenCollapsible(false);\n    _inspectorRouter->Add(_renInspector = new RendererInspector(_ce));\n    _inspectorRouter->Add(_dataInspector = new DatasetInspector(_ce));\n}\n\nvoid RenderersPanel::Update()\n{\n    GUIStateParams *guiParams = (GUIStateParams *)_ce->GetParamsMgr()->GetParams(GUIStateParams::GetClassType());\n\n    _renList->Update();\n\n    if (!guiParams->GetActiveDataset().empty() && guiParams->GetActiveRendererInst().empty()) {\n        _inspectorRouter->Show(_dataInspector);\n        _dataInspector->Update();\n    } else {\n        _inspectorRouter->Show(_renInspector);\n        _renInspector->Update();\n    }\n}"
  },
  {
    "path": "apps/vaporgui/RenderersPanel.h",
    "content": "#pragma once\n\n#include \"VContainer.h\"\n#include \"Updatable.h\"\n#include \"VaporFwd.h\"\n\nclass RendererList;\nclass RendererInspector;\nclass DatasetInspector;\nclass VRouter;\nclass QSplitter;\n\nclass RenderersPanel : public VContainer, public Updatable {\n    Q_OBJECT\n    QSplitter *_splitter;\n    VAPoR::ControlExec *_ce;\n    RendererList *_renList;\n    VRouter *_inspectorRouter;\n    RendererInspector *_renInspector;\n    DatasetInspector *_dataInspector;\n\npublic:\n    RenderersPanel(VAPoR::ControlExec *ce);\n    void Update();\n};"
  },
  {
    "path": "apps/vaporgui/SliceEventRouter.cpp",
    "content": "#include \"SliceEventRouter.h\"\n#include <vapor/SliceParams.h>\n#include \"PWidgets.h\"\n#include \"PSliceController.h\"\n#include \"PMetadataClasses.h\"\n\nusing namespace VAPoR;\n\nstatic RenderEventRouterRegistrar<SliceEventRouter> registrar(SliceEventRouter::GetClassType());\n\nSliceEventRouter::SliceEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, SliceParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PScalarVariableSelector\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    AddAppearanceSubtab(new PGroup({\n        new PTFEditor,\n        new PSection(\"Slice\", {\n            (new PDoubleSliderEdit(RenderParams::SampleRateTag, \"N Samples\"))->SetRange(32, 2000)\n        })\n    }));\n    \n    AddGeometrySubtab(new PGroup({\n        new PSliceController,\n        new PGeometrySubtab,\n    }));\n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nstring SliceEventRouter::_getDescription() const\n{\n    return (\"Displays a slice or cutting plane through\"\n            \"a 3D variable.  Slices are sampled along the plane's axes according\"\n            \" to a sampling rate define by the user.\\n\\n\");\n}\n"
  },
  {
    "path": "apps/vaporgui/SliceEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include <vapor/SliceRenderer.h>\n\n//!\n//! \\class SliceEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Defines the Slice Renderer GUI\n//! \\author Stas Jaroszynski\n\nclass SliceEventRouter : public RenderEventRouterGUI {\npublic:\n    SliceEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::SliceRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return false; }\n    bool          Supports3DVariables() const { return true; }\n\nprotected:\n    string _getDescription() const;\n    string _getSmallIconImagePath() const { return \"Slice_small.png\"; }\n    string _getIconImagePath() const { return \"Slice.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/Statistics.cpp",
    "content": "//************************************************************************\n//                                                                       *\n//         Copyright (C)  2016                                           *\n//   University Corporation for Atmospheric Research                     *\n//         All Rights Reserved                                           *\n//                                                                       *\n//************************************************************************\n//\n//  File:      Statistics.cpp\n//\n//  Author:  Samuel Li\n//        National Center for Atmospheric Research\n//        PO 3000, Boulder, Colorado\n//\n//  Date:      November 2017\n//\n//  Description:    Implements the Statistics class.\n//\n#ifdef WIN32\n    #pragma warning(disable : 4100)\n#endif\n#include \"Statistics.h\"\n#include <vapor/GUIStateParams.h>\n#include \"ErrorReporter.h\"\n#include \"Flags.h\"\n\n#include <QFileDialog>\n#include <QMouseEvent>\n#include <fstream>\n#include <iostream>\n#include <sstream>\n#include <cmath>\n#include \"vapor/VAssert.h\"\n#include <cstdio>\n#include <algorithm>\n#include <vapor/MyBase.h>\n#include <vapor/DataStatus.h>\n#include \"PWidgets.h\"\n#include \"VPushButton.h\"\n\nusing namespace Wasp;\nusing namespace VAPoR;\nusing namespace std;\n\n// Class Statistics\n//\nStatistics::Statistics(QWidget *parent) : QDialog(parent), Ui_StatsWindow()\n{\n    _controlExec = NULL;\n\n    setupUi(this);\n    setWindowTitle(\"Statistics\");\n    MyFidelityWidget->Reinit((VariableFlags)AUXILIARY);\n\n    Connect();\n\n    auto rs = new PRegionSelector;\n    verticalLayout_2->insertWidget(0, rs);\n    _pw.push_back(rs);\n\n    auto cr = new PCopyRegionWidget;\n    verticalLayout_2->insertWidget(1, cr);\n    _pw.push_back(cr);\n\n    VPushButton *close = new VPushButton(\"Close Window\");\n    connect(close, &VPushButton::ButtonClicked, this, &QDialog::accept);\n    layout()->addWidget(close);\n}\n\nStatistics::~Statistics()\n{\n}\n\nvoid Statistics::Update()\n{\n    // Initialize pointers\n    VAPoR::DataStatus *      dataStatus = _controlExec->GetDataStatus();\n    std::vector<std::string> dmNames = dataStatus->GetDataMgrNames();\n    if (dmNames.empty()) {\n        this->close();\n        return;\n    }\n    GUIStateParams *guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string     currentDatasetName = guiParams->GetStatsDatasetName();\n    if (currentDatasetName == \"\" || currentDatasetName == \"NULL\") {\n        this->close();\n        return;\n    }\n\n    int currentIdx = -1;\n    for (int i = 0; i < dmNames.size(); i++)\n        if (currentDatasetName == dmNames[i]) {\n            currentIdx = i;\n            break;\n        }\n    if (currentIdx == -1)    // currentDatasetName is closed!!!\n    {\n        currentDatasetName = dmNames[0];\n        currentIdx = 0;\n        guiParams->SetStatsDatasetName(currentDatasetName);\n\n        _validStats.Clear();    // since the old dataset is closed, we clear all stats.\n        _validStats.currentDataSourceName = currentDatasetName;\n    }\n    VAPoR::DataMgr *         currentDmgr = dataStatus->GetDataMgr(currentDatasetName);\n    StatisticsParams *       statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(currentDatasetName, StatisticsParams::GetClassType()));\n    std::vector<std::string> enabledVars = statsParams->GetAuxVariableNames();\n    if (_validStats.GetVariableCount() == 0)    // likely because the current data set is switched\n    {\n        for (int i = 0; i < enabledVars.size(); i++) _validStats.AddVariable(enabledVars[i]);\n    }\n\n    // detect params changed by undo/redo\n    if (_validStats.currentDataSourceName != currentDatasetName || !_validStats.HaveSameParams(statsParams)) {\n        _validStats.currentDataSourceName = currentDatasetName;\n        _validStats.UpdateMyParams(statsParams);\n    }\n\n    // Update DataMgrCombo\n    DataMgrCombo->blockSignals(true);\n    DataMgrCombo->clear();\n    for (int i = 0; i < dmNames.size(); i++) DataMgrCombo->addItem(QString::fromStdString(dmNames[i]));\n    DataMgrCombo->setCurrentIndex(currentIdx);\n    DataMgrCombo->blockSignals(false);\n\n    // Update auto-update checkbox\n    bool autoUpdate = statsParams->GetAutoUpdateEnabled();\n    UpdateCheckbox->blockSignals(true);\n    if (autoUpdate)\n        UpdateCheckbox->setCheckState(Qt::Checked);\n    else\n        UpdateCheckbox->setCheckState(Qt::Unchecked);\n    UpdateCheckbox->blockSignals(false);\n\n    // Update \"Add a Variable\"\n    std::vector<std::string> availVars = currentDmgr->GetDataVarNames();\n    for (int i = 0; i < enabledVars.size(); i++)\n        for (int rmIdx = 0; rmIdx < availVars.size(); rmIdx++)\n            if (availVars[rmIdx] == enabledVars[i]) {\n                availVars.erase(availVars.begin() + rmIdx);\n                break;\n            }\n    std::sort(availVars.begin(), availVars.end());\n    NewVarCombo->blockSignals(true);\n    NewVarCombo->clear();\n    NewVarCombo->blockSignals(false);\n    NewVarCombo->addItem(QString(\"Add a Variable\"));\n    for (std::vector<std::string>::iterator it = availVars.begin(); it != availVars.end(); ++it) { NewVarCombo->addItem(QString::fromStdString(*it)); }\n    NewVarCombo->setCurrentIndex(0);\n\n    // Update \"Remove a Variable\"\n    VAssert(enabledVars.size() == _validStats.GetVariableCount());\n    std::sort(enabledVars.begin(), enabledVars.end());\n    RemoveVarCombo->blockSignals(true);\n    RemoveVarCombo->clear();\n    RemoveVarCombo->addItem(QString(\"Remove a Variable\"));\n    for (int i = 0; i < enabledVars.size(); i++) { RemoveVarCombo->addItem(QString::fromStdString(enabledVars[i])); }\n    RemoveVarCombo->setCurrentIndex(0);\n    RemoveVarCombo->blockSignals(false);\n\n    // Update Statistics table: header\n    this->_updateStatsTable();\n\n    // Update calculations\n    NewCalcCombo->blockSignals(true);\n    RemoveCalcCombo->blockSignals(true);\n    NewCalcCombo->clear();\n    RemoveCalcCombo->clear();\n    NewCalcCombo->addItem(QString(\"Add a Calculation\"));\n    RemoveCalcCombo->addItem(QString(\"Remove a Calculation\"));\n    if (statsParams->GetMinEnabled())\n        RemoveCalcCombo->addItem(QString(\"Min\"));\n    else\n        NewCalcCombo->addItem(QString(\"Min\"));\n    if (statsParams->GetMaxEnabled())\n        RemoveCalcCombo->addItem(QString(\"Max\"));\n    else\n        NewCalcCombo->addItem(QString(\"Max\"));\n    if (statsParams->GetMeanEnabled())\n        RemoveCalcCombo->addItem(QString(\"Mean\"));\n    else\n        NewCalcCombo->addItem(QString(\"Mean\"));\n    if (statsParams->GetMedianEnabled())\n        RemoveCalcCombo->addItem(QString(\"Median\"));\n    else\n        NewCalcCombo->addItem(QString(\"Median\"));\n    if (statsParams->GetStdDevEnabled())\n        RemoveCalcCombo->addItem(QString(\"StdDev\"));\n    else\n        NewCalcCombo->addItem(QString(\"StdDev\"));\n    NewCalcCombo->setCurrentIndex(0);\n    RemoveCalcCombo->setCurrentIndex(0);\n    NewCalcCombo->blockSignals(false);\n    RemoveCalcCombo->blockSignals(false);\n\n    // Update LOD, Refinement\n    MyFidelityWidget->Update(currentDmgr, _controlExec->GetParamsMgr(), statsParams);\n\n    // Update timesteps\n    MinTimestepSpinbox->blockSignals(true);\n    MinTimestepSpinbox->setMinimum(0);\n    MinTimestepSpinbox->setMaximum(currentDmgr->GetNumTimeSteps() - 1);\n    MinTimestepSpinbox->setValue(statsParams->GetCurrentTimestep());\n    MinTimestepSpinbox->blockSignals(false);\n\n    MaxTimestepSpinbox->blockSignals(true);\n    MaxTimestepSpinbox->setMinimum(0);\n    MaxTimestepSpinbox->setMaximum(currentDmgr->GetNumTimeSteps() - 1);\n    MaxTimestepSpinbox->setValue(statsParams->GetCurrentMaxTS());\n    MaxTimestepSpinbox->blockSignals(false);\n\n    bool has3DVar = false;\n    for (const auto &var : enabledVars) has3DVar |= 3 == currentDmgr->GetNumDimensions(var);\n\n    _controlExec->GetParamsMgr()->BeginSaveStateGroup(\"Update Box Dims\");\n    if (has3DVar) {\n        statsParams->GetBox()->SetPlanar(false);\n        statsParams->GetBox()->SetOrientation(Box::XYZ);\n    } else {\n        statsParams->GetBox()->SetPlanar(true);\n        statsParams->GetBox()->SetOrientation(Box::XY);\n    }\n    _controlExec->GetParamsMgr()->EndSaveStateGroup();\n\n    for (auto p : _pw) p->Update(statsParams, _controlExec->GetParamsMgr(), currentDmgr);\n}\n\nvoid Statistics::_updateStatsTable()\n{\n    // Initialize pointers\n    GUIStateParams *guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string     currentDatasetName = guiParams->GetStatsDatasetName();\n    VAssert(currentDatasetName != \"\");\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(currentDatasetName, StatisticsParams::GetClassType()));\n\n    // Update Statistics Table: header\n    VariablesTable->clear();    // this also deletes the items properly.\n    QStringList header;\n    header << \"Variable\"\n           << \"No. of Samples\";\n    if (statsParams->GetMinEnabled()) header << \"Min\";\n    if (statsParams->GetMaxEnabled()) header << \"Max\";\n    if (statsParams->GetMeanEnabled()) header << \"Mean\";\n    if (statsParams->GetMedianEnabled()) header << \"Median\";\n    if (statsParams->GetStdDevEnabled()) header << \"StdDev\";\n    VariablesTable->setColumnCount(header.size());\n    VariablesTable->setHorizontalHeaderLabels(header);\n    VariablesTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);\n\n    // Update Statistics Table: cells\n    QBrush                   brush(QColor(255, 0, 0));\n    std::vector<std::string> enabledVars = statsParams->GetAuxVariableNames();\n    VAssert(enabledVars.size() == _validStats.GetVariableCount());\n    VariablesTable->setRowCount(enabledVars.size());\n    int numberOfDigits = 3;\n    for (int row = 0; row < enabledVars.size(); row++) {\n        float m3[3]{0.0f, 0.0f, 0.0f}, median = 0.0f, stddev = 0.0f;\n        long  count = 0;\n        _validStats.GetCount(enabledVars[row], &count);\n        _validStats.Get3MStats(enabledVars[row], m3);\n        _validStats.GetMedian(enabledVars[row], &median);\n        _validStats.GetStddev(enabledVars[row], &stddev);\n\n        VariablesTable->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(enabledVars[row])));\n        if (count == -1) {\n            VariablesTable->setItem(row, 1, new QTableWidgetItem(QString(\"??\")));\n            VariablesTable->item(row, 1)->setForeground(brush);\n        } else\n            VariablesTable->setItem(row, 1, new QTableWidgetItem(QString::number(count)));\n\n        int column = 2;\n        if (statsParams->GetMinEnabled()) {\n            if (!std::isnan(m3[0])) {\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(m3[0], 'g', numberOfDigits)));\n            } else {\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString(\"??\")));\n                VariablesTable->item(row, column)->setForeground(brush);\n            }\n            column++;\n        }\n        if (statsParams->GetMaxEnabled()) {\n            if (!std::isnan(m3[1]))\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(m3[1], 'g', numberOfDigits)));\n            else {\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString(\"??\")));\n                VariablesTable->item(row, column)->setForeground(brush);\n            }\n            column++;\n        }\n        if (statsParams->GetMeanEnabled()) {\n            if (!std::isnan(m3[2]))\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(m3[2], 'g', numberOfDigits)));\n            else {\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString(\"??\")));\n                VariablesTable->item(row, column)->setForeground(brush);\n            }\n            column++;\n        }\n        if (statsParams->GetMedianEnabled()) {\n            if (!std::isnan(median))\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(median, 'g', numberOfDigits)));\n            else {\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString(\"??\")));\n                VariablesTable->item(row, column)->setForeground(brush);\n            }\n            column++;\n        }\n        if (statsParams->GetStdDevEnabled()) {\n            if (!std::isnan(stddev))\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString::number(stddev, 'g', numberOfDigits)));\n            else {\n                VariablesTable->setItem(row, column, new QTableWidgetItem(QString(\"??\")));\n                VariablesTable->item(row, column)->setForeground(brush);\n            }\n            column++;\n        }\n    }\n    for (int r = 0; r < VariablesTable->rowCount(); r++)\n        for (int c = 0; c < VariablesTable->columnCount(); c++) {\n            QTableWidgetItem *item = VariablesTable->item(r, c);\n            item->setFlags(Qt::NoItemFlags);\n        }\n\n    VariablesTable->update();\n    VariablesTable->repaint();\n    VariablesTable->viewport()->update();\n}\n\nvoid Statistics::showMe()\n{\n    open();\n    Update();\n}\n\nint Statistics::initControlExec(ControlExec *ce)\n{\n    if (ce != NULL)\n        _controlExec = ce;\n    else\n        return -1;\n\n    // Store the active dataset name\n    std::vector<std::string> dmNames = _controlExec->GetDataStatus()->GetDataMgrNames();\n    if (dmNames.empty())\n        return -1;\n    else {\n        GUIStateParams *guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n        std::string     dsName = guiParams->GetStatsDatasetName();\n        if (dsName == \"\" || dsName == \"NULL\")    // not initialized yet\n            guiParams->SetStatsDatasetName(dmNames[0]);\n    }\n\n    return 0;\n}\n\nbool Statistics::Connect()\n{\n    connect(NewVarCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_newVarChanged(int)));\n    connect(RemoveVarCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_removeVarChanged(int)));\n    connect(NewCalcCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_newCalcChanged(int)));\n    connect(RemoveCalcCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_removeCalcChanged(int)));\n    connect(MinTimestepSpinbox, SIGNAL(valueChanged(int)), this, SLOT(_minTSChanged(int)));\n    connect(MaxTimestepSpinbox, SIGNAL(valueChanged(int)), this, SLOT(_maxTSChanged(int)));\n    connect(UpdateButton, SIGNAL(clicked()), this, SLOT(_updateButtonClicked()));\n    connect(DataMgrCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(_dataSourceChanged(int)));\n    connect(UpdateCheckbox, SIGNAL(stateChanged(int)), this, SLOT(_autoUpdateClicked(int)));\n    connect(ExportButton, SIGNAL(clicked()), this, SLOT(_exportTextClicked()));\n    return true;\n}\n\nvoid Statistics::_autoUpdateClicked(int state)\n{\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n\n    if (state == 0)    // unchecked\n        statsParams->SetAutoUpdateEnabled(false);\n    else if (state == 2)    // checked\n    {\n        statsParams->SetAutoUpdateEnabled(true);\n        _updateButtonClicked();\n    } else {\n        std::cerr << \"Dont know what this state is!!!\" << std::endl;\n        // REPORT ERROR!!!\n    }\n}\n\nvoid Statistics::_dataSourceChanged(int index)\n{\n    std::string newDataSourceName = DataMgrCombo->itemText(index).toStdString();\n\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(newDataSourceName, StatisticsParams::GetClassType()));\n\n    guiParams->SetStatsDatasetName(newDataSourceName);\n\n    _validStats.currentDataSourceName = newDataSourceName;\n\n    // add variables to _validStats if there are any\n    _validStats.Clear();\n    std::vector<std::string> enabledVars = statsParams->GetAuxVariableNames();\n    for (int i = 0; i < enabledVars.size(); i++) _validStats.AddVariable(enabledVars[i]);\n}\n\nvoid Statistics::_geometryValueChanged()\n{\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n\n    _validStats.InvalidAll();\n\n    std::vector<double> myMin, myMax;\n    statsParams->GetBox()->GetExtents(myMin, myMax);\n    _validStats.SetCurrentExtents(myMin, myMax);\n\n    // Auto-update if enabled\n    if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked();\n}\n\nvoid Statistics::_updateButtonClicked()\n{\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n\n    for (int i = 0; i < _validStats.GetVariableCount(); i++) {\n        std::string varname = _validStats.GetVariableName(i);\n        long        count = 0;\n        _validStats.GetCount(varname, &count);\n        if (count == -1) {\n            _calc3M(varname);\n            _updateStatsTable();\n        }\n        float m3[3]{0.0f, 0.0f, 0.0f}, median = 0.0f, stddev = 0.0f;\n        _validStats.Get3MStats(varname, m3);\n        _validStats.GetMedian(varname, &median);\n        _validStats.GetStddev(varname, &stddev);\n        if ((statsParams->GetMinEnabled() || statsParams->GetMaxEnabled() || statsParams->GetMeanEnabled()) && std::isnan(m3[2])) {\n            _calc3M(varname);\n            _updateStatsTable();\n        }\n        if (statsParams->GetMedianEnabled() && std::isnan(median)) {\n            _calcMedian(varname);\n            _updateStatsTable();\n        }\n        if (statsParams->GetStdDevEnabled() && std::isnan(stddev)) {\n            _calcStddev(varname);\n            _updateStatsTable();\n        }\n    }\n}\n\nvoid Statistics::_minTSChanged(int val)\n{\n    VAssert(val >= 0);\n\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n\n    _validStats.currentTimeStep[0] = val;\n\n    // Add this minTS to parameter if different\n    if (val != statsParams->GetCurrentTimestep()) {\n        statsParams->SetCurrentTimestep(val);\n        _validStats.InvalidAll();\n\n        if (val > statsParams->GetCurrentMaxTS()) {\n            _validStats.currentTimeStep[1] = val;\n            statsParams->SetCurrentMaxTS(val);\n            MaxTimestepSpinbox->setValue(val);\n        }\n    }\n\n    // Auto-update if enabled\n    if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked();\n}\n\nvoid Statistics::_maxTSChanged(int val)\n{\n    VAssert(val >= 0);\n\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n\n    _validStats.currentTimeStep[1] = val;\n\n    // Add this maxTS to parameter if different\n    if (val != statsParams->GetCurrentMaxTS()) {\n        statsParams->SetCurrentMaxTS(val);\n        _validStats.InvalidAll();\n\n        if (val < statsParams->GetCurrentTimestep()) {\n            _validStats.currentTimeStep[0] = val;\n            statsParams->SetCurrentTimestep(val);\n            MinTimestepSpinbox->setValue(val);\n        }\n    }\n\n    // Auto-update if enabled\n    if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked();\n}\n\nvoid Statistics::_newCalcChanged(int index)\n{\n    VAssert(index > 0);\n\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n    std::string       calcName = NewCalcCombo->itemText(index).toStdString();\n\n    // Add this calculation to parameter\n    if (calcName == \"Min\")\n        statsParams->SetMinEnabled(true);\n    else if (calcName == \"Max\")\n        statsParams->SetMaxEnabled(true);\n    else if (calcName == \"Mean\")\n        statsParams->SetMeanEnabled(true);\n    else if (calcName == \"Median\")\n        statsParams->SetMedianEnabled(true);\n    else if (calcName == \"StdDev\")\n        statsParams->SetStdDevEnabled(true);\n    else {\n        // REPORT ERROR!!\n    }\n\n    // Auto-update if enabled\n    if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked();\n}\n\nvoid Statistics::_removeCalcChanged(int index)\n{\n    VAssert(index > 0);\n\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n    std::string       calcName = RemoveCalcCombo->itemText(index).toStdString();\n\n    // Remove this calculation from parameter\n    if (calcName == \"Min\")\n        statsParams->SetMinEnabled(false);\n    else if (calcName == \"Max\")\n        statsParams->SetMaxEnabled(false);\n    else if (calcName == \"Mean\")\n        statsParams->SetMeanEnabled(false);\n    else if (calcName == \"Median\")\n        statsParams->SetMedianEnabled(false);\n    else if (calcName == \"StdDev\")\n        statsParams->SetStdDevEnabled(false);\n    else {\n        // REPORT ERROR!!\n    }\n}\n\nvoid Statistics::_newVarChanged(int index)\n{\n    if (index <= 0) return;\n\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n    VAPoR::DataMgr *  currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName);\n    std::string       varName = NewVarCombo->itemText(index).toStdString();\n\n    // Test if the selected variable available at the specific time step,\n    //   compression level, etc.\n    if (!currentDmgr->VariableExists(statsParams->GetCurrentTimestep(), varName, statsParams->GetRefinementLevel(), statsParams->GetCompressionLevel())) {\n        MSG_WARN(\"Selected variable not available at this settings!\");\n        NewVarCombo->setCurrentIndex(0);\n        return;\n    } else {\n        // Add this variable to parameter\n        std::vector<std::string> vars = statsParams->GetAuxVariableNames();\n        vars.push_back(varName);\n        statsParams->SetAuxVariableNames(vars);\n\n        // Add this variable to _validStats\n        _validStats.AddVariable(varName);\n\n        // Auto-update if enabled\n        if (statsParams->GetAutoUpdateEnabled()) _updateButtonClicked();\n    }\n}\n\nvoid Statistics::_removeVarChanged(int index)\n{\n    VAssert(index > 0);\n\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n    std::string       varName = RemoveVarCombo->itemText(index).toStdString();\n\n    // Remove this variable from parameter\n    std::vector<std::string> vars = statsParams->GetAuxVariableNames();\n    int                      rmIdx = -1;\n    for (int i = 0; i < vars.size(); i++)\n        if (vars[i] == varName) {\n            rmIdx = i;\n            break;\n        }\n    VAssert(rmIdx != -1);\n    vars.erase(vars.begin() + rmIdx);\n    statsParams->SetAuxVariableNames(vars);\n\n    // Remove this variable from _validStats\n    _validStats.RemoveVariable(varName);\n}\n\nbool Statistics::_calc3M(std::string varname)\n{\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n    VAPoR::DataMgr *  currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName);\n\n    int minTS = statsParams->GetCurrentTimestep();\n    int maxTS = statsParams->GetCurrentMaxTS();\n    if (!currentDmgr->IsTimeVarying(varname)) maxTS = minTS;\n\n    CoordType minExtent = {0.0, 0.0, 0.0};\n    CoordType maxExtent = {0.0, 0.0, 0.0};\n    statsParams->GetBox()->GetExtents(minExtent, maxExtent);\n\n    float c = 0.0;\n    float sum = 0.0;\n    float min = std::numeric_limits<float>::max();\n    float max = -min;\n    long  count = 0;\n\n    for (int ts = minTS; ts <= maxTS; ts++) {\n        VAPoR::Grid *grid = currentDmgr->GetVariable(ts, varname, statsParams->GetRefinementLevel(), statsParams->GetCompressionLevel(), minExtent, maxExtent);\n        if (grid) {\n            Grid::ConstIterator endItr = grid->cend();\n            float               missingVal = grid->GetMissingValue();\n\n            for (Grid::ConstIterator it = grid->cbegin(minExtent, maxExtent); it != endItr; ++it) {\n                if (*it != missingVal) {\n                    float val = *it;\n                    min = min < val ? min : val;\n                    max = max > val ? max : val;\n                    float y = val - c;\n                    float t = sum + y;\n                    c = t - sum - y;\n                    sum = t;\n                    count++;\n                }\n            }\n\n            delete grid;    // delete the grid after using it!\n        }\n    }\n\n    if (count > 0) {\n        float m3[3] = {min, max, sum / (float)count};\n        _validStats.Add3MStats(varname, m3);\n    } else    // count == 0\n    {\n        // std::cerr << \"Error: Zero value got selected!!\" << std::endl;\n    }\n\n    _validStats.AddCount(varname, count);\n\n    return true;\n}\n\nbool Statistics::_calcMedian(std::string varname)\n{\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n    VAPoR::DataMgr *  currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName);\n\n    int minTS = statsParams->GetCurrentTimestep();\n    int maxTS = statsParams->GetCurrentMaxTS();\n    if (!currentDmgr->IsTimeVarying(varname)) maxTS = minTS;\n\n    CoordType minExtent = {0.0, 0.0, 0.0};\n    CoordType maxExtent = {0.0, 0.0, 0.0};\n    statsParams->GetBox()->GetExtents(minExtent, maxExtent);\n\n    std::vector<float> buffer;\n    for (int ts = minTS; ts <= maxTS; ts++) {\n        VAPoR::Grid *grid = currentDmgr->GetVariable(ts, varname, statsParams->GetRefinementLevel(), statsParams->GetCompressionLevel(), minExtent, maxExtent);\n        if (grid) {\n            Grid::ConstIterator endItr = grid->cend();\n            float               missingVal = grid->GetMissingValue();\n\n            for (Grid::ConstIterator it = grid->cbegin(minExtent, maxExtent); it != endItr; ++it) {\n                if (*it != missingVal) buffer.push_back(*it);\n            }\n        }\n    }\n\n    if (buffer.size() > 0) {\n        std::sort(buffer.begin(), buffer.end());\n        float median = buffer.at(buffer.size() / 2);\n        _validStats.AddMedian(varname, median);\n    } else {\n        // std::cerr << \"Error: Zero value got selected!!\" << std::endl;\n    }\n\n    _validStats.AddCount(varname, buffer.size());\n\n    return true;\n}\n\nbool Statistics::_calcStddev(std::string varname)\n{\n    // Initialize pointers\n    GUIStateParams *  guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n    std::string       dsName = guiParams->GetStatsDatasetName();\n    StatisticsParams *statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n    VAPoR::DataMgr *  currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName);\n\n    int minTS = statsParams->GetCurrentTimestep();\n    int maxTS = statsParams->GetCurrentMaxTS();\n    if (!currentDmgr->IsTimeVarying(varname)) maxTS = minTS;\n\n    CoordType minExtent = {0.0, 0.0, 0.0};\n    CoordType maxExtent = {0.0, 0.0, 0.0};\n    statsParams->GetBox()->GetExtents(minExtent, maxExtent);\n\n    float c = 0.0;\n    float sum = 0.0;\n    long  count = 0;\n    float m3[3];\n    _validStats.Get3MStats(varname, m3);\n    if (std::isnan(m3[2])) {\n        this->_calc3M(varname);\n        _validStats.Get3MStats(varname, m3);\n    }\n\n    for (int ts = minTS; ts <= maxTS; ts++) {\n        VAPoR::Grid *grid = currentDmgr->GetVariable(ts, varname, statsParams->GetRefinementLevel(), statsParams->GetCompressionLevel(), minExtent, maxExtent);\n        if (grid) {\n            Grid::ConstIterator endItr = grid->cend();\n            float               missingVal = grid->GetMissingValue();\n            for (Grid::ConstIterator it = grid->cbegin(minExtent, maxExtent); it != endItr; ++it) {\n                if (*it != missingVal) {\n                    float val = *it;\n                    float y = (val - m3[2]) * (val - m3[2]) - c;\n                    float t = sum + y;\n                    c = t - sum - y;\n                    sum = t;\n                    count++;\n                }\n            }\n        }\n    }\n\n    if (count > 0) {\n        _validStats.AddStddev(varname, std::sqrt(sum / (float)count));\n    } else {\n        // std::cerr << \"Error: Zero value got selected!!\" << std::endl;\n    }\n\n    _validStats.AddCount(varname, count);\n\n    return true;\n}\n\n// ValidStats class\n//\nint Statistics::ValidStats::_getVarIdx(std::string &varName)\n{\n    int idx = -1;\n    for (int i = 0; i < _variables.size(); i++) {\n        if (_variables[i] == varName) {\n            idx = i;\n            break;\n        }\n    }\n    return idx;\n}\n\nbool Statistics::ValidStats::AddVariable(std::string &newVar)\n{\n    if (newVar == \"\") return false;\n    if (_getVarIdx(newVar) != -1)    // this variable already exists.\n        return false;\n\n    _variables.push_back(newVar);\n    for (int i = 0; i < 5; i++) {\n        _values[i].push_back(std::nan(\"1\"));\n        VAssert(_values[i].size() == _variables.size());\n    }\n    _count.push_back(-1);\n    if (_count.size() != _variables.size()) std::cerr << \"_count.size() = \" << _count.size() << \",  _variables.size() = \" << _variables.size() << std::endl;\n    VAssert(_count.size() == _variables.size());\n    return true;\n}\n\nbool Statistics::ValidStats::RemoveVariable(std::string &varname)\n{\n    int rmIdx = _getVarIdx(varname);\n    if (rmIdx == -1)    // this variable doesn't exist.\n        return false;\n\n    _variables.erase(_variables.begin() + rmIdx);\n    for (int i = 0; i < 5; i++) {\n        _values[i].erase(_values[i].begin() + rmIdx);\n        VAssert(_values[i].size() == _variables.size());\n    }\n    _count.erase(_count.begin() + rmIdx);\n    VAssert(_count.size() == _variables.size());\n    return true;\n}\n\nbool Statistics::ValidStats::Add3MStats(std::string &varName, const float *input3M)\n{\n    int idx = _getVarIdx(varName);\n    if (idx == -1)    // This variable doesn't exist\n        return false;\n\n    for (int i = 0; i < 3; i++) { _values[i][idx] = input3M[i]; }\n    return true;\n}\n\nbool Statistics::ValidStats::AddMedian(std::string &varName, float inputMedian)\n{\n    int idx = _getVarIdx(varName);\n    if (idx == -1)    // This variable doesn't exist\n        return false;\n\n    _values[3][idx] = inputMedian;\n    return true;\n}\n\nbool Statistics::ValidStats::AddStddev(std::string &varName, float inputStddev)\n{\n    int idx = _getVarIdx(varName);\n    if (idx == -1)    // This variable doesn't exist\n        return false;\n\n    _values[4][idx] = inputStddev;\n    return true;\n}\n\nbool Statistics::ValidStats::AddCount(std::string &varName, long inputCount)\n{\n    int idx = _getVarIdx(varName);\n    if (idx == -1)    // This variable doesn't exist\n        return false;\n\n    _count[idx] = inputCount;\n    return true;\n}\n\nbool Statistics::ValidStats::Get3MStats(std::string &varName, float *output3M)\n{\n    int idx = _getVarIdx(varName);\n    if (idx == -1)    // This variable doesn't exist\n        return false;\n\n    for (int i = 0; i < 3; i++) { output3M[i] = _values[i][idx]; }\n    return true;\n}\n\nbool Statistics::ValidStats::GetMedian(std::string &varName, float *outputMedian)\n{\n    int idx = _getVarIdx(varName);\n    if (idx == -1)    // This variable doesn't exist\n        return false;\n\n    *outputMedian = _values[3][idx];\n    return true;\n}\n\nbool Statistics::ValidStats::GetStddev(std::string &varName, float *outputStddev)\n{\n    int idx = _getVarIdx(varName);\n    if (idx == -1)    // This variable doesn't exist\n        return false;\n\n    *outputStddev = _values[4][idx];\n    return true;\n}\n\nbool Statistics::ValidStats::GetCount(std::string &varName, long *outputCount)\n{\n    int idx = _getVarIdx(varName);\n    if (idx == -1)    // This variable doesn't exist\n        return false;\n\n    *outputCount = _count[idx];\n    return true;\n}\n\nbool Statistics::ValidStats::InvalidAll()\n{\n    for (int i = 0; i < 5; i++)\n        for (int j = 0; j < _values[i].size(); j++) _values[i][j] = std::nan(\"1\");\n    for (int i = 0; i < _count.size(); i++) _count[i] = -1;\n    return true;\n}\n\nbool Statistics::ValidStats::Clear()\n{\n    _variables.clear();\n    for (int i = 0; i < 5; i++) _values[i].clear();\n    _count.clear();\n    return true;\n}\n\nsize_t Statistics::ValidStats::GetVariableCount() { return _variables.size(); }\n\nstd::string Statistics::ValidStats::GetVariableName(int i)\n{\n    if (i < _variables.size())\n        return _variables.at(i);\n    else\n        return std::string(\"\");\n}\n\nbool Statistics::ValidStats::HaveSameParams(const VAPoR::StatisticsParams *rhs) const\n{\n    std::vector<double> myMin, myMax;\n    rhs->GetBox()->GetExtents(myMin, myMax);\n    std::vector<float> paramsMin, paramsMax;\n    for (int i = 0; i < myMin.size(); i++) {\n        paramsMin.push_back((float)myMin[i]);\n        paramsMax.push_back((float)myMax[i]);\n    }\n    return (_variables == rhs->GetAuxVariableNames() && currentExtentMin == paramsMin && currentExtentMax == paramsMax && currentTimeStep[0] == rhs->GetCurrentTimestep()\n            && currentTimeStep[1] == rhs->GetCurrentMaxTS() && currentLOD == rhs->GetCompressionLevel() && currentRefLev == rhs->GetRefinementLevel());\n}\n\nbool Statistics::ValidStats::UpdateMyParams(const VAPoR::StatisticsParams *rhs)\n{\n    this->Clear();\n    std::vector<std::string> enabledVars = rhs->GetAuxVariableNames();\n    for (int i = 0; i < enabledVars.size(); i++) this->AddVariable(enabledVars[i]);\n    std::vector<double> myMin, myMax;\n    rhs->GetBox()->GetExtents(myMin, myMax);\n    this->SetCurrentExtents(myMin, myMax);\n    currentTimeStep[0] = rhs->GetCurrentTimestep();\n    currentTimeStep[1] = rhs->GetCurrentMaxTS();\n    currentLOD = rhs->GetCompressionLevel();\n    currentRefLev = rhs->GetRefinementLevel();\n    return true;\n}\n\nbool Statistics::ValidStats::SetCurrentExtents(const std::vector<float> &min, const std::vector<float> &max)\n{\n    currentExtentMin.clear();\n    currentExtentMax.clear();\n    if (min.size() != max.size()) {\n        // REPORT ERROR!!\n        return false;\n    }\n    for (int i = 0; i < min.size(); i++) {\n        currentExtentMin.push_back(min[i]);\n        currentExtentMax.push_back(max[i]);\n    }\n\n    return true;\n}\n\nbool Statistics::ValidStats::SetCurrentExtents(const std::vector<double> &min, const std::vector<double> &max)\n{\n    std::vector<float> minf, maxf;\n    for (int i = 0; i < min.size(); i++) {\n        minf.push_back((float)min[i]);\n        maxf.push_back((float)max[i]);\n    }\n    return (this->SetCurrentExtents(minf, maxf));\n}\n\nvoid Statistics::_exportTextClicked()\n{\n    QString homePath = QDir::homePath();\n    homePath.append(\"/Variable_Statistics.txt\");\n    QString path = QDir::toNativeSeparators(homePath);\n    QString fName = QFileDialog::getSaveFileName(this, \"Select file to save statistics:\", path, \"Comma-separated values (*.txt)\");\n    if (!fName.isEmpty()) {\n        ofstream file;\n        file.open(fName.toStdString().c_str());\n        if (file.fail()) {\n            std::ostringstream ss;\n            ss << \"Failed to open file \";\n            ss << fName.toStdString();\n            ss << \" for writing.\";\n            return;\n        }\n\n        // Initialize pointers\n        GUIStateParams *         guiParams = dynamic_cast<GUIStateParams *>(_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType()));\n        std::string              dsName = guiParams->GetStatsDatasetName();\n        StatisticsParams *       statsParams = dynamic_cast<StatisticsParams *>(_controlExec->GetParamsMgr()->GetAppRenderParams(dsName, StatisticsParams::GetClassType()));\n        VAPoR::DataMgr *         currentDmgr = _controlExec->GetDataStatus()->GetDataMgr(dsName);\n        std::vector<std::string> availVars3D = currentDmgr->GetDataVarNames(3);\n        availVars3D.clear();    // This is a temporary change to hide all 3D variables.\n                                //   Removing this line could expose 3D variables again.\n\n        file << \"Data Source = \" << guiParams->GetStatsDatasetName() << endl << endl;\n        file << \"#Variable Statistics:\" << endl;\n        file << \"Variable_Name, No_of_Samples\";\n        if (statsParams->GetMinEnabled()) file << \", Min\";\n        if (statsParams->GetMaxEnabled()) file << \", Max\";\n        if (statsParams->GetMeanEnabled()) file << \", Mean\";\n        if (statsParams->GetMedianEnabled()) file << \", Median\";\n        if (statsParams->GetStdDevEnabled()) file << \", Stddev\";\n        file << endl;\n\n        bool has3DVar = false;\n        for (int i = 0; i < _validStats.GetVariableCount(); i++) {\n            std::string varname = _validStats.GetVariableName(i);\n            float       m3[3], median, stddev;\n            long        count;\n            _validStats.Get3MStats(varname, m3);\n            _validStats.GetMedian(varname, &median);\n            _validStats.GetStddev(varname, &stddev);\n            _validStats.GetCount(varname, &count);\n            file << varname << \", \" << count;\n            if (statsParams->GetMinEnabled()) file << \", \" << m3[0];\n            if (statsParams->GetMaxEnabled()) file << \", \" << m3[1];\n            if (statsParams->GetMeanEnabled()) file << \", \" << m3[2];\n            if (statsParams->GetMedianEnabled()) file << \", \" << median;\n            if (statsParams->GetStdDevEnabled()) file << \", \" << stddev;\n            file << endl;\n\n            for (int j = 0; j < availVars3D.size(); j++)\n                if (availVars3D[j] == varname) {\n                    has3DVar = true;\n                    break;\n                }\n        }\n\n        file << endl;\n\n        std::vector<double> myMin, myMax;\n        statsParams->GetBox()->GetExtents(myMin, myMax);\n\n        file << \"#Spatial Extents:\" << endl;\n        file << \"X min = \" << myMin[0] << endl;\n        file << \"X max = \" << myMax[0] << endl;\n        file << \"Y min = \" << myMin[1] << endl;\n        file << \"Y max = \" << myMax[1] << endl;\n        if (has3DVar) {\n            file << \"Z min = \" << myMin[2] << endl;\n            file << \"Z max = \" << myMax[2] << endl;\n        }\n        file << endl;\n\n        file << \"#Temporal Extents:\" << endl;\n        file << \"Minimum Timestep = \" << statsParams->GetCurrentTimestep() << endl;\n        file << \"Maximum Timestep = \" << statsParams->GetCurrentMaxTS() << endl;\n        file << endl;\n\n        file << \"#Compression Parameters:\" << endl;\n        file << \"Level of Detail  =  \" << MyFidelityWidget->GetCurrentLodString() << endl;\n        file << \"Refinement Level = \" << MyFidelityWidget->GetCurrentMultiresString() << endl;\n\n        file.close();\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/Statistics.h",
    "content": "//************************************************************************\n//                                                                    *\n//         Copyright (C)  2016                                      *\n//   University Corporation for Atmospheric Research                  *\n//         All Rights Reserved                                      *\n//                                                                    *\n//************************************************************************/\n//\n//  File:      Statistics.h\n//\n//  Author:  Samuel Li\n//        National Center for Atmospheric Research\n//        PO 3000, Boulder, Colorado\n//\n//  Date:     November 2017\n//\n//  Description:    Implements the Statistics class.\n//\n#ifdef WIN32\n    #pragma warning(disable : 4100)\n#endif\n\n#ifndef STATISTICS_H\n    #define STATISTICS_H\n\n    #include <qdialog.h>\n    #include <qwidget.h>\n    #include <vapor/DataMgr.h>\n    #include <vapor/Grid.h>\n    #include <vapor/ControlExecutive.h>\n    #include \"ui_statsWindow.h\"\n    #include <RangeCombos.h>\n    #include <StatisticsParams.h>\n    #include \"PWidgets.h\"\n    #include \"Updatable.h\"\n\nnamespace VAPoR {\nclass ParamsMgr;\nclass DataMgr;\n}    // namespace VAPoR\n\nclass Statistics : public QDialog, public Ui_StatsWindow, public Updatable {\n    Q_OBJECT\n\npublic:\n    Statistics(QWidget *parent);\n    ~Statistics();\n    int  initControlExec(VAPoR::ControlExec *ce);\n    void showMe();\n    void Update();\n\nprotected:\n    // Keeps the current variables shown and their statistical values.\n    // Invalid values are stored as std::nan(\"1\");\n    //\n    class ValidStats {\n    public:\n        bool        AddVariable(std::string &);\n        bool        RemoveVariable(std::string &);\n        size_t      GetVariableCount();\n        std::string GetVariableName(int i);\n\n        bool Add3MStats(std::string &, const float *);    // Min, Max, Mean\n        bool AddMedian(std::string &, float);\n        bool AddStddev(std::string &, float);\n        bool AddCount(std::string &, long);\n\n        // invalid values are represented as nan.\n        bool Get3MStats(std::string &, float *);\n        bool GetMedian(std::string &, float *);\n        bool GetStddev(std::string &, float *);\n        bool GetCount(std::string &, long *);\n\n        bool InvalidAll();    // keep existing variables, but set values to nan\n        bool Clear();         // clear all variables and values.\n\n        // keeps the current parameters, and make them public.\n        std::string        currentDataSourceName;\n        std::vector<float> currentExtentMin, currentExtentMax;\n        int                currentTimeStep[2], currentLOD, currentRefLev;\n\n        bool HaveSameParams(const VAPoR::StatisticsParams *rhs) const;\n        bool UpdateMyParams(const VAPoR::StatisticsParams *rhs);\n        bool SetCurrentExtents(const std::vector<float> &min, const std::vector<float> &max);\n        bool SetCurrentExtents(const std::vector<double> &min, const std::vector<double> &max);\n\n    private:\n        std::vector<std::string> _variables;\n        std::vector<float>       _values[5];    // 0: min\n                                                // 1: max\n                                                // 2: mean\n                                                // 3: median\n                                                // 4: stddev\n        std::vector<long> _count;               // number of samples\n\n        int _getVarIdx(std::string &);    // -1: not exist\n                                          // >=0: a valid index\n    };                                    // finish class ValidStats\n\n    bool Connect();    // connect slots\n\nprivate slots:\n    void _newVarChanged(int);\n    void _removeVarChanged(int);\n    void _newCalcChanged(int);\n    void _removeCalcChanged(int);\n    void _minTSChanged(int);\n    void _maxTSChanged(int);\n    void _updateButtonClicked();\n    void _geometryValueChanged();\n    void _dataSourceChanged(int);\n    void _autoUpdateClicked(int);\n    void _exportTextClicked();\n\nprivate:\n    ValidStats             _validStats;\n    VAPoR::ControlExec *   _controlExec;\n    std::vector<PWidget *> _pw;\n\n    void _updateStatsTable();\n\n    // calculations should put results in _validStats directly.\n    bool _calc3M(std::string);    // min, max, mean\n    bool _calcMedian(std::string);\n    bool _calcStddev(std::string);\n};\n#endif\n"
  },
  {
    "path": "apps/vaporgui/StatisticsParams.cpp",
    "content": "//************************************************************************\n//                                  *\n//           Copyright (C)  2014                *\n//   University Corporation for Atmospheric Research            *\n//           All Rights Reserved                *\n//                                  *\n//************************************************************************/\n//\n//  File:       StatisticsParams.cpp\n//\n//  Author:     Samuel Li\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:       November 2017\n//\n//  Description:    Implements the StatisticsParams class.\n//\n#include <iostream>\n#include <sstream>\n#include <string>\n#include <cstring>\n#include <string>\n#include \"vapor/VAssert.h\"\n#include <StatisticsParams.h>\n\nusing namespace VAPoR;\n\nconst string StatisticsParams::_maxTSTag = \"MaxTS\";\nconst string StatisticsParams::_autoUpdateTag = \"AutoUpdate\";\nconst string StatisticsParams::_minEnabledTag = \"MinEnabled\";\nconst string StatisticsParams::_maxEnabledTag = \"MaxEnabled\";\nconst string StatisticsParams::_meanEnabledTag = \"MeanEnabled\";\nconst string StatisticsParams::_medianEnabledTag = \"MedianEnabled\";\nconst string StatisticsParams::_stdDevEnabledTag = \"StdDevEnabled\";\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<StatisticsParams> registrar(StatisticsParams::GetClassType());\n\nStatisticsParams::StatisticsParams(DataMgr *dmgr, ParamsBase::StateSave *ssave) : RenderParams(dmgr, ssave, StatisticsParams::GetClassType()) {}\n\nStatisticsParams::StatisticsParams(DataMgr *dmgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dmgr, ssave, node)\n{\n    // If node isn't tagged correctly we correct the tag and reinitialize from scratch;\n    //\n    if (node->GetTag() != StatisticsParams::GetClassType()) { node->SetTag(StatisticsParams::GetClassType()); }\n}\n\nStatisticsParams::~StatisticsParams() { MyBase::SetDiagMsg(\"StatisticsParams::~StatisticsParams() this=%p\", this); }\n\nbool StatisticsParams::GetAutoUpdateEnabled() { return (GetValueLong(_autoUpdateTag, (long)false)); }\n\nvoid StatisticsParams::SetAutoUpdateEnabled(bool val) { SetValueLong(_autoUpdateTag, \"if we want stats auto-update\", (long)val); }\n\nint StatisticsParams::GetCurrentMaxTS() const { return (int)(GetValueDouble(_maxTSTag, 0.0)); }\n\nvoid StatisticsParams::SetCurrentMaxTS(int ts) { SetValueDouble(_maxTSTag, \"Maximum selected timestep for statistics\", (double)ts); }\n\nbool StatisticsParams::GetMinEnabled() { return GetValueLong(_minEnabledTag, (long)true); }\n\nvoid StatisticsParams::SetMinEnabled(bool state) { SetValueLong(_minEnabledTag, \"Minimum statistic calculation\", (long)state); }\n\nbool StatisticsParams::GetMaxEnabled() { return GetValueLong(_maxEnabledTag, (long)true); }\n\nvoid StatisticsParams::SetMaxEnabled(bool state) { SetValueLong(_maxEnabledTag, \"Maximum statistic calculation\", (long)state); }\n\nbool StatisticsParams::GetMeanEnabled() { return GetValueLong(_meanEnabledTag, (long)true); }\n\nvoid StatisticsParams::SetMeanEnabled(bool state) { SetValueLong(_meanEnabledTag, \"Mean statistic calculation\", (long)state); }\n\nbool StatisticsParams::GetMedianEnabled() { return GetValueLong(_medianEnabledTag, (long)false); }\n\nvoid StatisticsParams::SetMedianEnabled(bool state) { SetValueLong(_medianEnabledTag, \"Median statistic calculation\", (long)state); }\n\nbool StatisticsParams::GetStdDevEnabled() { return GetValueLong(_stdDevEnabledTag, (long)false); }\n\nvoid StatisticsParams::SetStdDevEnabled(bool state) { SetValueLong(_stdDevEnabledTag, \"Standard deviation statistic calculation\", (long)state); }\n"
  },
  {
    "path": "apps/vaporgui/StatisticsParams.h",
    "content": "//************************************************************************\n//                                                                       *\n//           Copyright (C)  2004                                         *\n//     University Corporation for Atmospheric Research                   *\n//           All Rights Reserved                                         *\n//                                                                       *\n//************************************************************************\n//\n//  File:       StatisticsParams.h\n//\n//  Author:     Samuel Li\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:       November 2017\n//\n//  Description:    Defines the StatisticsParams class.\n//\n\n#ifndef STATISTICSPARAMS_H\n#define STATISTICSPARAMS_H\n\n#include <vapor/RenderParams.h>\n\nnamespace VAPoR {\n\nclass StatisticsParams : public RenderParams {\npublic:\n    StatisticsParams(DataMgr *dmgr, ParamsBase::StateSave *ssave);\n    StatisticsParams(DataMgr *dmgr, ParamsBase::StateSave *ssave, XmlNode *node);\n    ~StatisticsParams();\n\n    bool GetAutoUpdateEnabled();\n    void SetAutoUpdateEnabled(bool state);\n\n    // Note: we'll use the Get/SetCurrentTimestep() from RendererParams to\n    // represent the min timestep, MinTS, so we only need to keep track of MaxTS.\n    int  GetCurrentMaxTS() const;\n    void SetCurrentMaxTS(int ts);\n\n    bool GetMinEnabled();\n    void SetMinEnabled(bool state);\n\n    bool GetMaxEnabled();\n    void SetMaxEnabled(bool state);\n\n    bool GetMeanEnabled();\n    void SetMeanEnabled(bool state);\n\n    bool GetMedianEnabled();\n    void SetMedianEnabled(bool state);\n\n    bool GetStdDevEnabled();\n    void SetStdDevEnabled(bool state);\n\n    static string  GetClassType() { return (\"StatisticsParams\"); }\n    virtual size_t GetRenderDim() const override { return (0); }\n    virtual string GetActualColorMapVariableName() const override { return \"\"; }\n\nprivate:\n    static const string _maxTSTag;\n    static const string _autoUpdateTag;\n    static const string _minEnabledTag;\n    static const string _maxEnabledTag;\n    static const string _meanEnabledTag;\n    static const string _medianEnabledTag;\n    static const string _stdDevEnabledTag;\n};\n\n};    // End namespace VAPoR\n#endif\n"
  },
  {
    "path": "apps/vaporgui/TFColorInfoWidget.cpp",
    "content": "#include \"TFColorInfoWidget.h\"\n#include <QBoxLayout>\n#include <QLabel>\n#include <QPainter>\n#include <QDoubleValidator>\n#include <vapor/RenderParams.h>\n#include \"VLineItem.h\"\n\nTFColorInfoWidget::TFColorInfoWidget(const std::string &variableNameTag) : TFInfoWidget(variableNameTag)\n{\n    ((QBoxLayout *)layout())->addWidget(new VLineItem(\"Color\", _colorEdit = new QColorWidget));\n\n    connect(_colorEdit, SIGNAL(colorChanged(QColor)), this, SLOT(colorEditChanged()));\n}\n\nvoid TFColorInfoWidget::DeselectControlPoint()\n{\n    TFInfoWidget::DeselectControlPoint();\n    _colorEdit->setColor(Qt::gray);\n}\n\nvoid TFColorInfoWidget::SetColor(const QColor &color) { _colorEdit->setColor(color); }\n\nvoid TFColorInfoWidget::SetControlPoint(float value, const QColor &color)\n{\n    this->setEnabled(true);\n    SetNormalizedValue(value);\n    SetColor(color);\n}\n\nvoid TFColorInfoWidget::controlPointChanged() { emit ControlPointChanged(_value, _colorEdit->getColor()); }\n\nvoid TFColorInfoWidget::colorEditChanged() { controlPointChanged(); }\n"
  },
  {
    "path": "apps/vaporgui/TFColorInfoWidget.h",
    "content": "#pragma once\n\n#include \"TFInfoWidget.h\"\n#include <QLineEdit>\n#include \"QColorWidget.h\"\n\nnamespace VAPoR {\nclass RenderParams;\n}\n\nclass TFColorInfoWidget : public TFInfoWidget {\n    Q_OBJECT\n\npublic:\n    TFColorInfoWidget(const std::string &variableNameTag);\n    void SetColor(const QColor &color);\n\nprotected:\n    void controlPointChanged();\n\nprivate:\n    QColorWidget *_colorEdit;\n\nsignals:\n    void ControlPointChanged(float value, QColor color);\n\npublic slots:\n    void SetControlPoint(float value, const QColor &color);\n    void DeselectControlPoint();\n\nprivate slots:\n    void colorEditChanged();\n};\n"
  },
  {
    "path": "apps/vaporgui/TFColorWidget.cpp",
    "content": "#include \"TFColorWidget.h\"\n#include <QPainter>\n#include <QMouseEvent>\n#include <vapor/RenderParams.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/ResourcePath.h>\n#include <vapor/FileUtils.h>\n#include \"TFColorInfoWidget.h\"\n#include \"TFUtils.h\"\n#include \"QPaintUtils.h\"\n#include \"ParamsMenuItems.h\"\n\nusing namespace VAPoR;\nusing glm::vec2;\nusing std::vector;\n\nstatic vec2 qvec2(const QPoint &qp) { return vec2(qp.x(), qp.y()); }\n\nTFColorMap::TFColorMap(const std::string &variableNameTag, TFMapWidget *parent)\n: TFMap(variableNameTag, parent)\n{\n    _colorInterpolationMenu = new ParamsDropdownMenuItem(\n        this, VAPoR::ColorMap::_interpTypeTag, {\"Linear HSV\", \"Linear RGB\", \"Linear LAB\", \"Linear LCH\", \"Discrete\", \"Diverging\"},\n        {TFInterpolator::linear, TFInterpolator::linearRGB, TFInterpolator::linearLAB, TFInterpolator::linearLCH, TFInterpolator::discrete, TFInterpolator::diverging}, \"Color Interpolation\");\n    _colorInterpolationWhitepointAction = new ParamsCheckboxMenuItem(this, ColorMap::_useWhitespaceTag, \"Add Whitespace\");\n    _colorInterpolationMenu->menu()->addAction(_colorInterpolationWhitepointAction);\n}\n\nQSize TFColorMap::minimumSizeHint() const { return QSize(100, 30); }\n\nQSizePolicy TFColorMap::GetSizePolicy() const { return QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); }\n\nvoid TFColorMap::LostFocus() { DeselectControlPoint(); }\n\n#define PROPERTY_INDEX (\"index\")\n#define PROPERTY_VALUE (\"value\")\n\nvoid TFColorMap::PopulateContextMenu(QMenu *menu, const glm::vec2 &p)\n{\n    int selected = findSelectedControlPoint(p);\n\n    if (selected != -1)\n        menu->addAction(\"Delete control point\", this, SLOT(menuDeleteSelectedControlPoint()))->setProperty(PROPERTY_INDEX, selected);\n    else\n        menu->addAction(\"Add control point\", this, SLOT(menuAddControlPoint()))->setProperty(PROPERTY_VALUE, QVariant(valueForControlX(p.x)));\n}\n\nvoid TFColorMap::PopulateSettingsMenu(QMenu *menu) const\n{\n    menu->addAction(_colorInterpolationMenu);\n    menu->addAction(\"Reverse Colormap\", this, SLOT(menuReverse()));\n    menu->addSeparator();\n    menu->addAction(\"Save Colormap\", this, SLOT(menuSave()));\n    menu->addAction(\"Load Colormap\", this, SLOT(menuLoad()));\n\n    QMenu *builtinColormapMenu = menu->addMenu(\"Load Built-In Colormap\");\n    string builtinPath = GetSharePath(\"palettes\");\n\n    populateBuiltinColormapMenu(builtinColormapMenu, builtinPath);\n}\n\nvoid TFColorMap::populateBuiltinColormapMenu(QMenu *menu, const std::string &builtinPath) const\n{\n    auto fileNames = FileUtils::ListFiles(builtinPath);\n    std::sort(fileNames.begin(), fileNames.end());\n\n    for (int i = 0; i < fileNames.size(); i++) {\n        string path = FileUtils::JoinPaths({builtinPath, fileNames[i]});\n\n        if (FileUtils::IsDirectory(path)) populateBuiltinColormapMenu(menu->addMenu(QString::fromStdString(fileNames[i])), path);\n    }\n\n    for (int i = 0; i < fileNames.size(); i++) {\n        string path = FileUtils::JoinPaths({builtinPath, fileNames[i]});\n\n        if (FileUtils::Extension(path) != \"tf3\") continue;\n\n        QAction *item = new ColorMapMenuItem(path);\n        connect(item, SIGNAL(triggered(std::string)), this, SLOT(menuLoadBuiltin(std::string)));\n        menu->addAction(item);\n    }\n}\n\nvoid TFColorMap::paramsUpdate()\n{\n    const auto cm = getColormap();\n    _colorInterpolationMenu->Update(cm);\n    _colorInterpolationWhitepointAction->Update(cm);\n    _colorInterpolationWhitepointAction->setEnabled(cm->GetInterpType() == TFInterpolator::diverging);\n    updateImage();\n    _paramsNormalizedControlPoints.resize(cm->numControlPoints());\n    for (int i = 0; i < _paramsNormalizedControlPoints.size(); i++)\n        _paramsNormalizedControlPoints[i] = cm->controlPointValueNormalized(i);\n    update();\n\n    if (_selectedId > -1) UpdateInfo(getColormap()->controlPointValueNormalized(_selectedId), VColorToQColor(getColormap()->controlPointColor(_selectedId)));\n}\n\nvoid TFColorMap::updateImage()\n{\n    if (width() <= 0) return;\n    ColorMap *cm = getRenderParams()->GetMapperFunc(getVariableName())->GetColorMap();\n\n    QMargins       padding = GetPadding();\n    int            nSamples = width() - (padding.left() + padding.right());\n    nSamples = std::max(nSamples, 256);\n    _imageData.resize(nSamples * 3);\n    float          rgb[3];\n    for (int i = 0; i < nSamples; i++) {\n        cm->colorNormalized(i / (float)nSamples).toRGB(rgb);\n        _imageData[i * 3 + 0] = rgb[0] * 255;\n        _imageData[i * 3 + 1] = rgb[1] * 255;\n        _imageData[i * 3 + 2] = rgb[2] * 255;\n    }\n    _image = QImage(_imageData.data(), nSamples, 1, QImage::Format::Format_RGB888);\n}\n\nTFInfoWidget *TFColorMap::createInfoWidget()\n{\n    TFColorInfoWidget *info = new TFColorInfoWidget(getVariableNameTag());\n\n    connect(this, SIGNAL(ControlPointDeselected()), info, SLOT(DeselectControlPoint()));\n    connect(this, SIGNAL(UpdateInfo(float, QColor)), info, SLOT(SetControlPoint(float, QColor)));\n    connect(info, SIGNAL(ControlPointChanged(float, QColor)), this, SLOT(UpdateFromInfo(float, QColor)));\n\n    return info;\n}\n\n#define CONTROL_POINT_RADIUS (4.0f)\n#define PADDING              (CONTROL_POINT_RADIUS + 1.0f)\n\nvoid TFColorMap::_paintEvent(QPainter &p)\n{\n    //     243 245 249\n    p.fillRect(rect(), Qt::lightGray);\n    QPaintUtils::BoxDropShadow(p, paddedRect(), 10, QColor(0, 0, 0, 120));\n\n    p.drawImage(paddedRect(), _image);\n\n    for (int i = 0; i < _paramsNormalizedControlPoints.size(); i++) { drawControl(p, controlQPositionForValue(_paramsNormalizedControlPoints[i]), i == _selectedId); }\n}\n\nvoid TFColorMap::mousePressEvent(QMouseEvent *event)\n{\n    emit      Activated(this);\n    ColorMap *cm = getColormap();\n    vec2      mouse(event->pos().x(), event->pos().y());\n\n    for (int i = 0; i < cm->numControlPoints(); i++) {\n        float value = cm->controlPointValueNormalized(i);\n        if (controlPointContainsPixel(value, mouse)) {\n            _isDraggingControl = true;\n            _draggingControlID = i;\n            selectControlPoint(i);\n            update();\n            _dragOffset = controlPositionForValue(value) - mouse;\n            BeginSaveStateGroup(getParamsMgr(), \"Colormap modification\");\n            return;\n        }\n    }\n\n    DeselectControlPoint();\n    event->ignore();\n    update();\n}\n\nvoid TFColorMap::mouseReleaseEvent(QMouseEvent *event)\n{\n    if (_isDraggingControl)\n        EndSaveStateGroup(getParamsMgr());\n    else\n        event->ignore();\n    _isDraggingControl = false;\n}\n\nvoid TFColorMap::mouseMoveEvent(QMouseEvent *event)\n{\n    vec2 mouse = qvec2(event->pos());\n\n    if (_isDraggingControl) {\n        float newVal = glm::clamp(valueForControlX(mouse.x + _dragOffset.x), 0.f, 1.f);\n\n        moveControlPoint(&_draggingControlID, newVal);\n        selectControlPoint(_draggingControlID);\n        updateImage();\n        paramsUpdate();\n        getParamsMgr()->IntermediateChange();\n    } else {\n        event->ignore();\n    }\n}\n\nvoid TFColorMap::mouseDoubleClickEvent(QMouseEvent *event)\n{\n    vec2 mouse = qvec2(event->pos());\n    int  selectedId = findSelectedControlPoint(mouse);\n    if (selectedId >= 0) {\n        deleteControlPoint(selectedId);\n        return;\n    }\n\n    float newVal = valueForControlX(mouse.x);\n    if (newVal >= 0 && newVal <= 1) addControlPoint(newVal);\n}\n\nvoid TFColorMap::moveControlPoint(int *index, float value, const VAPoR::ColorMap::Color &c)\n{\n    ColorMap *cm = getColormap();\n\n    cm->deleteControlPoint(*index);\n    *index = cm->addNormControlPoint(value, c);\n}\n\nvoid TFColorMap::moveControlPoint(int *index, float value)\n{\n    ColorMap *      cm = getColormap();\n    ColorMap::Color c = cm->controlPointColor(_draggingControlID);\n    moveControlPoint(index, value, c);\n}\n\nvoid TFColorMap::deleteControlPoint(int index)\n{\n    ColorMap *cm = getColormap();\n    if (cm->numControlPoints() == 1) return;\n    if (index == _selectedId)\n        DeselectControlPoint();\n    else if (index < _selectedId)\n        _selectedId--;\n    cm->deleteControlPoint(index);\n    update();\n}\n\nvoid TFColorMap::addControlPoint(float value)\n{\n    selectControlPoint(getColormap()->addNormControlPointAt(value));\n    update();\n}\n\nColorMap *TFColorMap::getColormap() const { return getRenderParams()->GetMapperFunc(getVariableName())->GetColorMap(); }\n\nvoid TFColorMap::selectControlPoint(int index)\n{\n    _selectedId = index;\n    ColorMap *cm = getColormap();\n\n    float           value = cm->controlPointValueNormalized(index);\n    ColorMap::Color vColor = cm->controlPointColor(index);\n\n    UpdateInfo(value, VColorToQColor(vColor));\n}\n\nvoid TFColorMap::DeselectControlPoint()\n{\n    _selectedId = -1;\n    emit ControlPointDeselected();\n    update();\n}\n\nvoid TFColorMap::UpdateFromInfo(float value, QColor color) { moveControlPoint(&_selectedId, value, QColorToVColor(color)); }\n\nvoid TFColorMap::menuDeleteSelectedControlPoint()\n{\n    emit            Activated(this);\n    const ColorMap *cm = getColormap();\n    QVariant        valueVariant = sender()->property(PROPERTY_INDEX);\n    if (valueVariant.isValid()) {\n        int index = valueVariant.toInt();\n        if (index >= 0 && index < cm->numControlPoints()) deleteControlPoint(index);\n    }\n}\n\nvoid TFColorMap::menuAddControlPoint()\n{\n    emit     Activated(this);\n    QVariant value = sender()->property(PROPERTY_VALUE);\n    if (value.isValid()) addControlPoint(value.toFloat());\n}\n\nvoid TFColorMap::menuLoad()\n{\n    RenderParams *rp = getRenderParams();\n    if (!rp) return;\n    TFUtils::LoadColormap(getParamsMgr(), rp->GetMapperFunc(getVariableName()));\n}\n\nvoid TFColorMap::menuSave()\n{\n    RenderParams *rp = getRenderParams();\n    if (!rp) return;\n    TFUtils::SaveTransferFunction(getParamsMgr(), rp->GetMapperFunc(getVariableName()));\n}\n\nvoid TFColorMap::menuLoadBuiltin(std::string path)\n{\n    RenderParams *rp = getRenderParams();\n    if (!rp) return;\n    TFUtils::LoadColormap(rp->GetMapperFunc(getVariableName()), path);\n}\n\nvoid TFColorMap::menuReverse()\n{\n    RenderParams *rp = getRenderParams();\n    if (!rp) return;\n    MapperFunction *tf = rp->GetMapperFunc(getVariableName());\n    ColorMap *      cm = tf->GetColorMap();\n\n    cm->Reverse();\n}\n\nint TFColorMap::findSelectedControlPoint(const glm::vec2 &mouse) const\n{\n    const ColorMap *cm = getColormap();\n    const int       n = cm->numControlPoints();\n    for (int i = 0; i < n; i++)\n        if (controlPointContainsPixel(cm->controlPointValueNormalized(i), mouse)) return i;\n    return -1;\n}\n\nbool TFColorMap::controlPointContainsPixel(float cp, const vec2 &pixel) const { return glm::distance(pixel, controlPositionForValue(cp)) <= GetControlPointRadius(); }\n\nQPointF TFColorMap::controlQPositionForValue(float value) const\n{\n    const vec2 v = controlPositionForValue(value);\n    return QPointF(v.x, v.y);\n}\n\nglm::vec2 TFColorMap::controlPositionForValue(float value) const { return vec2(controlXForValue(value), height() / 2.f); }\n\nfloat TFColorMap::controlXForValue(float value) const { return NDCToPixel(vec2(value, 0.f)).x; }\n\nfloat TFColorMap::valueForControlX(float position) const { return PixelToNDC(vec2(position, 0.f)).x; }\n\nQColor TFColorMap::VColorToQColor(const ColorMap::Color &c)\n{\n    float rgb[3];\n    c.toRGB(rgb);\n    return QColor(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);\n}\n\nColorMap::Color TFColorMap::QColorToVColor(const QColor &c)\n{\n    double h, s, v;\n    c.getHsvF(&h, &s, &v);\n    return ColorMap::Color(h, s, v);\n}\n\n#include <vapor/STLUtils.h>\n#include <QPushButton>\n\nstd::map<std::string, QIcon> ColorMapMenuItem::icons;\n\nQIcon ColorMapMenuItem::getCachedIcon(const std::string &path)\n{\n    auto it = icons.find(path);\n    if (it != icons.end()) return it->second;\n\n    ParamsBase::StateSave stateSave;\n    MapperFunction        mf(&stateSave);\n\n    mf.LoadColormapFromFile(path);\n    ColorMap *cm = mf.GetColorMap();\n\n    QSize          size = getIconSize();\n    int            nSamples = size.width();\n    unsigned char *buf = new unsigned char[nSamples * 3];\n    float          rgb[3];\n    for (int i = 0; i < nSamples; i++) {\n        cm->colorNormalized(i / (float)nSamples).toRGB(rgb);\n        buf[i * 3 + 0] = rgb[0] * 255;\n        buf[i * 3 + 1] = rgb[1] * 255;\n        buf[i * 3 + 2] = rgb[2] * 255;\n    }\n    QImage image(buf, nSamples, 1, QImage::Format::Format_RGB888);\n    icons[path] = QIcon(QPixmap::fromImage(image).scaled(size.width(), size.height()));\n\n    delete[] buf;\n    return icons[path];\n}\n\nQSize ColorMapMenuItem::getIconSize() { return QSize(50, 15); }\n\nQSize ColorMapMenuItem::getIconPadding() { return QSize(10, 10); }\n\nColorMapMenuItem::ColorMapMenuItem(const std::string &path) : QWidgetAction(nullptr), _path(path)\n{\n    QPushButton *button = new QPushButton;\n    setDefaultWidget(button);\n\n    button->setIcon(getCachedIcon(path));\n    button->setFixedSize(getIconSize() + getIconPadding());\n    button->installEventFilter(this);\n\n    string name = STLUtils::Split(FileUtils::Basename(path), \".\")[0];\n    button->setToolTip(QString::fromStdString(name));\n\n    button->setStyleSheet(R\"(\n                          QPushButton {\n                              icon-size: 50px 15px;\n                          padding: 0px;\n                          margin: 0px;\n                          background: none;\n                          border: none;\n                          }\n                          QPushButton::hover {\n                          background: #aaa;\n                          }\n                          )\");\n}\n\n// Manually riggering an action does not close the menu so it has to be done manually.\nvoid ColorMapMenuItem::CloseMenu(QAction *action)\n{\n    if (!action) return;\n\n    QList<QWidget *> menus = action->associatedWidgets();\n\n    for (QWidget *widget : menus) {\n        QMenu *menu = dynamic_cast<QMenu *>(widget);\n        if (!menu) continue;\n        if (menu->isHidden()) continue;\n\n        menu->hide();\n        CloseMenu(menu->menuAction());\n    }\n}\n\nbool ColorMapMenuItem::eventFilter(QObject *obj, QEvent *event)\n{\n    if (event->type() == QEvent::MouseButtonRelease) {\n        trigger();\n        emit triggered(_path);\n        CloseMenu(this);\n        return true;\n    }\n    return QObject::eventFilter(obj, event);\n}\n"
  },
  {
    "path": "apps/vaporgui/TFColorWidget.h",
    "content": "#pragma once\n\n#include \"TFMapWidget.h\"\n#include <vapor/RenderParams.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/VAssert.h>\n#include <glm/glm.hpp>\n\nclass TFColorInfoWidget;\nclass ParamsDropdownMenuItem;\nclass ParamsCheckboxMenuItem;\n\nclass TFColorMap : public TFMap {\n    Q_OBJECT\n\npublic:\n    TFColorMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr);\n\n    QSize minimumSizeHint() const override;\n    QSizePolicy GetSizePolicy() const override;\n    void  LostFocus() override;\n    void  PopulateContextMenu(QMenu *menu, const glm::vec2 &p) override;\n    void  PopulateSettingsMenu(QMenu *menu) const override;\n\nprivate:\n    void populateBuiltinColormapMenu(QMenu *menu, const std::string &builtinPath) const;\n\nprotected:\n    void          paramsUpdate() override;\n    TFInfoWidget *createInfoWidget() override;\n    void          _paintEvent(QPainter &p) override;\n    void          mousePressEvent(QMouseEvent *event) override;\n    void          mouseReleaseEvent(QMouseEvent *event) override;\n    void          mouseMoveEvent(QMouseEvent *event) override;\n    void          mouseDoubleClickEvent(QMouseEvent *event) override;\n\nprivate:\n    ParamsDropdownMenuItem *_colorInterpolationMenu;\n    ParamsCheckboxMenuItem *_colorInterpolationWhitepointAction;\n    bool                    _isDraggingControl = false;\n    int                     _draggingControlID;\n    int                     _selectedId = -1;\n    glm::vec2               _dragOffset;\n    glm::vec2               m;\n\n    QImage _image;\n    vector<unsigned char> _imageData;\n    std::vector<float> _paramsNormalizedControlPoints;\n\n    void updateImage();\n\n    bool controlPointContainsPixel(const glm::vec2 &cp, const glm::vec2 &pixel) const;\n\n    void             moveControlPoint(int *index, float value, const VAPoR::ColorMap::Color &c);\n    void             moveControlPoint(int *index, float value);\n    void             deleteControlPoint(int index);\n    void             addControlPoint(float value);\n    VAPoR::ColorMap *getColormap() const;\n    void             selectControlPoint(int index);\n    int              findSelectedControlPoint(const glm::vec2 &mouse) const;\n    bool             controlPointContainsPixel(float cp, const glm::vec2 &pixel) const;\n    QPointF          controlQPositionForValue(float value) const;\n    glm::vec2        controlPositionForValue(float value) const;\n    float            controlXForValue(float value) const;\n    float            valueForControlX(float position) const;\n\n    static QColor                 VColorToQColor(const VAPoR::ColorMap::Color &c);\n    static VAPoR::ColorMap::Color QColorToVColor(const QColor &c);\n\nsignals:\n    void ControlPointDeselected();\n    void UpdateInfo(float value, QColor color);\n\npublic slots:\n    void DeselectControlPoint();\n    void UpdateFromInfo(float value, QColor color);\n\nprivate slots:\n    void menuDeleteSelectedControlPoint();\n    void menuAddControlPoint();\n    void menuLoad();\n    void menuSave();\n    void menuLoadBuiltin(std::string path);\n    void menuReverse();\n};\n\nclass TFColorWidget : public TFMapWidget {\n    Q_OBJECT\npublic:\n    TFColorWidget(const std::string &variableNameTag) : TFMapWidget(new TFColorMap(variableNameTag, this)) {}\n};\n\n#include <QWidgetAction>\nclass ColorMapMenuItem : public QWidgetAction {\n    Q_OBJECT\n\n    static std::map<std::string, QIcon> icons;\n    static QIcon                        getCachedIcon(const std::string &path);\n    static QSize                        getIconSize();\n    static QSize                        getIconPadding();\n\n    const std::string _path;\n\npublic:\n    ColorMapMenuItem(const std::string &path);\n    static void CloseMenu(QAction *action);\n\nprotected:\n    bool eventFilter(QObject *obj, QEvent *event);\n\nsignals:\n    void triggered(std::string colormapPath);\n};\n"
  },
  {
    "path": "apps/vaporgui/TFHistogramInfoWidget.cpp",
    "content": "#include \"TFHistogramInfoWidget.h\"\n#include <vapor/RenderParams.h>\n#include <QLabel>\n#include <QBoxLayout>\n\nTFHistogramInfoWidget::TFHistogramInfoWidget(const std::string &variableNameTag) : TFInfoWidget(variableNameTag) { _valueEdit->SetReadOnly(true); }\n\nvoid TFHistogramInfoWidget::SetControlPoint(float value)\n{\n    this->setEnabled(true);\n    SetNormalizedValue(value);\n}\n\nvoid TFHistogramInfoWidget::Deselect()\n{\n    this->setEnabled(false);\n    _valueEdit->Clear();\n}\n"
  },
  {
    "path": "apps/vaporgui/TFHistogramInfoWidget.h",
    "content": "#pragma once\n\n#include \"TFInfoWidget.h\"\n#include <QLineEdit>\n\nnamespace VAPoR {\nclass RenderParams;\n}\n\nclass TFHistogramInfoWidget : public TFInfoWidget {\n    Q_OBJECT\n\n    using TFInfoWidget::TFInfoWidget;\n\npublic:\n    TFHistogramInfoWidget(const std::string &variableNameTag);\n\npublic slots:\n    void SetControlPoint(float value);\n    void Deselect();\n};\n"
  },
  {
    "path": "apps/vaporgui/TFHistogramWidget.cpp",
    "content": "#include \"TFHistogramWidget.h\"\n#include \"TFHistogramInfoWidget.h\"\n#include <QPaintEvent>\n#include <vapor/DataMgr.h>\n#include <QPainter>\n#include <QPicture>\n#include <glm/glm.hpp>\n#include <vapor/Histo.h>\n#include \"ErrorReporter.h\"\n#include <vapor/RenderParams.h>\n#include <vapor/ParamsMgr.h>\n#include <math.h>\n#include \"QPaintUtils.h\"\n#include \"ParamsMenuItems.h\"\n\nusing namespace VAPoR;\nusing glm::clamp;\nusing glm::vec2;\nusing std::vector;\n\n#define SCALING_TAG \"HistogramScalingTag\"\n\nTFHistogramMap::TFHistogramMap(const std::string &variableNameTag, TFMapWidget *parent) : TFMap(variableNameTag, parent)\n{\n    _scalingMenu = new ParamsDropdownMenuItem(this, SCALING_TAG, {\"Linear\", \"Logarithmic\", \"Boolean\"}, {}, \"Histogram Scaling\");\n}\n\nQSize TFHistogramMap::minimumSizeHint() const\n{\n    //    return QSize(100, 40);\n    return QSize(100, 75);\n}\n\nvoid TFHistogramMap::PopulateSettingsMenu(QMenu *menu) const\n{\n    menu->addAction(_scalingMenu);\n\n    QAction *histogramDynamicScalingAction = menu->addAction(\"Histogram Dynamic Scaling\", this, SLOT(_menuDynamicScalingToggled(bool)));\n    histogramDynamicScalingAction->setCheckable(true);\n    histogramDynamicScalingAction->setChecked(_dynamicScaling);\n}\n\nvoid TFHistogramMap::paramsUpdate()\n{\n    RenderParams *rp = getRenderParams();\n    if (rp->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag).size()) {\n        auto range = rp->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag);\n        auto bins = rp->GetValueLongVec(RenderParams::CustomHistogramDataTag);\n        int  numBins = bins.size();\n        _histo.reset(numBins, range[0], range[1]);\n        _histo.setBins(bins);\n    } else {\n        int numBins = width() ? width() : 256;\n        if (_histo.getNumBins() != numBins) _histo.reset(numBins);    // This can be called before it is resized\n        if (_histo.PopulateIfNeeded(getVariableName(), getDataMgr(), getRenderParams()) < 0) MSG_ERR(\"Failed to populate histogram\");\n    }\n\n    _scalingMenu->Update(getRenderParams());\n    _mapRange = getRenderParams()->GetMapperFunc(getVariableName())->getMinMaxMapValue();\n    update();\n}\n\nTFInfoWidget *TFHistogramMap::createInfoWidget()\n{\n    TFHistogramInfoWidget *info = new TFHistogramInfoWidget(getVariableNameTag());\n\n    connect(this, SIGNAL(UpdateInfo(float)), info, SLOT(SetControlPoint(float)));\n    connect(this, SIGNAL(InfoDeselected()), info, SLOT(Deselect()));\n\n    return info;\n}\n\nvoid TFHistogramMap::_paintEvent(QPainter &p)\n{\n    if (width() == 0) return;\n\n    p.fillRect(rect(), Qt::lightGray);\n\n    QPolygonF graph;\n    graph.push_back(NDCToQPixel(0, 0));\n\n    int      startBin = _histo.getBinIndexForValue(_mapRange[0]);\n    int      endBin = _histo.getBinIndexForValue(_mapRange[1]);\n    int      stride = 1;\n    QMargins padding = GetPadding();\n    while ((endBin - startBin) / stride >= 2 * (width() - (padding.left() + padding.right()))) stride *= 2;\n    startBin -= startBin % stride;\n\n    // Prevents an edge case where the current range is very far from the computed one\n    if (_histo.getRange() < FLT_EPSILON || (_mapRange[1] - _mapRange[0]) / _histo.getRange() > 10000) return;\n\n    float maxBin;\n    if (_dynamicScaling)\n        maxBin = _histo.getMaxBinSizeBetweenIndices(startBin, endBin);\n    else\n        maxBin = _histo.getMaxBinSize();\n\n    const float logMaxBin = maxBin == 1 ? 1 : logf(maxBin);\n    ScalingType scaling = _getScalingType();\n\n    for (int i = startBin; i < endBin; i += stride) {\n        float bin = _histo.getBinSize(i, stride);\n\n        switch (scaling) {\n        default:\n        case ScalingType::Linear: bin /= maxBin; break;\n        case ScalingType::Logarithmic: bin = bin == 0 ? 0 : logf(bin) / logMaxBin; break;\n        case ScalingType::Boolean: bin = bin > 0 ? 1 : 0; break;\n        }\n\n        graph.push_back(NDCToQPixel((i - startBin) / (float)(endBin - startBin), bin));\n    }\n\n    graph.push_back(NDCToQPixel(1, 0));\n\n    QPicture picture;\n    QPainter pp(&picture);\n    pp.setRenderHint(QPainter::Antialiasing);\n\n    pp.setPen(Qt::NoPen);\n    pp.setBrush(QBrush(QColor(56, 128, 255)));\n    pp.drawPolygon(graph);\n    pp.end();\n    QPaintUtils::DropShadow(p, picture, 10, QColor(56, 128, 255, 150));\n    p.drawPicture(0, 0, picture);\n    QPaintUtils::InnerShadow(p, picture, 10, QColor(0, 0, 0, 100));\n}\n\nvoid TFHistogramMap::mousePressEvent(QMouseEvent *event)\n{\n    emit Activated(this);\n    emit UpdateInfo(PixelToNDC(event->pos()).x);\n}\n\nvoid TFHistogramMap::mouseReleaseEvent(QMouseEvent *event) { emit InfoDeselected(); }\n\nvoid TFHistogramMap::mouseMoveEvent(QMouseEvent *event) { emit UpdateInfo(PixelToNDC(event->pos()).x); }\n\n// void TFHistogramWidget::mouseDoubleClickEvent(QMouseEvent *event)\n\nTFHistogramMap::ScalingType TFHistogramMap::_getScalingType() const\n{\n    if (!getRenderParams()) return ScalingType::Linear;\n\n    ScalingType type = (ScalingType)getRenderParams()->GetValueLong(SCALING_TAG, (int)ScalingType::Linear);\n    if (type >= ScalingTypeCount || type < 0) type = Linear;\n\n    return type;\n}\n\nvoid TFHistogramMap::_menuDynamicScalingToggled(bool on) { _dynamicScaling = on; }\n"
  },
  {
    "path": "apps/vaporgui/TFHistogramWidget.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include <QFrame>\n#include <vapor/VAssert.h>\n#include <vapor/Histo.h>\n#include \"TFMapWidget.h\"\n\nclass ParamsDropdownMenuItem;\n\nclass TFHistogramMap : public TFMap {\n    Q_OBJECT\n\n    enum ScalingType { Linear = 0, Logarithmic, Boolean, ScalingTypeCount };\n\npublic:\n    TFHistogramMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr);\n\n    QSize minimumSizeHint() const;\n    void  LostFocus() {}\n    void  PopulateSettingsMenu(QMenu *menu) const;\n\nprotected:\n    void          paramsUpdate();\n    TFInfoWidget *createInfoWidget();\n    void          _paintEvent(QPainter &p);\n    void          mousePressEvent(QMouseEvent *event);\n    void          mouseReleaseEvent(QMouseEvent *event);\n    void          mouseMoveEvent(QMouseEvent *event);\n    //    void mouseDoubleClickEvent(QMouseEvent *event);\n\nprivate:\n    Histo                   _histo;\n    ParamsDropdownMenuItem *_scalingMenu;\n    bool                    _dynamicScaling = true;\n\n    vector<double> _mapRange;\n\n    ScalingType _getScalingType() const;\n\nprivate slots:\n    void _menuDynamicScalingToggled(bool on);\n\nsignals:\n    void InfoDeselected();\n    void UpdateInfo(float value);\n};\n\nclass TFHistogramWidget : public TFMapWidget {\n    Q_OBJECT\npublic:\n    TFHistogramWidget(const std::string &variableNameTag) : TFMapWidget(new TFHistogramMap(variableNameTag, this)) {}\n};\n"
  },
  {
    "path": "apps/vaporgui/TFInfoWidget.cpp",
    "content": "#include \"TFInfoWidget.h\"\n#include <QBoxLayout>\n#include <QLabel>\n#include <QPainter>\n#include <vapor/RenderParams.h>\n#include <VLineItem.h>\n\n#ifndef __FLT_MIN__\n    #define __FLT_MIN__ FLT_MIN\n    #define __FLT_MAX__ FLT_MAX\n#endif\n\nTFInfoWidget::TFInfoWidget(const std::string &variableNameTag) : _variableNameTag(variableNameTag)\n{\n    QBoxLayout *layout = new QVBoxLayout;\n    layout->setSpacing(12);\n    layout->setMargin(0);\n    this->setLayout(layout);\n    layout->addWidget(new VLineItem(\"Data Value\", _valueEdit = new VDoubleLineEdit));\n    _valueEditType = new QComboBox;\n\n    _valueEditType->blockSignals(true);\n    _valueEditType->setMinimumSize(30, 10);\n    _valueEditType->setSizeAdjustPolicy(QComboBox::AdjustToContents);\n    _valueEditType->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);\n    _valueEditType->addItem(\"data\");\n    _valueEditType->addItem(\"%\");\n    _valueEditType->blockSignals(false);\n\n    connect(_valueEditType, SIGNAL(currentIndexChanged(int)), this, SLOT(valueEditTypeChanged(int)));\n    connect(_valueEdit, &VDoubleLineEdit::ValueChanged, this, &TFInfoWidget::valueEditChanged);\n\n    this->setDisabled(true);\n}\n\nvoid TFInfoWidget::Update(VAPoR::RenderParams *rParams)\n{\n    if (!rParams) return;\n\n    string variableName = rParams->GetValueString(_variableNameTag, \"\");\n\n    _min = rParams->GetMapperFunc(variableName)->getMinMapValue();\n    _max = rParams->GetMapperFunc(variableName)->getMaxMapValue();\n\n    updateValueEditValidator();\n}\n\nvoid TFInfoWidget::DeselectControlPoint()\n{\n    this->setDisabled(true);\n    _valueEdit->Clear();\n}\n\nvoid TFInfoWidget::SetNormalizedValue(float value)\n{\n    value = value < 0 ? 0 : value > 1 ? 1 : value;\n    _value = value;\n    updateValue();\n}\n\nvoid TFInfoWidget::paintEvent(QPaintEvent *event)\n{\n    QStyleOption opt;\n    opt.init(this);\n    QPainter p(this);\n    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);\n\n    QWidget::paintEvent(event);\n}\n\nvoid TFInfoWidget::updateValue()\n{\n    if (!isEnabled()) return;\n\n    float value = _value;\n    if (isUsingMappedValue())\n        value = toMappedValue(value);\n    else\n        value *= 100;\n    _valueEdit->SetValueDouble(value);\n}\n\nvoid TFInfoWidget::updateValueEditValidator()\n{\n    if (isUsingMappedValue())\n        _valueEdit->SetRange(_min, _max);\n    else\n        _valueEdit->SetRange(0, 100);\n}\n\nbool TFInfoWidget::isUsingNormalizedValue() const { return _valueEditType->currentIndex() == ValueFormat::Percent; }\n\nbool TFInfoWidget::isUsingMappedValue() const { return _valueEditType->currentIndex() == ValueFormat::Mapped; }\n\nfloat TFInfoWidget::toMappedValue(float normalized) const { return normalized * (_max - _min) + _min; }\n\nfloat TFInfoWidget::toNormalizedValue(float mapped) const\n{\n    if (_max == _min) return 0;\n\n    return (mapped - _min) / (_max - _min);\n}\n\nfloat TFInfoWidget::getValueFromEdit() const\n{\n    float value = _valueEdit->GetValueDouble();\n    if (isUsingMappedValue())\n        return toNormalizedValue(value);\n    else\n        return value / 100.f;\n}\n\nvoid TFInfoWidget::valueEditTypeChanged(int)\n{\n    updateValue();\n    updateValueEditValidator();\n}\n\nvoid TFInfoWidget::valueEditChanged()\n{\n    _value = getValueFromEdit();\n    controlPointChanged();\n}\n"
  },
  {
    "path": "apps/vaporgui/TFInfoWidget.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include <VDoubleLineEdit.h>\n#include <QComboBox>\n#include <string>\n\nnamespace VAPoR {\nclass RenderParams;\n}\n\n//! \\class TFInfoWidget\n//! The TFInfoWidget displays details and allow users to manually edit values for the control\n//! points used by the TFMapWidget\n\nclass TFInfoWidget : public QWidget {\n    Q_OBJECT\n\npublic:\n    enum ValueFormat { Mapped = 0, Percent = 1 };\n\n    TFInfoWidget(const std::string &variableNameTag);\n\n    void Update(VAPoR::RenderParams *rParams);\n    void DeselectControlPoint();\n    void SetNormalizedValue(float value);\n\nprotected:\n    void  paintEvent(QPaintEvent *event);\n    void  updateValue();\n    void  updateValueEditValidator();\n    bool  isUsingNormalizedValue() const;\n    bool  isUsingMappedValue() const;\n    float toMappedValue(float normalized) const;\n    float toNormalizedValue(float mapped) const;\n    float getValueFromEdit() const;\n\n    virtual void controlPointChanged(){};\n\nprotected:\n    VDoubleLineEdit *_valueEdit;\n    QComboBox *      _valueEditType;\n\n    float _min = 0;\n    float _max = 1;\n\nprotected:\n    float             _value;\n    const std::string _variableNameTag;\n\nprivate slots:\n    void valueEditTypeChanged(int);\n    void valueEditChanged();\n};\n"
  },
  {
    "path": "apps/vaporgui/TFIsoValueInfoWidget.cpp",
    "content": "#include \"TFIsoValueInfoWidget.h\"\n#include <vapor/RenderParams.h>\n#include <QLabel>\n#include <QBoxLayout>\n\nvoid TFIsoValueInfoWidget::controlPointChanged() { emit ControlPointChanged(this->getValueFromEdit()); }\n\nvoid TFIsoValueInfoWidget::SetControlPoint(float value)\n{\n    this->setEnabled(true);\n    SetNormalizedValue(value);\n}\n\nvoid TFIsoValueInfoWidget::Deselect()\n{\n    this->setEnabled(false);\n    _valueEdit->Clear();\n}\n"
  },
  {
    "path": "apps/vaporgui/TFIsoValueInfoWidget.h",
    "content": "#pragma once\n\n#include \"TFInfoWidget.h\"\n#include <QLineEdit>\n\nnamespace VAPoR {\nclass RenderParams;\n}\n\nclass TFIsoValueInfoWidget : public TFInfoWidget {\n    Q_OBJECT\n\n    using TFInfoWidget::TFInfoWidget;\n\nprotected:\n    void controlPointChanged();\n\nsignals:\n    void ControlPointChanged(float value);\n\npublic slots:\n    void SetControlPoint(float value);\n    void Deselect();\n};\n"
  },
  {
    "path": "apps/vaporgui/TFIsoValueWidget.cpp",
    "content": "#include \"TFIsoValueWidget.h\"\n#include <QPainter>\n#include <QMouseEvent>\n#include <vapor/RenderParams.h>\n#include <vapor/ParamsMgr.h>\n#include \"QPaintUtils.h\"\n#include \"TFIsoValueInfoWidget.h\"\n\nusing namespace VAPoR;\nusing glm::vec2;\nusing std::vector;\n\nstatic vec2 qvec2(const QPoint &qp) { return vec2(qp.x(), qp.y()); }\n\nTFIsoValueMap::TFIsoValueMap(const std::string &variableNameTag, TFMapWidget *parent) : TFMap(variableNameTag, parent) {}\n\nvoid TFIsoValueMap::paramsUpdate()\n{\n    if (!getRenderParams()->HasIsoValues()) {\n        hide();\n        return;\n    }\n\n    loadFromParams(getRenderParams());\n    update();\n\n    if (_selectedId > -1) UpdateInfo(_isoValues[_selectedId]);\n}\n\nQSizePolicy TFIsoValueMap::GetSizePolicy() const { return QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); }\n\n#define PROPERTY_INDEX (\"index\")\n#define PROPERTY_VALUE (\"value\")\n\nvoid TFIsoValueMap::PopulateContextMenu(QMenu *menu, const glm::vec2 &p)\n{\n    if (_equidistantIsoValues) return;\n\n    int selectedId = findSelectedControlPoint(p);\n    if (selectedId != -1)\n        menu->addAction(\"Delete control point\", this, SLOT(menuDeleteControlPoint()))->setProperty(PROPERTY_INDEX, selectedId);\n    else {\n        QAction *action = menu->addAction(\"Add control point\", this, SLOT(menuAddControlPoint()));\n        action->setProperty(PROPERTY_VALUE, QVariant(valueForControlX(p.x)));\n        if (_isoValues.size() >= 4) action->setDisabled(true);\n    }\n}\n\nQSize TFIsoValueMap::minimumSizeHint() const\n{\n    QSize s = GetControlPointArea(QPoint(0, 0)).size();\n    if (BottomPadding) s.setHeight(s.height() + GetControlPointRadius());\n    return s;\n}\n\nvoid TFIsoValueMap::LostFocus() { DeselectControlPoint(); }\n\nTFInfoWidget *TFIsoValueMap::createInfoWidget()\n{\n    TFIsoValueInfoWidget *info = new TFIsoValueInfoWidget(getVariableNameTag());\n\n    connect(this, SIGNAL(ControlPointDeselected()), info, SLOT(Deselect()));\n    connect(this, SIGNAL(UpdateInfo(float)), info, SLOT(SetControlPoint(float)));\n    connect(info, SIGNAL(ControlPointChanged(float)), this, SLOT(UpdateFromInfo(float)));\n\n    return info;\n}\n\nvoid TFIsoValueMap::_paintEvent(QPainter &p)\n{\n    p.fillRect(rect(), Qt::lightGray);\n\n    for (int i = 0; i < _isoValues.size(); i++) {\n        float v = _isoValues[i];\n        bool  invalid = false;\n        if (v < 0 || v > 1) {\n            v = glm::clamp(v, 0.f, 1.f);\n            invalid = true;\n        }\n        drawControl(p, controlQPositionForValue(v), i == _selectedId, invalid);\n    }\n\n    if (_isoValues.size() == 0) {\n        QFont font = getFont();\n        font.setPixelSize(rect().height());\n        p.setFont(font);\n        p.drawText(rect(), Qt::AlignCenter, \"doubleclick to add isovalues\");\n    }\n}\n\nvoid TFIsoValueMap::drawControl(QPainter &p, const QPointF &pos, bool selected, bool invalid) const\n{\n    float r = GetControlPointRadius();\n    float t = GetControlPointTriangleHeight();\n    float s = GetControlPointSquareHeight();\n\n    QPen   pen(Qt::darkGray, 0.5);\n    QBrush brush(QColor(0xfa, 0xfa, 0xfa));\n    p.setBrush(brush);\n    p.setPen(pen);\n\n    if (invalid) p.setBrush(QBrush(QColor(0xfa, 0x8a, 0x8a)));\n\n    QPolygonF graph;\n    graph.push_back(pos + QPointF(0, 0));\n    graph.push_back(pos + QPointF(-r, t));\n    graph.push_back(pos + QPointF(-r, t + s));\n    graph.push_back(pos + QPointF(r, t + s));\n    graph.push_back(pos + QPointF(r, t));\n\n    p.drawPolygon(graph);\n\n    if (selected) {\n        if (selected) {\n            p.setPen(Qt::NoPen);\n            p.setBrush(QBrush(Qt::black));\n            r *= 0.38;\n            p.drawEllipse(pos + QPointF(0, t + (s / 3)), r, r);\n        }\n    }\n}\n\nfloat TFIsoValueMap::GetControlPointTriangleHeight() const { return GetControlPointRadius() * 2 * 0.618; }\n\nfloat TFIsoValueMap::GetControlPointSquareHeight() const { return GetControlPointRadius() * 1.618; }\n\nQRect TFIsoValueMap::GetControlPointArea(const QPoint &p) const\n{\n    float h = GetControlPointSquareHeight() + GetControlPointTriangleHeight();\n    float r = GetControlPointRadius();\n    return QRect(p - QPoint(r, 0), p + QPoint(r, h));\n}\n\nvoid TFIsoValueMap::mousePressEvent(QMouseEvent *event)\n{\n    emit Activated(this);\n    vec2 mouse(event->pos().x(), event->pos().y());\n\n    int selectedId = findSelectedControlPoint(mouse);\n    if (selectedId >= 0) {\n        _isDraggingControl = true;\n        _draggingControlID = selectedId;\n        selectControlPoint(selectedId);\n        update();\n        _dragOffset = controlPositionForValue(glm::clamp(_isoValues[selectedId], 0.f, 1.f)) - mouse;\n        getParamsMgr()->BeginSaveStateGroup(\"IsoValue modification\");\n        return;\n    }\n\n    DeselectControlPoint();\n    event->ignore();\n    update();\n}\n\nvoid TFIsoValueMap::mouseReleaseEvent(QMouseEvent *event)\n{\n    if (_isDraggingControl)\n        getParamsMgr()->EndSaveStateGroup();\n    else\n        event->ignore();\n    _isDraggingControl = false;\n}\n\nvoid TFIsoValueMap::mouseMoveEvent(QMouseEvent *event)\n{\n    vec2 mouse = qvec2(event->pos());\n\n    if (_isDraggingControl) {\n        float newVal = glm::clamp(valueForControlX(mouse.x + _dragOffset.x), 0.f, 1.f);\n\n        moveControlPoint(&_draggingControlID, newVal);\n        selectControlPoint(_draggingControlID);\n        saveToParams(getRenderParams());\n        update();\n        getParamsMgr()->IntermediateChange();\n    } else {\n        event->ignore();\n    }\n}\n\nvoid TFIsoValueMap::mouseDoubleClickEvent(QMouseEvent *event)\n{\n    if (_equidistantIsoValues) return;\n\n    vec2 mouse = qvec2(event->pos());\n    int  selectedId = findSelectedControlPoint(mouse);\n    if (selectedId >= 0) {\n        deleteControlPoint(selectedId);\n        return;\n    }\n\n    if (_isoValues.size() < 4) {\n        float newVal = valueForControlX(mouse.x);\n        if (newVal >= 0 && newVal <= 1) { addControlPoint(newVal); }\n        return;\n    }\n}\n\nQMargins TFIsoValueMap::GetPadding() const\n{\n    QMargins m = TFMap::GetPadding();\n    m.setTop(0);\n    return m;\n}\n\nvoid TFIsoValueMap::saveToParams(VAPoR::RenderParams *rp) const\n{\n    if (!rp) return;\n    if (!rp->HasIsoValues()) return;\n    assert(rp->HasIsoValues());\n\n    const float min = getMapRangeMin();\n    const float max = getMapRangeMax();\n\n    vector<double> values(_isoValues.size());\n    for (int i = 0; i < values.size(); i++) values[i] = _isoValues[i] * (max - min) + min;\n    rp->SetIsoValues(values);\n}\n\nvoid TFIsoValueMap::loadFromParams(VAPoR::RenderParams *rp)\n{\n    if (!rp) return;\n    if (!rp->HasIsoValues()) return;\n    assert(rp->HasIsoValues());\n\n    const float min = getMapRangeMin();\n    const float max = getMapRangeMax();\n\n    vector<double> newValues = rp->GetIsoValues();\n    if (newValues.size() != _isoValues.size()) {\n        DeselectControlPoint();\n        _isoValues.resize(newValues.size());\n    }\n    for (int i = 0; i < newValues.size(); i++) _isoValues[i] = (newValues[i] - min) / (max - min);\n\n    //    if (!_equidistantIsoValues)\n    //        clampIsoValuesToMappingRange();\n}\n\n// void TFIsoValueMap::clampIsoValuesToMappingRange()\n//{\n//   / for (int i = 0; i < _isoValues.size(); i++)\n//        _isoValues[i] = glm::clamp(_isoValues[i], 0.f, 1.f);\n//}\n\nint TFIsoValueMap::addControlPoint(float value)\n{\n    int index = -1;\n    for (int i = 0; i < _isoValues.size(); i++) {\n        if (value < _isoValues[i]) {\n            _isoValues.insert(_isoValues.begin() + i, value);\n            index = i;\n            break;\n        }\n    }\n    if (index == -1) {\n        _isoValues.push_back(value);\n        index = _isoValues.size() - 1;\n    }\n    saveToParams(getRenderParams());\n    selectControlPoint(index);\n    update();\n    return index;\n}\n\nvoid TFIsoValueMap::deleteControlPoint(int i)\n{\n    if (i == _selectedId) DeselectControlPoint();\n    _isoValues.erase(_isoValues.begin() + i);\n    update();\n    saveToParams(getRenderParams());\n}\n\nvoid TFIsoValueMap::moveControlPoint(int *index, float value)\n{\n    if (_equidistantIsoValues) {\n        if (*index == 0) {\n            const float initialValue = _isoValues[0];\n            const float diff = value - initialValue;\n            for (float &v : _isoValues) v += diff;\n        } else {\n            const float baseValue = _isoValues[0];\n            float       spacing = (value - baseValue) / (float)(*index);\n            spacing = std::max(spacing, 0.f);\n            for (int i = 1; i < _isoValues.size(); i++) _isoValues[i] = baseValue + spacing * i;\n        }\n    } else {\n        deleteControlPoint(*index);\n        *index = addControlPoint(value);\n    }\n}\n\nvoid TFIsoValueMap::selectControlPoint(int index)\n{\n    _selectedId = index;\n    float value = _isoValues[index];\n    emit  UpdateInfo(value);\n}\n\nvoid TFIsoValueMap::DeselectControlPoint()\n{\n    _selectedId = -1;\n    emit ControlPointDeselected();\n    update();\n}\n\nvoid TFIsoValueMap::UpdateFromInfo(float value)\n{\n    if (_selectedId >= 0 && _selectedId < _isoValues.size()) {\n        moveControlPoint(&_selectedId, value);\n        update();\n        saveToParams(getRenderParams());\n    }\n}\n\nint TFIsoValueMap::findSelectedControlPoint(const glm::vec2 &mouse) const\n{\n    for (int i = _isoValues.size() - 1; i >= 0; i--)\n        if (controlPointContainsPixel(glm::clamp(_isoValues[i], 0.f, 1.f), mouse)) return i;\n    return -1;\n}\n\nbool TFIsoValueMap::controlPointContainsPixel(float cp, const vec2 &p) const\n{\n    QRect rect = GetControlPointArea(controlQPositionForValue(cp));\n    return rect.contains(QPoint(p.x, p.y));\n}\n\nQPoint TFIsoValueMap::controlQPositionForValue(float value) const\n{\n    const vec2 v = controlPositionForValue(value);\n    return QPoint(v.x, v.y);\n}\n\nglm::vec2 TFIsoValueMap::controlPositionForValue(float value) const { return vec2(controlXForValue(value), 0); }\n\nfloat TFIsoValueMap::controlXForValue(float value) const { return NDCToPixel(vec2(value, 0.f)).x; }\n\nfloat TFIsoValueMap::valueForControlX(float position) const { return PixelToNDC(vec2(position, 0.f)).x; }\n\nfloat TFIsoValueMap::getMapRangeMin() const\n{\n    if (!getRenderParams()) return 0;\n    return getRenderParams()->GetMapperFunc(getRenderParams()->GetVariableName())->getMinMapValue();\n}\n\nfloat TFIsoValueMap::getMapRangeMax() const\n{\n    if (!getRenderParams()) return 1;\n    return getRenderParams()->GetMapperFunc(getRenderParams()->GetVariableName())->getMaxMapValue();\n}\n\nvoid TFIsoValueMap::menuDeleteControlPoint()\n{\n    emit     Activated(this);\n    QVariant valueVariant = sender()->property(PROPERTY_INDEX);\n    if (valueVariant.isValid()) {\n        int index = valueVariant.toInt();\n        if (index >= 0 && index < _isoValues.size()) deleteControlPoint(index);\n    }\n}\n\nvoid TFIsoValueMap::menuAddControlPoint()\n{\n    emit     Activated(this);\n    QVariant value = sender()->property(PROPERTY_VALUE);\n    if (value.isValid()) addControlPoint(value.toFloat());\n}\n"
  },
  {
    "path": "apps/vaporgui/TFIsoValueWidget.h",
    "content": "#pragma once\n\n#include \"TFMapWidget.h\"\n#include <vapor/RenderParams.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/VAssert.h>\n#include <glm/glm.hpp>\n\n// class TFIsoValueInfoWidget;\n\nclass TFIsoValueMap : public TFMap {\n    Q_OBJECT\n\npublic:\n    bool BottomPadding = false;\n\n    TFIsoValueMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr);\n    void PopulateContextMenu(QMenu *menu, const glm::vec2 &p) override;\n\n    QSize minimumSizeHint() const override;\n    QSizePolicy GetSizePolicy() const override;\n    void  LostFocus() override;\n\n    TFIsoValueMap *SetEquidistantIsoValues(bool b)\n    {\n        _equidistantIsoValues = b;\n        return this;\n    }\n\nprotected:\n    void          paramsUpdate() override;\n    TFInfoWidget *createInfoWidget() override;\n    void          _paintEvent(QPainter &p) override;\n    void          drawControl(QPainter &p, const QPointF &pos, bool selected = false, bool invalid = false) const;\n    float         GetControlPointTriangleHeight() const;\n    float         GetControlPointSquareHeight() const;\n    QRect         GetControlPointArea(const QPoint &p) const;\n    void          mousePressEvent(QMouseEvent *event) override;\n    void          mouseReleaseEvent(QMouseEvent *event) override;\n    void          mouseMoveEvent(QMouseEvent *event) override;\n    void          mouseDoubleClickEvent(QMouseEvent *event) override;\n    QMargins      GetPadding() const override;\n\nprivate:\n    bool               _isDraggingControl = false;\n    int                _draggingControlID;\n    int                _selectedId = -1;\n    glm::vec2          _dragOffset;\n    glm::vec2          m;\n    std::vector<float> _isoValues;\n    std::vector<bool>  _isoValuesInBounds;\n    bool               _equidistantIsoValues = true;\n\n    bool controlPointContainsPixel(const glm::vec2 &cp, const glm::vec2 &pixel) const;\n\n    void      saveToParams(VAPoR::RenderParams *rp) const;\n    void      loadFromParams(VAPoR::RenderParams *rp);\n    void      clampIsoValuesToMappingRange();\n    int       addControlPoint(float value);\n    void      deleteControlPoint(int i);\n    void      moveControlPoint(int *index, float value);\n    void      selectControlPoint(int index);\n    int       findSelectedControlPoint(const glm::vec2 &mouse) const;\n    bool      controlPointContainsPixel(float cp, const glm::vec2 &pixel) const;\n    QPoint    controlQPositionForValue(float value) const;\n    glm::vec2 controlPositionForValue(float value) const;\n    float     controlXForValue(float value) const;\n    float     valueForControlX(float position) const;\n    float     getMapRangeMin() const;\n    float     getMapRangeMax() const;\n\nsignals:\n    void ControlPointDeselected();\n    void UpdateInfo(float value);\n\npublic slots:\n    void DeselectControlPoint();\n    void UpdateFromInfo(float value);\n\nprivate slots:\n    void menuDeleteControlPoint();\n    void menuAddControlPoint();\n};\n\nclass TFIsoValueWidget : public TFMapWidget {\npublic:\n    TFIsoValueWidget(const std::string &variableNameTag) : TFMapWidget(new TFIsoValueMap(variableNameTag, this)) {}\n};\n"
  },
  {
    "path": "apps/vaporgui/TFMapGroupWidget.cpp",
    "content": "#include \"TFMapGroupWidget.h\"\n#include \"TFMapWidget.h\"\n#include \"TFInfoWidget.h\"\n#include <QBoxLayout>\n\nTFMapGroupWidget::TFMapGroupWidget()\n{\n    QVBoxLayout *layout = new QVBoxLayout;\n    layout->setSpacing(0);\n    layout->setMargin(0);\n    setLayout(layout);\n}\n\nvoid TFMapGroupWidget::Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams)\n{\n    for (auto map : _maps) map->Update(dataMgr, paramsMgr, rParams);\n}\n\nTFMapInfoGroupWidget *TFMapGroupWidget::CreateInfoGroup()\n{\n    TFMapInfoGroupWidget *infos = new TFMapInfoGroupWidget;\n\n    for (auto map : _maps) { infos->add(map); }\n\n    return infos;\n}\n\nvoid TFMapGroupWidget::Add(TFMapWidget *mapWidget)\n{\n    _maps.push_back(mapWidget);\n    layout()->addWidget(mapWidget);\n    connect(mapWidget, SIGNAL(Activated(TFMapWidget *)), this, SLOT(mapActivated(TFMapWidget *)));\n}\n\nvoid TFMapGroupWidget::Add(TFMap *map) { Add(new TFMapWidget(map)); }\n\nvoid TFMapGroupWidget::Add(const std::initializer_list<TFMap *> &layeredMaps)\n{\n    assert(layeredMaps.size() > 0);\n    if (layeredMaps.size() == 0) return;\n\n    TFMapWidget *mapWidget = new TFMapWidget(*layeredMaps.begin());\n\n    for (auto it = layeredMaps.begin() + 1; it != layeredMaps.end(); ++it) mapWidget->AddMap(*it);\n\n    Add(mapWidget);\n}\n\nvoid TFMapGroupWidget::mapActivated(TFMapWidget *activatedMap)\n{\n    for (auto map : _maps)\n        if (map != activatedMap) map->Deactivate();\n}\n\nvoid TFMapInfoGroupWidget::Update(VAPoR::RenderParams *rParams)\n{\n    for (auto info : _infos) info->Update(rParams);\n}\n\nvoid TFMapInfoGroupWidget::add(TFMapWidget *mapWidget)\n{\n    for (TFMap *map : mapWidget->GetMaps()) {\n        TFInfoWidget *info = map->GetInfoWidget();\n        if (!info) continue;\n        _infos.push_back(info);\n\n        // Qt::StackedLayout does not support alignment so we need to wrap\n        // the info widget in another widget with a box layout.\n        QWidget *    box = new QWidget;\n        QVBoxLayout *layout = new QVBoxLayout;\n        layout->setMargin(0);\n        layout->setAlignment(Qt::AlignTop);\n        layout->addWidget(info);\n        box->setLayout(layout);\n        addWidget(box);\n\n        connect(map, SIGNAL(Activated(TFMap *)), this, SLOT(mapActivated(TFMap *)));\n    }\n}\n\nvoid TFMapInfoGroupWidget::mapActivated(TFMap *activatedMap) { setCurrentWidget((QWidget *)(activatedMap->GetInfoWidget()->parent())); }\n"
  },
  {
    "path": "apps/vaporgui/TFMapGroupWidget.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include <QStackedWidget>\n#include <vector>\n\nclass TFInfoWidget;\nclass TFMapWidget;\nclass TFMap;\nclass TFMapInfoGroupWidget;\n\nnamespace VAPoR {\nclass DataMgr;\nclass ParamsMgr;\nclass RenderParams;\n}    // namespace VAPoR\n\n//! \\class TFMapGroupWidget\n//! Manages a vertical stack of TFMap without any spacing between them\n//! to create the illusion of a continuous widget\n\nclass TFMapGroupWidget : public QWidget {\n    Q_OBJECT\n\n    std::vector<TFMapWidget *> _maps;\n\npublic:\n    TFMapGroupWidget();\n    void Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams);\n\n    TFMapInfoGroupWidget *CreateInfoGroup();\n\n    void Add(TFMapWidget *mapWidget);\n    void Add(TFMap *map);\n    void Add(const std::initializer_list<TFMap *> &layeredMaps);\n\nprivate slots:\n    void mapActivated(TFMapWidget *map);\n};\n\n//! \\class TFMapInfoGroupWidget\n//! Holds a group of TFMapInfo and only displays the relevant one.\n\nclass TFMapInfoGroupWidget : public QStackedWidget {\n    Q_OBJECT\n\n    std::vector<TFInfoWidget *> _infos;\n\npublic:\n    void Update(VAPoR::RenderParams *rParams);\n\n    friend class TFMapGroupWidget;\n\nprivate:\n    void add(TFMapWidget *map);\n\nprivate slots:\n    void mapActivated(TFMap *map);\n};\n"
  },
  {
    "path": "apps/vaporgui/TFMapWidget.cpp",
    "content": "#include \"TFMapWidget.h\"\n#include \"TFColorWidget.h\"\n#include \"TFIsoValueWidget.h\"\n#include <QPainter>\n#include <QResizeEvent>\n#include <QMenu>\n#include <vapor/VAssert.h>\n#include <vapor/ParamsMgr.h>\n\nusing glm::vec2;\n\n#define CONTROL_POINT_RADIUS (4.0f)\n#define PADDING              (CONTROL_POINT_RADIUS + 1.0f)\n\nTFMap::TFMap(const std::string &variableNameTag, TFMapWidget *parent) : _variableNameTag(variableNameTag), _parent(parent) {}\n\nTFInfoWidget *TFMap::GetInfoWidget()\n{\n    if (!_infoWidget) _infoWidget = createInfoWidget();\n\n    return _infoWidget;\n}\n\nvoid TFMap::Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams)\n{\n    assert(_parent);\n    if (_renderParams != rParams) LostFocus();\n\n    _dataMgr = dataMgr;\n    _paramsMgr = paramsMgr;\n    _renderParams = rParams;\n    _variableName = _renderParams->GetValueString(_variableNameTag, \"\");\n\n    if (!_dataMgr->VariableExists(_renderParams->GetCurrentTimestep(), getVariableName()))\n        _renderParams = nullptr;\n\n    if (HasValidParams())\n        paramsUpdate();\n}\n\nbool TFMap::HasValidParams() const { return _dataMgr && _paramsMgr && _renderParams; }\n\nbool TFMap::IsShown() const { return !_hidden; }\n\nvoid TFMap::resize(int width, int height)\n{\n    _width = width;\n    _height = height;\n}\n\nbool TFMap::isLargeEnoughToPaint() const\n{\n    QMargins p = GetPadding();\n    if (_width - (p.left() + p.right()) <= 0) return false;\n    if (_height - (p.top() + p.bottom()) <= 0) return false;\n    return true;\n}\n\nvoid TFMap::paintEvent(QPainter &p)\n{\n    // _renderParams can be invalid during a paintEvent if params are changed and then Qt refreshes the GUI\n    // prior to the change event being handled.\n    const auto savedParams = _renderParams;\n    _renderParams = nullptr;\n    _paintEvent(p);\n    _renderParams = savedParams;\n}\n\nvoid TFMap::mousePressEvent(QMouseEvent *event) { event->ignore(); }\nvoid TFMap::mouseReleaseEvent(QMouseEvent *event) { event->ignore(); }\nvoid TFMap::mouseMoveEvent(QMouseEvent *event) { event->ignore(); }\nvoid TFMap::mouseDoubleClickEvent(QMouseEvent *event) { event->ignore(); }\n\nvoid TFMap::update()\n{\n    if (_parent) _parent->update();\n}\n\nvoid TFMap::show()\n{\n    _hidden = false;\n    if (_parent) _parent->showMap(this);\n}\n\nvoid TFMap::hide()\n{\n    _hidden = true;\n    if (_parent) _parent->hideMap(this);\n}\n\nVAPoR::MapperFunction *TFMap::getMapperFunction() const { return _renderParams->GetMapperFunc(getVariableName()); }\n\nQSizePolicy TFMap::GetSizePolicy() const { return QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); }\n\nstd::string TFMap::getVariableName() const { return _variableName; }\n\nconst std::string &TFMap::getVariableNameTag() const { return _variableNameTag; }\n\nvoid TFMap::drawControl(QPainter &p, const QPointF &pos, bool selected) const\n{\n    float radius = CONTROL_POINT_RADIUS;\n\n    if (selected) {\n        QRadialGradient gradient(0.5, 0.5, 0.4);\n        gradient.setCoordinateMode(QGradient::ObjectBoundingMode);\n        gradient.setColorAt(0, QColor(0, 0, 0, 100));\n        gradient.setColorAt(1, Qt::transparent);\n        QBrush shadowBrush(gradient);\n\n        p.setPen(Qt::NoPen);\n        p.setBrush(shadowBrush);\n        p.drawEllipse(pos, radius * 2, radius * 2);\n    }\n\n    QPen   pen(Qt::darkGray, 0.5);\n    QBrush brush(QColor(0xfa, 0xfa, 0xfa));\n\n    //    if (selected) {\n    //        pen.setColor(Qt::black);\n    //        pen.setWidth(1.5);\n    //\n    //        brush.setColor(Qt::white);\n    //    }\n\n    p.setBrush(brush);\n    p.setPen(pen);\n\n    p.drawEllipse(pos, radius, radius);\n\n    if (selected) {\n        p.setPen(Qt::NoPen);\n        p.setBrush(QBrush(Qt::black));\n        radius *= 0.38;\n        p.drawEllipse(pos, radius, radius);\n    }\n}\n\nQRect TFMap::paddedRect() const\n{\n    const QMargins p = GetPadding();\n    return QRect(p.left(), p.top(), width() - (p.left() + p.right()), height() - (p.top() + p.bottom()));\n}\n\nQRect TFMap::rect() const { return QRect(0, 0, width(), height()); }\n\nconst QFont TFMap::getFont() const\n{\n    if (_parent) return _parent->font();\n    return QFont();\n}\n\nglm::vec2 TFMap::NDCToPixel(const glm::vec2 &v) const\n{\n    const QRect p = paddedRect();\n    return vec2(p.x() + v.x * p.width(), p.y() + (1.0f - v.y) * p.height());\n}\n\nQPointF TFMap::NDCToQPixel(const glm::vec2 &v) const\n{\n    const vec2 p = NDCToPixel(v);\n    return QPointF(p.x, p.y);\n}\n\nQPointF TFMap::NDCToQPixel(float x, float y) const { return NDCToQPixel(vec2(x, y)); }\n\nglm::vec2 TFMap::PixelToNDC(const glm::vec2 &p) const\n{\n    float width = TFMap::width();\n    float height = TFMap::height();\n    if (width == 0 || height == 0) return vec2(0);\n\n    return vec2((p.x - PADDING) / (width - 2 * PADDING), 1.0f - (p.y - PADDING) / (height - 2 * PADDING));\n}\n\nglm::vec2 TFMap::PixelToNDC(const QPointF &p) const { return PixelToNDC(vec2(p.x(), p.y())); }\n\nQMargins TFMap::GetPadding() const { return QMargins(PADDING, PADDING, PADDING, PADDING); }\n\nint TFMap::GetControlPointRadius() const { return CONTROL_POINT_RADIUS; }\n\nvoid TFMap::BeginSaveStateGroup(VAPoR::ParamsMgr *paramsMgr, const std::string &description)\n{\n    assert(!_insideSaveStateGroup);\n    paramsMgr->BeginSaveStateGroup(description);\n    _insideSaveStateGroup = true;\n}\n\nvoid TFMap::EndSaveStateGroup(VAPoR::ParamsMgr *paramsMgr)\n{\n    assert(_insideSaveStateGroup);\n    paramsMgr->EndSaveStateGroup();\n    _insideSaveStateGroup = false;\n}\n\nvoid TFMap::CancelSaveStateGroup(VAPoR::ParamsMgr *paramsMgr)\n{\n    if (_insideSaveStateGroup) paramsMgr->EndSaveStateGroup();\n    _insideSaveStateGroup = false;\n}\n\nTFMapWidget::TFMapWidget(TFMap *map)\n{\n    AddMap(map);\n    setContextMenuPolicy(Qt::CustomContextMenu);\n    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(_showContextMenu(const QPoint &)));\n    setSizePolicy(map->GetSizePolicy());\n}\n\nTFMapWidget::~TFMapWidget()\n{\n    for (TFMap *map : _maps) { delete map; }\n}\n\nvoid TFMapWidget::AddMap(TFMap *map)\n{\n    if (std::find(_maps.begin(), _maps.end(), map) == _maps.end()) {\n        map->_parent = this;\n        _maps.push_back(map);\n        connect(map, SIGNAL(Activated(TFMap *)), this, SLOT(_mapActivated(TFMap *)));\n    }\n}\n\nstd::vector<TFMap *> TFMapWidget::GetMaps() const { return _maps; }\n\nTFInfoWidget *TFMapWidget::GetInfoWidget()\n{\n    assert(_maps.size() == 1);\n    if (_maps.size()) return _maps[0]->GetInfoWidget();\n    return nullptr;\n}\n\nvoid TFMapWidget::Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams)\n{\n    for (auto map : _maps) map->Update(dataMgr, paramsMgr, rParams);\n}\n\nvoid TFMapWidget::Deactivate()\n{\n    for (auto map : _maps) map->LostFocus();\n}\n\nQSize TFMapWidget::minimumSizeHint() const\n{\n    QSize max(0, 0);\n    for (auto map : _maps) {\n        QSize s = map->minimumSizeHint();\n        max.setWidth(std::max(max.width(), s.width()));\n        max.setHeight(std::max(max.height(), s.height()));\n    }\n    return max;\n}\n\nvoid TFMapWidget::showMap(TFMap *map)\n{\n    map->_hidden = false;\n    show();\n}\n\nvoid TFMapWidget::hideMap(TFMap *map)\n{\n    map->_hidden = true;\n    int nHidden = 0;\n    for (TFMap *m : _maps)\n        if (m->_hidden) nHidden++;\n    if (nHidden == _maps.size()) hide();\n}\n\nvoid TFMapWidget::_mapActivated(TFMap *who)\n{\n    for (auto map : _maps)\n        if (map != who) map->LostFocus();\n\n    emit Activated(this);\n}\n\nvoid TFMapWidget::_showContextMenu(const QPoint &qp)\n{\n    vec2  p(qp.x(), qp.y());\n    QMenu menu(\"Context Menu\", this);\n\n    for (auto map : _maps) {\n        if (map->HasValidParams() && map->rect().contains(qp)) {\n            map->PopulateContextMenu(&menu, p);\n            menu.addSeparator();\n            map->PopulateSettingsMenu(&menu);\n            menu.addSeparator();\n        }\n    }\n\n    menu.exec(mapToGlobal(qp));\n}\n\n//#include <vapor/GLManager.h>\nvoid TFMapWidget::paintEvent(QPaintEvent *event)\n{\n    QWidget::paintEvent(event);\n    QPainter p(this);\n    p.setRenderHint(QPainter::Antialiasing);\n\n    //    void *s = VAPoR::GLManager::BeginTimer();\n    for (int i = _maps.size() - 1; i >= 0; i--) {\n        if (!_maps[i]->HasValidParams() || !_maps[i]->isLargeEnoughToPaint() || _maps[i]->_hidden) continue;\n        p.save();\n        _maps[i]->paintEvent(p);\n        p.restore();\n    }\n    //    printf(\"Paint took %fs\\n\", VAPoR::GLManager::EndTimer(s));\n}\n\nvoid TFMapWidget::mousePressEvent(QMouseEvent *event)\n{\n    if (event->button() == Qt::RightButton) return;    // Reserved for context menu\n\n    for (auto map : _maps) {\n        if (!map->HasValidParams() || map->_hidden) continue;\n        event->accept();\n        map->mousePressEvent(event);\n        if (event->isAccepted()) break;\n    }\n}\n\nvoid TFMapWidget::mouseReleaseEvent(QMouseEvent *event)\n{\n    if (event->button() == Qt::RightButton) return;    // Reserved for context menu\n\n    for (auto map : _maps) {\n        if (!map->HasValidParams() || map->_hidden) continue;\n        event->accept();\n        map->mouseReleaseEvent(event);\n        if (event->isAccepted()) break;\n    }\n}\n\nvoid TFMapWidget::mouseMoveEvent(QMouseEvent *event)\n{\n    if (event->button() == Qt::RightButton) return;    // Reserved for context menu\n\n    for (auto map : _maps) {\n        if (!map->HasValidParams() || map->_hidden) continue;\n        event->accept();\n        map->mouseMoveEvent(event);\n        if (event->isAccepted()) break;\n    }\n}\n\nvoid TFMapWidget::mouseDoubleClickEvent(QMouseEvent *event)\n{\n    if (event->button() == Qt::RightButton) return;    // Reserved for context menu\n\n    for (auto map : _maps) {\n        if (!map->HasValidParams() || map->_hidden) continue;\n        event->accept();\n        map->mouseDoubleClickEvent(event);\n        if (event->isAccepted()) break;\n    }\n}\n\nvoid TFMapWidget::resizeEvent(QResizeEvent *event)\n{\n    for (auto map : _maps) { map->resize(event->size().width(), event->size().height()); }\n}\n"
  },
  {
    "path": "apps/vaporgui/TFMapWidget.h",
    "content": "#pragma once\n\n#include <QFrame>\n#include <QMenu>\n#include <glm/glm.hpp>\n#include <vector>\n#include <string>\n#include <vapor/ParamsBase.h>\n\nnamespace VAPoR {\nclass DataMgr;\nclass ParamsMgr;\nclass RenderParams;\nclass MapperFunction;\n}    // namespace VAPoR\n\nclass TFInfoWidget;\nclass TFMapWidget;\n\n//! \\class TFMap\n//! A widget for editing a transfer function mapped value, for example opacity or color.\n//! They are not QWidgets because of limitations in Qt which do not allow widgets to be\n//! stacked on top of another with passthrough mouse events. Because of this, TFMapWidget\n//! manually holds TFMaps and manages such events.\n\nclass TFMap : public QObject {\n    Q_OBJECT\n\n    const std::string _variableNameTag;\n    TFMapWidget *     _parent = nullptr;\n    TFInfoWidget *    _infoWidget = nullptr;\n    int               _width = 0;\n    int               _height = 0;\n    bool              _insideSaveStateGroup = false;\n    bool              _hidden = false;\n\n    std::string _variableName;\n\n    VAPoR::DataMgr *     _dataMgr = nullptr;\n    VAPoR::ParamsMgr *   _paramsMgr = nullptr;\n    VAPoR::RenderParams *_renderParams = nullptr;\n\npublic:\n    TFMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr);\n\n    TFInfoWidget *GetInfoWidget();\n    void          Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams);\n    bool          HasValidParams() const;\n    bool          IsShown() const;\n    virtual void  LostFocus() = 0;\n    virtual QSize minimumSizeHint() const = 0;\n    virtual QSizePolicy GetSizePolicy() const;\n    //! (Right-click menu)\n    virtual void PopulateContextMenu(QMenu *menu, const glm::vec2 &p) {}\n    virtual void PopulateSettingsMenu(QMenu *menu) const {}\n\n    int  width() const { return _width; }\n    int  height() const { return _height; }\n    void resize(int width, int height);\n    //! Sometimes Qt tries painting a 0 sized widget\n    bool isLargeEnoughToPaint() const;\n    //! Returns the rect of the internal padded area\n    QRect       paddedRect() const;\n    QRect       rect() const;\n    const QFont getFont() const;\n\n    //! These map to the QWidget counterparts\n    void paintEvent(QPainter &p);\n    virtual void mousePressEvent(QMouseEvent *event);\n    virtual void mouseReleaseEvent(QMouseEvent *event);\n    virtual void mouseMoveEvent(QMouseEvent *event);\n    virtual void mouseDoubleClickEvent(QMouseEvent *event);\n\n    friend class TFMapWidget;\n\npublic slots:\n    //! These map to the QWidget counterparts\n    void update();\n    void show();\n    void hide();\n\nprotected:\n    virtual void _paintEvent(QPainter &p) = 0;\n    virtual void paramsUpdate() = 0;\n\n    VAPoR::DataMgr *       getDataMgr() const { return _dataMgr; }\n    VAPoR::ParamsMgr *     getParamsMgr() const { return _paramsMgr; }\n    VAPoR::RenderParams *  getRenderParams() const { return _renderParams; }\n    VAPoR::MapperFunction *getMapperFunction() const;\n    std::string            getVariableName() const;\n    const std::string &    getVariableNameTag() const;\n\n    void                  drawControl(QPainter &p, const QPointF &pos, bool selected = false) const;\n    virtual TFInfoWidget *createInfoWidget() = 0;\n\n    glm::vec2 NDCToPixel(const glm::vec2 &v) const;\n    QPointF   NDCToQPixel(const glm::vec2 &v) const;\n    QPointF   NDCToQPixel(float x, float y) const;\n    glm::vec2 PixelToNDC(const QPointF &p) const;\n    glm::vec2 PixelToNDC(const glm::vec2 &p) const;\n\n    virtual QMargins GetPadding() const;\n    int              GetControlPointRadius() const;\n\n    void BeginSaveStateGroup(VAPoR::ParamsMgr *paramsMgr, const std::string &description = \"\");\n    void EndSaveStateGroup(VAPoR::ParamsMgr *paramsMgr);\n    void CancelSaveStateGroup(VAPoR::ParamsMgr *paramsMgr);\n\nsignals:\n    //! Emittend when focus was gained\n    void Activated(TFMap *who);\n};\n\n//! \\class TFMapWidget\n//! Wrap a TFMap(s) in a QWidget\n\nclass TFMapWidget : public QWidget {\n    Q_OBJECT\n\n    std::vector<TFMap *> _maps;\n\npublic:\n    TFMapWidget(TFMap *map);\n    ~TFMapWidget();\n    void                 AddMap(TFMap *map);\n    std::vector<TFMap *> GetMaps() const;\n    TFInfoWidget *       GetInfoWidget();\n    void                 Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams);\n    void                 Deactivate();\n    QSize                minimumSizeHint() const override;\n    void                 showMap(TFMap *map);\n    void                 hideMap(TFMap *map);\n\nsignals:\n    void Activated(TFMapWidget *who);\n\nprivate slots:\n    void _mapActivated(TFMap *who);\n    void _showContextMenu(const QPoint &);\n\nprotected:\n    void paintEvent(QPaintEvent *event) override;\n    void mousePressEvent(QMouseEvent *event) override;\n    void mouseReleaseEvent(QMouseEvent *event) override;\n    void mouseMoveEvent(QMouseEvent *event) override;\n    void mouseDoubleClickEvent(QMouseEvent *event) override;\n    void resizeEvent(QResizeEvent *event) override;\n};\n"
  },
  {
    "path": "apps/vaporgui/TFMappingRangeSelector.cpp",
    "content": "#include \"TFMappingRangeSelector.h\"\n#include <vapor/RenderParams.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/DataMgrUtils.h>\n\nusing VAPoR::RenderParams;\n\nTFMappingRangeSelector::TFMappingRangeSelector(const std::string &variableNameTag) : _variableNameTag(variableNameTag)\n{\n    AllowCustomRange();\n\n    connect(this, SIGNAL(ValueChanged(float, float)), this, SLOT(_rangeChanged(float, float)));\n    connect(this, SIGNAL(ValueChangedBegin()), this, SLOT(_rangeChangedBegin()));\n    connect(this, SIGNAL(ValueChangedIntermediate(float, float)), this, SLOT(_rangeChangedIntermediate(float, float)));\n    connect(this, SIGNAL(RangeChanged(float, float)), this, SLOT(_sliderRangeChanged(float, float)));\n    connect(this, SIGNAL(RangeDefaultRequested()), this, SLOT(_sliderRangeResetToDefaultRequested()));\n}\n\nvoid TFMappingRangeSelector::Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams)\n{\n    _rParams = rParams;\n    _paramsMgr = paramsMgr;\n    if (!rParams || !paramsMgr || !dataMgr) return;\n    if (!dataMgr->VariableExists(rParams->GetCurrentTimestep(), _getVariableName())) return;\n\n    float min, max;\n    if (_getTF()->IsUsingCustomMappingSliderRange()) {\n        auto range = _getTF()->GetCustomMappingSliderRange();\n        min = range[0];\n        max = range[1];\n    } else {\n        _getDefaultRange(dataMgr, rParams, &min, &max);\n    }\n    SetRange(min, max);\n\n    vector<double> mapperRange = rParams->GetMapperFunc(_getVariableName())->getMinMaxMapValue();\n    SetValue(mapperRange[0], mapperRange[1]);\n}\n\nvoid TFMappingRangeSelector::_getDefaultRange(VAPoR::DataMgr *d, VAPoR::RenderParams *r, float *min, float *max) const\n{\n    if (r->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag).size() == 2) {\n        auto range = r->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag);\n        *min = range[0];\n        *max = range[1];\n    } else {\n        _getDataRange(d, r, min, max);\n    }\n}\n\nvoid TFMappingRangeSelector::_getDataRange(VAPoR::DataMgr *d, VAPoR::RenderParams *r, float *min, float *max) const\n{\n    VAPoR::CoordType minExt, maxExt;\n    r->GetBox()->GetExtents(minExt, maxExt);\n\n    std::vector<double> range;\n    d->GetDataRange(r->GetCurrentTimestep(), _getVariableName(), r->GetRefinementLevel(), r->GetCompressionLevel(), minExt, maxExt, range);\n    *min = range[0];\n    *max = range[1];\n}\n\nstd::string TFMappingRangeSelector::_getVariableName() const { return _rParams->GetValueString(_variableNameTag, \"\"); }\n\nVAPoR::MapperFunction *TFMappingRangeSelector::_getTF() const { return _rParams->GetMapperFunc(_getVariableName()); }\n\nvoid TFMappingRangeSelector::_rangeChangedBegin()\n{\n    if (!_rParams || !_paramsMgr) return;\n\n    _paramsMgr->BeginSaveStateGroup(\"Change tf mapping range\");\n    _insideIntermediateChangeGroup = true;\n}\n\nvoid TFMappingRangeSelector::_rangeChangedIntermediate(float left, float right)\n{\n    if (!_rParams || !_paramsMgr) return;\n\n    _rParams->GetMapperFunc(_getVariableName())->setMinMaxMapValue(left, right);\n\n    //    _maps->histo->update();\n\n    _paramsMgr->IntermediateChange();\n}\n\nvoid TFMappingRangeSelector::_rangeChanged(float left, float right)\n{\n    if (!_rParams || !_paramsMgr) return;\n\n    _rParams->GetMapperFunc(_getVariableName())->setMinMaxMapValue(left, right);\n    if (_insideIntermediateChangeGroup)\n        _paramsMgr->EndSaveStateGroup();\n    _insideIntermediateChangeGroup = false;\n}\n\nvoid TFMappingRangeSelector::_sliderRangeChanged(float left, float right)\n{\n    _paramsMgr->BeginSaveStateGroup(\"Enable custom tf slider range\");\n    _getTF()->SetUsingCustomMappingSliderRange(true);\n    _getTF()->SetCustomMappingSliderRange({left, right});\n    _paramsMgr->EndSaveStateGroup();\n}\n\nvoid TFMappingRangeSelector::_sliderRangeResetToDefaultRequested() { _getTF()->SetUsingCustomMappingSliderRange(false); }\n"
  },
  {
    "path": "apps/vaporgui/TFMappingRangeSelector.h",
    "content": "#pragma once\n\n#include \"QRangeSliderTextCombo.h\"\n#include <string>\n\nnamespace VAPoR {\nclass DataMgr;\nclass ParamsMgr;\nclass RenderParams;\nclass MapperFunction;\n}    // namespace VAPoR\n\nclass TFMappingRangeSelector : public QRangeSliderTextCombo {\n    Q_OBJECT\n\npublic:\n    TFMappingRangeSelector(const std::string &variableNameTag);\n    void Update(VAPoR::DataMgr *dataMgr, VAPoR::ParamsMgr *paramsMgr, VAPoR::RenderParams *rParams);\n\nprivate:\n    VAPoR::RenderParams *_rParams = nullptr;\n    VAPoR::ParamsMgr *   _paramsMgr = nullptr;\n    const std::string &  _variableNameTag;\n    bool                 _insideIntermediateChangeGroup = false;\n\n    void                   _getDefaultRange(VAPoR::DataMgr *dataMgr, VAPoR::RenderParams *rParams, float *min, float *max) const;\n    void                   _getDataRange(VAPoR::DataMgr *dataMgr, VAPoR::RenderParams *rParams, float *min, float *max) const;\n    std::string            _getVariableName() const;\n    VAPoR::MapperFunction *_getTF() const;\n\nprivate slots:\n    void _rangeChangedBegin();\n    void _rangeChangedIntermediate(float left, float right);\n    void _rangeChanged(float left, float right);\n    void _sliderRangeChanged(float left, float right);\n    void _sliderRangeResetToDefaultRequested();\n};\n"
  },
  {
    "path": "apps/vaporgui/TFOpacityInfoWidget.cpp",
    "content": "#include \"TFOpacityInfoWidget.h\"\n#include <QBoxLayout>\n#include <QLabel>\n#include <QPainter>\n#include <QDoubleValidator>\n#include <vapor/RenderParams.h>\n#include \"VLineItem.h\"\n\nTFOpacityInfoWidget::TFOpacityInfoWidget(const std::string &variableNameTag) : TFInfoWidget(variableNameTag)\n{\n    ((QBoxLayout *)layout())->addWidget(new VLineItem(\"Opacity\", _opacityEdit = new VDoubleLineEdit));\n\n    _opacityEdit->SetRange(0, 1);\n    connect(_opacityEdit, &VDoubleLineEdit::ValueChanged, this, &TFOpacityInfoWidget::opacityEditChanged);\n}\n\nvoid TFOpacityInfoWidget::DeselectControlPoint()\n{\n    TFInfoWidget::DeselectControlPoint();\n    _opacityEdit->Clear();\n}\n\nvoid TFOpacityInfoWidget::SetOpacity(float opacity)\n{\n    _opacity = opacity;\n    updateOpacity();\n}\n\nvoid TFOpacityInfoWidget::SetControlPoint(float value, float opacity)\n{\n    this->setEnabled(true);\n    SetNormalizedValue(value);\n    SetOpacity(opacity);\n}\n\nvoid TFOpacityInfoWidget::updateOpacity()\n{\n    if (!isEnabled()) return;\n\n    _opacityEdit->SetValueDouble(_opacity);\n}\n\nfloat TFOpacityInfoWidget::getOpacityFromEdit() const { return _opacityEdit->GetValueDouble(); }\n\nvoid TFOpacityInfoWidget::controlPointChanged() { emit ControlPointChanged(_value, _opacity); }\n\nvoid TFOpacityInfoWidget::opacityEditChanged()\n{\n    _opacity = getOpacityFromEdit();\n    controlPointChanged();\n}\n"
  },
  {
    "path": "apps/vaporgui/TFOpacityInfoWidget.h",
    "content": "#pragma once\n\n#include \"TFInfoWidget.h\"\n#include <VDoubleLineEdit.h>\n\nnamespace VAPoR {\nclass RenderParams;\n}\n\nclass TFOpacityInfoWidget : public TFInfoWidget {\n    Q_OBJECT\n\npublic:\n    TFOpacityInfoWidget(const std::string &variableNameTag);\n\npublic:\n    void SetOpacity(float opacity);\n\nprotected:\n    void  updateOpacity();\n    float getOpacityFromEdit() const;\n\n    void controlPointChanged();\n\nprivate:\n    VDoubleLineEdit *_opacityEdit;\n\n    float _opacity;\n\nsignals:\n    void ControlPointChanged(float value, float opacity);\n\npublic slots:\n    void SetControlPoint(float value, float opacity);\n    void DeselectControlPoint();\n\nprivate slots:\n    void opacityEditChanged();\n};\n"
  },
  {
    "path": "apps/vaporgui/TFOpacityWidget.cpp",
    "content": "#include \"TFOpacityWidget.h\"\n#include <QPaintEvent>\n#include <QPainter>\n#include <QAction>\n#include <glm/glm.hpp>\n#include <vapor/RenderParams.h>\n#include <vapor/ParamsMgr.h>\n#include \"TFOpacityInfoWidget.h\"\n#include \"TFUtils.h\"\n\nusing namespace VAPoR;\nusing glm::clamp;\nusing glm::vec2;\nusing std::vector;\n\nstatic vec2    qvec2(const QPoint &qp) { return vec2(qp.x(), qp.y()); }\nstatic vec2    qvec2(const QPointF &qp) { return vec2(qp.x(), qp.y()); }\nstatic QPointF qvec2(const vec2 &v) { return QPointF(v.x, v.y); }\n\nstatic vec2 Project(vec2 a, vec2 b, vec2 p)\n{\n    vec2  n = glm::normalize(b - a);\n    float t = glm::dot(n, p - a);\n\n    return n * t + a;\n}\n\nstatic float DistanceToLine(vec2 a, vec2 b, vec2 p)\n{\n    vec2  n = glm::normalize(b - a);\n    float t = glm::dot(n, p - a);\n\n    if (t < 0) return glm::distance(a, p);\n    if (t > glm::distance(a, b)) return glm::distance(b, p);\n\n    vec2 projection = n * t + a;\n    return glm::distance(projection, p);\n}\n\n#define CONTROL_POINT_RADIUS (4.0f)\n#define PADDING              (CONTROL_POINT_RADIUS + 1.0f)\n\nTFOpacityMap::TFOpacityMap(const std::string &variableNameTag, TFMapWidget *parent) : TFMap(variableNameTag, parent) {}\n\nQSize TFOpacityMap::minimumSizeHint() const { return QSize(100, 75); }\n\nvoid TFOpacityMap::LostFocus() { DeselectControlPoint(); }\n\n#define PROPERTY_INDEX    (\"index\")\n#define PROPERTY_LOCATION (\"location\")\n\nvoid TFOpacityMap::PopulateContextMenu(QMenu *menu, const glm::vec2 &p)\n{\n    auto selected = findSelectedControlPoint(p);\n\n    if (selected != _controlPoints.EndPoints())\n        menu->addAction(\"Delete control point\", this, SLOT(menuDeleteSelectedControlPoint()))->setProperty(PROPERTY_INDEX, QVariant(selected.Index()));\n    else\n        menu->addAction(\"Add control point\", this, SLOT(menuAddControlPoint()))->setProperty(PROPERTY_LOCATION, QVariant(qvec2(PixelToNDC(p))));\n}\n\nvoid TFOpacityMap::PopulateSettingsMenu(QMenu *menu) const\n{\n    menu->addAction(\"Save Transfer Function\", this, SLOT(menuSave()));\n    menu->addAction(\"Load Transfer Function\", this, SLOT(menuLoad()));\n}\n\nvoid TFOpacityMap::paramsUpdate()\n{\n    MapperFunction *mf = getRenderParams()->GetMapperFunc(getVariableName());\n    // TODO Multiple opacity maps?\n    //    int n = mf->getNumOpacityMaps();\n    //    printf(\"# opacity maps = %i\\n\", n);\n\n    OpacityMap *om = mf->GetOpacityMap(0);\n\n    vector<double> cp = om->GetControlPoints();\n    _controlPoints.Resize(cp.size() / 2);\n    for (int i = 0; i < cp.size(); i += 2) {\n        _controlPoints[i / 2].y = cp[i];\n        _controlPoints[i / 2].x = cp[i + 1];\n    }\n    update();\n\n    if (_selectedControl > -1) UpdateInfo(_controlPoints[_selectedControl].x, _controlPoints[_selectedControl].y);\n}\n\nTFInfoWidget *TFOpacityMap::createInfoWidget()\n{\n    TFOpacityInfoWidget *info = new TFOpacityInfoWidget(getVariableNameTag());\n\n    connect(info, SIGNAL(ControlPointChanged(float, float)), this, SLOT(UpdateFromInfo(float, float)));\n    connect(this, SIGNAL(UpdateInfo(float, float)), info, SLOT(SetControlPoint(float, float)));\n    connect(this, SIGNAL(ControlPointDeselected()), info, SLOT(DeselectControlPoint()));\n\n    return info;\n}\n\nvoid TFOpacityMap::_paintEvent(QPainter &p)\n{\n    //    p.setViewport(10, 10, 30, 30);\n    //    p.setWindow(10, 10, 30, 30);\n\n    //    p.fillRect(event->rect(), QBrush(QColor(64, 32, 64)));\n\n    if (_controlPoints.Size()) {\n        ControlPointList &cp = _controlPoints;\n\n        for (auto it = cp.BeginLines(); it != cp.EndLines(); ++it) {\n            p.drawLine(NDCToQPixel(it.a()), NDCToQPixel(it.b()));\n\n            //            p.drawEllipse(qvec2(Project(NDCToPixel(it.a()), NDCToPixel(it.b()), m)), 2, 2);\n        }\n\n        for (auto it = --cp.EndPoints(); it != --cp.BeginPoints(); --it) drawControl(p, NDCToQPixel(*it), it.Index() == _selectedControl);\n    }\n}\n\nvoid TFOpacityMap::mousePressEvent(QMouseEvent *event)\n{\n    emit Activated(this);\n    vec2 mouse = qvec2(event->localPos());\n    auto it = findSelectedControlPoint(mouse);\n    auto lineIt = findSelectedControlLine(mouse);\n\n    if (it != _controlPoints.EndPoints()) {\n        _draggedControl = it;\n        _dragOffset = NDCToPixel(*it) - mouse;\n        _isDraggingControl = true;\n        selectControlPoint(it);\n        getParamsMgr()->BeginSaveStateGroup(\"Move opacity control point\");\n    } else if (lineIt != _controlPoints.EndLines()) {\n        _draggedLine = lineIt;\n        _dragOffset = NDCToPixel(lineIt.a()) - mouse;\n        _dragOffsetB = NDCToPixel(lineIt.b()) - mouse;\n        _isDraggingLine = true;\n        getParamsMgr()->BeginSaveStateGroup(\"Move opacity control line\");\n    } else {\n        DeselectControlPoint();\n        event->ignore();\n    }\n}\n\nvoid TFOpacityMap::mouseReleaseEvent(QMouseEvent *event)\n{\n    if (_isDraggingControl || _isDraggingLine) {\n        opacityChanged();\n        getParamsMgr()->EndSaveStateGroup();\n    } else\n        event->ignore();\n    _isDraggingControl = false;\n    _isDraggingLine = false;\n}\n\nvoid TFOpacityMap::mouseMoveEvent(QMouseEvent *event)\n{\n    vec2 mouse = qvec2(event->pos());\n    m = mouse;\n    //    const int i = _draggedID;\n    //    ControlPointList &cp = _controlPoints;\n    //    const int N = cp.Size();\n\n    if (_isDraggingControl) {\n        const auto &it = _draggedControl;\n        vec2        newVal = glm::clamp(PixelToNDC(mouse + _dragOffset), vec2(it.IsFirst() ? 0 : (*(it - 1)).x, 0), vec2(it.IsLast() ? 1 : (*(it + 1)).x, 1));\n\n        *_draggedControl = newVal;\n        emit UpdateInfo(newVal.x, newVal.y);\n        update();\n        opacityChanged();\n        getParamsMgr()->IntermediateChange();\n    } else if (_isDraggingLine) {\n        auto &it = _draggedLine;\n        it.setA(glm::clamp(PixelToNDC(mouse + _dragOffset), vec2(it.IsFirst() ? 0 : (it - 1).a().x, 0), vec2(it.IsLast() ? 1 : (it + 1).b().x, 1)));\n        it.setB(glm::clamp(PixelToNDC(mouse + _dragOffsetB), vec2(it.IsFirst() ? 0 : (it - 1).a().x, 0), vec2(it.IsLast() ? 1 : (it + 1).b().x, 1)));\n        update();\n        opacityChanged();\n        getParamsMgr()->IntermediateChange();\n    } else {\n        event->ignore();\n    }\n}\n\nvoid TFOpacityMap::mouseDoubleClickEvent(QMouseEvent *event)\n{\n    vec2              mouse = qvec2(event->pos());\n    ControlPointList &cp = _controlPoints;\n\n    auto controlPointIt = findSelectedControlPoint(mouse);\n    if (controlPointIt != cp.EndPoints()) {\n        deleteControlPoint(controlPointIt);\n        return;\n    }\n\n    auto controlLineIt = findSelectedControlLine(mouse);\n    if (controlLineIt != cp.EndLines()) {\n        const vec2 a = NDCToPixel(controlLineIt.a());\n        const vec2 b = NDCToPixel(controlLineIt.b());\n        addControlPoint(PixelToNDC(Project(a, b, mouse)));\n        return;\n    }\n\n    event->ignore();\n}\n\nvoid TFOpacityMap::opacityChanged()\n{\n    if (!getRenderParams()) return;\n\n    MapperFunction *mf = getRenderParams()->GetMapperFunc(getVariableName());\n\n    OpacityMap *om = mf->GetOpacityMap(0);\n\n    vector<double> cp(_controlPoints.Size() * 2);\n    for (int i = 0; i < _controlPoints.Size(); i++) {\n        cp[i * 2] = _controlPoints[i].y;\n        cp[i * 2 + 1] = _controlPoints[i].x;\n    }\n    om->SetControlPoints(cp);\n}\n\nbool TFOpacityMap::controlPointContainsPixel(const vec2 &cp, const vec2 &pixel) const { return glm::distance(pixel, NDCToPixel(cp)) <= GetControlPointRadius(); }\n\nControlPointList::PointIterator TFOpacityMap::findSelectedControlPoint(const glm::vec2 &mouse)\n{\n    const auto end = _controlPoints.EndPoints();\n    for (auto it = _controlPoints.BeginPoints(); it != end; ++it)\n        if (controlPointContainsPixel(*it, mouse)) return it;\n    return end;\n}\n\nControlPointList::LineIterator TFOpacityMap::findSelectedControlLine(const glm::vec2 &mouse)\n{\n    ControlPointList &cp = _controlPoints;\n    const float       radius = GetControlPointRadius();\n\n    for (auto it = cp.BeginLines(); it != cp.EndLines(); ++it) {\n        const vec2 a = NDCToPixel(it.a());\n        const vec2 b = NDCToPixel(it.b());\n\n        if (DistanceToLine(a, b, mouse) <= radius) return it;\n    }\n    return cp.EndLines();\n}\n\nvoid TFOpacityMap::selectControlPoint(ControlPointList::PointIterator it)\n{\n    _selectedControl = it.Index();\n    update();\n    emit UpdateInfo((*it).x, (*it).y);\n}\n\nvoid TFOpacityMap::deleteControlPoint(ControlPointList::PointIterator it)\n{\n    if (_isDraggingControl || _isDraggingLine) {\n        getParamsMgr()->EndSaveStateGroup();\n        _isDraggingControl = false;\n        _isDraggingLine = false;\n    }\n\n    if (_selectedControl == it.Index())\n        DeselectControlPoint();\n    else if (_selectedControl > it.Index())\n        _selectedControl--;\n\n    _controlPoints.Remove(it);\n    update();\n    opacityChanged();\n}\n\nvoid TFOpacityMap::addControlPoint(const glm::vec2 &ndc)\n{\n    ControlPointList &cp = _controlPoints;\n    int               index = cp.Add(ndc);\n    selectControlPoint(cp.BeginPoints() + index);\n    update();\n    opacityChanged();\n}\n\nvoid TFOpacityMap::menuDeleteSelectedControlPoint()\n{\n    emit     Activated(this);\n    QVariant indexVariant = sender()->property(PROPERTY_INDEX);\n    if (indexVariant.isValid()) {\n        int index = indexVariant.toInt();\n        if (index >= 0 && index < _controlPoints.Size()) deleteControlPoint(_controlPoints.BeginPoints() + index);\n    }\n}\n\nvoid TFOpacityMap::menuAddControlPoint()\n{\n    emit     Activated(this);\n    QVariant location = sender()->property(PROPERTY_LOCATION);\n    if (location.isValid()) addControlPoint(qvec2(location.toPointF()));\n}\n\nvoid TFOpacityMap::menuLoad()\n{\n    RenderParams *rp = getRenderParams();\n    if (!rp) return;\n    TFUtils::LoadTransferFunction(getParamsMgr(), rp->GetMapperFunc(getVariableName()));\n}\n\nvoid TFOpacityMap::menuSave()\n{\n    RenderParams *rp = getRenderParams();\n    if (!rp) return;\n    TFUtils::SaveTransferFunction(getParamsMgr(), rp->GetMapperFunc(getVariableName()));\n}\n\nvoid TFOpacityMap::DeselectControlPoint()\n{\n    _selectedControl = -1;\n    update();\n    emit ControlPointDeselected();\n}\n\nvoid TFOpacityMap::UpdateFromInfo(float value, float opacity)\n{\n    assert(_selectedControl >= 0);\n    assert(value >= 0 && value <= 1);\n    assert(opacity >= 0 && opacity <= 1);\n\n    _controlPoints.Remove(_controlPoints.BeginPoints() + _selectedControl);\n    _selectedControl = _controlPoints.Add(vec2(value, opacity));\n\n    opacityChanged();\n}\n\nTFOpacityWidget::TFOpacityWidget(const std::string &variableNameTag) : TFMapWidget(new TFOpacityMap(variableNameTag, this))\n{\n    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);\n    // this->setFrameStyle(QFrame::Box);\n}\n"
  },
  {
    "path": "apps/vaporgui/TFOpacityWidget.h",
    "content": "#pragma once\n\n#include \"TFMapWidget.h\"\n#include <vapor/VAssert.h>\n#include <glm/glm.hpp>\n\nclass ControlPointList {\npublic:\n    class PointIterator {\n        ControlPointList *list;\n        int               i;\n\n        PointIterator(ControlPointList *list, int i) : list(list), i(i) {}\n\n    public:\n        PointIterator() {}\n        PointIterator &operator++()\n        {\n            ++i;\n            return *this;\n        }\n        PointIterator &operator--()\n        {\n            --i;\n            return *this;\n        }\n        PointIterator operator+(int x) const { return PointIterator(list, i + x); }\n        PointIterator operator-(int x) const { return PointIterator(list, i - x); }\n        glm::vec2 &   operator*() { return (*list)[i]; }\n        bool          operator!=(const PointIterator &other) { return !(*this == other); }\n        bool          operator==(const PointIterator &other) { return other.list == this->list && other.i == this->i; }\n\n        bool IsFirst() const { return i == 0; }\n        bool IsLast() const { return i == list->Size() - 1; }\n        int  Index() const { return i; }\n\n        friend class ControlPointList;\n    };\n\n    class LineIterator : public PointIterator {\n        using PointIterator::PointIterator;\n\n    public:\n        glm::vec2 &operator*() = delete;\n        //        bool IsFirst() const = delete;\n        //        bool IsLast() const = delete;\n        bool         IsLast() const { return i == list->Size(); }\n        LineIterator operator+(int x) const { return LineIterator(list, i + x); }\n        LineIterator operator-(int x) const { return LineIterator(list, i - x); }\n\n        const glm::vec2 a()\n        {\n            if (i == 0) return glm::vec2(0, (*list)[0].y);\n            return (*list)[i - 1];\n        }\n        const glm::vec2 b()\n        {\n            if (i == list->SizeLines() - 1) return glm::vec2(1, (*list)[list->Size() - 1].y);\n            return (*list)[i];\n        }\n        void setA(const glm::vec2 &v)\n        {\n            if (i != 0) (*list)[i - 1] = v;\n        }\n        void setB(const glm::vec2 &v)\n        {\n            if (i != list->SizeLines() - 1) (*list)[i] = v;\n        }\n\n        friend class ControlPointList;\n    };\n\n    std::vector<glm::vec2> _points;\n\npublic:\n    glm::vec2 &operator[](const int i)\n    {\n        VAssert(i >= 0 && i < _points.size());\n        return _points[i];\n    }\n\n    int Add(const glm::vec2 &v)\n    {\n        for (int i = 0; i < _points.size(); i++)\n            if (_points[i].x > v.x) return Add(v, i);\n\n        return Add(v, Size());\n    }\n\n    int Add(const glm::vec2 &v, const int i)\n    {\n        VAssert(i >= 0 && i <= _points.size());\n        glm::vec2 vClamped = glm::clamp(v, glm::vec2(0, 0), glm::vec2(1, 1));\n        _points.insert(_points.begin() + i, vClamped);\n        return i;\n    }\n\n    int Add(const glm::vec2 &v, const LineIterator &line)\n    {\n        VAssert(line.i >= 0 && line.i <= _points.size());\n        _points.insert(_points.begin() + line.i, v);\n        return line.i;\n    }\n\n    void Remove(const PointIterator &point)\n    {\n        VAssert(point.i >= 0 && point.i < _points.size());\n        if (Size() > 1) _points.erase(_points.begin() + point.i);\n    }\n\n    int  Size() const { return _points.size(); }\n    int  SizeLines() const { return Size() + 1; }\n    void Resize(int n) { _points.resize(n); }\n\n    PointIterator BeginPoints() { return PointIterator(this, 0); }\n    PointIterator EndPoints() { return PointIterator(this, Size()); }\n    LineIterator  BeginLines() { return LineIterator(this, 0); }\n    LineIterator  EndLines() { return LineIterator(this, SizeLines()); }\n};\n\nclass TFOpacityMap : public TFMap {\n    Q_OBJECT\n\npublic:\n    TFOpacityMap(const std::string &variableNameTag, TFMapWidget *parent = nullptr);\n\n    QSize minimumSizeHint() const override;\n    void  LostFocus() override;\n    void  PopulateContextMenu(QMenu *menu, const glm::vec2 &p) override;\n    void  PopulateSettingsMenu(QMenu *menu) const override;\n\nprotected:\n    void          paramsUpdate() override;\n    TFInfoWidget *createInfoWidget() override;\n    void          _paintEvent(QPainter &p) override;\n    void          mousePressEvent(QMouseEvent *event) override;\n    void          mouseReleaseEvent(QMouseEvent *event) override;\n    void          mouseMoveEvent(QMouseEvent *event) override;\n    void          mouseDoubleClickEvent(QMouseEvent *event) override;\n\nprivate:\n    ControlPointList                _controlPoints;\n    bool                            _isDraggingControl = false;\n    bool                            _isDraggingLine = false;\n    ControlPointList::PointIterator _draggedControl;\n    ControlPointList::LineIterator  _draggedLine;\n    glm::vec2                       _dragOffset;\n    glm::vec2                       _dragOffsetB;\n    glm::vec2                       m;\n    int                             _selectedControl = -1;\n\n    void opacityChanged();\n\n    bool                            controlPointContainsPixel(const glm::vec2 &cp, const glm::vec2 &pixel) const;\n    ControlPointList::PointIterator findSelectedControlPoint(const glm::vec2 &mouse);\n    ControlPointList::LineIterator  findSelectedControlLine(const glm::vec2 &mouse);\n\n    void selectControlPoint(ControlPointList::PointIterator it);\n    void deleteControlPoint(ControlPointList::PointIterator it);\n    void addControlPoint(const glm::vec2 &ndc);\n\nsignals:\n    void ControlPointDeselected();\n    void UpdateInfo(float value, float opacity);\n\npublic slots:\n    void DeselectControlPoint();\n    void UpdateFromInfo(float value, float opacity);\n\nprivate slots:\n    void menuDeleteSelectedControlPoint();\n    void menuAddControlPoint();\n    void menuLoad();\n    void menuSave();\n};\n\nclass TFOpacityWidget : public TFMapWidget {\n    Q_OBJECT\npublic:\n    TFOpacityWidget(const std::string &variableNameTag);\n};\n"
  },
  {
    "path": "apps/vaporgui/TFUtils.cpp",
    "content": "#include \"TFUtils.h\"\n#include <vapor/MapperFunction.h>\n#include <vapor/FileUtils.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/SettingsParams.h>\n#include \"ErrorReporter.h\"\n#include <QFileDialog>\n#include <cassert>\n\nvoid TFUtils::LoadColormap(VAPoR::MapperFunction *tf, const std::string &path)\n{\n    int rc = tf->LoadColormapFromFile(path);\n\n    if (rc < 0) MSG_ERR(\"Failed to load transfer function\");\n}\n\nvoid TFUtils::LoadColormap(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf)\n{\n    assert(paramsMgr);\n\n    SettingsParams *sp = (SettingsParams *)paramsMgr->GetParams(SettingsParams::GetClassType());\n\n    QString qDefaultDirectory = QString::fromStdString(sp->GetSessionDir());\n    QString qSelectedPath = QFileDialog::getOpenFileName(nullptr, \"Select a .tf3 file\", qDefaultDirectory, \"Vapor Transfer Function (*.tf3)\");\n    if (qSelectedPath.isNull()) return;\n\n    string selectedPath = qSelectedPath.toStdString();\n    sp->SetSessionDir(Wasp::FileUtils::Dirname(selectedPath));\n\n    LoadColormap(tf, selectedPath);\n}\n\nvoid TFUtils::LoadTransferFunction(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf)\n{\n    SettingsParams *sp = (SettingsParams *)paramsMgr->GetParams(SettingsParams::GetClassType());\n\n    QString qDefaultDirectory = QString::fromStdString(sp->GetSessionDir());\n    QString qSelectedPath = QFileDialog::getOpenFileName(nullptr, \"Select a .tf3 file\", qDefaultDirectory, \"Vapor Transfer Function (*.tf3)\");\n    if (qSelectedPath.isNull()) return;\n\n    string selectedPath = qSelectedPath.toStdString();\n    sp->SetSessionDir(FileUtils::Dirname(selectedPath));\n\n    int rc = tf->LoadFromFile(selectedPath);\n\n    if (rc < 0) MSG_ERR(\"Failed to load transfer function\");\n}\n\nvoid TFUtils::SaveTransferFunction(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf)\n{\n    SettingsParams *sp = (SettingsParams *)paramsMgr->GetParams(SettingsParams::GetClassType());\n\n    QString qDefaultDirectory = QString::fromStdString(sp->GetSessionDir());\n    QString qSelectedPath = QFileDialog::getSaveFileName(nullptr, \"Select a .tf3 file\", qDefaultDirectory, \"Vapor Transfer Function (*.tf3)\", 0);\n    if (qSelectedPath.isNull()) return;\n    string selectedPath = qSelectedPath.toStdString();\n\n    if (FileUtils::Extension(selectedPath) != \"tf3\") selectedPath += \".tf3\";\n\n    sp->SetSessionDir(FileUtils::Dirname(selectedPath));\n\n    int rc = tf->SaveToFile(selectedPath);\n\n    if (rc < 0) MSG_ERR(\"Failed to save transfer function\");\n}\n"
  },
  {
    "path": "apps/vaporgui/TFUtils.h",
    "content": "#pragma once\n\n#include <string>\n\nnamespace VAPoR {\nclass MapperFunction;\nclass ParamsMgr;\n}    // namespace VAPoR\n\nnamespace TFUtils {\nvoid LoadColormap(VAPoR::MapperFunction *tf, const std::string &path);\nvoid LoadColormap(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf);\nvoid LoadTransferFunction(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf);\nvoid SaveTransferFunction(VAPoR::ParamsMgr *paramsMgr, VAPoR::MapperFunction *tf);\n}    // namespace TFUtils\n"
  },
  {
    "path": "apps/vaporgui/TwoDDataEventRouter.cpp",
    "content": "#include \"TwoDDataEventRouter.h\"\n#include \"vapor/TwoDDataParams.h\"\n#include \"PWidgets.h\"\n#include \"PMetadataClasses.h\"\n\nusing namespace VAPoR;\n\nstatic RenderEventRouterRegistrar<TwoDDataEventRouter> registrar(TwoDDataEventRouter::GetClassType());\n\nTwoDDataEventRouter::TwoDDataEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, TwoDDataParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PScalarVariableSelector,\n            new PHeightVariableSelector\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    AddAppearanceSubtab(new PGroup({\n        new PTFEditor,\n        new PCheckbox(RenderParams::DrawInFrontTag, \"Draw renderer in front\")\n    }));\n    AddGeometrySubtab(new PGeometrySubtab);\n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nstring TwoDDataEventRouter::_getDescription() const\n{\n    return (\"Displays \"\n            \"the user's 2D data variables along the plane described by the source data \"\n            \"file.\\n\\nThese 2D variables may be offset by a height variable.\\n\\n\");\n}\n"
  },
  {
    "path": "apps/vaporgui/TwoDDataEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include \"vapor/TwoDDataRenderer.h\"\n\n//! \\class TwoDDataEventRouter\n//! \\ingroup Public_GUI\n//! \\brief TwoDData Renderer GUI\n//! \\author Stas Jaroszynski\n\nclass TwoDDataEventRouter : public RenderEventRouterGUI {\npublic:\n    TwoDDataEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::TwoDDataRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return true; }\n    bool          Supports3DVariables() const { return false; }\n\nprotected:\n    string _getDescription() const;\n    string _getSmallIconImagePath() const { return \"TwoDData_small.png\"; }\n    string _getIconImagePath() const { return \"TwoDData.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/UCloseVDCMenu.cpp",
    "content": "#include \"UCloseVDCMenu.h\"\n#include <vapor/ControlExecutive.h>\n#include <vapor/GUIStateParams.h>\n\n\nUCloseVDCMenu::UCloseVDCMenu(QMenu *parent, ControlExec *ce)\n: QMenu(\"Close Dataset\", parent), _ce(ce)\n{ parent->addMenu(this); }\n\n\nvoid UCloseVDCMenu::Update()\n{\n    this->clear();\n    vector<string> dataSetNames = _ce->GetParams<GUIStateParams>()->GetOpenDataSetNames();\n    if (dataSetNames.empty()) {\n        this->setEnabled(false); // This doesn't really work on macOS (qt bug)\n    } else {\n        this->setEnabled(true);\n        for (const auto &name : dataSetNames)\n            this->addAction(QString::fromStdString(name), [this, name](){ _ce->CloseData(name); });\n    }\n}"
  },
  {
    "path": "apps/vaporgui/UCloseVDCMenu.h",
    "content": "#pragma once\n#include <QMenu>\n#include \"Updatable.h\"\n#include <common.h>\n\nclass UCloseVDCMenu : public QMenu, public Updatable{\n    Q_OBJECT\n    ControlExec * const _ce;\n\npublic:\n    UCloseVDCMenu(QMenu *parent, ControlExec *ce);\n    void Update() override;\n};\n"
  },
  {
    "path": "apps/vaporgui/UWidget.cpp",
    "content": "#include \"UWidget.h\"\n"
  },
  {
    "path": "apps/vaporgui/UWidget.h",
    "content": "#pragma once\n\n#include \"VContainer.h\"\n#include \"ParamsUpdatable.h\"\n\n//! \\class UWidget\n//! \\brief A widget that standardizes support for params updates.\n//! \\author Stas Jaroszynski\n\nclass UWidget : public VContainer, public ParamsUpdatable {\npublic:\n    using VContainer::VContainer;\n};\n"
  },
  {
    "path": "apps/vaporgui/Updatable.h",
    "content": "#pragma once\n\n#include <common.h>\n\nclass Updatable {\npublic:\n    virtual void Update() = 0;\n};\n"
  },
  {
    "path": "apps/vaporgui/V3DInput.cpp",
    "content": "#include \"V3DInput.h\"\n#include <QHBoxLayout>\n#include <QLabel>\n#include \"VDoubleLineEdit.h\"\n#include <vapor/VAssert.h>\n\nV3DInput::V3DInput()\n{\n    QHBoxLayout *layout = new QHBoxLayout;\n    layout->setMargin(0);\n    setLayout(layout);\n\n    layout->addWidget(new QLabel(\"X\"));\n    layout->addWidget(_x = new VDoubleLineEdit);\n    layout->addWidget(new QLabel(\"Y\"));\n    layout->addWidget(_y = new VDoubleLineEdit);\n    layout->addWidget(new QLabel(\"Z\"));\n    layout->addWidget(_z = new VDoubleLineEdit);\n\n    for (auto input : {_x, _y, _z}) QObject::connect(input, &VDoubleLineEdit::ValueChanged, this, &V3DInput::axisValueChanged);\n}\n\nvoid V3DInput::SetValue(double x, double y, double z)\n{\n    _x->SetValueDouble(x);\n    _y->SetValueDouble(y);\n    _z->SetValueDouble(z);\n}\n\nvoid V3DInput::SetValue(const std::vector<double> &xyz)\n{\n    VAssert(xyz.size() == 3);\n    SetValue(xyz[0], xyz[1], xyz[2]);\n}\n\nvoid V3DInput::SetValue(const double xyz[3]) { SetValue(xyz[0], xyz[1], xyz[2]); }\n\nvoid V3DInput::GetValue(double xyz[3]) const\n{\n    xyz[0] = _x->GetValueDouble();\n    xyz[1] = _y->GetValueDouble();\n    xyz[2] = _z->GetValueDouble();\n}\n\nstd::vector<double> V3DInput::GetValue() const\n{\n    std::vector<double> v(3);\n    GetValue(v.data());\n    return v;\n}\n\nvoid V3DInput::axisValueChanged(double)\n{\n    double x = _x->GetValueDouble();\n    double y = _y->GetValueDouble();\n    double z = _z->GetValueDouble();\n\n    emit ValueChanged(x, y, z);\n    emit ValueChangedVec(std::vector<double>{x, y, z});\n}\n"
  },
  {
    "path": "apps/vaporgui/V3DInput.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include <vector>\n\nclass VDoubleLineEdit;\n\n//! \\class V3DInput\n//! \\brief Widget that allows the user to specify a 3D point.\n//! \\author Stas Jaroszynski\n\nclass V3DInput : public QWidget {\n    Q_OBJECT\n\n    VDoubleLineEdit *_x, *_y, *_z;\n\npublic:\n    V3DInput();\n    void SetValue(double x, double y, double z);\n    void SetValue(const std::vector<double> &xyz);\n    void                SetValue(const double xyz[3]);\n    void                GetValue(double xyz[3]) const;\n    std::vector<double> GetValue() const;\n\nsignals:\n    void ValueChanged(double x, double y, double z);\n    void ValueChangedVec(const std::vector<double> &xyz);\n\nprivate slots:\n    void axisValueChanged(double);\n};\n"
  },
  {
    "path": "apps/vaporgui/V3DIntInput.cpp",
    "content": "#include \"V3DIntInput.h\"\n#include <QHBoxLayout>\n#include <QLabel>\n#include \"VIntLineEdit.h\"\n#include <vapor/VAssert.h>\n\nV3DIntInput::V3DIntInput()\n{\n    QHBoxLayout *layout = new QHBoxLayout;\n    layout->setMargin(0);\n    setLayout(layout);\n\n    layout->addWidget(new QLabel(\"X\"));\n    layout->addWidget(_x = new VIntLineEdit);\n    layout->addWidget(new QLabel(\"Y\"));\n    layout->addWidget(_y = new VIntLineEdit);\n    layout->addWidget(new QLabel(\"Z\"));\n    layout->addWidget(_z = new VIntLineEdit);\n\n    for (auto input : {_x, _y, _z}) QObject::connect(input, &VIntLineEdit::ValueChanged, this, &V3DIntInput::axisValueChanged);\n}\n\nvoid V3DIntInput::SetValue(int x, int y, int z)\n{\n    _x->SetValueInt(x);\n    _y->SetValueInt(y);\n    _z->SetValueInt(z);\n}\n\nvoid V3DIntInput::SetValue(const std::vector<int> &xyz)\n{\n    VAssert(xyz.size() == 3);\n    SetValue(xyz[0], xyz[1], xyz[2]);\n}\n\nvoid V3DIntInput::axisValueChanged(int)\n{\n    int x = _x->GetValueInt();\n    int y = _y->GetValueInt();\n    int z = _z->GetValueInt();\n\n    emit ValueChanged(x, y, z);\n    emit ValueChangedVec(std::vector<int>{x, y, z});\n}\n"
  },
  {
    "path": "apps/vaporgui/V3DIntInput.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include <vector>\n\nclass VIntLineEdit;\n\n//! \\class V3DIntInput\n//! \\brief Widget that allows the user to specify a 3D integer vector\n//! \\author Scott Pearse\n\nclass V3DIntInput : public QWidget {\n    Q_OBJECT\n\n    VIntLineEdit *_x, *_y, *_z;\n\npublic:\n    V3DIntInput();\n    void SetValue(int x, int y, int z);\n    void SetValue(const std::vector<int> &xyz);\n\nsignals:\n    void ValueChanged(int x, int y, int z);\n    void ValueChangedVec(const std::vector<int> &xyz);\n\nprivate slots:\n    void axisValueChanged(int);\n};\n"
  },
  {
    "path": "apps/vaporgui/VActions.cpp",
    "content": "#include <string>\n\n#include \"VActions.h\"\n#include \"VIntSpinBox.h\"\n#include \"VCheckBox.h\"\n#include \"VStringLineEdit.h\"\n#include \"VIntLineEdit.h\"\n#include \"VDoubleLineEdit.h\"\n\nVLineAction::VLineAction(const std::string &title, VHBoxWidget *container) : QWidgetAction(NULL)\n{\n    VLineItem *vli = new VLineItem(title, container);\n    vli->setContentsMargins(5, 0, 5, 0);\n    setDefaultWidget(vli);\n}\n\nVSpinBoxAction::VSpinBoxAction(const std::string &title, int value) : VLineAction(title, _spinBox = new VIntSpinBox(1, 10))\n{\n    _spinBox->SetValue(value);\n    connect(_spinBox, SIGNAL(ValueChanged(int)), this, SLOT(_spinBoxChanged(int)));\n}\n\nvoid VSpinBoxAction::SetValue(int value) { _spinBox->SetValue(value); }\n\nvoid VSpinBoxAction::_spinBoxChanged(int value) { emit editingFinished(value); }\n\nVCheckBoxAction::VCheckBoxAction(const std::string &title, bool value) : VLineAction(title, _checkBox = new VCheckBox(value))\n{\n    connect(_checkBox, &VCheckBox::ValueChanged, this, &VCheckBoxAction::_checkBoxChanged);\n}\n\nvoid VCheckBoxAction::SetValue(bool value) { _checkBox->SetValue(value); }\n\nvoid VCheckBoxAction::_checkBoxChanged(bool value) { emit clicked(value); }\n\nVStringLineEditAction::VStringLineEditAction(const std::string &title, std::string value) : VLineAction(title, _lineEdit = new VStringLineEdit(value))\n{\n    connect(_lineEdit, SIGNAL(ValueChanged(int)), this, SLOT(_lineEditChanged(int)));\n}\n\nvoid VStringLineEditAction::SetValue(const std::string &value) { _lineEdit->SetValueString(value); }\n\nvoid VStringLineEditAction::_lineEditChanged(int value) { emit ValueChanged(value); }\n\nVIntLineEditAction::VIntLineEditAction(const std::string &title, int value) : VLineAction(title, _lineEdit = new VIntLineEdit(value))\n{\n    connect(_lineEdit, SIGNAL(ValueChanged(int)), this, SLOT(_lineEditChanged(int)));\n}\n\nvoid VIntLineEditAction::SetValue(int value) { _lineEdit->SetValueInt(value); }\n\nvoid VIntLineEditAction::_lineEditChanged(int value) { emit ValueChanged(value); }\n\nVDoubleLineEditAction::VDoubleLineEditAction(const std::string &title, double value) : VLineAction(title, _lineEdit = new VDoubleLineEdit(value))\n{\n    connect(_lineEdit, SIGNAL(ValueChanged(double)), this, SLOT(_lineEditChanged(double)));\n}\n\nvoid VDoubleLineEditAction::SetValue(double value) { _lineEdit->SetValueDouble(value); }\n\nvoid VDoubleLineEditAction::_lineEditChanged(double value) { emit ValueChanged(value); }\n"
  },
  {
    "path": "apps/vaporgui/VActions.h",
    "content": "#pragma once\n\n#include <string>\n\n#include <QWidgetAction>\n\nclass VIntSpinBox;\nclass VCheckBox;\nclass VStringLineEdit;\nclass VIntLineEdit;\nclass VDoubleLineEdit;\n\n#include \"VHBoxWidget.h\"\n\nclass VLineAction : public QWidgetAction {\n    Q_OBJECT\n\npublic:\n    VLineAction(const std::string &title, VHBoxWidget *container);\n};\n\n//!\n//! \\class VSpinBoxAction\n//! \\ingroup Public_GUI\n//! \\brief A menu item represented by a VLabel and VSpinBox, wrapped in a VLineItem\n//! selection tab in any renderer EventRouter class\n\n//! A QWidgetAction that represents itself as a VLineItem, which contains\n//! a VLabel and a VSpinBox.  VWidget's standard SetValue()\n//! function can be used to retrieve and update the current value.  Used\n//! within QMenu classes.\n\nclass VSpinBoxAction : public VLineAction {\n    Q_OBJECT\n\npublic:\n    VSpinBoxAction(const std::string &title, int value);\n\n    //! Set the current integer value held by the VSpinBox\n    void SetValue(int value);\n\nprivate:\n    VIntSpinBox *_spinBox;\n\nprivate slots:\n\n    //! Respond to a change in the VSpinBox\n    void _spinBoxChanged(int value);\n\nsignals:\n    void editingFinished(int);\n};\n\n//!\n//! \\class VCheckBoxAction\n//! \\ingroup Public_GUI\n//! \\brief A menu item represented by a VLabel and VCheckBox, wrapped in a VLineItem\n\n//! A QWidgetAction that represents itself as a VLineItem, which contains\n//! a VLabel and a VCheckBox.  VWidget's standard SetValue()\n//! function can be used to retrieve and update the current value.  Used\n//! within QMenu classes.\n\nclass VCheckBoxAction : public VLineAction {\n    Q_OBJECT\n\npublic:\n    VCheckBoxAction(const std::string &title, bool value);\n\n    //! Set the checkstate of the VCheckBox (0=unchecked, 1=checked)\n    void SetValue(bool value);\n\nprivate:\n    VCheckBox *_checkBox;\n\nprivate slots:\n\n    //! Respond to a change in the checkstate of the VCheckBox\n    void _checkBoxChanged(bool value);\n\nsignals:\n    void clicked(bool);\n};\n\n//!\n//! \\class VStringLineEditAction\n//! \\ingroup Public_GUI\n//! \\brief A menu item represented by a VLabel and VStringLineEdit, wrapped in a VLineItem\n\n//! A QWidgetAction that represents itself as a VLineItem, which contains\n//! a VLabel and a VStringLineEditAction.  VWidget's standard SetValue()\n//! function can be used to retrieve and update the current value.  Used\n//! within QMenu classes.\n\nclass VStringLineEditAction : public VLineAction {\n    Q_OBJECT\n\npublic:\n    VStringLineEditAction(const std::string &title, std::string value);\n\n    //! Set the string value held by the VStringLineEdit\n    void SetValue(const std::string &value);\n\nprivate:\n    VStringLineEdit *_lineEdit;\n\nprivate slots:\n\n    //! Respond to a change made (editingFinished, or returnPressed) in the V*LineEdit\n    void _lineEditChanged(int value);\n\nsignals:\n    void ValueChanged(int);\n};\n\n//!\n//! \\class VIntLineEditAction\n//! \\ingroup Public_GUI\n//! \\brief A menu item represented by a VLabel and VIntLineEdit, wrapped in a VLineItem\n\n//! A QWidgetAction that represents itself as a VLineItem, which contains\n//! a VLabel and a VIntLineEditAction.  VWidget's standard SetValue()\n//! function can be used to retrieve and update the current value.  Used\n//! within QMenu classes.\n\nclass VIntLineEditAction : public VLineAction {\n    Q_OBJECT\n\npublic:\n    VIntLineEditAction(const std::string &title, int value);\n\n    //! Set the numeric value held by the VIntLineEdit\n    void SetValue(int value);\n\nprivate:\n    VIntLineEdit *_lineEdit;\n\nprivate slots:\n\n    //! @copydoc VStringLineEditAction::SetValue()\n    void _lineEditChanged(int value);\n\nsignals:\n    void ValueChanged(int);\n};\n\n//!\n//! \\class VIntLineEditAction\n//! \\ingroup Public_GUI\n//! \\brief A menu item represented by a VLabel and VIntLineEdit, wrapped in a VLineItem\n\n//! A QWidgetAction that represents itself as a VLineItem, which contains\n//! a VLabel and a VDoubleLineEditAction.  VWidget's standard SetValue()\n//! function can be used to retrieve and update the current value.  Used\n//! within QMenu classes.\n\nclass VDoubleLineEditAction : public VLineAction {\n    Q_OBJECT\n\npublic:\n    VDoubleLineEditAction(const std::string &title, double value);\n\n    //! @copydoc VIntLineEditAction::SetValue()\n    void SetValue(double value);\n\nprivate:\n    VDoubleLineEdit *_lineEdit;\n\nprivate slots:\n\n    //! @copydoc VIntLineEditAction::_lineEditChanged()\n    void _lineEditChanged(double value);\n\nsignals:\n    void ValueChanged(double);\n};\n"
  },
  {
    "path": "apps/vaporgui/VCheckBox.cpp",
    "content": "#include \"VCheckBox.h\"\n\nVCheckBox::VCheckBox(bool checked) : VHBoxWidget()\n{\n    _checkBox = new QCheckBox;\n    SetValue(checked);\n    layout()->addWidget(_checkBox);\n\n    connect(_checkBox, &QCheckBox::clicked, this, &VCheckBox::emitCheckBoxChanged);\n}\n\n// Stas thinks that we should have setValues and setValue instead of Update\n//\nvoid VCheckBox::SetValue(bool checked)\n{\n    _checkBox->blockSignals(true);\n    _checkBox->setChecked(checked);\n    _checkBox->blockSignals(false);\n}\n\nbool VCheckBox::GetValue() const { return _checkBox->isChecked(); }\n\nvoid VCheckBox::emitCheckBoxChanged(bool checked) { emit ValueChanged(checked); }\n"
  },
  {
    "path": "apps/vaporgui/VCheckBox.h",
    "content": "#pragma once\n\n#include <string>\n\n#include <QWidget>\n#include <QCheckBox>\n\n#include \"VHBoxWidget.h\"\n\n//! class VCheckBox\n//!\n//! Wraps a QCheckBox and provides vaporgui's standard setter/getter functions\n//! and signals.\n\nclass VCheckBox : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    VCheckBox(bool value = false);\n\n    void SetValue(bool value);\n\n    bool GetValue() const;\n\nprivate:\n    QCheckBox *_checkBox;\n\npublic slots:\n    void emitCheckBoxChanged(bool checked);\n\nsignals:\n    void ValueChanged(bool checked);\n};\n"
  },
  {
    "path": "apps/vaporgui/VComboBox.cpp",
    "content": "#include \"VComboBox.h\"\n#include <vapor/STLUtils.h>\n#include <QStandardItemModel>\n#include <cassert>\n#include \"VHBoxWidget.h\"\n\nVComboBox::VComboBox(const std::vector<std::string> &values) : VContainer(_combo = new QComboBox)\n{\n    _combo->setSizeAdjustPolicy(QComboBox::AdjustToContents);\n\n    // Disable scroll wheel\n    //\n    _combo->setFocusPolicy(Qt::StrongFocus);\n    _combo->installEventFilter(new MouseWheelWidgetAdjustmentGuard(_combo));\n\n    SetOptions(values);\n\n    // We are forced to used SIGNAL/SLOT macros here because there are two\n    // signatures for QComboBox::currentIndexChanged\n    connect(_combo, SIGNAL(currentIndexChanged(QString)), this, SLOT(emitComboChanged(QString)));\n}\n\n// Stas thinks that we should have setValues and setValue instead of Update\n//\nvoid VComboBox::SetOptions(const std::vector<std::string> &values)\n{\n    _options = values;\n    _combo->blockSignals(true);\n    _combo->clear();\n    for (auto i : values) { _combo->addItem(QString::fromStdString(i)); }\n    _combo->blockSignals(false);\n}\n\nvoid VComboBox::SetIndex(int index)\n{\n    if (index >= _combo->count()) return;\n\n    _combo->blockSignals(true);\n    _combo->setCurrentIndex(index);\n    _combo->blockSignals(false);\n}\n\nvoid VComboBox::SetValue(const std::string &value)\n{\n    if (!STLUtils::Contains(_options, value)) {\n        _options.push_back(value);\n        SetOptions(_options);\n    }\n    QString qValue = QString::fromStdString(value);\n    int     index = _combo->findText(qValue);\n    if (index >= 0) SetIndex(index);\n}\n\nvoid VComboBox::SetItemEnabled(int index, bool enabled)\n{\n    QStandardItemModel *model = dynamic_cast<QStandardItemModel *>(_combo->model());\n    assert(model);\n    if (!model) return;\n\n    model->item(index)->setEnabled(enabled);\n}\n\nint VComboBox::GetCurrentIndex() const { return _combo->currentIndex(); }\n\nstd::string VComboBox::GetValue() const { return _combo->currentText().toStdString(); }\n\nint VComboBox::GetCount() const { return _combo->count(); }\n\nvoid VComboBox::emitComboChanged(const QString &value)\n{\n    emit ValueChanged(value.toStdString());\n    emit IndexChanged(_combo->currentIndex());\n}\n"
  },
  {
    "path": "apps/vaporgui/VComboBox.h",
    "content": "#pragma once\n\n#include <string>\n#include <QComboBox>\n#include \"VContainer.h\"\n\n//! class VComboBox\n//!\n//! Wraps a QComboBox and provides vaporgui's standard setter/getter functions\n//! and signals.\n\nclass VComboBox : public VContainer {\n    Q_OBJECT\n\npublic:\n    VComboBox(const std::vector<std::string> &values = {});\n\n    void SetOptions(const std::vector<std::string> &values);\n    void SetIndex(int index);\n    void SetValue(const std::string &value);\n    void SetItemEnabled(int index, bool enabled);\n\n    std::string GetValue() const;\n    int         GetCurrentIndex() const;\n    int         GetCount() const;\n\nprivate:\n    QComboBox *_combo;\n    std::vector<std::string> _options;\n\npublic slots:\n    void emitComboChanged(const QString &value);\n\nsignals:\n    void ValueChanged(std::string value);\n    void IndexChanged(int index);\n};\n"
  },
  {
    "path": "apps/vaporgui/VContainer.cpp",
    "content": "#include \"VContainer.h\"\n#include <cassert>\n#include <QVBoxLayout>\n\nVContainer::VContainer(QWidget *w)\n{\n    QLayout *layout = new QVBoxLayout;\n    layout->setMargin(0);\n    layout->setSpacing(0);\n    layout->addWidget(w);\n    QWidget::setLayout(layout);\n}\n\nvoid VContainer::AddBottomStretch()\n{\n    QVBoxLayout *layout = dynamic_cast<QVBoxLayout *>(QWidget::layout());\n    assert(layout);\n    assert(layout->count() == 1);\n    layout->addStretch();\n}\n\nvoid VContainer::SetPadding(int left, int top, int right, int bottom)\n{\n    QVBoxLayout *layout = dynamic_cast<QVBoxLayout *>(QWidget::layout());\n    assert(layout);\n    layout->setContentsMargins(left, top, right, bottom);\n}\n"
  },
  {
    "path": "apps/vaporgui/VContainer.h",
    "content": "#pragma once\n\n#include <QWidget>\n\nclass VContainer : public QWidget {\npublic:\n    VContainer(QWidget *w);\n    void AddBottomStretch();\n    void SetPadding(int left, int top, int right, int bottom);\n\n    QLayout *layout() const = delete;\n    void     setLayout(QLayout *) = delete;\n};\n"
  },
  {
    "path": "apps/vaporgui/VDoubleLineEdit.cpp",
    "content": "#include <string>\n#include <sstream>\n#include <iomanip>\n\n#include <QString>\n\n#include \"VDoubleLineEdit.h\"\n\nVDoubleLineEdit::VDoubleLineEdit(double value) : VNumericLineEdit(), _value(value)\n{\n    std::string formattedNumber = _formatValue(_value);\n    SetValueString(formattedNumber);\n}\n\nvoid VDoubleLineEdit::SetValueDouble(double value)\n{\n    _value = value;\n    std::string formattedNumber = _formatValue(value);\n    SetValueString(formattedNumber);\n}\n\ndouble VDoubleLineEdit::GetValueDouble() const { return _value; }\n\nvoid VDoubleLineEdit::SetRange(double min, double max)\n{\n    _min = min;\n    _max = max;\n}\n\nvoid VDoubleLineEdit::_valueChanged()\n{\n    std::string str = _getText();\n\n    double value;\n    try {\n        value = std::stod(str);\n\n        value = std::min(_max, std::max(_min, value));\n\n        // If value changed, update and emit, otherwiese revert to old value\n        if (value != _value) {\n            SetValueDouble(value);\n            emit ValueChanged(_value);\n        } else {\n            SetValueDouble(_value);\n        }\n    } catch (const std::invalid_argument &) {\n        SetValueDouble(_value);\n    } catch (const std::out_of_range &) {\n        SetValueDouble(_value);\n    }\n}\n\nstd::string VDoubleLineEdit::_formatValue(double value)\n{\n    std::stringstream stream;\n    stream << std::fixed << std::setprecision(_decimalDigits);\n    if (_sciNotation) {\n        stream << std::scientific;\n        stream << value;\n    } else {\n        stream << value;\n    }\n    return stream.str();\n}\n"
  },
  {
    "path": "apps/vaporgui/VDoubleLineEdit.h",
    "content": "#pragma once\n\n#include <iostream>\n\n#include <string>\n#include <sstream>\n#include <iomanip>\n\n#include <QString>\n\n#include \"VNumericLineEdit.h\"\n\n//! \\class VDoubleLineEdit\n//! \\ingroup Public_GUI\n//! \\brief A wrapper for a QLineEdit that handles user input of type double,\n//! and provides Vapor's standard setters, getters, and signals\n\nclass VDoubleLineEdit : public VNumericLineEdit {\n    Q_OBJECT\n\npublic:\n    VDoubleLineEdit(double value = 0.0);\n\n    //! Set the current double value in the line edit\n    void SetValueDouble(double value);\n\n    //! Get the current double value in the line edit\n    double GetValueDouble() const;\n\n    void SetRange(double min, double max);\n\nprotected:\n    std::string _formatValue(double value);\n\n    double _value;\n    double _min = -std::numeric_limits<double>::max();\n    double _max = std::numeric_limits<double>::max();\n\nprotected slots:\n    void _valueChanged() override;\n\nsignals:\n    void ValueChanged(double value);\n};\n"
  },
  {
    "path": "apps/vaporgui/VDoubleRangeMenu.cpp",
    "content": "#include \"VDoubleRangeMenu.h\"\n#include \"VActions.h\"\n\nVDoubleRangeMenu::VDoubleRangeMenu(QWidget *parent, bool sciNotation, double decimalDigits, double min, double max, bool rangeChangable)\n: VNumericFormatMenu(parent, sciNotation, decimalDigits), _minRangeAction(new VDoubleLineEditAction(\"Minimum value\", min)), _maxRangeAction(new VDoubleLineEditAction(\"Maximum value\", max))\n{\n    connect(_minRangeAction, &VDoubleLineEditAction::ValueChanged, this, &VDoubleRangeMenu::_minChanged);\n    addAction(_minRangeAction);\n\n    connect(_maxRangeAction, &VDoubleLineEditAction::ValueChanged, this, &VDoubleRangeMenu::_maxChanged);\n    addAction(_maxRangeAction);\n\n    if (!rangeChangable) {\n        _minRangeAction->setEnabled(false);\n        _maxRangeAction->setEnabled(false);\n    }\n}\n\nvoid VDoubleRangeMenu::AllowUserRange(bool allowed)\n{\n    _minRangeAction->setEnabled(allowed);\n    _maxRangeAction->setEnabled(allowed);\n}\n\nvoid VDoubleRangeMenu::SetMinimum(double min) { _minRangeAction->SetValue(min); }\n\nvoid VDoubleRangeMenu::SetMaximum(double max) { _maxRangeAction->SetValue(max); }\n\nvoid VDoubleRangeMenu::_minChanged(double min) { emit MinChanged(min); }\n\nvoid VDoubleRangeMenu::_maxChanged(double max) { emit MaxChanged(max); }\n"
  },
  {
    "path": "apps/vaporgui/VDoubleRangeMenu.h",
    "content": "#pragma once\n\n#include \"VNumericFormatMenu.h\"\n\nclass VDoubleLineEditAction;\n\n//! \\class VDoubleRangeMenu\n//! \\ingroup Public_GUI\n//! \\brief A menu that allows the user to control the range of double values\n//! that can be set by a widget.  Also allows for setting the numeric format\n//! that the number is displayed with.\n\nclass VDoubleRangeMenu : public VNumericFormatMenu {\n    Q_OBJECT\n\npublic:\n    explicit VDoubleRangeMenu(QWidget *parent, bool sciNotation, double decimalDigits, double min, double max, bool rangeChangable);\n\n    void AllowUserRange(bool allowed = true);\n\nprotected:\n    VDoubleLineEditAction *_minRangeAction;\n    VDoubleLineEditAction *_maxRangeAction;\n\npublic slots:\n    //! Set the minimum value that the current widget can use\n    void SetMinimum(double min);\n\n    //! Set the maximum value that the current widget can use\n    void SetMaximum(double max);\n\nprivate slots:\n    void _minChanged(double min);\n    void _maxChanged(double max);\n\nsignals:\n    void MinChanged(double min);\n    void MaxChanged(double max);\n};\n"
  },
  {
    "path": "apps/vaporgui/VDoubleSliderEdit.cpp",
    "content": "#include <cmath>\n#include <iostream>\n\n#include <QMenu>\n\n#include \"vapor/VAssert.h\"\n\n#include \"VDoubleSliderEdit.h\"\n#include \"VDoubleLineEdit.h\"\n#include \"VDoubleSliderEditMenu.h\"\n#include \"VSlider.h\"\n\nVDoubleSliderEdit::VDoubleSliderEdit(double min, double max, double value, bool rangeChangable) : VSliderEditInterface(), _value(value), _rangeChangable(rangeChangable)\n{\n    _slider->SetRange(min, max);\n    _slider->SetValue(value);\n    connect(_slider, &VSlider::ValueChanged, this, &VDoubleSliderEdit::SetValue);\n    connect(_slider, &VSlider::ValueChangedIntermediate, this, &VDoubleSliderEdit::_sliderChangedIntermediate);\n\n    _lineEdit = new VDoubleLineEdit(value);\n    _lineEdit->RemoveContextMenu();\n    layout()->addWidget(_lineEdit);\n    connect(_lineEdit, SIGNAL(ValueChanged(double)), this, SLOT(SetValue(double)));\n\n    _makeContextMenu();\n}\n\nvoid VDoubleSliderEdit::AllowUserRange(bool allowed)\n{\n    _rangeChangable = allowed;\n    _menu->AllowUserRange(allowed);\n}\n\nvoid VDoubleSliderEdit::_makeContextMenu()\n{\n    _menu = new VDoubleSliderEditMenu(this);\n    connect(_menu, &VNumericFormatMenu::DecimalDigitsChanged, this, &VDoubleSliderEdit::SetNumDigits);\n    connect(_menu, &VNumericFormatMenu::SciNotationChanged, this, &VDoubleSliderEdit::SetSciNotation);\n    connect(_menu, &VDoubleRangeMenu::MinChanged, this, &VDoubleSliderEdit::SetMinimum);\n    connect(_menu, &VDoubleRangeMenu::MaxChanged, this, &VDoubleSliderEdit::SetMaximum);\n    connect(_menu, &VDoubleSliderEditMenu::DynamicUpdateChanged, this, &VDoubleSliderEdit::SetDynamicUpdate);\n}\n\nvoid VDoubleSliderEdit::AllowDynamicUpdate() const { _menu->AllowDynamicUpdate(); }\n\nvoid VDoubleSliderEdit::SetDynamicUpdate(bool enabled) { emit DynamicUpdateChanged(enabled); }\n\nbool VDoubleSliderEdit::GetSciNotation() const { return _lineEdit->GetSciNotation(); }\n\nvoid VDoubleSliderEdit::SetSciNotation(bool value)\n{\n    if (value == _lineEdit->GetSciNotation()) { return; }\n    _lineEdit->SetSciNotation(value);\n    emit FormatChanged();\n}\n\nint VDoubleSliderEdit::GetNumDigits() const { return _lineEdit->GetNumDigits(); }\n\nvoid VDoubleSliderEdit::SetNumDigits(int digits)\n{\n    if (digits == _lineEdit->GetNumDigits()) { return; }\n    _lineEdit->SetNumDigits(digits);\n    emit FormatChanged();\n}\n\ndouble VDoubleSliderEdit::GetValue() const { return _value; }\n\nvoid VDoubleSliderEdit::SetValue(double value)\n{\n    // If the new value is illegal, reset _lineEdit's text and return\n    if (value < _slider->GetMinimum() || value > _slider->GetMaximum()) {\n        _lineEdit->SetValueDouble(_value);\n        return;\n    }\n\n    _value = value;\n\n    _lineEdit->SetValueDouble(_value);\n    _slider->SetValue(_value);\n\n    if (QObject::sender() != nullptr && QObject::sender() != this) { emit ValueChanged(_value); }\n}\n\ndouble VDoubleSliderEdit::GetMinimum() const\n{\n    return _slider->GetMinimum();\n    ;\n}\n\nvoid VDoubleSliderEdit::SetMinimum(double min)\n{\n    // If the new value is unchanged, or illegal, reset the menu and return\n    if (min == _slider->GetMinimum() || min > _slider->GetMaximum()) {\n        if (min > _value) {\n            _value = min;\n            SetValue(_value);\n        }\n        _menu->SetMinimum(_slider->GetMinimum());\n        return;\n    }\n\n    _slider->SetMinimum(min);\n    _menu->SetMinimum(min);\n\n    // If sender() is a nullptr, then this fuction is being called from Update().\n    // Don't emit anythong.  Otherwise, emit our signal.\n    if (QObject::sender() != nullptr) { emit MinimumChanged(min); }\n}\n\ndouble VDoubleSliderEdit::GetMaximum() const { return _slider->GetMaximum(); }\n\nvoid VDoubleSliderEdit::SetMaximum(double max)\n{\n    // If the new value is unchanged, or illegal, reset the menu and retur\n    if (max == _slider->GetMaximum() || max < _slider->GetMinimum()) {\n        if (max < _value) {\n            _value = max;\n            SetValue(_value);\n        }\n        _menu->SetMaximum(_slider->GetMaximum());\n        return;\n    }\n\n    _slider->SetMaximum(max);\n    _menu->SetMaximum(max);\n\n    // If sender() is a nullptr, then this fuction is being called from Update().\n    // Don't emit anythong.  Otherwise, emit our signal.\n    if (QObject::sender() != nullptr) { emit MaximumChanged(max); }\n}\n\nvoid VDoubleSliderEdit::ShowContextMenu(const QPoint &pos)\n{\n    QPoint globalPos = mapToGlobal(pos);\n    _menu->exec(globalPos);\n}\n\nvoid VDoubleSliderEdit::_sliderChangedIntermediate(double value)\n{\n    dynamic_cast<VDoubleLineEdit *>(_lineEdit)->SetValueDouble(value);\n    emit ValueChangedIntermediate(value);\n}\n"
  },
  {
    "path": "apps/vaporgui/VDoubleSliderEdit.h",
    "content": "#pragma once\n\n#include <string>\n#include \"VHBoxWidget.h\"\n#include \"VSliderEditInterface.h\"\n\nclass QMenu;\nclass VDoubleLineEdit;\nclass VDoubleSliderEditMenu;\n\n//! \\class VDoubleSliderEdit\n//! \\ingroup Public_GUI\n//! \\brief A wrapper for a VSlider and a VDoubleLineEdit, that\n//! provides synchronization between the two widgets, and support\n//! for a menu that allows setting and getting the VSlider range,\n//! and the numeric representation of the VDoubleLineEdit\n\nclass VDoubleSliderEdit : public VSliderEditInterface {\n    Q_OBJECT\n\npublic:\n    VDoubleSliderEdit(double min = 0, double max = 10, double value = 3, bool rangeChangable = false);\n\n    //! Set the minimum allowable value for the VSlider and VDoubleLineEdit\n    void SetMinimum(double min);\n\n    //! Set the maximum allowable value for the VSlider and VDoubleLineEdit\n    void SetMaximum(double max);\n\n    void AllowUserRange(bool allowed = true);\n    void AllowDynamicUpdate() const;\n\n    //! Get the value associated with the VSlider and VDoubleLineEdit\n    double GetValue() const;\n\n    //! Get the minimum allowable value for the VSlider and VDoubleLineEdit\n    double GetMinimum() const;\n\n    //! Get the maximum allowable value for the VSlider and VDoubleLineEdit\n    double GetMaximum() const;\n\n    //! Get the number of digits displayed by the VDoubleLineEdit\n    virtual int GetNumDigits() const;\n\n    //! Get whether the VDoubleLineEdit is being displayed with scientific notation\n    virtual bool GetSciNotation() const;\n\npublic slots:\n    //! Set the current value displayed by the slider and line edit\n    void SetValue(double value);\n\n    //! Set the number of digits displayed by the VDoubleLineEdit\n    virtual void SetNumDigits(int numDigits);\n\n    //! Set whether the VDoubleLineEdit is being displayed with scientific notation\n    virtual void SetSciNotation(bool sciNotation);\n\n    //! Set the dynamic update menu item's toggle state\n    virtual void SetDynamicUpdate(bool enabled);\n\n    //! Show the context menu options for the entire widget, triggered on right-click\n    virtual void ShowContextMenu(const QPoint &pos);\n\nprotected:\n    virtual void _makeContextMenu();\n    void         _sliderChanged(double value);\n    void         _sliderChangedIntermediate(double value);\n\n    double _value;\n    bool   _rangeChangable;\n\n    VDoubleLineEdit * _lineEdit;\n    VDoubleSliderEditMenu *_menu;\n\nsignals:\n    void ValueChanged(double value);\n    void ValueChangedIntermediate(double value);\n    void MinimumChanged(double min);\n    void MaximumChanged(double max);\n    void DynamicUpdateChanged(bool enabled);\n};\n"
  },
  {
    "path": "apps/vaporgui/VDoubleSliderEditMenu.cpp",
    "content": "#include <QWidget>\n\n#include \"VActions.h\"\n#include \"VDoubleSliderEditMenu.h\"\n\n// clang-format off\n\nVDoubleSliderEditMenu::VDoubleSliderEditMenu(QWidget *parent) : \nVDoubleRangeMenu( parent, false, 2, 0., 10., false)\n{\n    _dynamicUpdateAction = new VCheckBoxAction(\"Dynamic update enabled\", false);\n    connect(_dynamicUpdateAction, &VCheckBoxAction::clicked, this, &VDoubleSliderEditMenu::_dynamicUpdateChanged);\n    addAction(_dynamicUpdateAction);\n    _dynamicUpdateAction->setEnabled(false);\n}\n\nvoid VDoubleSliderEditMenu::AllowDynamicUpdate() const { _dynamicUpdateAction->setEnabled(true); }\n\nvoid VDoubleSliderEditMenu::SetDynamicUpdate(bool dynamicUpdateEnabled) { _dynamicUpdateAction->SetValue(dynamicUpdateEnabled); }\n\nvoid VDoubleSliderEditMenu::_dynamicUpdateChanged(bool dynamicUpdateEnabled) { emit DynamicUpdateChanged(dynamicUpdateEnabled); }\n\n// clang-format on\n"
  },
  {
    "path": "apps/vaporgui/VDoubleSliderEditMenu.h",
    "content": "#pragma once\n\n#include <QMenu>\n#include \"VDoubleRangeMenu.h\"\n\nclass VCheckBoxAction;\n\n//! \\class VDoubleSliderEditMenu\n//! \\ingroup Public_GUI\n//! \\brief A menu for VDoubleSliderEdit that allows for setting\n//! a min/max range, numeric formatting controls, and dynamic update controls\n//! in regard to how many digits are displayed, and whether scientific notation is used.\n\n// clang-format off\n\nclass VDoubleSliderEditMenu : public VDoubleRangeMenu {\n    Q_OBJECT\n\npublic:\n    explicit VDoubleSliderEditMenu(QWidget *parent);\n\n    //! Allow the toggling of the dynamic update checkbox in the right-click menu\n    void AllowDynamicUpdate() const;\n\nprotected:\n    VCheckBoxAction *_dynamicUpdateAction;\n\npublic slots:\n    //! Check/Uncheck the dynamic update checkbox\n    void SetDynamicUpdate(bool enabled);\n\nprivate slots:\n    void _dynamicUpdateChanged(bool dynamicUpdateEnabled);\n\nsignals:\n    void DynamicUpdateChanged(bool dynamicUpdateEnabled);\n};\n\n// clang-format on\n"
  },
  {
    "path": "apps/vaporgui/VDoubleValidator.cpp",
    "content": "#include \"VDoubleValidator.h\"\n\nvoid VDoubleValidator::fixup(QString &input) const\n{\n    bool   ok;\n    double v = locale().toDouble(input, &ok);\n    if (ok) {\n        if (v > top()) input.setNum(top());\n        if (v < bottom()) input.setNum(bottom());\n    }\n}\n\nQValidator::State VDoubleValidator::validate(QString &input, int &pos) const\n{\n    State s = QDoubleValidator::validate(input, pos);\n\n    if (s == State::Intermediate) {\n        bool   ok;\n        double v = locale().toDouble(input, &ok);\n        if (ok)\n            if (v > top() || v < bottom()) s = State::Invalid;\n    }\n\n    return s;\n}\n"
  },
  {
    "path": "apps/vaporgui/VDoubleValidator.h",
    "content": "#pragma once\n\n#include <QDoubleValidator>\n\n//! \\class VDoubleValidator\n//! Use as a direct replacement of QDoubleValidator.\n//! They behave the same except QDoubleValidator does not accept values outside\n//! the range while VDoubleValidator does not allow the user to input\n//! values outside of the range. This solves some quirks with QLineEdit\n//! With QDoubleValidator, the user can type a value outside the range in the text\n//! box but the text box will say the value is invalid and it will stop working\n//! VDoubleValidator, will not allow the user to type in a value outside the range\n//! omitting the above problem.\n\nclass VDoubleValidator : public QDoubleValidator {\npublic:\n    using QDoubleValidator::QDoubleValidator;\n    virtual void              fixup(QString &input) const override;\n    virtual QValidator::State validate(QString &input, int &pos) const override;\n};\n"
  },
  {
    "path": "apps/vaporgui/VFileSelector.cpp",
    "content": "#include \"VFileSelector.h\"\n\n#include <iostream>\n\n#include \"FileOperationChecker.h\"\n#include \"ErrorReporter.h\"\n\n#include \"VPushButton.h\"\n#include \"VLineEdit_Deprecated.h\"\n\nVFileSelector::VFileSelector(const std::string &buttonText, const std::string &defaultPath, const std::string &filter = \"\") : VHBoxWidget(), _filePath(defaultPath), _filter(filter)\n{\n    _pushButton = new VPushButton(buttonText);\n    _lineEdit = new VLineEdit_Deprecated(defaultPath);\n    layout()->addWidget(_pushButton);\n    layout()->addWidget(_lineEdit);\n\n    if (_filePath.empty()) _filePath = QDir::homePath().toStdString();\n\n    connect(_pushButton, &VPushButton::ButtonClicked, this, &VFileSelector::OpenFileDialog);\n    connect(_lineEdit, SIGNAL(ValueChanged(std::string)), this, SLOT(SetPathFromLineEdit(std::string)));\n}\n\nstd::string VFileSelector::GetValue() const { return _filePath; }\n\nbool VFileSelector::SetValue(const std::string &file)\n{\n    bool success = false;\n\n    if (file == _filePath)    // Do nothing, if nothing is changed\n        return success;\n\n    if (_isFileOperable(file)) {\n        _filePath = file;\n        success = true;\n    } else {\n        MSG_ERR(FileOperationChecker::GetLastErrorMessage().toStdString());\n    }\n\n    _lineEdit->SetValue(_filePath);\n    _lineEdit->setToolTip(QString::fromStdString(_filePath));\n    return success;\n}\n\nvoid VFileSelector::OpenFileDialog()\n{\n    std::string file = _launchFileDialog();\n    if (SetValue(file)) { emit ValueChanged(_filePath); }\n}\n\nvoid VFileSelector::SetPathFromLineEdit(const std::string &file)\n{\n    if (SetValue(file)) emit ValueChanged(_filePath);\n}\n\nvoid VFileSelector::HideLineEdit(bool hide)\n{\n    if (hide)\n        _lineEdit->hide();\n    else\n        _lineEdit->show();\n}\n\n//\n//\n//\nVFileReader::VFileReader(const std::string &buttonText, const std::string &defaultPath, const std::string &filter) : VFileSelector(buttonText, defaultPath, filter) {}\n\nstd::string VFileReader::_launchFileDialog()\n{\n    QString fileName = QFileDialog::getOpenFileName(this, \"Select Directory/File\", QString::fromStdString(_filePath), QString::fromStdString(_filter));\n    return fileName.toStdString();\n}\n\nbool VFileReader::_isFileOperable(const std::string &filePath) const\n{\n    bool operable = false;\n    operable = FileOperationChecker::FileGoodToRead(QString::fromStdString(filePath));\n    return operable;\n}\n\n//\n//\n//\nVFileWriter::VFileWriter(const std::string &buttonText, const std::string &defaultPath, const std::string &filter) : VFileSelector(buttonText, defaultPath, filter) {}\n\nbool VFileWriter::_isFileOperable(const std::string &filePath) const\n{\n    bool operable = false;\n    operable = FileOperationChecker::FileGoodToWrite(QString::fromStdString(filePath));\n    return operable;\n}\n\nstd::string VFileWriter::_launchFileDialog()\n{\n    QString fileName = QFileDialog::getSaveFileName(this, \"Select Directory/File\", QString::fromStdString(_filePath), QString::fromStdString(_filter));\n    return fileName.toStdString();\n}\n\nVDirSelector::VDirSelector(const std::string &buttonText, const std::string &defaultPath) : VFileSelector(buttonText, defaultPath) {}\n\nstd::string VDirSelector::_launchFileDialog()\n{\n    QString fileName = QFileDialog::getExistingDirectory(this, \"Select Directory/File\", QString::fromStdString(_filePath));\n    return fileName.toStdString();\n}\n\nbool VDirSelector::_isFileOperable(const std::string &filePath) const\n{\n    bool operable = false;\n    operable = FileOperationChecker::DirectoryGoodToRead(QString::fromStdString(filePath));\n    return operable;\n}\n"
  },
  {
    "path": "apps/vaporgui/VFileSelector.h",
    "content": "#pragma once\n\n#include <string>\n#include <QWidget>\n#include <QFileDialog>\n\n#include \"VHBoxWidget.h\"\n\nclass VPushButton;\nclass VLineEdit_Deprecated;\n\n//! class VFileSelector\n//!\n//! An abstract class for reading and writing files, or selecting\n//! directory paths.  This class wraps a VLineEdit_Deprecated to display the current\n//! selection, and a VPushButton to open file dialogs.  It also provides\n//! vaporgui's standard setter/getter functions and signals.\nclass VFileSelector : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    std::string GetValue() const;\n    bool        SetValue(const std::string &file);\n\n    void HideLineEdit(bool hide);\n\nprotected:\n    VFileSelector(const std::string &buttonText, const std::string &defaultPath, const std::string &filter);\n\n    VLineEdit_Deprecated *_lineEdit;\n    VPushButton *         _pushButton;\n\n    std::string _filePath;\n    std::string _filter;\n\nprivate:\n    virtual std::string _launchFileDialog() = 0;\n    virtual bool        _isFileOperable(const std::string &file) const = 0;\n\npublic slots:\n    void OpenFileDialog();\n    void SetPathFromLineEdit(const std::string &value);\n\nsignals:\n    void ValueChanged(const std::string &path);\n};\n\n//! class VFileReader\n//!\n//! A class for opening a file-dialog and selecting a file for reading.\n//! This class provides vaporgui's standard setter/getter functions, and signals.\nclass VFileReader : public VFileSelector {\n    Q_OBJECT\n\npublic:\n    VFileReader(const std::string &buttonText = \"Select\", const std::string &defaultPath = QDir::homePath().toStdString(), const std::string &filter = \"\");\n\nprivate:\n    virtual std::string _launchFileDialog();\n    virtual bool        _isFileOperable(const std::string &file) const;\n};\n\n//! class VFileWriter\n//!\n//! A class for opening a file-dialog and selecting a file for writing.\n//! This class provides vaporgui's standard setter/getter functions, and signals.\nclass VFileWriter : public VFileSelector {\n    Q_OBJECT\n\npublic:\n    VFileWriter(const std::string &buttonText = \"Select\", const std::string &defaultPath = QDir::homePath().toStdString(), const std::string &filter = \"\");\n\nprivate:\n    virtual std::string _launchFileDialog();\n    virtual bool        _isFileOperable(const std::string &file) const;\n};\n\n//! class VFileSelector\n//!\n//! A class for opening a file-dialog and selecting a directory.\n//! This class provides vaporgui's standard setter/getter functions, and signals.\nclass VDirSelector : public VFileSelector {\n    Q_OBJECT\n\npublic:\n    VDirSelector(const std::string &buttonText = \"Select\", const std::string &defaultPath = QDir::homePath().toStdString());\n\nprivate:\n    virtual std::string _launchFileDialog();\n    virtual bool        _isFileOperable(const std::string &file) const;\n};\n"
  },
  {
    "path": "apps/vaporgui/VFrame.cpp",
    "content": "#include \"VFrame.h\"\n\n#include <QVBoxLayout>\n\nVFrame::VFrame()\n{\n    setLayout(new QVBoxLayout);\n    layout()->setContentsMargins(0, 0, 0, 0);\n    layout()->setSpacing(12);\n    setFrameStyle(QFrame::NoFrame);\n}\n\nvoid VFrame::addWidget(QWidget *widget)\n{\n    layout()->addWidget(widget);\n    _child_widgets.push_front(widget);\n    _num_of_children++;\n}\n\nint VFrame::getNumOfChildWidgets() const { return _num_of_children; }\n\nint VFrame::hideChildAtIdx(int idx)\n{\n    if (_child_widgets.empty())\n        return 1;\n    else if (idx < 0 || idx >= _num_of_children)\n        return 1;\n    else {\n        auto itr = _child_widgets.before_begin();\n        for (int i = 0; i < _num_of_children - idx; i++) ++itr;\n        (*itr)->hide();\n        return 0;\n    }\n}\n\nint VFrame::showChildAtIdx(int idx)\n{\n    if (_child_widgets.empty())\n        return 1;\n    else if (idx < 0 || idx >= _num_of_children)\n        return 1;\n    else {\n        auto itr = _child_widgets.before_begin();\n        for (int i = 0; i < _num_of_children - idx; i++) ++itr;\n        (*itr)->show();\n        return 0;\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/VFrame.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include <QFrame>\n#include <forward_list>\n\n//! \\class VFrame\n//!\n//! A simple class that sets a layout, spacing, and margin\n//! policy onto a QFrame for consistency throughout the application.\nclass VFrame : public QFrame {\n    Q_OBJECT\n\npublic:\n    VFrame();\n\n    void addWidget(QWidget *widget);\n\n    int getNumOfChildWidgets() const;\n\n    // The following two methods control if a child is shown or hidden.\n    // If a child widget is the ith added to this VFrame, then idx should be i-1.\n    // It returns 0 upon success, and 1 upon failure (e.g. invalid index).\n    int hideChildAtIdx(int idx);\n    int showChildAtIdx(int idx);\n\nprivate:\n    std::forward_list<QWidget *> _child_widgets;\n    int                          _num_of_children = 0;\n};\n"
  },
  {
    "path": "apps/vaporgui/VGroup.cpp",
    "content": "#include \"VGroup.h\"\n#include <QVBoxLayout>\n\nVGroup::VGroup(List children)\n: VGroup(new QVBoxLayout, children) {}\n\nVGroup::VGroup(QBoxLayout *layout, List children)\n{\n    layout->setMargin(0);\n    layout->setSpacing(4);\n    setLayout(layout);\n    AddM(children);\n}\n\nVGroup *VGroup::Add(QWidget *w)\n{\n    layout()->addWidget(w);\n    return this;\n}\n\nVSubGroup::VSubGroup(List children)\n{\n    layout()->setContentsMargins(12, 0, 0, 0);\n    AddM(children);\n}\n\nVHGroup::VHGroup()\n: VGroup(new QHBoxLayout, {}) {}\n"
  },
  {
    "path": "apps/vaporgui/VGroup.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include \"AbstractWidgetGroup.h\"\n\nclass QBoxLayout;\n\n//! \\class VGroup\n//! Creates a group for parameter controls in the sidebar\n\nclass VGroup : public QWidget, public AbstractWidgetGroup<VGroup, QWidget> {\n    Q_OBJECT\npublic:\n    VGroup(List children = {});\n    VGroup *Add(QWidget *w);\nprotected:\n    VGroup(QBoxLayout *layout, List children);\n};\n\n\nclass VHGroup : public VGroup {\n    Q_OBJECT\npublic:\n    VHGroup();\n};\n\n\n//! \\class VSubGroup\n//! Creates a subgroup for parameter controls in the sidebar\n\nclass VSubGroup : public VGroup {\n    Q_OBJECT\npublic:\n    VSubGroup(List children = {});\n};\n"
  },
  {
    "path": "apps/vaporgui/VHBoxWidget.cpp",
    "content": "#include <iostream>\n#include <QEvent>\n#include <QWidget>\n\n#include \"VHBoxWidget.h\"\n\nconst int VHBoxWidget::_LEFT_MARGIN = 0;\nconst int VHBoxWidget::_TOP_MARGIN = 0;\nconst int VHBoxWidget::_RIGHT_MARGIN = 0;\nconst int VHBoxWidget::_BOTTOM_MARGIN = 0;\n\nVHBoxWidget::VHBoxWidget() : QFrame()\n{\n    QHBoxLayout *layout = new QHBoxLayout;\n    layout->setContentsMargins(_LEFT_MARGIN, _TOP_MARGIN, _RIGHT_MARGIN, _BOTTOM_MARGIN);\n    setLayout(layout);\n\n    setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);\n}\n\nMouseWheelWidgetAdjustmentGuard::MouseWheelWidgetAdjustmentGuard(QObject *parent) : QObject(parent) {}\n\nbool MouseWheelWidgetAdjustmentGuard::eventFilter(QObject *o, QEvent *e)\n{\n    const QWidget *widget = dynamic_cast<QWidget *>(o);\n    if (e->type() == QEvent::Wheel && widget && !widget->hasFocus()) {\n        e->ignore();\n        return true;\n    }\n\n    return QObject::eventFilter(o, e);\n}\n\n// QSize VContainer::sizeHint() const {\n//    QWidget* parent = this->parentWidget();\n//    if ( layout()->count() > 1 ) {\n//        return QSize( parent->width() / 2., 20 );\n//    }\n//    else {\n//        return QSize( parent->width() / 3. , 20 );\n//    }\n//}\n"
  },
  {
    "path": "apps/vaporgui/VHBoxWidget.h",
    "content": "#pragma once\n\n#include <QFrame>\n#include <QHBoxLayout>\n\n#include <string>\n\n#include \"VLineItem.h\"\n\n//! \\class VContainer\n//!\n//! A simple wrapper class for one or more VWidgets.\n//! Sets a standard layout and margin policy, and protects\n//! against unwanted mouse scroll whell events.\n\nclass VHBoxWidget : public QFrame {\n    Q_OBJECT\n\npublic:\n    //    virtual QSize sizeHint() const;\n    VHBoxWidget();\n\nprivate:\n    static const int _LEFT_MARGIN;\n    static const int _TOP_MARGIN;\n    static const int _RIGHT_MARGIN;\n    static const int _BOTTOM_MARGIN;\n};\n\n// Helper object for disabling the mouse scroll-wheel on a given widget.\n//\n\n#include <QObject>\n\nclass MouseWheelWidgetAdjustmentGuard : public QObject {\npublic:\n    explicit MouseWheelWidgetAdjustmentGuard(QObject *parent);\n\nprotected:\n    bool eventFilter(QObject *o, QEvent *e) override;\n};\n"
  },
  {
    "path": "apps/vaporgui/VHyperlink.cpp",
    "content": "#include \"VHyperlink.h\"\n#include <QLabel>\n\nVHyperlink::VHyperlink(const std::string &text, const std::string &url, bool bullet) : VLabel() {\n    std::string link = \"<a href=\\\"\" + url + \"\\\">\" + text + \"</a>\";\n    if (bullet == true) link.insert(0, \"• \");\n    _ql->setText(QString::fromStdString(link));\n    _ql->setTextFormat(Qt::RichText);\n    _ql->setTextInteractionFlags(Qt::TextBrowserInteraction);\n    _ql->setOpenExternalLinks(true);\n}\n"
  },
  {
    "path": "apps/vaporgui/VHyperlink.h",
    "content": "#pragma once\n\n#include \"VLabel.h\"\n\n//! \\class VHyperlink\n//! A VLabel that contains a hyperlink and optional bulletpoint\n\nclass VHyperlink : public VLabel {\npublic:\n    VHyperlink(const std::string &text = \"\", const std::string &url = \"\", bool bullet=false);\n};\n"
  },
  {
    "path": "apps/vaporgui/VIntLineEdit.cpp",
    "content": "#include <string>\n#include <sstream>\n#include <iomanip>\n\n#include <QString>\n\n#include <ErrorReporter.h>\n\n#include \"VIntLineEdit.h\"\n\nVIntLineEdit::VIntLineEdit(int value) : VNumericLineEdit(), _value(value)\n{\n    std::string formattedNumber = _formatValue(_value);\n    SetValueString(formattedNumber);\n}\n\nvoid VIntLineEdit::SetValueInt(int value)\n{\n    std::string formattedNumber = _formatValue(value);\n\n    try {\n        _value = (int)std::stod(formattedNumber);\n    } catch (const std::invalid_argument &) {\n        return;\n    } catch (const std::out_of_range &) {\n        return;\n    }\n\n    SetValueString(formattedNumber);\n}\n\nint VIntLineEdit::GetValueInt() const { return _value; }\n\nvoid VIntLineEdit::_valueChanged()\n{\n    std::string str = _getText();\n\n    int value;\n    try {\n        double dValue = std::stod(str);\n\n        if (_checkOverflow(dValue)) {\n            SetValueInt(_value);\n            return;\n        }\n\n        value = (int)std::stod(str);\n\n        // If value changed, update and emit, otherwiese revert to old value\n        if (value != _value) {\n            SetValueInt(value);\n            emit ValueChanged(_value);\n        } else {\n            SetValueInt(_value);\n        }\n    } catch (const std::invalid_argument &) {\n        SetValueInt(_value);\n    } catch (const std::out_of_range &) {\n        SetValueInt(_value);\n    }\n}\n\nstd::string VIntLineEdit::_formatValue(int value)\n{\n    std::stringstream stream;\n    stream << std::fixed << std::setprecision(_decimalDigits);\n    if (_sciNotation) {\n        stream << std::scientific;\n        stream << (double)value;\n    } else {\n        stream << value;\n    }\n    return stream.str();\n}\n\nbool VIntLineEdit::_checkOverflow(double value)\n{\n    std::stringstream svalue;\n    svalue << std::fixed << std::setprecision(0) << value;\n    std::string error = \"Value \" + svalue.str() + \" exceeds \";\n\n    if (value < INT_MIN) {\n        error += \" minimum integer limit (\" + std::to_string(INT_MIN) + \").\";\n        MSG_ERR(error);\n        return true;\n    }\n    if (value > INT_MAX) {\n        error += \" maximum integer limit (\" + std::to_string(INT_MAX) + \").\";\n        MSG_ERR(error);\n        return true;\n    }\n\n    return false;\n}\n"
  },
  {
    "path": "apps/vaporgui/VIntLineEdit.h",
    "content": "#pragma once\n\n#include <iostream>\n\n#include <string>\n#include <sstream>\n#include <iomanip>\n\n#include <QString>\n\n#include \"VNumericLineEdit.h\"\n\n//! \\class VIntLineEdit\n//! \\ingroup Public_GUI\n//! \\brief A wrapper for a QLineEdit that handles user input of type int,\n//! and provides Vapor's standard setters, getters, and signals\n\nclass VIntLineEdit : public VNumericLineEdit {\n    Q_OBJECT\n\npublic:\n    VIntLineEdit(int value = 0);\n\n    //! Set the current int value in the line edit\n    void SetValueInt(int value);\n\n    //! Get the current int value in the line iedit\n    int GetValueInt() const;\n\nprotected:\n    virtual void _valueChanged();\n\n    std::string _formatValue(int value);\n    bool        _checkOverflow(double value);\n\n    int _value;\n\nsignals:\n    void ValueChanged(int value);\n};\n"
  },
  {
    "path": "apps/vaporgui/VIntRangeMenu.cpp",
    "content": "#include \"VIntRangeMenu.h\"\n#include \"VActions.h\"\n\nVIntRangeMenu::VIntRangeMenu(QWidget *parent, bool sciNotation, int decimalDigits, int min, int max, bool rangeChangable)\n: VNumericFormatMenu(parent, sciNotation, decimalDigits), _minRangeAction(new VIntLineEditAction(\"Minimum value\", min)), _maxRangeAction(new VIntLineEditAction(\"Maximum value\", max))\n{\n    connect(_minRangeAction, &VIntLineEditAction::ValueChanged, this, &VIntRangeMenu::_minChanged);\n    addAction(_minRangeAction);\n\n    connect(_maxRangeAction, &VIntLineEditAction::ValueChanged, this, &VIntRangeMenu::_maxChanged);\n    addAction(_maxRangeAction);\n\n    if (!rangeChangable) {\n        _minRangeAction->setEnabled(false);\n        _maxRangeAction->setEnabled(false);\n    }\n}\n\nvoid VIntRangeMenu::AllowUserRange(bool allowed)\n{\n    _minRangeAction->setEnabled(allowed);\n    _maxRangeAction->setEnabled(allowed);\n}\n\nvoid VIntRangeMenu::SetMinimum(int min) { _minRangeAction->SetValue(min); }\n\nvoid VIntRangeMenu::SetMaximum(int max) { _maxRangeAction->SetValue(max); }\n\nvoid VIntRangeMenu::_minChanged(int min) { emit MinChanged(min); }\n\nvoid VIntRangeMenu::_maxChanged(int max) { emit MaxChanged(max); }\n"
  },
  {
    "path": "apps/vaporgui/VIntRangeMenu.h",
    "content": "#pragma once\n\n#include \"VNumericFormatMenu.h\"\n\nclass VIntLineEditAction;\n\n//! \\class VIntRangeMenu\n//! \\ingroup Public_GUI\n//! \\brief A menu that allows the user to control the range of integer values\n//! that can be set by a widget.  Also allows for setting the numeric format\n//! that the number is displayed with.\n\nclass VIntRangeMenu : public VNumericFormatMenu {\n    Q_OBJECT\n\npublic:\n    explicit VIntRangeMenu(QWidget *parent, bool sciNotation, int decimalDigits, int min, int max, bool rangeChangable = false);\n\n    void AllowUserRange(bool allowed = true);\n\nprotected:\n    VIntLineEditAction *_minRangeAction;\n    VIntLineEditAction *_maxRangeAction;\n\npublic:\n    //! Set the minimum value that the current widget can use\n    void SetMinimum(int min);\n\n    //! Set the maximum value that the current widget can use\n    void SetMaximum(int max);\n\nprivate slots:\n    void _minChanged(int min);\n    void _maxChanged(int max);\n\nsignals:\n    void MinChanged(int min);\n    void MaxChanged(int max);\n};\n"
  },
  {
    "path": "apps/vaporgui/VIntSliderEdit.cpp",
    "content": "#include <cmath>\n#include <iostream>\n\n#include \"vapor/VAssert.h\"\n\n#include \"VIntSliderEdit.h\"\n#include \"VIntLineEdit.h\"\n#include \"VIntSliderEditMenu.h\"\n#include \"VSlider.h\"\n\nVIntSliderEdit::VIntSliderEdit(int min, int max, int value, bool rangeChangable) : VSliderEditInterface(), _value(value), _rangeChangable(rangeChangable)\n{\n    _slider->SetRange(min, max);\n    _slider->SetValue(value);\n    connect(_slider, &VSlider::ValueChanged, this, &VIntSliderEdit::SetValue);\n    connect(_slider, &VSlider::ValueChangedIntermediate, this, &VIntSliderEdit::_sliderChangedIntermediate);\n\n    _lineEdit = new VIntLineEdit(value);\n    _lineEdit->RemoveContextMenu();\n    layout()->addWidget(_lineEdit);\n    connect(_lineEdit, SIGNAL(ValueChanged(int)), this, SLOT(SetValue(int)));\n\n    _makeContextMenu();\n}\n\nvoid VIntSliderEdit::AllowUserRange(bool allowed)\n{\n    _rangeChangable = allowed;\n    _menu->AllowUserRange(allowed);\n}\n\nvoid VIntSliderEdit::_makeContextMenu()\n{\n    _menu = new VIntSliderEditMenu(this);\n    connect(_menu, &VNumericFormatMenu::DecimalDigitsChanged, this, &VIntSliderEdit::SetNumDigits);\n    connect(_menu, &VNumericFormatMenu::SciNotationChanged, this, &VIntSliderEdit::SetSciNotation);\n    connect(_menu, &VIntRangeMenu::MinChanged, this, &VIntSliderEdit::SetMinimum);\n    connect(_menu, &VIntRangeMenu::MaxChanged, this, &VIntSliderEdit::SetMaximum);\n    connect(_menu, &VIntSliderEditMenu::DynamicUpdateChanged, this, &VIntSliderEdit::SetDynamicUpdate);\n}\n\nvoid VIntSliderEdit::AllowDynamicUpdate() const { _menu->AllowDynamicUpdate(); }\n\nvoid VIntSliderEdit::SetDynamicUpdate(bool enabled) { emit DynamicUpdateChanged(enabled); }\n\nbool VIntSliderEdit::GetSciNotation() const { return _lineEdit->GetSciNotation(); }\n\nvoid VIntSliderEdit::SetSciNotation(bool value)\n{\n    if (value == _lineEdit->GetSciNotation()) { return; }\n    _lineEdit->SetSciNotation(value);\n    emit FormatChanged();\n}\n\nint VIntSliderEdit::GetNumDigits() const { return _lineEdit->GetNumDigits(); }\n\nvoid VIntSliderEdit::SetNumDigits(int digits)\n{\n    if (digits == _lineEdit->GetNumDigits()) { return; }\n    _lineEdit->SetNumDigits(digits);\n    emit FormatChanged();\n}\n\nint VIntSliderEdit::GetValue() const { return _value; }\n\nvoid VIntSliderEdit::SetValue(int value)\n{\n    // If the new value is unchanged or illegal, reset _lineEdit and return\n    if (value == _value || value < _slider->GetMinimum() || value > _slider->GetMaximum()) {\n        _lineEdit->SetValueInt(_value);\n        return;\n    }\n\n    _value = value;\n\n    _lineEdit->SetValueInt(_value);\n    _slider->SetValue(_value);\n\n    if (QObject::sender() != nullptr && QObject::sender() != this) { emit ValueChanged(_value); }\n}\n\nint VIntSliderEdit::GetMinimum() const\n{\n    return _slider->GetMinimum();\n    ;\n}\n\nvoid VIntSliderEdit::SetMinimum(int min)\n{\n    // If the new value is unchanged, or illegal, reset the menu and retur\n    if (min == _slider->GetMinimum() || min > _slider->GetMaximum()) {\n        if (min > _value) {\n            _value = min;\n            SetValue(_value);\n        }\n        _menu->SetMinimum(_slider->GetMinimum());\n        return;\n    }\n\n    _slider->SetMinimum(min);\n    _menu->SetMinimum(min);\n\n    // If sender() is a nullptr, then this fuction is being called from Update().\n    // Don't emit anythong.  Otherwise, emit our signal.\n    if (QObject::sender() != nullptr) { emit MinimumChanged(min); }\n}\n\nint VIntSliderEdit::GetMaximum() const { return _slider->GetMaximum(); }\n\nvoid VIntSliderEdit::SetMaximum(int max)\n{\n    // If the new value is unchanged, or illegal, reset the menu and return\n    if (max == _slider->GetMaximum() || max < _slider->GetMinimum()) {\n        if (max < _value) {\n            _value = max;\n            SetValue(_value);\n        }\n        _menu->SetMaximum(_slider->GetMaximum());\n        return;\n    }\n\n    _slider->SetMaximum(max);\n\n    _menu->SetMaximum(max);\n\n    // If sender() is a nullptr, then this fuction is being called from Update().\n    // Don't emit anythong.  Otherwise, emit our signal.\n    if (QObject::sender() != nullptr) { emit MaximumChanged(max); }\n}\n\nvoid VIntSliderEdit::ShowContextMenu(const QPoint &pos)\n{\n    QPoint globalPos = mapToGlobal(pos);\n    _menu->exec(globalPos);\n}\n\nvoid VIntSliderEdit::_sliderChangedIntermediate(int value)\n{\n    dynamic_cast<VIntLineEdit *>(_lineEdit)->SetValueInt(value);\n    emit ValueChangedIntermediate(value);\n}\n"
  },
  {
    "path": "apps/vaporgui/VIntSliderEdit.h",
    "content": "#pragma once\n\n#include <string>\n#include \"VHBoxWidget.h\"\n#include \"VSliderEditInterface.h\"\n\nclass VIntSliderEditMenu;\nclass VIntLineEdit;\n\n//! \\class VIntSliderEdit\n//! \\ingroup Public_GUI\n//! \\brief A wrapper for a VSlider and a VIntLineEdit, that\n//! provides synchronization between the two widgets, and support\n//! for a menu that allows setting and getting the VSlider range,\n//! and the numeric representation of the VIntLineEdit\n\nclass VIntSliderEdit : public VSliderEditInterface {\n    Q_OBJECT\n\npublic:\n    VIntSliderEdit(int min = 0, int max = 10, int value = 3, bool rangeChangable = false);\n\n    //! Set the dynamic update menu item's toggle state\n    virtual void SetDynamicUpdate(bool enabled);\n\n    //! Set the minimum allowable value for the VSlider and VIntLineEdit\n    void SetMinimum(int min);\n\n    //! Set the maximum allowable value for the VSlider and VIntLineEdit\n    void SetMaximum(int max);\n\n    void AllowUserRange(bool allowed = true);\n\n    //! Allow the toggling of dynamic updating widgets\n    void AllowDynamicUpdate() const;\n\n    //! Get the value associated with the VSlider and VIntLineEdit\n    int GetValue() const;\n\n    //! Get the minimum allowable value for the VSlider and VIntLineEdit\n    int GetMinimum() const;\n\n    //! Get the maximum allowable value for the VSlider and VIntLineEdit\n    int GetMaximum() const;\n\n    //! Get the number of digits displayed by the VIntLineEdit\n    virtual int GetNumDigits() const;\n\n    //! Set the number of digits displayed by the VIntLineEdit\n    virtual void SetNumDigits(int numDigits);\n\n    //! Get whether the VIntLineEdit is being displayed with scientific notation\n    virtual bool GetSciNotation() const;\n\n    //! Set whether the VIntLineEdit is being displayed with scientific notation\n    virtual void SetSciNotation(bool sciNotation);\n\n    //! Show the context menu options for the entire widget, triggered on right-click\n    virtual void ShowContextMenu(const QPoint &pos);\n\npublic slots:\n    //! Set the current value displayed by the slider and line edit\n    void SetValue(int value);\n\nprotected:\n    virtual void _makeContextMenu();\n    void         _sliderChanged(int value);\n    void         _sliderChangedIntermediate(int value);\n\n    int  _value;\n    bool _rangeChangable;\n\n    VIntSliderEditMenu *_menu;\n    VIntLineEdit * _lineEdit;\n\nsignals:\n    void ValueChanged(int value);\n    void ValueChangedIntermediate(int value);\n    void MinimumChanged(int min);\n    void MaximumChanged(int max);\n    void DynamicUpdateChanged(bool enabled);\n};\n"
  },
  {
    "path": "apps/vaporgui/VIntSliderEditMenu.cpp",
    "content": "#include <QWidget>\n\n#include \"VActions.h\"\n#include \"VIntSliderEditMenu.h\"\n\n// clang-format off\n\nVIntSliderEditMenu::VIntSliderEditMenu( QWidget *parent ) : \nVIntRangeMenu( parent, false, 2, 0., 10., false )\n{\n    _dynamicUpdateAction = new VCheckBoxAction(\"Dynamic update enabled\", false);\n    connect(_dynamicUpdateAction, &VCheckBoxAction::clicked, this, &VIntSliderEditMenu::_dynamicUpdateChanged);\n    addAction(_dynamicUpdateAction);\n    _dynamicUpdateAction->setEnabled(false);\n}\n\nvoid VIntSliderEditMenu::AllowDynamicUpdate() const { _dynamicUpdateAction->setEnabled(true); }\n\nvoid VIntSliderEditMenu::SetDynamicUpdate(bool dynamicUpdateEnabled) { _dynamicUpdateAction->SetValue(dynamicUpdateEnabled); }\n\nvoid VIntSliderEditMenu::_dynamicUpdateChanged(bool dynamicUpdateEnabled) { emit DynamicUpdateChanged(dynamicUpdateEnabled); }\n\n// clang-format on\n"
  },
  {
    "path": "apps/vaporgui/VIntSliderEditMenu.h",
    "content": "#pragma once\n\n#include <QMenu>\n#include \"VIntRangeMenu.h\"\n\nclass VCheckBoxAction;\n\n//! \\class VIntSliderEditMenu\n//! \\ingroup Public_GUI\n//! \\brief A menu for VIntSliderEdit that allows for setting\n//! a min/max range, numeric formatting controls, and dynamic update controls\n//! in regard to how many digits are displayed, and whether scientific notation is used.\n\n// clang-format off\n\nclass VIntSliderEditMenu : public VIntRangeMenu {\n    Q_OBJECT\n\npublic:\n    explicit VIntSliderEditMenu( QWidget *parent );\n\n    //! Allow the toggling of the dynamic update checkbox in the right-click menu\n    void AllowDynamicUpdate() const;\n\nprotected:\n    VCheckBoxAction *_dynamicUpdateAction;\n\npublic slots:\n    //! Check/Uncheck the dynamic update checkbox\n    void SetDynamicUpdate(bool enabled);\n\nprivate slots:\n    void _dynamicUpdateChanged(bool dynamicUpdateEnabled);\n\nsignals:\n    void DynamicUpdateChanged(bool dynamicUpdateEnabled);\n};\n\n// clang-format on\n"
  },
  {
    "path": "apps/vaporgui/VIntSpinBox.cpp",
    "content": "#include <QLineEdit>\n#include \"VIntSpinBox.h\"\n#include <iostream>\nVIntSpinBox::VIntSpinBox(int min, int max) : VHBoxWidget(), _value(min)\n{\n    _spinBox = new QSpinBox;\n    SetRange(min, max);\n    SetValue(min);\n    layout()->addWidget(_spinBox);\n    _spinBox->setKeyboardTracking(false);\n\n    // Emit when the spinbox loses focus, or when return is pressed\n    // Note: when opening a context menu with right click, a QSpinBox will emit the editingFinished signal,\n    // due to the QLineEdit receiving focus upon click, and losing focus upon opening the menu.\n    // In the VIntSpinBox's slot, we must therefore check if the currently held value has changed before emitting.\n    connect(_spinBox, &QSpinBox::editingFinished, this, &VIntSpinBox::emitValueChanged);\n\n    // QSpinBox overloads valueChanged.  This makes the function pointer\n    // based syntax for signal and slot connection ugly, so defer to\n    // SIGNAL/SLOT connections with data type specificaiton.\n    //\n    // More info here: https://doc.qt.io/qt-5/qspinbox.html#valueChanged\n    connect(_spinBox, SIGNAL(valueChanged(int)), this, SLOT(emitValueChangedIntermediate(int)));\n}\n\nvoid VIntSpinBox::SetValue(int value)\n{\n    _value = value;\n    _spinBox->blockSignals(true);\n    _spinBox->setValue(_value);\n    _spinBox->blockSignals(false);\n}\n\nvoid VIntSpinBox::SetRange(int min, int max)\n{\n    blockSignals(true);\n    _spinBox->setRange(min, max);\n    blockSignals(false);\n}\n\nint VIntSpinBox::GetValue() const { return _spinBox->value(); }\n\nvoid VIntSpinBox::emitValueChanged()\n{\n    int value = GetValue();\n    if (value != _value) {\n        _value = value;\n        emit ValueChanged(_value);\n    }\n}\n\nvoid VIntSpinBox::emitValueChangedIntermediate(int value) { emit ValueChangedIntermediate(value); }\n"
  },
  {
    "path": "apps/vaporgui/VIntSpinBox.h",
    "content": "#pragma once\n\n#include <string>\n\n#include <QWidget>\n#include <QSpinBox>\n\n#include \"VHBoxWidget.h\"\n\n//! class VIntSpinBox\n//!\n//! Wraps a QSpinBox and provides vaporgui's standard setter/getter functions\n//! and signals.\n\nclass VIntSpinBox : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    VIntSpinBox(int min, int max);\n\n    void SetValue(int value);\n    void SetRange(int min, int max);\n\n    int GetValue() const;\n\nprivate:\n    QSpinBox *_spinBox;\n    int       _value;\n\npublic slots:\n    void emitValueChanged();\n    void emitValueChangedIntermediate(int value);\n\nsignals:\n    void ValueChanged(int value);\n    void ValueChangedIntermediate(int value);\n};\n"
  },
  {
    "path": "apps/vaporgui/VLabel.cpp",
    "content": "#include \"VLabel.h\"\n#include <QLabel>\n\nVLabel::VLabel(const std::string &text) : VContainer(_ql = new QLabel)\n{\n    _ql->setWordWrap(true);\n    SetText(text);\n}\n\nvoid VLabel::SetText(const std::string &text) { _ql->setText(QString::fromStdString(text)); }\n\nvoid VLabel::MakeSelectable() { _ql->setTextInteractionFlags(_ql->textInteractionFlags() | Qt::TextSelectableByMouse); }\n"
  },
  {
    "path": "apps/vaporgui/VLabel.h",
    "content": "#pragma once\n\n#include \"VContainer.h\"\n#include <string>\n\nclass QLabel;\n\nclass VLabel : public VContainer {\n\nprotected:\n    QLabel *_ql;\n\npublic:\n    VLabel(const std::string &text = \"\");\n    void SetText(const std::string &text);\n    void MakeSelectable();\n};\n"
  },
  {
    "path": "apps/vaporgui/VLabelPair.cpp",
    "content": "#include \"VLabelPair.h\"\n#include <QLabel>\n\nVLabelPair::VLabelPair() : VHBoxWidget() {\n    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);\n\n    _leftLabel = new QLabel();\n    _rightLabel = new QLabel();\n    _rightLabel->setAlignment(Qt::AlignRight);\n\n    layout()->addWidget(_leftLabel);\n    layout()->addWidget(_rightLabel);\n}\n\nvoid VLabelPair::SetLeftText(const std::string &text) const {\n    _leftLabel->setText(QString::fromStdString(text));\n}\n\nvoid VLabelPair::SetRightText(const std::string &text) const {\n    _rightLabel->setText(QString::fromStdString(text));\n}\n"
  },
  {
    "path": "apps/vaporgui/VLabelPair.h",
    "content": "#include \"VHBoxWidget.h\"\n\nclass QLabel;\n\n//! \\class VLabelPair\n//! \\brief A VHBoxWidget that contains a pair of labels that can be set independently\n\nclass VLabelPair : public VHBoxWidget {\n    Q_OBJECT\n\n    QLabel *_leftLabel;\n    QLabel *_rightLabel;\n\npublic:\n    VLabelPair();\n    void SetLeftText(const std::string &text) const;\n    void SetRightText(const std::string &text) const;\n};\n"
  },
  {
    "path": "apps/vaporgui/VLineEdit_Deprecated.cpp",
    "content": "#include <iostream>\n#include <iomanip>\n#include <string>\n#include <sstream>\n\n#include <QMenu>\n\n#include \"VLineEdit_Deprecated.h\"\n#include \"ErrorReporter.h\"\n\nVLineEdit_Deprecated::VLineEdit_Deprecated(const std::string &value) : VHBoxWidget(), _value(value), _isDouble(false), _scientific(false), _menuEnabled(false), _decDigits(10)\n{\n    _lineEdit = new QLineEdit;\n    SetValue(_value);\n    layout()->addWidget(_lineEdit);\n\n    connect(_lineEdit, &QLineEdit::editingFinished, this, &VLineEdit_Deprecated::emitLineEditChanged);\n}\n\nvoid VLineEdit_Deprecated::UseDoubleMenu()\n{\n    _menuEnabled = true;\n\n    _lineEdit->setContextMenuPolicy(Qt::CustomContextMenu);\n    connect(_lineEdit, &QLineEdit::customContextMenuRequested, this, &VLineEdit_Deprecated::ShowContextMenu);\n}\n\nvoid VLineEdit_Deprecated::SetValue(double value)\n{\n    VAssert(_isDouble);\n\n    std::stringstream stream;\n    if (_menuEnabled) {\n        stream << std::fixed << std::setprecision(_decDigits);\n        if (_scientific) stream << std::scientific;\n    }\n    stream << value << std::endl;\n    _value = stream.str();\n\n    _lineEdit->blockSignals(true);\n    _lineEdit->setText(QString::fromStdString(_value));\n    _lineEdit->blockSignals(false);\n}\n\nvoid VLineEdit_Deprecated::SetValue(const std::string &value)\n{\n    _value = value;\n\n    _lineEdit->blockSignals(true);\n    _lineEdit->setText(QString::fromStdString(_value));\n    _lineEdit->blockSignals(false);\n}\n\nstd::string VLineEdit_Deprecated::GetValue() const { return _value; }\n\nvoid VLineEdit_Deprecated::SetIsDouble(bool isDouble) { _isDouble = isDouble; }\n\nvoid VLineEdit_Deprecated::SetReadOnly(bool b) { _lineEdit->setReadOnly(b); }\n\nvoid VLineEdit_Deprecated::emitLineEditChanged()\n{\n    std::string value = _lineEdit->text().toStdString();\n    SetValue(value);\n    emit ValueChanged(_value);\n}\n\nvoid VLineEdit_Deprecated::ShowContextMenu(const QPoint &pos)\n{\n    if (!_menuEnabled) return;\n\n    QMenu menu;\n\n    SpinBoxAction *decimalAction = new SpinBoxAction(tr(\"Decimal digits\"), _decDigits);\n    connect(decimalAction, &SpinBoxAction::editingFinished, this, &VLineEdit_Deprecated::_decimalDigitsChanged);\n    menu.addAction(decimalAction);\n\n    CheckBoxAction *checkBoxAction = new CheckBoxAction(tr(\"Scientific\"), _scientific);\n    connect(checkBoxAction, &CheckBoxAction::clicked, this, &VLineEdit_Deprecated::_scientificClicked);\n    menu.addAction(checkBoxAction);\n\n    QPoint globalPos = _lineEdit->mapToGlobal(pos);\n    menu.exec(globalPos);\n}\n\nvoid VLineEdit_Deprecated::_decimalDigitsChanged(int value)\n{\n    _decDigits = value;\n    SetValue(_value);\n}\n\nvoid VLineEdit_Deprecated::_scientificClicked(bool value)\n{\n    _scientific = value;\n    SetValue(_value);\n}\n"
  },
  {
    "path": "apps/vaporgui/VLineEdit_Deprecated.h",
    "content": "#pragma once\n\n#include <string>\n\n#include <QWidget>\n#include <QLabel>\n#include <QLineEdit>\n#include <QSpinBox>\n#include <QCheckBox>\n#include <QWidgetAction>\n\n#include \"VHBoxWidget.h\"\n\n//! \\class VLineEdit_Deprecated\n//!\n//! Wraps a QLineEdit with vaporgui's standard setter/getter functions.\n//! Handles string and double types, as well as precision and display of\n//! double values.\n\nclass VLineEdit_Deprecated : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    VLineEdit_Deprecated(const std::string &value = \"\");\n\n    void        SetValue(double value);\n    void        SetValue(const std::string &value);\n    std::string GetValue() const;\n\n    // Note: VLineEdit_Deprecated does NOT support an integer type at this point.\n    // When isDouble == false, it represents a string.\n    void SetIsDouble(bool isDouble);\n    //! Sets the line edit to read-only based on the value of b\n    void SetReadOnly(bool b);\n\n    void UseDoubleMenu();\n\nprivate:\n    QLineEdit *_lineEdit;\n\n    std::string _value;\n    bool        _isDouble;\n    bool        _scientific;\n    bool        _menuEnabled;\n    int         _decDigits;\n\npublic slots:\n    void emitLineEditChanged();\n\n    void ShowContextMenu(const QPoint &);\n\nprivate slots:\n    void _decimalDigitsChanged(int value);\n    void _scientificClicked(bool value);\n\nsignals:\n    void ValueChanged(const std::string &value);\n};\n\nclass SpinBoxAction : public QWidgetAction {\n    Q_OBJECT\n\npublic:\n    SpinBoxAction(const QString &title, int value) : QWidgetAction(NULL)\n    {\n        QWidget *    widget = new QWidget(NULL);\n        QHBoxLayout *layout = new QHBoxLayout();\n        QLabel *     label = new QLabel(title);    // bug fixed here, pointer was missing\n        _spinBox = new QSpinBox(NULL);\n\n        _spinBox->setValue(value);\n        layout->setContentsMargins(-1, 0, -1, 0);\n        layout->addWidget(label);\n        layout->addWidget(_spinBox);\n        widget->setLayout(layout);\n\n        // We need to use SIGNAL/SLOT macros here because the arguments\n        // of the signal and slot do not match\n        connect(_spinBox, SIGNAL(valueChanged(int)), this, SLOT(spinBoxChanged()));\n\n        setDefaultWidget(widget);\n    }\n\nprivate:\n    QSpinBox *_spinBox;\n\nprivate slots:\n    void spinBoxChanged()\n    {\n        int  value = _spinBox->value();\n        emit editingFinished(value);\n    }\n\nsignals:\n    void editingFinished(int);\n};\n\nclass CheckBoxAction : public QWidgetAction {\n    Q_OBJECT\n\npublic:\n    CheckBoxAction(const QString &title, bool value) : QWidgetAction(NULL)\n    {\n        QWidget *    widget = new QWidget(NULL);\n        QHBoxLayout *layout = new QHBoxLayout();\n        QLabel *     label = new QLabel(title);\n        _checkBox = new QCheckBox(NULL);\n        _checkBox->setChecked(value);\n\n        layout->setContentsMargins(-1, 0, 20, 0);\n        layout->addWidget(label);\n        layout->addStretch();\n        layout->addWidget(_checkBox);\n        widget->setLayout(layout);\n\n        connect(_checkBox, &QCheckBox::clicked, this, &CheckBoxAction::checkBoxChanged);\n\n        setDefaultWidget(widget);\n    }\n\nprivate:\n    QCheckBox *_checkBox;\n\nprivate slots:\n    void checkBoxChanged(bool value) { emit clicked(value); }\n\nsignals:\n    void clicked(bool);\n};\n"
  },
  {
    "path": "apps/vaporgui/VLineItem.cpp",
    "content": "#include <iostream>\n\n#include \"VLineItem.h\"\n#include <QHBoxLayout>\n#include <QLabel>\n\nconst int VLineItem::_LEFT_MARGIN = 0;\nconst int VLineItem::_TOP_MARGIN = 0;\nconst int VLineItem::_RIGHT_MARGIN = 0;\nconst int VLineItem::_BOTTOM_MARGIN = 0;\n\nVLineItem::VLineItem(const std::string &label, QLayoutItem *centerItem, QWidget *rightWidget) : VLineItem(label)\n{\n    layout()->addItem(centerItem);\n    layout()->addWidget(rightWidget);\n}\n\nVLineItem::VLineItem(const std::string &label, QWidget *centerWidget, QWidget *rightWidget) : VLineItem(label)\n{\n    layout()->addWidget(centerWidget);\n    layout()->addWidget(rightWidget);\n}\n\nVLineItem::VLineItem(const std::string &label, QWidget *rightWidget) : VLineItem(label, (QLayoutItem *)new QSpacerItem(0, 20, QSizePolicy::Maximum, QSizePolicy::Minimum), rightWidget) {}\n\nVLineItem::VLineItem(const std::string &label)\n{\n    setLayout(new QHBoxLayout);\n    layout()->setContentsMargins(_LEFT_MARGIN, _TOP_MARGIN, _RIGHT_MARGIN, _BOTTOM_MARGIN);\n\n    QLabel *qLabel = new QLabel(label.c_str());\n    layout()->addWidget(qLabel);\n}\n"
  },
  {
    "path": "apps/vaporgui/VLineItem.h",
    "content": "#pragma once\n\n#include <QWidget>\n#include <QLayoutItem>\n#include <string>\n\n//! \\class VLineItem\n//! A widget that creates a label - input pair separated by a spacer\n//! as is used throughout vapor\n\nclass VLineItem : public QWidget {\n    Q_OBJECT\n\npublic:\n    VLineItem(const std::string &label, QLayoutItem *centerItem, QWidget *rightWidget);\n    VLineItem(const std::string &label, QWidget *centerWidget, QWidget *rightWidget);\n    VLineItem(const std::string &label, QWidget *rightWidget);\n\nprivate:\n    static const int _LEFT_MARGIN;\n    static const int _TOP_MARGIN;\n    static const int _BOTTOM_MARGIN;\n    static const int _RIGHT_MARGIN;\n\n    VLineItem(const std::string &label);\n};\n"
  },
  {
    "path": "apps/vaporgui/VNumericFormatMenu.cpp",
    "content": "#include <string>\n#include <sstream>\n#include <iomanip>\n\n#include <QWidget>\n\n#include \"VActions.h\"\n#include \"VNumericFormatMenu.h\"\n\nVNumericFormatMenu::VNumericFormatMenu(QWidget *parent, bool sciNotation, int decimalDigits)\n: QMenu(parent), _sciNotationAction(new VCheckBoxAction(\"Scientific notation\", sciNotation)), _decimalAction(new VSpinBoxAction(\"Decimal digits\", decimalDigits))\n{\n    connect(_sciNotationAction, &VCheckBoxAction::clicked, this, &VNumericFormatMenu::_sciNotationChanged);\n    addAction(_sciNotationAction);\n\n    connect(_decimalAction, &VSpinBoxAction::editingFinished, this, &VNumericFormatMenu::_decimalDigitsChanged);\n    addAction(_decimalAction);\n}\n\nvoid VNumericFormatMenu::SetDecimalDigits(int digits) { _decimalAction->SetValue(digits); }\n\nvoid VNumericFormatMenu::SetSciNotation(bool sciNotation) { _sciNotationAction->SetValue(sciNotation); }\n\nvoid VNumericFormatMenu::_decimalDigitsChanged(int digits) { emit DecimalDigitsChanged(digits); }\n\nvoid VNumericFormatMenu::_sciNotationChanged(bool sciNotation) { emit SciNotationChanged(sciNotation); }\n"
  },
  {
    "path": "apps/vaporgui/VNumericFormatMenu.h",
    "content": "#pragma once\n\n#include <QMenu>\n\nclass VCheckBoxAction;\nclass VSpinBoxAction;\n\n//! \\class VNumericFormatMenu\n//! \\ingroup Public_GUI\n//! \\brief A menu that allows users to specify how a number is displayed in a line edit,\n//! in regard to how many digits are displayed, and whether scientific notation is used.\n\nclass VNumericFormatMenu : public QMenu {\n    Q_OBJECT\n\npublic:\n    explicit VNumericFormatMenu(QWidget *parent, bool sciNotation, int decimalDigits);\n\n    //! Set the number of decimal digits used by the clicked line-edit\n    void SetDecimalDigits(int digits);\n\n    //! Set whether the current line-edit is using scientific notation\n    void SetSciNotation(bool sciNotation);\n\nprotected:\n    VCheckBoxAction *_sciNotationAction;\n    VSpinBoxAction * _decimalAction;\n\nprivate slots:\n    void _decimalDigitsChanged(int digits);\n    void _sciNotationChanged(bool sciNotation);\n\nsignals:\n    void DecimalDigitsChanged(int decimalDigits);\n    void SciNotationChanged(bool sciNotation);\n};\n"
  },
  {
    "path": "apps/vaporgui/VNumericLineEdit.cpp",
    "content": "#include <QLineEdit>\n\n#include \"VNumericFormatMenu.h\"\n#include \"VNumericLineEdit.h\"\n\nVNumericLineEdit::VNumericLineEdit(int decimals) : VStringLineEdit(), _sciNotation(false), _decimalDigits(decimals)\n{\n    _menu = new VNumericFormatMenu(this, _sciNotation, _decimalDigits);\n\n    connect(_menu, &VNumericFormatMenu::SciNotationChanged, this, &VNumericLineEdit::SetSciNotation);\n    connect(_menu, &VNumericFormatMenu::DecimalDigitsChanged, this, &VNumericLineEdit::SetNumDigits);\n    SetCustomContextMenu();\n}\n\nint VNumericLineEdit::GetNumDigits() const { return _decimalDigits; }\n\nvoid VNumericLineEdit::SetNumDigits(int digits)\n{\n    _decimalDigits = digits;\n    _valueChanged();\n    emit DecimalDigitsChanged(_decimalDigits);\n}\n\nbool VNumericLineEdit::GetSciNotation() const { return _sciNotation; }\n\nvoid VNumericLineEdit::SetSciNotation(bool sciNotation)\n{\n    _sciNotation = sciNotation;\n    _valueChanged();\n    emit SciNotationChanged(_sciNotation);\n}\n\nvoid VNumericLineEdit::_showMenu(const QPoint &pos)\n{\n    QPoint globalPos = mapToGlobal(pos);\n    _menu->exec(globalPos);\n};\n"
  },
  {
    "path": "apps/vaporgui/VNumericLineEdit.h",
    "content": "#pragma once\n\n#include <QLineEdit>\n\n#include \"vapor/VAssert.h\"\n\n#include \"VHBoxWidget.h\"\n#include \"VStringLineEdit.h\"\n\nclass VNumericFormatMenu;\nclass VCheckBoxAction;\nclass VSpinBoxAction;\n\n//! \\class VNumericSliderEdit\n//! \\ingroup Public_GUI\n//! \\brief An abstract class defining functions used by different\n//! V*LineEdits (VDoubleLineEdit, VIntLineEdit, and VStringLineEdit).\n//! Supports menus that allow different functionalities, depending\n//! on the data type being used by the line edit.\n\nclass VNumericLineEdit : public VStringLineEdit {\n    Q_OBJECT\n\nprotected:\n    explicit VNumericLineEdit(int decimals = 5);\n\npublic:\n    //! If the line edit is numeric, get the number of digits of the number being displayed\n    int GetNumDigits() const;\n\n    //! If the line edit is numeric, set the number of digits of the number being displayed\n    void SetNumDigits(int digits);\n\n    //! If the line edit is numeric, get whether the display is in scientific notation\n    bool GetSciNotation() const;\n\n    //! If the line edit is numeric, set whether the display is in scientific notation\n    void SetSciNotation(bool sciNotation);\n\nprotected slots:\n\n    //! Called whenever the line edit's value is changed.  Must be reimplemented by derived classes\n    //! to handle correct formatting\n    virtual void _valueChanged() = 0;\n\n    //! Show a custom context menu\n    virtual void _showMenu(const QPoint &pos);\n\nprotected:\n    VNumericFormatMenu *_menu;\n\n    bool _sciNotation;\n    int  _decimalDigits;\n\nsignals:\n\n    // Required to propogate changes from the menus\n    // up to Params, via PWidgets\n    void DecimalDigitsChanged(int decimalDigits);\n    void SciNotationChanged(bool sciNotation);\n};\n"
  },
  {
    "path": "apps/vaporgui/VProjectionStringFrame.cpp",
    "content": "#include <QLayout>\n#include \"VProjectionStringFrame.h\"\n#include \"PProjectionStringWidget.h\"\n\nVProjectionStringFrame::VProjectionStringFrame(PProjectionStringWidget *section) : VFrame(), _section(section) {\n    layout()->addWidget(_section);\n    show();\n}\n\nvoid VProjectionStringFrame::Update(ParamsBase *p, ParamsMgr *pm, DataMgr* dm) {\n    _section->Update(p, pm);\n}\n\nvoid VProjectionStringFrame::closeEvent(QCloseEvent *event) {\n    emit closed();\n    QWidget::closeEvent(event);\n}\n"
  },
  {
    "path": "apps/vaporgui/VProjectionStringFrame.h",
    "content": "#pragma once\n\n#include \"VFrame.h\"\n#include \"ParamsUpdatable.h\"\n\nclass PProjectionStringWidget;\n\nclass VProjectionStringFrame : public VFrame , public ParamsUpdatable {\n    Q_OBJECT\n\n    PProjectionStringWidget *_section;\n\npublic:\n    VProjectionStringFrame(PProjectionStringWidget *psection);\n    void Update(VAPoR::ParamsBase *p, VAPoR::ParamsMgr *pm = nullptr, VAPoR::DataMgr *dm = nullptr) override;\n\nprotected:\n    void closeEvent(QCloseEvent *event) override;\n\nsignals:\n    void closed();\n};\n"
  },
  {
    "path": "apps/vaporgui/VPushButton.cpp",
    "content": "#include \"VPushButton.h\"\n\nVPushButton::VPushButton(const std::string &buttonText) : VHBoxWidget()\n{\n    _pushButton = new QPushButton(QString::fromStdString(buttonText));\n    _pushButton->setFocusPolicy(Qt::NoFocus);\n    layout()->addWidget(_pushButton);\n\n    // We need to use SIGNAL/SLOT macros here because the arguments\n    // of the signal and slot do not match\n    connect(_pushButton, SIGNAL(clicked(bool)), this, SLOT(emitButtonClicked()));\n}\n\nvoid VPushButton::emitButtonClicked() { emit ButtonClicked(); }\n"
  },
  {
    "path": "apps/vaporgui/VPushButton.h",
    "content": "#pragma once\n\n#include <string>\n\n#include <QWidget>\n#include <QPushButton>\n\n#include \"VHBoxWidget.h\"\n\n//! \\class VPushButton\n//!\n//! Wraps a QPushButton with vaporgui's VContainer, so that\n//! the QPushButton follows correct size policy\n\nclass VPushButton : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    VPushButton(const std::string &buttonText = \"Select\");\n\nprivate:\n    QPushButton *_pushButton;\n\npublic slots:\n    void emitButtonClicked();\n\nsignals:\n    void ButtonClicked();\n};\n"
  },
  {
    "path": "apps/vaporgui/VRadioButton.cpp",
    "content": "#include \"VRadioButton.h\"\n#include <QRadioButton>\n\nVRadioButton::VRadioButton(const std::string &label, bool checked) : VHBoxWidget()\n{\n    _radioButton = new QRadioButton(QString::fromStdString(label), nullptr);\n    SetValue(checked);\n    layout()->addWidget(_radioButton);\n\n    connect(_radioButton, &QRadioButton::toggled, this, &VRadioButton::emitRadioButtonChanged);\n}\n\nvoid VRadioButton::SetValue(bool checked)\n{\n    _radioButton->blockSignals(true);\n    _radioButton->setChecked(checked);\n    _radioButton->blockSignals(false);\n}\n\nbool VRadioButton::GetValue() const { return _radioButton->isChecked(); }\n\nstd::string VRadioButton::GetText() const { return _radioButton->text().toStdString(); }\n\nvoid VRadioButton::emitRadioButtonChanged(bool checked) { emit ValueChanged(checked); }\n"
  },
  {
    "path": "apps/vaporgui/VRadioButton.h",
    "content": "#pragma once\n\n#include <string>\n#include <QRadioButton>\n#include \"VHBoxWidget.h\"\n\nclass QRadioButton;\n\n//! class VRadioButton\n//!\n//! Wraps a QRadioButton and provides vaporgui's standard setter/getter functions\n//! and signals.\n\nclass VRadioButton : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    VRadioButton(const std::string &label, bool value = false);\n    void SetValue(bool value);\n    bool GetValue() const;\n    std::string GetText() const;\n\nprivate:\n    QRadioButton *_radioButton;\n\npublic slots:\n    void emitRadioButtonChanged(bool checked);\n\nsignals:\n    void ValueChanged(bool checked);\n};\n"
  },
  {
    "path": "apps/vaporgui/VRouter.cpp",
    "content": "#include \"VRouter.h\"\n#include \"vapor/STLUtils.h\"\n\nVRouter::VRouter() \n: VContainer(_stack = new QStackedWidget)\n{\n}\n\nVRouter::VRouter(AbstractWidgetGroup<VRouter, QWidget>::List children)\n: VContainer(_stack = new QStackedWidget)\n{\n    AddM(children);\n}\n\nVRouter *VRouter::Add(QWidget *w)\n{\n    AbstractWidgetGroup::Add(w);\n    _stack->addWidget(w);\n    return this;\n}\n\nvoid VRouter::Show(QWidget *w)\n{\n    if (w == nullptr)\n        return Show(emptyWidget());\n    if (!STLUtils::Contains(_children, w)) Add(w);\n    _stack->setCurrentWidget(w);\n}\n\nQWidget *VRouter::emptyWidget()\n{\n    if (_emptyWidget == nullptr)\n        _emptyWidget = new QWidget;\n    return _emptyWidget;\n}"
  },
  {
    "path": "apps/vaporgui/VRouter.h",
    "content": "#pragma once\n\n#include \"VContainer.h\"\n#include \"AbstractWidgetGroup.h\"\n#include <QStackedWidget>\n\nclass VRouter : public VContainer, public AbstractWidgetGroup<VRouter, QWidget> {\n    Q_OBJECT\n\n    QStackedWidget *_stack;\n    QWidget *_emptyWidget = nullptr;\n\npublic:\n\tVRouter();\n\tVRouter(List children);\n    VRouter *Add(QWidget *w) override;\n\n    void Show(QWidget *w);\n\nprivate:\n    QWidget *emptyWidget();\n};\n"
  },
  {
    "path": "apps/vaporgui/VScrollArea.cpp",
    "content": "#include \"VScrollArea.h\"\n\nVScrollArea::VScrollArea(QWidget *w)\n{\n    QScrollArea::setWidget(w);\n    QScrollArea::setWidgetResizable(true);\n    sizePolicy().setVerticalStretch(1);\n//    setSizePolicy(QSizePolicy::Ignored,QSizePolicy::Ignored);\n}"
  },
  {
    "path": "apps/vaporgui/VScrollArea.h",
    "content": "#pragma once\n\n#include <QScrollArea>\n\nclass VScrollArea : public QScrollArea {\n    Q_OBJECT\npublic:\n    VScrollArea(QWidget *w);\n};"
  },
  {
    "path": "apps/vaporgui/VScrollGroup.h",
    "content": "#pragma once\n\n#include \"VScrollArea.h\"\n#include \"VGroup.h\"\n#include \"VContainer.h\"\n\nclass VScrollGroup : public VScrollArea, public WidgetGroupWrapper<VScrollGroup, QWidget, VGroup> {\n    Q_OBJECT\n\n    VContainer *_container;\n    VGroup *_group;\npublic:\n    VScrollGroup(List children = {})\n    : VScrollArea(_container = new VContainer(_group = new VGroup())),\n      WidgetGroupWrapper(_group)\n    {\n        _container->AddBottomStretch();\n        _group->AddM(children);//\n    }\n};"
  },
  {
    "path": "apps/vaporgui/VSection.cpp",
    "content": "#include \"VSection.h\"\n#include <QStylePainter>\n#include <QStyleOption>\n#include <vapor/ResourcePath.h>\n\nVSection::VSection(const std::string &title)\n{\n    QTabWidget::addTab(new QWidget, QString::fromStdString(title));\n    _tab()->setLayout(new QVBoxLayout);\n    layout()->setMargin(12);\n    setStyleSheet(_createStylesheet());\n}\n\nQVBoxLayout *VSection::layout() const { return (QVBoxLayout *)_tab()->layout(); }\n\nvoid VSection::setMenu(QMenu *menu)\n{\n    SettingsMenuButton *menuButton = (SettingsMenuButton *)QTabWidget::cornerWidget();\n\n    if (!menuButton) {\n        menuButton = new SettingsMenuButton;\n        QTabWidget::setCornerWidget(menuButton);\n    }\n\n    menuButton->setMenu(menu);\n}\n\nvoid VSection::enableExpandedSection()\n{\n    ExpandSectionButton *expandSectionButton = (ExpandSectionButton *)QTabWidget::cornerWidget();\n    if (!expandSectionButton) {\n        expandSectionButton = new ExpandSectionButton;\n        QTabWidget::setCornerWidget(expandSectionButton, Qt::TopLeftCorner);\n    }\n    connect(expandSectionButton, &QToolButton::clicked, this, [this](){ emit this->expandButtonClicked(); });\n}\n\nstd::string VSection::getTitle() const {\n    return QTabWidget::tabText(0).toStdString();\n}\n\nQWidget *VSection::_tab() const { return QTabWidget::widget(0); }\n\nQString VSection::_createStylesheet() const\n{\n    std::string stylesheet;\n\n#if defined(Darwin)\n    stylesheet +=\n        R\"(\n    QTabWidget::right-corner {\n    top: 24px;\n    right: 3px;\n    }\n    )\";\n    stylesheet +=\n        R\"(\n    QTabWidget::left-corner {\n    top: 24px;\n    left: 3px;\n    }\n    )\";\n#else\n    stylesheet +=\n        R\"(\n    QTabWidget::right-corner {\n    top: -3px;\n    right: 5px;\n    }\n    )\";\n    stylesheet +=\n        R\"(\n    QTabWidget::left-corner {\n    top: -3px;\n    right: 5px;\n    }\n    )\";\n#endif\n\n    return QString::fromStdString(stylesheet);\n}\n\nVSection::SettingsMenuButton::SettingsMenuButton() : AbstractButton()\n{\n    setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath(\"images/gear-dropdown1.png\"))));\n    configureButton();\n}\n\nvoid VSection::SettingsMenuButton::setIconDark(bool darkMode) {\n    if (darkMode) setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath(\"images/gear-dropdown1_darkMode.png\"))));\n    else setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath(\"images/gear-dropdown1.png\"))));\n}\n\nvoid VSection::AbstractButton::setDarkOrLight() {\n    QColor textColor = this->palette().color(QPalette::WindowText);\n    if (textColor.lightness() > 128) setIconDark();\n    else setIconDark(false);\n}\n\nvoid VSection::AbstractButton::paintEvent(QPaintEvent *event)\n{\n    // This function is overridden to prevent Qt from drawing its own dropdown arrow\n    QStylePainter p(this);\n\n    setDarkOrLight();\n\n    QStyleOptionToolButton option;\n    initStyleOption(&option);\n    option.subControls = QStyle::SC_ToolButton;\n    option.features = QStyleOptionToolButton::None;\n    p.drawComplexControl(QStyle::CC_ToolButton, option);\n}\n\nvoid VSection::AbstractButton::configureButton() {\n    setIconSize(QSize(18, 18));\n    setCursor(QCursor(Qt::PointingHandCursor));\n    setPopupMode(QToolButton::InstantPopup);\n\n    setStyleSheet(\"border: none;\"\n                  \"background-color: none;\"\n                  \"padding: 0px;\");\n}\nVSection::ExpandSectionButton::ExpandSectionButton() : AbstractButton()\n{\n    setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath(\"images/expandSection.png\"))));\n    configureButton();\n}\n\nvoid VSection::ExpandSectionButton::setIconDark(bool darkMode) {\n    if (darkMode) setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath(\"images/expandSection_darkMode.png\"))));\n    else setIcon(QIcon(QString::fromStdString(Wasp::GetSharePath(\"images/expandSection.png\"))));\n}\n"
  },
  {
    "path": "apps/vaporgui/VSection.h",
    "content": "#pragma once\n\n#include <QTabWidget>\n#include <QStackedWidget>\n#include <QVBoxLayout>\n#include <string>\n\n#include <QToolButton>\n\n//! \\class VSection\n//! Represents a section/group to be used in the sidebar.\n//! Provides a consistent layout which is not supposed to be changed\n//! Provides a settings menu that is intended to provide extra options for the parameters that are\n//! shown within this section, for example resetting to default values.\n//!\n//! Prefer the use of VSectionGroup when possible.\n\nclass VSection : public QTabWidget {\n    Q_OBJECT\n\n    class SettingsMenuButton;\n    class ExpandSectionButton;\n    class AbstractButton;\n\npublic:\n    VSection(const std::string &title);\n    QVBoxLayout *layout() const;\n    void         setMenu(QMenu *menu);\n    void         enableExpandedSection();\n    std::string getTitle() const;\n\n    void     setLayout(QLayout *layout) = delete;\n    int      addTab(QWidget *page, const QString &label) = delete;\n    QWidget *widget(int index) const = delete;\n    void     setCornerWidget(QWidget *widget, Qt::Corner corner) = delete;\n    QWidget *cornerWidget() const = delete;\n\nprivate:\n    QWidget *_tab() const;\n    QString  _createStylesheet() const;\n\nsignals:\n    void expandButtonClicked();\n};\n\n#include \"AbstractWidgetGroup.h\"\n#include \"VGroup.h\"\n\n//! \\class VSectionGroup\n//! \\brief VSection that implements the standardized widget group interface. Use this one when possible.\n//! \\author Stas Jaroszynski\n\nclass VSectionGroup : public VSection, public WidgetGroupWrapper<VSectionGroup, QWidget, VGroup> {\npublic:\n    VSectionGroup(const std::string &title, List children = {}) : VSection(title), WidgetGroupWrapper(new VGroup())\n    {\n        layout()->addWidget(_group);\n        _group->AddM(children);\n    }\n};\n\nclass VSection::AbstractButton : public QToolButton {\n    Q_OBJECT\n\nprotected:\n    AbstractButton() {};\n    void paintEvent(QPaintEvent *event);\n    void configureButton();\n    void setDarkOrLight();\n    virtual void setIconDark(bool darkMode = true) = 0;\n};\n\nclass VSection::SettingsMenuButton : public AbstractButton {\n    Q_OBJECT\n\n    void setIconDark(bool darkMode) override;\n\npublic:\n    SettingsMenuButton();\n};\n\nclass VSection::ExpandSectionButton: public AbstractButton {\n    Q_OBJECT\n\n    void setIconDark(bool darkMode) override;\n\npublic:\n    ExpandSectionButton();\n};\n"
  },
  {
    "path": "apps/vaporgui/VSlider.cpp",
    "content": "#include <iostream>\n#include <cmath>\n\n#include <QScrollEvent>\n#include <vapor/VAssert.h>\n#include \"VSlider.h\"\n\n#define NUM_STEPS 100\n\nVSlider::VSlider(double min, double max) : VHBoxWidget(), _min(0.0), _max(0.0), _stepSize(1.0)\n{\n    _slider = new QSlider;\n    _slider->setOrientation(Qt::Horizontal);\n    _slider->setMinimum(0);\n    _slider->setMaximum(NUM_STEPS);\n    SetRange(min, max);\n    SetValue((max - min) / 2);\n    layout()->addWidget(_slider);\n\n    connect(_slider, &QSlider::sliderMoved, this, &VSlider::_sliderChangedIntermediate);\n\n    connect(_slider, &QSlider::sliderReleased, this, &VSlider::_sliderChanged);\n\n    _slider->installEventFilter(new ScrollWheelEater);\n}\n\nvoid VSlider::SetValue(double value)\n{\n    if (_stepSize <= 0) return;\n\n    if (value > _max) value = _max;\n    if (value < _min) value = _min;\n\n    value = (value - _min) / _stepSize;\n    _slider->blockSignals(true);\n    _slider->setValue(value);\n    _slider->blockSignals(false);\n}\n\ndouble VSlider::GetMinimum() const { return _min; }\n\nvoid VSlider::SetMinimum(double min)\n{\n    if (min > _max) _max = min;\n    SetRange(min, _max);\n}\n\ndouble VSlider::GetMaximum() const { return _max; }\n\nvoid VSlider::SetMaximum(double max)\n{\n    if (max < _min) _min = max;\n    SetRange(_min, max);\n}\n\nvoid VSlider::SetRange(double min, double max)\n{\n    // VAssert( min <= max );\n\n    double previousValue = GetValue();\n\n    _min = min;\n    _max = max;\n    _stepSize = (_max - _min) / NUM_STEPS;\n\n    if (previousValue < min) previousValue = min;\n    if (previousValue > max) previousValue = max;\n\n    SetValue(previousValue);\n}\n\ndouble VSlider::GetValue() const\n{\n    int sliderVal = _slider->value();\n\n    // Return min/max values if the slider is at the end.\n    // note - Qt does not move the sliders to positions 0, 1, 99, or 100 until\n    // the mouse is released.\n    if (sliderVal <= 2)    // positions 0, 1 and 2\n        return _min;\n    if (sliderVal >= NUM_STEPS - 2)    // positions 98, 99, and 100\n        return _max;\n\n    double value = _stepSize * _slider->value() + _min;\n    return value;\n}\n\nvoid VSlider::_sliderChanged()\n{\n    double value = GetValue();\n    emit   ValueChanged(value);\n}\n\nvoid VSlider::_sliderChangedIntermediate(int position)\n{\n    double value = GetValue();\n    emit   ValueChangedIntermediate(value);\n}\n\nbool ScrollWheelEater::eventFilter(QObject *object, QEvent *event)\n{\n    if (event->type() == QEvent::Wheel) {\n        return true;\n    } else {\n        return QObject::eventFilter(object, event);\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/VSlider.h",
    "content": "#pragma once\n\n#include <string>\n\n#include <QWidget>\n#include <QSlider>\n\n#include \"VHBoxWidget.h\"\n\n// Fix for Qt bug https://bugreports.qt.io/browse/QTBUG-98093\n// Apply a style sheet to QSlider to make it work on OSX Monterey\n#ifdef Darwin\n    #include \"QMontereySlider.h\"\n    #define QSlider QMontereySlider\n#endif\n\n//! class VSlider\n//!\n//! Wraps a QSlider and provides vaporgui's standard setter/getter fucntions\n//! and signals.  This class also provides range setting for the slider values.\n\nclass VSlider : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    VSlider(double min = 0, double max = 1);\n\n    double GetValue() const;\n    void   SetValue(double value);\n\n    double GetMinimum() const;\n    void   SetMinimum(double min);\n\n    double GetMaximum() const;\n    void   SetMaximum(double max);\n\n    void SetRange(double min, double max);\n\nprivate:\n    QSlider *_slider;\n    double   _min;\n    double   _max;\n    double   _stepSize;\n\nprivate slots:\n    void _sliderChanged();\n    void _sliderChangedIntermediate(int position);\n\nsignals:\n    void ValueChanged(double value);\n    void ValueChangedIntermediate(double value);\n};\n\nclass ScrollWheelEater : public QObject {\n    Q_OBJECT\n\nprotected:\n    bool eventFilter(QObject *obj, QEvent *event) override;\n};\n"
  },
  {
    "path": "apps/vaporgui/VSliderEdit.cpp",
    "content": "#include <cmath>\n#include <iostream>\n\n#include \"vapor/VAssert.h\"\n#include \"VSliderEdit.h\"\n#include \"VSlider.h\"\n#include \"VLineEdit_Deprecated.h\"\n\nVSliderEdit::VSliderEdit(double min, double max, double value) : VHBoxWidget(), _minValid(min), _maxValid(max), _value(value), _isIntType(false)\n{\n    _lineEdit = new VLineEdit_Deprecated();\n    _slider = new VSlider();\n\n    SetRange(min, max);\n    SetValue(value);\n\n    layout()->addWidget(_slider);\n    layout()->addWidget(_lineEdit);\n\n    connect(_lineEdit, SIGNAL(ValueChanged(const std::string &)), this, SLOT(_lineEditChanged(const std::string &)));\n\n    connect(_slider, &VSlider::ValueChanged, this, &VSliderEdit::_sliderChanged);\n\n    connect(_slider, &VSlider::ValueChangedIntermediate, this, &VSliderEdit::_sliderChangedIntermediate);\n}\n\ndouble VSliderEdit::GetValue() const { return _value; }\n\nvoid VSliderEdit::SetValue(double value)\n{\n    if (_isIntType) value = std::round(value);\n    if (value < _minValid) value = _minValid;\n    if (value > _maxValid) value = _maxValid;\n\n    if (_isIntType)\n        _lineEdit->SetValue(std::to_string((int)value));\n    else\n        _lineEdit->SetValue(std::to_string(value));\n    _slider->SetValue(value);\n    _value = value;\n}\n\nvoid VSliderEdit::SetRange(double min, double max)\n{\n    if (_isIntType) {\n        min = round(min);\n        max = round(max);\n    }\n\n    VAssert(min <= max);\n    if (_value < min) _value = min;\n    if (_value > max) _value = max;\n\n    _slider->SetRange(min, max);\n\n    _minValid = min;\n    _maxValid = max;\n}\n\nvoid VSliderEdit::SetIntType(bool type)\n{\n    _isIntType = type;\n    SetValue(_value);\n}\n\nvoid VSliderEdit::_lineEditChanged(const std::string &value)\n{\n    try {\n        double newValue = std::stod(value);\n        SetValue(newValue);\n        if (_isIntType)\n            emit ValueChangedInt((int)_value);\n        else\n            emit ValueChanged(_value);\n    }\n    // If we can't convert the _lineEdit text to a double,\n    // then revert to the previous value.\n    catch (...) {\n        SetValue(_value);\n    }\n}\n\nvoid VSliderEdit::_sliderChanged(double value)\n{\n    SetValue(value);\n    if (_isIntType) {\n        emit ValueChangedInt((int)_value);\n    } else\n        emit ValueChanged(_value);\n}\n\nvoid VSliderEdit::_sliderChangedIntermediate(double value)\n{\n    if (_isIntType) {\n        _lineEdit->SetValue(std::to_string((int)value));\n        emit ValueChangedIntIntermediate((int)value);\n    } else {\n        _lineEdit->SetValue(std::to_string(value));\n        emit ValueChangedIntermediate(value);\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/VSliderEdit.h",
    "content": "#pragma once\n\n#include <string>\n#include \"VHBoxWidget.h\"\n\nclass VSlider;\nclass VLineEdit_Deprecated;\n\n//! class VSliderEdit\n//!\n//! Wraps a VSlider and a VLineEdit_Deprecated for selecting a numeric value within a\n//! defined range.  Allows for integer and double value types.  This class\n//! also provides vaporgui's standard setter/getter functions and signals.\nclass VSliderEdit : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    VSliderEdit(double min = 0., double max = 1., double value = 0.);\n\n    void SetIntType(bool type);\n\n    void SetValue(double value);\n    void SetRange(double min, double max);\n\n    double GetValue() const;\n\nprivate:\n    VLineEdit_Deprecated *_lineEdit;\n    VSlider *             _slider;\n    double                _minValid;\n    double                _maxValid;\n    double                _value;\n    bool                  _isIntType;\n\nprivate slots:\n    void _lineEditChanged(const std::string &value);\n\n    void _sliderChanged(double value);\n    void _sliderChangedIntermediate(double value);\n\nsignals:\n    void ValueChanged(double value);\n    void ValueChangedInt(int value);\n\n    void ValueChangedIntermediate(double value);\n    void ValueChangedIntIntermediate(int value);\n};\n"
  },
  {
    "path": "apps/vaporgui/VSliderEditInterface.cpp",
    "content": "#include <cmath>\n#include <iostream>\n\n#include <QMenu>\n\n#include \"vapor/VAssert.h\"\n\n#include \"VSliderEditInterface.h\"\n#include \"VSlider.h\"\n#include \"VActions.h\"\n\nVSliderEditInterface::VSliderEditInterface() : VHBoxWidget()\n{\n    _slider = new VSlider();\n    _slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);\n    layout()->addWidget(_slider);\n\n    setContextMenuPolicy(Qt::CustomContextMenu);\n    connect(this, &VSliderEditInterface::customContextMenuRequested, this, &VSliderEditInterface::ShowContextMenu);\n}\n\nQSize VSliderEditInterface::sizeHint() const\n{\n    QWidget *parent = this->parentWidget();\n    return QSize(parent->width() * 3 / 5., 20);\n}\n"
  },
  {
    "path": "apps/vaporgui/VSliderEditInterface.h",
    "content": "#pragma once\n\n#include <string>\n#include \"VHBoxWidget.h\"\n\nclass VSlider;\nclass VCheckBoxAction;\nclass VSpinBoxAction;\n\n//! \\class VSliderEditInterface\n//! \\ingroup Public_GUI\n//! \\brief An interface class that needs to be reimplemented to support the\n//! synchronization of a VSlider and a numeric V*LineEdit, and their menus.\n\nclass VSliderEditInterface : public VHBoxWidget {\n    Q_OBJECT\n\npublic slots:\n    //! Emit signal when dynamic update checkbox is toggled\n    virtual void SetDynamicUpdate(bool enabled) = 0;\n\n    //! Set use of scientific notation on the current type of line edit\n    virtual void SetSciNotation(bool sci) = 0;\n\n    //! Set the number of digits shown on the current line edit\n    virtual void SetNumDigits(int digits) = 0;\n\n    //! Show the context menu for the slider-edit, triggered on right-click\n    virtual void ShowContextMenu(const QPoint &) = 0;\n\npublic:\n    //! Retrieve whether dynamic updates are toggled\n    virtual void AllowDynamicUpdate() const = 0;\n\n    //! Retrieve whether the currnet line edit is using scientific notation\n    virtual bool GetSciNotation() const = 0;\n\n    //! Get the number of digits in use by the current line edit\n    virtual int GetNumDigits() const = 0;\n\n    //! Return the size-hint for the current slider-edit\n    virtual QSize sizeHint() const;\n\nprotected:\n    VSliderEditInterface();\n    virtual void _makeContextMenu() = 0;\n\n    VSlider *        _slider;\n\nsignals:\n    void FormatChanged();\n};\n"
  },
  {
    "path": "apps/vaporgui/VStringLineEdit.cpp",
    "content": "#include <string>\n#include <sstream>\n#include <iomanip>\n\n#include <QString>\n#include <QLineEdit>\n\n#include <VStringLineEdit.h>\n\nVStringLineEdit::VStringLineEdit(std::string value) : VHBoxWidget(), _lineEdit(new QLineEdit), _strValue(value)\n{\n    layout()->addWidget(_lineEdit);\n    _lineEdit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);\n    connect(_lineEdit, SIGNAL(editingFinished()), this, SLOT(_valueChanged()));\n\n    _lineEdit->setContextMenuPolicy(Qt::DefaultContextMenu);\n    _lineEdit->setText(QString::fromStdString(value));\n    _lineEdit->setToolTip(QString::fromStdString(value));\n}\n\nvoid VStringLineEdit::SetValueString(std::string value)\n{\n    _strValue = value;\n    _lineEdit->setText(QString::fromStdString(_strValue));\n    if (_autoTooltip) _lineEdit->setToolTip(QString::fromStdString(_strValue));\n    _lineEdit->setCursorPosition(0);\n}\n\nstd::string VStringLineEdit::GetValueString() const { return _strValue; }\n\nvoid VStringLineEdit::RemoveContextMenu()\n{\n    _lineEdit->setContextMenuPolicy(Qt::NoContextMenu);\n    setContextMenuPolicy(Qt::NoContextMenu);\n}\n\nvoid VStringLineEdit::SetCustomContextMenu()\n{\n    _lineEdit->setContextMenuPolicy(Qt::CustomContextMenu);\n    setContextMenuPolicy(Qt::CustomContextMenu);\n    connect(_lineEdit, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(_showMenu(const QPoint &)));\n}\n\nvoid VStringLineEdit::SetAutoTooltip(bool on)\n{\n    _autoTooltip = on;\n    if (on)\n        _lineEdit->setToolTip(_lineEdit->text());\n    else\n        _lineEdit->setToolTip(\"\");\n}\n\nvoid VStringLineEdit::_valueChanged()\n{\n    std::string value = _lineEdit->text().toStdString();\n    if (value != _strValue) {\n        _strValue = value;\n        emit ValueChanged(_strValue);\n    }\n}\n\nstd::string VStringLineEdit::_getText() const\n{\n    std::string value = _lineEdit->text().toStdString();\n    return value;\n}\n"
  },
  {
    "path": "apps/vaporgui/VStringLineEdit.h",
    "content": "#pragma once\n\n#include <iostream>\n\n#include <string>\n#include <sstream>\n#include <iomanip>\n#include <QLineEdit>\n\n#include \"VHBoxWidget.h\"\n\nclass QStringLineEdit;\n\n//! \\class VStringLineEdit\n//! \\ingroup Public_GUI\n//! \\brief A wrapper for a QLineEdit that handles user input of type string,\n//! and provides Vapor's standard setters, getters, and signals\n\nclass VStringLineEdit : public VHBoxWidget {\n    Q_OBJECT\n\npublic:\n    VStringLineEdit(std::string value = \"\");\n\n    //! Set the current string value in the line edit\n    void SetValueString(std::string value);\n\n    //! Get the current value in the line edit\n    std::string GetValueString() const;\n\n    //! Remove the current context menu\n    void RemoveContextMenu();\n\n    //! Create a custom context menu for the QLineEdit\n    void SetCustomContextMenu();\n\n    void SetReadOnly(bool b) { _lineEdit->setReadOnly(b); }\n    void Clear() { SetValueString(\"\"); }\n\n    void SetAutoTooltip(bool on);\n\nprivate:\n    QLineEdit * _lineEdit;\n    std::string _strValue;\n    bool        _autoTooltip = true;\n\nprotected:\n    std::string _getText() const;\n\nprotected slots:\n    virtual void _valueChanged();\n\nsignals:\n    void ValueChanged(const std::string &value);\n};\n"
  },
  {
    "path": "apps/vaporgui/VVisibilityCheckbox.cpp",
    "content": "#include \"VVisibilityCheckbox.h\"\n#include <vapor/ResourcePath.h>\n#include <QVariant>\n#include \"mac_helpers.h\"\n\nVVisibilityCheckbox::VVisibilityCheckbox()\n{\n    _isWhite = true;\n    setBlack();\n}\n\nvoid VVisibilityCheckbox::paintEvent(QPaintEvent *e)\n{\n#ifdef __APPLE__\n    if (MacIsDarkMode())\n        setWhite();\n    else\n        setBlack();\n#endif\n    \n    VCheckBox::paintEvent(e);\n}\n\nvoid VVisibilityCheckbox::setColor(std::string color)\n{\n    string eye = Wasp::GetSharePath(\"images/eye\");\n    if (eye.empty())\n        return;\n    \n    setStyleSheet(QString(\nR\"VV(\nQCheckBox::indicator:checked\n{\nimage: url(%1);\n}\nQCheckBox::indicator:unchecked\n{\nimage: url(%2);\n}\n)VV\")\n    .arg(QString::fromStdString(eye + \"/eye_on_\" + color + \".png\"))\n    .arg(QString::fromStdString(eye + \"/eye_off_\" + color + \".png\"))\n);\n}\n\nvoid VVisibilityCheckbox::setBlack()\n{\n    if (_isWhite) {\n        _isWhite = false;\n        setColor(\"black\");\n    }\n}\n\nvoid VVisibilityCheckbox::setWhite()\n{\n    if (!_isWhite) {\n        _isWhite = true;\n        setColor(\"white\");\n    }\n}\n"
  },
  {
    "path": "apps/vaporgui/VVisibilityCheckbox.h",
    "content": "#pragma once\n\n#include \"VCheckBox.h\"\n\nclass VVisibilityCheckbox : public VCheckBox {\n    bool _isWhite;\npublic:\n    VVisibilityCheckbox();\nprotected:\n    void paintEvent(QPaintEvent *e) override;\nprivate:\n    void setColor(std::string color);\n    void setBlack();\n    void setWhite();\n};\n"
  },
  {
    "path": "apps/vaporgui/VaporFwd.h",
    "content": "#pragma once\n\nnamespace VAPoR {\n    class ParamsMgr;\n    class DataMgr;\n    class ControlExec;\n\n    class ParamsBase;\n    class RenderParams;\n    class ViewpointParams;\n}\nusing namespace VAPoR;\n\nclass GUIStateParams;\nclass AnimationParams;\n"
  },
  {
    "path": "apps/vaporgui/VaporTable.cpp",
    "content": "//*************************************************************************\n//                                                                        *\n//   Copyright (C)  2017                                                  *\n//   University Corporation for Atmospheric Research                      *\n//   All Rights Reserved                                                  *\n//                                                                        *\n//************************************************************************/\n//\n//    File:      VaporTable.cpp\n//\n//    Author:  Scott Pearse\n//    National Center for Atmospheric Research\n//    PO 3000, Boulder, Colorado\n//\n//  Date:      December 2017\n//\n\n#include <QtGui>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <stdlib.h>\n#include <QHeaderView>\n#include <QHBoxLayout>\n#include <QCheckBox>\n#include <QScrollBar>\n#include \"VaporTable.h\"\n\nnamespace {\nQString selectionColor = \"{color: white; background-color: blue}\";\nQString normalColor = \"{ color: black; background: white; }\";\n}    // namespace\n\nVaporTable::VaporTable(QTableWidget *table, bool lastRowIsCheckboxes, bool lastColIsCheckboxes)\n{\n    _table = table;\n    _lastRowIsCheckboxes = lastRowIsCheckboxes;\n    _lastColIsCheckboxes = lastColIsCheckboxes;\n    _checkboxesEnabled = true;\n    _activeRow = -1;\n    _stretchColumn = -1;\n    _hideColumn = -1;\n    _autoResizeHeight = false;\n    _showToolTips = false;\n\n    SetVerticalHeaderWidth(100);\n    _table->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);\n\n    connect(_table, &QTableWidget::cellClicked, this, &VaporTable::emitCellClicked);\n    connect(_table, &QTableWidget::cellChanged, this, &VaporTable::emitValueChanged);\n}\n\n// Clear current table, then generate table of rows x columns\n// Determine if checkboxes are needed\n// Convert values, rowHeaders, and colHeaders to QStrings, then populate\nvoid VaporTable::Update(int rows, int cols, std::vector<int> values, std::vector<std::string> rowHeaders, std::vector<std::string> colHeaders)\n{\n    std::vector<std::string> sValues = convertToString(values);\n    Update(rows, cols, sValues, rowHeaders, colHeaders);\n\n    resizeTableHeight();\n}\n\nvoid VaporTable::Update(int rows, int cols, std::vector<double> values, std::vector<std::string> rowHeaders, std::vector<std::string> colHeaders)\n{\n    std::vector<std::string> sValues = convertToString(values);\n    Update(rows, cols, sValues, rowHeaders, colHeaders);\n\n    resizeTableHeight();\n}\n\nvoid VaporTable::Update(int rows, int cols, std::vector<std::string> values, std::vector<std::string> rowHeaders, std::vector<std::string> colHeaders)\n{\n    _table->blockSignals(true);\n    _table->clearContents();\n    _table->setRowCount(rows);\n    _table->setColumnCount(cols);\n\n    setTableCells(values);\n    setVerticalHeader(rowHeaders);\n    setHorizontalHeader(colHeaders);\n\n    addCheckboxes(values);\n\n    if ((rows < 1) || (cols < 1)) { _activeRow = -1; }\n    if (_activeRow >= rows) { _activeRow = rows - 1; }\n\n    if (_highlightFlags & ROWS) highlightActiveRow(_activeRow);\n\n    resizeTableHeight();\n\n    if (_mutabilityFlags & IMMUTABLE) { _correctImmutableCellText(); }\n    _table->blockSignals(false);\n}\n\nvoid VaporTable::SetVerticalHeaderWidth(int width) { _table->verticalHeader()->setMaximumWidth(width); }\n\nvoid VaporTable::SetAutoResizeHeight(bool val) { _autoResizeHeight = val; }\n\nbool VaporTable::GetAutoResizeHeight() const { return _autoResizeHeight; }\n\nvoid VaporTable::StretchToColumn(int column) { _stretchColumn = column; }\n\nvoid VaporTable::HideColumn(int column) { _hideColumn = column; }\n\nvoid VaporTable::ShowToolTips(bool showOrHide) { _showToolTips = showOrHide; }\n\nbool VaporTable::GetShowToolTips() const { return _showToolTips; }\n\nvoid VaporTable::resizeTableHeight()\n{\n    if (!_autoResizeHeight) return;\n\n    int height = _table->horizontalHeader()->height();\n    int rows = _table->rowCount();\n    _table->setMaximumHeight(height * rows * 3);\n}\n\nvoid VaporTable::Reinit(VaporTable::ValidatorFlags vFlags, VaporTable::MutabilityFlags mFlags, VaporTable::HighlightFlags hFlags)\n{\n    _validatorFlags = vFlags;\n    _mutabilityFlags = mFlags;\n    _highlightFlags = hFlags;\n}\n\nstd::vector<std::string> VaporTable::convertToString(std::vector<int> values)\n{\n    std::vector<std::string> sValues;\n\n    int size = values.size();\n    for (int i = 0; i < size; i++) {\n        std::stringstream ss;\n        ss << values[i];\n        std::string s = ss.str();\n        sValues.push_back(s);\n    }\n\n    return sValues;\n}\n\nstd::vector<std::string> VaporTable::convertToString(std::vector<double> values)\n{\n    std::vector<std::string> sValues;\n\n    int size = values.size();\n    for (int i = 0; i < size; i++) {\n        std::stringstream ss;\n        ss << values[i];\n        std::string s = ss.str();\n        sValues.push_back(s);\n    }\n\n    return sValues;\n}\n\nvoid VaporTable::setTableCells(std::vector<std::string> values)\n{\n    int cols = _table->columnCount();\n    int rows = _table->rowCount();\n\n    for (int i = 0; i < cols; i++) {\n        for (int j = 0; j < rows; j++) {\n            int         index = i + (cols)*j;\n            std::string value = values[index];\n\n            QString qVal = QString::fromStdString(value);\n\n            // If the cell has a checkbox,\n            // don't write the string value into the cell\n            if (_lastColIsCheckboxes && i == _table->columnCount() - 1) { qVal = \"\"; }\n\n            QTableWidgetItem *item = new QTableWidgetItem(qVal);\n            if (_mutabilityFlags & IMMUTABLE) {\n                item->setFlags(Qt::ItemIsEditable);    // turns off user-editability\n            }\n\n            if (_showToolTips) item->setToolTip(qVal);\n            _table->setItem(j, i, item);\n        }\n    }\n}\n\nvoid VaporTable::addCheckboxes(std::vector<std::string> values)\n{\n    int cols = _table->columnCount();\n    int rows = _table->rowCount();\n\n    if (_lastColIsCheckboxes) {\n        for (int j = 0; j < rows; j++) {\n            int  index = j * cols + (cols - 1);\n            bool checked = isValueChecked(values, index);\n            addCheckbox(j, cols - 1, checked);\n        }\n    }\n\n    if (_lastRowIsCheckboxes) {\n        for (int i = 0; i < cols; i++) {\n            int  index = (rows - 1) * (cols - 1) + i;\n            bool checked = isValueChecked(values, index);\n            addCheckbox(rows - 1, i, checked);\n        }\n    }\n}\n\nbool VaporTable::isValueChecked(std::vector<std::string> values, int index)\n{\n    std::string value = values[index];\n\n    std::stringstream ss;\n    ss << value;\n\n    bool checked = false;\n    if (atoi(ss.str().c_str())) checked = true;\n\n    return checked;\n}\n\nvoid VaporTable::addCheckbox(int row, int column, bool checked)\n{\n    _table->removeCellWidget(row, column);\n\n    QWidget *    cbWidget = new QWidget();\n    QCheckBox *  checkBox = new QCheckBox();\n    QHBoxLayout *cbLayout = new QHBoxLayout(cbWidget);\n\n    cbLayout->addWidget(checkBox);\n    cbLayout->setAlignment(Qt::AlignCenter);\n    cbLayout->setContentsMargins(0, 0, 0, 0);\n\n    cbWidget->setLayout(cbLayout);\n\n    _table->setCellWidget(row, column, cbWidget);\n\n    if (checked) {\n        checkBox->setCheckState(Qt::Checked);\n    } else {\n        checkBox->setCheckState(Qt::Unchecked);\n    }\n\n    // The chekbox and the widget can both be clicked,\n    // so I've given both objects row and column\n    // properties to relay if needed\n    checkBox->setProperty(\"row\", row);\n    checkBox->setProperty(\"col\", column);\n    cbWidget->setProperty(\"row\", row);\n    cbWidget->setProperty(\"col\", column);\n\n    checkBox->setEnabled(_checkboxesEnabled);\n\n    connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(emitValueChanged()));\n}\n\nvoid VaporTable::emitValueChanged(int row, int col)\n{\n    QCheckBox *item = qobject_cast<QCheckBox *>(QObject::sender());\n    if (item != nullptr) {\n        row = item->property(\"row\").toInt();\n        col = item->property(\"col\").toInt();\n    }\n\n    _activeRow = row;\n    if (_highlightFlags & ROWS) highlightActiveRow(_activeRow);\n\n    emit valueChanged(row, col);\n}\n\nvoid VaporTable::emitReturnPressed() { emit returnPressed(); }\n\nvoid VaporTable::emitCellClicked(int row, int col)\n{\n    _activeRow = row;\n\n    if (_highlightFlags & ROWS) { highlightActiveRow(_activeRow); }\n    emit cellClicked(row, col);\n}\n\nvoid VaporTable::setValidator(QLineEdit *edit)\n{\n    if (_validatorFlags & INT) { edit->setValidator(new QIntValidator(edit)); }\n    if (_validatorFlags & DOUBLE) { edit->setValidator(new QDoubleValidator(edit)); }\n    if (_validatorFlags & STRING) {\n        QRegExpValidator *validator;\n        validator = new QRegExpValidator(QRegExp(\".{1,64}\"));\n        edit->setValidator(validator);\n    }\n}\n\nvoid VaporTable::setHorizontalHeader(std::vector<std::string> header)\n{\n    QHeaderView *headerView = _table->horizontalHeader();\n    if (_stretchColumn != -1) {\n        _table->horizontalScrollBar()->setEnabled(false);\n        _table->resizeColumnsToContents();\n        headerView->setSectionResizeMode(_stretchColumn, QHeaderView::Stretch);\n    } else {\n        headerView->setSectionResizeMode(1, QHeaderView::Stretch);\n    }\n\n    if (_hideColumn != -1) _table->hideColumn(_hideColumn);\n\n    int size = header.size();\n    if (size < 1) {\n        _table->horizontalHeader()->hide();\n        return;\n    }\n\n    QStringList list;\n    for (int i = 0; i < size; i++) { list << QString::fromStdString(header[i]); }\n\n    _table->setHorizontalHeaderLabels(list);\n\n    QTableWidgetItem *headerItem;\n    for (int i = 0; i < size; i++) {\n        headerItem = _table->horizontalHeaderItem(i);\n        if (headerItem) headerItem->setToolTip(list[i]);\n    }\n}\n\nstd::string VaporTable::GetHorizontalHeaderItem(int index)\n{\n    QString str = _table->horizontalHeaderItem(index)->text();\n    return str.toStdString();\n}\n\nvoid VaporTable::setVerticalHeader(std::vector<std::string> header)\n{\n    int size = header.size();\n    if (size < 1) {\n        _table->verticalHeader()->hide();\n        return;\n    } else if (_table->verticalHeader()->isHidden()) {\n        _table->verticalHeader()->show();\n    }\n\n    QStringList list;\n    for (int i = 0; i < size; i++) { list << QString::fromStdString(header[i]); }\n\n    _table->setVerticalHeaderLabels(list);\n    _table->resizeRowsToContents();\n    _table->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);\n\n    QTableWidgetItem *headerItem;\n    for (int i = 0; i < size; i++) {\n        headerItem = _table->verticalHeaderItem(i);\n        if (headerItem) headerItem->setToolTip(list[i]);\n    }\n}\n\nstd::string VaporTable::GetVerticalHeaderItem(int index)\n{\n    QString str = _table->verticalHeaderItem(index)->text();\n    return str.toStdString();\n}\n\nvoid VaporTable::SetCheckboxesInFinalRow(bool enabled) { _lastRowIsCheckboxes = enabled; }\n\nvoid VaporTable::SetCheckboxesInFinalColumn(bool enabled) { _lastColIsCheckboxes = enabled; }\n\nvoid VaporTable::EnableDisableCheckboxes(bool enabled)\n{\n    if (!_lastRowIsCheckboxes && !_lastColIsCheckboxes) { return; }\n\n    _checkboxesEnabled = enabled;\n}\n\nValue VaporTable::GetValue(int row, int col)\n{\n    std::string value;\n    int         nRows = _table->rowCount();\n    int         nCols = _table->columnCount();\n\n    QWidget *widget = _table->cellWidget(row, col);\n\n    if ((col == nCols - 1 && _lastColIsCheckboxes) || (row == nRows - 1 && _lastRowIsCheckboxes)) {\n        QCheckBox *checkBox = widget->findChild<QCheckBox *>();\n        if (checkBox->isChecked())\n            value = \"1\";\n        else\n            value = \"0\";\n    } else {\n        QString qvalue = _table->item(row, col)->text();\n        value = qvalue.toStdString();\n    }\n\n    return {value};\n}\n\nstd::string VaporTable::GetStringValue(int row, int col)\n{\n    std::string value;\n    int         nRows = _table->rowCount();\n    int         nCols = _table->columnCount();\n\n    if (row >= nRows || col >= nCols) return \"\";\n\n    if ((col == nCols - 1 && _lastColIsCheckboxes) || (row == nRows - 1 && _lastRowIsCheckboxes)) {\n        QCheckBox *checkBox = _table->cellWidget(row, col)->findChild<QCheckBox *>();\n        if (checkBox->isChecked())\n            value = \"1\";\n        else\n            value = \"0\";\n    } else {\n        QString qvalue = _table->item(row, col)->text();\n        value = qvalue.toStdString();\n    }\n\n    return value;\n}\n\nvoid VaporTable::GetValues(std::vector<std::string> &vec)\n{\n    vec.clear();\n\n    int nRows = _table->rowCount();\n    int nCols = _table->columnCount();\n\n    for (int i = 0; i < nRows; i++) {\n        for (int j = 0; j < nCols; j++) {\n            std::string cellVal = GetValue(i, j);\n            vec.push_back(cellVal);\n        }\n    }\n}\n\nvoid VaporTable::GetValues(std::vector<int> &vec)\n{\n    vec.clear();\n\n    int nRows = _table->rowCount();\n    int nCols = _table->columnCount();\n\n    for (int i = 0; i < nRows; i++) {\n        for (int j = 0; j < nCols; j++) {\n            int cellVal = GetValue(i, j);\n            vec.push_back(cellVal);\n        }\n    }\n}\n\nvoid VaporTable::GetValues(std::vector<double> &vec)\n{\n    vec.clear();\n\n    int nRows = _table->rowCount();\n    int nCols = _table->columnCount();\n\n    for (int i = 0; i < nRows; i++) {\n        for (int j = 0; j < nCols; j++) {\n            double cellVal = GetValue(i, j);\n            vec.push_back(cellVal);\n        }\n    }\n}\n\nvoid VaporTable::_correctImmutableCellText()\n{\n    _table->blockSignals(true);\n    for (int i = 0; i < _table->rowCount(); i++) {\n        if ((i == _activeRow) && (_highlightFlags == ROWS)) { continue; }\n        for (int j = 0; j < _table->columnCount(); j++) {\n            QBrush b(QColor(\"black\"));\n            QBrush w(QColor(\"white\"));\n            _table->item(i, j)->setForeground(b);\n            _table->item(i, j)->setBackground(w);\n        }\n    }\n    _table->blockSignals(false);\n}\n\nvoid VaporTable::highlightActiveRow(int row)\n{\n    if (row < 0) return;\n    _table->blockSignals(true);\n\n    for (int i = 0; i < _table->rowCount(); i++) {\n        for (int j = 0; j < _table->columnCount(); j++) {\n            if (i == row) {\n                QBrush b(QColor(\"blue\"));\n                QBrush w(QColor(\"white\"));\n                _table->item(i, j)->setForeground(w);\n                _table->item(i, j)->setBackground(b);\n            } else {\n                QBrush b(QColor(\"black\"));\n                QBrush w(QColor(\"white\"));\n                _table->item(i, j)->setForeground(b);\n                _table->item(i, j)->setBackground(w);\n            }\n        }\n    }\n    _table->blockSignals(false);\n}\n\nint VaporTable::GetActiveRow() const { return _activeRow; }\n\nvoid VaporTable::SetActiveRow(int row) { _activeRow = row; }\n"
  },
  {
    "path": "apps/vaporgui/VaporTable.h",
    "content": "#ifndef VAPORTABLE_H\n#define VAPORTABLE_H\n\n#include <QWidget>\n#include <QTableWidget>\n#include <QLineEdit>\n#include <sstream>\n\nstruct Value;\n\n// class VaporTable\n//\nclass VaporTable : public QWidget {\n    Q_OBJECT\n\npublic:\n    enum HighlightFlags {\n        ROWS = (1u << 0),\n        COLS = (1u << 1),\n    };\n\n    enum MutabilityFlags {\n        MUTABLE = (1u << 0),\n        IMMUTABLE = (1u << 1),\n    };\n\n    // The ValidatorTypeFlag will be used to apply validators\n    // to the cells that are regenerated on each Update call.\n    //\n    // Can this be replaced with the template info in Update?\n    //\n    enum ValidatorFlags {\n        INT = (1u << 0),\n        DOUBLE = (1u << 1),\n        STRING = (1u << 2),\n    };\n\n    VaporTable(QTableWidget *table, bool lastRowIsCheckboxes = false, bool lastColIsCheckboxes = false);\n\n    void Update(int rows, int columns, std::vector<int> values, std::vector<std::string> rowHeaders = std::vector<std::string>(), std::vector<std::string> colHeaders = std::vector<std::string>());\n    void Update(int rows, int columns, std::vector<double> values, std::vector<std::string> rowHeaders = std::vector<std::string>(), std::vector<std::string> colHeaders = std::vector<std::string>());\n    void Update(int rows, int columns, std::vector<std::string> values, std::vector<std::string> rowHeaders = std::vector<std::string>(),\n                std::vector<std::string> colHeaders = std::vector<std::string>());\n\n    void Reinit(ValidatorFlags vFlags, MutabilityFlags mFlags, HighlightFlags hFlags);\n\n    Value       GetValue(int row, int col);\n    std::string GetStringValue(int row, int col);\n\n    // Dump all values in the table back to the user\n    void GetValues(std::vector<std::string> &vec);\n    void GetValues(std::vector<int> &vec);\n    void GetValues(std::vector<double> &vec);\n\n    std::string GetVerticalHeaderItem(int index);\n    std::string GetHorizontalHeaderItem(int index);\n\n    void SetCheckboxesInFinalColumn(bool enabled);\n    void SetCheckboxesInFinalRow(bool enabled);\n    void EnableDisableCheckboxes(bool enabled);\n\n    // I think we may need something like this.  TBD...\n    void SetCellMutability(int row, int col);\n\n    int      RowCount() const { return _table->rowCount(); }\n    int      ColumnCount() const { return _table->columnCount(); }\n    QWidget *CellWidget(int row, int col) { return _table->cellWidget(row, col); }\n\n    int GetActiveRow() const;\n\n    void SetActiveRow(int row);\n\n    void SetAutoResizeHeight(bool val);\n    bool GetAutoResizeHeight() const;\n\n    void StretchToColumn(int column);\n    void HideColumn(int column);\n\n    void ShowToolTips(bool showOrHide);\n    bool GetShowToolTips() const;\n\n    void SetVerticalHeaderWidth(int width);\n\npublic slots:\n    void emitCellClicked(int, int);\n    void emitValueChanged(int row = 0, int col = 0);\n    void emitReturnPressed();\n\nsignals:\n    void valueChanged(int row, int col);\n    void cellClicked(int row, int col);\n    void returnPressed();\n\nprivate:\n    std::vector<std::string> convertToString(std::vector<int> values);\n\n    std::vector<std::string> convertToString(std::vector<double> values);\n\n    void setHorizontalHeader(std::vector<std::string> header);\n\n    void setVerticalHeader(std::vector<std::string> header);\n\n    void setValidator(QLineEdit *edit);\n\n    void setTableCells(std::vector<std::string> values);\n\n    void addCheckboxes(std::vector<std::string> values);\n\n    void addCheckbox(int row, int column, bool checked = false);\n\n    bool isValueChecked(std::vector<std::string> values, int index);\n\n    void highlightActiveRow(int row);\n\n    void resizeTableHeight();\n\n    void _correctImmutableCellText();\n\n    int           _activeRow;\n    int           _stretchColumn;\n    int           _hideColumn;\n    bool          _lastRowIsCheckboxes;\n    bool          _lastColIsCheckboxes;\n    bool          _checkboxesEnabled;\n    bool          _autoResizeHeight;\n    bool          _showToolTips;\n    QTableWidget *_table;\n\n    MutabilityFlags _mutabilityFlags;\n    ValidatorFlags  _validatorFlags;\n    HighlightFlags  _highlightFlags;\n};\n\n// A way to return a generic built-in type, so that the user can do:\n// int myVal = vaporTable->GetValue(0,0);\n// double myVal = vaporTable->GetValue(0,0);\n// std::string myVal = vaporTable->GetValue(0,0);\nstruct Value {\n    std::string _value;\n\n    template<typename T> operator T() const    // implicitly convert into T\n    {\n        std::stringstream ss(_value);\n        T                 convertedValue;\n        if (ss >> convertedValue)\n            return convertedValue;\n        else\n            throw std::runtime_error(\"conversion failed\");\n    }\n};\n\n#endif\n"
  },
  {
    "path": "apps/vaporgui/VaporTableGUI.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>VaporTableGUI</class>\n <widget class=\"QWidget\" name=\"VaporTableGUI\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>410</width>\n    <height>100</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Preferred\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"minimumSize\">\n   <size>\n    <width>0</width>\n    <height>100</height>\n   </size>\n  </property>\n  <property name=\"maximumSize\">\n   <size>\n    <width>16777215</width>\n    <height>113</height>\n   </size>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"spacing\">\n    <number>0</number>\n   </property>\n   <property name=\"sizeConstraint\">\n    <enum>QLayout::SetDefaultConstraint</enum>\n   </property>\n   <property name=\"leftMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"topMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"rightMargin\">\n    <number>0</number>\n   </property>\n   <property name=\"bottomMargin\">\n    <number>0</number>\n   </property>\n   <item>\n    <widget class=\"QTableWidget\" name=\"vaporTable\"/>\n   </item>\n  </layout>\n </widget>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "apps/vaporgui/VaporWidgetsFwd.h",
    "content": "#pragma once\n\nclass QDoubleValidator;\nclass QComboBox;\nclass QLineEdit;\n\ntypedef QLineEdit VDoubleInput;\ntypedef QLineEdit VIntegerInput;\n\n// Needs to allow changing contents without having to worry about blocking signals\ntypedef QComboBox VDropdown;\n"
  },
  {
    "path": "apps/vaporgui/ViewpointToolbar.cpp",
    "content": "#include \"ViewpointToolbar.h\"\n#include <QComboBox>\n#include \"VizWinMgr.h\"\n#include \"PVisualizerSelector.h\"\n#include <vapor/GUIStateParams.h>\n#include <vapor/NavigationUtils.h>\n\n#include \"images/tiles.xpm\"\n#include \"images/home.xpm\"\n#include \"images/sethome.xpm\"\n#include \"images/eye.xpm\"\n\nViewpointToolbar::ViewpointToolbar(QWidget *parent, VAPoR::ControlExec *ce, VizWinMgr *vwm)\n: QToolBar(parent), _ce(ce), _vizWinMgr(vwm)\n{\n\n    _visualizerSelector = new PVisualizerSelector();\n    addWidget(_visualizerSelector);\n\n    addAction(QPixmap(tiles), \"Tile Windows\", [this](){_vizWinMgr->FitSpace();});\n    addAction(QPixmap(home), \"Go to Home View\", [this](){NavigationUtils::UseHomeViewpoint(_ce);});\n    addAction(QPixmap(sethome), \"Set Home View\", [this](){NavigationUtils::SetHomeViewpoint(_ce);});\n    addAction(QPixmap(eye), \"View All\", [this](){NavigationUtils::ViewAll(_ce);});\n\n    auto alignViewCombo = new QComboBox(this);\n    alignViewCombo->addItems({\"Align View\", \"Nearest axis\", \"+ X\", \"+ Y\", \"+ Z\", \"- X\", \"- Y\", \"- Z (Default)\"});\n    alignViewCombo->setToolTip(\"Rotate view to an axis-aligned viewpoint, centered on current rotation center.\");\n    QObject::connect(alignViewCombo, QOverload<int>::of(&QComboBox::activated), this, [this](int i){\n        NavigationUtils::AlignView(_ce, i);\n        sender()->blockSignals(true);\n        ((QComboBox *)sender())->setCurrentIndex(0);\n        sender()->blockSignals(false);\n    });\n    addWidget(alignViewCombo);\n}\n\n\nvoid ViewpointToolbar::Update()\n{\n    _visualizerSelector->Update(_ce->GetParams<GUIStateParams>(), _ce->GetParamsMgr());\n}\n"
  },
  {
    "path": "apps/vaporgui/ViewpointToolbar.h",
    "content": "#pragma once\n#include <QToolBar>\n#include <common.h>\n#include \"Updatable.h\"\n\nclass VizWinMgr;\nclass PVisualizerSelector;\n\nclass ViewpointToolbar : public QToolBar, public Updatable {\n    Q_OBJECT\n    ControlExec * const _ce;\n    VizWinMgr * const _vizWinMgr;\n    PVisualizerSelector *_visualizerSelector;\n\npublic:\n    ViewpointToolbar(QWidget *parent, ControlExec *ce, VizWinMgr *vwm);\n    void Update() override;\n};\n"
  },
  {
    "path": "apps/vaporgui/VizWin.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2013\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\tFile:\t\tVizWin.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tOctober 2013\n//\n//\tDescription:\tImplements the VizWin class\n//\t\tThis is the QGLWidget that performs OpenGL rendering (using associated\n//\t\tVisualizer).\n//\n//\t\tSupports mouse event reporting.\n//\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include \"vapor/VAssert.h\"\n#include <QResizeEvent>\n#include <QFocusEvent>\n#include <QMouseEvent>\n#include <QCloseEvent>\n#include <QApplication>\n#include <QWindow>\n#include <QDesktopWidget>\n#include <QIcon>\n#include <vapor/ControlExecutive.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/Viewpoint.h>\n#include <vapor/debug.h>\n#include <vapor/ImageParams.h>\n#include <vapor/TrackBall.h>\n#include <vapor/GUIStateParams.h>\n#include <vapor/MouseModeParams.h>\n#include <vapor/AnimationParams.h>\n#include \"qdatetime.h\"\n#include \"ErrorReporter.h\"\n#include \"RenderEventRouterGUI.h\"\n#include \"FlowEventRouter.h\"\n#include \"images/vapor-icon-32.xpm\"\n#include \"VizWin.h\"\n#include \"Core3_2_context.h\"\n#include <glm/gtc/type_ptr.hpp>\n#include \"vapor/GLManager.h\"\n#include \"vapor/LegacyGL.h\"\n#include \"vapor/FontManager.h\"\n#include \"vapor/FileUtils.h\"\n#include \"vapor/Visualizer.h\"\n#include <vapor/FlowParams.h>\n#include <vapor/SliceParams.h>\n#include <vapor/ContourParams.h>\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n#include \"hide_std_error_util.h\"\n\nusing namespace VAPoR;\n\n#define ORIGIN_TIC_WIDTH .03\n\n/*\n *  Constructs a VizWindow as a child of 'parent', with the\n *  name 'name' and widget flags set to 'f'.\n *\n */\nVizWin::VizWin(const QGLFormat &format, QWidget *parent, const QString &name, string winName, ControlExec *ce, Trackball *trackBall) : QGLWidget(new Core3_2_context(format), parent)\n{\n    _trackBall = trackBall;\n\n    setAttribute(Qt::WA_DeleteOnClose);\n    _winName = winName;\n    setWindowIcon(QPixmap(vapor_icon___));\n    _controlExec = ce;\n\n    _glManager = nullptr;\n    _manip = nullptr;\n\n    setAutoBufferSwap(false);\n    _mouseClicked = false;\n    _buttonNum = 0;\n    _navigateFlag = false;\n    _manipFlag = false;\n    _openGLInitFlag = false;\n\n    setMouseTracking(false);    // Only track mouse when button clicked/held\n}\n\n\nVizWin::~VizWin()\n{\n    // Sometimes when closing the application this will crash as the OpenGL context is\n    // destroyed prior to the destructor being called.\n    // Qt specifically states you are supposed to call ::makeCurrent() in the destructor.\n    // https://doc.qt.io/qt-6/qopenglwidget.html#resource-initialization-and-cleanup\n    // TODO Migrate to QOpenGLWidget\n    this->makeCurrent();\n    delete _glManager;\n}\n\n// First project all 8 box corners to the center line of the camera\n// view, finding the furthest and nearest projection in front of the\n// camera.  The furthest distance is used as the far distance.\n// If some point projects behind the camera, then either the\n// camera is inside the box, or a corner of the\n// box is behind the camera.  This calculation is always performed in\n// local coordinates since a translation won't affect\n// the result\n//\nvoid VizWin::_getNearFarDist(const double posVec[3], const double dirVec[3], double &boxNear, double &boxFar) const\n{\n    // First check full box\n    double wrk[3], cor[3], boxcor[3];\n    double camPosBox[3], dvdir[3];\n#ifdef WIN32\n    double maxProj = -DBL_MAX;\n    double minProj = DBL_MAX;\n#else\n    double maxProj = -std::numeric_limits<double>::max();\n    double minProj = std::numeric_limits<double>::max();\n#endif\n\n    DataStatus *dataStatus = _controlExec->GetDataStatus();\n    ParamsMgr * paramsMgr = _controlExec->GetParamsMgr();\n\n    AnimationParams *p = (AnimationParams *)paramsMgr->GetParams(AnimationParams::GetClassType());\n    size_t           ts = p->GetCurrentTimestep();\n\n    VAPoR::CoordType minExts, maxExts;\n    dataStatus->GetActiveExtents(paramsMgr, _winName, ts, minExts, maxExts);\n\n    for (int i = 0; i < 3; i++) camPosBox[i] = posVec[i];\n\n    for (int i = 0; i < 3; i++) dvdir[i] = dirVec[i];\n    vnormal(dvdir);\n\n    // For each box corner,\n    //   convert to box coords, then project to line of view\n    for (int i = 0; i < 8; i++) {\n        for (int j = 0; j < 3; j++) { cor[j] = ((i >> j) & 1) ? maxExts[j] : minExts[j]; }\n        for (int k = 0; k < 3; k++) boxcor[k] = cor[k];\n\n        vsub(boxcor, camPosBox, wrk);\n\n        float mdist = abs(vdot(wrk, dvdir));\n        if (minProj > mdist) { minProj = mdist; }\n        if (maxProj < mdist) { maxProj = mdist; }\n    }\n\n    if (maxProj < 1.e-10) maxProj = 1.e-10;\n    if (minProj > 0.03 * maxProj) minProj = 0.03 * maxProj;\n\n    // minProj will be < 0 if either the camera is in the box, or\n    // if some of the region is behind the camera plane.  In that case, just\n    // set the nearDist a reasonable multiple of the fardist\n    //\n    if (minProj <= 0.0) minProj = 0.0002 * maxProj;\n    boxFar = (float)maxProj;\n    boxNear = (float)minProj;\n\n    return;\n}\n\nvoid VizWin::_setUpProjMatrix()\n{\n    ParamsMgr *      paramsMgr = _controlExec->GetParamsMgr();\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName);\n    MatrixManager *  mm = _glManager->matrixManager;\n\n    double m[16];\n    vParams->GetModelViewMatrix(m);\n\n    double posvec[3], upvec[3], dirvec[3];\n    bool   status = vParams->ReconstructCamera(m, posvec, upvec, dirvec);\n    if (!status) {\n        MSG_ERR(\"Failed to get camera parameters\");\n        return;\n    }\n\n    double nearDist, farDist;\n    _getNearFarDist(posvec, dirvec, nearDist, farDist);\n    nearDist *= 0.25;\n    farDist *= 4.0;\n\n    size_t width, height;\n    vParams->GetWindowSize(width, height);\n    width *= this->devicePixelRatioF();\n    height *= this->devicePixelRatioF();\n    int wWidth = width;\n    int wHeight = height;\n\n    if (vParams->GetValueLong(ViewpointParams::UseCustomFramebufferTag, 0)) {\n        width = vParams->GetValueLong(ViewpointParams::CustomFramebufferWidthTag, 0);\n        height = vParams->GetValueLong(ViewpointParams::CustomFramebufferHeightTag, 0);\n        if (width == 0) width = 1;\n        if (height == 0) height = 1;\n\n        int maxSize;\n        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);\n        if (width > maxSize) {\n            width = maxSize;\n            vParams->SetValueLong(ViewpointParams::CustomFramebufferWidthTag, ViewpointParams::CustomFramebufferWidthTag, width);\n            MSG_ERR(\"Selected width is larger than your OpenGL implementation supports\");\n        }\n        if (height > maxSize) {\n            height = maxSize;\n            vParams->SetValueLong(ViewpointParams::CustomFramebufferHeightTag, ViewpointParams::CustomFramebufferHeightTag, height);\n            MSG_ERR(\"Selected height is larger than your OpenGL implementation supports\");\n        }\n\n        float fa = width / (float)height;\n        float wa = wWidth / (float)wHeight;\n\n        if (fa >= wa) {\n            int x = 0;\n            int y = (wHeight / 2) - (wHeight / fa * wa / 2);\n            int w = wWidth;\n            int h = wHeight / fa * wa;\n            glViewport(x, y, w, h);\n        } else {\n            int x = (wWidth / 2) - (wWidth * fa / wa / 2);\n            int y = 0;\n            int w = wWidth * fa / wa;\n            int h = wHeight;\n            glViewport(x, y, w, h);\n        }\n    } else {\n        glViewport(0, 0, width, height);\n    }\n\n    mm->MatrixModeProjection();\n    mm->LoadIdentity();\n\n    GLfloat w = (float)width / (float)height;\n\n    if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic) {\n        float s = _trackBall->GetOrthoSize();\n        mm->Ortho(-s * w, s * w, -s, s, nearDist, farDist);\n    } else {\n        double fov = vParams->GetFOV();\n        mm->Perspective(glm::radians(fov), w, nearDist, farDist);\n    }\n\n    double pMatrix[16];\n    mm->GetDoublev(MatrixManager::Mode::Projection, pMatrix);\n\n    bool enabled = _controlExec->GetSaveStateEnabled();\n    _controlExec->SetSaveStateEnabled(false);\n\n    vParams->SetProjectionMatrix(pMatrix);\n\n    if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic) vParams->SetOrthoProjectionSize(_trackBall->GetOrthoSize());\n\n    _controlExec->SetSaveStateEnabled(enabled);\n\n    mm->MatrixModeModelView();\n}\n\nvoid VizWin::_setUpModelViewMatrix()\n{\n    makeCurrent();    // necessary?\n\n    ParamsMgr *      paramsMgr = _controlExec->GetParamsMgr();\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName);\n\n    double m[16];\n    vParams->GetModelViewMatrix(m);\n    _glManager->matrixManager->LoadMatrixd(m);\n}\n\n// React to a user-change in window size/position (or possibly max/min)\n// Either the window is minimized, maximized, restored, or just resized.\n//\nvoid VizWin::resizeGL(int width, int height)\n{\n    _resizeGL(width, height);\n    if (paintOnResize)\n        Render(true);\n}\n\nvoid VizWin::_resizeGL(int width, int height)\n{\n    if (!_openGLInitFlag || !FrameBufferReady()) { return; }\n\n    int rc = CheckGLErrorMsg(\"GLVizWindowResizeEvent\");\n    if (rc < 0) { MSG_ERR(\"OpenGL error\"); }\n\n    rc = _controlExec->ResizeViz(_winName, width, height);\n    if (rc < 0) { MSG_ERR(\"OpenGL error\"); }\n\n    glViewport(0, 0, (GLint)width, (GLint)height);\n\n    ParamsMgr *      paramsMgr = _controlExec->GetParamsMgr();\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName);\n\n    // Window size can't be undone, so disable state saving\n    //\n    bool enabled = _controlExec->GetSaveStateEnabled();\n    _controlExec->SetSaveStateEnabled(false);\n    vParams->SetWindowSize(width, height);\n    _controlExec->SetSaveStateEnabled(enabled);\n}\n\nvoid VizWin::initializeGL()\n{\n    bool ok = gladLoaderLoadGL();\n    VAssert(GLManager::CheckError());\n    if (!ok) {\n        MyBase::SetErrMsg(\"Error: Unable to initialize GLAD\");\n        MSG_ERR(\"OpenGL Error\");\n    }\n    \n    _glManager = new GLManager;\n    _manip = new TranslateStretchManip(_glManager);\n    bool initialize = true;\n    updateManip(initialize);\n\n    CheckGLErrorMsg(\"GLVizWindowInitializeEvent\");\n    int rc = _controlExec->InitializeViz(_winName, _glManager);\n    if (rc < 0) {\n        MSG_FATAL(\"Failure to initialize Visualizer\");\n        return;\n    }\n    _glManager->legacy->Initialize();\n    CheckGLErrorMsg(\"GLVizWindowInitializeEvent\");\n\n    ParamsMgr *      paramsMgr = _controlExec->GetParamsMgr();\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName);\n\n    if (vParams != NULL) {\n        bool enabled = _controlExec->GetSaveStateEnabled();\n        _controlExec->SetSaveStateEnabled(false);\n        vParams->SetWindowSize(width(), height());\n        _controlExec->SetSaveStateEnabled(enabled);\n    }\n\n    _openGLInitFlag = true;\n}\n\nvoid VizWin::paintGL()\n{\n    if (_swapBufferQueued) {\n        swapBuffers();\n        _swapBufferQueued = false;\n    }\n}\n\nvoid VizWin::safeSwapBuffers()\n{\n    if (windowHandle()->isExposed())\n        swapBuffers();\n    else\n        _swapBufferQueued = true;\n}\n\nvoid VizWin::_mousePressEventManip(QMouseEvent *e)\n{\n    makeCurrent();\n\n    std::vector<double> screenCoords = _getScreenCoords(e);\n\n    screenCoords[0] *= this->devicePixelRatioF();\n    screenCoords[1] *= this->devicePixelRatioF();\n\n    _manipFlag = _manip->MouseEvent(_buttonNum, screenCoords, _strHandleMid);\n}\n\nvoid VizWin::_mousePressEventNavigate(QMouseEvent *e)\n{\n    _navigateFlag = true;\n\n    ParamsMgr *paramsMgr = _controlExec->GetParamsMgr();\n\n    double           m[16];\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName);\n    vParams->GetModelViewMatrix(m);\n\n    double center[3];\n    vParams->GetRotationCenter(center);\n\n    double posvec[3], upvec[3], dirvec[3];\n    bool   status = vParams->ReconstructCamera(m, posvec, upvec, dirvec);\n    VAssert(status);\n\n    _trackBall->setFromFrame(posvec, dirvec, upvec, center, true);\n\n    int trackballButtonNumber = _buttonNum;\n    if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic && _buttonNum == 1) trackballButtonNumber = 2;\n\n    _trackBall->MouseOnTrackball(0, trackballButtonNumber, e->x(), e->y(), width(), height());\n\n    _navigationPendingChanges = false;\n}\n\nvoid VizWin::mousePressEvent(QMouseEvent *e)\n{\n    if (_mouseClicked) return;\n\n    _buttonNum = 0;\n    _mouseClicked = true;\n\n    if ((e->buttons() & Qt::LeftButton) && (e->buttons() & Qt::RightButton))\n        ;    // do nothing\n    else if (e->button() == Qt::LeftButton)\n        _buttonNum = 1;\n    else if (e->button() == Qt::RightButton)\n        _buttonNum = 3;\n    else if (e->button() == Qt::MiddleButton)\n        _buttonNum = 2;\n\n    // ControlModifier means [command], not [control] apparently\n    if (e->button() == Qt::LeftButton && (e->modifiers() & Qt::ShiftModifier)) { _buttonNum = 2; }\n\n    if (_buttonNum == 0) {\n        _mouseClicked = true;    // mouse button is held\n        return;\n    }\n\n    string modeName = _getCurrentMouseMode();\n\n    if (modeName == MouseModeParams::GetRegionModeName()) {\n        _mousePressEventManip(e);\n\n        // Only manipulating if user managed to grab manipulator handle.\n        // Otherwise we navigate\n        //\n        if (_manipFlag) { return; }\n    }\n\n    _mousePressEventNavigate(e);\n}\n\nvoid VizWin::_mouseReleaseEventManip(QMouseEvent *e)\n{\n    if (!_manipFlag) return;\n\n    std::vector<double> screenCoords = _getScreenCoords(e);\n\n    screenCoords[0] *= this->devicePixelRatioF();\n    screenCoords[1] *= this->devicePixelRatioF();\n\n    (void)_manip->MouseEvent(_buttonNum, screenCoords, _strHandleMid, true);\n    _setNewExtents();\n\n    _manipFlag = false;\n}\n\nvoid VizWin::_mouseReleaseEventNavigate(QMouseEvent *e)\n{\n    if (!_navigateFlag) return;\n\n    _trackBall->MouseOnTrackball(2, _buttonNum, e->x(), e->y(), width(), height());\n    _trackBall->TrackballSetMatrix();\n\n    const double *m = _trackBall->GetModelViewMatrix();\n\n    ParamsMgr *paramsMgr = _controlExec->GetParamsMgr();\n\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName);\n\n    if (_navigationPendingChanges) {\n        vParams->SetModelViewMatrix(m);\n        paramsMgr->EndSaveStateGroup();\n        emit EndNavigation(_winName);\n    }\n    _navigationPendingChanges = false;\n    _navigateFlag = false;\n}\n\n/*\n * If the user releases the mouse or moves it (with the left mouse down)\n * then we note the displacement\n */\nvoid VizWin::mouseReleaseEvent(QMouseEvent *e)\n{\n    if (_buttonNum == 0) {\n        _mouseClicked = false;\n        return;\n    }\n\n    _mouseClicked = false;\n\n    if (_manipFlag) {\n        _mouseReleaseEventManip(e);\n    } else if (_navigateFlag) {\n        _mouseReleaseEventNavigate(e);\n    }\n\n    _buttonNum = 0;\n}\n\nvoid VizWin::_mouseMoveEventManip(QMouseEvent *e)\n{\n    if (!_manipFlag) return;\n\n    std::vector<double> screenCoords = _getScreenCoords(e);\n\n    screenCoords[0] *= this->devicePixelRatioF();\n    screenCoords[1] *= this->devicePixelRatioF();\n\n    (void)_manip->MouseEvent(_buttonNum, screenCoords, _strHandleMid);\n    _controlExec->GetParamsMgr()->IntermediateChange();\n}\n\nvoid VizWin::_mouseMoveEventNavigate(QMouseEvent *e)\n{\n    if (!_navigateFlag) return;\n\n    // if (_getCurrentMouseMode() == MouseModeParams::GetGeoRefModeName() && _buttonNum == 1)\n    // return;\n\n    // _buttonNum is ignored in MouseOnTrackball here\n    _trackBall->MouseOnTrackball(1, _buttonNum, e->x(), e->y(), width(), height());\n\n    _trackBall->TrackballSetMatrix();\n\n    const double *m = _trackBall->GetModelViewMatrix();\n\n    ParamsMgr *paramsMgr = _controlExec->GetParamsMgr();\n\n    // Set modelview matrix in ViewpointParams\n    //\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName);\n    if (!_navigationPendingChanges)\n        paramsMgr->BeginSaveStateGroup(\"Navigate\");\n    _navigationPendingChanges = true;\n\n    vParams->SetModelViewMatrix(m);\n    paramsMgr->IntermediateChange();\n}\n\nstd::vector<double> VizWin::_getScreenCoords(QMouseEvent *e) const\n{\n    std::vector<double> screenCoords;\n    screenCoords.push_back((double)e->x());\n    screenCoords.push_back((double)(height() - e->y()));\n    return screenCoords;\n}\n\nstring VizWin::_getCurrentMouseMode() const\n{\n    ParamsMgr *     paramsMgr = _controlExec->GetParamsMgr();\n    GUIStateParams *guiP = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n\n    string activeTab = guiP->ActiveTab();\n    if (activeTab == RenderEventRouterGUI::GeometryTabName || activeTab == FlowEventRouter::SeedingTabName || activeTab == FlowEventRouter::IntegrationTabName)\n        return MouseModeParams::GetRegionModeName();\n    else\n        return MouseModeParams::GetNavigateModeName();\n}\n\nvoid VizWin::_setNewExtents()\n{\n    std::vector<double> llc, urc;\n    _manip->GetBox(llc, urc);\n    VAPoR::RenderParams *rParams = _getRenderParams();\n    if (rParams == NULL) return;\n    VAPoR::Box *        box = rParams->GetBox();\n    std::vector<double> pllc, purc;\n    box->GetExtents(pllc, purc);\n\n    if (_manipFlowSeedFlag) {\n        FlowParams *fp = dynamic_cast<FlowParams *>(rParams);\n        if (fp) {\n            // Sam's box format: xmin, xmax, ymin, ymax, zmin, zmax\n            int dims = fp->GetRenderDim();\n\n            if (dims == 3) {    // 3D flow renderer\n                vector<float> b(6);\n                b[0] = llc[0];\n                b[2] = llc[1];\n                b[4] = llc[2];\n                b[1] = urc[0];\n                b[3] = urc[1];\n                b[5] = urc[2];\n                fp->SetRake(b);\n            } else if (dims == 2) {    // 2D flow renderer\n                vector<float> b(4);\n                b[0] = llc[0];\n                b[2] = llc[1];\n                b[1] = urc[0];\n                b[3] = urc[1];\n                fp->SetRake(b);\n            }\n        }\n    } else if (_manipFlowIntegrationFlag) {\n        FlowParams *fp = dynamic_cast<FlowParams *>(rParams);\n        VAssert(fp);\n        fp->GetIntegrationBox()->SetExtents(llc, urc);\n    } else {\n        box->SetExtents(llc, urc);\n    }\n}\n\n/*\n * When the mouse is moved, it can affect navigation,\n * region position, light position, or probe position, depending\n * on current mode.  The values associated with the window are\n * changed whether or not the tabbed panel is visible.\n *  It's important that coordinate changes eventually get recorded in the\n * viewpoint params panel.  This requires some work every time there is\n * mouse navigation.  Changes in the viewpoint params panel will notify\n * the viztab if it is active and change the values there.\n * Conversely, when values are changed in the viztab, the viewpoint\n * values are set in the VizWin class, provided they did not originally\n * come from the mouse navigation.  Such a change forces a reinitialization\n * of the trackball and the new values will be used at the next rendering.\n *\n */\nvoid VizWin::mouseMoveEvent(QMouseEvent *e)\n{\n    if (_buttonNum == 0) return;\n\n    if (_manipFlag) {\n        _mouseMoveEventManip(e);\n    } else if (_navigateFlag) {\n        _mouseMoveEventNavigate(e);\n    }\n    return;\n}\n\nvoid VizWin::setFocus() { QWidget::setFocus(); }\n\nvoid VizWin::Render(bool fast)\n{\n    // Failsafe to prevent VizWin::Render from being called recursively.\n    if (_insideRender) return;\n    _insideRender = true;\n    _renderHelper(fast);\n    _insideRender = false;\n\n    HideSTDERR();\n    safeSwapBuffers();\n    RestoreSTDERR();\n}\n\nvoid VizWin::_renderHelper(bool fast)\n{\n    // Need to call since we're not overriding QGLWidget::paintGL()\n    //\n    makeCurrent();\n\n    if (!_openGLInitFlag || !FrameBufferReady()) { return; }\n\n    glClearColor(0.3, 0.3, 0.3, 1);\n    glClear(GL_COLOR_BUFFER_BIT);\n\n    ParamsMgr *      paramsMgr = _controlExec->GetParamsMgr();\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(_winName);\n\n    bool enabled = _controlExec->GetSaveStateEnabled();\n    _controlExec->SetSaveStateEnabled(false);\n    vParams->SetWindowSize(width(), height());\n    _controlExec->SetSaveStateEnabled(enabled);\n\n    DataStatus *dataStatus = _controlExec->GetDataStatus();\n    if (!dataStatus->GetDataMgrNames().size()) return;\n\n    _preRender();\n\n    int rc = _controlExec->Paint(_winName, fast);\n    if (rc < 0) { MSG_ERR(\"Paint failed\"); }\n\n    if (_getCurrentMouseMode() == MouseModeParams::GetRegionModeName()) {\n        updateManip();\n        if (_getRenderParams() && _getRenderParams()->GetOrientable()) {\n            _updateOriginGlyph();\n            _drawContourSliceQuad();\n        }\n    } else if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic) {\n#ifndef WIN32\n        _glManager->PixelCoordinateSystemPush();\n        _glManager->matrixManager->Translate(10, 10, 0);\n        glDisable(GL_DEPTH_TEST);\n        _glManager->fontManager->GetFont(\"arimo\", 22)->DrawText(\"Geo Referenced Mode\");\n        _glManager->PixelCoordinateSystemPop();\n#endif\n    }\n\n    rc = CheckGLErrorMsg(\"VizWindowPaintGL\");\n    if (rc < 0) { MSG_ERR(\"OpenGL error\"); }\n\n    _postRender();\n}\n\nvoid VizWin::_preRender()\n{\n    _glManager->matrixManager->MatrixModeProjection();\n    _glManager->matrixManager->PushMatrix();\n    _setUpProjMatrix();\n\n    _glManager->matrixManager->MatrixModeModelView();\n    _glManager->matrixManager->PushMatrix();\n    _setUpModelViewMatrix();\n}\n\nvoid VizWin::_postRender()\n{\n    _glManager->matrixManager->MatrixModeProjection();\n    _glManager->matrixManager->PopMatrix();\n    _glManager->matrixManager->MatrixModeModelView();\n    _glManager->matrixManager->PopMatrix();\n}\n\nVAPoR::RenderParams *VizWin::_getRenderParams()\n{\n    string className;\n    return _getRenderParams(className);\n}\n\nVAPoR::RenderParams *VizWin::_getRenderParams(string &className)\n{\n    ParamsMgr *     paramsMgr = _controlExec->GetParamsMgr();\n    GUIStateParams *guiP = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n\n    string inst, winName, dataSetName;\n    guiP->GetActiveRenderer(_winName, className, inst);\n\n    bool exists = paramsMgr->RenderParamsLookup(inst, winName, dataSetName, className);\n\n    if (!exists) return NULL;\n\n    //\tVAPoR::RenderParams* rParams = _controlExec->GetRenderParams(\n    //\t\t_winName, dataSetName, className, inst\n    //\t);\n    VAPoR::RenderParams *rParams = paramsMgr->GetRenderParams(_winName, dataSetName, className, inst);\n\n    return rParams;\n}\n\nstring VizWin::_getCurrentDataMgrName() const\n{\n    ParamsMgr *     paramsMgr = _controlExec->GetParamsMgr();\n    GUIStateParams *guiP = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n\n    string inst, winName, className, dataSetName;\n    guiP->GetActiveRenderer(_winName, className, inst);\n\n    bool exists = paramsMgr->RenderParamsLookup(inst, winName, dataSetName, className);\n\n    if (!exists) return \"\";\n\n    return dataSetName;\n}\n\nvoid VizWin::_getUnionOfFieldVarExtents(RenderParams *rParams, DataMgr *dataMgr, int timeStep, int refLevel, int lod, CoordType &minExts, CoordType &maxExts)\n{\n    vector<string> fieldVars = rParams->GetFieldVariableNames();\n    vector<int>    axes;\n    bool           ok = DataMgrUtils::GetExtents(dataMgr, timeStep, fieldVars, refLevel, lod, minExts, maxExts, axes);\n    VAssert(ok);\n}\n\nvoid VizWin::_getActiveExtents(CoordType &minExts, CoordType &maxExts)\n{\n    VAPoR::RenderParams *rParams = _getRenderParams();\n    if (rParams == NULL) return;\n\n    int            refLevel = rParams->GetRefinementLevel();\n    int            lod = rParams->GetCompressionLevel();\n    string         varName = rParams->GetVariableName();\n    vector<string> fieldVars = rParams->GetFieldVariableNames();\n\n    ParamsMgr *      paramsMgr = _controlExec->GetParamsMgr();\n    AnimationParams *aParams = (AnimationParams *)paramsMgr->GetParams(AnimationParams::GetClassType());\n    int              timeStep = aParams->GetCurrentTimestep();\n\n    DataStatus *dataStatus = _controlExec->GetDataStatus();\n    string      dataMgrName = _getCurrentDataMgrName();\n    DataMgr *   dataMgr = dataStatus->GetDataMgr(dataMgrName);\n\n    if (fieldVars[0] == \"\" && fieldVars[1] == \"\" && fieldVars[2] == \"\") {\n        dataMgr->GetVariableExtents(timeStep, varName, refLevel, lod, minExts, maxExts);\n    } else {\n        _getUnionOfFieldVarExtents(rParams, dataMgr, timeStep, refLevel, lod, minExts, maxExts);\n    }\n}\n\nVAPoR::Transform *VizWin::_getDataMgrTransform() const\n{\n    string dataMgrName = _getCurrentDataMgrName();\n    if (dataMgrName.empty()) return NULL;\n\n    ParamsMgr *       paramsMgr = _controlExec->GetParamsMgr();\n    ViewpointParams * vpParams = paramsMgr->GetViewpointParams(_winName);\n    vector<string>    names = paramsMgr->GetDataMgrNames();\n    VAPoR::Transform *t = vpParams->GetTransform(dataMgrName);\n    return t;\n}\n\nvoid VizWin::updateManip(bool initialize)\n{\n    CoordType minExts = {0.0, 0.0, 0.0};\n    CoordType maxExts = {0.0, 0.0, 0.0};\n\n    _getActiveExtents(minExts, maxExts);\n\n    CoordType            llc, urc;\n    string               classType;\n    VAPoR::RenderParams *rParams = _getRenderParams(classType);\n    if (initialize || rParams == NULL) {\n        llc = minExts;\n        urc = maxExts;\n    } else {\n        _manipFlowSeedFlag = false;\n        _manipFlowIntegrationFlag = false;\n        GUIStateParams *gp = (GUIStateParams *)_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType());\n\n        if (rParams->GetName() == FlowParams::GetClassType()) {\n            if (gp->ActiveTab() == FlowEventRouter::SeedingTabName) _manipFlowSeedFlag = true;\n            if (gp->ActiveTab() == FlowEventRouter::IntegrationTabName) _manipFlowIntegrationFlag = true;\n        }\n        if (_manipFlowSeedFlag) {\n            FlowParams *fp = dynamic_cast<FlowParams *>(rParams);\n            VAssert(fp);\n\n            // Sam's box format: xmin, xmax, ymin, ymax, zmin, zmax\n            // Why doesn't Sam's code use the standard box class?\n            vector<float> b = fp->GetRake();\n\n            // If the flow renderer is 2d, add z extents or the Manip will break\n            if (b.size() == 4) {\n                b.push_back(0);\n                b.push_back(0);\n            }\n\n            llc[0] = b[0];\n            urc[0] = b[1];\n            llc[1] = b[2];\n            urc[1] = b[3];\n            llc[2] = b[4];\n            urc[2] = b[5];\n        } else if (_manipFlowIntegrationFlag) {\n            FlowParams *fp = dynamic_cast<FlowParams *>(rParams);\n            VAssert(fp);\n            fp->GetIntegrationBox()->GetExtents(llc, urc);\n        } else {\n            VAPoR::Box *box = rParams->GetBox();\n            box->GetExtents(llc, urc);\n        }\n    }\n\n    bool constrain = true;\n    if (classType == ImageParams::GetClassType()) constrain = false;\n\n    VAPoR::Transform *dmTransform = _getDataMgrTransform();\n    VAPoR::Transform *rpTransform = NULL;\n    if (rParams != NULL) rpTransform = rParams->GetTransform();\n\n    vector<double> llcVec = {llc[0], llc[1], llc[2]};\n    vector<double> urcVec = {urc[0], urc[1], urc[2]};\n    vector<double> minExtsVec = {minExts[0], minExts[1], minExts[2]};\n    vector<double> maxExtsVec = {maxExts[0], maxExts[1], maxExts[2]};\n\n    if (rParams && rParams->GetRenderDim() == 2) {\n        double defaultZ = DataMgrUtils::Get2DRendererDefaultZ(_controlExec->GetDataStatus()->GetDataMgr(_getCurrentDataMgrName()), rParams->GetCurrentTimestep(), rParams->GetRefinementLevel(), rParams->GetCompressionLevel());\n        llcVec[2] = defaultZ;\n        urcVec[2] = defaultZ;\n        minExtsVec[2] = defaultZ;\n        maxExtsVec[2] = defaultZ;\n    }\n\n    _manip->Update(llcVec, urcVec, minExtsVec, maxExtsVec, rpTransform, dmTransform, constrain);\n\n    if (!initialize) _manip->Render();\n\n    GL_ERR_BREAK();\n}\n\nvoid VizWin::_updateOriginGlyph()\n{\n    _glManager->matrixManager->PushMatrix();\n    Renderer::ApplyDatasetTransform(_glManager, _getDataMgrTransform());\n    Renderer::ApplyTransform(_glManager->matrixManager, _getDataMgrTransform(), _getRenderParams()->GetTransform());\n\n    VAPoR::RenderParams *rp = _getRenderParams();\n    double               xOrigin = rp->GetValueDouble(RenderParams::XSlicePlaneOriginTag, 0.);\n    double               yOrigin = rp->GetValueDouble(RenderParams::YSlicePlaneOriginTag, 0.);\n    double               zOrigin = rp->GetValueDouble(RenderParams::ZSlicePlaneOriginTag, 0.);\n\n    std::vector<double> scales = _getDataMgrTransform()->GetScales();\n    std::vector<double> scales2 = rp->GetTransform()->GetScales();\n    scales[0] *= scales2[0];\n    scales[1] *= scales2[1];\n    scales[2] *= scales2[2];\n\n    int            refLevel = rp->GetRefinementLevel();\n    int            lod = rp->GetCompressionLevel();\n    string         varName = rp->GetVariableName();\n    vector<string> fieldVars = rp->GetFieldVariableNames();\n\n    int timeStep = rp->GetCurrentTimestep();\n\n    DataStatus *dataStatus = _controlExec->GetDataStatus();\n    string      dataMgrName = _getCurrentDataMgrName();\n    DataMgr *   dataMgr = dataStatus->GetDataMgr(dataMgrName);\n\n    CoordType min, max;\n    dataMgr->GetVariableExtents(timeStep, varName, refLevel, lod, min, max);\n\n    // Find the average magnitude of the X and Y axes.  3% of that magnitude will be the size of the\n    // origin marker's crosshairs.\n    double              p = .03 * ((max[0] - min[0]) + (max[1] - min[1])) / 2;\n    std::vector<double> width = {p / scales[0], p / scales[1], p / scales[2]};\n\n    int depthFunc;\n    glGetIntegerv(GL_DEPTH_FUNC, &depthFunc);\n\n    glDepthMask(GL_TRUE);\n    glEnable(GL_DEPTH_TEST);\n    glDepthFunc(GL_LEQUAL);\n    LegacyGL *lgl = _glManager->legacy;\n    lgl->Color4f(1., 1., 0., 1.);\n\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3f(xOrigin, yOrigin, zOrigin - width[2]);\n    lgl->Vertex3f(xOrigin, yOrigin, zOrigin + width[2]);\n    lgl->End();\n\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3f(xOrigin - width[0], yOrigin, zOrigin);\n    lgl->Vertex3f(xOrigin + width[0], yOrigin, zOrigin);\n    lgl->End();\n\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3f(xOrigin, yOrigin - width[1], zOrigin);\n    lgl->Vertex3f(xOrigin, yOrigin + width[1], zOrigin);\n    lgl->End();\n\n    glDepthFunc(depthFunc);\n    _glManager->matrixManager->PopMatrix();\n}\n\nvoid VizWin::_drawContourSliceQuad()\n{\n    _glManager->matrixManager->PushMatrix();\n    Renderer::ApplyDatasetTransform(_glManager, _getDataMgrTransform());\n    Renderer::ApplyTransform(_glManager->matrixManager, _getDataMgrTransform(), _getRenderParams()->GetTransform());\n\n    auto quad = _getRenderParams()->GetSlicePlaneQuad();\n\n    LegacyGL *lgl = _glManager->legacy;\n    lgl->Color3f(0, 1, 0);\n    lgl->Begin(GL_LINE_STRIP);\n    for (auto v : quad) lgl->Vertex3dv(v.data());\n    if (quad.size()) lgl->Vertex3dv(quad[0].data());\n    lgl->End();\n    _glManager->matrixManager->PopMatrix();\n}\n"
  },
  {
    "path": "apps/vaporgui/VizWin.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2013\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tVizWin.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tOctober 2013\n//\n//\n\n#ifndef VIZWIN_H\n#define VIZWIN_H\n\n#include <vapor/glutil.h>\n#include <QGLWidget>\n#include \"vapor/Transform.h\"\n#include \"Manip.h\"\n#include <QWheelEvent>\n\nclass QCloseEvent;\nclass QRect;\nclass QMouseEvent;\nclass QFocusEvent;\n\nclass Visualizer;\nclass Viewpoint;\nclass Trackball;\n\nnamespace VAPoR {\nclass ControlExec;\nclass Visualizer;\nstruct GLManager;\n};    // namespace VAPoR\n\n//! \\class VizWin\n//! \\ingroup Public_GUI\n/*! \\brief A QGLWidget that supports display based on GL methods invoked in a\n *    Visualizer\n */\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date October 2013\n\n//!\tThe VizWin class is a QGLWidget that supports the rendering by the VAPOR\n//! Visualizer class.\n//! The standard rendering methods (resize, initialize, paint) are passed to the\n//! Visualizer.\n//! In addition this is the class that responds to mouse events, resulting in\n//! scene navigation\n//! or manipulator changes.\n//!\nclass VizWin : public QGLWidget {\n    Q_OBJECT\n\npublic:\n    VizWin(const QGLFormat &format, QWidget *parent, const QString &name, string winName, VAPoR::ControlExec *ce, Trackball *trackBall);\n    ~VizWin();\n\n    //! Identify the visualizer index\n    //! \\retval visualizer index.\n    string getWindowName() { return _winName; }\n\n    // Render the scene\n    //\n    // If \\p fast is true try to render the scene quickly\n    //\n    void Render(bool fast);\n    bool paintOnResize = true;\n\nsignals:\n    void EndNavigation(const string &winName);\n\npublic slots:\n    virtual void setFocus();\n\nprivate:\n    void _renderHelper(bool fast);\n    void _preRender();\n    void _postRender();\n    void updateManip(bool initialize = false);\n    void _updateOriginGlyph();\n    void _drawContourSliceQuad();\n\n    // Event handling\n    // Virtual overrides:\n    virtual void wheelEvent(QWheelEvent *e) { e->accept(); }\n\n    // QWidget reimplementations\n    virtual void mousePressEvent(QMouseEvent *);\n    virtual void mouseReleaseEvent(QMouseEvent *);\n    virtual void mouseMoveEvent(QMouseEvent *);\n\n    virtual void _mousePressEventNavigate(QMouseEvent *);\n    virtual void _mouseReleaseEventNavigate(QMouseEvent *);\n    virtual void _mouseMoveEventNavigate(QMouseEvent *);\n\n    virtual void _mousePressEventManip(QMouseEvent *);\n    virtual void _mouseReleaseEventManip(QMouseEvent *);\n    virtual void _mouseMoveEventManip(QMouseEvent *);\n\n    // QGLWidget reimplementations\n    virtual void resizeGL(int width, int height);\n    void _resizeGL(int width, int height);\n    virtual void initializeGL();\n    virtual void paintGL();\n\n    void safeSwapBuffers();\n\n    string              _winName;\n    VAPoR::ControlExec *_controlExec;\n    VAPoR::GLManager *  _glManager;\n    double              _strHandleMid[3];\n    bool                _insideRender = false;\n\n    bool       _mouseClicked;    // Indicates mouse has been clicked but not move\n    int        _buttonNum;       // currently pressed button (0=none, 1=left,2=mid, 3=right)\n    bool       _navigateFlag;\n    bool       _manipFlag;\n    bool       _manipFlowSeedFlag = false;\n    bool       _manipFlowIntegrationFlag = false;\n    Trackball *_trackBall;\n    bool _navigationPendingChanges;\n\n    std::vector<double> _getScreenCoords(QMouseEvent *e) const;\n    string              _getCurrentMouseMode() const;\n    void                _setNewExtents();\n    void                _getActiveExtents(VAPoR::CoordType &minExts, VAPoR::CoordType &maxExts);\n    void                _getUnionOfFieldVarExtents(VAPoR::RenderParams *rParams, VAPoR::DataMgr *dataMgr, int timestep, int refLevel, int lod, VAPoR::CoordType &minExts, VAPoR::CoordType &maxExts);\n    string _getCurrentDataMgrName() const;\n    VAPoR::Transform *_getDataMgrTransform() const;\n\n    void                 _getNearFarDist(const double posVec[3], const double dirVec[3], double &boxNear, double &boxFar) const;\n    VAPoR::RenderParams *_getRenderParams();\n    VAPoR::RenderParams *_getRenderParams(string &classType);\n\n    void _setUpProjMatrix();\n    void _setUpModelViewMatrix();\n\n    VAPoR::TranslateStretchManip *_manip;\n\n    bool _openGLInitFlag;\n    bool _swapBufferQueued = false;\n\n    friend class VizWinMgr;\n};\n\n#endif    // VIZWIN_H\n"
  },
  {
    "path": "apps/vaporgui/VizWinMgr.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tVizWinMgr.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tSept 2004\n//\n//\tDescription:  Implementation of VizWinMgr class\n//\t\tThis class manages the VizWin visualizers\n//\t\tIts main function is to catch events from the visualizers and\n//\t\tto route them to the appropriate params class, and in reverse,\n//\t\tto route events from tab panels to the appropriate visualizer.\n//\n#ifdef WIN32\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <iostream>\n#include <fstream>\n#include <sstream>\n#include <typeinfo>\n#include \"vapor/VAssert.h\"\n#include <qapplication.h>\n#include <QMdiArea>\n#include <QMdiSubWindow>\n#include <vapor/ControlExecutive.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/DataStatus.h>\n#include <vapor/STLUtils.h>\n#include \"QtVizWinGLContextManager.h\"\n\n#include <vapor/AnimationParams.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/GUIStateParams.h>\n#include <vapor/MouseModeParams.h>\n#include <vapor/TrackBall.h>\n#include \"VizWin.h\"\n#include \"VizWinMgr.h\"\n#include \"ErrorReporter.h\"\n#include <common.h>\n\nusing namespace VAPoR;\n\nVizWinMgr::VizWinMgr(ControlExec *ce)\n: _controlExec(ce), visualizerGLContextManager(new QtVizWinGLContextManager(this))\n{\n    _mdiArea = this;\n    _mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);\n    _mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);\n\n    _trackBall = new Trackball();\n\n    _initialized = false;\n}\n\nVizWinMgr::~VizWinMgr()\n{\n    if (_trackBall) delete _trackBall;\n}\n\nclass DisableFocusFilter: public QObject {\nprotected:\n    bool eventFilter(QObject* object, QEvent* event)\n    {\n        if(event->type() == QEvent::FocusIn)\n            return true;\n        return QObject::eventFilter(object, event);\n    }\n};\n\n// All other tested methods for user-interaction window activation also fire from programmatic events\n// - The original focus method had no way of truly distinguishing user actions.\n//   Even when wrapping the operations in _safeMDIChange which disables focus signals, for some actions such as adding subwindows Qt will ignore this.\n// - MDI active signals are also indistinguishable and unblockable for certain operations.\n//   Also, while QMDISubWindow and QMDIArea both have a \"window activated\" signal, they behave a little differently, both have the same issues though.\n// A potential solution would be to not have the active visualizer be a core part of the application state but this is currently deeply ingrained in the app.\nclass UserFocusEventFilter: public QObject {\n    function<void(void)> _callback;\n    static QWidget *_focusedWidget;\npublic:\n    UserFocusEventFilter(const function<void(void)> &callback): _callback(callback) {}\nprotected:\n    bool eventFilter(QObject* object, QEvent* event)\n    {\n        if(event->type() == QEvent::FocusIn && ((QFocusEvent*)event)->reason() == Qt::MouseFocusReason)\n            _callback();\n        return QObject::eventFilter(object, event);\n    }\n};\nvoid OnMDISubwindowUserFocus(QMdiSubWindow *w, const function<void(void)> &callback)\n{\n    w->widget()->setFocusPolicy(Qt::ClickFocus);\n    w->widget()->installEventFilter(new UserFocusEventFilter(callback));\n    w->installEventFilter(new UserFocusEventFilter(callback));\n}\n\nclass CancelCloseEventFilter: public QObject {\n    function<void(void)> _callback;\npublic:\n    CancelCloseEventFilter(const function<void(void)> &callback): _callback(callback) {}\nprotected:\n    bool eventFilter(QObject* object, QEvent* event)\n    {\n        if(event->type() == QEvent::Close) {\n            _callback();\n            event->ignore();\n            return true;\n        }\n        return QObject::eventFilter(object, event);\n    }\n};\n\nvoid VizWinMgr::_attachVisualizer(string vizName)\n{\n    if (_vizWindow.find(vizName) != _vizWindow.end()) return;\n\n    QString qvizname = QString::fromStdString(vizName);\n\n    QGLFormat glFormat;\n    glFormat.setVersion(4, 1);\n    glFormat.setProfile(QGLFormat::CoreProfile);\n\n    _vizWindow[vizName] = new VizWin(glFormat, this, qvizname, vizName, _controlExec, _trackBall);\n    _vizWindow[vizName]->setWindowTitle(qvizname);\n//    _vizWindow[vizName]->setAttribute(Qt::WA_ShowWithoutActivating); // Not honored in MDI view\n\n    // Closing window will be handled by syncing with params\n    _vizWindow[vizName]->installEventFilter(new CancelCloseEventFilter([this, vizName](){\n        if (_controlExec->GetNumVisualizers() == 1)\n            return;\n        _controlExec->GetParamsMgr()->RemoveVisualizer(vizName);\n    }));\n\n    connect(_vizWindow[vizName], SIGNAL(EndNavigation(const string &)), this, SLOT(_syncViewpoints(const string &)));\n\n    _vizMdiWin[vizName] = _mdiArea->addSubWindow(_vizWindow[vizName]);\n    OnMDISubwindowUserFocus(_vizMdiWin[vizName], [this, vizName](){\n        _setActiveViz(vizName);\n    });\n\n    GUIStateParams *p = _controlExec->GetParams<GUIStateParams>();\n    string          prevActiveVizName = p->GetActiveVizName();\n\n    _safeMDIChange([&](){ _vizWindow[vizName]->showMaximized(); });\n\n    int numWins = _controlExec->GetNumVisualizers();\n    // Tile if more than one visualizer:\n    if (numWins > 1) FitSpace();\n\n    // When we go from 1 to 2 windows, need to enable multiple\n    // viz panels and signals.\n    //\n    if (numWins > 1) {\n        emit enableMultiViz(true);\n        _syncViewpoints(prevActiveVizName);\n    }\n}\n\n\nvoid VizWinMgr::FitSpace() {\n    _safeMDIChange([this](){\n        _mdiArea->tileSubWindows();\n    });\n}\n\n\nvoid VizWinMgr::_setActiveViz(string vizName)\n{\n    GUIStateParams *p = _controlExec->GetParams<GUIStateParams>();\n    string          currentVizName = p->GetActiveVizName();\n    if (currentVizName != vizName) {\n        p->SetActiveVizName(vizName);\n        emit(activateViz(QString::fromStdString(vizName)));\n\n        if (vizName.empty()) return;\n\n        // Need to cause a redraw in all windows if we are not in navigate mode,\n        // So that the manips will change where they are drawn:\n\n        if (p->GetMouseModeParams()->GetCurrentMouseMode() != MouseModeParams::GetNavigateModeName()) {\n            map<string, VizWin *>::iterator it;\n            for (it = _vizWindow.begin(); it != _vizWindow.end(); it++) { (it->second)->Render(false); }\n        }\n    }\n}\n\nvoid VizWinMgr::_syncViewpoints(string vizName)\n{\n    if (vizName.empty()) return;\n\n    ParamsMgr *paramsMgr = _controlExec->GetParamsMgr();\n\n    bool enabled = paramsMgr->GetSaveStateEnabled();\n    paramsMgr->SetSaveStateEnabled(false);\n\n    ViewpointParams *currentVP = _controlExec->GetParamsMgr()->GetViewpointParams(vizName);\n\n    vector<string> winNames = _getVisualizerNames();\n    for (int i = 0; i < winNames.size(); i++) {\n        if (winNames[i] != vizName) {\n            ViewpointParams *vpParams = _controlExec->GetParamsMgr()->GetViewpointParams(winNames[i]);\n            vpParams->SetModelViewMatrix(currentVP->GetModelViewMatrix());\n            vpParams->SetRotationCenter(currentVP->GetRotationCenter());\n        }\n    }\n\n    paramsMgr->SetSaveStateEnabled(enabled);\n}\n\nvector<string> VizWinMgr::_getVisualizerNames() const\n{\n    vector<string>                             names;\n    std::map<string, VizWin *>::const_iterator itr = _vizWindow.begin();\n    for (; itr != _vizWindow.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\n\nvoid VizWinMgr::_killViz(string vizName)\n{\n    VAssert(_vizWindow.find(vizName) != _vizWindow.end());\n\n    _mdiArea->removeSubWindow(_vizMdiWin[vizName]);\n\n    // This will trigger a closeEvent on VizWin, which will in turn\n    // call vizAboutToDisappear\n    //\n    _vizWindow[vizName]->setEnabled(false);\n    _vizWindow[vizName]->close();\n}\n\n\nvoid VizWinMgr::_removeVisualizer(const string &name)\n{\n    auto win = _vizWindow[name];\n    win->makeCurrent();\n\n    _controlExec->CleanupVisualizer(name, true);\n\n    // disconnect all signals from window\n    disconnect(win, 0, this, 0);\n\n    // Remove the vizwin and the vizmdiwin\n    _safeMDIChange([&](){ _mdiArea->removeSubWindow(_vizMdiWin[name]); });\n    delete _vizWindow[name];\n    _vizMdiWin.erase(name);\n    _vizWindow.erase(name);\n}\n\nvoid VizWinMgr::_safeMDIChange(function<void(void)> f)\n{\n    // QMdiArea ignores attributes that disable focus signals launching by showing.\n    // These conflict with active visualizer selection based on viz win selection.\n    auto e = new DisableFocusFilter;\n    for (auto &w : _vizWindow) {\n        w.second->installEventFilter(e);\n        w.second->paintOnResize = false;\n    }\n\n    f();\n\n    for (auto &w : _vizWindow) {\n        w.second->removeEventFilter(e);\n        w.second->paintOnResize = true;\n    }\n}\n\n\nvoid VizWinMgr::syncWithParams()\n{\n    vector<string> vizNames = _controlExec->GetParamsMgr()->GetVisualizerNames();\n\n    vector<string> toRemove;\n    for (auto it = _vizWindow.cbegin(); it != _vizWindow.cend(); ++it)\n        if (!STLUtils::Contains(vizNames, it->first))\n            toRemove.push_back(it->first);\n\n    for (const auto &name : toRemove)\n        _removeVisualizer(name);\n    if (!toRemove.empty())\n        FitSpace();\n\n    for (int i = 0; i < vizNames.size(); i++) {\n        if (_vizWindow.find(vizNames[i]) != _vizWindow.end()) continue;\n        blockSignals(true);\n        _attachVisualizer(vizNames[i]);\n        blockSignals(false);\n    }\n\n    if (_controlExec->WasDataCacheDirty())\n        setTrackballScale();\n}\n\nvoid VizWinMgr::Update(bool fast)\n{\n    // Certain actions queue multiple renders within Qt's event queue (e.g. changing the\n    // renderer variable dimension). Normally, Qt will then process each of these events\n    // sequentially and render multiple times. While not ideal, this just results in extra\n    // renders and computation time. When using the progress bar, however, it sometimes\n    // requests a redraw of the entire GUI at which point Qt processes queued events.\n    // When you have pending render events, it will now try to initiate a new render\n    // before the first has finished. This prevents that but it does not fix the\n    // underlying issue.\n    if (_insideRender) return;\n    _insideRender = true;\n\n    this->syncWithParams();\n\n    map<string, VizWin *>::const_iterator it;\n    for (it = _vizWindow.begin(); it != _vizWindow.end(); it++) { (it->second)->Render(fast); }\n\n    _insideRender = false;\n}\n\nint VizWinMgr::EnableImageCapture(string filename, string winName)\n{\n    _vizWindow[winName]->makeCurrent();\n    _vizWindow[winName]->_preRender();\n    return _controlExec->EnableImageCapture(filename, winName);\n    _vizWindow[winName]->_postRender();\n}\n\nvoid VizWinMgr::setTrackballScale()\n{\n    if (_controlExec->GetDataNames().size() == 0) return;\n\n    DataStatus *dataStatus = _controlExec->GetDataStatus();\n    ParamsMgr * paramsMgr = _controlExec->GetParamsMgr();\n    size_t      ts = _controlExec->GetParams<AnimationParams>()->GetCurrentTimestep();\n\n    VAPoR::CoordType minExts, maxExts;\n    dataStatus->GetActiveExtents(paramsMgr, ts, minExts, maxExts);\n\n    double scale[3];\n    scale[0] = scale[1] = scale[2] = max(maxExts[0] - minExts[0], (maxExts[1] - minExts[1]));\n    _trackBall->SetScale(scale);\n}\n"
  },
  {
    "path": "apps/vaporgui/VizWinMgr.h",
    "content": "#pragma once\n\n#include <vapor/ControlExecutive.h>\n#include <QMdiArea>\n#include <vapor/common.h>\n#include <vapor/ParamsMgr.h>\n#include \"VaporFwd.h\"\n\nclass VizWin;\nclass Trackball;\nclass QtVizWinGLContextManager;\n\nclass VizWinMgr : public QMdiArea {\n    Q_OBJECT\n\n    VAPoR::ControlExec *_controlExec;\n\npublic:\n    VizWinMgr(VAPoR::ControlExec *ce);\n    ~VizWinMgr();\n\n    void Update(bool fast);\n\n    void SetTrackBall(const double posvec[3], const double dirvec[3], const double upvec[3], const double centerRot[3], bool perspective);\n    int EnableImageCapture(string filename, string winName);\n\n    VizWin *Get(const std::string &name) { return _vizWindow[name]; }\n\n    QtVizWinGLContextManager * const visualizerGLContextManager;\n\npublic slots:\n    void FitSpace();\n\nprivate slots:\n\n    void _setActiveViz(string winName);\n    void _syncViewpoints(string winName);\n\nsignals:\n    void enableMultiViz(bool onOff);\n    void activateViz(const QString &);\n\nprivate:\n    std::map<string, VizWin *>        _vizWindow;\n    std::map<string, QMdiSubWindow *> _vizMdiWin;\n\n    QMdiArea *_mdiArea;\n\n    Trackball *         _trackBall;\n    bool                _initialized;\n    bool                _insideRender = false;\n\n    void syncWithParams();\n\n    void _attachVisualizer(string vizName);\n\n    void _removeVisualizer(const string &name);\n    void _safeMDIChange(function<void(void)> f);\n\n    vector<string> _getVisualizerNames() const;\n    void           _killViz(string vizName);\n    void setTrackballScale();\n};\n"
  },
  {
    "path": "apps/vaporgui/VolumeEventRouter.cpp",
    "content": "#include \"VolumeEventRouter.h\"\n#include \"vapor/VolumeParams.h\"\n#include <vapor/VolumeOSPRay.h>\n#include \"PWidgets.h\"\n#include \"PStringDropdownHLI.h\"\n#include \"PMetadataClasses.h\"\n\nusing namespace VAPoR;\ntypedef VolumeParams VP;\n\nstatic RenderEventRouterRegistrar<VolumeEventRouter> registrar(VolumeEventRouter::GetClassType());\n\nVolumeEventRouter::VolumeEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, VolumeParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PScalarVariableSelector,\n            new PColorMapVariableSelector\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    AddAppearanceSubtab(new PGroup({\n        (new PTFEditor)->ShowColormapBasedOnParam(VP::UseColormapVariableTag, false),\n        new PSection(\"Rendering Method\", {\n            new PStringDropdownHLI<VP>(\"Raytracing Algorithm\", VP::GetAlgorithmNames(VP::Type::DVR), &VP::GetAlgorithm, &VP::SetAlgorithmByUser),\n        }),\n        (new PShowIf(VP::_algorithmTag))->Equals(VolumeOSPRay::GetName())->Then({\n            new PSection(\"OSPRay Parameters\", {\n                (new PDoubleSliderEdit(VolumeParams::OSPDensity, \"Density\"))->SetRange(0, 3)->EnableDynamicUpdate()->SetTooltip(\"Volume density (aka opacity).\"),\n                (new PIntegerSliderEdit(\"osp_spp\", \"Samples Per Pixel\"))->SetRange(1, 10)->SetTooltip(\"Number of render passes. Increases fidelity but may significantly reduce performance.\"),\n                (new PDoubleInput(VolumeParams::OSPSampleRateScalar, \"Volume Sample Rate Scalar\"))->EnableBasedOnParam(\"osp_usePT\", false)->SetTooltip(\"Scales the sampling rate along the ray throughout the volume. Increasing may significantly reduce performance.\"), })\n        })->Else({\n            new PSection(\"Ray Tracing\", {\n                new PEnumDropdown(VP::SamplingRateMultiplierTag, {\"1x\", \"2x\", \"4x\", \"8x\", \"16x\"}, {1, 2, 4, 8, 16}, \"Sampling Rate Multiplier\"),\n                (new PDoubleSliderEdit(VP::VolumeDensityTag, \"Volume Density\"))->EnableDynamicUpdate()->SetTooltip(\"Changes the overall density or 'opacity' of the volume allowing for finer tuning of the transfer function.\"),\n                new PCheckbox(VP::UseColormapVariableTag, \"Color by other variable\"),\n            }),\n            (new PColormapTFEditor)->ShowBasedOnParam(VolumeParams::UseColormapVariableTag),\n            new PSection(\"Lighting\", {\n                new PCheckbox(VolumeParams::LightingEnabledTag, \"Enabled\"),\n                (new PDoubleSliderEdit(VP::PhongAmbientTag,   \"Ambient\"  ))->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(VP::PhongDiffuseTag,   \"Diffuse\"  ))->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(VP::PhongSpecularTag,  \"Specular\" ))->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(VP::PhongShininessTag, \"Shininess\"))->EnableDynamicUpdate()\n            })\n        })\n    }));\n    \n    AddGeometrySubtab(new PGeometrySubtab);\n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nstring VolumeEventRouter::_getDescription() const\n{\n    return (\"Displays \"\n            \"the user's 3D data variables within a volume described by the source data \"\n            \"file, according to color and opacity settings defined by the user.\\n\\n\"\n            \"These 3D variables may be offset by a height variable.\\n\\n\");\n}\n"
  },
  {
    "path": "apps/vaporgui/VolumeEventRouter.h",
    "content": "#pragma once\n\n#include \"vapor/VolumeRenderer.h\"\n#include \"RenderEventRouterGUI.h\"\n\n//! \\class VolumeEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Volume renderer GUI\n//! \\author Stas Jaroszynski\n\nclass VolumeEventRouter : public RenderEventRouterGUI {\npublic:\n    VolumeEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::VolumeRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return false; }\n    bool          Supports3DVariables() const { return true; }\n\nprotected:\n    string _getDescription() const;\n    string _getSmallIconImagePath() const { return \"DVR_small.png\"; }\n    string _getIconImagePath() const { return \"DVR.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/VolumeIsoEventRouter.cpp",
    "content": "#include \"VolumeIsoEventRouter.h\"\n#include <vapor/VolumeIsoParams.h>\n#include <vapor/VolumeOSPRay.h>\n#include \"PWidgets.h\"\n#include \"PStringDropdownHLI.h\"\n#include \"PMetadataClasses.h\"\n\nusing namespace VAPoR;\ntypedef VolumeIsoParams VIP;\n\nstatic RenderEventRouterRegistrar<VolumeIsoEventRouter> registrar(VolumeIsoEventRouter::GetClassType());\n\nVolumeIsoEventRouter::VolumeIsoEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, VolumeIsoParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PScalarVariableSelector,\n            new PColorMapVariableSelector\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    AddAppearanceSubtab(new PGroup({\n        new PTFEditor(RenderParams::_variableNameTag, {PTFEditor::Histogram, PTFEditor::Opacity, PTFEditor::IsoValues}),\n        new PSection(\"Rendering Method\", {\n            new PStringDropdownHLI<VIP>(\"Raytracing Algorithm\", VIP::GetAlgorithmNames(VIP::Type::Iso), &VIP::GetAlgorithm, &VIP::SetAlgorithmByUser),\n        }),\n        (new PShowIf(VIP::_algorithmTag))->Equals(VolumeOSPRayIso::GetName())->Then({\n            new PSection(\"OSPRay Parameters\", {\n                (new PIntegerSliderEdit(\"osp_spp\", \"Samples Per Pixel\"))->SetRange(1, 10)->SetTooltip(\"Number of render passes. Increases fidelity but may significantly reduce performance.\"),\n                (new PDoubleSliderEdit(VIP::OSPAmbientLightIntensity, \"Ambient Light\"))->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(VIP::OSPDirectionalLightIntensity, \"Diffuse Light\"))->SetRange(0, 3)->EnableDynamicUpdate(),\n            })\n        })->Else({\n            new PSection(\"Ray Tracing\", {\n                new PEnumDropdown(VIP::SamplingRateMultiplierTag, {\"1x\", \"2x\", \"4x\", \"8x\", \"16x\"}, {1, 2, 4, 8, 16}, \"Sampling Rate Multiplier\"),\n                new PCheckbox(VIP::UseColormapVariableTag, \"Color by other variable\"),\n                (new PColorSelector(RenderParams::_constantColorTag, \"Color\"))->ShowBasedOnParam(VIP::UseColormapVariableTag, false),\n                (new PVariableSelector3D(RenderParams::_colorMapVariableNameTag))->ShowBasedOnParam(VIP::UseColormapVariableTag)\n            }),\n            (new PColormapTFEditor)->ShowBasedOnParam(VIP::UseColormapVariableTag),\n            new PSection(\"Lighting\", {\n                new PCheckbox(VIP::LightingEnabledTag, \"Enabled\"),\n                (new PDoubleSliderEdit(VIP::PhongAmbientTag,   \"Ambient\" ))->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(VIP::PhongDiffuseTag,   \"Diffuse\" ))->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(VIP::PhongSpecularTag,  \"Specular\"))->EnableDynamicUpdate(),\n                (new PDoubleSliderEdit(VIP::PhongShininessTag, \"Shininess\"))->SetRange(1, 100)->EnableDynamicUpdate()\n            })\n        })\n    }));\n    \n    AddGeometrySubtab(new PGeometrySubtab);\n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nstring VolumeIsoEventRouter::_getDescription() const\n{\n    return (\"Displays \"\n            \"the user's 3D data variables within a volume described by the source data \"\n            \"file, according to color and opacity settings defined by the user.\\n\\n\"\n            \"These 3D variables may be offset by a height variable.\\n\\n\");\n}\n"
  },
  {
    "path": "apps/vaporgui/VolumeIsoEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include \"vapor/VolumeIsoRenderer.h\"\n\n//! \\class VolumeIsoEventRouter\n//! \\ingroup Public_GUI\n//! \\brief Isosurface renderer GUI\n//! \\author Stas Jaroszynski\n\nclass VolumeIsoEventRouter : public RenderEventRouterGUI {\npublic:\n    VolumeIsoEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::VolumeIsoRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return false; }\n    bool          Supports3DVariables() const { return true; }\n\nprotected:\n    string _getDescription() const;\n    string _getSmallIconImagePath() const { return \"IsoSurface_small.png\"; }\n    string _getIconImagePath() const { return \"IsoSurface.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/WireFrameEventRouter.cpp",
    "content": "#include \"WireFrameEventRouter.h\"\n#include \"vapor/WireFrameParams.h\"\n#include \"PWidgets.h\"\n#include \"PConstantColorWidget.h\"\n#include \"PMetadataClasses.h\"\n\nusing namespace VAPoR;\n\nstatic RenderEventRouterRegistrar<WireFrameEventRouter> registrar(WireFrameEventRouter::GetClassType());\n\nWireFrameEventRouter::WireFrameEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, WireFrameParams::GetClassType())\n{\n    // clang-format off\n\n    AddVariablesSubtab(new PGroup({\n        new PSection(\"Variable Selection\", {\n            new PDimensionSelector,\n            new PScalarVariableSelector,\n            new PHeightVariableSelector\n        }),\n        new PFidelitySection,\n        new POpenVariableMetadataWidget\n    }));\n    \n    AddAppearanceSubtab(new PGroup({\n        (new PTFEditor)->ShowOpacityBasedOnParam(\"NULL\", 1),\n        new PSection(\"Appearance\", {\n            new PConstantColorWidget\n        })\n    }));\n    \n    AddGeometrySubtab(new PGeometrySubtab);\n    AddColorbarSubtab(new PAnnotationColorbarWidget);\n\n    // clang-format on\n}\n\nstring WireFrameEventRouter::_getDescription() const { return (\"Displays a wireframe of the mesh for the selected variable\"); }\n"
  },
  {
    "path": "apps/vaporgui/WireFrameEventRouter.h",
    "content": "#pragma once\n\n#include \"RenderEventRouterGUI.h\"\n#include \"vapor/WireFrameRenderer.h\"\n\n//! \\class WireFrameEventRouter\n//! \\ingroup Public_GUI\n//! \\brief WireFrame Renderer GUI\n//! \\author Stas Jaroszynski\n\nclass WireFrameEventRouter : public RenderEventRouterGUI {\npublic:\n    WireFrameEventRouter(QWidget *parent, VAPoR::ControlExec *ce);\n    static string GetClassType() { return VAPoR::WireFrameRenderer::GetClassType(); }\n    string        GetType() const { return GetClassType(); }\n    bool          Supports2DVariables() const { return true; }\n    bool          Supports3DVariables() const { return true; }\n\nprotected:\n    string _getDescription() const;\n    string _getSmallIconImagePath() const { return \"WireFrame_small.png\"; }\n    string _getIconImagePath() const { return \"WireFrame.png\"; }\n};\n"
  },
  {
    "path": "apps/vaporgui/common.cpp",
    "content": "#include <common.h>\n"
  },
  {
    "path": "apps/vaporgui/common.h",
    "content": "#pragma once\n#include <vapor/common.h>\n#include <QObject>\n#include \"PWidgetsFwd.h\"\n\nnamespace VAPoR {\nclass ParamsBase;\nclass ParamsMgr;\nclass DataMgr;\nclass ControlExec;\n}\nusing namespace VAPoR;\n\nclass SettingsParams;\nclass GUIStateParams;\n\nclass PDynamicMixin;\ntemplate<class, typename> class PWidgetHLIBase;\n\n"
  },
  {
    "path": "apps/vaporgui/core_profile_attributes.mm",
    "content": "#include <QGLContext>\n\n#if QT_VERSION < 0x050000 // if less than 5.0.0\nvoid* select_3_2_mac_visual(GDHandle handle, int depthBufferSize)\n{\n    static const int Max = 40;\n    NSOpenGLPixelFormatAttribute attribs[Max];\n    int cnt = 0;\n\n    attribs[cnt++] = NSOpenGLPFAOpenGLProfile;\n    attribs[cnt++] = NSOpenGLProfileVersion3_2Core;\n\n    attribs[cnt++] = NSOpenGLPFADoubleBuffer;\n\n    attribs[cnt++] = NSOpenGLPFADepthSize;\n    attribs[cnt++] = (NSOpenGLPixelFormatAttribute)(depthBufferSize==-1)?32:depthBufferSize;\n\n    attribs[cnt] = 0;\n    Q_ASSERT(cnt < Max);\n\n\n    return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];\n}\n#endif\n"
  },
  {
    "path": "apps/vaporgui/hide_std_error_util.cpp",
    "content": "#include \"hide_std_error_util.h\"\n\n#ifndef WIN32\n    #include <unistd.h>\n    #include <stdio.h>\n#endif\n\nstatic int _savedSTDERR;\n\nvoid HideSTDERR()\n{\n#ifndef WIN32\n    _savedSTDERR = -1;\n    if (fflush(stderr) != 0) return;\n\n    int rc = dup(STDERR_FILENO);\n    if (rc < 0)\n        return;\n    else\n        _savedSTDERR = rc;\n\n    auto *tmp = freopen(\"/dev/null\", \"w\", stderr);\n    (void)tmp;\n#endif\n}\nvoid RestoreSTDERR()\n{\n#ifndef WIN32\n    if (_savedSTDERR == -1) return;\n\n    fflush(stderr);\n\n    dup2(_savedSTDERR, STDERR_FILENO);\n    close(_savedSTDERR);\n\n    clearerr(stderr);\n#endif\n}\n"
  },
  {
    "path": "apps/vaporgui/hide_std_error_util.h",
    "content": "#pragma once\n\nvoid HideSTDERR();\nvoid RestoreSTDERR();\n"
  },
  {
    "path": "apps/vaporgui/images/arrowrake.xpm",
    "content": "/* XPM */\r\nconst static char *arrowrake[] = {\r\n/* columns rows colors chars-per-pixel */\r\n\"26 23 82 1\",\r\n\"  c #040404\",\r\n\". c #040308\",\r\n\"X c #090A05\",\r\n\"o c #0A0B0A\",\r\n\"O c #100F14\",\r\n\"+ c #131314\",\r\n\"@ c #16151A\",\r\n\"# c  gray11\",\r\n\"$ c #232323\",\r\n\"% c #2B2C29\",\r\n\"& c #2C2B31\",\r\n\"* c #343434\",\r\n\"= c #393A36\",\r\n\"- c #3D3D3C\",\r\n\"; c #494949\",\r\n\": c #51524A\",\r\n\"> c #505050\",\r\n\", c #5F5F5F\",\r\n\"< c #626262\",\r\n\"1 c #6C6C6C\",\r\n\"2 c #737373\",\r\n\"3 c #7A7A7A\",\r\n\"4 c #848483\",\r\n\"5 c #878880\",\r\n\"6 c #8A8B84\",\r\n\"7 c #8B8B89\",\r\n\"8 c #91928B\",\r\n\"9 c #9A9C8F\",\r\n\"0 c #959595\",\r\n\"q c #9A9B94\",\r\n\"w c #9C9C9A\",\r\n\"e c #9C9BA0\",\r\n\"r c #9FA194\",\r\n\"t c #A1A29C\",\r\n\"y c #ABAD9F\",\r\n\"u c #A4A4A2\",\r\n\"i c #ABACA3\",\r\n\"p c #ABABAB\",\r\n\"a c #A7A5B2\",\r\n\"s c #ADABB6\",\r\n\"d c #B2B5A4\",\r\n\"f c #B3B5A9\",\r\n\"g c #B7B9AE\",\r\n\"h c #B2B2B2\",\r\n\"j c #B7B8B0\",\r\n\"k c #B8B7BC\",\r\n\"l c #B9B9B4\",\r\n\"z c #BABABB\",\r\n\"x c #BEBDC3\",\r\n\"c c #BFC1B3\",\r\n\"v c #C2C3BC\",\r\n\"b c #C7C9BC\",\r\n\"n c #CACDBD\",\r\n\"m c #C1C1C3\",\r\n\"M c #C7C8C3\",\r\n\"N c #C8C7CC\",\r\n\"B c #CACCC3\",\r\n\"V c #CBCBCA\",\r\n\"C c #D0CFD4\",\r\n\"Z c #D0D2C7\",\r\n\"A c #D7D9CB\",\r\n\"S c #DADDCC\",\r\n\"D c #D7D7D5\",\r\n\"F c #DCDCDA\",\r\n\"G c #DEE1CC\",\r\n\"H c #DEE0D4\",\r\n\"J c none\",\r\n\"K c none\",\r\n\"L c none\",\r\n\"P c none\",\r\n\"I c none\",\r\n\"U c none\",\r\n\"Y c none\",\r\n\"T c none\",\r\n\"R c none\",\r\n\"E c none\",\r\n\"W c none\",\r\n\"Q c none\",\r\n\"! c none\",\r\n\"~ c none\",\r\n\"^ c none\",\r\n\"/ c none\",\r\n/* pixels */\r\n\"PYYKPYUJUPURYU!IUUUUUUUUUU\",\r\n\"YUY/TKURURPKTYITUUUUUUUUUU\",\r\n\"YPPPIIYYUKTRJPYPUUUUUUYUUU\",\r\n\"YPTYcqfYTRUURUGTUUUUUUUUUU\",\r\n\"YPPYYFj6fK!KU~YPUUIUUUUUUU\",\r\n\"PY~Fi8iVuwlIYKTYUUUUUUUUUU\",\r\n\"UPIIIEVwphuwrB^KUUUUUUUUUU\",\r\n\"PUUbq8pNxpp0=:ZWUUUUUUUUUU\",\r\n\"UP!KEYDhuppw*>17HWWLIYYPUU\",\r\n\"UPGy88wwhpp4$23-%6H^IY!TTI\",\r\n\"PPTLQQFNhpp4&33;@o-qVcpiq7\",\r\n\"!KBrrrupppp2$21,&O.o XooO \",\r\n\"KY~IQEVxzhk3$73;@.$<678685\",\r\n\"TIAiruhxhpp2$3,;=2MQYI!!YI\",\r\n\"IY~EEFmeppu2%230AY!IHYTJUU\",\r\n\"YIFfqumNhpp1#sQE!IIYTYJUYY\",\r\n\"UUUHECsazpuiyIUUUUUUUUUUUU\",\r\n\"TJIBtlVkivIYGYPUUUUUUUUUUU\",\r\n\"JY~~YgrVUY!TUTUPUUUUUUUUUU\",\r\n\"~K!Adn!KUUJKUYYYUUUUUUUUUU\",\r\n\"ILYYYUGTUYTUUUUYUUUUUUUUUU\",\r\n\"IW!II!UYYYYUKUYUUUUUUUUUUU\",\r\n\"IY!II!YEEW!!K/YUUUUUUUUUUU\"\r\n};\r\n"
  },
  {
    "path": "apps/vaporgui/images/back.xpm",
    "content": "/* XPM */\r\n/* Drawn  by Mark Donohoe for the K Desktop Environment */\r\n/* See http://www.kde.org */\r\nconst static char*back[]={\r\n\"16 16 5 1\",\r\n\"# c #000000\",\r\n\"a c #ffffff\",\r\n\"c c #808080\",\r\n\"b c #c0c0c0\",\r\n\". c None\",\r\n\"................\",\r\n\".......#........\",\r\n\"......##........\",\r\n\".....#a#........\",\r\n\"....#aa########.\",\r\n\"...#aabaaaaaaa#.\",\r\n\"..#aabbbbbbbbb#.\",\r\n\"...#abbbbbbbbb#.\",\r\n\"...c#ab########.\",\r\n\"....c#a#ccccccc.\",\r\n\".....c##c.......\",\r\n\"......c#c.......\",\r\n\".......cc.......\",\r\n\"........c.......\",\r\n\"................\",\r\n\"......................\"};\r\n\r\n"
  },
  {
    "path": "apps/vaporgui/images/capture-off.xpm",
    "content": "/* XPM */\nconst static char *capture-off[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 236 2\",\n\"   c black\",\n\".  c #000100\",\n\"X  c #010100\",\n\"o  c #010101\",\n\"O  c #000002\",\n\"+  c #010103\",\n\"@  c #010200\",\n\"#  c #020200\",\n\"$  c #020300\",\n\"%  c #030301\",\n\"&  c #020202\",\n\"*  c gray1\",\n\"=  c #000004\",\n\"-  c #000005\",\n\";  c #010005\",\n\":  c #010006\",\n\">  c #020106\",\n\",  c #020107\",\n\"<  c #020204\",\n\"1  c #030305\",\n\"2  c #030207\",\n\"3  c #040500\",\n\"4  c #040402\",\n\"5  c #040404\",\n\"6  c gray2\",\n\"7  c #040406\",\n\"8  c #050507\",\n\"9  c #060606\",\n\"0  c #070707\",\n\"q  c #03020A\",\n\"w  c #040308\",\n\"e  c #040309\",\n\"r  c #050409\",\n\"t  c #070709\",\n\"y  c #080903\",\n\"u  c #080806\",\n\"i  c #090A04\",\n\"p  c #0A0B05\",\n\"a  c #0B0C06\",\n\"s  c #0B0C07\",\n\"d  c #0D0F04\",\n\"f  c #090909\",\n\"g  c gray4\",\n\"h  c #0C0C0A\",\n\"j  c #0D0E08\",\n\"k  c gray5\",\n\"l  c #11110F\",\n\"z  c #13140C\",\n\"x  c #14150D\",\n\"c  c #111113\",\n\"v  c #131313\",\n\"b  c #151513\",\n\"n  c #151611\",\n\"m  c #161712\",\n\"M  c gray8\",\n\"N  c #151515\",\n\"B  c #151517\",\n\"V  c #161616\",\n\"C  c gray9\",\n\"Z  c #161618\",\n\"A  c #171719\",\n\"S  c #171812\",\n\"D  c #1A1B15\",\n\"F  c #1A1B16\",\n\"G  c #1C1E11\",\n\"H  c #1C1D17\",\n\"J  c #191919\",\n\"K  c #1B1B19\",\n\"L  c #1D1E18\",\n\"P  c #1E1E1E\",\n\"I  c #1E2015\",\n\"U  c #1F2018\",\n\"Y  c #1F201B\",\n\"T  c #22231D\",\n\"R  c #24261B\",\n\"E  c #232323\",\n\"W  c #252523\",\n\"Q  c #252620\",\n\"!  c #262721\",\n\"~  c gray14\",\n\"^  c #252525\",\n\"/  c #252527\",\n\"(  c #272729\",\n\")  c #272823\",\n\"_  c #2A2B26\",\n\"`  c #2A2A28\",\n\"'  c #2A2A2A\",\n\"]  c gray17\",\n\"[  c #303129\",\n\"{  c #32332E\",\n\"}  c #303032\",\n\"|  c #333331\",\n\" . c gray20\",\n\".. c #343530\",\n\"X. c #353535\",\n\"o. c #343436\",\n\"O. c #353537\",\n\"+. c #393937\",\n\"@. c #3A3B35\",\n\"#. c #3C3D35\",\n\"$. c gray22\",\n\"%. c #38383A\",\n\"&. c #3A3A38\",\n\"*. c #3C3C3A\",\n\"=. c #41423C\",\n\"-. c #43443C\",\n\";. c gray25\",\n\":. c #424240\",\n\">. c #434341\",\n\",. c #454641\",\n\"<. c #444444\",\n\"1. c #454547\",\n\"2. c gray28\",\n\"3. c #454449\",\n\"4. c #474749\",\n\"5. c #474840\",\n\"6. c #4A4B45\",\n\"7. c #484848\",\n\"8. c #494949\",\n\"9. c #4D4E48\",\n\"0. c #50504E\",\n\"q. c #53544C\",\n\"w. c #595B4E\",\n\"e. c #56555A\",\n\"r. c #5F605A\",\n\"t. c #606257\",\n\"y. c #6A6B63\",\n\"u. c #7A7A7C\",\n\"i. c #7D7D7F\",\n\"p. c #82837E\",\n\"a. c #85877C\",\n\"s. c #878785\",\n\"d. c #878789\",\n\"f. c #888886\",\n\"g. c #8E8F87\",\n\"h. c #898989\",\n\"j. c #88888A\",\n\"k. c #8B8B89\",\n\"l. c gray54\",\n\"z. c #8B8B8D\",\n\"x. c #8C8C8E\",\n\"c. c #97998B\",\n\"v. c #9C9E91\",\n\"b. c gray61\",\n\"n. c #9C9C9E\",\n\"m. c #A8AA9F\",\n\"M. c #A9AAA5\",\n\"N. c #AAABA5\",\n\"B. c #ABADA0\",\n\"V. c #ACADA5\",\n\"C. c #ACADA7\",\n\"Z. c #AEAEAE\",\n\"A. c #AFAFB1\",\n\"S. c #BBBCB4\",\n\"D. c #BFC1B4\",\n\"F. c #C3C5BA\",\n\"G. c #C6C8BD\",\n\"H. c #C8CABD\",\n\"J. c #CBCDC0\",\n\"K. c #CDCFC4\",\n\"L. c #CFD2C1\",\n\"P. c #CFD1C6\",\n\"I. c #D1D3C5\",\n\"U. c #D2D4C7\",\n\"Y. c #D3D5CA\",\n\"T. c #D8D9D1\",\n\"R. c #D8D8D6\",\n\"E. c #DBDDD0\",\n\"W. c #DEDFD7\",\n\"Q. c #DDDDDB\",\n\"!. c #DDDED8\",\n\"~. c #E6EACF\",\n\"^. c #E2E4D6\",\n\"/. c #E4E7D2\",\n\"(. c #E4E7D4\",\n\"). c #E4E7D6\",\n\"_. c #E2E4D9\",\n\"`. c #E4E6D8\",\n\"'. c #E5E7D9\",\n\"]. c #E5E8D3\",\n\"[. c #E6EAD3\",\n\"{. c #E7EBD2\",\n\"}. c #E5E8D7\",\n\"|. c #E6E9D4\",\n\" X c #E6E9D6\",\n\".X c #E7EAD5\",\n\"XX c #E7EBD4\",\n\"oX c #E7EAD7\",\n\"OX c #E6E9D8\",\n\"+X c #E6E8DA\",\n\"@X c #E6E8DB\",\n\"#X c #E7E9DB\",\n\"$X c #E7EAD9\",\n\"%X c #E6E8DD\",\n\"&X c #E7E9DE\",\n\"*X c #E8EBD6\",\n\"=X c #E8ECD3\",\n\"-X c #E9EED0\",\n\";X c #E8ECD5\",\n\":X c #E9ECD7\",\n\">X c #E9EDD6\",\n\",X c #EAEED5\",\n\"<X c #EBEFD4\",\n\"1X c #EAEED7\",\n\"2X c #E8EBD8\",\n\"3X c #E8EBDA\",\n\"4X c #E8EADC\",\n\"5X c #E9EBDD\",\n\"6X c #E8EADF\",\n\"7X c #E9EBDE\",\n\"8X c #E9ECD9\",\n\"9X c #E9ECDB\",\n\"0X c #EAEDD8\",\n\"qX c #EAEDDA\",\n\"wX c #EBEED9\",\n\"eX c #EBEEDB\",\n\"rX c #EAEDDC\",\n\"tX c #EAECDE\",\n\"yX c #EBEDDF\",\n\"uX c #EBEEDD\",\n\"iX c #ECEFDA\",\n\"pX c #ECEFDC\",\n\"aX c #ECEFDE\",\n\"sX c #EDF0DD\",\n\"dX c #EDF0DF\",\n\"fX c #EFF3DC\",\n\"gX c #E9EBE0\",\n\"hX c #E9EAE2\",\n\"jX c #EBEDE0\",\n\"kX c #EBEDE2\",\n\"lX c #ECEEE0\",\n\"zX c #EDEFE1\",\n\"xX c #EDEEE6\",\n\"cX c #EDEDEB\",\n\"vX c #EEF1E0\",\n\"bX c #EEF0E2\",\n/* pixels */\n\"9X9X<X<X XwXwX*X7X9X9X=X<X~.<X9X9X$X#XuX XwX*X<X\",\n\"rX*X X<XuX7X`.aXkXrX(.wX].sX9X*X$X7XrX(.eX#X#XwX\",\n\"9X9X.X9X$X_.q.d * [ v.uX7XyX$XF.5.y s -.H.yXeX X\",\n\"<X].<X9X&X_ * * 1 * * y.xXhXM.s * * * * s K.$XeX\",\n\"$XwX X$Xg.* * t * 1 * f Q.cXK * 1 1 t 1 * P rX$X\",\n\"9X9X/.rXH f 1 1.j.1.4 * b.Z.* 5 1.d.3.t c * H.9X\",\n\"9X XsX^.* * 1 j.n j.* * u.z.* * j.n z.1 4 * B.aX\",\n\"eX*X<XrXH 4 1 1.s.2.* * n.Z.* * ,.s.3.* * * H.7X\",\n\"<X#X7XrXc.* * q 4 * * s `.9XI E 5 * e q * G rXrX\",\n\"<XwX#XeX^.w.* 1 * * * M.aXrXT.A * 1 * * y E.$X$X\",\n\"9X^.#X9X9X#X#.* * c e.R.K.U.Q.i.n * * ! W.9X9X<X\",\n\"<XrXR a.Y.&X6.* * 1 1 * S z S ^ _ ~ A P 7X9X<X9X\",\n\"rX&X{ * * S c * * * * C 0.) _ ( ~ ' 7.T uX X].wX\",\n\"$XkX&.* * * * * * * * P 8.k C C v A 7.! 7X<XfX/.\",\n\"<XrX{ * * * * A C c l f  . .X.| O.} ] n 7X<X*XwX\",\n\"{. X+.* * * * | O.+.X.* 1 * * * 1 1 * D 7X#X*X#X\",\n\"9X7X1 p.U.9XR 1 * 4 h * * * * * * * * z rX#X9X<X\",\n\"~.9XkX`.9X].L.C.F.e.* * * * 1 1 * ;.C.D.#X*X9X*X\",\n\"1X<X<X<X9X<X*X9X#XI.t.=.;.;.<.;.=.m.`.9X#XuX].9X\",\n\"rX#X9X X9XrX9X*X<X9X9X9X#X9X<X X$XrXuX9X<X<X#X<X\",\n\"7X*XwX*X9X7X9X*X9X9X9X9X9X#X*X<X7XrXrX<X X<X#X*X\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/capture-on.xpm",
    "content": "/* XPM */\nconst static char *capture-on[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 127 2\",\n\"   c #F50100\",\n\".  c #F60108\",\n\"X  c #F60D09\",\n\"o  c #FD0201\",\n\"O  c #FE010B\",\n\"+  c #FC0903\",\n\"@  c #FE0C0A\",\n\"#  c #FC0F17\",\n\"$  c #FF1006\",\n\"%  c #FB140E\",\n\"&  c #F41011\",\n\"*  c #FB1313\",\n\"=  c #FF131A\",\n\"-  c #FF1816\",\n\";  c #FF181B\",\n\":  c #F21C28\",\n\">  c #F81D23\",\n\",  c #FF1D28\",\n\"<  c #F62217\",\n\"1  c #F9221F\",\n\"2  c #F42E23\",\n\"3  c #F52A2E\",\n\"4  c #FE2B26\",\n\"5  c #FF2B2A\",\n\"6  c #F72234\",\n\"7  c #F72F32\",\n\"8  c #FD2431\",\n\"9  c #FD2B32\",\n\"0  c #F33326\",\n\"q  c #FF3228\",\n\"w  c #FF3B2C\",\n\"e  c #F63D3A\",\n\"r  c #FD3434\",\n\"t  c #FD353C\",\n\"y  c #FD3B34\",\n\"u  c #FD3B3C\",\n\"i  c #FE3641\",\n\"p  c #FD3A44\",\n\"a  c #FC3C49\",\n\"s  c #F74237\",\n\"d  c #F7443D\",\n\"f  c #F94137\",\n\"g  c #FC403D\",\n\"h  c #FF4444\",\n\"j  c #FF4048\",\n\"k  c #FF4D44\",\n\"l  c #FD4B4A\",\n\"z  c #FF4755\",\n\"x  c #FC4D54\",\n\"c  c #F95345\",\n\"v  c #FF5155\",\n\"b  c #FF605A\",\n\"n  c #F86C5F\",\n\"m  c #F76C6F\",\n\"M  c #FF6567\",\n\"N  c #FE6C63\",\n\"B  c #FA6B68\",\n\"V  c #FF6D73\",\n\"C  c #FB716D\",\n\"Z  c #FC7D6A\",\n\"A  c #FA7274\",\n\"S  c #FA7D7B\",\n\"D  c #FC827C\",\n\"F  c #FD8184\",\n\"G  c #FF848A\",\n\"H  c #FF8F83\",\n\"J  c #FF8F8E\",\n\"K  c #FF8B93\",\n\"L  c #F2998B\",\n\"P  c #F89083\",\n\"I  c #FF938E\",\n\"U  c #F59599\",\n\"Y  c #FD9494\",\n\"T  c #FF939D\",\n\"R  c #FF8EA0\",\n\"E  c #FFA199\",\n\"W  c #FFAB9C\",\n\"Q  c #FBBDA8\",\n\"!  c #FCB2B3\",\n\"~  c #F2CDBA\",\n\"^  c #FDC0BB\",\n\"/  c #DEECD2\",\n\"(  c #DBEEDA\",\n\")  c #DEF3DC\",\n\"_  c #DEF0E0\",\n\"`  c #F9D5C5\",\n\"'  c #FFDBD1\",\n\"]  c #E5E6C7\",\n\"[  c #E4ECCD\",\n\"{  c #E9EBCD\",\n\"}  c #E5E7D9\",\n\"|  c #E5ECD4\",\n\" . c #E4ECDB\",\n\".. c #EDE7D4\",\n\"X. c #EBE6DB\",\n\"o. c #EAEBD4\",\n\"O. c #EAEBDA\",\n\"+. c #E3F0CC\",\n\"@. c #E4F0D4\",\n\"#. c #E4F0DC\",\n\"$. c #EDF2D4\",\n\"%. c #ECF1DB\",\n\"&. c #F7E7CD\",\n\"*. c #F0E9CD\",\n\"=. c #F4E7D3\",\n\"-. c #F1E6D9\",\n\";. c #F3EBD3\",\n\":. c #F1E9DA\",\n\">. c #FFE2DF\",\n\",. c #F0F1CF\",\n\"<. c #F2F1DD\",\n\"1. c #F6FCD8\",\n\"2. c #E4EDE4\",\n\"3. c #E9E7EA\",\n\"4. c #EAEBE2\",\n\"5. c #E4F3E3\",\n\"6. c #ECF4E5\",\n\"7. c #E6FAF8\",\n\"8. c #F5ECE2\",\n\"9. c #F6ECEB\",\n\"0. c #FEE5E1\",\n\"q. c #FCE9E4\",\n\"w. c #FBEBEC\",\n\"e. c #F0EEF1\",\n\"r. c #F3F3E3\",\n\"t. c #F6FDF5\",\n\"y. c #FBF4F2\",\n/* pixels */\n\"| .. .o.[ | O.| O.4.+...O.o. ...O.|  .O.O.#.| $.\",\n\"O.o.O.| ) O.-.o...O.;.O./ ;.o.#.o...O.o.2.{ O.X.\",\n\"2.:...:.8.| W :   b @. .#.} #.4.L ; X I O.&. .:.\",\n\"O.O.} o.%.v O o O o O ' O.;.o.& o o + o # 6._ | \",\n\"O.[ 5.$.~   y y t p t ; ] %.t g p t f a O u O.%.\",\n\"O. . .=.7 * p R >.Y e O O.O.o y I q.J f t o r. .\",\n\"| 4.$. .O y u 9.v 9.y o 2.| . j w., ' a w   t.{ \",\n\"[ O.X.8.3 + w Y q.U u o o.o.o t Y q.T y 4 o e.#.\",\n\"o.O.{ O.` O y a u u g ; O.:.j g y t d t O a ;. .\",\n\"O.[  .#.%.S o   +   O 1.2./ 5.4 O o o o ; $.{ 4.\",\n\"O.#.:.| 3.O.Z o o < ! :.6.y.7.y.9 o   l %.%...} \",\n\"O.:.a Q r.;.Y O o o # o 9 5 0 k x l 9 e  .[ 4.) \",\n\"O.o.N O O t 2 o   o o r E h l v c l Y k =.o.O. .\",\n\"O.[ m o o     o O o O y H > r 7 9 6 K x 4.{ | o.\",\n\"o.O.A O   o O 8 r 4 1 % B M B N n V x t O.o.X.o.\",\n\"o.O.B o o o O B C B V o o o O o o o o q 5.2.$.} \",\n\"o.O.@ @.$. .z o @ O - o o   O o o o   9 O.O.@.O.\",\n\"o.} O.4.} O.O.r.O.P O   O o   o o F 8.r. .o.@.} \",\n\"O.o.} o. ...O.O. .O.^ G D G G D D o.O.;.{ o.o.O.\",\n\"@.O.o. .o.o.o.| o...@.o.o.o.| o.| O.O. .4.o.o.4.\",\n\"@.O.o. .O.o.o.@. .O.o.o.o.| | o. .o.O. .4...@.4.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/cascade.xpm",
    "content": "/* XPM */\nconst static char *cascade[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 202 2\",\n\"   c #000100\",\n\".  c #020300\",\n\"X  c #030301\",\n\"o  c gray1\",\n\"O  c #050503\",\n\"+  c #060606\",\n\"@  c #070707\",\n\"#  c #090A02\",\n\"$  c #0D0E06\",\n\"%  c gray3\",\n\"&  c #08080A\",\n\"*  c #0B0B09\",\n\"=  c gray4\",\n\"-  c #0B0B0B\",\n\";  c #0C0C0A\",\n\":  c #0C0C0C\",\n\">  c gray5\",\n\",  c #0F0F0D\",\n\"<  c gray6\",\n\"1  c #0E0E10\",\n\"2  c #0F1103\",\n\"3  c #0F100B\",\n\"4  c #101207\",\n\"5  c #10100E\",\n\"6  c #11110F\",\n\"7  c #12130D\",\n\"8  c #12130E\",\n\"9  c #14150D\",\n\"0  c #101010\",\n\"q  c #111111\",\n\"w  c #131311\",\n\"e  c gray7\",\n\"r  c #131313\",\n\"t  c #131315\",\n\"y  c #141510\",\n\"u  c #151513\",\n\"i  c #151610\",\n\"p  c #151611\",\n\"a  c #161711\",\n\"s  c #161712\",\n\"d  c gray8\",\n\"f  c #161614\",\n\"g  c gray9\",\n\"h  c #181914\",\n\"j  c #191A15\",\n\"k  c #1A1A18\",\n\"l  c #1D1D1B\",\n\"z  c #1D1D1D\",\n\"x  c #1D1D1F\",\n\"c  c #1E1E1E\",\n\"v  c #1D1C21\",\n\"b  c #20201E\",\n\"n  c #212123\",\n\"m  c #232323\",\n\"M  c #242520\",\n\"N  c #252525\",\n\"B  c #252527\",\n\"V  c #272727\",\n\"C  c #242328\",\n\"Z  c gray16\",\n\"A  c #2A2A2A\",\n\"S  c #2C2C2E\",\n\"D  c #302F34\",\n\"F  c gray21\",\n\"G  c #70706E\",\n\"H  c #71716F\",\n\"J  c #73746F\",\n\"K  c gray44\",\n\"L  c #717171\",\n\"P  c #717173\",\n\"I  c #727270\",\n\"U  c #737371\",\n\"Y  c #727272\",\n\"T  c gray45\",\n\"R  c #727177\",\n\"E  c #727274\",\n\"W  c #737375\",\n\"Q  c #737277\",\n\"!  c #747472\",\n\"~  c #747474\",\n\"^  c gray46\",\n\"/  c #747476\",\n\"(  c #767676\",\n\")  c #747378\",\n\"_  c gray48\",\n\"`  c #A5A6A1\",\n\"'  c gray65\",\n\"]  c #A7A7A7\",\n\"[  c #A6A6A8\",\n\"{  c #A9A9A7\",\n\"}  c #A9AAA5\",\n\"|  c #AAABA6\",\n\" . c #ABACA7\",\n\".. c gray66\",\n\"X. c #A9A9A9\",\n\"o. c #A9A9AB\",\n\"O. c #AAAAA8\",\n\"+. c #ABABA9\",\n\"@. c #AAAAAA\",\n\"#. c gray67\",\n\"$. c #AAA9AF\",\n\"%. c #AAAAAC\",\n\"&. c #ABABAD\",\n\"*. c #ACADA8\",\n\"=. c #ACACAA\",\n\"-. c #ADADAB\",\n\";. c #ADAEA9\",\n\":. c #ACACAC\",\n\">. c gray68\",\n\",. c #ADADAF\",\n\"<. c #AEAEAE\",\n\"1. c #AFAFAF\",\n\"2. c #AAA9B1\",\n\"3. c #AEAEB0\",\n\"4. c #B0B1AC\",\n\"5. c #B0B0B2\",\n\"6. c #DCDDD7\",\n\"7. c gray85\",\n\"8. c #DADADC\",\n\"9. c #DCDCDA\",\n\"0. c #DDDED9\",\n\"q. c #DCDCDE\",\n\"w. c #DDDDDF\",\n\"e. c #DEDEDC\",\n\"r. c gray87\",\n\"t. c #DFDFDF\",\n\"y. c #DBDAE0\",\n\"u. c #DEDEE0\",\n\"i. c #DFDFE1\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n\"z. c none\",\n\"x. c none\",\n\"c. c none\",\n\"v. c none\",\n\"b. c none\",\n\"n. c none\",\n\"m. c none\",\n\"M. c none\",\n\"N. c none\",\n\"B. c none\",\n\"V. c none\",\n\"C. c none\",\n\"Z. c none\",\n\"A. c none\",\n\"S. c none\",\n\"D. c none\",\n\"F. c none\",\n\"G. c none\",\n\"H. c none\",\n\"J. c none\",\n\"K. c none\",\n\"L. c none\",\n\"P. c none\",\n\"I. c none\",\n\"U. c none\",\n\"Y. c none\",\n\"T. c none\",\n\"R. c none\",\n\"E. c none\",\n\"W. c none\",\n\"Q. c none\",\n\"!. c none\",\n\"~. c none\",\n\"^. c none\",\n\"/. c none\",\n\"(. c none\",\n\"). c none\",\n\"_. c none\",\n\"`. c none\",\n\"'. c none\",\n\"]. c none\",\n\"[. c none\",\n\"{. c none\",\n\"}. c none\",\n\"|. c none\",\n\" X c none\",\n\".X c none\",\n\"XX c none\",\n\"oX c none\",\n\"OX c none\",\n\"+X c none\",\n\"@X c none\",\n\"#X c none\",\n\"$X c none\",\n\"%X c none\",\n\"&X c none\",\n\"*X c none\",\n\"=X c none\",\n\"-X c none\",\n\";X c none\",\n\":X c none\",\n\">X c none\",\n\",X c none\",\n/* pixels */\n\"/.x.K.x.K./.s.K./.N.N.K.H.H.:Xj.H.K.N.Z.N.c./.Z.\",\n\"Z.N././.E.&X].E.&Xj.].E.].H.N.K.E.N.K.].].c.K.:X\",\n\"].;XN.W.  = a a a l j 8 $ 2 s.P.].N.K.H.H.K.N.j.\",\n\"].N.].E.a q.u.w.i.7.u.%Xw.$ E.K.&XN./.].Z./.K.Z.\",\n\"N.K.N.Z.j u.8.%X0.e.@Xq.$X= 6.&Xh. Xs./.E./.a.].\",\n\"N.K. Xd.a u.B A b b C v C x x 0   N.K.s.:XZ. Xx.\",\n\"/.K.s.,Xa t.S T ( ( G _ T H / P g N.K./.E.].N.M.\",\n\"Z././.j., i.D T / / T H G T T T = ].x./.j.E./.N.\",\n\"N./.H.H.s @XV H 0 @ = 0 o = @ : t a q O /./.Z./.\",\n\"/.N.H.H.3 %XF G @ X.1.@.<.' 1.#.,.O.[ r N.N.].K.\",\n\"N./.].:X9 e.n / @ @.#.X.#.#.#.#.o.| -.: /./.].N.\",\n\"/.N.H.j.9 q.Z / g #.@.#.#.#.X.#.#.4.[ , Z.M.]./.\",\n\"/.b.E.].4 a m Q : #.#.#.@.#.#.<.-.| 3.: N.N.j.K.\",\n\"H./.H.H.E.:Xa / x @.#.X.X.<.X.#.5.` -.3 ]./.].K.\",\n\"x. Xj.H.H.E.8 / : @.#.#.1.X.@.#.[ +.#., N.K.W./.\",\n\"P.s.E.].H.H.  & b #.#.@.@.X.<.#.#.+.O.= /.N.j.K.\",\n\"K.H.H.E./.H.H.H.1 o.,.o.o.o.,.o.+.+.| # H./.N.N.\",\n\"H.H.H.H.H.H.H.H., +.O.-.-.O.-.O.2.2.2.8 W.H./.K.\",\n\"H.H.H./.H./.H.H.+ & e = e g r 0 t e +   Z./.N.N.\",\n\"H.H.H.E.H.E.H.H.Z././.Z.H.]./.H.K./.].Z./.x.].H.\",\n\"H.H.H.H.H.E.K.H.N././.Z.Z.].].Z./.Z.H././.s./.E.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/cube.xpm",
    "content": "/* XPM */\nconst static char *cube[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 121 2\",\n\"   c black\",\n\".  c black\",\n\"X  c black\",\n\"o  c black\",\n\"O  c black\",\n\"+  c black\",\n\"@  c black\",\n\"#  c black\",\n\"$  c black\",\n\"%  c black\",\n\"&  c black\",\n\"*  c black\",\n\"=  c black\",\n\"-  c black\",\n\";  c black\",\n\":  c black\",\n\">  c black\",\n\",  c black\",\n\"<  c black\",\n\"1  c black\",\n\"2  c black\",\n\"3  c black\",\n\"4  c black\",\n\"5  c black\",\n\"6  c black\",\n\"7  c black\",\n\"8  c black\",\n\"9  c black\",\n\"0  c black\",\n\"q  c black\",\n\"w  c black\",\n\"e  c black\",\n\"r  c black\",\n\"t  c black\",\n\"y  c black\",\n\"u  c black\",\n\"i  c black\",\n\"p  c black\",\n\"a  c black\",\n\"s  c black\",\n\"d  c black\",\n\"f  c black\",\n\"g  c black\",\n\"h  c black\",\n\"j  c black\",\n\"k  c black\",\n\"l  c black\",\n\"z  c black\",\n\"x  c black\",\n\"c  c black\",\n\"v  c black\",\n\"b  c black\",\n\"n  c black\",\n\"m  c black\",\n\"M  c black\",\n\"N  c black\",\n\"B  c black\",\n\"V  c black\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n/* pixels */\n\") I +.+.I +.) L I 5.I +.+.T 4.I +.T ) ) L ) I { \",\n\"I 4.I +.+.+.I +.{ W +.+.+.{ +.{ +.{ +.) L ) 5.W \",\n\"{ ~ ) A +.+.| 6.5.) L ) ) ) I #.*.{ { W 5.+.I +.\",\n\"~ +.K 5.) W 9.5 V t w q b n q % + g . +.I I +.) \",\n\"*.+.+.K ~ {   x *.{ W { { { *.| 0.+ o { I 5.) +.\",\n\"{ ~ +.~ { : - 5 5 2 e - 2 5 2 5 5 6.$ +.~ K T ) \",\n\"{ +.I { | z | | +.+.I W +.+.{ +.$ *.g 4.W +.) ) \",\n\"+.+.:.| | , { *.+.I +.+.I +.I #.- ! ; W +.R +.+.\",\n\"T [ W +.>.a #.W ~ +.{ +.+.+.~ { 1 4.1 #.I +.[ T \",\n\"T +.+.+.) a +.I +.~ { ~ +.~ +.{ 4 T 4 W ) I 4.) \",\n\"I { =.+.J r I +.~ +.+.+.{ { +.+.5 I e W 5.+.W T \",\n\") =.{ +.L u I +.{ { +.~ +.~ +.~ 5 ) x +.Z 5.+.T \",\n\"+.) I +.>.a 5.+.~ +.{ { +.+.~ { 2 +.4 +.+.Z { T \",\n\") +.W +.) i I ) +.+.+.~ +.~ +.{ 4 #.1 +.) 5.{ #.\",\n\"I +.{ =.K 4 I +.~ { ~ +.{ { +.+.1 ) p S 5.Z [ T \",\n\"+.+.[ +.) i ) { +.{ +.+.+.~ +.~ 4 B e +.) I =.) \",\n\") +.+.W 3.l ! { +.W [ { { { +.[ 1 X ! +.L #.T +.\",\n\"J >.K #.W k N 5 # h N + q n 5 h b *.! 4.+.I +.+.\",\n\"W { W +.+.+.I ) +.+.I +.4.+.{ +.{ [ #.S =.I +.+.\",\n\") >.) +.I +.=.{ ) ) +.T I +.) +.) ) +.+.{ { I +.\",\n\") ) I +.[ +.+.+.) T +.) T ) ) ) L T ) +.{ =.+.+.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/eye.xpm",
    "content": "/* XPM */\nconst static char *eye[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 73 1\",\n\"  c #060606\",\n\". c #0C0C0C\",\n\"X c #131313\",\n\"o c #1B1B1B\",\n\"O c gray14\",\n\"+ c #2D2D2D\",\n\"@ c #343530\",\n\"# c #3C3C3C\",\n\"$ c #444444\",\n\"% c #4B4B4C\",\n\"& c #4F4E53\",\n\"* c #51514F\",\n\"= c #535351\",\n\"- c #585954\",\n\"; c #5B5B5B\",\n\": c #60605E\",\n\"> c #626163\",\n\", c #6A6B66\",\n\"< c #6B6B6B\",\n\"1 c #727271\",\n\"2 c #747378\",\n\"3 c #7C7C7C\",\n\"4 c #7F7F81\",\n\"5 c #807F84\",\n\"6 c #838483\",\n\"7 c #858489\",\n\"8 c #898987\",\n\"9 c #8B8B8B\",\n\"0 c #8E8E90\",\n\"q c #91928C\",\n\"w c #939494\",\n\"e c #969699\",\n\"r c #9B9B9B\",\n\"t c #A0A09E\",\n\"y c #A3A3A3\",\n\"u c #A7A7A9\",\n\"i c #A8A8A6\",\n\"p c #ACACAB\",\n\"a c #AEADB2\",\n\"s c #B0B0AE\",\n\"d c #B4B4B4\",\n\"f c #B6B6B8\",\n\"g c #B8B9B5\",\n\"h c #BBBBBB\",\n\"j c #C3C4BF\",\n\"k c #C4C4C4\",\n\"l c #C6C6C8\",\n\"z c #CBCCC7\",\n\"x c #CBCBCB\",\n\"c c #CCCBD0\",\n\"v c #D0D1CD\",\n\"b c #D3D3D3\",\n\"n c #D5D4D9\",\n\"m c #D9DAD6\",\n\"M c #DCDCDB\",\n\"N c #DFDFE1\",\n\"B c none\",\n\"V c none\",\n\"C c none\",\n\"Z c none\",\n\"A c none\",\n\"S c none\",\n\"D c none\",\n\"F c none\",\n\"G c none\",\n\"H c none\",\n\"J c none\",\n\"K c none\",\n\"L c none\",\n\"P c none\",\n\"I c #F2F4E7\",\n\"U c #F0F1E9\",\n\"Y c #F1F1F1\",\n/* pixels */\n\"AAAAASSLKKKKKKYGKSASAAAS\",\n\"SSAASSJKKGVMMMNGHPJSAACS\",\n\"AZASLKJGFMblhhhkbNJSSSSS\",\n\"SAAJJKGGKGFbhutyajbJSSSA\",\n\"ASJKKKGKYYYGbhy90tgJCICS\",\n\"CJKKGFFGYYYKNxpw68rjSSSS\",\n\"SJJGFNMmbnlfie96430iNZUS\",\n\"SJJFnkuq3<%@$%$%;<3rhMJJ\",\n\"KVbge6<&#O#%oo$$*;19anKJ\",\n\"Kmp3,-#&:X6rX #1=*,9pcVI\",\n\"Kz7>*@*i1XXX .+w8::4ycNK\",\n\"Gg2>:;9h-XX.Xo+9t415elFJ\",\n\"Kj94tsis>ooooO$ee88rplHS\",\n\"Lmkapjvlp<+oo@<rurrflnJJ\",\n\"JHMxdukMYVfw79phlkjkbGUS\",\n\"SSGbhyrdkcFVxhhhgpphbGJJ\",\n\"ASJSbguutrreweewerpBSAAA\",\n\"AASJFbhiteew999wrgxSSASA\",\n\"SACSIJVvhpyttishlMSACAAS\",\n\"SASACSJJSVmvvbnVJJJZSACA\",\n\"SSASCSJSJHKGKKHKJJSCSASS\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/fileopen.xpm",
    "content": "/* XPM */\nstatic const char *fileopen[] = {\n/* columns rows colors chars-per-pixel */\n\"24 23 50 1\",\n\"  c black\",\n\". c #000400\",\n\"X c gray3\",\n\"o c #080C08\",\n\"O c #101410\",\n\"+ c #181C18\",\n\"@ c #313000\",\n\"# c #313400\",\n\"$ c #393800\",\n\"% c #393C00\",\n\"& c #212021\",\n\"* c #212421\",\n\"= c #292829\",\n\"- c #292C29\",\n\"; c #313431\",\n\": c #393C39\",\n\"> c #424100\",\n\", c #424500\",\n\"< c #4A4900\",\n\"1 c #4A4D00\",\n\"2 c #525100\",\n\"3 c #525500\",\n\"4 c #5A5D00\",\n\"5 c #636100\",\n\"6 c #636500\",\n\"7 c #6B6900\",\n\"8 c #6B6D00\",\n\"9 c #737100\",\n\"0 c #737500\",\n\"q c #7B7900\",\n\"w c #424142\",\n\"e c #424542\",\n\"r c gray38\",\n\"t c #C6C342\",\n\"y c #D6D74A\",\n\"u c #E7E74A\",\n\"i c #E7E752\",\n\"p c #C6C763\",\n\"a c #D6D36B\",\n\"s c #EFEB73\",\n\"d c #F7F37B\",\n\"f c #F7F77B\",\n\"g c #F7F784\",\n\"h c #F7F78C\",\n\"j c #F7F794\",\n\"k c #F7F79C\",\n\"l c #D6D3CE\",\n\"z c #E6E4E1\",\n\"x c #EFEEEC\",\n\"c c #F5F5F3\",\n/* pixels */\n\"xzzzzzzzzzzzzzzzzzzzzzzx\",\n\"zllllllllllllllllllllllz\",\n\"zllllllllllllllO. lllllz\",\n\"zlllllllllllll  l  llllz\",\n\"zllllllllllll  lll  ll z\",\n\"zllllllllllllllllllll  z\",\n\"zlll:*Xlllllllllllll   z\",\n\"zllekhg lllllllllll    z\",\n\"zlwkjgf XO&**+X lllllllz\",\n\"zl;jhgffgghhhgfa llllllz\",\n\"zl-hggfffgggggsp llllllz\",\n\"zl=hgffiiiiiiuyt llllllz\",\n\"zl=hgffuu         .o   r\",\n\"zl=hgfuu qqqqq00000841 z\",\n\"zl=hgfu qqqqqqq00962> lz\",\n\"zl*hgi qqqqqqqq0851$ llz\",\n\"zl+gi 00000000974<# lllz\",\n\"zlod 66666666653,# llllz\",\n\"zl  31<<<<<<<<,%@ lllllz\",\n\"zll              llllllz\",\n\"zllllllllllllllllllllllz\",\n\"zllllllllllllllllllllllz\",\n\"cxxxxxxxxxxxxxxxxxxxxxxc\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/forward.xpm",
    "content": "/* XPM */\r\n/* Drawn  by Mark Donohoe for the K Desktop Environment */\r\n/* See http://www.kde.org */\r\nconst static char*forward[]={\r\n\"16 16 5 1\",\r\n\"# c #000000\",\r\n\"a c #ffffff\",\r\n\"c c #808080\",\r\n\"b c #c0c0c0\",\r\n\". c None\",\r\n\"................\",\r\n\"................\",\r\n\".........#......\",\r\n\".........##.....\",\r\n\".........#a#....\",\r\n\"..########aa#...\",\r\n\"..#aaaaaaabaa#..\",\r\n\"..#bbbbbbbbbaa#.\",\r\n\"..#bbbbbbbbba#..\",\r\n\"..########ba#c..\",\r\n\"..ccccccc#a#c...\",\r\n\"........c##c....\",\r\n\"........c#c.....\",\r\n\"........cc......\",\r\n\"........c.......\",\r\n\"................\",\r\n\"................\"};\r\n\r\n"
  },
  {
    "path": "apps/vaporgui/images/home.xpm",
    "content": "/* XPM */\nconst static char *home[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 163 2\",\n\"   c black\",\n\".  c #000100\",\n\"X  c #010100\",\n\"o  c #010101\",\n\"O  c #000002\",\n\"+  c #000200\",\n\"@  c #010200\",\n\"#  c #010300\",\n\"$  c #020300\",\n\"%  c #000004\",\n\"&  c #020106\",\n\"*  c #030207\",\n\"=  c #030400\",\n\"-  c #050601\",\n\";  c #6B6A70\",\n\":  c #92938B\",\n\">  c #92938D\",\n\",  c #96978F\",\n\"<  c #96988D\",\n\"1  c #989A8F\",\n\"2  c #9A9C8E\",\n\"3  c #939393\",\n\"4  c #959690\",\n\"5  c #969791\",\n\"6  c #969792\",\n\"7  c #959595\",\n\"8  c #959597\",\n\"9  c #969694\",\n\"0  c #979795\",\n\"q  c #949399\",\n\"w  c #97969C\",\n\"e  c #979892\",\n\"r  c #979893\",\n\"t  c #989896\",\n\"y  c #9A9B96\",\n\"u  c #9B9C96\",\n\"i  c #989898\",\n\"p  c gray\",\n\"a  c #BEBEC0\",\n\"s  c #C0C1B9\",\n\"d  c #C1C1BF\",\n\"f  c #C4C6B8\",\n\"g  c #C1C1C1\",\n\"h  c #C2C2C0\",\n\"j  c #C3C3C3\",\n\"k  c #C2C2C4\",\n\"l  c #C5C5C5\",\n\"z  c #C7C7C5\",\n\"x  c none\",\n\"c  c none\",\n\"v  c none\",\n\"b  c none\",\n\"n  c none\",\n\"m  c none\",\n\"M  c none\",\n\"N  c none\",\n\"B  c none\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c #F0EFF4\",\n\"h. c #F0F3E2\",\n\"j. c #F3F6E3\",\n\"k. c #F0F1EB\",\n\"l. c #F1F1EF\",\n\"z. c #F1F2ED\",\n\"x. c #F2F3EE\",\n\"c. c #F3F4EF\",\n\"v. c #F0F0F2\",\n\"b. c #F1F1F3\",\n\"n. c #F3F3F3\",\n\"m. c #F2F1F6\",\n\"M. c #F3F3F5\",\n\"N. c #F4F4F2\",\n\"B. c #F4F4F4\",\n\"V. c #F4F4F6\",\n\"C. c #F4F3F8\",\n\"Z. c #F6F6F8\",\n\"A. c #FBFBFB\",\n\"S. c #FCFBFF\",\n\"D. c #FCFCFA\",\n\"F. c #FDFDFB\",\n\"G. c #FDFEF9\",\n\"H. c #FFFFF8\",\n\"J. c #FFFFFB\",\n\"K. c #FEFEFC\",\n\"L. c #FFFFFD\",\n\"P. c #FFFEFF\",\n\"I. c gray100\",\n/* pixels */\n\"+.G E *.G +.D ~ &.~ ~ ) ~ >.D ! E D D D ~ _ G +.\",\n\"G *.~ E D +.G +.E +.,.G +.G +.I } *.S ~ +.&.+.,.\",\n\"E ~ c ~ +.~ E G G ~ B &.~ :.:.V t._ +.+.G +.+.G \",\n\"+.E ~ +.+.G +.&.x y.y.< # ~ n y 7 # _ _ I I +.~ \",\n\"D G *.E G +.+.G +._ q l.&.# &.8 4.- } +.+.+.G ! \",\n\"+.+.+.G +.I I &._ t l.# # T # 4 9.# %.I ~  .~ ~ \",\n\"D E G +._ I h.v 4 l.* p z # T # 9.# } D ! +.G +.\",\n\"~ ~ E +._ &.v 2 n.# d P.S.g # } # # I +.+.G +.~ \",\n\"G ~ D +._ T t m.# k P.G.c.n.p * t.# t.~ &.I ~ ~ \",\n\"+.+.G E &.< n.# l A.P.V.n.n.4.g # a.# ~ +.G <.G \",\n\"+.G +.D &., # k S.P.V.f.C.4.d.m f # # D I &.~ G \",\n\"+.~ D ~ _ } < P.P.n.3 7 i # 4.6.I # y.) +.+.D +.\",\n\"+.c +.G E } 4 P.P.d.u G.e.# w.9.+.# T D +.I :.G \",\n\"+.c ~ ,.~ t.4 P.C.a.: t.s # 6.9.I # %.~ +.I D +.\",\n\"b j.D G E %.: G.B m 6 g 7 # B } &.# &.S +.I +.G \",\n\"&.c +.~ &.&.4 u._ } 7 w ; # } _ G # I ) c +.D +.\",\n\"+.G :.! +.I # # # # # # # # # # # # I ~ D ) E &.\",\n\"I &.G :.G &.} } !  .I _ E I I G } } &.E +.G +.+.\",\n\"G :.G G +.+.G &. . . . ._ +._ +._ G +.+.+.G ~ G \",\n\") G &.+.G ~ ! ! ! ) ! ! +.~ ~ ~ E E _ _ +.+.G ~ \",\n\"~ G +.+.I ~ ~ W ~ Q ! ) ~ ) ~ ~ W ~ ~ I +.+.D ! \"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/home2.xpm",
    "content": "/* XPM */\r\n/* Drawn  by Mark Donohoe for the K Desktop Environment */\r\n/* See http://www.kde.org */\r\nconst static char*home2[]={\r\n\"16 16 4 1\",\r\n\"# c #000000\",\r\n\"a c #ffffff\",\r\n\"b c #c0c0c0\",\r\n\". c None\",\r\n\"........... ....\",\r\n\"   ....##.......\",\r\n\"..#...####......\",\r\n\"..#..#aabb#.....\",\r\n\"..#.#aaaabb#....\",\r\n\"..##aaaaaabb#...\",\r\n\"..#aaaaaaaabb#..\",\r\n\".#aaaaaaaaabbb#.\",\r\n\"###aaaaaaaabb###\",\r\n\"..#aaaaaaaabb#..\",\r\n\"..#aaa###aabb#..\",\r\n\"..#aaa#.#aabb#..\",\r\n\"..#aaa#.#aabb#..\",\r\n\"..#aaa#.#aabb#..\",\r\n\"..#aaa#.#aabb#..\",\r\n\"..#####.######..\",\r\n\"................\"};\r\n\r\n"
  },
  {
    "path": "apps/vaporgui/images/isoline.xpm",
    "content": "/* XPM */\nstatic const char *isoline[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 20 1 \",\n\"  c black\",\n\". c #E4E8CF\",\n\"X c #E3E6D1\",\n\"o c #E5E8D5\",\n\"O c #E7EBD4\",\n\"+ c #E7EAD5\",\n\"@ c #E9EDD4\",\n\"# c #E4E6D8\",\n\"$ c #E6E8DA\",\n\"% c #E8EBDA\",\n\"& c #E9ECD9\",\n\"* c #E9ECDB\",\n\"= c #ECEFDA\",\n\"- c #E8EADC\",\n\"; c #EAECDE\",\n\": c #ECEFDC\",\n\"> c #ECF0D9\",\n\", c #EEF1DE\",\n\"< c #EFF2DF\",\n\"1 c #E5E6E0\",\n/* pixels */\n\"&&&&&&&&@@&&&:&&%&.>+*&&\",\n\"&&&&&&&&&&&&&&--*+@@&*%+\",\n\"&&&&&&         >-:+@&#+@\",\n\"&&&&&  &&&&&&&   &&@&%<+\",\n\"&&&&  &&&&&&&&&&&  &+,o,\",\n\"&&&& &&&&&&&&&&&&&   %:+\",\n\"&&&  &&&&&&&&&&&&&&&  &@\",\n\"&&& &&&&&     &&&&&&&  +\",\n\"&&  &&&&  &&&   &&&&&&  \",\n\",& &&&&& &&&&&&   &&X&@:\",\n\"&* +&&&  &&&&&&&&  %&&&&\",\n\"%+ &&&& &&&&&&&&&& +&&:&\",\n\"%% &&&&  &&&&&&&&  :&%+&\",\n\"+% ,&&&&  &&&&&&& &&@%<&\",\n\"&&  &&&&&         %@%,@+\",\n\"&&&  &&&&&&#&&%&&+&%%+&&\",\n\"&&&@   &&1&&@&+&&&&&&&  \",\n\"&+&%%%   &&&&&>@&&&    &\",\n\"&&&+&%&&   &&&&&    &&&&\",\n\"@@%:*:+&&+       &&&&&&&\",\n\"@+&:%&+&*+%%-**@&&&&&&&&\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/lightbulb.xpm",
    "content": "/* XPM */\nconst static char *lightbulb[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 137 2\",\n\"   c #000100\",\n\".  c #010200\",\n\"X  c #020200\",\n\"o  c #020300\",\n\"O  c #030301\",\n\"+  c #030305\",\n\"@  c #030400\",\n\"#  c #040500\",\n\"$  c #040402\",\n\"%  c #040600\",\n\"&  c #050600\",\n\"*  c #050601\",\n\"=  c #060700\",\n\"-  c #060701\",\n\";  c #060702\",\n\":  c #040406\",\n\">  c #070707\",\n\",  c #050409\",\n\"<  c #070709\",\n\"1  c #070800\",\n\"2  c #08070C\",\n\"3  c #080903\",\n\"4  c #090B00\",\n\"5  c #0A0B03\",\n\"6  c #090A05\",\n\"7  c #0A0B06\",\n\"8  c gray3\",\n\"9  c #0B0B09\",\n\"0  c #0B0B0B\",\n\"q  c #0D0E08\",\n\"w  c #0C0C0C\",\n\"e  c #0F0F0D\",\n\"r  c #0F100B\",\n\"t  c #101109\",\n\"y  c #10110B\",\n\"u  c #11110F\",\n\"i  c #13140C\",\n\"p  c #121210\",\n\"a  c gray7\",\n\"s  c #141510\",\n\"d  c #161712\",\n\"f  c #151515\",\n\"g  c #161616\",\n\"h  c #21221C\",\n\"j  c #21221D\",\n\"k  c #2D2E28\",\n\"l  c #2F302B\",\n\"z  c #DDDCE2\",\n\"x  c #E2E5D2\",\n\"c  c #E3E7D0\",\n\"v  c #E2E5D4\",\n\"b  c #E3E5D7\",\n\"n  c #E4E7D4\",\n\"m  c #E4E6D8\",\n\"M  c #E4E8D1\",\n\"N  c #E5E8D3\",\n\"B  c #E6EAD1\",\n\"V  c #E6EAD3\",\n\"C  c #E5E8D5\",\n\"Z  c #E5E8D7\",\n\"A  c #E6E9D4\",\n\"S  c #E6E9D6\",\n\"D  c #E7EAD5\",\n\"F  c #E7EBD4\",\n\"G  c #E7EAD7\",\n\"H  c #E6E9D8\",\n\"J  c #E6E8DA\",\n\"K  c #E7E9DB\",\n\"L  c #E7EAD9\",\n\"P  c #E7E9DC\",\n\"I  c #E7E9DE\",\n\"U  c #E8EBD6\",\n\"Y  c #E8ECD3\",\n\"T  c #E8ECD5\",\n\"R  c #E9ECD7\",\n\"E  c #E9EDD6\",\n\"W  c #EAEED7\",\n\"Q  c #E8EBD8\",\n\"!  c #E8EBDA\",\n\"~  c #E8EADC\",\n\"^  c #E8EADD\",\n\"/  c #E9EBDD\",\n\"(  c #E9EBDE\",\n\")  c #E9ECD9\",\n\"_  c #E9ECDB\",\n\"`  c #EAEDD8\",\n\"'  c #EAEDDA\",\n\"]  c #EBEED9\",\n\"[  c #EBEFD8\",\n\"{  c #EBEEDB\",\n\"}  c #EAEDDC\",\n\"|  c #EAECDE\",\n\" . c #EAECDF\",\n\".. c #EBEEDD\",\n\"X. c #ECEFDA\",\n\"o. c #ECEFDC\",\n\"O. c #ECEFDE\",\n\"+. c #ECF0D7\",\n\"@. c #ECF0D9\",\n\"#. c #EDF0DB\",\n\"$. c #EDF1DA\",\n\"%. c #EDF0DD\",\n\"&. c #EEF1DC\",\n\"*. c #EEF1DE\",\n\"=. c #E1E0E5\",\n\"-. c #E1E0E6\",\n\";. c #E5E4E9\",\n\":. c #E8E9E1\",\n\">. c #EBEDE2\",\n\",. c #EBECE4\",\n\"<. c #ECEEE0\",\n\"1. c #EDEFE1\",\n\"2. c #EDEEE6\",\n\"3. c #F0F3E0\",\n\"4. c #F1F1F1\",\n\"5. c #F3F3F3\",\n\"6. c #F4F4F6\",\n\"7. c #F6F6F8\",\n\"8. c #F7F6FC\",\n\"9. c #FBFBF9\",\n\"0. c gray98\",\n\"q. c #FBFBFD\",\n\"w. c #FBFAFF\",\n\"e. c #FDFEF9\",\n\"r. c #FFFFFB\",\n\"t. c gray99\",\n\"y. c #FDFDFD\",\n\"u. c #FCFCFE\",\n\"i. c #FDFCFF\",\n\"p. c #FDFDFF\",\n\"a. c #FEFDFF\",\n\"s. c #FEFEFC\",\n\"d. c #FFFFFD\",\n\"f. c #FEFEFE\",\n\"g. c #FEFEFF\",\n\"h. c #FFFEFF\",\n\"j. c gray100\",\n/* pixels */\n\"U ` D ! ! L ` ` ! L ` ` D D ! ! ` X.D ! ! ` ` ` \",\n\"` D ` ! ` ` R D R o.X.D ` ` ` R [ n *.` ` ! +.U \",\n\"! D ` X.F ` D ` R ! ! <.P L ! U R R n U ` ` x ..\",\n\"! ` D U Y R R R ! ! 1 j ; i ! ! R U U +.D ` ` ! \",\n\"` ` R +.n W o.L o q g g.g.a j o ! ` o.n U U X.! \",\n\"` ! R n +.` P % 9 g.g.g.8.g.g.e 5 m ` U X.U D ` \",\n\"D D ` R ! b ,.q g.g.g.g.g.g.q.g.k 2.P ` X.n U ! \",\n\"! ` n X.L <.; e g.g.r.r.r.9.g.g.# ; P ! D +.U ` \",\n\"X.U X.n X.P 6 g.r.9.g.g.g.g.r.r.g.6 ! ` ! U ! U \",\n\"U o.v o.U P q q.r.g.g.g.0.g.g.0.q.o 1.D ` ` X.U \",\n\"U U ` U U ..; g g.g.g.g.g.g.g.g.a ; ! D X.U D R \",\n\"X.! X.! U ! >.o g.g.g.r.r.g.g.g.; P ..D ! ..! ! \",\n\"U U ! U +.U P o < g.g.g.g.r.g.+ % P D +.! D X.U \",\n\"n o.! ..Y R ` 1.a o 8 w 9 > o u 1.U X.c ..P X.! \",\n\"X.D ! X.R B o.v :.3 5.7.5.5.i ,.! U [ U U ..U U \",\n\"X.U ! ! +.Y U ! ! 5 o 2 , o i I X.R Y X.` ! ` ! \",\n\"! ! ! ` ! ` ! ` P # ;.z -.-.i P X.! ! ` ! ` ! ` \",\n\"! ! ` ! ` ! ` ! R l + d o 8 o ! ` ! ` ! ` ! ` ! \",\n\"R ` ! ` ! ` ! ` P X.D ; ; ! B ..! ` ! ` ! ` ! ` \",\n\"` ! ` ! ` ! ` ! U R ` P ! ! +.U ` ! ` ! ` ! ` ! \",\n\"` ! ` ! ! ` ! ` U R R ..! U X.U ` ! ` ! ! ` ! ` \"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/magnify.xpm",
    "content": "/* XPM */\nconst static char *magnify[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 165 2\",\n\"   c black\",\n\".  c #000100\",\n\"X  c #010103\",\n\"o  c #020200\",\n\"O  c #010005\",\n\"+  c #020106\",\n\"@  c #0C0D07\",\n\"#  c #0E0E0E\",\n\"$  c #0C0B10\",\n\"%  c #0F1008\",\n\"&  c #13140C\",\n\"*  c #1A1B13\",\n\"=  c #33342F\",\n\"-  c #353439\",\n\";  c #38373D\",\n\":  c #3C3D37\",\n\">  c #3D3E36\",\n\",  c #3C3D38\",\n\"<  c #3D3D3B\",\n\"1  c #3E3F39\",\n\"2  c #3D3C41\",\n\"3  c #565752\",\n\"4  c #595A54\",\n\"5  c #5B5C57\",\n\"6  c #676862\",\n\"7  c #6A6B63\",\n\"8  c #696A65\",\n\"9  c #6A6B65\",\n\"0  c gray46\",\n\"q  c #747476\",\n\"w  c #7E7F77\",\n\"e  c #78787A\",\n\"r  c #7C7D78\",\n\"t  c #7E8073\",\n\"y  c #808179\",\n\"u  c #81817F\",\n\"i  c #838383\",\n\"p  c #8D8F82\",\n\"a  c #898989\",\n\"s  c #8A8A88\",\n\"d  c #8A8A8C\",\n\"f  c #8B8B8D\",\n\"g  c #989A8F\",\n\"h  c #9B9E8D\",\n\"j  c #9A9B93\",\n\"k  c #989896\",\n\"l  c #999997\",\n\"z  c #9C9E91\",\n\"x  c #9D9E99\",\n\"c  c #AAABA3\",\n\"v  c #ABABA9\",\n\"b  c #ABABAD\",\n\"n  c #AEAEB0\",\n\"m  c #B4B6AB\",\n\"M  c #B6B8AD\",\n\"N  c #B1B1B3\",\n\"B  c #B2B2B4\",\n\"V  c #B3B3B5\",\n\"C  c #B6B6B6\",\n\"Z  c #BCBEB1\",\n\"A  c #BABAB8\",\n\"S  c gray73\",\n\"D  c #BABABC\",\n\"F  c #BBBBBD\",\n\"G  c #BFBFBD\",\n\"H  c #C2C2C0\",\n\"J  c gray76\",\n\"K  c #C2C2C4\",\n\"L  c #C3C2C7\",\n\"P  c #C4C4C2\",\n\"I  c #C7C7C9\",\n\"U  c #CECFC7\",\n\"Y  c #CBCBCB\",\n\"T  c #CACACC\",\n\"R  c #CBCBCD\",\n\"E  c gray80\",\n\"W  c #CCCCCE\",\n\"Q  c #CDCDCF\",\n\"!  c #CECED0\",\n\"~  c #CFD0CB\",\n\"^  c #D1D3C6\",\n\"/  c #D0D1C9\",\n\"(  c #D2D3CD\",\n\")  c #DADCCE\",\n\"_  c #D0D0D2\",\n\"`  c #D2D1D6\",\n\"'  c #D5D5D5\",\n\"]  c #D7D7D7\",\n\"[  c #D6D6D8\",\n\"{  c #DDDFD2\",\n\"}  c #D8D8DA\",\n\"|  c #DADADC\",\n\" . c #DCDCDA\",\n\".. c #DDDDDD\",\n\"X. c gray87\",\n\"o. c #DFE1D3\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n\"z. c none\",\n\"x. c none\",\n\"c. c none\",\n\"v. c none\",\n\"b. c none\",\n\"n. c none\",\n\"m. c none\",\n\"M. c none\",\n\"N. c none\",\n\"B. c none\",\n\"V. c none\",\n\"C. c none\",\n\"Z. c none\",\n\"A. c none\",\n\"S. c none\",\n\"D. c none\",\n\"F. c none\",\n\"G. c none\",\n\"H. c none\",\n\"J. c none\",\n\"K. c none\",\n\"L. c none\",\n\"P. c none\",\n\"I. c none\",\n\"U. c none\",\n\"Y. c none\",\n/* pixels */\n\"s.3.k.V.q.k.q.k.V.q.=.V.t.=.k.k.k.k.k.k.k.k.k.k.\",\n\"C.k.3.t.q.k.k.C.3.q.V.3.t.V.3.V.k.k.k.k.k.k.k.k.\",\n\"q.t.k.t.q.3.n.s.I.f.$.n.4.k.k.q.k.k.k.k.k.k.k.k.\",\n\"V.=.t.t.C.s.o.z r 4 6 / 4.s.s.q.k.k.k.k.k.k.k.k.\",\n\"k.t.s.k.#.^ @.U ' ] v 9 r U.k.V.k.k.k.k.k.k.k.k.\",\n\"3.D.3.s.{ J.K. .| T Q C 5 M s.q.k.k.k.k.k.k.k.k.\",\n\"k.3.n.n.g ~ X.[ _ W F F u > C.s.k.k.k.k.k.k.k.k.\",\n\"q.k.n.f.r  .} ` Y T B b k % f.s.k.k.k.k.k.k.k.k.\",\n\"w.t.C.f.3 [ ! Q P A P W d # Y.s.s.q.k.k.3.k.3.q.\",\n\"t.q.k.f.7 v K L A J ..I q = f.t.V.q.3.k.3.C.D.q.\",\n\"k.k.3.s.Z 9 G B b ..B f # c *.O.=.k.t.t.t.3.k.k.\",\n\"n.3.p.t.3.w 4 i l s 0 $ +   I.w.D.t.w.t.t.t.q.3.\",\n\"f.k.k.=.V.f.m > & @ 1 e ; +   f.4.H.3.D.t.t.k.3.\",\n\"4.q.t.V.t.s.s.I.I.f.o./ s -     f.n.k.3.w.k.k.k.\",\n\"k.k.3.q.k.#.C.q.4.H.t.3.J.x <     Y.4.H.t.t.t.k.\",\n\"q.k.k.k.3.H.=.t.n.3.=.A.s.L.j 1     f.4.D.=.k.k.\",\n\"k.k.k.k.k.k.k.k.t.w.q.k.t.k.n.h 2   * n.3.t.t.k.\",\n\"k.k.k.k.k.k.k.k.t.t.t.3.H.4.k.k.x > p n.k.t.3.k.\",\n\"k.k.k.k.k.k.k.k.q.s.H.k.3.k.k.k.f.) k.k.t.t.k.t.\",\n\"k.k.k.k.k.k.k.k.k.k.s.k.t.t.t.k.t.t.k.n.4.k.t.t.\",\n\"k.k.k.k.k.k.k.k.k.k.q.V.t.t.k.k.2.t.k.n.k.k.t.t.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/pauseA.xpm",
    "content": "/* XPM */\nstatic const char *pause_[] = {\n/* columns rows colors chars-per-pixel */\n\"24 17 38 1\",\n\"  c black\",\n\". c #000002\",\n\"X c #010103\",\n\"o c #000004\",\n\"O c #000005\",\n\"+ c #010005\",\n\"@ c #010006\",\n\"# c #000106\",\n\"$ c #000008\",\n\"% c #010008\",\n\"& c #02000D\",\n\"* c #00000E\",\n\"= c none\",\n\"- c none\",\n\"; c none\",\n\": c none\",\n\"> c none\",\n\", c none\",\n\"< c none\",\n\"1 c none\",\n\"2 c none\",\n\"3 c none\",\n\"4 c none\",\n\"5 c none\",\n\"6 c none\",\n\"7 c none\",\n\"8 c none\",\n\"9 c none\",\n\"0 c none\",\n\"q c none\",\n\"w c none\",\n\"e c none\",\n\"r c none\",\n\"t c none\",\n\"y c none\",\n\"u c none\",\n\"i c none\",\n\"p c none\",\n/* pixels */\n\"qqqqqqqq=iq-;i3=qqqqqqqq\",\n\"qqqqqqqq3u8ru8q3qqqqqqqq\",\n\"qqqqqqqqi8u;;u8iqqqqqqqq\",\n\"qqqqqqqq8u8ii8pwqqqqqqqq\",\n\"qqqqqqqq+*+w8+*+qqqqqqqq\",\n\"qqqqqqqq$*+wq+*$qqqqqqqq\",\n\"qqqqqqqq+++qq$++qqqqqqqq\",\n\"qqqqqqqq+++-q+++qqqqqqqq\",\n\"qqqqqqqqXXX33XXXqqqqqqqq\",\n\"qqqqqqqqXXX:-XXXqqqqqqqq\",\n\"qqqqqqqqXXX-:XXXqqqqqqqq\",\n\"qqqqqqqqXXX3:XXXqqqqqqqq\",\n\"qqqqqqqqXX+q3+XXqqqqqqqq\",\n\"qqqqqqq0XX+q-+XXqqqqqqqq\",\n\"qqqqqqqqqqqqqqqqqqqqqqqq\",\n\"qqqqqqqqqqqqqqqqqqqqqqqq\",\n\"qqqqqqqqqqqqqqqqqqqqqqqq\",\n};\n"
  },
  {
    "path": "apps/vaporgui/images/pauseimage.xpm",
    "content": "/* XPM */\nconst static char *pauseimage[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 38 1\",\n\"  c black\",\n\". c black\",\n\"X c black\",\n\"o c black\",\n\"O c black\",\n\"+ c black\",\n\"@ c black\",\n\"# c black\",\n\"$ c black\",\n\"% c black\",\n\"& c black\",\n\"* c black\",\n\"= c none\",\n\"- c none\",\n\"; c none\",\n\": c none\",\n\"> c none\",\n\", c none\",\n\"< c none\",\n\"1 c none\",\n\"2 c none\",\n\"3 c none\",\n\"4 c none\",\n\"5 c none\",\n\"6 c none\",\n\"7 c none\",\n\"8 c none\",\n\"9 c none\",\n\"0 c none\",\n\"q c none\",\n\"w c none\",\n\"e c none\",\n\"r c none\",\n\"t c none\",\n\"y c none\",\n\"u c none\",\n\"i c none\",\n\"p c none\",\n/* pixels */\n\"qqqqqqqq03:33:31qqqqqqqq\",\n\"qqqqqqqqu88uu88uqqqqqqqq\",\n\"qqqqqqqq=iq-;i3=qqqqqqqq\",\n\"qqqqqqqq3u8ru8q3qqqqqqqq\",\n\"qqqqqqqqi8u;;u8iqqqqqqqq\",\n\"qqqqqqqq8u8ii8pwqqqqqqqq\",\n\"qqqqqqqq+*+w8+*+qqqqqqqq\",\n\"qqqqqqqq$*+wq+*$qqqqqqqq\",\n\"qqqqqqqq+++qq$++qqqqqqqq\",\n\"qqqqqqqq+++-q+++qqqqqqqq\",\n\"qqqqqqqqXXX33XXXqqqqqqqq\",\n\"qqqqqqqqXXX:-XXXqqqqqqqq\",\n\"qqqqqqqqXXX-:XXXqqqqqqqq\",\n\"qqqqqqqqXXX3:XXXqqqqqqqq\",\n\"qqqqqqqqXX+q3+XXqqqqqqqq\",\n\"qqqqqqq0XX+q-+XXqqqqqqqq\",\n\"qqqqqqqqqqqqqqqqqqqqqqqq\",\n\"qqqqqqqqqqqqqqqqqqqqqqqq\",\n\"qqqqqqqqqqqqqqqqqqqqqqqq\",\n\"qqqqqqqqqqqqqqqqqqqqqqqq\",\n\"qqqqqqqqqqqqqqqqqqqqqqqq\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/planes.xpm",
    "content": "/* XPM */\nconst static char *planes[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 175 2\",\n\"   c #292A22\",\n\".  c #282826\",\n\"X  c #2C2E20\",\n\"o  c #2C2E23\",\n\"O  c gray16\",\n\"+  c #2F3028\",\n\"@  c #313325\",\n\"#  c #30312B\",\n\"$  c #33342C\",\n\"%  c #383A2F\",\n\"&  c #3A3B35\",\n\"*  c #3D3F32\",\n\"=  c #42433B\",\n\"-  c #41413F\",\n\";  c #42433E\",\n\":  c #43443C\",\n\">  c gray25\",\n\",  c #414141\",\n\"<  c #434247\",\n\"1  c #454543\",\n\"2  c #454640\",\n\"3  c #494A44\",\n\"4  c #4B4D42\",\n\"5  c #4B4C46\",\n\"6  c #4B4C47\",\n\"7  c #4C4D45\",\n\"8  c #4D4F44\",\n\"9  c #4D4E46\",\n\"0  c #4E4F47\",\n\"q  c #4D4E49\",\n\"w  c #4E4F49\",\n\"e  c #4E4F4A\",\n\"r  c #4F4F4D\",\n\"t  c gray31\",\n\"y  c #4F5143\",\n\"u  c #4F5048\",\n\"i  c #4F504A\",\n\"p  c #4F504B\",\n\"a  c #505245\",\n\"s  c #505247\",\n\"d  c #515346\",\n\"f  c #50514B\",\n\"g  c #51524A\",\n\"h  c #52534B\",\n\"j  c #50514C\",\n\"k  c #50504E\",\n\"l  c #52534D\",\n\"z  c #53544C\",\n\"x  c #56584D\",\n\"c  c #595B4D\",\n\"v  c #585A4F\",\n\"b  c #5A5C4F\",\n\"n  c #505050\",\n\"m  c #575852\",\n\"M  c #585951\",\n\"N  c #595A52\",\n\"B  c #5A5B53\",\n\"V  c #595A54\",\n\"C  c #595A55\",\n\"Z  c #5A5B56\",\n\"A  c #5B5D50\",\n\"S  c #5B5D52\",\n\"D  c #5B5C54\",\n\"F  c #5B5C56\",\n\"G  c #5C5D55\",\n\"H  c #5C5D57\",\n\"J  c #5A5A5C\",\n\"K  c #5C5D58\",\n\"L  c #5E5F5A\",\n\"P  c #5E5E5C\",\n\"I  c #5E6053\",\n\"U  c #6F6F6F\",\n\"Y  c gray44\",\n\"T  c #717171\",\n\"R  c #707072\",\n\"E  c #727270\",\n\"W  c #727272\",\n\"Q  c gray45\",\n\"!  c #727274\",\n\"~  c #737375\",\n\"^  c #737277\",\n\"/  c #747570\",\n\"(  c #767772\",\n\")  c #747474\",\n\"_  c #747476\",\n\"`  c #757577\",\n\"'  c #737278\",\n\"]  c #8B8B89\",\n\"[  c #8C8C8A\",\n\"{  c #8D8D8B\",\n\"}  c #8D8E88\",\n\"|  c #8D8D8D\",\n\" . c #8D8D8F\",\n\".. c #8E8E8C\",\n\"X. c #8F8F8D\",\n\"o. c #8E8E90\",\n\"O. c #8F8F91\",\n\"+. c #90908E\",\n\"@. c #91918F\",\n\"#. c #929290\",\n\"$. c #919096\",\n\"%. c #929294\",\n\"&. c #B8BAAD\",\n\"*. c #B9BBAD\",\n\"=. c #B8BAAF\",\n\"-. c #B9BCAB\",\n\";. c #BABCAE\",\n\":. c #B6B7B1\",\n\">. c #B7B8B0\",\n\",. c #B8B9B3\",\n\"<. c #B9BBB0\",\n\"1. c #B9BAB2\",\n\"2. c #BABBB3\",\n\"3. c #B9BAB4\",\n\"4. c #BABCB1\",\n\"5. c #BBBCB6\",\n\"6. c #E4E7D4\",\n\"7. c #E4E6D9\",\n\"8. c #E5E7D9\",\n\"9. c #E5E9D2\",\n\"0. c #E7EBD0\",\n\"q. c #E6EAD3\",\n\"w. c #E7EBD2\",\n\"e. c #E5E8D5\",\n\"r. c #E5E8D7\",\n\"t. c #E6E9D4\",\n\"y. c #E6E9D6\",\n\"u. c #E7EAD5\",\n\"i. c #E7EBD4\",\n\"p. c #E7EAD7\",\n\"a. c #E6E9D8\",\n\"s. c #E6E8DA\",\n\"d. c #E7EAD9\",\n\"f. c #E7E9DC\",\n\"g. c #E7E9DE\",\n\"h. c #E8EBD6\",\n\"j. c #E8ECD3\",\n\"k. c #E8ECD5\",\n\"l. c #E9EDD4\",\n\"z. c #E9ECD7\",\n\"x. c #E9EDD6\",\n\"c. c #EAEED5\",\n\"v. c #EBEFD4\",\n\"b. c #EAEED7\",\n\"n. c #EBEFD6\",\n\"m. c #E8EBD8\",\n\"M. c #E8EBDA\",\n\"N. c #E8EADC\",\n\"B. c #E9EBDD\",\n\"V. c #E9EBDE\",\n\"C. c #E9ECD9\",\n\"Z. c #E9ECDB\",\n\"A. c #EAEDD8\",\n\"S. c #EAEDDA\",\n\"D. c #EBEED9\",\n\"F. c #EBEFD8\",\n\"G. c #EBEEDB\",\n\"H. c #EAEDDC\",\n\"J. c #EAECDE\",\n\"K. c #EAECDF\",\n\"L. c #EBEEDD\",\n\"P. c #ECEFDA\",\n\"I. c #ECEFDC\",\n\"U. c #ECEFDE\",\n\"Y. c #ECF0D5\",\n\"T. c #ECF0D7\",\n\"R. c #ECF0D9\",\n\"E. c #EDF0DB\",\n\"W. c #EFF3DC\",\n\"Q. c #E9EBE0\",\n\"!. c #E9EAE2\",\n\"~. c #EBEDE0\",\n\"^. c #ECEEE0\",\n\"/. c #EEF1E0\",\n\"(. c #EFF2E1\",\n/* pixels */\n\"G.x.x.h.h.h.P.h.h.x.!.P.0.U.h.M.p.G.h.G.x.9.x.h.\",\n\"p.G.G.h.x.6.h.m.G.p.m.9.9.U.P.M.G.6.U.p.x.P.9.G.\",\n\"h.9.h.h.p.U.G.M.% n.P.h.U.& p.m.m.U.* !.x.p.W.p.\",\n\"G.G.G.h.p.G.g.B 1 9.G.m.m - x.m.g.x = U.G.9.9.G.\",\n\"G.6.p.P.P.G.7 ( - n.p.a #., h.M.g 4.: 7.P.P.x.p.\",\n\"p.m.P.p.7.4 ( E r x.y } o.e P.7 >.>.h G.G.x.h.p.\",\n\"U.p.p.P.m.z E ' P 9.g  .%.B x.k ;.*.x !.p.x.G.G.\",\n\"m.G.h.h.M.F Y ' C P.C $.o.b x.J -.*.b G.G.9.G.m.\",\n\"G.p.G.9.G.F ! ( H G.C +.} K m.H *.2.C m.x.m.m.m.\",\n\"9.G.G.x.p.k Y Q 7 G.k #. .e h.g *.:.k p.x.G.G.p.\",\n\"9.G.m.G.m.e ! ' 7 G.e ] #.e m.a *.2.e m.x.G.m.x.\",\n\"x.G.m.x.P.m ) ! 7 P.K +.+.5 G.H *.5.6 G.p.h.G.p.\",\n\"x.G.G.p.G.B ! ! - G.C X.X.- G.B *.2.2 p.h.G.M.h.\",\n\"x.p.G.p.m.H ! E 7 G.C X.#.e G.B *.2.5 m.h.G.G.h.\",\n\"G.p.p.9.G.C ) Q g G.K X.} e p.B ;.5.e G.h.p.m.G.\",\n\"x.G.G.x.m.e E Q 7 G.e #.X.e G.7 ;.>.e p.x.G.U.m.\",\n\"p.G.9.x.m.n ' Q I p.e O. .K h.e >.4.x G.G.p.x.x.\",\n\"p.G.G.x.G.- U h p.G.< O.8 G.P., 4.d M.p.p.h.G.h.\",\n\"m.G.p.9.G.  $ p.G.p.O + G.x.x.O @ p.G.G.x.G.p.m.\",\n\"G.e.Z.G.G.o U.x.p.x.o p.G.p.q.+ G.G.p.x.h.p.m.h.\",\n\"9.(.m.h.U.Q.g.q.g.Y.p.(.6.G.x.!.m.m.x.h.x.h.m.m.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/playforward.xpm",
    "content": "/* XPM */\nconst static char *playforward[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 95 2\",\n\"   c black\",\n\".  c black\",\n\"X  c black\",\n\"o  c black\",\n\"O  c black\",\n\"+  c black\",\n\"@  c black\",\n\"#  c black\",\n\"$  c black\",\n\"%  c black\",\n\"&  c black\",\n\"*  c black\",\n\"=  c black\",\n\"-  c black\",\n\";  c black\",\n\":  c black\",\n\">  c black\",\n\",  c black\",\n\"<  c black\",\n\"1  c black\",\n\"2  c none\",\n\"3  c none\",\n\"4  c none\",\n\"5  c none\",\n\"6  c none\",\n\"7  c none\",\n\"8  c none\",\n\"9  c none\",\n\"0  c none\",\n\"q  c none\",\n\"w  c none\",\n\"e  c none\",\n\"r  c none\",\n\"t  c none\",\n\"y  c none\",\n\"u  c none\",\n\"i  c none\",\n\"p  c none\",\n\"a  c none\",\n\"s  c none\",\n\"d  c none\",\n\"f  c none\",\n\"g  c none\",\n\"h  c none\",\n\"j  c none\",\n\"k  c none\",\n\"l  c none\",\n\"z  c none\",\n\"x  c none\",\n\"c  c none\",\n\"v  c none\",\n\"b  c none\",\n\"n  c none\",\n\"m  c none\",\n\"M  c none\",\n\"N  c none\",\n\"B  c none\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n/* pixels */\n\"L L L L L L L L L L n [ L A n A L L L L L L L L \",\n\"L L L L L L L L J L ) M M L ' l L L L L L L L L \",\n\"L L L L L L L L L l L L  .J ) Q L L L L L L L L \",\n\"L L L L L L L L A A A l L J ) Q L L L L L L L L \",\n\"L L L L L L L L n I z Z A l n L L L L L L L L L \",\n\"L L L L L L L L Q / L n A L I A L L L L L L L L \",\n\"L L L L L L L L e y .. .J M A n L L L L L L L L \",\n\"L L L L L L L L , % 7 p Q / J J L L L L L L L L \",\n\"L L L L L L L L % , , , w t  .n L l N N M A M / \",\n\"L L L L L L L L o   O % % 1 6 u Q ) ) M M M l M \",\n\"L L L L L L L L     O       % = r h S Q L L A A \",\n\"L L L L L L L L %   %     % 4 q d S X./ n M A M \",\n\"L L L L L L L L     % : 2 q i g J ) F l A A L L \",\n\"L L L L L L L L   : 3 9 a f } H A z A A L n L L \",\n\"L L L L L L J J 6 9 s j | F [ z n A A M z L L / \",\n\"L L L L L L L F d } / n ' n L / / L L A A L F L \",\n\"L L L L L L L L L L L L L L L L L L L L L L L L \",\n\"L L L L L L L L L L L L L L L L L L L L L L L L \",\n\"L L L L L L L L L L L L L L L L L L L L L L L L \",\n\"L L L L L L L L L L L L L L L L L L L L L L L L \",\n\"L L L L L L L L L L L L L L L L L L L L L L L L \"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/playforwardA.xpm",
    "content": "/* XPM */\nconst static char *playforward[] = {\n/* columns rows colors chars-per-pixel */\n\"24 17 95 2\",\n\"   c black\",\n\".  c #000002\",\n\"X  c gray1\",\n\"o  c #040500\",\n\"O  c #040402\",\n\"+  c #000004\",\n\"@  c #000005\",\n\"#  c #010005\",\n\"$  c #020204\",\n\"%  c #010006\",\n\"&  c #000007\",\n\"*  c #010008\",\n\"=  c #000009\",\n\"-  c #00000B\",\n\";  c #02000B\",\n\":  c #040309\",\n\">  c #04030B\",\n\",  c #00000C\",\n\"<  c #00000E\",\n\"1  c #08070D\",\n\"2  c #43414C\",\n\"3  c #46454D\",\n\"4  c #4D4C51\",\n\"5  c #605F67\",\n\"6  c #67666B\",\n\"7  c #767676\",\n\"8  c #76757B\",\n\"9  c #75747C\",\n\"0  c #78777F\",\n\"q  c #7B7A80\",\n\"w  c #7B7984\",\n\"e  c #878789\",\n\"r  c #8A8A88\",\n\"t  c #9F9F9F\",\n\"y  c #A7A7A5\",\n\"u  c #A4A4A6\",\n\"i  c #A7A6AB\",\n\"p  c #B2B3AB\",\n\"a  c #ABAAB0\",\n\"s  c #B2B2B4\",\n\"d  c #BBBCB7\",\n\"f  c #BCBCBA\",\n\"g  c #BABABC\",\n\"h  c #C0C1BC\",\n\"j  c #C2C3BE\",\n\"k  c none\",\n\"l  c none\",\n\"z  c none\",\n\"x  c none\",\n\"c  c none\",\n\"v  c none\",\n\"b  c none\",\n\"n  c none\",\n\"m  c none\",\n\"M  c none\",\n\"N  c none\",\n\"B  c none\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c #F2F4E9\",\n/* pixels */\n\"L L L L L L L L L l L L  .J ) Q L L L L L L L L \",\n\"L L L L L L L L A A A l L J ) Q L L L L L L L L \",\n\"L L L L L L L L n I z Z A l n L L L L L L L L L \",\n\"L L L L L L L L Q / L n A L I A L L L L L L L L \",\n\"L L L L L L L L e y .. .J M A n L L L L L L L L \",\n\"L L L L L L L L , % 7 p Q / J J L L L L L L L L \",\n\"L L L L L L L L % , , , w t  .n L l N N M A M / \",\n\"L L L L L L L L o   O % % 1 6 u Q ) ) M M M l M \",\n\"L L L L L L L L     O       % = r h S Q L L A A \",\n\"L L L L L L L L %   %     % 4 q d S X./ n M A M \",\n\"L L L L L L L L     % : 2 q i g J ) F l A A L L \",\n\"L L L L L L L L   : 3 9 a f } H A z A A L n L L \",\n\"L L L L L L J J 6 9 s j | F [ z n A A M z L L / \",\n\"L L L L L L L F d } / n ' n L / / L L A A L F L \",\n\"L L L L L L L L L L L L L L L L L L L L L L L L \",\n\"L L L L L L L L L L L L L L L L L L L L L L L L \",\n\"L L L L L L L L L L L L L L L L L L L L L L L L \",\n};\n"
  },
  {
    "path": "apps/vaporgui/images/playreverse.xpm",
    "content": "/* XPM */\nconst static char *playreverse[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 95 2\",\n\"   c black\",\n\".  c black\",\n\"X  c black\",\n\"o  c black\",\n\"O  c black\",\n\"+  c black\",\n\"@  c black\",\n\"#  c black\",\n\"$  c black\",\n\"%  c black\",\n\"&  c black\",\n\"*  c black\",\n\"=  c black\",\n\"-  c black\",\n\";  c black\",\n\":  c black\",\n\">  c black\",\n\",  c black\",\n\"<  c black\",\n\"1  c black\",\n\"2  c none\",\n\"3  c none\",\n\"4  c none\",\n\"5  c none\",\n\"6  c none\",\n\"7  c none\",\n\"8  c none\",\n\"9  c none\",\n\"0  c none\",\n\"q  c none\",\n\"w  c none\",\n\"e  c none\",\n\"r  c none\",\n\"t  c none\",\n\"y  c none\",\n\"u  c none\",\n\"i  c none\",\n\"p  c none\",\n\"a  c none\",\n\"s  c none\",\n\"d  c none\",\n\"f  c none\",\n\"g  c none\",\n\"h  c none\",\n\"j  c none\",\n\"k  c none\",\n\"l  c none\",\n\"z  c none\",\n\"x  c none\",\n\"c  c none\",\n\"v  c none\",\n\"b  c none\",\n\"n  c none\",\n\"m  c none\",\n\"M  c none\",\n\"N  c none\",\n\"B  c none\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n/* pixels */\n\"L L L L L L L L Z Z Z M _ b L L K P K P K P K P \",\n\"L L L L L L L L b L L F M _ K L P K P K P K P K \",\n\"L L L L L L L L W ( K _ L L l I K P K P K P K P \",\n\"L L L L L L L L W _ K Z b M M Z P K P K P K P K \",\n\"L L L L L L L L L b l Z ` b I b K P K P K P K P \",\n\"L L L L L L L L L I L b M Z ( W P K P K P K P K \",\n\"L L L L L L L L M Z b Z _ ..y e K P K P K P K P \",\n\"L L L L L L L L W F ( W p 7 = = P K P K P K P K \",\n\"W M Z M c c l Z M  .t w < = > & K P K P K P K P \",\n\"I b M K M ( _ K y 6 1 . & . . o P K P K P K P K \",\n\"Z M Z L W S j r = & . . . o . . K P K P K P K P \",\n\"M M M M W X.S d q 4 & . . . & . P K P K P K P K \",\n\"K I M I c M _ L g i 0 2 > & . . K P K P K P K P \",\n\"K K M I P c c P W | f a 8 3 : . P K P K P K P K \",\n\"K K K c M I K M c ] b | j s 8 5 K P K P K P K P \",\n\"I M P M M I K W ( K M P M _ | f P K P K P K P K \",\n\"K T K P K P K P K P K P K P K P K P K P K P K P \",\n\"T K P K P K P K P K P K P K P K P K P K P K P K \",\n\"K P K P K P K P K P K P K P K P K P K P K P K P \",\n\"P K P K P K P K P K P K P K P K P K P K P K P K \",\n\"P K P K K P K P K P K P P K P K P K P K K P K P \"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/playreverseA.xpm",
    "content": "/* XPM */\nconst static char *playreverse[] = {\n/* columns rows colors chars-per-pixel */\n\"24 17 95 2\",\n\"   c black\",\n\".  c #000002\",\n\"X  c gray1\",\n\"o  c #040500\",\n\"O  c #040402\",\n\"+  c #000004\",\n\"@  c #000005\",\n\"#  c #010005\",\n\"$  c #020204\",\n\"%  c #010006\",\n\"&  c #000007\",\n\"*  c #010008\",\n\"=  c #000009\",\n\"-  c #00000B\",\n\";  c #02000B\",\n\":  c #040309\",\n\">  c #04030B\",\n\",  c #00000C\",\n\"<  c #00000E\",\n\"1  c #08070D\",\n\"2  c #43414C\",\n\"3  c #46454D\",\n\"4  c #4D4C51\",\n\"5  c #605F67\",\n\"6  c #67666B\",\n\"7  c #767676\",\n\"8  c #76757B\",\n\"9  c #75747C\",\n\"0  c #78777F\",\n\"q  c #7B7A80\",\n\"w  c #7B7984\",\n\"e  c #878789\",\n\"r  c #8A8A88\",\n\"t  c #9F9F9F\",\n\"y  c #A7A7A5\",\n\"u  c #A4A4A6\",\n\"i  c #A7A6AB\",\n\"p  c #B2B3AB\",\n\"a  c #ABAAB0\",\n\"s  c #B2B2B4\",\n\"d  c #BBBCB7\",\n\"f  c #BCBCBA\",\n\"g  c #BABABC\",\n\"h  c #C0C1BC\",\n\"j  c #C2C3BE\",\n\"k  c none\",\n\"l  c none\",\n\"z  c none\",\n\"x  c none\",\n\"c  c none\",\n\"v  c none\",\n\"b  c none\",\n\"n  c none\",\n\"m  c none\",\n\"M  c none\",\n\"N  c none\",\n\"B  c none\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c #F2F4E9\",\n/* pixels */\n\"L L L L L L L L W ( K _ L L l I K P K P K P K P \",\n\"L L L L L L L L W _ K Z b M M Z P K P K P K P K \",\n\"L L L L L L L L L b l Z ` b I b K P K P K P K P \",\n\"L L L L L L L L L I L b M Z ( W P K P K P K P K \",\n\"L L L L L L L L M Z b Z _ ..y e K P K P K P K P \",\n\"L L L L L L L L W F ( W p 7 = = P K P K P K P K \",\n\"W M Z M c c l Z M  .t w < = > & K P K P K P K P \",\n\"I b M K M ( _ K y 6 1 . & . . o P K P K P K P K \",\n\"Z M Z L W S j r = & . . . o . . K P K P K P K P \",\n\"M M M M W X.S d q 4 & . . . & . P K P K P K P K \",\n\"K I M I c M _ L g i 0 2 > & . . K P K P K P K P \",\n\"K K M I P c c P W | f a 8 3 : . P K P K P K P K \",\n\"K K K c M I K M c ] b | j s 8 5 K P K P K P K P \",\n\"I M P M M I K W ( K M P M _ | f P K P K P K P K \",\n\"K T K P K P K P K P K P K P K P K P K P K P K P \",\n\"T K P K P K P K P K P K P K P K P K P K P K P K \",\n\"K P K P K P K P K P K P K P K P K P K P K P K P \",\n};\n"
  },
  {
    "path": "apps/vaporgui/images/probe.xpm",
    "content": "/* XPM */\nconst static char *probe[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 128 2\",\n\"   c black\",\n\".  c black\",\n\"X  c black\",\n\"o  c black\",\n\"O  c black\",\n\"+  c black\",\n\"@  c black\",\n\"#  c black\",\n\"$  c black\",\n\"%  c black\",\n\"&  c black\",\n\"*  c black\",\n\"=  c black\",\n\"-  c black\",\n\";  c black\",\n\":  c black\",\n\">  c black\",\n\",  c black\",\n\"<  c black\",\n\"1  c black\",\n\"2  c black\",\n\"3  c black\",\n\"4  c black\",\n\"5  c black\",\n\"6  c black\",\n\"7  c black\",\n\"8  c black\",\n\"9  c black\",\n\"0  c black\",\n\"q  c black\",\n\"w  c black\",\n\"e  c black\",\n\"r  c black\",\n\"t  c black\",\n\"y  c black\",\n\"u  c black\",\n\"i  c black\",\n\"p  c black\",\n\"a  c black\",\n\"s  c black\",\n\"d  c black\",\n\"f  c black\",\n\"g  c black\",\n\"h  c black\",\n\"j  c black\",\n\"k  c black\",\n\"l  c black\",\n\"z  c black\",\n\"x  c black\",\n\"c  c none\",\n\"v  c none\",\n\"b  c none\",\n\"n  c none\",\n\"m  c none\",\n\"M  c none\",\n\"N  c none\",\n\"B  c none\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n/* pixels */\n\"X.X.X.X.X.X.X.X.( ( ( #.X.=.X.X.( #.m #.U ..X.( \",\n\"X.X.X.X.X.X.X.X... .=.B =.P  . ...P ] ( X.$.X.P \",\n\"X.X.X.X.X.X.X.X.U X.X.X.( ] ^ ,. .1.( ( P X./ <.\",\n\"X.X.X.X.X.X.X.X.#.( P X.P X.P P y.N X.X.X.N u.m \",\n\"X.X.X.X.X.X.X.X.B u.% % 3 l > s % e N ( P #.P 5.\",\n\"X.X.X.X.X.X.X.X.6.B D % > > 8 > t < =.X.U =.X.P \",\n\"X.X.X.X.X.X.X.X.n / ..e.% 5 % < > t U X.P X.U X.\",\n\"X.X.X.X.X.X.X.X.X.e.v % r % % % > % >.P #.X.X.( \",\n\"P X.X...P X.( ( w.C % % % % y > % % S N 6./ P X.\",\n\"1.P ( ..X.P 1.N q.g 5 5 > x % % % % e.1.m X.( =.\",\n\"N 1.X.( X.1.A e.% % % y % % i w.% % ..=.X.X.P X.\",\n\"..P ( #.X.N c % % x % > p % ..X.q.< ..P ( ( X.#.\",\n\"X.1.( X.P e.q > t % k % % D X.#.....X.X.X.X.P X.\",\n\"P N X.1.D % g > % % % < e.D X.( X.X.X.X.U P 1.X.\",\n\"<.X.B u.% 5 > > s % i D ..X.( X.( X.( P X.1.P ( \",\n\"^ / 1.D q % > : : % q.N X.X.U X.X.P X.X...P X.X.\",\n\"X.X.( ( ..< % % 6 S ..( X.X.( X.X.X.X.X.X.X.X.X.\",\n\"X./ X.X.N ..i % S >.( P ( X.#.X.X.X.X.X.X.X.X.X.\",\n\"( X.X.P .. .e. ...X.( #.U X.P <.X.X.X.X.X.X.X.X.\",\n\"X.( U =.X.X.P ( X./ X.X.D e.X.( X.X.X.X.X.X.X.X.\",\n\"X.( X...X.X.P ( X.( X.X.N e.X.( X.X.X.X.X.X.X.X.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/rake.xpm",
    "content": "/* XPM */\nconst static char *rake[] = {\n/* columns rows colors chars-per-pixel */\n\"26 23 82 1\",\n\"  c #040404\",\n\". c #040308\",\n\"X c #090A05\",\n\"o c #0A0B0A\",\n\"O c #100F14\",\n\"+ c #131314\",\n\"@ c #16151A\",\n\"# c  gray11\",\n\"$ c #232323\",\n\"% c #2B2C29\",\n\"& c #2C2B31\",\n\"* c #343434\",\n\"= c #393A36\",\n\"- c #3D3D3C\",\n\"; c #494949\",\n\": c #51524A\",\n\"> c #505050\",\n\", c #5F5F5F\",\n\"< c #626262\",\n\"1 c #6C6C6C\",\n\"2 c #737373\",\n\"3 c #7A7A7A\",\n\"4 c #848483\",\n\"5 c #878880\",\n\"6 c #8A8B84\",\n\"7 c #8B8B89\",\n\"8 c #91928B\",\n\"9 c #9A9C8F\",\n\"0 c #959595\",\n\"q c #9A9B94\",\n\"w c #9C9C9A\",\n\"e c #9C9BA0\",\n\"r c #9FA194\",\n\"t c #A1A29C\",\n\"y c #ABAD9F\",\n\"u c #A4A4A2\",\n\"i c #ABACA3\",\n\"p c #ABABAB\",\n\"a c #A7A5B2\",\n\"s c #ADABB6\",\n\"d c #B2B5A4\",\n\"f c #B3B5A9\",\n\"g c #B7B9AE\",\n\"h c #B2B2B2\",\n\"j c #B7B8B0\",\n\"k c #B8B7BC\",\n\"l c #B9B9B4\",\n\"z c #BABABB\",\n\"x c #BEBDC3\",\n\"c c #BFC1B3\",\n\"v c #C2C3BC\",\n\"b c #C7C9BC\",\n\"n c #CACDBD\",\n\"m c #C1C1C3\",\n\"M c #C7C8C3\",\n\"N c #C8C7CC\",\n\"B c #CACCC3\",\n\"V c #CBCBCA\",\n\"C c #D0CFD4\",\n\"Z c #D0D2C7\",\n\"A c #D7D9CB\",\n\"S c #DADDCC\",\n\"D c #D7D7D5\",\n\"F c #DCDCDA\",\n\"G c #DEE1CC\",\n\"H c #DEE0D4\",\n\"J c none\",\n\"K c none\",\n\"L c none\",\n\"P c none\",\n\"I c none\",\n\"U c none\",\n\"Y c none\",\n\"T c none\",\n\"R c none\",\n\"E c none\",\n\"W c none\",\n\"Q c none\",\n\"! c none\",\n\"~ c none\",\n\"^ c none\",\n\"/ c none\",\n/* pixels */\n\"PYYKPYUJUPURYU!IUUUUUUUUUU\",\n\"YUY/TKURURPKTYITUUUUUUUUUU\",\n\"YPPPIIYYUKTRJPYPUUUUUUYUUU\",\n\"YPTYcqfYTRUURUGTUUUUUUUUUU\",\n\"YPPYYFj6fK!KU~YPUUIUUUUUUU\",\n\"PY~Fi8iVuwlIYKTYUUUUUUUUUU\",\n\"UPIIIEVwphuwrB^KUUUUUUUUUU\",\n\"PUUbq8pNxpp0=:ZWUUUUUUUUUU\",\n\"UP!KEYDhuppw*>17HWWLIYYPUU\",\n\"UPGy88wwhpp4$23-%6H^IY!TTI\",\n\"PPTLQQFNhpp4&33;@o-qVcpiq7\",\n\"!KBrrrupppp2$21,&O.o XooO \",\n\"KY~IQEVxzhk3$73;@.$<678685\",\n\"TIAiruhxhpp2$3,;=2MQYI!!YI\",\n\"IY~EEFmeppu2%230AY!IHYTJUU\",\n\"YIFfqumNhpp1#sQE!IIYTYJUYY\",\n\"UUUHECsazpuiyIUUUUUUUUUUUU\",\n\"TJIBtlVkivIYGYPUUUUUUUUUUU\",\n\"JY~~YgrVUY!TUTUPUUUUUUUUUU\",\n\"~K!Adn!KUUJKUYYYUUUUUUUUUU\",\n\"ILYYYUGTUYTUUUUYUUUUUUUUUU\",\n\"IW!II!UYYYYUKUYUUUUUUUUUUU\",\n\"IY!II!YEEW!!K/YUUUUUUUUUUU\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/replayA.xpm",
    "content": "/* XPM */\nstatic const char *replay_[] = {\n/* columns rows colors chars-per-pixel */\n\"24 17 196 2\",\n\"   c black\",\n\".  c #000002\",\n\"X  c #020202\",\n\"o  c #000004\",\n\"O  c #010204\",\n\"+  c #000007\",\n\"@  c #020106\",\n\"#  c #030207\",\n\"$  c #060606\",\n\"%  c #000009\",\n\"&  c #020109\",\n\"*  c #030208\",\n\"=  c #020308\",\n\"-  c #00000A\",\n\";  c #01010B\",\n\":  c #040509\",\n\">  c #00000C\",\n\",  c #01000D\",\n\"<  c #02000D\",\n\"1  c #00000E\",\n\"2  c #01000E\",\n\"3  c #01000F\",\n\"4  c #050311\",\n\"5  c #121214\",\n\"6  c #141517\",\n\"7  c #151517\",\n\"8  c #15141A\",\n\"9  c #18181A\",\n\"0  c #20201E\",\n\"q  c #171427\",\n\"w  c #1F1E23\",\n\"e  c #201F24\",\n\"r  c #27262B\",\n\"t  c #2C2D28\",\n\"y  c #29282D\",\n\"u  c #29282E\",\n\"i  c #2A292E\",\n\"p  c #2D2D2F\",\n\"a  c #2B2936\",\n\"s  c #2C2A37\",\n\"d  c #303133\",\n\"f  c #333237\",\n\"g  c #363837\",\n\"h  c #393B38\",\n\"j  c gray24\",\n\"k  c #3F403B\",\n\"l  c #41423D\",\n\"z  c #343146\",\n\"x  c #383641\",\n\"c  c #403F45\",\n\"v  c #444540\",\n\"b  c #444446\",\n\"n  c #464648\",\n\"m  c #48474C\",\n\"M  c #51524D\",\n\"N  c #52554E\",\n\"B  c #444250\",\n\"V  c #494850\",\n\"C  c #4C4B51\",\n\"Z  c #505251\",\n\"A  c #505052\",\n\"S  c #525254\",\n\"D  c #595957\",\n\"F  c #55545A\",\n\"G  c #56555B\",\n\"H  c #5B5B59\",\n\"J  c #5F6064\",\n\"K  c #656563\",\n\"L  c #616065\",\n\"P  c #656764\",\n\"I  c #676475\",\n\"U  c #6A6873\",\n\"Y  c #706E79\",\n\"T  c #757573\",\n\"R  c #7B7C74\",\n\"E  c #7C7D78\",\n\"W  c #777580\",\n\"Q  c #787684\",\n\"!  c #7D7B88\",\n\"~  c #7F7D88\",\n\"^  c #848388\",\n\"/  c #89888E\",\n\"(  c #90908E\",\n\")  c #8B8A92\",\n\"_  c #908E99\",\n\"`  c #949398\",\n\"'  c #9D9E99\",\n\"]  c #A2A1A9\",\n\"[  c #A4A3A8\",\n\"{  c #B0AFB7\",\n\"}  c #B9B8BE\",\n\"|  c #C1C1BF\",\n\" . c #BEBFC3\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n\"z. c none\",\n\"x. c none\",\n\"c. c none\",\n\"v. c none\",\n\"b. c none\",\n\"n. c none\",\n\"m. c none\",\n\"M. c none\",\n\"N. c none\",\n\"B. c none\",\n\"V. c none\",\n\"C. c none\",\n\"Z. c none\",\n\"A. c none\",\n\"S. c none\",\n\"D. c none\",\n\"F. c none\",\n\"G. c none\",\n\"H. c none\",\n\"J. c none\",\n\"K. c none\",\n\"L. c none\",\n\"P. c none\",\n\"I. c none\",\n\"U. c none\",\n\"Y. c none\",\n\"T. c none\",\n\"R. c none\",\n\"E. c none\",\n\"W. c none\",\n\"Q. c none\",\n\"!. c none\",\n\"~. c none\",\n\"^. c none\",\n\"/. c none\",\n\"(. c none\",\n\"). c none\",\n\"_. c none\",\n\"`. c none\",\n\"'. c none\",\n\"]. c none\",\n\"[. c none\",\n\"{. c none\",\n\"}. c none\",\n\"|. c none\",\n\" X c none\",\n\".X c none\",\n\"XX c none\",\n\"oX c none\",\n\"OX c none\",\n\"+X c none\",\n\"@X c none\",\n\"#X c none\",\n\"$X c none\",\n\"%X c none\",\n\"&X c none\",\n\"*X c none\",\n/* pixels */\n\";.`.Z.v.].z.j.+X+Xz.z.m.m.F.u.%._.y.y.m.v.T.;.v.\",\n\"Z.y.y.;.;.I.].p.z.T.T.z.m.m.m./.6.y.Z.;.Z.`.y.v.\",\n\"Z.;.y.v._._.+.`.y.6.(.y.y.Z.m.m.Z.;.;.{.;.;.;.0.\",\n\"m.m.Z.v.+.v.].m.Z.j.{.;.T.d.' j j.@X{.;.Z.0.0.Z.\",\n\"m.'.+.`.v.I.}.( C b b n m V a 4 t  Xz.;._.Z.Z.Z.\",\n\"y.6.y.Z.+X| G - < - - . . : + < . k T._.6.y.F.m.\",\n\"6.;.y.6.+XU < 6 I Q Y E ! ! B 4 d |.+Xz.Z.T.%.6.\",\n\"/.I.Z.v.T.p + N (.X.6...m.@XR v z.T w P j.y.T.j.\",\n\"u.0.Z.y.j.6 - Z z.T.T.Z.%.;.@XL.T.H + 9 j.6.;.%X\",\n\"%._.%.F.T.l 5 J } A E +XZ.Z.Z.;.z.M $ 0 T.y._.y.\",\n\"/.L.@./.j.].z.+Xx + F ` ^ / ) _ P 8 - Z m.6.%.F.\",\n\"m.0.F.m.Z.%.+Xh . . . . $ + + < + < z ] j.6.Z.z.\",\n\"1._.%.m.Z.y.T. .q < a i r i i w g L [ }.{.%.m.+X\",\n\"L.0.0.E.y.o.Z.$X{ f H *Xj.F.;.Z.+Xm.y.X.6.y.;.y.\",\n\"m.Z.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.\",\n\"y.m.Z.y.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.\",\n\"Z.Z.m.j.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.Z.v.\",\n};\n"
  },
  {
    "path": "apps/vaporgui/images/sethome.xpm",
    "content": "/* XPM */\nconst static char *sethome[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 157 2\",\n\"   c black\",\n\".  c #000100\",\n\"X  c #010100\",\n\"o  c #010101\",\n\"O  c #000002\",\n\"+  c #010103\",\n\"@  c #000200\",\n\"#  c #010200\",\n\"$  c #010300\",\n\"%  c #020200\",\n\"&  c #020300\",\n\"*  c #020202\",\n\"=  c #000004\",\n\"-  c #000005\",\n\";  c #010005\",\n\":  c #020204\",\n\">  c #030305\",\n\",  c #030400\",\n\"<  c #040500\",\n\"1  c #050503\",\n\"2  c #050601\",\n\"3  c gray2\",\n\"4  c #040406\",\n\"5  c #050507\",\n\"6  c #000009\",\n\"7  c #040308\",\n\"8  c #91928C\",\n\"9  c #91928D\",\n\"0  c #93948F\",\n\"q  c #94968B\",\n\"w  c #95978C\",\n\"e  c #96978F\",\n\"r  c #9A9C8E\",\n\"t  c #919193\",\n\"y  c #949492\",\n\"u  c #969791\",\n\"i  c #969792\",\n\"p  c #949496\",\n\"a  c #969694\",\n\"s  c #979795\",\n\"d  c #979893\",\n\"f  c #9A9B93\",\n\"g  c #989994\",\n\"h  c #999997\",\n\"j  c #9A9B95\",\n\"k  c gray60\",\n\"l  c #9A9A9A\",\n\"z  c #C0C2B7\",\n\"x  c #C1C1C1\",\n\"c  c #C2C2C0\",\n\"v  c #C3C3C1\",\n\"b  c #C3C3C5\",\n\"n  c #C5C5C5\",\n\"m  c none\",\n\"M  c none\",\n\"N  c none\",\n\"B  c none\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n\"z. c none\",\n\"x. c #F0F3E2\",\n\"c. c #F0F1E9\",\n\"v. c #F2F3EE\",\n\"b. c #F6F7EF\",\n\"n. c #F0F0F2\",\n\"m. c #F3F3F3\",\n\"M. c #F5F5F3\",\n\"N. c gray96\",\n\"B. c gray97\",\n\"V. c #F5F4FA\",\n\"C. c #F7F8F3\",\n\"Z. c #FBFBF9\",\n\"A. c #FDFDFD\",\n\"S. c #FDFDFF\",\n\"D. c #FEFEFE\",\n\"F. c #FFFEFF\",\n\"G. c gray100\",\n/* pixels */\n\"&.G W >.S >.S ) ) ) P i.+.) ^ &.&.S ^ ^ W Y G ) \",\n\"G >.) W W ) G &.) ) &.o o ) G &.+.&.S S &.&.&.&.\",\n\"W ) m ) 2.&.W G 2.^ s.o o E ) s.s.P &.) G k.&.G \",\n\"&.W ) &.Y G &.&.S P &.o * G +.w y o &.&.G P G &.\",\n\"S W >.W G +.&.Y k.W p o o o G k 7.* P &.&.&.L L \",\n\">.) &.G &.Y P &.P j z.: : +.o d r.o k.G &.L L ) \",\n\"S S W &.Y P x.N y b.7 : 5 o Y * r.o +.S L 2.G &.\",\n\") &.G >.) &.N r b.o b 6 o z * s.o o P &.&.G &.G \",\n\"&.G ) ) ) &.9 V.o x A.o 7 j.n o s.* +.Q &.L ^ &.\",\n\") 2.R +.E e N.o x Z.A.B.j.N.5.x * q.* &.u.&.&.P \",\n\"Q P * o o 3 o o o 3 v.j.C.5.o o o * o o o * &.s.\",\n\"[ G o o o o o o : o p f y h o o o o o o * o S +.\",\n\"L +.E R +.g.y A.A.n.k A.h.k 7.6.+.* Y k.R k.^ L \",\n\"&.&.S 2.S G 8 A.N.w.p o o y q.w.G * +.L s.m [ L \",\n\"S &.) ) S &.j A.B y.y o : d 5.R P * M ^ 4.L ^ L \",\n\") G &.) &.&.w y.+.E d o o d E +.+.o &.[ L &.L &.\",\n\"&.G [ L [ P * o o o o : : o o o o o G &.Q [ L &.\",\n\"&.&.L &.L &.+.Y ) ) &.o o +.) ) R +.&.L &.G &.} \",\n\"G &.G G &.&.} &.+.G +.o o E S &.&.L &.&.G Q &.S \",\n\") G &.&.L [ L L +.) &.o o &.) +.) L ) L +.&.L ) \",\n\"[ L &.&.L L Q L Y &.L +.+.L ) } ^ L ) } &.+.L [ \"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/sphere.xpm",
    "content": "/* XPM */\nconst static char *sphere[] = {\n/* columns rows colors chars-per-pixel */\n\"20 20 42 1\",\n\"  c black\",\n\". c #010101\",\n\"X c #020202\",\n\"o c gray1\",\n\"O c #040404\",\n\"+ c gray2\",\n\"@ c #060606\",\n\"# c gray3\",\n\"$ c #090909\",\n\"% c gray4\",\n\"& c #0C0C0C\",\n\"* c gray5\",\n\"= c #0E0E0E\",\n\"- c #101010\",\n\"; c #131313\",\n\": c gray9\",\n\"> c #1B1B1B\",\n\", c #E6E6E6\",\n\"< c #E7E7E7\",\n\"1 c #E9E9E9\",\n\"2 c #EAEAEA\",\n\"3 c gray92\",\n\"4 c #ECECEC\",\n\"5 c gray93\",\n\"6 c #EEEEEE\",\n\"7 c #EFEFEF\",\n\"8 c gray94\",\n\"9 c #F1F1F1\",\n\"0 c gray95\",\n\"q c #F3F3F3\",\n\"w c #F4F4F4\",\n\"e c gray96\",\n\"r c #F6F6F6\",\n\"t c gray97\",\n\"y c #F8F8F8\",\n\"u c #F9F9F9\",\n\"i c gray98\",\n\"p c #FBFBFB\",\n\"a c gray99\",\n\"s c #FDFDFD\",\n\"d c #FEFEFE\",\n\"f c gray100\",\n/* pixels */\n\"dddrdddddtddddddttdd\",\n\"rd00d6tdd6dtdddrdddr\",\n\"dddd0dd00dddrddd2ddd\",\n\"drdddr<>.%..;rdtdd6d\",\n\"tdd6d%..d.d.d.&dddd2\",\n\"dddt+d;d.t&d.dr.dttd\",\n\"dtd;0.6d%d.td.dd.tdd\",\n\"dd.td.d.dtd%r+rdd%td\",\n\"td&td.d.ddd.d.ddd.dt\",\n\"d.0d.dt%tdd.dd%ddt.t\",\n\"t.dd%dd.d2d+dd.ddd.t\",\n\"d%dd.dd%rtd.6d.d0d.d\",\n\"d2.d0+t%dd0+d.d0d.t6\",\n\"td.dd.d.ddr.0&2dd.dd\",\n\"d0d.r&0d.d&dd.dd.ddd\",\n\"drdd+t.d%r.d.rd.dddt\",\n\"dtddt+.+d-t.d..ddddd\",\n\"d6dd0dd......trddddd\",\n\"ddtddddddddddtd6dddd\",\n\"ddr0ddrdtdt<dtrddddd\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/spherecolored.xpm",
    "content": "/* XPM */\nconst static char *spherecolored[] = {\n/* columns rows colors chars-per-pixel */\n\"20 20 198 2\",\n\"   c #020304\",\n\".  c #00040B\",\n\"X  c #000B03\",\n\"o  c #000C0A\",\n\"O  c #0C0000\",\n\"+  c #0E0B00\",\n\"@  c #060E10\",\n\"#  c #00081B\",\n\"$  c #0D081F\",\n\"%  c #001503\",\n\"&  c #00140A\",\n\"*  c #001C0B\",\n\"=  c #001214\",\n\"-  c #00111C\",\n\";  c #001B11\",\n\":  c #001D1B\",\n\">  c #16000A\",\n\",  c #170E00\",\n\"<  c #1C0000\",\n\"1  c #1F000C\",\n\"2  c #110012\",\n\"3  c #19031A\",\n\"4  c #131300\",\n\"5  c #000221\",\n\"6  c #00002E\",\n\"7  c #080020\",\n\"8  c #000930\",\n\"9  c #0B0930\",\n\"0  c #001623\",\n\"q  c #00152C\",\n\"w  c #001D33\",\n\"e  c #180026\",\n\"r  c #002716\",\n\"t  c #00241A\",\n\"y  c #022123\",\n\"u  c #002820\",\n\"i  c #00263D\",\n\"p  c #240000\",\n\"a  c #230009\",\n\"s  c #2B0002\",\n\"d  c #201B18\",\n\"f  c #320100\",\n\"g  c #31000C\",\n\"h  c #3D0000\",\n\"j  c #310810\",\n\"k  c #24192A\",\n\"l  c #000443\",\n\"z  c #000B40\",\n\"x  c #145B4D\",\n\"c  c #13695E\",\n\"v  c #0C6D66\",\n\"b  c #176963\",\n\"n  c #116F6E\",\n\"m  c #1A6D65\",\n\"M  c #156677\",\n\"N  c #106579\",\n\"B  c #156A73\",\n\"V  c #1F6376\",\n\"C  c #1B7C74\",\n\"Z  c #1D7F7E\",\n\"A  c #205C5D\",\n\"S  c #2C676B\",\n\"D  c #2B7167\",\n\"F  c #297569\",\n\"G  c #2C797F\",\n\"H  c #336A65\",\n\"J  c #3C626D\",\n\"K  c #3D6C76\",\n\"L  c #327D74\",\n\"P  c #307A7B\",\n\"I  c #3C7972\",\n\"U  c #460906\",\n\"Y  c #630000\",\n\"T  c #6E0000\",\n\"R  c #762218\",\n\"E  c #693935\",\n\"W  c #7F2A41\",\n\"Q  c #574E2F\",\n\"!  c #446061\",\n\"~  c #614544\",\n\"^  c #3C7588\",\n\"/  c #427684\",\n\"(  c #2C8073\",\n\")  c #36879A\",\n\"_  c #7987A1\",\n\"`  c #6EA3B5\",\n\"'  c #5B83CB\",\n\"]  c #56BFC5\",\n\"[  c #6992D4\",\n\"{  c #7F9BE5\",\n\"}  c #65CAB8\",\n\"|  c #69D0BB\",\n\" . c #5FC3C5\",\n\".. c #62C5C4\",\n\"X. c #68CFD4\",\n\"o. c #65D1C1\",\n\"O. c #63D9DD\",\n\"+. c #79D3C7\",\n\"@. c #72DED1\",\n\"#. c #77E7CF\",\n\"$. c #77E0DB\",\n\"%. c #70E7ED\",\n\"&. c #8E2D2B\",\n\"*. c #842932\",\n\"=. c #933E3B\",\n\"-. c #AD160F\",\n\";. c #B10A02\",\n\":. c #B4120D\",\n\">. c #A61E20\",\n\",. c #A3271D\",\n\"<. c #B12116\",\n\"1. c #9B2B44\",\n\"2. c #D8231C\",\n\"3. c #C42A20\",\n\"4. c #ED6F3D\",\n\"5. c #D27F5D\",\n\"6. c #C07764\",\n\"7. c #DB7863\",\n\"8. c #E17E45\",\n\"9. c #F66F52\",\n\"0. c #8277BC\",\n\"q. c #8D7CB2\",\n\"w. c #9077B8\",\n\"e. c #CE7D84\",\n\"r. c #BD8F5E\",\n\"t. c #BF8E6E\",\n\"y. c #C1925E\",\n\"u. c #DF8B66\",\n\"i. c #DB886A\",\n\"p. c #D38B7D\",\n\"a. c #FB9C5C\",\n\"s. c #E88A7E\",\n\"d. c #E29166\",\n\"f. c #E9976F\",\n\"g. c #FF8C69\",\n\"h. c #86858D\",\n\"j. c #8784BD\",\n\"k. c #8D90B9\",\n\"l. c #9182B9\",\n\"z. c #9895B4\",\n\"x. c #B58E87\",\n\"c. c #A5BDA7\",\n\"v. c #AEB3AD\",\n\"b. c #8D89C4\",\n\"n. c #8F8DCE\",\n\"m. c #968CC0\",\n\"M. c #9E8ACF\",\n\"N. c #9598C1\",\n\"B. c #96D1B1\",\n\"V. c #87D2D8\",\n\"C. c #93D5D4\",\n\"Z. c #CA9B89\",\n\"A. c #CA96A2\",\n\"S. c #E4948B\",\n\"D. c #FF8D80\",\n\"F. c #F0A387\",\n\"G. c #DCDADB\",\n\"H. c #DCE1E1\",\n\"J. c #D2FDF9\",\n\"K. c #D9F7F9\",\n\"L. c #DDFFFC\",\n\"P. c #E8DDE3\",\n\"I. c #F6E3DF\",\n\"U. c #FFF8DB\",\n\"Y. c #E5E3E8\",\n\"T. c #E5ECEC\",\n\"R. c #EBE3EB\",\n\"E. c #E9EAEF\",\n\"W. c #E6E8F5\",\n\"Q. c #E7F0EF\",\n\"!. c #E8F2EA\",\n\"~. c #ECFFEE\",\n\"^. c #E6F0F1\",\n\"/. c #E0FBFD\",\n\"(. c #ECF3F3\",\n\"). c #EBF4FE\",\n\"_. c #EDFAF3\",\n\"`. c #ECFEFE\",\n\"'. c #F6EEEC\",\n\"]. c #FDE5E3\",\n\"[. c #FFEEEA\",\n\"{. c #F6E4F4\",\n\"}. c #F3EEF4\",\n\"|. c #FDE5FC\",\n\" X c #FBECF2\",\n\".X c #FFEBFB\",\n\"XX c #F5F3E5\",\n\"oX c #F1F2ED\",\n\"OX c #F5F8E5\",\n\"+X c #FEFCEA\",\n\"@X c #F2F4F3\",\n\"#X c #F4F6FF\",\n\"$X c #F5FFF4\",\n\"%X c #F4FDFD\",\n\"&X c #FCF2F3\",\n\"*X c #FDF3FD\",\n\"=X c #FEFBF5\",\n\"-X c #FCFDFE\",\n/* pixels */\n\"+X+X+XXX-X%X).-X-X=X~.$X=X X&X=X&X=X@X-X\",\n\"OXOXOX=XG.*X-X*X}.'.%X_.@X-X-XoX*X-X=X-X\",\n\"-X=X%X-X=X].|.|.*X*X.X-X%X%XY.-XP.*X-X-X\",\n\"}.%X`.!.+X+X{.k O   7 5 = J.%X-X-X-XP.-X\",\n\"-X%X-X@XU., o & B.X k.6 J : o L.W.-X-XP.\",\n\"#X-XR.I.f Q r | % c.9 b.# K S : %X-XY.-X\",\n\"-X*X*XU R < } #.4 Z.2 q.m.6 ^ c o %X%X-X\",\n\"*X*Xf &.=.O #.* t.7.A.e w.8 B C I X `.`.\",\n\"*X.XT ,.E o ..; 5.g.p.> M.l M C F & J./.\",\n\"|.f :.<.O C.X.& f.4.i.p 0.{ w v ( x t /.\",\n\"-Xf 2.3.X ..O.* y.a.d.p n.' q C c ( & J.\",\n\"&Xf ;.-.O V.%.* r.8.u.p b.[ i B m D : L.\",\n\"-X[.Y >.W 7  .t F.9.s.g l.z N Z P H J.K.\",\n\"=X].h &.1.1  .r 6.g.e.> N.8 ) B A = `.%X\",\n\"-X X].p *.g $.o.1 S.a z.` 0 V ^ - `.#XW.\",\n\" X=X-X&Xs ~ : +.+ x.3 _ = G / # `.).-X-X\",\n\"-X%X%X-X&X  o ; v.d h.. ! y . %X%X-X-X-X\",\n\"%XE.-X`.W.%X%X  .   &     W.-X%X-X-X-X-X\",\n\"-X-X_.-X-X%X-X%X-X(.%X%X%XQ.-X_.-X-X-X-X\",\n\"%X-X(.T.%X-X(.-XT.-X-XH.-X%XT.-X-X-X-X-X\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/step-back-off.xpm",
    "content": "/* XPM */\nconst static char *step-back-off[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 75 1\",\n\"  c #B3B6A3\",\n\". c #B6B9A6\",\n\"X c #B7BAA7\",\n\"o c #B7B9AB\",\n\"O c #B7BAA9\",\n\"+ c #B8BBA8\",\n\"@ c #B8BBAA\",\n\"# c #B9BBAD\",\n\"$ c #B9BCA9\",\n\"% c #B9BCAB\",\n\"& c #BABDAA\",\n\"* c #BBBEAB\",\n\"= c #BBBDAF\",\n\"- c #BBBEAD\",\n\"; c #BCBFAC\",\n\": c #BCBFAE\",\n\"> c #BCBEB0\",\n\", c #BDBFB1\",\n\"< c #BDC0AD\",\n\"1 c #BDC0AF\",\n\"2 c #BEC1AE\",\n\"3 c #BEC0B2\",\n\"4 c #BFC1B3\",\n\"5 c #C0C2B4\",\n\"6 c #C1C3B5\",\n\"7 c #C1C4B3\",\n\"8 c #C3C6B5\",\n\"9 c #C6C9B8\",\n\"0 c #C8CBBA\",\n\"q c #CFD1C3\",\n\"w c #CFD2C1\",\n\"e c #D2D5C4\",\n\"r c #DADDCA\",\n\"t c #DBDECD\",\n\"y c #DDE0CF\",\n\"u c #DFE2D1\",\n\"i c #E0E3D2\",\n\"p c #E2E5D2\",\n\"a c #E3E6D3\",\n\"s c #E4E7D4\",\n\"d c #E4E7D6\",\n\"f c #E5E8D3\",\n\"g c #E5E8D5\",\n\"h c #E6E9D4\",\n\"j c #E6E9D6\",\n\"k c #E7EAD5\",\n\"l c #E7EBD4\",\n\"z c #E7EAD7\",\n\"x c #E6E9D8\",\n\"c c #E7EAD9\",\n\"v c #E8EBD6\",\n\"b c #E8ECD5\",\n\"n c #E9ECD7\",\n\"m c #E9EDD6\",\n\"M c #EAEED7\",\n\"N c #E8EBD8\",\n\"B c #E8EBDA\",\n\"V c #E8EADC\",\n\"C c #E9EBDD\",\n\"Z c #E9ECD9\",\n\"A c #E9ECDB\",\n\"S c #EAEDD8\",\n\"D c #EAEDDA\",\n\"F c #EBEED9\",\n\"G c #EBEEDB\",\n\"H c #EAEDDC\",\n\"J c #EBEEDD\",\n\"K c #ECEFDA\",\n\"L c #ECEFDC\",\n\"P c #EDF0DB\",\n\"I c #EDF0DD\",\n\"U c #EEF1DC\",\n\"Y c #EEF1DE\",\n\"T c #EFF2DD\",\n\"R c #EFF2DF\",\n/* pixels */\n\"knvSSSkSSkSnnSnnGzzzzzSz\",\n\"SnKfSkvSnSaYnknSzcGGSGGG\",\n\"SkfnScYfSSkkSkYkzGGczcGc\",\n\"cGSYkkSSSdYSGkSSSGzzzSzG\",\n\"zSzkGJpJGGScdGckGczGSGzG\",\n\"SzGJSzYScSSkJSSSSzzIzGzn\",\n\"zScGo$X$- --.X-SzSzGacGz\",\n\"GGzS-S-zcSSk-c-zzGzfyzGm\",\n\"SkSG$$OGvSkGX,XCBct84GGl\",\n\"kYca<c$BSkYd,c>Vy9444czm\",\n\"nkGGO$$SSkGcoXX033444IdG\",\n\"zccG<z:cSkcS-G>de444:Gcc\",\n\"nSkk$$<cdYYkX:OGGuq44GdG\",\n\"nScR$S.ISdcS-d:cSSGuqBGk\",\n\"zcGc+<-@:X,$$$$cmmSGSGcS\",\n\"zScScdIBcGckYcSSznScccSk\",\n\"SSSGcSGccSGcSGcSGcSGcSGc\",\n\"SccSSccSSccSScSccScSSccS\",\n\"SSccGSSGSGGSccSGSSccGSSG\",\n\"cSSGccSccSccSGcSGcSGccSc\",\n\"ScScScSGSGcScScGScScScSG\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/step-fwd-off.xpm",
    "content": "/* XPM */\nconst static char *step-fwd-off[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 76 1\",\n\"  c #B0B3A0\",\n\". c #B1B4A3\",\n\"X c #B2B5A2\",\n\"o c #B3B6A3\",\n\"O c #B2B5A4\",\n\"+ c #B3B5A7\",\n\"@ c #B3B6A5\",\n\"# c #B4B7A4\",\n\"$ c #B4B7A6\",\n\"% c #B5B8A5\",\n\"& c #B5B8A7\",\n\"* c #B6B9A6\",\n\"= c #B6B9A8\",\n\"- c #B7B9AB\",\n\"; c #B7BAA9\",\n\": c #B8BBA8\",\n\"> c #B8BBAA\",\n\", c #B8BAAC\",\n\"< c #B9BBAD\",\n\"1 c #B9BCA9\",\n\"2 c #B9BCAB\",\n\"3 c #BABDAA\",\n\"4 c #BBBDAF\",\n\"5 c #BCBEB0\",\n\"6 c #BDBFB1\",\n\"7 c #BEC1B0\",\n\"8 c #BEC0B2\",\n\"9 c #BFC1B3\",\n\"0 c #BFC2B1\",\n\"q c #C1C4B3\",\n\"w c #C4C7B6\",\n\"e c #C5C8B7\",\n\"r c #CDD0BF\",\n\"t c #CDCFC1\",\n\"y c #D0D3C2\",\n\"u c #D8DBC8\",\n\"i c #DADDCC\",\n\"p c #DBDECD\",\n\"a c #DDE0CF\",\n\"s c #E0E3D2\",\n\"d c #E2E5D2\",\n\"f c #E3E6D3\",\n\"g c #E4E7D4\",\n\"h c #E5E8D3\",\n\"j c #E5E8D5\",\n\"k c #E5E8D7\",\n\"l c #E6E9D4\",\n\"z c #E6E9D6\",\n\"x c #E7EAD5\",\n\"c c #E7EAD7\",\n\"v c #E6E9D8\",\n\"b c #E7E9DB\",\n\"n c #E7EAD9\",\n\"m c #E8EBD6\",\n\"M c #E9ECD7\",\n\"N c #E9EDD6\",\n\"B c #EAEED7\",\n\"V c #E8EBD8\",\n\"C c #E8EBDA\",\n\"Z c #E9EBDD\",\n\"A c #E9ECD9\",\n\"S c #E9ECDB\",\n\"D c #EAEDD8\",\n\"F c #EAEDDA\",\n\"G c #EBEED9\",\n\"H c #EBEEDB\",\n\"J c #EAEDDC\",\n\"K c #EBEEDD\",\n\"L c #ECEFDA\",\n\"P c #ECEFDC\",\n\"I c #ECEFDE\",\n\"U c #EDF0DD\",\n\"Y c #EDF0DF\",\n\"T c #EEF1DC\",\n\"R c #EEF1DE\",\n\"E c #EFF2DF\",\n/* pixels */\n\"VVFcFcVVmmmchmmmFmcFmNBl\",\n\"FFFcFFFFVVcFUcFFFFmmcGhU\",\n\"VFFVVFFVcUFFgcFFcnFFhmmB\",\n\"FFVFcFFVFccFFFcFFFFcUmxm\",\n\"FVcFcVVFFnUcFVFVFcFNcNmm\",\n\"cFFFFVVFFcFFmVFcnBcFFNUc\",\n\"cFFdUVFcF** :@X:*-*#FFmF\",\n\"FFVuVcFVF*F<VnUnn*c-cFnn\",\n\"mFN80inJZ+$-FcFFS.2.UnnF\",\n\"Bmn088wpb,J*dUmmU:S:gnUf\",\n\"mNJ9,<<:e..*BcBmn$-XUFNU\",\n\"cFJ,<58yn-J-FUcFn:c*NnFg\",\n\"Fcn88tsFF-X*ccJcn-*:ccFF\",\n\"cUnraFnnc:F*FFcFJ*n$FFmc\",\n\"UcnFFnmBF*# *--*-.:*cFcF\",\n\"hFNFNNBmFncUFnnFnUncFnFc\",\n\"FmnFmnFmFnFFnFFnFmnFmnFm\",\n\"FFFFFFFFFmmFFmFmFFFFFFFF\",\n\"nFFmFnnFnFFnFmFFnFFmFnnF\",\n\"FmnFmFFmFFmFnFFnFmnFmFFm\",\n\"nFFmFFnFnFmFFFmFnFFmFFnF\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/stepback.xpm",
    "content": "/* XPM */\nconst static char *stepback[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 139 2\",\n\"   c black\",\n\".  c black\",\n\"X  c black\",\n\"o  c black\",\n\"O  c black\",\n\"+  c black\",\n\"@  c black\",\n\"#  c black\",\n\"$  c black\",\n\"%  c black\",\n\"&  c black\",\n\"*  c black\",\n\"=  c black\",\n\"-  c black\",\n\";  c black\",\n\":  c black\",\n\">  c black\",\n\",  c black\",\n\"<  c black\",\n\"1  c black\",\n\"2  c black\",\n\"3  c black\",\n\"4  c black\",\n\"5  c black\",\n\"6  c black\",\n\"7  c black\",\n\"8  c black\",\n\"9  c black\",\n\"0  c black\",\n\"q  c black\",\n\"w  c black\",\n\"e  c black\",\n\"r  c black\",\n\"t  c black\",\n\"y  c black\",\n\"u  c black\",\n\"i  c black\",\n\"p  c black\",\n\"a  c black\",\n\"s  c black\",\n\"d  c black\",\n\"f  c black\",\n\"g  c black\",\n\"h  c black\",\n\"j  c black\",\n\"k  c black\",\n\"l  c black\",\n\"z  c black\",\n\"x  c black\",\n\"c  c black\",\n\"v  c black\",\n\"b  c black\",\n\"n  c black\",\n\"m  c black\",\n\"M  c black\",\n\"N  c black\",\n\"B  c black\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n/* pixels */\n\"[ E ) $.$.$.X.@.O.2.$.E [ 2.$.O.X.$.[ +.$.) ) $.\",\n\"$.$.$.$.E E $.$.2.$.[ [ [ / $.t./ E $.w.U $.$.E \",\n\"+.+.X.$.q.$.$.E [ E / [ [ / [ U $.E / U $.) ) +.\",\n\"+.8.E $.E E X.$.2.2.f.X.X.2.X.g.E X.2.@.8.+.+.$.\",\n\"$.X.$.X.$.+.$.E q./ U [ $./ E $.E 2.@.2.J X.2./ \",\n\"E $.$.X.g.O.s.2.U w.U t.[ / w.E $.@.E E g.@.$.@.\",\n\"$.E E g.O - - O , X s 3 3 3 + h.$.X.$.$.U q.@.@.\",\n\"[ $.2.X.1 i.X j.$.@.O.f.$ f.$ 2.@.$.@.@.C Y $.@.\",\n\"2.E @.e.w - 0 @.@.$.$.E u O 0 *.@.*.Z m c f.E *.\",\n\"X.$./ X.w O.q X.( [ / q.+ e.0 @.A n x v x X.q.$.\",\n\"$.@.$.X.y - 3 e.O.d.O.l.2 0 p M f d k l f [ ! / \",\n\"@.Y / 2.+ O.q E ' ' [ / 0 *.+ F V x z l g X.[ $.\",\n\"@.$.' $.q - q X.E / $.@.+ - q *.i.D B b j *.@.O.\",\n\"2.J w.P + f.3 e.@.@.t.@.3 d.3 2.$.E X.S N E t.O.\",\n\"*.$.G q.0 1 0 O 4 0 + 0 a O i p./ @.2.O.O.' / f.\",\n\"*.$.( ! p.X.k.2./ $./ / f.^ *.H @.$.$.2.@.^ ^ / \",\n\"@.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.\",\n\"@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.\",\n\"$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.\",\n\"@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.\",\n\"@.$.@.$.$.@.$.@.$.@.$.@.@.$.@.$.@.$.@.$.$.@.$.@.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/stepbackA.xpm",
    "content": "/* XPM */\nconst static char *stepback[] = {\n/* columns rows colors chars-per-pixel */\n\"24 17 139 2\",\n\"   c #1D1F12\",\n\".  c #1E1F19\",\n\"X  c #1D1D1B\",\n\"o  c gray12\",\n\"O  c #1F2018\",\n\"+  c #1F201A\",\n\"@  c #212413\",\n\"#  c #202214\",\n\"$  c #212316\",\n\"%  c #222514\",\n\"&  c #222417\",\n\"*  c #212318\",\n\"=  c #20211B\",\n\"-  c #252719\",\n\";  c #20211C\",\n\":  c #21211F\",\n\">  c #23241C\",\n\",  c #23241F\",\n\"<  c #25271C\",\n\"1  c #26281A\",\n\"2  c #201E29\",\n\"3  c #202020\",\n\"4  c gray13\",\n\"5  c #222220\",\n\"6  c #232321\",\n\"7  c #232323\",\n\"8  c #242520\",\n\"9  c #252621\",\n\"0  c #242422\",\n\"q  c #232325\",\n\"w  c #222126\",\n\"e  c #232227\",\n\"r  c gray14\",\n\"t  c #252525\",\n\"y  c #252527\",\n\"u  c gray15\",\n\"i  c #212028\",\n\"p  c #23212C\",\n\"a  c #22202D\",\n\"s  c #282828\",\n\"d  c #30302E\",\n\"f  c gray21\",\n\"g  c #393A35\",\n\"h  c #383836\",\n\"j  c #3A3B36\",\n\"k  c #363638\",\n\"l  c #36353B\",\n\"z  c #3A3A3C\",\n\"x  c #3F3F3D\",\n\"c  c #40403E\",\n\"v  c #424146\",\n\"b  c #444444\",\n\"n  c #53544C\",\n\"m  c #4E4E50\",\n\"M  c #555553\",\n\"N  c #797A72\",\n\"B  c #7B7C76\",\n\"V  c #898989\",\n\"C  c #A0A390\",\n\"Z  c #ABACA6\",\n\"A  c #B3B4AC\",\n\"S  c #CACBC5\",\n\"D  c #CED0C5\",\n\"F  c #DFE1D3\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n/* pixels */\n\"+.+.X.$.q.$.$.E [ E / [ [ / [ U $.E / U $.) ) +.\",\n\"+.8.E $.E E X.$.2.2.f.X.X.2.X.g.E X.2.@.8.+.+.$.\",\n\"$.X.$.X.$.+.$.E q./ U [ $./ E $.E 2.@.2.J X.2./ \",\n\"E $.$.X.g.O.s.2.U w.U t.[ / w.E $.@.E E g.@.$.@.\",\n\"$.E E g.O - - O , X s 3 3 3 + h.$.X.$.$.U q.@.@.\",\n\"[ $.2.X.1 i.X j.$.@.O.f.$ f.$ 2.@.$.@.@.C Y $.@.\",\n\"2.E @.e.w - 0 @.@.$.$.E u O 0 *.@.*.Z m c f.E *.\",\n\"X.$./ X.w O.q X.( [ / q.+ e.0 @.A n x v x X.q.$.\",\n\"$.@.$.X.y - 3 e.O.d.O.l.2 0 p M f d k l f [ ! / \",\n\"@.Y / 2.+ O.q E ' ' [ / 0 *.+ F V x z l g X.[ $.\",\n\"@.$.' $.q - q X.E / $.@.+ - q *.i.D B b j *.@.O.\",\n\"2.J w.P + f.3 e.@.@.t.@.3 d.3 2.$.E X.S N E t.O.\",\n\"*.$.G q.0 1 0 O 4 0 + 0 a O i p./ @.2.O.O.' / f.\",\n\"*.$.( ! p.X.k.2./ $./ / f.^ *.H @.$.$.2.@.^ ^ / \",\n\"@.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.\",\n\"@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.\",\n\"$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.$.@.\",\n};\n"
  },
  {
    "path": "apps/vaporgui/images/stepfwd.xpm",
    "content": "/* XPM */\nconst static char *stepfwd[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 139 2\",\n\"   c black\",\n\".  c black\",\n\"X  c black\",\n\"o  c black\",\n\"O  c black\",\n\"+  c black\",\n\"@  c black\",\n\"#  c black\",\n\"$  c black\",\n\"%  c black\",\n\"&  c black\",\n\"*  c black\",\n\"=  c black\",\n\"-  c black\",\n\";  c black\",\n\":  c black\",\n\">  c black\",\n\",  c black\",\n\"<  c black\",\n\"1  c black\",\n\"2  c black\",\n\"3  c black\",\n\"4  c black\",\n\"5  c black\",\n\"6  c black\",\n\"7  c black\",\n\"8  c black\",\n\"9  c black\",\n\"0  c black\",\n\"q  c black\",\n\"w  c black\",\n\"e  c black\",\n\"r  c black\",\n\"t  c black\",\n\"y  c black\",\n\"u  c black\",\n\"i  c black\",\n\"p  c black\",\n\"a  c black\",\n\"s  c black\",\n\"d  c black\",\n\"f  c black\",\n\"g  c black\",\n\"h  c black\",\n\"j  c black\",\n\"k  c black\",\n\"l  c black\",\n\"z  c black\",\n\"x  c black\",\n\"c  c black\",\n\"v  c black\",\n\"b  c black\",\n\"n  c black\",\n\"m  c black\",\n\"M  c black\",\n\"N  c black\",\n\"B  c black\",\n\"V  c black\",\n\"C  c black\",\n\"Z  c black\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n/* pixels */\n\";.Q  .;.' ' ;.' 2.;.;.' Q ;.6.$.+.;.6.;.%.;.Q ;.\",\n\"Q ;.;.P e.;.Q  .6.%.E  . .' Q 6.' ;.Q Q ' ;. .;.\",\n\";.Q  .;.Q  .P ;.Q ;. .{ {  . .{ E ;.' t.;.+.+.+.\",\n\";.%.%.q.+.;.+.;.d.+.%.$.+.d.6.$.e.' ' Q Q ;.r.;.\",\n\"+.;.Q L 6.;.6.+. .E ' ;.;.E  .{ +.6.;.;.&.&.+.;.\",\n\"%.;.;.d.+.Q %.;.E e. .Q ;.P e.Q 6.u.+.d.Q &.;.Q \",\n\"%.%.q.L ;.6.+.+.f.0 y y 5 g . r @ # , O d.+.Y ;.\",\n\"%.6.Q S +.;.%.;.&.% u.# 6.u.&.6.k.@ u.1 +.e.;.' \",\n\"6.Q 6.b B D 6.&.$.0 O u Q  .;.Q ;.y @ s 6.' ' ;.\",\n\";.e.+.b m b N F +.q 6.@ e. .`  .&.o d.s +.e.&.&.\",\n\"Q ' ;.j c x h j V d 0 3 l.o.u.6.6.5 O p Q Q ;.' \",\n\";. .+.k c v b A J @ $.0 ' ' {  .;.u u.o ;.e.+.6.\",\n\"5.;.5.z M Z H u.5.s 2 5 ;.e.&.' +.0 # y Q ` +.+.\",\n\"+.r.Q C G $.Q 6.&.@ t.@ +.r.&.' d.o u.0 ' w.&.;.\",\n\"6.(  .5.$.6. .' f.a @ f , , 0 y & o 2 @ { ' &.&.\",\n\"' { ) ' 6.;. .' K 6.{ u.( ' ;.Q +.k.5.k.( U e.&.\",\n\"&.;.&.&.;.;.&.&.;.&.' &.;.&.' ;.&.&.;.&.' &.;.&.\",\n\"&.&.;.' &.' &.;.&.&.;.&.;.' &.;.&.;.&.&.;.&.;.' \",\n\";.;.&.&.' &.' ;.' ;.&.;.&.&.' &.' &.;.;.&.;.&.&.\",\n\"&.' &.;.;.;.&.&.&.;.&.' &.;.;.&.;.&.&.' &.' &.;.\",\n\"&.&.;.' &.&.;.&.&.&.;.&.;.' &.;.&.;.&.&.;.&.' ;.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/stepfwdA.xpm",
    "content": "/* XPM */\nconst static char *stepfwd[] = {\n/* columns rows colors chars-per-pixel */\n\"24 17 139 2\",\n\"   c #1D1F12\",\n\".  c #1E1E1C\",\n\"X  c #1F1F1D\",\n\"o  c gray12\",\n\"O  c #1F2113\",\n\"+  c #1F2018\",\n\"@  c #1F201A\",\n\"#  c #212316\",\n\"$  c #202217\",\n\"%  c #222514\",\n\"&  c #252817\",\n\"*  c #20211B\",\n\"=  c #22231B\",\n\"-  c #242619\",\n\";  c #252719\",\n\":  c #20211C\",\n\">  c #20201E\",\n\",  c #22231E\",\n\"<  c #23241F\",\n\"1  c #25271C\",\n\"2  c #26281A\",\n\"3  c #201E29\",\n\"4  c #202020\",\n\"5  c gray13\",\n\"6  c #222220\",\n\"7  c #232321\",\n\"8  c #222222\",\n\"9  c #232323\",\n\"0  c #242520\",\n\"q  c #252621\",\n\"w  c #242422\",\n\"e  c #252523\",\n\"r  c #262722\",\n\"t  c #232227\",\n\"y  c gray14\",\n\"u  c #252525\",\n\"i  c #242426\",\n\"p  c #252527\",\n\"a  c #222129\",\n\"s  c #242328\",\n\"d  c #23212E\",\n\"f  c #25232E\",\n\"g  c #282828\",\n\"h  c #30302E\",\n\"j  c gray21\",\n\"k  c #393A35\",\n\"l  c #383836\",\n\"z  c #3A3B36\",\n\"x  c #363638\",\n\"c  c #36353B\",\n\"v  c #3A3A3C\",\n\"b  c #3F3F3D\",\n\"n  c #40403E\",\n\"m  c #424146\",\n\"M  c #444444\",\n\"N  c #53544C\",\n\"B  c #4E4E50\",\n\"V  c #565654\",\n\"C  c #797A72\",\n\"Z  c #7B7C76\",\n\"A  c #898989\",\n\"S  c #A0A390\",\n\"D  c #ABACA6\",\n\"F  c #B3B4AC\",\n\"G  c #CACBC5\",\n\"H  c #CED0C5\",\n\"J  c #DFE1D3\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n/* pixels */\n\";.Q  .;.Q  .P ;.Q ;. .{ {  . .{ E ;.' t.;.+.+.+.\",\n\";.%.%.q.+.;.+.;.d.+.%.$.+.d.6.$.e.' ' Q Q ;.r.;.\",\n\"+.;.Q L 6.;.6.+. .E ' ;.;.E  .{ +.6.;.;.&.&.+.;.\",\n\"%.;.;.d.+.Q %.;.E e. .Q ;.P e.Q 6.u.+.d.Q &.;.Q \",\n\"%.%.q.L ;.6.+.+.f.0 y y 5 g . r @ # , O d.+.Y ;.\",\n\"%.6.Q S +.;.%.;.&.% u.# 6.u.&.6.k.@ u.1 +.e.;.' \",\n\"6.Q 6.b B D 6.&.$.0 O u Q  .;.Q ;.y @ s 6.' ' ;.\",\n\";.e.+.b m b N F +.q 6.@ e. .`  .&.o d.s +.e.&.&.\",\n\"Q ' ;.j c x h j V d 0 3 l.o.u.6.6.5 O p Q Q ;.' \",\n\";. .+.k c v b A J @ $.0 ' ' {  .;.u u.o ;.e.+.6.\",\n\"5.;.5.z M Z H u.5.s 2 5 ;.e.&.' +.0 # y Q ` +.+.\",\n\"+.r.Q C G $.Q 6.&.@ t.@ +.r.&.' d.o u.0 ' w.&.;.\",\n\"6.(  .5.$.6. .' f.a @ f , , 0 y & o 2 @ { ' &.&.\",\n\"' { ) ' 6.;. .' K 6.{ u.( ' ;.Q +.k.5.k.( U e.&.\",\n\"&.;.&.&.;.;.&.&.;.&.' &.;.&.' ;.&.&.;.&.' &.;.&.\",\n\"&.&.;.' &.' &.;.&.&.;.&.;.' &.;.&.;.&.&.;.&.;.' \",\n\";.;.&.&.' &.' ;.' ;.&.;.&.&.' &.' &.;.;.&.;.&.&.\",\n};\n"
  },
  {
    "path": "apps/vaporgui/images/tiles.xpm",
    "content": "/* XPM */\nconst static char *tiles[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 142 2\",\n\"   c black\",\n\".  c #000100\",\n\"X  c #010100\",\n\"o  c #000002\",\n\"O  c #010103\",\n\"+  c #000200\",\n\"@  c #010200\",\n\"#  c #010300\",\n\"$  c #000004\",\n\"%  c #000005\",\n\"&  c #010005\",\n\"*  c #000007\",\n\"=  c #010006\",\n\"-  c #020106\",\n\";  c #020107\",\n\":  c #020204\",\n\">  c #020400\",\n\",  c #030400\",\n\"<  c #030500\",\n\"1  c #030600\",\n\"2  c #040500\",\n\"3  c #040600\",\n\"4  c #050700\",\n\"5  c #060701\",\n\"6  c #060702\",\n\"7  c #040404\",\n\"8  c #050507\",\n\"9  c #020109\",\n\"0  c #030208\",\n\"q  c #04020D\",\n\"w  c #05030E\",\n\"e  c #05040A\",\n\"r  c #05040C\",\n\"t  c #07060C\",\n\"y  c #08070D\",\n\"u  c #08070F\",\n\"i  c #080901\",\n\"p  c #090B00\",\n\"a  c #080904\",\n\"s  c #090907\",\n\"d  c #0A0B05\",\n\"f  c #0D0F04\",\n\"g  c #08080A\",\n\"h  c #0A0A0C\",\n\"j  c #050213\",\n\"k  c #0D0C12\",\n\"l  c #10100E\",\n\"z  c #181A0D\",\n\"x  c gray7\",\n\"c  c #121116\",\n\"v  c #151419\",\n\"b  c #191A14\",\n\"n  c #1D1D1B\",\n\"m  c #28282A\",\n\"M  c none\",\n\"N  c none\",\n\"B  c none\",\n\"V  c none\",\n\"C  c none\",\n\"Z  c none\",\n\"A  c none\",\n\"S  c none\",\n\"D  c none\",\n\"F  c none\",\n\"G  c none\",\n\"H  c none\",\n\"J  c none\",\n\"K  c none\",\n\"L  c none\",\n\"P  c none\",\n\"I  c none\",\n\"U  c none\",\n\"Y  c none\",\n\"T  c none\",\n\"R  c none\",\n\"E  c none\",\n\"W  c none\",\n\"Q  c none\",\n\"!  c none\",\n\"~  c none\",\n\"^  c none\",\n\"/  c none\",\n\"(  c none\",\n\")  c none\",\n\"_  c none\",\n\"`  c none\",\n\"'  c none\",\n\"]  c none\",\n\"[  c none\",\n\"{  c none\",\n\"}  c none\",\n\"|  c none\",\n\" . c none\",\n\".. c none\",\n\"X. c none\",\n\"o. c none\",\n\"O. c none\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n\"z. c none\",\n\"x. c none\",\n\"c. c none\",\n/* pixels */\n\"..^ [ [ Y ;.Y K [ h.;.! [ #.J h.#.[ Y ;.;.Y ....\",\n\";.Y [ ;.;.! #.-.[ R M c.B [ ( ;.R ;.;.J Y ;.Y ;.\",\n\";.Y ;.R h.h.X.#.( #.[ h.[ R  ...#.R ..l.Y #.;.[ \",\n\"R Y ;.#.i 2 X X X t X w X = X = z X X ! ! J [ J \",\n\"R #...a.2 x.! X.K R r.X [ V [ ;.R l.b u.r.-.^ ;.\",\n\";.J X.a.X u.l.[ ;.! R X [ #.^ #.;.a.X a.#.M -...\",\n\"[ ^ ;...X l.;.J ( ;.X.h Y X.( ;.( ..X a.;. .V [ \",\n\"[ ^ ;.#.5 #.Y 4.[ #.X.n ..h...X.[ ;.X a.;.( [ ;.\",\n\"#.Y Y ;.X ;.[ ;.#.Y ;.X [ Y Y #.#.r.= ;.;.J ^ ;.\",\n\"Y [ [ J X R ;.#.h.#.R 8 J ;.;.#.#.X.j [ Y q.J Y \",\n\"Y -.J ;.9 < 5 X m X l j X 5 5 X < X e [ ;.J -.[ \",\n\"[ [ ;.r.= h.;.h.c.J ;.X ;.R  .#.;...= ^ #.[ Y #.\",\n\"#.#.R R 9 ;.[ Y J  .;.x K -.J [ ^ #.k ;.;.V ;.^ \",\n\"X.! l.Z = ;.( [ X.#.h.q #.#.R #.^ [ X ^ ..[ ;...\",\n\";.J #.R 9 ;.J ;.r.M ;.X -.J  .J -.;.= ( ^ [ J ..\",\n\"( [ Y ;.t R ;.R Y ;.#.= ;.;.[ ;.^ ..v ;.^ ^ ;.;.\",\n\"[ ;.X.a.< #.[ ( [ [ #.X c.R ;.( #.#.f X.R [ ;...\",\n\"[ Y ! S e c = = t X = 9 = = = g h < X d.h.Y [ ..\",\n\"[ Y ^ ;.R ;.Y ;.;.Y ;...;.R ;.R N  .Y [ [ K ^ ;.\",\n\"..;.;.^ [ ;.Y [ ..[ ^ Y J ;.J ;.#...l.R ^ [ [ ..\",\n\"R ;.;.Y Y ;.[ [ ;.[ ^ [ J Y ;...#.R l...^ [ [ ..\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/tobeginA.xpm",
    "content": "/* XPM */\nstatic const char *toBegin_[] = {\n/* columns rows colors chars-per-pixel */\n\"24 17 91 1\",\n\"  c black\",\n\". c #000100\",\n\"X c #010100\",\n\"o c #010101\",\n\"O c #000200\",\n\"+ c #010200\",\n\"@ c #030301\",\n\"# c #010103\",\n\"$ c #000005\",\n\"% c #020106\",\n\"& c #353535\",\n\"* c #363634\",\n\"= c #373833\",\n\"- c #353439\",\n\"; c #363638\",\n\": c #35343A\",\n\"> c #393939\",\n\", c #3B3B39\",\n\"< c #3E3E3C\",\n\"1 c #3E3E3E\",\n\"2 c gray25\",\n\"3 c #424240\",\n\"4 c #424244\",\n\"5 c #4B4B4D\",\n\"6 c #4E4E4E\",\n\"7 c #565656\",\n\"8 c #7B7C74\",\n\"9 c #7D7D7B\",\n\"0 c gray53\",\n\"q c #9FA193\",\n\"w c #AFAFAD\",\n\"e c #B2B3AD\",\n\"r c #C9CAC4\",\n\"t c #CBCCC4\",\n\"y c #D8D9D4\",\n\"u c #DDDED9\",\n\"i c none\",\n\"p c none\",\n\"a c none\",\n\"s c none\",\n\"d c none\",\n\"f c none\",\n\"g c none\",\n\"h c none\",\n\"j c none\",\n\"k c none\",\n\"l c none\",\n\"z c none\",\n\"x c none\",\n\"c c none\",\n\"v c none\",\n\"b c none\",\n\"n c none\",\n\"m c none\",\n\"M c none\",\n\"N c none\",\n\"B c none\",\n\"V c none\",\n\"C c none\",\n\"Z c none\",\n\"A c none\",\n\"S c none\",\n\"D c none\",\n\"F c none\",\n\"G c none\",\n\"H c none\",\n\"J c none\",\n\"K c none\",\n\"L c none\",\n\"P c none\",\n\"I c none\",\n\"U c none\",\n\"Y c none\",\n\"T c none\",\n\"R c none\",\n\"E c none\",\n\"W c none\",\n\"Q c none\",\n\"! c none\",\n\"~ c none\",\n\"^ c none\",\n\"/ c none\",\n\"( c none\",\n\") c none\",\n\"_ c none\",\n\"` c none\",\n\"' c none\",\n\"] c none\",\n\"[ c none\",\n\"{ c none\",\n\"} c none\",\n/* pixels */\n\"GGGGGGGGBkBvvGTGvvMLMfMh\",\n\"GGGGGGGGvGgBvvLGLLvAJMMM\",\n\"GGGGGGGGLAMMMvLkvGLvkLfk\",\n\"GGGGGGGGWGLLvLGLTkTLkMvL\",\n\"GGGGGGGGXXAkMfLka[kMLMkv\",\n\"GGGGGGGGXXYLMMvLqkTkLvkv\",\n\"GGGGGGGGXXLs)'w53GvvvGv]\",\n\"GGGGGGGGXX']e6121WvL^vv]\",\n\"GGGGGGGGXXy7:;;&&WBGiBLv\",\n\"GGGGGGGG$X{u04;>,]vGGvBM\",\n\"GGGGGGGG$XWvWr93=GGkWBsG\",\n\"GGGGGGGG$XalGGVr8aBvCBBG\",\n\"GGGGGGGGXXLBvG^C'Bs^WGBC\",\n\"GGGGGGGG`WCGGkvBWlbaWWkW\",\n\"GGGGGGGGGGGGGGGGGGGGGGGG\",\n\"GGGGGGGGGGGGGGGGGGGGGGGG\",\n\"GGGGGGGGGGGGGGGGGGGGGGGG\",\n};\n"
  },
  {
    "path": "apps/vaporgui/images/toendA.xpm",
    "content": "/* XPM */\nstatic const char *toEnd_[] = {\n/* columns rows colors chars-per-pixel */\n\"24 17 91 1\",\n\"  c black\",\n\". c #000100\",\n\"X c #010100\",\n\"o c #010101\",\n\"O c #000200\",\n\"+ c #010200\",\n\"@ c #030301\",\n\"# c #010103\",\n\"$ c #000005\",\n\"% c #020106\",\n\"& c #353535\",\n\"* c #363634\",\n\"= c #373833\",\n\"- c #353439\",\n\"; c #363638\",\n\": c #35343A\",\n\"> c #393939\",\n\", c #3B3B39\",\n\"< c #3E3E3C\",\n\"1 c #3E3E3E\",\n\"2 c gray25\",\n\"3 c #424240\",\n\"4 c #424244\",\n\"5 c #4B4B4D\",\n\"6 c #4E4E4E\",\n\"7 c #565656\",\n\"8 c #7B7C74\",\n\"9 c #7D7D7B\",\n\"0 c gray53\",\n\"q c #9FA193\",\n\"w c #AFAFAD\",\n\"e c #B2B3AD\",\n\"r c #C9CAC4\",\n\"t c #CBCCC4\",\n\"y c #D8D9D4\",\n\"u c #DDDED9\",\n\"i c none\",\n\"p c none\",\n\"a c none\",\n\"s c none\",\n\"d c none\",\n\"f c none\",\n\"g c none\",\n\"h c none\",\n\"j c none\",\n\"k c none\",\n\"l c none\",\n\"z c none\",\n\"x c none\",\n\"c c none\",\n\"v c none\",\n\"b c none\",\n\"n c none\",\n\"m c none\",\n\"M c none\",\n\"N c none\",\n\"B c none\",\n\"V c none\",\n\"C c none\",\n\"Z c none\",\n\"A c none\",\n\"S c none\",\n\"D c none\",\n\"F c none\",\n\"G c none\",\n\"H c none\",\n\"J c none\",\n\"K c none\",\n\"L c none\",\n\"P c none\",\n\"I c none\",\n\"U c none\",\n\"Y c none\",\n\"T c none\",\n\"R c none\",\n\"E c none\",\n\"W c none\",\n\"Q c none\",\n\"! c none\",\n\"~ c none\",\n\"^ c none\",\n\"/ c none\",\n\"( c none\",\n\") c none\",\n\"_ c none\",\n\"` c none\",\n\"' c none\",\n\"] c none\",\n\"[ c none\",\n\"{ c none\",\n\"} c none\",\n/* pixels */\n\"MLivJGMMMLMhMJfvGGGGGGGG\",\n\"vMvJChGLMGMMvMvMGGGGGGGG\",\n\"MiLMaJGCMLvvvLMLGGGGGGGG\",\n\"JMMMJThQLLJfJLCTGGGGGGGG\",\n\"MMhGGC[ahLhLCSooGGGGGGGG\",\n\"MMMGGWaqLhvMWCooGGGGGGGG\",\n\"TMvCvvL25w`QfJooGGGGGGGG\",\n\"WMLWJhW1216e]TooGGGGGGGG\",\n\"C_vhLvT**;;:7yooGGGGGGGG\",\n\"GvvLLv}>>;40u{ooGGGGGGGG\",\n\"LfvQh)h=29tWCWo$GGGGGGGG\",\n\"hvLCMvp8rVWvcho$GGGGGGGG\",\n\"GLLW_fL'CWLvz)ooGGGGGGGG\",\n\"ThLGvvcWvvCCLhTSGGGGGGGG\",\n\"GGGGGGGGGGGGGGGGGGGGGGGG\",\n\"GGGGGGGGGGGGGGGGGGGGGGGG\",\n\"GGGGGGGGGGGGGGGGGGGGGGGG\",\n};\n"
  },
  {
    "path": "apps/vaporgui/images/twoDData.xpm",
    "content": "/* XPM */\nconst static char *twoDData[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 61 1\",\n\"  c #020201\",\n\". c #070801\",\n\"X c #0A0B04\",\n\"o c #0C0C0B\",\n\"O c #0F100A\",\n\"+ c #13140D\",\n\"@ c #131313\",\n\"# c #191A17\",\n\"$ c #1A1A18\",\n\"% c #1F201B\",\n\"& c  gray14\",\n\"* c #54564B\",\n\"= c #57594E\",\n\"- c #5B5C54\",\n\"; c #616358\",\n\": c #6C6D66\",\n\"> c #73756A\",\n\", c #7A7B73\",\n\"< c #80807E\",\n\"1 c #878882\",\n\"2 c #8E8F89\",\n\"3 c #95978C\",\n\"4 c #969791\",\n\"5 c #9A9C95\",\n\"6 c #9C9C9A\",\n\"7 c #A6A7A3\",\n\"8 c #ADAEA8\",\n\"9 c #C0C1BC\",\n\"0 c #C6C8BB\",\n\"q c #CACDBC\",\n\"w c  gray76\",\n\"e c #CDCFC2\",\n\"r c #CFD2C1\",\n\"t c #D1D4C5\",\n\"y c #D3D5CB\",\n\"u c #D7D9CA\",\n\"i c #D9DCCD\",\n\"p c  gray84\",\n\"a c #DBDCD3\",\n\"s c #DDDDDA\",\n\"d c #DFE1D3\",\n\"f c none\",\n\"g c none\",\n\"h c none\",\n\"j c none\",\n\"k c none\",\n\"l c none\",\n\"z c none\",\n\"x c none\",\n\"c c none\",\n\"v c none\",\n\"b c none\",\n\"n c none\",\n\"m c none\",\n\"M c none\",\n\"N c none\",\n\"B c none\",\n\"V c none\",\n\"C c none\",\n\"Z c none\",\n\"A c none\",\n/* pixels */\n\"llkggklnfkmmMuuljcjBcZaN\",\n\"llkkgklluVjeqZZMjVjlsjev\",\n\"lhllllkhllvtZ .NavaxZZbN\",\n\"lhzlllkjkfjVZ  AcNvjyyjd\",\n\"hhhhhzlkvjypN..ZxsvNvCAp\",\n\"hhghhllvvvZZA XAAbZAAACA\",\n\"hhgghlmMZ,   $o   oX  $8\",\n\"hhgfglMC-+ o  @@o. .@o s\",\n\"gfMgfiZ; .,bA  AbACAp$ A\",\n\"zlmrlZ*+ 2AwAo AspA7  7v\",\n\"ugvgZ=. :A6bA oAxA1Xo4Ax\",\n\"mBfn>$ 2A9ApwAAxZ5 o1NCj\",\n\"lyA5X jACCCbAAxA8. :ZsyN\",\n\"xZ:  %    @ &   .X:AaCyN\",\n\"vA   o .o  # $@. 3ZyZeiZ\",\n\"NpAZACCANAACA  CZMfZdnZu\",\n\"llllclkctVM0ZXXMlllllllc\",\n\"lkkllkllMqiMB XVllllllll\",\n\"lklkkllkzBBqBVVullllllll\",\n\"llllllllVimVfqglllllllll\",\n\"llllllllhtdVdlMmllllllll\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/twoDImage.xpm",
    "content": "/* XPM */\nconst static char *twoDImage[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 256 2\",\n\"   c #020401\",\n\".  c #0A0200\",\n\"X  c #020B00\",\n\"o  c #080607\",\n\"O  c #130003\",\n\"+  c #1D0101\",\n\"@  c #1B030E\",\n\"#  c #190906\",\n\"$  c #001200\",\n\"%  c #041604\",\n\"&  c #191A01\",\n\"*  c #1B1000\",\n\"=  c #000216\",\n\"-  c #0D0013\",\n\";  c #0F001B\",\n\":  c #140017\",\n\">  c #1B0116\",\n\",  c #1A0819\",\n\"<  c #031718\",\n\"1  c #121411\",\n\"2  c #1B171C\",\n\"3  c #230200\",\n\"4  c #2C0001\",\n\"5  c #20080E\",\n\"6  c #260708\",\n\"7  c #330000\",\n\"8  c #3A0002\",\n\"9  c #310F06\",\n\"0  c #27001C\",\n\"q  c #102B00\",\n\"w  c #073A0F\",\n\"e  c #1B3F1B\",\n\"r  c #34220E\",\n\"t  c #282909\",\n\"y  c #000324\",\n\"u  c #02022E\",\n\"i  c #0D062F\",\n\"p  c #050931\",\n\"a  c #160338\",\n\"s  c #041938\",\n\"d  c #171624\",\n\"f  c #240028\",\n\"g  c #2C0031\",\n\"h  c #36003E\",\n\"j  c #330032\",\n\"k  c #2C1132\",\n\"l  c #271428\",\n\"z  c #002928\",\n\"x  c #152522\",\n\"c  c #440002\",\n\"v  c #490000\",\n\"b  c #4B060B\",\n\"n  c #482C1E\",\n\"m  c #3A0041\",\n\"M  c #28005B\",\n\"N  c #2C1950\",\n\"B  c #002F51\",\n\"V  c #062746\",\n\"C  c #0F006C\",\n\"Z  c #1A0A66\",\n\"A  c #27006B\",\n\"S  c #2F0076\",\n\"D  c #410049\",\n\"F  c #451841\",\n\"G  c #451852\",\n\"H  c #54095C\",\n\"J  c #BD5866\",\n\"K  c #DB7F66\",\n\"L  c #CD707A\",\n\"P  c #D87B7A\",\n\"I  c #EE736C\",\n\"U  c #EC7677\",\n\"Y  c #F07B71\",\n\"T  c #F17A7C\",\n\"R  c #BC9279\",\n\"E  c #D28477\",\n\"W  c #C8847B\",\n\"Q  c #E98578\",\n\"!  c #F2F172\",\n\"~  c #F2EB66\",\n\"^  c #E279DE\",\n\"/  c #F87BE7\",\n\"(  c #5F98B3\",\n\")  c #18C1BC\",\n\"_  c #4BCCB6\",\n\"`  c #6DD4BF\",\n\"'  c #74C7AB\",\n\"]  c #64A5CD\",\n\"[  c #5FB8E2\",\n\"{  c #7CABE9\",\n\"}  c #6CBAE5\",\n\"|  c #7CB4E4\",\n\" . c #70A3F6\",\n\".. c #6EBAF6\",\n\"X. c #7CBEFC\",\n\"o. c #79BAF6\",\n\"O. c #1DCDCA\",\n\"+. c #3ED1CB\",\n\"@. c #2CF5EF\",\n\"#. c #5DCBCC\",\n\"$. c #4CD7CC\",\n\"%. c #53D5CD\",\n\"&. c #59D7D4\",\n\"*. c #6DCCC6\",\n\"=. c #7FC0DC\",\n\"-. c #6CDDD7\",\n\";. c #52E0D4\",\n\":. c #73E6D6\",\n\">. c #76E6DE\",\n\",. c #6AC1EE\",\n\"<. c #72C3F0\",\n\"1. c #59EFED\",\n\"2. c #43F6F3\",\n\"3. c #5EF7F4\",\n\"4. c #B48E99\",\n\"5. c #B68B85\",\n\"6. c #8F9EB5\",\n\"7. c #8BBBAF\",\n\"8. c #9EAFB9\",\n\"9. c #94B0BE\",\n\"0. c #9CA3A9\",\n\"q. c #DB8F82\",\n\"w. c #DF868A\",\n\"e. c #DD8491\",\n\"r. c #D6869F\",\n\"t. c #C68D8E\",\n\"y. c #E6878C\",\n\"u. c #E1919C\",\n\"i. c #FF9393\",\n\"p. c #FA858B\",\n\"a. c #CE98B0\",\n\"s. c #FC9AA7\",\n\"d. c #8FD4B5\",\n\"f. c #89CDB4\",\n\"g. c #DAE182\",\n\"h. c #FFFC87\",\n\"j. c #FFFE8A\",\n\"k. c #F6F58A\",\n\"l. c #FFFC95\",\n\"z. c #F6F998\",\n\"x. c #D9F2BB\",\n\"c. c #F5EEA6\",\n\"v. c #E6FAA8\",\n\"b. c #F9F9A6\",\n\"n. c #F5F9AE\",\n\"m. c #FAF8A9\",\n\"M. c #E6E7B4\",\n\"N. c #F2EFBC\",\n\"B. c #EFF5BD\",\n\"V. c #E9FBB4\",\n\"C. c #F4F4B7\",\n\"Z. c #80A3C9\",\n\"A. c #99B6DE\",\n\"S. c #85BCDA\",\n\"D. c #8EA7E0\",\n\"F. c #9EBAEC\",\n\"G. c #80A7F4\",\n\"H. c #9BA9FD\",\n\"J. c #9DBDF0\",\n\"K. c #9095CF\",\n\"L. c #CA86C9\",\n\"P. c #DA84C1\",\n\"I. c #D197CB\",\n\"U. c #E393D8\",\n\"Y. c #D591FE\",\n\"T. c #F88AE7\",\n\"R. c #EF8AF2\",\n\"E. c #FF8EF0\",\n\"W. c #E794FC\",\n\"Q. c #FA95F9\",\n\"!. c #EB90E6\",\n\"~. c #EFAAED\",\n\"^. c #FFA7E4\",\n\"/. c #8DE4DB\",\n\"(. c #86CEF4\",\n\"). c #9FC3F7\",\n\"_. c #91D2FC\",\n\"`. c #89C3EB\",\n\"'. c #A8CAE5\",\n\"]. c #BBC5FF\",\n\"[. c #B7DCFF\",\n\"{. c #9FF9F0\",\n\"}. c #9DF7EB\",\n\"|. c #A1EDEB\",\n\" X c none\",\n\".X c none\",\n\"XX c none\",\n\"oX c none\",\n\"OX c none\",\n\"+X c none\",\n\"@X c none\",\n\"#X c none\",\n\"$X c none\",\n\"%X c none\",\n\"&X c none\",\n\"*X c none\",\n\"=X c none\",\n\"-X c none\",\n\";X c none\",\n\":X c none\",\n\">X c none\",\n\",X c none\",\n\"<X c none\",\n\"1X c none\",\n\"2X c none\",\n\"3X c none\",\n\"4X c none\",\n\"5X c none\",\n\"6X c none\",\n\"7X c none\",\n\"8X c none\",\n\"9X c none\",\n\"0X c none\",\n\"qX c none\",\n\"wX c none\",\n\"eX c none\",\n\"rX c none\",\n\"tX c none\",\n\"yX c none\",\n\"uX c none\",\n\"iX c none\",\n\"pX c none\",\n\"aX c none\",\n\"sX c none\",\n\"dX c none\",\n\"fX c none\",\n\"gX c none\",\n\"hX c none\",\n\"jX c none\",\n\"kX c none\",\n\"lX c none\",\n\"zX c none\",\n\"xX c none\",\n\"cX c none\",\n\"vX c none\",\n\"bX c none\",\n\"nX c none\",\n\"mX c none\",\n\"MX c none\",\n\"NX c none\",\n\"BX c none\",\n\"VX c none\",\n\"CX c none\",\n\"ZX c none\",\n\"AX c none\",\n\"SX c none\",\n\"DX c none\",\n\"FX c none\",\n\"GX c none\",\n\"HX c none\",\n\"JX c none\",\n\"KX c none\",\n\"LX c none\",\n\"PX c none\",\n\"IX c none\",\n\"UX c none\",\n/* pixels */\n\"mX%X4X,Xx.1XwX#X6XUXDX@XCX;X2XM.VXFXfXJXCXOXqX2X\",\n\"%XSX4X$XwX;X#XZXPXlXtXUXDX  . VXiXsXHXFXuXIXOX<X\",\n\"8X8XrX0X3XBXmXdXvX[.J.D.K.a N I.r.^.L.pXsXiXIX9X\",\n\"0X3XVXCXuXGXlXF.| o.G.G.].A M W.T.T.T.!.U.I.@XFX\",\n\"3XAXCXuXGXzXF.| o...X. .H.C S W./ / Q.^ !.~.HXtX\",\n\"0X8XDXKXzXJ.| o.<...X.G.H.Z A Y.Q.E.R.R.Q.L.aXuX\",\n\"VXoXlXkX`.} <.,.] B V s i a N a h j H D m g k GX\",\n\"@XUXkXS.} ,...| s = 2 5 5 5 2 l > F f h G g > BX\",\n\"FXJXcXS.,.[ | s = + 4 7 7 4 + O + # 0 > : - O IX\",\n\"NXfXvX( (._.p y @ 7 Q Q K 7 7 R t.5.4.> , 2 . 3X\",\n\"nXLX9.'.] i u : 4 s.T I Y v c q.E W 3 ,     8XrX\",\n\"%XfX8.6.= i ; 6 r.J p.I T i.P P P c 6 < z f.#XCX\",\n\"PXfX0.d - - : a.t.u.y.y.y.L e.e.8 + o < *./.hX&X\",\n\"%X%X2 o o @ O + 3 7 3 4 7 b b 8 O 1 z #.+.%.vXZX\",\n\"mX  1 X   . . * * . r 3 n 6 9 # x < &.2.@.) xXdX\",\n\"6X    X     %   o & . X   t & X % -.3.O.2.1.XXbX\",\n\"8X5X4XqX>XC.b.l.h.j.k.z.v.q e f.:.;.$.&.>.|.kXPX\",\n\"5X5X-X>XB.n.z.j.j.~ ! k.v.% w ' _ $.>.{.xXjXfX6X\",\n\"-X-X-X<X>XB.n.b.k.l.k.g.V.$ $ d.` :.}..XbXjXNX8X\",\n\"=X=X-X5X-X-XN.C.c.m.b.m.V.$ $ *X X X.XgX%X6X0XSX\",\n\"=X=X-XqX8X8X5X:X:XC.M.M.2X1XeX*XjXhXjXZX0X5X3X:X\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/vapor-icon-32.xpm",
    "content": "/* XPM */\nconst static char *vapor_icon___[] = {\n/* columns rows colors chars-per-pixel */\n\"32 32 193 2\",\n\"   c #337771\",\n\".  c #D25F02\",\n\"X  c #D4670F\",\n\"o  c #DB7800\",\n\"O  c #D3710D\",\n\"+  c #E76507\",\n\"@  c #EE6B07\",\n\"#  c #E96B0F\",\n\"$  c #EF7804\",\n\"%  c #F17701\",\n\"&  c #EB6B14\",\n\"*  c #EA7315\",\n\"=  c #CE7F24\",\n\"-  c #DC7228\",\n\";  c #D07E36\",\n\":  c #D4793E\",\n\">  c #E77528\",\n\",  c #DD7844\",\n\"<  c #D57F49\",\n\"1  c #3CBF23\",\n\"2  c #79CD11\",\n\"3  c #AE9C01\",\n\"4  c #B2A000\",\n\"5  c #A4B703\",\n\"6  c #ACB90C\",\n\"7  c #BBB703\",\n\"8  c #B5A11C\",\n\"9  c #95AE2E\",\n\"0  c #84B835\",\n\"q  c #BBAA3F\",\n\"w  c #A3B83E\",\n\"e  c #B6B93F\",\n\"r  c #D98814\",\n\"t  c #F78D00\",\n\"y  c #F98B00\",\n\"u  c #E59300\",\n\"i  c #E8960B\",\n\"p  c #F29904\",\n\"a  c #E18015\",\n\"s  c #E59417\",\n\"d  c #F39C19\",\n\"f  c #C4A300\",\n\"g  c #C4AF0E\",\n\"h  c #CCBC00\",\n\"j  c #DFB60E\",\n\"k  c #DCBC13\",\n\"l  c #DDBC1A\",\n\"z  c #E3A503\",\n\"x  c #E8A404\",\n\"c  c #F5A000\",\n\"v  c #FAA600\",\n\"b  c #F4AF02\",\n\"n  c #ECB401\",\n\"m  c #EEBE04\",\n\"M  c #F9B700\",\n\"N  c #F6BD00\",\n\"B  c #E1A11A\",\n\"V  c #ECAC19\",\n\"C  c #F0AC1F\",\n\"Z  c #F2B417\",\n\"A  c #C2942E\",\n\"S  c #DE942F\",\n\"D  c #C09535\",\n\"F  c #EB8520\",\n\"G  c #E98A25\",\n\"H  c #E39323\",\n\"J  c #E79F22\",\n\"K  c #E99926\",\n\"L  c #E38C33\",\n\"P  c #E6873B\",\n\"I  c #E58E3B\",\n\"U  c #E99133\",\n\"Y  c #F19F34\",\n\"T  c #CDB624\",\n\"R  c #F5A020\",\n\"E  c #ECBF26\",\n\"W  c #F2AE33\",\n\"Q  c #81CA0B\",\n\"!  c #84CF19\",\n\"~  c #92CA12\",\n\"^  c #96DE1B\",\n\"/  c #A2DF01\",\n\"(  c #BCDC01\",\n\")  c #BCCD14\",\n\"_  c #9BE809\",\n\"`  c #A0E300\",\n\"'  c #A2EA0C\",\n\"]  c #93C138\",\n\"[  c #BDC03D\",\n\"{  c #CFCF01\",\n\"}  c #D4C302\",\n\"|  c #CDD303\",\n\" . c #C2DB02\",\n\".. c #CBDF02\",\n\"X. c #DED100\",\n\"o. c #D9DE02\",\n\"O. c #DBCC1C\",\n\"+. c #C4D712\",\n\"@. c #CCD11A\",\n\"#. c #E4CF01\",\n\"$. c #ECCD04\",\n\"%. c #EECB0B\",\n\"&. c #F4C30B\",\n\"*. c #F6CB08\",\n\"=. c #E4D400\",\n\"-. c #F0D403\",\n\";. c #E1CB13\",\n\":. c #E7CB18\",\n\">. c #F6C91B\",\n\",. c #C3E103\",\n\"<. c #D4E602\",\n\"1. c #D9E202\",\n\"2. c #DFD12B\",\n\"3. c #DDC133\",\n\"4. c #F7C527\",\n\"5. c #EAD33B\",\n\"6. c #F1D33A\",\n\"7. c #DF8842\",\n\"8. c #D5824D\",\n\"9. c #DB804C\",\n\"0. c #DE8552\",\n\"q. c #DA9D54\",\n\"w. c #E3844B\",\n\"e. c #E89D46\",\n\"r. c #E3885E\",\n\"t. c #E59550\",\n\"y. c #EA9352\",\n\"u. c #EB9E56\",\n\"i. c #C6B950\",\n\"p. c #C5B55E\",\n\"a. c #E2A04B\",\n\"s. c #EEB243\",\n\"d. c #F5B74F\",\n\"f. c #E9AA53\",\n\"g. c #EDA25F\",\n\"h. c #E2BE54\",\n\"j. c #D68A69\",\n\"k. c #E99463\",\n\"l. c #EA9A66\",\n\"z. c #E69770\",\n\"x. c #EC9A74\",\n\"c. c #E4997C\",\n\"v. c #DFA870\",\n\"b. c #EBAC6E\",\n\"n. c #E4B661\",\n\"m. c #F7B06C\",\n\"M. c #EDA473\",\n\"N. c #F2B473\",\n\"B. c #96C540\",\n\"V. c #DAC141\",\n\"C. c #D5C845\",\n\"Z. c #DDC55B\",\n\"A. c #F9C54F\",\n\"S. c #EDD544\",\n\"D. c #FBDB52\",\n\"F. c #F7C963\",\n\"G. c #18789C\",\n\"H. c #2F46AF\",\n\"J. c #ECA382\",\n\"K. c #F0AB81\",\n\"L. c #E8BD80\",\n\"P. c #F1B784\",\n\"I. c #EBBA94\",\n\"U. c #EDBBA4\",\n\"Y. c #F3BFAB\",\n\"T. c #EBCA95\",\n\"R. c #F7C19C\",\n\"E. c #DBD1A1\",\n\"W. c #EEC8AA\",\n\"Q. c #FACAA7\",\n\"!. c #F1C0B5\",\n\"~. c #F1CFB6\",\n\"^. c #FACEB2\",\n\"/. c #F5CEB8\",\n\"(. c #F8CBBB\",\n\"). c #F5C9C0\",\n\"_. c #F8CEC7\",\n\"`. c #F7D1C5\",\n\"'. c #FAD4C4\",\n\"]. c #FDD8C6\",\n\"[. c #F5D0C9\",\n\"{. c #F9D5CC\",\n\"}. c #FDDBCD\",\n\"|. c #FAD7D1\",\n\" X c #F6DAD3\",\n\".X c #FBDCD4\",\n\"XX c #FBDED9\",\n\"oX c #FDE0D5\",\n\"OX c #FDE3DD\",\n\"+X c #FDE6E2\",\n\"@X c #FEE9E4\",\n\"#X c #FEEDE8\",\n\"$X c None\",\n/* pixels */\n\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$Xl R $X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$XD f 2 G.$X$X$X\",\n\"$Xg b u 7.$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X8 h 5   H.1 $X\",\n\"$X$Xk N p s H r t.N.u.l.$X$X$X$X$X$X$X$X$X$X$X$Xp.6 7 3 4 5 $.D.\",\n\"$X$X$Xm i U L L a g.P.M.k.9., < $X$X$X$X$X$X$X$XT ,.( { -.4.F.$X\",\n\"$X$X$X:.n Y Q._.$XI y.J.$X$X$X$X8.0.c.$X[.OX).q.X.o.=.*.d.$X$X$X\",\n\"$X$X$XO.$.W $X]..X{.K.x.$X$X$X$X$X).`.{.$X.X[.e ,...*.d.$X$X$X$X\",\n\"$X$X$XC.#.f.oX@XXX$X$X$X$X$X$X$XOXOX.X`.$X{.E.^ ' 1.A.$X$X$X$X$X\",\n\"$X$X$X$X=.V R.$X$X+XXXXX.X$X$X$X.X{.{.$X$X(.e _ <.6.$X$X$X$X$X$X\",\n\"$X$X$X$X=.V m.].$X$X$X+XOXXX.XXXXXXX+X+X@Xv.| 1.6.$X$X$X$X$X$X$X\",\n\"$X$X$X$X;.s ^.^.+X$X$X$X+X@XXX$X$X$X$X$X$Xi.1.2.$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X5.z `.oX].OX$X$X$X$X+X+X$X$X$X$X$X@.) $X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$XS.n I.OX}.oX@X$X$X$X$X$X$X$X$X$XZ. .w $X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X&.a..XOXoXOX@X$X$X$X$X$X$X$XW.| ~ $X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X>.J /.OXOXOX@X@X$X$X$X$X$X Xh.` B.$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X4.b b.@X@X+X@X#X$X$X$X$X$XT.+.! $X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$XM K }.@X@X#X$X$X$X$X$X$XV.` 0 $X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$XZ c M.XX@X$X$X$X$X$X$XL.( Q $X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$Xs.v G W.+X$X$X$X$X$X~.3.` ] $X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$Xd t P _.+X$X$X$X$Xn.| ~ $X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$Xe.y $ z.{.+X$X$XU.j ( 9 $X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$XF % & r.!._.U.S =.6 $X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X* @ & , j.; x } q $X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X> & + X o u D $X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X$Xw.- X O = $X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\",\n\"$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X$X\"\n};\n"
  },
  {
    "path": "apps/vaporgui/images/wheel.xpm",
    "content": "/* XPM */\nconst static char *wheel[] = {\n/* columns rows colors chars-per-pixel */\n\"24 21 195 2\",\n\"   c black\",\n\".  c black\",\n\"X  c black\",\n\"o  c black\",\n\"O  c black\",\n\"+  c black\",\n\"@  c black\",\n\"#  c black\",\n\"$  c black\",\n\"%  c black\",\n\"&  c black\",\n\"*  c black\",\n\"=  c black\",\n\"-  c black\",\n\";  c black\",\n\":  c black\",\n\">  c black\",\n\",  c black\",\n\"<  c black\",\n\"1  c black\",\n\"2  c black\",\n\"3  c black\",\n\"4  c black\",\n\"5  c black\",\n\"6  c black\",\n\"7  c black\",\n\"8  c black\",\n\"9  c black\",\n\"0  c black\",\n\"q  c black\",\n\"w  c black\",\n\"e  c black\",\n\"r  c black\",\n\"t  c black\",\n\"y  c black\",\n\"u  c black\",\n\"i  c black\",\n\"p  c black\",\n\"a  c black\",\n\"s  c black\",\n\"d  c black\",\n\"f  c black\",\n\"g  c black\",\n\"h  c black\",\n\"j  c black\",\n\"k  c black\",\n\"l  c black\",\n\"z  c black\",\n\"x  c black\",\n\"c  c black\",\n\"v  c black\",\n\"b  c black\",\n\"n  c black\",\n\"m  c black\",\n\"M  c black\",\n\"N  c black\",\n\"B  c black\",\n\"V  c black\",\n\"C  c black\",\n\"Z  c black\",\n\"A  c black\",\n\"S  c black\",\n\"D  c black\",\n\"F  c black\",\n\"G  c black\",\n\"H  c black\",\n\"J  c black\",\n\"K  c black\",\n\"L  c black\",\n\"P  c black\",\n\"I  c black\",\n\"U  c black\",\n\"Y  c black\",\n\"T  c black\",\n\"R  c black\",\n\"E  c black\",\n\"W  c black\",\n\"Q  c black\",\n\"!  c black\",\n\"~  c black\",\n\"^  c black\",\n\"/  c black\",\n\"(  c black\",\n\")  c black\",\n\"_  c black\",\n\"`  c black\",\n\"'  c black\",\n\"]  c black\",\n\"[  c black\",\n\"{  c black\",\n\"}  c black\",\n\"|  c black\",\n\" . c black\",\n\".. c black\",\n\"X. c black\",\n\"o. c black\",\n\"O. c black\",\n\"+. c none\",\n\"@. c none\",\n\"#. c none\",\n\"$. c none\",\n\"%. c none\",\n\"&. c none\",\n\"*. c none\",\n\"=. c none\",\n\"-. c none\",\n\";. c none\",\n\":. c none\",\n\">. c none\",\n\",. c none\",\n\"<. c none\",\n\"1. c none\",\n\"2. c none\",\n\"3. c none\",\n\"4. c none\",\n\"5. c none\",\n\"6. c none\",\n\"7. c none\",\n\"8. c none\",\n\"9. c none\",\n\"0. c none\",\n\"q. c none\",\n\"w. c none\",\n\"e. c none\",\n\"r. c none\",\n\"t. c none\",\n\"y. c none\",\n\"u. c none\",\n\"i. c none\",\n\"p. c none\",\n\"a. c none\",\n\"s. c none\",\n\"d. c none\",\n\"f. c none\",\n\"g. c none\",\n\"h. c none\",\n\"j. c none\",\n\"k. c none\",\n\"l. c none\",\n\"z. c none\",\n\"x. c none\",\n\"c. c none\",\n\"v. c none\",\n\"b. c none\",\n\"n. c none\",\n\"m. c none\",\n\"M. c none\",\n\"N. c none\",\n\"B. c none\",\n\"V. c none\",\n\"C. c none\",\n\"Z. c none\",\n\"A. c none\",\n\"S. c none\",\n\"D. c none\",\n\"F. c none\",\n\"G. c none\",\n\"H. c none\",\n\"J. c none\",\n\"K. c none\",\n\"L. c none\",\n\"P. c none\",\n\"I. c none\",\n\"U. c none\",\n\"Y. c none\",\n\"T. c none\",\n\"R. c none\",\n\"E. c none\",\n\"W. c none\",\n\"Q. c none\",\n\"!. c none\",\n\"~. c none\",\n\"^. c none\",\n\"/. c none\",\n\"(. c none\",\n\"). c none\",\n\"_. c none\",\n\"`. c none\",\n\"'. c none\",\n\"]. c none\",\n\"[. c none\",\n\"{. c none\",\n\"}. c none\",\n\"|. c none\",\n\" X c none\",\n\".X c none\",\n\"XX c none\",\n\"oX c none\",\n\"OX c none\",\n\"+X c none\",\n\"@X c none\",\n\"#X c none\",\n\"$X c none\",\n\"%X c none\",\n\"&X c none\",\n/* pixels */\n\"H.b.b.u.D.u.c.D.H.5.g.D.u.D.D.f.D.u.g.b.D.u.D.f.\",\n\"b.u.U.g.s.s.D.4.g.F.D.4.c.g.g.D.4.D.D.D.u.H.b.g.\",\n\"c.D.s.+Xs.b.D.c.D.g.s.i  .b.D.c.b.D.D.f.f.s.u.F.\",\n\"q.D.s.oXN Q s.D.H.7.%Xg Y B.f.b.D.U.Q l f.D.F.q.\",\n\"c.u.U.f.b | oXf.] ) V _ t G T ] +Xs.b | f.s.c.v.\",\n\"c.g.D.b.+XB.a k Z X >.r r '.X Z b s oXf.H.D.g.u.\",\n\"c.D.D.3.H.oX( : % %.{.X : +.(.% : o.7.Q.3.D.q.b.\",\n\"b.b.u.F.H.U J % 2 X *.- X ).7 : 2 r Q b.D.D.D.H.\",\n\"c.D.c.D.oXA q '.X : X X : X X ; >.X F f.D.D.g.g.\",\n\"4.D.u.f.7.U >.>.-.: X X : X X %.}.%.Q B.H.b.g.D.\",\n\"D.c.H.i F ..X % X X : X X 9 X ; % X g b ` s.u.c.\",\n\"u.u.H.N b A X % X : 7 7 : e X X 9 7 g b a H.F.c.\",\n\"c.F.5.f..Xk `.%.%.: X X X X : `.`.#.] %Xf.b.b.g.\",\n\"u.4.Q.u.7.Q X (.: X X 9 7 X X : %.T ^ 2.~.u.g.H.\",\n\"f.q.c.F.g.i T % X : #.X X -.9 X X T f.D.q.F.b.H.\",\n\"b.D.c.<.F.f.D S 7 `.`.9 9 `.{.X X.g b.v.1.v.D.b.\",\n\"c.B.c.q.} T c.b G X `.X X %.X / D c.g / D.c.7.c.\",\n\"c.7.D.g.T s F.f.{ Y t G O.C J Z f.D.b T c.c.f.c.\",\n\"D.b.q.D.H.7.F.D.c.g.f.N l s.D.g.D.g.6.+Xg.c.D.u.\",\n\"g.c.c.g.f.D.u.c.q.~.f.b U +Xb.c.c.c.b.H.g.c.g.c.\",\n\"u.c.c.c.D.H.u.q.g.D.6.B.%Xb.u.c.u.D.b.b.g.c.c.c.\"\n};\n"
  },
  {
    "path": "apps/vaporgui/mac_helpers.h",
    "content": "#pragma once\n\nclass QWidget;\n\nbool MacIsDarkMode();\nvoid DisableMacFullscreen(QWidget *widget);\n"
  },
  {
    "path": "apps/vaporgui/mac_helpers.mm",
    "content": "#include \"mac_helpers.h\"\n#import <Foundation/Foundation.h>\n#import <AppKit/AppKit.h>\n#include <QWidget>\n\nbool MacIsDarkMode()\n{\n    NSString *appearanceName = [[NSAppearance currentAppearance] name];\n\treturn [appearanceName containsString:@\"Dark\"];\n}\n\nvoid DisableMacFullscreen(QWidget* widget) {\n    // Ensure native view exists\n    widget->winId();\n\n    NSView *nsView = (NSView *)widget->window()->winId();\n    if (![nsView isKindOfClass:[NSView class]]) return;\n\n    NSWindow *nsWindow = [nsView window];\n    if (!nsWindow) return;\n\n    // Remove fullscreen behavior\n    NSUInteger behavior = [nsWindow collectionBehavior];\n    behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;\n    [nsWindow setCollectionBehavior:behavior];\n\n    // Keep resizable, but disable fullscreen by overriding standardWindowButton\n    NSButton *zoomButton = [nsWindow standardWindowButton:NSWindowZoomButton];\n    [zoomButton setTarget:nil];\n    [zoomButton setAction:nil];\n}\n"
  },
  {
    "path": "apps/vaporgui/main.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tmain.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune 2004\n//\n//\tDescription:  Main program for vapor gui\n\n#include <cstdio>\n#include <cstdlib>\n#include <iostream>\n#include <cerrno>\n#include <qapplication.h>\n#include \"MainForm.h\"\n#include <qfont.h>\n#include <QMessageBox>\n#include <QFontDatabase>\n#include \"BannerGUI.h\"\n#include <vapor/Version.h>\n#include <vapor/CMakeConfig.h>\n#include <vapor/ResourcePath.h>\n#include <vapor/OptionParser.h>\n#include <vapor/FileUtils.h>\n#include <vapor/OSPRay.h>\n#include <vapor/SetHDF5PluginPath.h>\n#ifdef WIN32\n    #include \"Windows.h\"\n#endif\n\nusing namespace std;\nusing namespace VAPoR;\nusing namespace Wasp;\nvoid myMessageOutput(QtMsgType type, const char *msg)\n{\n    switch (type) {\n    case QtDebugMsg: break;\n    case QtWarningMsg: break;\n    case QtFatalMsg: break;\n    default:    // ignore QtCriticalMsg and QtSystemMsg\n        break;\n    }\n}\n\n//\n// Open a file named by the environment variable, path_var. Exit on failure\n//\nFILE *OpenLog(string path_var)\n{\n    FILE *      fp = NULL;\n    const char *cstr = getenv(path_var.c_str());\n    if (!cstr) return (NULL);\n    string s = cstr;\n    if (!s.empty()) {\n        fp = fopen(s.c_str(), \"w\");\n        if (!fp) {\n            cerr << \"Failed to open \" << s << \" : \" << strerror(errno) << endl;\n            exit(1);\n        }\n        MyBase::SetDiagMsgFilePtr(fp);\n    }\n    return (fp);\n}\n\nstruct opt_t {\n    OptionParser::Boolean_T    help;\n    OptionParser::Boolean_T    render;\n    OptionParser::IntRange_    renderRange;\n    OptionParser::Dimension2D_ resolution;\n    char *                     outputPath;\n    char *                     datasetType;\n} opt;\nOptionParser::OptDescRec_T set_opts[] = {{\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {\"render\", 0, \"\", \"Render a given session file and exit\"},\n                                         {\"timesteps\", 1, \"0:0\", \"Timesteps to render when using -render. Defaults to all timesteps.\"},\n                                         {\"resolution\", 1, \"1920x1080\", \"Output resolution when using -render\"},\n                                         {\"output\", 1, \"vapor.tiff\", \"Output image file when using -render. This will be suffixed with the timestep number. Supports tiff, jpg\"},\n                                         {\"ftype\", 1, \"auto\", \"Specify file format of datasets passed in command line. Valid options are: auto vdc wrf mpas dcp ugrid cf bov\"},\n                                         {NULL}};\nOptionParser::Option_T     get_options[] = {{\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"render\", Wasp::CvtToBoolean, &opt.render, sizeof(opt.render)},\n                                        {\"timesteps\", Wasp::CvtToIntRange, &opt.renderRange, sizeof(opt.renderRange)},\n                                        {\"resolution\", Wasp::CvtToDimension2D, &opt.resolution, sizeof(opt.resolution)},\n                                        {\"output\", Wasp::CvtToString, &opt.outputPath, sizeof(opt.outputPath)},\n                                        {\"ftype\", Wasp::CvtToString, &opt.datasetType, sizeof(opt.datasetType)},\n                                        {NULL}};\nconst char *               ProgName;\n\nQApplication *app;\nint           main(int argc, char **argv)\n{\n    OptionParser op;\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] [session.vs3] [data files...]\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    // Install our own message handler.\n    // Needed for SGI to avoid dithering:\n\n    // FILE *diagfp = OpenLog(\"VAPOR_DIAG_LOG\");\n    // FILE *errfp = OpenLog(\"VAPOR_ERR_LOG\");\n    FILE *diagfp = NULL;\n    FILE *errfp = NULL;\n    if (getenv(\"VAPOR_DEBUG\")) MyBase::SetDiagMsgFilePtr(stderr);\n\n#ifdef Darwin\n    if (!getenv(\"DISPLAY\")) setenv(\"DISPLAY\", \":0.0\", 0);\n#endif\n#ifdef Q_WS_X11\n    if (!getenv(\"DISPLAY\")) {\n        fprintf(stderr, \"Error:  X11 DISPLAY variable is not defined. %s \\n\", \"Vapor user interface requires X server to be available.\");\n        exit(-1);\n    }\n#endif\n\n#ifdef IRIX\n    QApplication::setColorSpec(QApplication::ManyColor);\n#endif\n\n    VOSP::Initialize(&argc, argv);\n\n    QApplication a(argc, argv, true);\n\n    // All C programs are run with the locale set to \"C\"\n    // Initalizing QApplication changes the locale to the system configuration\n    // which can cause problems if it is not supported.\n    // Udunits does not support it and vapor potentially does not either.\n    //\n    // https://www.gnu.org/software/libc/manual/html_node/Setting-the-Locale.html\n    // https://doc.qt.io/qt-5/qcoreapplication.html#locale-settings\n    //\n    setlocale(LC_ALL, \"C\");\n\n// For Mac and Linux, set the PYTHONHOME in this app\n#ifndef WIN32\n    const char *s = getenv(\"PYTHONHOME\");\n    string      phome = s ? s : \"\";\n    if (!phome.empty() && !getenv(\"PYTHONHOME_SET_BY_VAPOR\")) {\n        string msg(\"The PYTHONHOME variable is already specified as: \\n\");\n        msg += phome;\n        msg += \"\\n\";\n        msg += \"The VAPOR \";\n        msg += \"python\" + PYTHON_VERSION;\n        msg += \" environment will operate in this path\\n\";\n        msg += \" This path must be the location of a Python \";\n        msg += \"python\" + PYTHON_VERSION;\n        msg += \" installation\\n\";\n        msg += \"Unset the PYTHONHOME environment to revert to the installed \";\n        msg += \"VAPOR python\" + PYTHON_VERSION + \" environment.\";\n        QMessageBox::warning(0, \"PYTHONHOME warning\", msg.c_str()); // This does not work on Casper\n        printf(\"========  PYTHONHOME warning  ========\\n\");\n        printf(\"%s\\n\\n\", msg.c_str());\n    } else {\n        phome = GetPythonDir();\n        setenv(\"PYTHONHOME\", phome.c_str(), 1);\n        // We shouldnt be setting \"PYTHONHOME\" here but this is a temporary fix for relaunching vapor without extra warnings\n        setenv(\"PYTHONHOME_SET_BY_VAPOR\", \"\", 1);\n\n    }\n    MyBase::SetDiagMsg(\"PYTHONHOME = %s\", phome.c_str());\n#endif\n\n    VAPoR::SetHDF5PluginPath();\n\n    app = &a;\n\n    vector<QString> files;\n    for (int i = 1; i < argc; i++) { files.push_back(argv[i]); }\n    MainForm *mw = new MainForm(files, app, !opt.render, opt.datasetType);\n\n    // StartupParams* sParams = new StartupParams(0);\n\n    string fontFile = GetSharePath(\"fonts/arimo.ttf\");\n\n    QFontDatabase fdb;\n    fdb.addApplicationFont(QString::fromStdString(fontFile));\n    QStringList fonts = fdb.families();\n    QFont       f = fdb.font(\"Arimo\", \"normal\", 12);\n\n    const char *useFont = std::getenv(\"USE_SYSTEM_FONT\");\n    if (!useFont) { mw->setFont(f); }\n\n    string title = \"VAPOR \" + Version::GetVersionString() + \" (\" + Version::GetBuildHash() + \")\";\n    mw->setWindowTitle(title.c_str());\n    mw->show();\n    // Disable banner in debug build\n#ifdef NDEBUG\n    std::string banner_file_name = \"vapor_banner.png\";\n    BannerGUI   banner(mw, banner_file_name, 3000);\n#endif\n    a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));\n\n    int estatus = 0;\n    if (opt.render) { estatus = mw->RenderAndExit(opt.renderRange.min, opt.renderRange.max, opt.outputPath, opt.resolution.nx, opt.resolution.ny); }\n\n    if (estatus == 0) { estatus = a.exec(); }\n\n    VOSP::Shutdown();\n    if (diagfp) fclose(diagfp);\n    if (errfp) fclose(errfp);\n    exit(estatus);\n}\n"
  },
  {
    "path": "apps/vaporgui/plotWindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>PlotWindow</class>\n <widget class=\"QDialog\" name=\"PlotWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>885</width>\n    <height>651</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n   <property name=\"sizeConstraint\">\n    <enum>QLayout::SetMinimumSize</enum>\n   </property>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout\" stretch=\"0,0,0\">\n     <property name=\"sizeConstraint\">\n      <enum>QLayout::SetMinimumSize</enum>\n     </property>\n     <item>\n      <layout class=\"QVBoxLayout\" name=\"verticalLayout_5\">\n       <property name=\"rightMargin\">\n        <number>20</number>\n       </property>\n       <item>\n        <layout class=\"QHBoxLayout\" name=\"horizontalLayout_7\">\n         <property name=\"bottomMargin\">\n          <number>0</number>\n         </property>\n         <item>\n          <widget class=\"QLabel\" name=\"label_7\">\n           <property name=\"text\">\n            <string>Data Source:</string>\n           </property>\n          </widget>\n         </item>\n         <item>\n          <spacer name=\"horizontalSpacer_3\">\n           <property name=\"orientation\">\n            <enum>Qt::Horizontal</enum>\n           </property>\n           <property name=\"sizeHint\" stdset=\"0\">\n            <size>\n             <width>40</width>\n             <height>20</height>\n            </size>\n           </property>\n          </spacer>\n         </item>\n         <item>\n          <widget class=\"QComboBox\" name=\"dataMgrCombo\">\n           <property name=\"minimumSize\">\n            <size>\n             <width>150</width>\n             <height>0</height>\n            </size>\n           </property>\n          </widget>\n         </item>\n        </layout>\n       </item>\n       <item>\n        <widget class=\"QComboBox\" name=\"newVarCombo\"/>\n       </item>\n       <item>\n        <widget class=\"QComboBox\" name=\"removeVarCombo\"/>\n       </item>\n       <item>\n        <widget class=\"QLabel\" name=\"label\">\n         <property name=\"text\">\n          <string>Variables</string>\n         </property>\n        </widget>\n       </item>\n       <item>\n        <widget class=\"QTableWidget\" name=\"variablesTable\"/>\n       </item>\n       <item>\n        <widget class=\"FidelityWidget\" name=\"myFidelityWidget\" native=\"true\"/>\n       </item>\n      </layout>\n     </item>\n     <item>\n      <widget class=\"Line\" name=\"line\">\n       <property name=\"minimumSize\">\n        <size>\n         <width>5</width>\n         <height>0</height>\n        </size>\n       </property>\n       <property name=\"orientation\">\n        <enum>Qt::Vertical</enum>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QTabWidget\" name=\"spaceTimeTab\">\n       <property name=\"minimumSize\">\n        <size>\n         <width>0</width>\n         <height>0</height>\n        </size>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>16777215</width>\n         <height>16777215</height>\n        </size>\n       </property>\n       <property name=\"currentIndex\">\n        <number>0</number>\n       </property>\n       <widget class=\"QWidget\" name=\"spaceTab\">\n        <attribute name=\"title\">\n         <string>Space</string>\n        </attribute>\n        <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\">\n         <item>\n          <layout class=\"QHBoxLayout\" name=\"horizontalLayout_3\">\n           <property name=\"leftMargin\">\n            <number>20</number>\n           </property>\n           <item>\n            <widget class=\"QCheckBox\" name=\"xlock\">\n             <property name=\"text\">\n              <string>Lock X</string>\n             </property>\n            </widget>\n           </item>\n           <item>\n            <widget class=\"QCheckBox\" name=\"ylock\">\n             <property name=\"text\">\n              <string>Lock Y</string>\n             </property>\n            </widget>\n           </item>\n           <item>\n            <widget class=\"QCheckBox\" name=\"zlock\">\n             <property name=\"text\">\n              <string>Lock Z</string>\n             </property>\n            </widget>\n           </item>\n          </layout>\n         </item>\n         <item>\n          <widget class=\"QSinglePoint\" name=\"spaceTabP1\" native=\"true\"/>\n         </item>\n         <item>\n          <widget class=\"QSinglePoint\" name=\"spaceTabP2\" native=\"true\"/>\n         </item>\n         <item>\n          <widget class=\"QFrame\" name=\"timeStepSelectorFrame\">\n           <property name=\"frameShape\">\n            <enum>QFrame::StyledPanel</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Plain</enum>\n           </property>\n           <property name=\"lineWidth\">\n            <number>1</number>\n           </property>\n           <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n            <property name=\"spacing\">\n             <number>-1</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>12</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>12</number>\n            </property>\n            <item>\n             <widget class=\"QLabel\" name=\"timeStepLabel\">\n              <property name=\"text\">\n               <string>Select one time step:</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QSliderEdit\" name=\"spaceTabTimeSelector\" native=\"true\"/>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QFrame\" name=\"numOfSamplesFrame\">\n           <property name=\"frameShape\">\n            <enum>QFrame::StyledPanel</enum>\n           </property>\n           <property name=\"frameShadow\">\n            <enum>QFrame::Plain</enum>\n           </property>\n           <layout class=\"QHBoxLayout\" name=\"horizontalLayout_2\">\n            <item>\n             <widget class=\"QLabel\" name=\"numOfSamplesLabel\">\n              <property name=\"frameShape\">\n               <enum>QFrame::NoFrame</enum>\n              </property>\n              <property name=\"frameShadow\">\n               <enum>QFrame::Plain</enum>\n              </property>\n              <property name=\"text\">\n               <string>Number of samples between two points:  </string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QLineEdit\" name=\"numOfSamplesLineEdit\"/>\n            </item>\n           </layout>\n          </widget>\n         </item>\n         <item>\n          <widget class=\"QPushButton\" name=\"spaceTabPlotButton\">\n           <property name=\"text\">\n            <string>Plot</string>\n           </property>\n          </widget>\n         </item>\n        </layout>\n       </widget>\n       <widget class=\"QWidget\" name=\"timeTab\">\n        <attribute name=\"title\">\n         <string>Time</string>\n        </attribute>\n        <layout class=\"QVBoxLayout\" name=\"verticalLayout_4\">\n         <item>\n          <widget class=\"QSinglePoint\" name=\"timeTabSinglePoint\" native=\"true\"/>\n         </item>\n         <item>\n          <widget class=\"QRange\" name=\"timeTabTimeRange\" native=\"true\"/>\n         </item>\n         <item>\n          <widget class=\"QPushButton\" name=\"timeTabPlotButton\">\n           <property name=\"text\">\n            <string>Plot</string>\n           </property>\n          </widget>\n         </item>\n        </layout>\n       </widget>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>QSinglePoint</class>\n   <extends>QWidget</extends>\n   <header location=\"global\">QSinglePoint.h</header>\n   <container>1</container>\n  </customwidget>\n  <customwidget>\n   <class>FidelityWidget</class>\n   <extends>QWidget</extends>\n   <header>FidelityWidget.h</header>\n   <container>1</container>\n  </customwidget>\n  <customwidget>\n   <class>QRange</class>\n   <extends>QWidget</extends>\n   <header location=\"global\">QRange.h</header>\n   <container>1</container>\n  </customwidget>\n  <customwidget>\n   <class>QSliderEdit</class>\n   <extends>QWidget</extends>\n   <header location=\"global\">QSliderEdit.h</header>\n   <container>1</container>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "apps/vaporgui/statsWindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>StatsWindow</class>\n <widget class=\"QWidget\" name=\"StatsWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>1009</width>\n    <height>441</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"windowTitle\">\n   <string>Form</string>\n  </property>\n  <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n   <property name=\"sizeConstraint\">\n    <enum>QLayout::SetDefaultConstraint</enum>\n   </property>\n   <item>\n    <layout class=\"QHBoxLayout\" name=\"horizontalLayout_12\" stretch=\"0,0,0\">\n     <property name=\"sizeConstraint\">\n      <enum>QLayout::SetDefaultConstraint</enum>\n     </property>\n     <item>\n      <widget class=\"QWidget\" name=\"widget_3\" native=\"true\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <layout class=\"QVBoxLayout\" name=\"verticalLayout\">\n        <item>\n         <layout class=\"QVBoxLayout\" name=\"VariablesLayout\">\n          <property name=\"spacing\">\n           <number>0</number>\n          </property>\n          <property name=\"topMargin\">\n           <number>0</number>\n          </property>\n          <property name=\"bottomMargin\">\n           <number>10</number>\n          </property>\n          <item>\n           <widget class=\"QTableWidget\" name=\"VariablesTable\">\n            <property name=\"sizePolicy\">\n             <sizepolicy hsizetype=\"Minimum\" vsizetype=\"Minimum\">\n              <horstretch>1</horstretch>\n              <verstretch>1</verstretch>\n             </sizepolicy>\n            </property>\n            <property name=\"minimumSize\">\n             <size>\n              <width>500</width>\n              <height>120</height>\n             </size>\n            </property>\n            <attribute name=\"horizontalHeaderVisible\">\n             <bool>true</bool>\n            </attribute>\n            <attribute name=\"horizontalHeaderMinimumSectionSize\">\n             <number>21</number>\n            </attribute>\n            <attribute name=\"horizontalHeaderDefaultSectionSize\">\n             <number>129</number>\n            </attribute>\n            <attribute name=\"horizontalHeaderShowSortIndicator\" stdset=\"0\">\n             <bool>false</bool>\n            </attribute>\n            <attribute name=\"horizontalHeaderStretchLastSection\">\n             <bool>false</bool>\n            </attribute>\n            <attribute name=\"verticalHeaderVisible\">\n             <bool>false</bool>\n            </attribute>\n           </widget>\n          </item>\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"horizontalLayout\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>10</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QLabel\" name=\"label_5\">\n              <property name=\"text\">\n               <string>Data Source</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <spacer name=\"horizontalSpacer_8\">\n              <property name=\"orientation\">\n               <enum>Qt::Horizontal</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>40</width>\n                <height>20</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n            <item>\n             <widget class=\"QComboBox\" name=\"DataMgrCombo\">\n              <property name=\"minimumSize\">\n               <size>\n                <width>280</width>\n                <height>0</height>\n               </size>\n              </property>\n             </widget>\n            </item>\n           </layout>\n          </item>\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"horizontalLayout_9\">\n            <property name=\"leftMargin\">\n             <number>5</number>\n            </property>\n            <property name=\"topMargin\">\n             <number>5</number>\n            </property>\n            <property name=\"rightMargin\">\n             <number>5</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>5</number>\n            </property>\n            <item>\n             <layout class=\"QVBoxLayout\" name=\"verticalLayout_8\">\n              <property name=\"rightMargin\">\n               <number>10</number>\n              </property>\n              <item>\n               <widget class=\"QLabel\" name=\"label_4\">\n                <property name=\"sizePolicy\">\n                 <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n                  <horstretch>0</horstretch>\n                  <verstretch>0</verstretch>\n                 </sizepolicy>\n                </property>\n                <property name=\"text\">\n                 <string>Variable Selection</string>\n                </property>\n                <property name=\"alignment\">\n                 <set>Qt::AlignCenter</set>\n                </property>\n               </widget>\n              </item>\n              <item>\n               <widget class=\"QComboBox\" name=\"NewVarCombo\">\n                <property name=\"insertPolicy\">\n                 <enum>QComboBox::InsertAlphabetically</enum>\n                </property>\n               </widget>\n              </item>\n              <item>\n               <widget class=\"QComboBox\" name=\"RemoveVarCombo\">\n                <property name=\"insertPolicy\">\n                 <enum>QComboBox::InsertAlphabetically</enum>\n                </property>\n               </widget>\n              </item>\n             </layout>\n            </item>\n            <item>\n             <widget class=\"Line\" name=\"line_5\">\n              <property name=\"orientation\">\n               <enum>Qt::Vertical</enum>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <layout class=\"QVBoxLayout\" name=\"verticalLayout_9\">\n              <property name=\"leftMargin\">\n               <number>10</number>\n              </property>\n              <item>\n               <widget class=\"QLabel\" name=\"label_3\">\n                <property name=\"sizePolicy\">\n                 <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Maximum\">\n                  <horstretch>0</horstretch>\n                  <verstretch>0</verstretch>\n                 </sizepolicy>\n                </property>\n                <property name=\"text\">\n                 <string>Statistic Selection</string>\n                </property>\n                <property name=\"alignment\">\n                 <set>Qt::AlignCenter</set>\n                </property>\n               </widget>\n              </item>\n              <item>\n               <widget class=\"QComboBox\" name=\"NewCalcCombo\">\n                <property name=\"insertPolicy\">\n                 <enum>QComboBox::InsertAlphabetically</enum>\n                </property>\n                <property name=\"duplicatesEnabled\">\n                 <bool>false</bool>\n                </property>\n               </widget>\n              </item>\n              <item>\n               <widget class=\"QComboBox\" name=\"RemoveCalcCombo\">\n                <property name=\"insertPolicy\">\n                 <enum>QComboBox::InsertAlphabetically</enum>\n                </property>\n                <property name=\"duplicatesEnabled\">\n                 <bool>true</bool>\n                </property>\n               </widget>\n              </item>\n             </layout>\n            </item>\n           </layout>\n          </item>\n         </layout>\n        </item>\n        <item>\n         <widget class=\"Line\" name=\"line_4\">\n          <property name=\"orientation\">\n           <enum>Qt::Horizontal</enum>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <widget class=\"FidelityWidget\" name=\"MyFidelityWidget\" native=\"true\">\n          <property name=\"sizePolicy\">\n           <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n            <horstretch>0</horstretch>\n            <verstretch>0</verstretch>\n           </sizepolicy>\n          </property>\n          <property name=\"minimumSize\">\n           <size>\n            <width>0</width>\n            <height>0</height>\n           </size>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <spacer name=\"verticalSpacer_2\">\n          <property name=\"orientation\">\n           <enum>Qt::Vertical</enum>\n          </property>\n          <property name=\"sizeType\">\n           <enum>QSizePolicy::Expanding</enum>\n          </property>\n          <property name=\"sizeHint\" stdset=\"0\">\n           <size>\n            <width>20</width>\n            <height>0</height>\n           </size>\n          </property>\n         </spacer>\n        </item>\n       </layout>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"Line\" name=\"line\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <property name=\"minimumSize\">\n        <size>\n         <width>3</width>\n         <height>3</height>\n        </size>\n       </property>\n       <property name=\"orientation\">\n        <enum>Qt::Vertical</enum>\n       </property>\n      </widget>\n     </item>\n     <item>\n      <widget class=\"QWidget\" name=\"widget_2\" native=\"true\">\n       <property name=\"sizePolicy\">\n        <sizepolicy hsizetype=\"Preferred\" vsizetype=\"Minimum\">\n         <horstretch>0</horstretch>\n         <verstretch>0</verstretch>\n        </sizepolicy>\n       </property>\n       <layout class=\"QVBoxLayout\" name=\"verticalLayout_2\" stretch=\"0,0,1,0,0\">\n        <property name=\"spacing\">\n         <number>12</number>\n        </property>\n        <item>\n         <widget class=\"Line\" name=\"line_2\">\n          <property name=\"minimumSize\">\n           <size>\n            <width>3</width>\n            <height>3</height>\n           </size>\n          </property>\n          <property name=\"orientation\">\n           <enum>Qt::Horizontal</enum>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <layout class=\"QVBoxLayout\" name=\"TimeLayout\" stretch=\"0,0,0\">\n          <property name=\"spacing\">\n           <number>0</number>\n          </property>\n          <property name=\"topMargin\">\n           <number>20</number>\n          </property>\n          <property name=\"bottomMargin\">\n           <number>10</number>\n          </property>\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"TemporalExtentsLayout\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"bottomMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QLabel\" name=\"TemporalExtentsLabel\">\n              <property name=\"text\">\n               <string>Temporal Extents</string>\n              </property>\n              <property name=\"margin\">\n               <number>5</number>\n              </property>\n             </widget>\n            </item>\n           </layout>\n          </item>\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"MinTimeLayout\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QLabel\" name=\"MinTimestepLabel\">\n              <property name=\"text\">\n               <string>Minimum Timestep</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <spacer name=\"horizontalSpacer_4\">\n              <property name=\"orientation\">\n               <enum>Qt::Horizontal</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::MinimumExpanding</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>40</width>\n                <height>20</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n            <item>\n             <widget class=\"QSpinBox\" name=\"MinTimestepSpinbox\"/>\n            </item>\n           </layout>\n          </item>\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"MaxTimeLayout\">\n            <property name=\"spacing\">\n             <number>0</number>\n            </property>\n            <property name=\"leftMargin\">\n             <number>0</number>\n            </property>\n            <item>\n             <widget class=\"QLabel\" name=\"MaxTimestepLabel\">\n              <property name=\"text\">\n               <string>Maximum Timestep</string>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <spacer name=\"horizontalSpacer_5\">\n              <property name=\"orientation\">\n               <enum>Qt::Horizontal</enum>\n              </property>\n              <property name=\"sizeType\">\n               <enum>QSizePolicy::MinimumExpanding</enum>\n              </property>\n              <property name=\"sizeHint\" stdset=\"0\">\n               <size>\n                <width>40</width>\n                <height>20</height>\n               </size>\n              </property>\n             </spacer>\n            </item>\n            <item>\n             <widget class=\"QSpinBox\" name=\"MaxTimestepSpinbox\"/>\n            </item>\n           </layout>\n          </item>\n         </layout>\n        </item>\n        <item>\n         <spacer name=\"verticalSpacer\">\n          <property name=\"orientation\">\n           <enum>Qt::Vertical</enum>\n          </property>\n          <property name=\"sizeType\">\n           <enum>QSizePolicy::Expanding</enum>\n          </property>\n          <property name=\"sizeHint\" stdset=\"0\">\n           <size>\n            <width>20</width>\n            <height>0</height>\n           </size>\n          </property>\n         </spacer>\n        </item>\n        <item>\n         <widget class=\"Line\" name=\"line_3\">\n          <property name=\"minimumSize\">\n           <size>\n            <width>3</width>\n            <height>3</height>\n           </size>\n          </property>\n          <property name=\"orientation\">\n           <enum>Qt::Horizontal</enum>\n          </property>\n         </widget>\n        </item>\n        <item>\n         <layout class=\"QVBoxLayout\" name=\"verticalLayout_7\">\n          <property name=\"spacing\">\n           <number>5</number>\n          </property>\n          <item>\n           <layout class=\"QHBoxLayout\" name=\"horizontalLayout_4\">\n            <property name=\"spacing\">\n             <number>-1</number>\n            </property>\n            <item>\n             <widget class=\"QPushButton\" name=\"ExportButton\">\n              <property name=\"enabled\">\n               <bool>true</bool>\n              </property>\n              <property name=\"minimumSize\">\n               <size>\n                <width>150</width>\n                <height>0</height>\n               </size>\n              </property>\n              <property name=\"text\">\n               <string>Export Text</string>\n              </property>\n              <property name=\"autoDefault\">\n               <bool>false</bool>\n              </property>\n              <property name=\"default\">\n               <bool>false</bool>\n              </property>\n              <property name=\"flat\">\n               <bool>false</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QPushButton\" name=\"UpdateButton\">\n              <property name=\"minimumSize\">\n               <size>\n                <width>150</width>\n                <height>0</height>\n               </size>\n              </property>\n              <property name=\"text\">\n               <string>Update Statistics</string>\n              </property>\n              <property name=\"autoDefault\">\n               <bool>true</bool>\n              </property>\n              <property name=\"default\">\n               <bool>false</bool>\n              </property>\n             </widget>\n            </item>\n            <item>\n             <widget class=\"QCheckBox\" name=\"UpdateCheckbox\">\n              <property name=\"text\">\n               <string>Auto-update</string>\n              </property>\n             </widget>\n            </item>\n           </layout>\n          </item>\n         </layout>\n        </item>\n       </layout>\n      </widget>\n     </item>\n    </layout>\n   </item>\n  </layout>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>FidelityWidget</class>\n   <extends>QWidget</extends>\n   <header>FidelityWidget.h</header>\n   <container>1</container>\n  </customwidget>\n </customwidgets>\n <resources/>\n <connections/>\n</ui>\n"
  },
  {
    "path": "apps/vaporgui/vapor.rc.in",
    "content": "IDI_ICON1 ICON DISCARDABLE \"@WINDOWS_ICON_PATH@\"\n"
  },
  {
    "path": "apps/vaporgui/windowsUtils.cpp",
    "content": "#ifdef WIN32\r\n    #include <Windows.h>\r\n    #include <string>\r\n    #include <sstream>\r\n    #include <locale>\r\n    #include <codecvt>\r\n    #include \"windowsUtils.h\"\r\n\r\nLONG Windows_OpenRegistry(HKEY root, std::string keyName, HKEY &key) { return RegOpenKeyEx(root, TEXT(keyName.c_str()), 0, KEY_ALL_ACCESS, &key); }\r\n\r\nLONG Windows_CloseRegistry(HKEY key) { return RegCloseKey(key); }\r\n\r\nLONG Windows_GetRegistryString(HKEY hKey, const std::string &strValueName, std::string &strValue, const std::string &strDefaultValue)\r\n{\r\n    strValue = strDefaultValue;\r\n    CHAR  szBuffer[8192];\r\n    DWORD dwBufferSize = sizeof(szBuffer);\r\n    LONG  error;\r\n    error = RegQueryValueEx(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);\r\n    if (error == ERROR_SUCCESS) strValue = szBuffer;\r\n    return error;\r\n}\r\n\r\nLONG Windows_SetRegistryString(HKEY hKey, const std::string &strValueName, const std::string &strValue)\r\n{\r\n    LONG error;\r\n    error = RegSetValueEx(hKey, strValueName.c_str(), 0, REG_SZ, (LPBYTE)strValue.c_str(), strValue.length());\r\n    if (error == ERROR_SUCCESS) { BroadcastSystemMessage(0, 0, WM_SETTINGCHANGE, 0, (LPARAM)TEXT(\"Environment\")); }\r\n    return error;\r\n}\r\n\r\nstd::string Windows_GetErrorString(LONG errorCode)\r\n{\r\n    LPVOID lpMsgBuf;\r\n\r\n    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);\r\n\r\n    std::wstringstream wss;\r\n    wss << (LPCTSTR)lpMsgBuf;\r\n    std::wstring ws = wss.str();\r\n\r\n    std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;\r\n    std::string                                               s = converter.to_bytes(ws);\r\n    LocalFree(lpMsgBuf);\r\n\r\n    return s;\r\n}\r\n#endif"
  },
  {
    "path": "apps/vaporgui/windowsUtils.h",
    "content": "#ifndef WINDOWS_UTILS_H\r\n#define WINDOWS_UTILS_H\r\n#ifdef WIN32\r\n\r\n    #include <Windows.h>\r\n\r\n    #define WIN32_LEAN_AND_MEAN\r\n    #define WINDOWS_SUCCESS              ERROR_SUCCESS\r\n    #define WINDOWS_ERROR_FILE_NOT_FOUND ERROR_FILE_NOT_FOUND\r\n    #define WINDOWS_HKEY_CLASSES_ROOT    HKEY_CLASSES_ROOT\r\n    #define WINDOWS_HKEY_CURRENT_CONFIG  HKEY_CURRENT_CONFIG\r\n    #define WINDOWS_HKEY_CURRENT_USER    HKEY_CURRENT_USER\r\n    #define WINDOWS_HKEY_LOCAL_MACHINE   HKEY_LOCAL_MACHINE\r\n    #define WINDOWS_HKEY_USERS           HKEY_USERS\r\n\r\nLONG        Windows_OpenRegistry(HKEY root, std::string keyName, HKEY &key);\r\nLONG        Windows_CloseRegistry(HKEY key);\r\nLONG        Windows_GetRegistryString(HKEY hKey, const std::string &strValueName, std::string &strValue, const std::string &strDefaultValue);\r\nLONG        Windows_SetRegistryString(HKEY hKey, const std::string &strValueName, const std::string &strValue);\r\nstd::string Windows_GetErrorString(LONG errorCode);\r\n\r\n#endif\r\n#endif\r\n"
  },
  {
    "path": "apps/vaporpychecker/CMakeLists.txt",
    "content": "add_executable (vaporpychecker vaporpychecker.cpp)\n\ntarget_link_libraries (vaporpychecker common render ${Python_LIBRARIES})\n\nOpenMPInstall (\n\tTARGETS vaporpychecker\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/vaporpychecker/vaporpychecker.cpp",
    "content": "#include <iostream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/MyPython.h>\n#include <vapor/CFuncs.h>\n#include <vapor/FileUtils.h>\n#include <vapor/ResourcePath.h>\n\nusing namespace Wasp;\n\nstruct opt_t {\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"quiet\", 0, \"\", \"Don't print anything, just exit with status\"}, {\"help\", 0, \"\", \"Print this message and exit\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}};\n\nstring ProgName;\n\n// Fetch an error message genereated by Python API.\n//\nstring pyErr()\n{\n    PyObject *pMain = PyImport_AddModule(\"__main__\");\n\n    PyObject *catcher = NULL;\n    if (pMain && PyObject_HasAttrString(pMain, \"catchErr\")) { catcher = PyObject_GetAttrString(pMain, \"catchErr\"); }\n\n    // If catcher is NULL the Python message will be written\n    // to stderr. Otherwise it is writter to the catchErr object.\n    //\n    PyErr_Print();\n\n    if (!catcher) {\n        cerr << \"CATCHER NULL\" << endl;\n        return (\"No Python error catcher\");\n    }\n\n    PyObject *output = PyObject_GetAttrString(catcher, \"value\");\n    return (PyUnicode_AsUTF8(output));\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n#ifndef WIN32\n    std::string phome = GetPythonDir();\n    setenv(\"PYTHONHOME\", phome.c_str(), 1);\n#endif\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { return (1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); }\n\n    if (argc != 1 || opt.help) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        return (1);\n    }\n\n    // Use MyPython singleton class to initialize Python interpeter to\n    // ensure it only gets initialized once.\n    //\n    int rc = MyPython::Instance()->Initialize();\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Failed to initialize python : %s\", pyErr().c_str());\n        printf(\"Failed to initialize python : %s\\n\", pyErr().c_str());\n        return (1);\n    }\n\n\n    cout << endl << \"System search path: \";\n    std::string printSysPath = \"try:\\n\"\n                               \"\timport sys\\n\"\n                               \"except: \\n\"\n                               \"\tprint >> sys.stderr, \\'Failed to import sys\\'\\n\"\n                               \"\traise\\n\"\n                               \"print(sys.path)\\n\";\n    rc = PyRun_SimpleString(printSysPath.c_str());\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"PyRun_SimpleString() : %s\", MyPython::Instance()->PyErr().c_str());\n        return (1);\n    }\n    cout << MyPython::Instance()->PyOut() << endl;\n\n\n    cout << \"Location of site module: \";\n    std::string printSiteModulePath = \"try:\\n\"\n                                      \"\timport site\\n\"\n                                      \"except: \\n\"\n                                      \"\tprint >> sys.stderr, \\'Failed to import site\\'\\n\"\n                                      \"\traise\\n\"\n                                      \"import os\\n\"\n                                      \"print(os.path.dirname(site.__file__))\\n\";\n    rc = PyRun_SimpleString(printSiteModulePath.c_str());\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"PyRun_SimpleString() : %s\", MyPython::Instance()->PyErr().c_str());\n        return (1);\n    }\n    cout << MyPython::Instance()->PyOut() << endl;\n\n\n    cout << \"Location of matplotlib module: \";\n    std::string printMatplotlibModulePath = \"try:\\n\"\n                                            \"\timport matplotlib\\n\"\n                                            \"except: \\n\"\n                                            \"\tprint >> sys.stderr, \\'Failed to import matplotlib\\'\\n\"\n                                            \"\traise\\n\"\n                                            \"import os\\n\"\n                                            \"print(os.path.dirname(matplotlib.__file__))\\n\";\n    rc = PyRun_SimpleString(printMatplotlibModulePath.c_str());\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"PyRun_SimpleString() : %s\", MyPython::Instance()->PyErr().c_str());\n        return (1);\n    }\n    cout << MyPython::Instance()->PyOut() << endl;\n\n    return (0);\n}\n"
  },
  {
    "path": "apps/vaporversion/CMakeLists.txt",
    "content": "add_executable (vaporversion vaporversion.cpp)\n\ntarget_link_libraries (vaporversion common)\n\nOpenMPInstall (\n\tTARGETS vaporversion\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/vaporversion/vaporversion.cpp",
    "content": "//\n//      $Id$\n//\n//***********************************************************************\n//                                                                       *\n//                            Copyright (C)  2005                        *\n//            University Corporation for Atmospheric Research            *\n//                            All Rights Reserved                        *\n//                                                                       *\n//***********************************************************************/\n//\n//      File:\t\traw2vdf.cpp\n//\n//      Author:         John Clyne\n//                      National Center for Atmospheric Research\n//                      PO 3000, Boulder, Colorado\n//\n//      Date:           Tue Jun 14 15:01:13 MDT 2005\n//\n//      Description:\tRead a file containing a raw data volume. Translate\n//\t\t\tand append the volume to an existing\n//\t\t\tVapor Data Collection\n//\n\n#include <iostream>\n#include <cstdlib>\n#include <cstring>\n#include <vector>\n#include <sstream>\n#include <cerrno>\n#include <cstdio>\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/Version.h>\n#include <vapor/FileUtils.h>\n#ifdef WIN32\n    #include \"windows.h\"\n#endif\n\nusing namespace Wasp;\n\n//\n//\tCommand line argument stuff\n//\nstruct opt_t {\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T _long;\n    OptionParser::Boolean_T numeric;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"help\", 0, \"\", \"Print this message and exit\"}, {\"long\", 0, \"\", \"Print long form (version and date)\"}, {\"numeric\", 0, \"\", \"Print numeric form\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {\n    {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {\"long\", Wasp::CvtToBoolean, &opt._long, sizeof(opt._long)}, {\"numeric\", Wasp::CvtToBoolean, &opt.numeric, sizeof(opt.numeric)}, {NULL}};\n\nconst char *ProgName;\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] metafile datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (argc != 1) {\n        cerr << \"Usage: \" << ProgName << \" [options] \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    if (opt._long) {\n        cout << \"Vapor \" << Version::GetBuildType() << \" version \" << Version::GetFullVersionString() << \" (\" << Version::GetDateString() << \")\" << endl;\n    } else if (opt.numeric) {\n        cout << Version::GetMajor() << \".\" << Version::GetMinor() << \".\" << Version::GetMinorMinor() << endl;\n    } else {\n        cout << \"vapor-\" << Version::GetVersionString() << endl;\n    }\n}\n"
  },
  {
    "path": "apps/vdc2raw/CMakeLists.txt",
    "content": "add_executable (vdc2raw vdc2raw.cpp)\n\ntarget_link_libraries (vdc2raw common vdc)\n\nOpenMPInstall (\n\tTARGETS vdc2raw\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/vdc2raw/vdc2raw.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include <cerrno>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    int                     ts;\n    string                  varname;\n    string                  type;\n    int                     level;\n    int                     lod;\n    int                     nthreads;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T debug;\n    OptionParser::Boolean_T quiet;\n    vector<int>             xregion;\n    vector<int>             yregion;\n    vector<int>             zregion;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"ts\", 1, \"0\", \"Timestep of data file starting from 0\"},\n                                         {\"varname\", 1, \"var1\", \"Name of variable\"},\n                                         {\"type\", 1, \"float32\", \"Primitive type of output data\"},\n                                         {\"level\", 1, \"-1\", \"Multiresolution refinement level. Zero implies coarsest resolution\"},\n                                         {\"lod\", 1, \"-1\", \"Compression level of detail. Zero implies coarsest approximation\"},\n                                         {\"nthreads\", 1, \"0\", \"Number of execution threads (0=># processors)\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {\"debug\", 0, \"\", \"Enable debugging\"},\n                                         {\"quiet\", 0, \"\", \"Operate quietly\"},\n                                         {\"xregion\", 1, \"-1:-1\", \"X dimension subregion bounds (min:max)\"},\n                                         {\"yregion\", 1, \"-1:-1\", \"Y dimension subregion bounds (min:max)\"},\n                                         {\"zregion\", 1, \"-1:-1\", \"Z dimension subregion bounds (min:max)\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"ts\", Wasp::CvtToInt, &opt.ts, sizeof(opt.ts)},\n                                        {\"varname\", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)},\n                                        {\"type\", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)},\n                                        {\"level\", Wasp::CvtToInt, &opt.level, sizeof(opt.level)},\n                                        {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"xregion\", Wasp::CvtToIntVec, &opt.xregion, sizeof(opt.xregion)},\n                                        {\"yregion\", Wasp::CvtToIntVec, &opt.yregion, sizeof(opt.yregion)},\n                                        {\"zregion\", Wasp::CvtToIntVec, &opt.zregion, sizeof(opt.zregion)},\n                                        {NULL}};\n\nsize_t size_of_type(string type)\n{\n    if (type.compare(\"float32\") == 0) return (4);\n    if (type.compare(\"float64\") == 0) return (8);\n    if (type.compare(\"int8\") == 0) return (1);\n    return (1);\n}\n\nint write_data(FILE * fp,\n               string type,    // element type\n               size_t n, const float *slice)\n{\n    static SmartBuf smart_buf;\n\n    size_t         element_sz = size_of_type(type);\n    unsigned char *buffer = (unsigned char *)smart_buf.Alloc(n * element_sz);\n\n    const float *sptr = slice;\n    if (type.compare(\"float32\") == 0) {\n        float *dptr = (float *)buffer;\n        for (size_t i = 0; i < n; i++) { *dptr++ = (float)*sptr++; }\n    } else if (type.compare(\"float64\") == 0) {\n        double *dptr = (double *)buffer;\n        for (size_t i = 0; i < n; i++) { *dptr++ = (double)*sptr++; }\n    } else if (type.compare(\"int8\") == 0) {\n        char *dptr = (char *)buffer;\n        for (size_t i = 0; i < n; i++) { *dptr++ = (char)*sptr++; }\n    }\n\n    int rc = fwrite(buffer, element_sz, n, fp);\n    if (rc != n) {\n        MyBase::SetErrMsg(\"Error writing output file : %M\");\n        return (-1);\n    }\n\n    return (0);\n}\n\nvoid process_volume(size_t ts, string varname, int level, int lod, VDCNetCDF &vdc, FILE *fp, vector<size_t> dims, string type)\n{\n    vector<size_t> hslice_dims;\n    size_t         nslice;\n    int            rc = vdc.GetHyperSliceInfo(varname, opt.level, hslice_dims, nslice);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Invalid variable name : %s\", varname.c_str());\n        exit(1);\n    }\n\n    size_t nelements = 1;\n    for (int i = 0; i < hslice_dims.size(); i++) { nelements *= hslice_dims[i]; }\n    float *buffer = new float[nelements];\n\n    size_t ntotal = 1;\n    for (int i = 0; i < dims.size(); i++) { ntotal *= dims[i]; }\n\n    int fd = vdc.OpenVariableRead(ts, varname, level, lod);\n    if (fd < 0) exit(1);\n\n    for (size_t i = 0; i < nslice; i++) {\n        rc = vdc.ReadSlice(fd, buffer);\n        if (rc < 0) exit(1);\n\n        nelements = nelements < ntotal ? nelements : ntotal;\n\n        rc = write_data(fp, type, nelements, buffer);\n        if (rc < 0) exit(1);\n\n        ntotal -= nelements;\n    }\n\n    rc = vdc.CloseVariable(fd);\n    if (rc < 0) exit(1);\n\n    delete[] buffer;\n}\n\nvoid process_region(size_t ts, string varname, int level, int lod, VDCNetCDF &vdc, FILE *fp, vector<size_t> dims, string type, const vector<int> &xregion, const vector<int> &yregion,\n                    const vector<int> &zregion)\n{\n    VAssert(dims.size() >= 1 && dims.size() <= 3);\n    VAssert(xregion.size() == 2);\n    VAssert(yregion.size() == 2);\n    VAssert(zregion.size() == 2);\n\n    vector<size_t> min_bound;\n    vector<size_t> max_bound;\n\n    min_bound.push_back(xregion[0] < 0 ? 0 : xregion[0]);\n    max_bound.push_back(xregion[1] < 0 ? dims[0] - 1 : xregion[1]);\n\n    int fd = vdc.OpenVariableRead(ts, varname, level, lod);\n    if (fd < 0) exit(1);\n\n    if (dims.size() > 1) {\n        min_bound.push_back(yregion[0] < 0 ? 0 : yregion[0]);\n        max_bound.push_back(yregion[1] < 0 ? dims[1] - 1 : yregion[1]);\n    }\n    if (dims.size() > 2) {\n        min_bound.push_back(zregion[0] < 0 ? 0 : zregion[0]);\n        max_bound.push_back(zregion[1] < 0 ? dims[2] - 1 : zregion[1]);\n    }\n\n    size_t nelements = 1;\n    for (int i = 0; i < dims.size(); i++) { nelements *= max_bound[i] - min_bound[i] + 1; }\n\n    float *region = new float[nelements];\n\n    int rc = vdc.ReadRegion(fd, min_bound, max_bound, region);\n    if (rc < 0) exit(1);\n\n    rc = write_data(fp, type, nelements, region);\n    if (rc < 0) exit(1);\n\n    delete[] region;\n\n    rc = vdc.CloseVariable(fd);\n    if (rc < 0) exit(1);\n}\n\nconst char *ProgName;\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] vdcmaster datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n    if (opt.xregion.size() != 2 || opt.yregion.size() != 2 || opt.zregion.size() != 2) {\n        cerr << \"Usage: \" << ProgName << \" [options] vdcmaster datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    if (argc != 3) {\n        cerr << \"Usage: \" << ProgName << \" [options] vdcmaster datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    string vdcmaster = argv[1];\n    string datafile = argv[2];\n\n    FILE *fp = fopen(datafile.c_str(), \"wb\");\n    if (!fp) {\n        MyBase::SetErrMsg(\"Could not open file \\\"%s\\\" : %M\", datafile.c_str());\n        exit(1);\n    }\n\n    VDCNetCDF vdc(opt.nthreads);\n\n    vector<size_t> bs;\n    int            rc = vdc.Initialize(vdcmaster, vector<string>(), VDC::R, bs, 4 * 1024 * 1024);\n    if (rc < 0) exit(1);\n\n    vector<size_t> dims;\n    vector<size_t> dummy;\n    if (vdc.GetDimLensAtLevel(opt.varname, opt.level, dims, dummy) < 0) { exit(1); }\n\n    if (dims.size() < 1) {\n        MyBase::SetErrMsg(\"Variable must be 1D, 2D or 3D\");\n        exit(1);\n    }\n\n    //\n\n    if (opt.xregion[0] == -1 && opt.xregion[1] == -1 && opt.yregion[0] == -1 && opt.yregion[1] == -1 && opt.zregion[0] == -1 && opt.zregion[1] == -1) {\n        process_volume(opt.ts, opt.varname, opt.level, opt.lod, vdc, fp, dims, opt.type);\n\n        if (!opt.quiet) {\n            cout << \"Wrote \";\n            for (int i = 0; i < dims.size(); i++) {\n                cout << dims[i];\n                if (i != dims.size() - 1) cout << \"x\";\n            }\n            cout << endl;\n        }\n    } else {\n        process_region(opt.ts, opt.varname, opt.level, opt.lod, vdc, fp, dims, opt.type, opt.xregion, opt.yregion, opt.zregion);\n\n        if (!opt.quiet) {\n            cout << \"Wrote \";\n            cout << (opt.xregion[1] - opt.xregion[0] + 1) << \"x\";\n            cout << (opt.yregion[1] - opt.yregion[0] + 1) << \"x\";\n            cout << (opt.zregion[1] - opt.zregion[0] + 1) << endl;\n        }\n    }\n\n    fclose(fp);\n\n    exit(0);\n}\n"
  },
  {
    "path": "apps/vdccompare/CMakeLists.txt",
    "content": "add_executable (vdccompare vdccompare.cpp)\n\ntarget_link_libraries (vdccompare common vdc)\n\nOpenMPInstall (\n\tTARGETS vdccompare\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/vdccompare/vdccompare.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string.h>\n#include <vector>\n#include <sstream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/CFuncs.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/DCWRF.h>\n#include <vapor/DCCF.h>\n#include <vapor/DCMPAS.h>\n#include <vapor/DataMgr.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    int                     nthreads;\n    int                     numts;\n    int                     memsize;\n    std::vector<string>     vars;\n    OptionParser::Boolean_T datamgr;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"numts\", 1, \"-1\", \"Number of timesteps to be included in the VDC. Default (-1) includes all timesteps.\"},\n                                         {\n                                             \"memsize\",\n                                             1,\n                                             \"2000\",\n                                             \"Cache size in MBs (if -datamgr used)\",\n                                         },\n                                         {\"vars\", 1, \"\",\n                                          \"Colon delimited list of 3D variable names (compressed) \"\n                                          \"to be included in \"\n                                          \"the VDC\"},\n                                         {\"datamgr\", 0, \"\", \"Get data from second data source via DataMgr\"},\n                                         {\"quiet\", 0, \"\", \"Don't print individual variable results\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},  {\"numts\", Wasp::CvtToInt, &opt.numts, sizeof(opt.numts)},\n                                        {\"memsize\", Wasp::CvtToInt, &opt.memsize, sizeof(opt.memsize)},     {\"vars\", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)},\n                                        {\"datamgr\", Wasp::CvtToBoolean, &opt.datamgr, sizeof(opt.datamgr)}, {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},          {NULL}};\n\nstring ProgName;\n\nDC *DCCreate(string ftype)\n{\n    if (ftype.compare(\"vdc\") == 0) {\n        return (new VDCNetCDF(opt.nthreads));\n    } else if (ftype.compare(\"wrf\") == 0) {\n        return (new DCWRF());\n    } else if (ftype.compare(\"cf\") == 0) {\n        return (new DCCF());\n    } else if (ftype.compare(\"mpas\") == 0) {\n        return (new DCMPAS());\n    } else {\n        MyBase::SetErrMsg(\"Invalid data collection format : %s\", ftype.c_str());\n        return (NULL);\n    }\n}\n\nfloat *Buffer1;\nsize_t BufSize1 = 0;\nfloat *Buffer2;\nsize_t BufSize2 = 0;\n\nvoid computeLMax(const float *buf1, const float *buf2, size_t nelements, double &lmax, double &min, double &max, bool hasMissing, float mv)\n{\n    lmax = 0.0;\n    min = 0.0;\n    max = 0.0;\n    if (nelements < 1) return;\n\n    size_t index = 0;\n    while (hasMissing && buf1[index] == mv && index < nelements) index++;\n\n    if (index >= nelements) return;\n\n    min = max = buf1[index];\n\n    for (; index < nelements; index++) {\n        if (hasMissing && buf1[index] == mv) continue;\n\n        if (min > buf1[index]) { min = buf1[index]; }\n        if (max < buf1[index]) { max = buf1[index]; }\n\n        double diff = fabs(buf1[index] - buf2[index]);\n        if (diff > lmax) { lmax = diff; }\n    }\n}\n\nint get_var(DC *dc, size_t ts, string varname, float *Buffer) { return (dc->GetVar(ts, varname, -1, -1, Buffer)); }\n\nint get_var(DataMgr *data_mgr, size_t ts, string varname, float *Buffer)\n{\n    Grid *grid = data_mgr->GetVariable(ts, varname, -1, -1);\n    if (!grid) return (-1);\n\n    Grid::Iterator itr;\n    Grid::Iterator enditr = grid->end();\n    for (itr = grid->begin(); itr != enditr; ++itr, ++Buffer) { *Buffer = *itr; }\n\n    delete grid;\n    return (0);\n}\n\ntemplate<class S, class T> bool compare(S *dc1, T *dc2, size_t nts, string varname, double &nlmax_all)\n{\n    vector<size_t> dims;\n    int            rc = dc1->GetDimLens(varname, dims);\n    if (rc < 0) return (false);\n\n    vector<size_t> dims2;\n    rc = dc2->GetDimLens(varname, dims2, -1);\n    if (rc < 0) return (false);\n\n    VAssert(dims == dims2);\n\n    size_t nelements = 1;\n    for (int i = 0; i < dims.size(); i++) { nelements *= dims[i]; }\n\n    if (BufSize1 < nelements) {\n        if (Buffer1) delete[] Buffer1;\n        Buffer1 = new float[nelements];\n        BufSize1 = nelements;\n        if (Buffer2) delete[] Buffer2;\n        Buffer2 = new float[nelements];\n        BufSize2 = nelements;\n    }\n\n    nlmax_all = 0.0;\n    for (int ts = 0; ts < nts; ts++) {\n        rc = get_var(dc1, ts, varname, Buffer1);\n        if (rc < 0) return (false);\n\n        DC::DataVar datavar;\n        bool        ok = dc1->GetDataVarInfo(varname, datavar);\n        VAssert(ok);\n\n        float mv = 0.0;\n        bool  hasMissing = datavar.GetHasMissing();\n        if (hasMissing) mv = datavar.GetMissingValue();\n\n        rc = get_var(dc2, ts, varname, Buffer2);\n        if (rc < 0) return (false);\n\n        double lmax, min, max;\n        computeLMax(Buffer1, Buffer2, nelements, lmax, min, max, hasMissing, mv);\n        if ((max - min) != 0.0) { lmax /= (max - min); }\n        if (lmax > nlmax_all) { nlmax_all = lmax; }\n    }\n\n    return (true);\n}\n\ntemplate<class S, class T> int process(S *dc1, const vector<string> &files1, T *dc2, const vector<string> &files2)\n{\n    int rc = dc1->Initialize(files1, vector<string>());\n    if (rc < 0) return (1);\n\n    rc = dc2->Initialize(files2, vector<string>());\n    if (rc < 0) return (1);\n\n    vector<string> varnames;\n    if (opt.vars.size()) {\n        varnames = opt.vars;\n    } else {\n        varnames = dc1->GetDataVarNames();\n    }\n\n    double max_nlmax = 0;\n    bool   success = true;\n    for (int i = 0; i < varnames.size(); i++) {\n        int nts = dc1->GetNumTimeSteps(varnames[i]);\n        nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts;\n        VAssert(nts >= 0);\n\n        if (!opt.quiet) { cout << \"Testing variable \" << varnames[i] << endl; }\n\n        double nlmax;\n        bool   ok = compare(dc1, dc2, nts, varnames[i], nlmax);\n        if (!ok) {\n            cout << \"failed!\" << endl;\n            success = false;\n            break;\n        }\n        if (!opt.quiet) { cout << \"\tNLmax = \" << nlmax << endl; }\n        if (nlmax > max_nlmax) { max_nlmax = nlmax; }\n    }\n    cout << \"Max NLmax = \" << max_nlmax << endl;\n\n    return success ? 0 : 1;\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { exit(1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); }\n\n    if (argc < 6 || opt.help) {\n        cerr << \"Usage: \" << ProgName << \" source_ftype secondary_ftype source_files... -- secondary_files... \" << endl;\n        cerr << \"Valid file types: vdc, wrf, cf, mpas\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(1);\n    }\n\n    argc--;\n    argv++;\n\n    string ftype1 = argv[0];\n    argc--;\n    argv++;\n\n    string ftype2 = argv[0];\n    argc--;\n    argv++;\n\n    vector<string> files1;\n    string         sep(\"--\");\n    while (*argv && string(*argv) != sep) {\n        files1.push_back(*argv);\n        argv++;\n    }\n    if (*argv) argv++;\n\n    vector<string> files2;\n    while (*argv) {\n        files2.push_back(*argv);\n        argv++;\n    }\n\n    DC *dc1 = NULL;\n    dc1 = DCCreate(ftype1);\n    if (!dc1) return (1);\n\n    if (opt.datamgr) {\n        DataMgr *datamgr2 = new DataMgr(ftype2, opt.memsize, opt.nthreads);\n        return (process(dc1, files1, datamgr2, files2));\n    } else {\n        DC *dc2 = DCCreate(ftype2);\n        if (!dc2) return (1);\n\n        return (process(dc1, files1, dc2, files2));\n    }\n}\n"
  },
  {
    "path": "apps/vdccreate/CMakeLists.txt",
    "content": "add_executable (vdccreate vdccreate.cpp)\n\ntarget_link_libraries (vdccreate common vdc)\n\nOpenMPInstall (\n\tTARGETS vdccreate\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/vdccreate/vdccreate.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string.h>\n#include <vector>\n#include <sstream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/CFuncs.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    OptionParser::Dimension3D_T dim;\n    std::vector<size_t>         bs;\n    std::vector<size_t>         cratios;\n    string                      wname;\n    string                      xtype;\n    string                      xcoords;\n    string                      ycoords;\n    string                      zcoords;\n    string                      tcoords;\n    int                         numts;\n    int                         nthreads;\n    std::vector<string>         vars3d;\n    std::vector<string>         vars2dxy;\n    std::vector<string>         vars2dxz;\n    std::vector<string>         vars2dyz;\n    std::vector<string>         ncvars3d;\n    std::vector<string>         ncvars2dxy;\n    std::vector<string>         ncvars2dxz;\n    std::vector<string>         ncvars2dyz;\n    std::vector<float>          extents;\n    OptionParser::Boolean_T     force;\n    OptionParser::Boolean_T     help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {\n    {\"dimension\", 1, \"512x512x512\",\n     \"Data volume dimensions expressed in \"\n     \"grid points (NXxNYxNZ)\"},\n    {\"bs\", 1, \"64:64:64\", \"Internal storage blocking factor expressed in grid points (NX:NY:NZ)\"},\n    {\"cratios\", 1, \"500:100:10:1\",\n     \"Colon delimited list compression ratios. \"\n     \"The default is 500:100:10:1. The maximum compression ratio \"\n     \"is wavelet and block size dependent.\"},\n    {\"wname\", 1, \"bior4.4\",\n     \"Wavelet family used for compression \"\n     \"Valid values are bior1.1, bior1.3, \"\n     \"bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, \"\n     \"bior3.5, bior3.7, bior3.9, bior4.4\"},\n    {\"xtype\", 1, \"float\",\n     \"External data type representation. \"\n     \"Valid values are uint8 int8 int16 int32 int64 float double\"},\n    {\"xcoords\", 1, \"\",\n     \"Path to a file containing a newline \"\n     \"delineated list of monotonically increasing X-axis user coordinates. The list may optionally be preceeded by a UDUNITS style units specification (e.g. meters, degrees_east)\"},\n    {\"ycoords\", 1, \"\",\n     \"Path to a file containing a newline \"\n     \"delineated list of monotonically increasing Y-axis user coordinates. The list may optionally be preceeded by a UDUNITS style units specification (e.g. meters, degrees_north)\"},\n    {\"zcoords\", 1, \"\",\n     \"Path to a file containing a newline \"\n     \"delineated list of monotonically increasing Z-axis user coordinates. The list may optionally be preceeded by a UDUNITS style units specification (e.g. meters)\"},\n    {\"tcoords\", 1, \"\",\n     \"Path to a file containing a newline \"\n     \"delineated list of monotonically increasing T-axis (time) user coordinates. The list may optionally be preceeded by a UDUNITS style units specification (e.g. hours since 2004-01-01 00:00:00)\"},\n    {\"numts\", 1, \"1\", \"Number of timesteps in the data set\"},\n    {\"nthreads\", 1, \"0\",\n     \"Specify number of execution threads \"\n     \"0 => use number of cores\"},\n    {\"vars3d\", 1, \"\",\n     \"Colon delimited list of 3D variable names (compressed) \"\n     \"to be included in \"\n     \"the VDC\"},\n    {\"vars2dxy\", 1, \"\",\n     \"Colon delimited list of 2D XY-plane variable \"\n     \"names (compressed) \"\n     \"to be included in the VDC\"},\n    {\"vars2dxz\", 1, \"\",\n     \"Colon delimited list of 3D XZ-plane variable \"\n     \"names (compressed) \"\n     \"to be included in the VDC\"},\n    {\"vars2dyz\", 1, \"\",\n     \"Colon delimited list of 3D YZ-plane variable \"\n     \"names (compressed) \"\n     \"to be included in the VDC\"},\n    {\"ncvars3d\", 1, \"\",\n     \"Colon delimited list of 3D variable names (not compressed) \"\n     \"to be included in \"\n     \"the VDC\"},\n    {\"ncvars2dxy\", 1, \"\",\n     \"Colon delimited list of 2D XY-plane variable \"\n     \"names (not compressed) \"\n     \"to be included in the VDC\"},\n    {\"ncvars2dxz\", 1, \"\",\n     \"Colon delimited list of 3D XZ-plane variable \"\n     \"names (not compressed) \"\n     \"to be included in the VDC\"},\n    {\"ncvars2dyz\", 1, \"\",\n     \"Colon delimited list of 3D YZ-plane variable \"\n     \"names (not compressed) \"\n     \"to be included in the VDC\"},\n    {\"extents\", 1, \"\",\n     \"Colon delimited 6-element vector \"\n     \"specifying domain extents in user coordinates (X0:Y0:Z0:X1:Y1:Z1)\"},\n    {\"force\", 0, \"\",\n     \"Create a new VDC master file even if a VDC data \"\n     \"directory already exists. Results may be undefined if settings between \"\n     \"the new master file and old data directory do not match.\"},\n    {\"help\", 0, \"\", \"Print this message and exit\"},\n    {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"dimension\", Wasp::CvtToDimension3D, &opt.dim, sizeof(opt.dim)},\n                                        {\"bs\", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)},\n                                        {\"cratios\", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)},\n                                        {\"wname\", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)},\n                                        {\"xtype\", Wasp::CvtToCPPStr, &opt.xtype, sizeof(opt.xtype)},\n                                        {\"xcoords\", Wasp::CvtToCPPStr, &opt.xcoords, sizeof(opt.xcoords)},\n                                        {\"ycoords\", Wasp::CvtToCPPStr, &opt.ycoords, sizeof(opt.ycoords)},\n                                        {\"zcoords\", Wasp::CvtToCPPStr, &opt.zcoords, sizeof(opt.zcoords)},\n                                        {\"tcoords\", Wasp::CvtToCPPStr, &opt.tcoords, sizeof(opt.tcoords)},\n                                        {\"numts\", Wasp::CvtToInt, &opt.numts, sizeof(opt.numts)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"vars3d\", Wasp::CvtToStrVec, &opt.vars3d, sizeof(opt.vars3d)},\n                                        {\"vars2dxy\", Wasp::CvtToStrVec, &opt.vars2dxy, sizeof(opt.vars2dxy)},\n                                        {\"vars2dxz\", Wasp::CvtToStrVec, &opt.vars2dxz, sizeof(opt.vars2dxz)},\n                                        {\"vars2dyz\", Wasp::CvtToStrVec, &opt.vars2dyz, sizeof(opt.vars2dyz)},\n                                        {\"ncvars3d\", Wasp::CvtToStrVec, &opt.ncvars3d, sizeof(opt.ncvars3d)},\n                                        {\"ncvars2dxy\", Wasp::CvtToStrVec, &opt.ncvars2dxy, sizeof(opt.ncvars2dxy)},\n                                        {\"ncvars2dxz\", Wasp::CvtToStrVec, &opt.ncvars2dxz, sizeof(opt.ncvars2dxz)},\n                                        {\"ncvars2dyz\", Wasp::CvtToStrVec, &opt.ncvars2dyz, sizeof(opt.ncvars2dyz)},\n                                        {\"extents\", Wasp::CvtToFloatVec, &opt.extents, sizeof(opt.extents)},\n\n                                        {\"force\", Wasp::CvtToBoolean, &opt.force, sizeof(opt.force)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nstring ProgName;\n\nvoid set_coord_uniform(VDCNetCDF &vdc, string dimname, size_t dimlen, float min, float max)\n{\n    VAssert(dimlen >= 1);\n\n    float *buf = new float[dimlen];\n\n    float delta = dimlen > 1 ? (max - min) / (float)(dimlen - 1) : 0.0;\n\n    for (int i = 0; i < dimlen; i++) { buf[i] = min + i * delta; }\n\n    int rc = vdc.PutVar(0, dimname, -1, buf);\n    if (rc < 0) exit(1);\n}\n\nvoid set_coord_stretched(VDCNetCDF &vdc, string dimname, const vector<float> &coords)\n{\n    int rc = vdc.PutVar(0, dimname, -1, coords.data());\n    if (rc < 0) exit(1);\n}\n\nvoid set_coords_uniform(VDCNetCDF &vdc, const vector<float> &extents, const vector<string> &dimnames, const vector<size_t> &dimlens)\n{\n    if (!extents.size()) return;\n\n    VAssert(extents.size() == 6);\n    VAssert(dimnames.size() == 4);\n    VAssert(dimlens.size() == 4);\n\n    set_coord_uniform(vdc, dimnames[0], dimlens[0], extents[0], extents[3]);\n    set_coord_uniform(vdc, dimnames[1], dimlens[1], extents[1], extents[4]);\n    set_coord_uniform(vdc, dimnames[2], dimlens[2], extents[2], extents[5]);\n}\n\nDC::XType parseXType(string xTypeStr)\n{\n    if (xTypeStr == \"uint8\") return (DC::XType::UINT8);\n    if (xTypeStr == \"int8\") return (DC::XType::INT8);\n    //\tif (xTypeStr == \"int16\") return (DC::XType::INT16);\n    if (xTypeStr == \"int32\") return (DC::XType::INT32);\n    if (xTypeStr == \"int64\") return (DC::XType::INT64);\n    if (xTypeStr == \"float\") return (DC::XType::FLOAT);\n    if (xTypeStr == \"float32\") return (DC::XType::FLOAT);\n    if (xTypeStr == \"float64\") return (DC::XType::DOUBLE);\n    if (xTypeStr == \"double\") return (DC::XType::DOUBLE);\n\n    return (DC::XType::INVALID);\n}\n\nbool string_to_float(string s, float &f)\n{\n    f = 0.0;\n    try {\n        f = std::stof(s);\n    } catch (invalid_argument const&) {\n        return (false);\n    } catch (out_of_range const&) {\n        return (false);\n    }\n    return (true);\n}\n\nint read_float_vec(string path, size_t n, vector<float> &vec, string &unit)\n{\n    vec.clear();\n    unit.clear();\n\n    ifstream fin(path.c_str());\n    if (!fin) {\n        MyBase::SetErrMsg(\"Error opening file %s\", path.c_str());\n        return (-1);\n    }\n\n    string item;\n    while (getline(fin, item)) {\n        if (item.empty()) continue;\n\n        float f;\n        bool  ok = string_to_float(item, f);\n\n        if (!ok) {\n            if (vec.empty()) {\n                unit = item;\n                continue;\n            } else {\n                MyBase::SetErrMsg(\"Invalid float %s\", item.c_str());\n                return -1;\n            }\n        }\n\n        vec.push_back(f);\n    }\n    if (fin.bad()) {\n        MyBase::SetErrMsg(\"Error reading file %s\", path.c_str());\n        return (-1);\n    }\n\n    fin.close();\n\n    // Make sure values are monotonic and increasing\n    //\n    bool mono = true;\n    for (int i = 0; i < (int)vec.size() - 1; i++) {\n        if (vec[i] > vec[i + 1]) mono = false;\n    }\n    if (!mono) {\n        MyBase::SetErrMsg(\"Sequence contained in %s must be monotonic\", path.c_str());\n        return (-1);\n    }\n\n    if (vec.size() != n) {\n        MyBase::SetErrMsg(\"Short read file %s\", path.c_str());\n        return (-1);\n    }\n\n    return (0);\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { exit(1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); }\n\n    if (argc != 2) {\n        cerr << \"Usage: \" << ProgName << \" [options] master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(1);\n    }\n    if (opt.extents.size() && opt.extents.size() != 6) {\n        cerr << \"Usage: \" << ProgName << \" master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(1);\n    }\n\n    string master = argv[1];\n\n    if (FileUtils::Extension(master) != \"vdc\") { fprintf(stderr, \"Warning: VDC files should the extension .vdc\\n\"); }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(0);\n    }\n\n    DC::XType xType = parseXType(opt.xtype);\n    if (xType == DC::XType::INVALID) {\n        MyBase::SetErrMsg(\"Invalid external data type specifier : %s\", opt.xtype.c_str());\n        exit(1);\n    }\n\n    VDCNetCDF vdc(opt.nthreads);\n\n    if (vdc.DataDirExists(master) && !opt.force) {\n        MyBase::SetErrMsg(\"Data directory exists and -force option not used. \"\n                          \"Remove directory %s or use -force\",\n                          vdc.GetDataDir(master).c_str());\n        exit(1);\n    }\n    if (FileUtils::Exists(master) && !opt.force) {\n        MyBase::SetErrMsg(\"\\\"%s\\\" already exists and -force option not used.\", master.c_str());\n        exit(1);\n    }\n\n    size_t chunksize = 1024 * 1024 * 4;\n    int    rc = vdc.Initialize(master, vector<string>(), VDC::W, opt.bs, chunksize);\n    if (rc < 0) exit(1);\n\n    vector<float> xcoords, ycoords, zcoords, tcoords;\n    string        xunit, yunit, zunit, tunit;\n    if (!opt.xcoords.empty()) {\n        rc = read_float_vec(opt.xcoords, opt.dim.nx, xcoords, xunit);\n        if (rc < 0) exit(1);\n    }\n    if (!opt.ycoords.empty()) {\n        rc = read_float_vec(opt.ycoords, opt.dim.ny, ycoords, yunit);\n        if (rc < 0) exit(1);\n    }\n    if (!opt.zcoords.empty()) {\n        rc = read_float_vec(opt.zcoords, opt.dim.nz, zcoords, zunit);\n        if (rc < 0) exit(1);\n    }\n    if (!opt.tcoords.empty()) {\n        rc = read_float_vec(opt.tcoords, opt.numts, tcoords, tunit);\n        if (rc < 0) exit(1);\n    }\n\n    vector<string> dimnames;\n    dimnames.push_back(\"Nx\");\n    dimnames.push_back(\"Ny\");\n    dimnames.push_back(\"Nz\");\n    dimnames.push_back(\"Nt\");\n\n    vector<size_t> dimlens;\n    dimlens.push_back(opt.dim.nx);\n    dimlens.push_back(opt.dim.ny);\n    dimlens.push_back(opt.dim.nz);\n    dimlens.push_back(opt.numts);\n\n    vector<size_t> cratios(1, 1);\n    rc = vdc.SetCompressionBlock(\"\", cratios);\n    rc = vdc.DefineDimension(dimnames[0], dimlens[0], 0);\n    rc = vdc.DefineDimension(dimnames[1], dimlens[1], 1);\n    rc = vdc.DefineDimension(dimnames[2], dimlens[2], 2);\n    rc = vdc.DefineDimension(dimnames[3], dimlens[3], 3);\n    if (rc < 0) exit(1);\n\n    if (!opt.xcoords.empty()) { rc = vdc.DefineCoordVar(dimnames[0], vector<string>{dimnames[0]}, \"\", xunit, 0, DC::XType::FLOAT, false); }\n    if (!opt.ycoords.empty()) { rc = vdc.DefineCoordVar(dimnames[1], vector<string>{dimnames[1]}, \"\", yunit, 1, DC::XType::FLOAT, false); }\n    if (!opt.zcoords.empty()) { rc = vdc.DefineCoordVar(dimnames[2], vector<string>{dimnames[2]}, \"\", zunit, 2, DC::XType::FLOAT, false); }\n    if (!opt.tcoords.empty()) { rc = vdc.DefineCoordVar(dimnames[3], vector<string>(), dimnames[3], tunit, 3, DC::XType::FLOAT, false); }\n\n    rc = vdc.SetCompressionBlock(opt.wname, opt.cratios);\n    if (rc < 0) exit(1);\n\n    for (int i = 0; i < opt.vars3d.size(); i++) { rc = vdc.DefineDataVar(opt.vars3d[i], dimnames, dimnames, \"\", xType, true); }\n    for (int i = 0; i < opt.ncvars3d.size(); i++) { rc = vdc.DefineDataVar(opt.ncvars3d[i], dimnames, dimnames, \"\", xType, false); }\n\n    vector<string> dimnames2dxy;\n    dimnames2dxy.push_back(dimnames[0]);\n    dimnames2dxy.push_back(dimnames[1]);\n    dimnames2dxy.push_back(dimnames[3]);\n\n    //\n    // Try to compute \"reasonable\" 2D compression ratios from 3D\n    // compression ratios\n    //\n    vector<size_t> cratios2D = opt.cratios;\n    for (int i = 0; i < cratios2D.size(); i++) {\n        size_t c = (size_t)pow((double)cratios2D[i], (double)(2.0 / 3.0));\n        cratios2D[i] = c;\n    }\n\n    rc = vdc.SetCompressionBlock(opt.wname, cratios2D);\n    if (rc < 0) exit(1);\n\n    for (int i = 0; i < opt.vars2dxy.size(); i++) { rc = vdc.DefineDataVar(opt.vars2dxy[i], dimnames2dxy, dimnames2dxy, \"\", xType, true); }\n    for (int i = 0; i < opt.ncvars2dxy.size(); i++) { rc = vdc.DefineDataVar(opt.ncvars2dxy[i], dimnames2dxy, dimnames2dxy, \"\", xType, false); }\n\n    vector<string> dimnames2dxz;\n    dimnames2dxz.push_back(dimnames[0]);\n    dimnames2dxz.push_back(dimnames[2]);\n    dimnames2dxz.push_back(dimnames[3]);\n    for (int i = 0; i < opt.vars2dxz.size(); i++) { rc = vdc.DefineDataVar(opt.vars2dxz[i], dimnames2dxz, dimnames2dxz, \"\", xType, true); }\n    for (int i = 0; i < opt.ncvars2dxz.size(); i++) { rc = vdc.DefineDataVar(opt.ncvars2dxz[i], dimnames2dxz, dimnames2dxz, \"\", xType, false); }\n\n    vector<string> dimnames2dyz;\n    dimnames2dyz.push_back(dimnames[1]);\n    dimnames2dyz.push_back(dimnames[2]);\n    dimnames2dyz.push_back(dimnames[3]);\n    for (int i = 0; i < opt.vars2dyz.size(); i++) { rc = vdc.DefineDataVar(opt.vars2dyz[i], dimnames2dyz, dimnames2dyz, \"\", xType, true); }\n    for (int i = 0; i < opt.ncvars2dyz.size(); i++) { rc = vdc.DefineDataVar(opt.ncvars2dyz[i], dimnames2dyz, dimnames2dyz, \"\", xType, false); }\n\n    vdc.EndDefine();\n\n    // Set coordinates to be uniform (e.g. a regular grid)\n    //\n    set_coords_uniform(vdc, opt.extents, dimnames, dimlens);\n\n    // Handle any stretched dimensions\n    //\n    if (xcoords.size()) { set_coord_stretched(vdc, dimnames[0], xcoords); }\n    if (ycoords.size()) { set_coord_stretched(vdc, dimnames[1], ycoords); }\n    if (zcoords.size()) { set_coord_stretched(vdc, dimnames[2], zcoords); }\n    if (tcoords.size()) { set_coord_stretched(vdc, dimnames[3], tcoords); }\n\n    return (0);\n}\n"
  },
  {
    "path": "apps/vdcdump/CMakeLists.txt",
    "content": "add_executable (vdcdump vdcdump.cpp)\n\ntarget_link_libraries (vdcdump common vdc)\n\nOpenMPInstall (\n\tTARGETS vdcdump\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/vdcdump/vdcdump.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cerrno>\n#include <csignal>\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\ntypedef VDCNetCDF::XType XType;\ntypedef DC::Dimension    Dimension;\ntypedef unsigned int     Verbosity;\n\nstruct Attribute;\nstruct Variable;\nstruct DataVariable;\nstruct CoordVariable;\nclass OutFormat;\n\n//---------------------------------------\n// Command Line Options\n//---------------------------------------\n\nstruct opt_t {\n    OptionParser::Boolean_T verbose;\n    OptionParser::Boolean_T ncOrder;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {\n    {\"verbose\", 0, \"0\", \"Print additional information\"}, {\"nc-order\", 0, \"0\", \"Reverse dimension order to match NetCDF\"}, {\"help\", 0, \"\", \"Print this message and exit\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"verbose\", Wasp::CvtToBoolean, &opt.verbose, sizeof(opt.verbose)},\n                                        {\"nc-order\", Wasp::CvtToBoolean, &opt.ncOrder, sizeof(opt.ncOrder)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\n//---------------------------------------\n// Utility Functions and Print Format\n//---------------------------------------\n\n#define Assert(tst)                                                                            \\\n    {                                                                                          \\\n        if (!(tst)) {                                                                          \\\n            cerr << \"[\" << __LINE__ << \":\" << __FILE__ << \"] Assert Failed: \" << #tst << endl; \\\n            std::raise(SIGINT);                                                                \\\n        }                                                                                      \\\n    }\n\nclass OutFormat {\nprotected:\n    int _depth;\n\npublic:\n    stringstream _ss;\n\n    OutFormat() : _depth(0) {}\n    void push() { _depth++; }\n    void pop()\n    {\n        _depth--;\n        Assert(_depth >= 0);\n    }\n    void pre()\n    {\n        for (int i = 0; i < _depth; i++) cout << \"\\t\";\n    }\n    void post()\n    {\n        cout << _ss.str() << \" ;\" << endl;\n        _ss.str(\"\");\n        _ss.clear();\n    }\n    void header(string name)\n    {\n        cout << \"----------------------------------\" << endl;\n        cout << name << endl;\n        cout << \"----------------------------------\" << endl;\n    }\n    void stringProperty(string owner, string name, string value)\n    {\n        pre();\n        _ss << owner << (owner == \"\" ? \"\" : \":\") << name << \" = \\\"\" << value << \"\\\"\";\n        post();\n    }\n    void boolProperty(string owner, string name, bool value)\n    {\n        pre();\n        _ss << owner << (owner == \"\" ? \"\" : \":\") << name << \" = \" << (value ? \"True\" : \"False\");\n        post();\n    }\n    void intProperty(string owner, string name, long value)\n    {\n        pre();\n        _ss << owner << (owner == \"\" ? \"\" : \":\") << name << \" = \" << value;\n        post();\n    }\n    void floatProperty(string owner, string name, double value)\n    {\n        pre();\n        _ss << owner << (owner == \"\" ? \"\" : \":\") << name << \" = \" << value;\n        post();\n    }\n    void typeProperty(string owner, XType type)\n    {\n        pre();\n        _ss << owner << (owner == \"\" ? \"\" : \":\") << \"Type = \" << GetTypeString(type);\n        post();\n    }\n    template<typename T> void vectorProperty(string owner, string name, vector<T> array, bool reversed)\n    {\n        pre();\n        _ss << owner << (owner == \"\" ? \"\" : \":\") << name << \" = \";\n        if (reversed)\n            for (int i = array.size() - 1; i >= 0; i--) _ss << (T)array[i] << (i == 0 ? \"\" : \", \");\n        else\n            for (int i = 0; i < array.size(); i++) _ss << (T)array[i] << (i == array.size() - 1 ? \"\" : \", \");\n        post();\n    }\n    void category(string name)\n    {\n        pre();\n        _ss << name;\n        post();\n    }\n    static string GetAxisString(int axis)\n    {\n        switch (axis) {\n        case 0: return \"X\";\n        case 1: return \"Y\";\n        case 2: return \"Z\";\n        case 3: return \"Time\";\n        default: return std::to_string((long long int)axis);\n        }\n    }\n    static string GetTypeString(XType type)\n    {\n        switch (type) {\n        case XType::UINT8: return \"uint8\";\n        case XType::INT8: return \"int8\";\n        case XType::INT32: return \"int32\";\n        case XType::INT64: return \"int64\";\n        case XType::FLOAT: return \"float\";\n        case XType::DOUBLE: return \"double\";\n        case XType::TEXT: return \"text\";\n        case XType::INVALID: return \"INVALID\";\n        default: return \"INVALID\";\n        };\n    }\n};\n\n//---------------------------------------\n// Classes that load and print vdc data\n//---------------------------------------\n\nstruct Attribute {\n    string         _name;\n    XType          _type;\n    vector<long>   _ivalues;\n    vector<double> _fvalues;\n    string         _svalues;\n\n    Attribute(string name, XType type) : _name(name), _type(type) {}\n    bool isInt() { return _type == XType::INT32 || _type == XType::INT64; }\n    bool isFloat() { return _type == XType::FLOAT || _type == XType::DOUBLE; }\n    bool isText() { return _type == XType::TEXT; }\n    void print(OutFormat *out, string parentName)\n    {\n        if (isText())\n            out->stringProperty(parentName, _name, _svalues);\n        else if (isInt())\n            out->vectorProperty<long>(parentName, _name, _ivalues, false);\n        else\n            out->vectorProperty<double>(parentName, _name, _fvalues, false);\n    }\n};\n\nstruct Variable {\n    string            _name;\n    DC::BaseVar *     _data;\n    vector<Attribute> _attributes;\n    vector<string>    _dimnames;\n\n    Variable(string name, VDCNetCDF &vdc) : _name(name), _data(0)\n    {\n        //\n        // Get Attributes\n        //\n        vector<string> attNames = vdc.GetAttNames(name);\n        for (int i = 0; i < attNames.size(); i++) {\n            _attributes.push_back(Attribute(attNames[i], vdc.GetAttType(name, attNames[i])));\n            if (_attributes[i].isInt())\n                vdc.GetAtt(name, attNames[i], _attributes[i]._ivalues);\n            else if (_attributes[i].isFloat())\n                vdc.GetAtt(name, attNames[i], _attributes[i]._fvalues);\n            else if (_attributes[i].isText())\n                vdc.GetAtt(name, attNames[i], _attributes[i]._svalues);\n        }\n        vdc.GetVarDimNames(_name, false, _dimnames);\n    }\n    virtual ~Variable() {}\n\n    void printName(OutFormat *out, Verbosity V, bool reversedCoordOrder)\n    {\n        out->pre();\n        out->_ss << OutFormat::GetTypeString(_data->GetXType()) << \" \" << _name << \"(\";\n        if (reversedCoordOrder)\n            for (int i = _dimnames.size() - 1; i >= 0; i--) out->_ss << _dimnames[i] << (i != 0 ? \", \" : \"\");\n        else\n            for (int i = 0; i < _dimnames.size(); i++) out->_ss << _dimnames[i] << (i != _dimnames.size() - 1 ? \", \" : \"\");\n        out->_ss << \")\";\n        out->post();\n    }\n\n    virtual void printChild(OutFormat *out, Verbosity V, bool reversedCoordOrder) = 0;\n    virtual void print(OutFormat *out, Verbosity V, bool reversedCoordOrder)\n    {\n        printName(out, V, reversedCoordOrder);\n        out->push();\n        // Print VDC specific data if verbose\n        if (V >= 1) {\n            out->stringProperty(_name, \"Units\", _data->GetUnits());\n            out->stringProperty(_name, \"WName\", _data->GetWName());\n            out->vectorProperty<size_t>(_name, \"CRatios\", _data->GetCRatios(), false);\n            out->vectorProperty<bool>(_name, \"Periodic\", _data->GetPeriodic(), false);\n        }\n\n        // Print information specific to Data or Coordinate variable\n        printChild(out, V, reversedCoordOrder);\n\n        // Print attributes\n        if (_attributes.size()) {\n            out->category(\"Attributes\");\n            out->push();\n            for (int i = 0; i < _attributes.size(); i++) _attributes[i].print(out, _name);\n            out->pop();\n        }\n        out->pop();\n    }\n};\n\nstruct DataVariable : public Variable {\n    vector<string> _coordvars;\n\n    DataVariable(string name, VDCNetCDF &vdc) : Variable(name, vdc)\n    {\n        _data = new DC::DataVar();\n        vdc.GetDataVarInfo(name, *(DC::DataVar *)_data);\n        vdc.GetVarCoordVars(name, false, _coordvars);\n    }\n    ~DataVariable()\n    {\n        if (_data) delete _data;\n    }\n\n    void printChild(OutFormat *out, Verbosity V, bool reversedCoordOrder)\n    {\n        out->vectorProperty(_name, \"Coord Vars\", _coordvars, reversedCoordOrder);\n\n        // Print VDC specific data if verbose\n        if (V >= 1) {\n            out->stringProperty(_name, \"Mask Var\", ((DC::DataVar *)_data)->GetMaskvar());\n            out->boolProperty(_name, \"Has Missing\", ((DC::DataVar *)_data)->GetHasMissing());\n            out->boolProperty(_name, \"Missing Value\", ((DC::DataVar *)_data)->GetMissingValue());\n        }\n    }\n};\n\nstruct CoordVariable : public Variable {\n    CoordVariable(string name, VDCNetCDF &vdc) : Variable(name, vdc)\n    {\n        _data = new DC::CoordVar();\n        vdc.GetCoordVarInfo(name, *(DC::CoordVar *)_data);\n    }\n    ~CoordVariable()\n    {\n        if (_data) delete _data;\n    }\n\n    void printChild(OutFormat *out, Verbosity V, bool reversedCoordOrder)\n    {\n        out->stringProperty(_name, \"Axis\", OutFormat::GetAxisString(((DC::CoordVar *)_data)->GetAxis()));\n\n        // Print VDC specific data if verbose\n        if (V >= 1) { out->boolProperty(_name, \"Uniform\", ((DC::CoordVar *)_data)->GetUniform()); }\n    }\n};\n\nstruct GlobalData : public Variable {\n    vector<DC::Dimension> _dimensions;\n\n    GlobalData(VDCNetCDF &vdc) : Variable(\"\", vdc)\n    {\n        _name = \"__GLOBAL__\";\n        vector<string> dimNames = vdc.GetDimensionNames();\n        _dimensions.resize(dimNames.size());\n        for (int i = 0; i < dimNames.size(); i++) vdc.GetDimension(dimNames[i], _dimensions[i], -1);\n    }\n    void printChild(OutFormat *out, Verbosity V, bool reversedCoordOrder) {}\n    void print(OutFormat *out, Verbosity V, bool reversedCoordOrder)\n    {\n        out->category(\"Dimensions\");\n        out->push();\n        for (int i = 0; i < _dimensions.size(); i++) {\n            out->category(_dimensions[i].GetName());\n            out->push();\n            out->intProperty(\"\", \"Length\", _dimensions[i].GetLength());\n            out->pop();\n        }\n        out->pop();\n\n        out->category(\"Attributes\");\n        out->push();\n        for (int i = 0; i < _attributes.size(); i++) _attributes[i].print(out, \"\");\n        out->pop();\n    }\n};\n\n//---------------------------------------\n// Utility Functions and Print Format\n//---------------------------------------\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    const char * progName = FileUtils::LegacyBasename(argv[0]);\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << progName << \": \" << op.GetErrMsg();\n        exit(1);\n    }\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << progName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n    if (opt.help) {\n        cerr << \"Usage: \" << progName << \" [options] vdc.vdc\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n    if (argc != 2) {\n        cerr << \"Usage: \" << progName << \" vdcmaster.vdc\" << endl;\n        exit(1);\n    }\n\n    VDCNetCDF vdc(1);\n    int       rc = vdc.Initialize(string(argv[1]), vector<string>(), VDC::R, vector<size_t>(), 4 * 1024 * 1024);\n    if (rc < 0) exit(1);\n\n    //\n    // Allocate VDC data\n    //\n    GlobalData *            globalData;\n    vector<DataVariable *>  variables;\n    vector<CoordVariable *> coordinates;\n\n    //\n    // Load VDC data\n    //\n    globalData = new GlobalData(vdc);\n    vector<string> varNames = vdc.GetDataVarNames();\n    for (int i = 0; i < varNames.size(); i++) variables.push_back(new DataVariable(varNames[i], vdc));\n    vector<string> coordNames = vdc.GetCoordVarNames();\n    for (int i = 0; i < coordNames.size(); i++) coordinates.push_back(new CoordVariable(coordNames[i], vdc));\n\n    //\n    // Print VDC data\n    //\n    OutFormat *out = new OutFormat;\n    out->header(\"Global Data\");\n\n    globalData->print(out, opt.verbose, opt.ncOrder);\n\n    out->header(\"Data Variables\");\n    for (int i = 0; i < variables.size(); i++) variables[i]->print(out, opt.verbose, opt.ncOrder);\n\n    out->header(\"Coordinate Variables\");\n    for (int i = 0; i < coordinates.size(); i++) coordinates[i]->print(out, opt.verbose, opt.ncOrder);\n\n    return 0;\n}\n"
  },
  {
    "path": "apps/vdcerr/vdcerr.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include <cerrno>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/WaveCodecIO.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    int                     ts;\n    char *                  varname;\n    int                     lod;\n    int                     nthreads;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"ts\", 1, \"0\", \"Timestep of data file starting from 0\"},\n                                         {\"varname\", 1, \"var1\", \"Name of variable\"},\n                                         {\"lod\", 1, \"-1\", \"Compression level of detail. Zero implies coarsest approximation\"},\n                                         {\"nthreads\", 1, \"0\", \"Number of execution threads (0=># processors)\"},\n                                         {\"quiet\", 0, \"\", \"Be less verbose\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"ts\", Wasp::CvtToInt, &opt.ts, sizeof(opt.ts)},\n                                        {\"varname\", Wasp::CvtToString, &opt.varname, sizeof(opt.varname)},\n                                        {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nconst char *ProgName;\n\nfloat *read_vdc_volume(string metafile, size_t dims[3], bool &has_missing, float &mv)\n{\n    has_missing = false;\n    mv = 0.0;\n    string varname = opt.varname;\n\n    WaveCodecIO *wcreader = new WaveCodecIO(metafile, opt.nthreads);\n    if (wcreader->GetErrCode() != 0) { return (NULL); }\n\n    if (wcreader->OpenVariableRead(opt.ts, varname.c_str(), -1, opt.lod) < 0) { return (NULL); }\n\n    if (wcreader->GetVMissingValue(opt.ts, varname).size() == 1) {\n        mv = wcreader->GetVMissingValue(0, varname)[0];\n        has_missing = true;\n    } else if (wcreader->GetTSMissingValue(opt.ts).size() == 1) {\n        mv = wcreader->GetTSMissingValue(opt.ts)[0];\n        has_missing = true;\n    } else if (wcreader->GetMissingValue().size() == 1) {\n        mv = wcreader->GetMissingValue()[0];\n        has_missing = true;\n    }\n\n    Metadata::VarType_T vtype = wcreader->GetVarType(varname);\n    wcreader->GetDim(dims, -1);\n\n    switch (vtype) {\n    case Metadata::VAR2D_XY: dims[2] = 1; break;\n\n    case Metadata::VAR2D_XZ:\n        dims[1] = dims[2];\n        dims[2] = 1;\n        break;\n    case Metadata::VAR2D_YZ:\n        dims[0] = dims[1];\n        dims[1] = dims[2];\n        dims[2] = 1;\n        break;\n    case Metadata::VAR3D: break;\n    default: break;\n    }\n\n    size_t slice_size = dims[0] * dims[1];\n    float *buf = new float[slice_size * dims[2]];\n    float *bufptr = buf;\n    VAssert(buf != NULL);\n\n    for (int z = 0; z < dims[2]; z++) {\n        if (!opt.quiet && z % 10 == 0) { cout << \"Reading vdc slice # \" << z << endl; }\n\n        if (wcreader->ReadSlice(bufptr) < 0) { return (NULL); }\n        bufptr += slice_size;\n    }\n    wcreader->CloseVariable();\n\n    return (buf);\n}\n\nfloat *read_raw_volume(string file, const size_t dims[3])\n{\n    FILE *fp = FOPEN64(file.c_str(), \"r\");\n    if (!fp) {\n        MyBase::SetErrMsg(\"Could not open file \\\"%s\\\" : %M\", file.c_str());\n        return (NULL);\n    }\n\n    size_t slice_size = dims[0] * dims[1];\n    float *buf = new float[slice_size * dims[2]];\n    float *bufptr = buf;\n    VAssert(buf != NULL);\n\n    for (int z = 0; z < dims[2]; z++) {\n        if (!opt.quiet && z % 10 == 0) { cout << \"Reading raw slice # \" << z << endl; }\n\n        int rc = fread(bufptr, sizeof(bufptr[0]), slice_size, fp);\n        if (rc != slice_size) {\n            MyBase::SetErrMsg(\"Errore reading slice : %M\");\n            return (NULL);\n        }\n        bufptr += slice_size;\n    }\n\n    fclose(fp);\n    return (buf);\n}\n\nvoid compute_error(const float *odata, const float *cdata, size_t nelements, bool has_missing, float mv, float &lmax, float &rms, float &min, float &max)\n{\n    lmax = 0.0;\n    rms = 0.0;\n    min = 0.0;\n    max = 0.0;\n\n    double delta = 0;\n    double sqrsum = 0;\n    size_t nvalid = 0;\n\n    bool first = true;\n    for (size_t idx = 0; idx < nelements; idx++) {\n        if (has_missing && cdata[idx] == mv) continue;\n\n        nvalid++;\n\n        if (first) {\n            min = max = odata[idx];\n            first = false;\n        }\n        if (min > odata[idx]) min = odata[idx];\n        if (max < odata[idx]) max = odata[idx];\n\n        delta = fabs(odata[idx] - cdata[idx]);\n        if (delta > lmax) lmax = delta;\n\n        sqrsum += (odata[idx] - cdata[idx]) * (odata[idx] - cdata[idx]);\n    }\n\n    rms = (float)sqrt(sqrsum / (double)nvalid);\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       metafile;\n    string       datafile;\n\n    ProgName = Basename(argv[0]);\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] metafile datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (argc != 3) {\n        cerr << \"Usage: \" << ProgName << \" [options] metafile datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    metafile = argv[1];\n    datafile = argv[2];\n\n    size_t dims[3];\n    bool   has_missing;\n    float  mv;\n    float *vdcdata = read_vdc_volume(metafile, dims, has_missing, mv);\n    if (!vdcdata) exit(1);\n\n    float *rawdata = read_raw_volume(datafile, dims);\n    if (!rawdata) exit(1);\n\n    float lmax, rms, min, max;\n    compute_error(rawdata, vdcdata, dims[0] * dims[1] * dims[2], has_missing, mv, lmax, rms, min, max);\n    float lmaxrel = 0.0;\n    if ((max - min) != 0.0) lmaxrel = lmax / (max - min);\n    float nrms = 0.0;\n    if ((max - min) != 0.0) nrms = rms / (max - min);\n\n    cout << \"Range : \" << min << \" .. \" << max << endl;\n    cout << \"Lmax : \" << lmax << endl;\n    cout << \"Lmax Relative: \" << lmaxrel << endl;\n    cout << \"RMS : \" << rms << endl;\n    cout << \"Normalized RMS : \" << nrms << endl;\n\n    exit(0);\n}\n"
  },
  {
    "path": "apps/wasp2ncdf/CMakeLists.txt",
    "content": "add_executable (wasp2ncdf wasp2ncdf.cpp)\n\ntarget_link_libraries (wasp2ncdf common wasp)\n\nOpenMPInstall (\n\tTARGETS wasp2ncdf\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/wasp2ncdf/wasp2ncdf.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cerrno>\n#include <cmath>\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/WASP.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n//\tCommand line argument stuff\n//\nstruct opt_t {\n    string                  varname;\n    int                     lod;\n    int                     nthreads;\n    std::vector<string>     xvarnames;\n    OptionParser::Boolean_T debug;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"varname\", 1, \"var1\", \"Name of variable\"},\n                                         {\"lod\", 1, \"-1\",\n                                          \"Compression levels saved. 0 => coarsest, 1 => \"\n                                          \"next refinement, etc. -1 => all levels defined by the netcdf file\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"xvarnames\", 1, \"\",\n                                          \"Colon delimited list of variable names \"\n                                          \"to exclude from compression.\"},\n                                         {\"debug\", 0, \"\", \"Enable diagnostic\"},\n                                         {\"quiet\", 0, \"\", \"Operate quietly\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"varname\", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)}, {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {\"xvarnames\", Wasp::CvtToStrVec, &opt.xvarnames, sizeof(opt.xvarnames)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},      {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},         {NULL}};\n\nconst char *ProgName;\n\n// Return true if string 'name' contained in vector of strings, 'names'\n//\nbool name_in(string name, const vector<string> &names) { return (find(names.begin(), names.end(), name) != names.end()); }\n\nint GetDims(const WASP &wasp, vector<string> &dimnames, vector<size_t> &dimlens)\n{\n    dimnames.clear();\n    dimlens.clear();\n\n    vector<string> vars;\n    int            rc = wasp.InqVarnames(vars);\n    if (rc < 0) return (-1);\n\n    // Ugh. No easy way to find all of the implicitly defined WASP\n    // dimensions in a file. So find all explicitly defined\n    // dimensions for each variable, and use that list to build\n    // list of dimensions\n    //\n    vector<string> all_dimnames;\n    for (int i = 0; i < vars.size(); i++) {\n        vector<string> var_dimnames;\n        vector<size_t> dummy;\n\n        int rc = wasp.InqVarDims(vars[i], var_dimnames, dummy);\n        if (rc < 0) return (-1);\n\n        all_dimnames.insert(all_dimnames.begin(), var_dimnames.begin(), var_dimnames.end());\n    }\n\n    //\n    // sort and remove duplicates\n    //\n    sort(all_dimnames.begin(), all_dimnames.end());\n    vector<string>::iterator lasts;\n    lasts = unique(all_dimnames.begin(), all_dimnames.end());\n    all_dimnames.erase(lasts, all_dimnames.end());\n\n    vector<string> my_dimnames;\n    vector<size_t> my_dimlens;\n\n    rc = wasp.InqDims(my_dimnames, my_dimlens);\n    if (rc < 0) return (-1);\n\n    VAssert(my_dimnames.size() == my_dimlens.size());\n\n    for (int i = 0; i < my_dimnames.size(); i++) {\n        if (name_in(my_dimnames[i], all_dimnames)) {\n            dimnames.push_back(my_dimnames[i]);\n            dimlens.push_back(my_dimlens[i]);\n        }\n    }\n    return (0);\n}\n\n//\n// Define the WASP output file using 'ncdf' as a template\n//\nint DefFile(const WASP &wasp, NetCDFCpp &ncdf)\n{\n    vector<string> dimnames;\n    vector<size_t> dimlens;\n\n    int rc = GetDims(wasp, dimnames, dimlens);\n    if (rc < 0) return (-1);\n\n    VAssert(dimnames.size() == dimlens.size());\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        rc = ncdf.DefDim(dimnames[i], dimlens[i]);\n        if (rc < 0) return (-1);\n    }\n\n    vector<string> attnames;\n    rc = wasp.InqAttnames(\"\", attnames);\n    if (rc < 0) return (-1);\n\n    for (int i = 0; i < attnames.size(); i++) {\n        if (attnames[i].find(\"WASP\") != std::string::npos) continue;\n\n        rc = wasp.CopyAtt(\"\", attnames[i], ncdf, \"\");\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\n// Get all of the variable names, and parse\n// the names into a vector of\n// variable names that will be copied verbatim, and a vector of variable\n// names that will be de-compressed.\n//\n\nint GetVarNames(const WASP &wasp, vector<string> &vars, vector<string> &copy_vars, vector<string> &compress_vars)\n{\n    vars.clear();\n    copy_vars.clear();\n    compress_vars.clear();\n\n    int rc = wasp.InqVarnames(vars);\n    if (rc < 0) return (-1);\n\n    for (int i = 0; i < vars.size(); i++) {\n        bool wasp_var;\n        rc = wasp.InqVarWASP(vars[i], wasp_var);\n        if (rc < 0) return (-1);\n\n        if (wasp_var) {\n            compress_vars.push_back(vars[i]);\n        } else {\n            copy_vars.push_back(vars[i]);\n        }\n    }\n\n    return (0);\n}\n\n// Copy variables verbatim from 'wasp' to 'ncdf'\n//\nint CopyVars(NetCDFCpp &wasp, const vector<string> &copy_vars, NetCDFCpp &ncdf)\n{\n    for (int i = 0; i < copy_vars.size(); i++) {\n        if (!opt.quiet) { cout << \"Copying variable \" << copy_vars[i] << endl; }\n        int rc = wasp.CopyVar(copy_vars[i], ncdf);\n        if (rc < 0) return (-1);\n    }\n    return (0);\n}\n\n// Define a variable that will not be compressed (i.e copied verbatim)\n//\nint DefCopyVar(const WASP &wasp, string varname, NetCDFCpp &ncdf)\n{\n    vector<string> dimnames;\n    vector<size_t> dimlens;\n    int            rc = wasp.InqVarDims(varname, dimnames, dimlens);\n    if (rc < 0) return (-1);\n\n    nc_type xtype;\n    rc = wasp.InqVartype(varname, xtype);\n    if (rc < 0) return (-1);\n\n    rc = ncdf.DefVar(varname, xtype, dimnames);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\n// Define all variables in 'wasp', preserving the variable order\n// in 'ncdf'\n//\nint DefVars(const WASP &wasp, const vector<string> &vars, NetCDFCpp &ncdf)\n{\n    int rc;\n    for (int i = 0; i < vars.size(); i++) {\n        rc = DefCopyVar(wasp, vars[i], ncdf);\n        if (rc < 0) return (-1);\n\n        // Now copy variable attributes\n        //\n        vector<string> attnames;\n        rc = wasp.InqAttnames(vars[i], attnames);\n        if (rc < 0) return (-1);\n\n        for (int j = 0; j < attnames.size(); j++) {\n            if (attnames[j].find(\"WASP\") != std::string::npos) continue;\n\n            rc = wasp.CopyAtt(vars[i], attnames[j], ncdf, vars[i]);\n            if (rc < 0) return (-1);\n        }\n    }\n    return (0);\n}\n\n// Compress variables\n//\nint DeCompressVars(WASP &wasp, const vector<string> &copy_vars, NetCDFCpp &ncdf)\n{\n    for (int i = 0; i < copy_vars.size(); i++) {\n        if (!opt.quiet) { cout << \"Decompressing  variable \" << copy_vars[i] << endl; }\n        int rc = wasp.CopyVarTo(copy_vars[i], ncdf);\n        if (rc < 0) return (-1);\n    }\n    return (0);\n}\n\nvoid Process(string waspfile, string ncdffile)\n{\n    NetCDFCpp ncdf;\n    WASP      wasp;\n    size_t    chunksize = 1024 * 1024 * 4;\n\n    int rc = wasp.Open(waspfile, NC_NOWRITE);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Error opening %s for reading\", waspfile.c_str());\n        exit(1);\n    }\n\n    rc = ncdf.Create(ncdffile, NC_64BIT_OFFSET, 0, chunksize);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Error opening %s for writing\", ncdffile.c_str());\n        exit(1);\n    }\n\n    rc = DefFile(wasp, ncdf);\n    if (rc < 0) exit(1);\n\n    vector<string> vars, copy_vars, compress_vars;\n    rc = GetVarNames(wasp, vars, copy_vars, compress_vars);\n    if (rc < 0) exit(1);\n\n    rc = DefVars(wasp, vars, ncdf);\n    if (rc < 0) exit(1);\n\n    rc = ncdf.EndDef();\n    if (rc < 0) exit(1);\n\n    rc = CopyVars(wasp, copy_vars, ncdf);\n    if (rc < 0) exit(1);\n\n    rc = DeCompressVars(wasp, compress_vars, ncdf);\n    if (rc < 0) exit(1);\n\n    (void)wasp.Close();\n    rc = ncdf.Close();\n    if (rc < 0) exit(1);\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { exit(1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] waspfile ncdffile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (argc != 3) {\n        cerr << \"Usage: \" << ProgName << \" [options] waspfile ncdffile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    string waspfile = argv[1];    // Path to wasp file\n    string ncdffile = argv[2];    // Path to a vdf file\n\n    if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr);\n\n    Process(waspfile, ncdffile);\n\n    return (0);\n}\n"
  },
  {
    "path": "apps/wasp2raw/CMakeLists.txt",
    "content": "add_executable (wasp2raw wasp2raw.cpp)\n\ntarget_link_libraries (wasp2raw common wasp)\n\nOpenMPInstall (\n\tTARGETS wasp2raw\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/wasp2raw/wasp2raw.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cerrno>\n#include <stdio.h>\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/WASP.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n//\tCommand line argument stuff\n//\nstruct opt_t {\n    string                  varname;\n    string                  type;\n    int                     lod;\n    int                     level;\n    int                     nthreads;\n    vector<int>             start;\n    vector<int>             count;\n    OptionParser::Boolean_T debug;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"varname\", 1, \"var1\", \"Name of variable\"},\n                                         {\"type\", 1, \"float32\", \"Primitive type of output data\"},\n                                         {\"lod\", 1, \"-1\",\n                                          \"Compression levels saved. 0 => coarsest, 1 => \"\n                                          \"next refinement, etc. -1 => all levels defined by the netcdf file\"},\n                                         {\"level\", 1, \"-1\",\n                                          \"Multiresolution refinement level. Zero implies coarsest \"\n                                          \"resolution\"},\n                                         {\"start\", 1, \"\", \"Colon-delimited NetCDF style start coordinate vector\"},\n                                         {\"count\", 1, \"\", \"Colon-delimited NetCDF style count coordinate vector\"},\n                                         {\"nthreads\", 1, \"0\", \"Number of execution threads. 0 => use number of cores\"},\n                                         {\"debug\", 0, \"\", \"Enable diagnostic\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"varname\", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)},\n                                        {\"type\", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)},\n                                        {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n                                        {\"level\", Wasp::CvtToInt, &opt.level, sizeof(opt.level)},\n                                        {\"start\", Wasp::CvtToIntVec, &opt.start, sizeof(opt.start)},\n                                        {\"count\", Wasp::CvtToIntVec, &opt.count, sizeof(opt.count)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nconst char *ProgName;\n\ntemplate<class T> void CopyVar(string ncdffile, string datafile, T dummy)\n{\n    WASP wasp(opt.nthreads);\n\n    int rc = wasp.Open(ncdffile, NC_WRITE);\n\n    vector<size_t> dims;\n    vector<size_t> bs;\n    rc = wasp.InqVarDimlens(opt.varname, opt.level, dims, bs);\n    if (rc < 0) exit(1);\n\n    rc = wasp.OpenVarRead(opt.varname, opt.level, opt.lod);\n    if (rc < 0) exit(1);\n\n    vector<size_t> start(dims.size(), 0);\n    if (opt.start.size()) {\n        if (opt.start.size() != dims.size()) {\n            MyBase::SetErrMsg(\"Invalid start specification\");\n            exit(1);\n        }\n        for (int i = 0; i < opt.start.size(); i++) { start[i] = opt.start[i]; }\n    }\n\n    vector<size_t> count = dims;\n    if (opt.count.size()) {\n        if (opt.count.size() != dims.size()) {\n            MyBase::SetErrMsg(\"Invalid count specification\");\n            exit(1);\n        }\n        for (int i = 0; i < opt.count.size(); i++) { count[i] = opt.count[i]; }\n    }\n\n    size_t nelements = 1;\n    for (int i = 0; i < count.size(); i++) nelements *= count[i];\n\n    T *data = new T[nelements];\n\n    rc = wasp.GetVara(start, count, data);\n    if (rc < 0) exit(1);\n\n    rc = wasp.CloseVar();\n    if (rc < 0) exit(1);\n\n    rc = wasp.Close();\n    if (rc < 0) exit(1);\n\n    FILE *fp = fopen(datafile.c_str(), \"wb\");\n    if (!fp) {\n        MyBase::SetErrMsg(\"fopen(%s) : %M\", datafile.c_str());\n        exit(1);\n    }\n\n    rc = fwrite(data, sizeof(*data), nelements, fp);\n    if (rc != nelements) {\n        MyBase::SetErrMsg(\"fread() : %M\");\n        exit(1);\n    }\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { exit(1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] netcdffile datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (argc != 3) {\n        cerr << \"Usage: \" << ProgName << \" [options] netcdffile datafile\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    string ncdffile = argv[1];    // Path to a vdf file\n    string datafile = argv[2];    // Path to raw data file\n\n    if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr);\n\n    if (opt.type == \"float32\") {\n        float dummy = 0.0;\n        CopyVar(ncdffile, datafile, dummy);\n    } else if (opt.type == \"float64\") {\n        double dummy = 0.0;\n        CopyVar(ncdffile, datafile, dummy);\n    } else if (opt.type == \"int32\") {\n        int dummy = 0;\n        CopyVar(ncdffile, datafile, dummy);\n    } else if (opt.type == \"int16\") {\n        int16_t dummy = 0;\n        CopyVar(ncdffile, datafile, dummy);\n    } else if (opt.type == \"uint8\") {\n        unsigned char dummy = 0;\n        CopyVar(ncdffile, datafile, dummy);\n    } else {\n        cerr << \"Invalid type \" << opt.type << endl;\n    }\n\n    return (0);\n}\n"
  },
  {
    "path": "apps/waspcreate/CMakeLists.txt",
    "content": "add_executable (waspcreate waspcreate.cpp)\n\ntarget_link_libraries (waspcreate common wasp)\n\nOpenMPInstall (\n\tTARGETS waspcreate\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/waspcreate/waspcreate.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string.h>\n#include <vector>\n#include <sstream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/CFuncs.h>\n#include <vapor/WASP.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    vector<string>          dimnames;\n    vector<int>             dimlens;\n    std::vector<size_t>     cratios;\n    string                  wname;\n    string                  ofile;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"dimnames\", 1, \"\", \"Colon delimited list of dimension names\"},\n                                         {\"dimlens\", 1, \"\", \"Colon delimited list of dimension lengths\"},\n                                         {\"wname\", 1, \"bior4.4\",\n                                          \"Wavelet family used for compression \"\n                                          \"Valid values are bior1.1, bior1.3, \"\n                                          \"bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, \"\n                                          \"bior3.5, bior3.7, bior3.9, bior4.4 intbior2.2\"},\n                                         {\"cratios\", 1, \"500:100:10:1\",\n                                          \"Colon delimited list compression ratios. \"\n                                          \"The default is 500:100:10:1. The maximum compression ratio \"\n                                          \"is wavelet and block size dependent.\"},\n                                         {\"ofile\", 1, \"test.nc\", \"Output file\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"dimnames\", Wasp::CvtToStrVec, &opt.dimnames, sizeof(opt.dimnames)},\n                                        {\"dimlens\", Wasp::CvtToIntVec, &opt.dimlens, sizeof(opt.dimlens)},\n                                        {\"cratios\", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)},\n                                        {\"wname\", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)},\n                                        {\"ofile\", Wasp::CvtToCPPStr, &opt.ofile, sizeof(opt.ofile)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nstring ProgName;\n\nvector<string> split(string s, string delim)\n{\n    size_t         pos = 0;\n    vector<string> tokens;\n    while ((pos = s.find(delim)) != std::string::npos) {\n        tokens.push_back(s.substr(0, pos));\n        s.erase(0, pos + delim.length());\n    }\n    if (!s.empty()) tokens.push_back(s);\n\n    return (tokens);\n}\n\nnc_type parsextype(string xtypestr)\n{\n    if (xtypestr.compare(\"NC_BYTE\") == 0) return (NC_BYTE);\n    if (xtypestr.compare(\"NC_UBYTE\") == 0) return (NC_UBYTE);\n    if (xtypestr.compare(\"NC_CHAR\") == 0) return (NC_CHAR);\n    if (xtypestr.compare(\"NC_SHORT\") == 0) return (NC_SHORT);\n    if (xtypestr.compare(\"NC_USHORT\") == 0) return (NC_USHORT);\n    if (xtypestr.compare(\"NC_INT\") == 0) return (NC_INT);\n    if (xtypestr.compare(\"NC_UINT\") == 0) return (NC_UINT);\n    if (xtypestr.compare(\"NC_FLOAT\") == 0) return (NC_FLOAT);\n    if (xtypestr.compare(\"NC_INT64\") == 0) return (NC_INT64);\n    if (xtypestr.compare(\"NC_UINT64\") == 0) return (NC_UINT64);\n    if (xtypestr.compare(\"NC_DOUBLE\") == 0) return (NC_DOUBLE);\n    return (-1);\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { exit(1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] [name:type:count[:dimname]+]+\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(0);\n    }\n\n    if (opt.dimnames.size() != opt.dimlens.size()) {\n        MyBase::SetErrMsg(\"dimension name and dimension length vector size mismatch\");\n        exit(1);\n    }\n\n    WASP           wasp;\n    vector<size_t> bs;\n    bs.push_back(64);\n    bs.push_back(64);\n    bs.push_back(64);\n    size_t chunksize = 1024 * 1024 * 4;\n\n    vector<size_t> cratios3D = opt.cratios;\n\n    vector<size_t> cratios2D = cratios3D;\n    vector<size_t> cratios1D = cratios3D;\n    for (int i = 0; i < cratios2D.size(); i++) {\n        size_t c = (size_t)pow((double)cratios2D[i], (double)(2.0 / 3.0));\n        cratios2D[i] = c;\n\n        c = (size_t)pow((double)cratios2D[i], (double)(1.0 / 3.0));\n        cratios2D[i] = c;\n    }\n\n    int rc = wasp.Create(opt.ofile, NC_64BIT_OFFSET, 0, chunksize, cratios3D.size());\n    if (rc < 0) exit(1);\n\n    int dummy;\n    rc = wasp.SetFill(NC_NOFILL, dummy);\n    if (rc < 0) exit(1);\n\n    for (int i = 0; i < opt.dimnames.size(); i++) {\n        int rc = wasp.DefDim(opt.dimnames[i], opt.dimlens[i]);\n        if (rc < 0) exit(1);\n    }\n\n    argc--;\n    argv++;\n    for (int i = 0; i < argc; i++) {\n        string         s = argv[i];\n        vector<string> vardef = split(s, \":\");\n        if (vardef.size() < 4) {\n            MyBase::SetErrMsg(\"Invalid variable definition : %s\", s.c_str());\n            exit(1);\n        }\n\n        string name = vardef[0];\n        vardef.erase(vardef.begin());\n\n        string xtypestr = vardef[0];\n        vardef.erase(vardef.begin());\n        int xtype = parsextype(xtypestr);\n\n        size_t ncdims;\n        std::istringstream(vardef[0]) >> ncdims;\n        vardef.erase(vardef.begin());\n\n        // Everything else should be dimension name\n        //\n        vector<string> dimnames = vardef;\n\n        if (ncdims == 0) {\n            vector<size_t> cratios;\n\n            int rc = wasp.DefVar(name, xtype, dimnames, \"\", bs, cratios);\n            if (rc < 0) exit(1);\n\n        } else {\n            vector<size_t> cratios;\n            if (ncdims == 3) cratios = cratios3D;\n            if (ncdims == 2) cratios = cratios2D;\n            if (ncdims == 1) cratios = cratios1D;\n            int rc = wasp.DefVar(name, xtype, dimnames, opt.wname, bs, cratios);\n            if (rc < 0) exit(1);\n        }\n    }\n\n    wasp.EndDef();\n    wasp.Close();\n}\n"
  },
  {
    "path": "apps/wrf2vdc/CMakeLists.txt",
    "content": "add_executable (wrf2vdc wrf2vdc.cpp)\n\ntarget_link_libraries (wrf2vdc common vdc)\n\nOpenMPInstall (\n\tTARGETS wrf2vdc\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/wrf2vdc/wrf2vdc.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string.h>\n#include <vector>\n#include <sstream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/CFuncs.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/DCWRF.h>\n#include <vapor/FileUtils.h>\n#include <vapor/SetHDF5PluginPath.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    int                     nthreads;\n    int                     numts;\n    std::vector<string>     vars;\n    std::vector<string>     xvars;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"numts\", 1, \"-1\", \"Number of timesteps to be included in the VDC. Default (-1) includes all timesteps.\"},\n                                         {\"vars\", 1, \"\",\n                                          \"Colon delimited list of variable names \"\n                                          \"to be copied to the VDC\"},\n                                         {\"xvars\", 1, \"\",\n                                          \"Colon delimited list of variable names \"\n                                          \"to exclude from copying the VDC\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {\"numts\", Wasp::CvtToInt, &opt.numts, sizeof(opt.numts)},\n                                        {\"vars\", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)},          {\"xvars\", Wasp::CvtToStrVec, &opt.xvars, sizeof(opt.xvars)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},         {NULL}};\n\n// Return a new vector containing elements of v1 with any elements from\n// v2 removed\n//\nvector<string> remove_vector(vector<string> v1, vector<string> v2)\n{\n    vector<string> newvec;\n    for (auto it = v1.begin(); it != v1.end(); ++it) {\n        if (find(v2.begin(), v2.end(), *it) == v2.end()) { newvec.push_back(*it); }\n    }\n    return (newvec);\n}\n\nstring ProgName;\n\nint main(int argc, char **argv)\n{\n    VAPoR::SetHDF5PluginPath();\n\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { return (1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { return (1); }\n\n    if (argc < 3) {\n        cerr << \"Usage: \" << ProgName << \" wrffiles... master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        return (1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        return (0);\n    }\n\n    argc--;\n    argv++;\n    vector<string> wrffiles;\n    for (int i = 0; i < argc - 1; i++) wrffiles.push_back(argv[i]);\n    string master = argv[argc - 1];\n\n    VDCNetCDF vdc(opt.nthreads);\n\n    size_t         chunksize = 1024 * 1024 * 4;\n    vector<size_t> bs;\n    int            rc = vdc.Initialize(master, vector<string>(), VDC::A, bs, chunksize);\n    if (rc < 0) return (1);\n\n    DCWRF dcwrf;\n    rc = dcwrf.Initialize(wrffiles, vector<string>());\n    if (rc < 0) { return (1); }\n\n    vector<string> varnames = dcwrf.GetCoordVarNames();\n    for (int i = 0; i < varnames.size(); i++) {\n        int nts = dcwrf.GetNumTimeSteps(varnames[i]);\n        nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts;\n        VAssert(nts >= 0);\n\n        cout << \"Copying variable \" << varnames[i] << endl;\n\n        for (int ts = 0; ts < nts; ts++) {\n            cout << \"  Time step \" << ts << endl;\n            int rc = vdc.CopyVar(dcwrf, ts, varnames[i], -1, -1);\n            if (rc < 0) {\n                MyBase::SetErrMsg(\"Failed to copy variable %s\", varnames[i].c_str());\n                return (1);\n            }\n        }\n    }\n\n    if (opt.vars.size()) {\n        varnames = opt.vars;\n    } else {\n        varnames = dcwrf.GetDataVarNames();\n    }\n\n    varnames = remove_vector(varnames, opt.xvars);\n\n    int estatus = 0;\n    for (int i = 0; i < varnames.size(); i++) {\n        int nts = dcwrf.GetNumTimeSteps(varnames[i]);\n        nts = opt.numts != -1 && nts > opt.numts ? opt.numts : nts;\n        VAssert(nts >= 0);\n\n        cout << \"Copying variable \" << varnames[i] << endl;\n\n        for (int ts = 0; ts < nts; ts++) {\n            cout << \"  Time step \" << ts << endl;\n\n            int rc = vdc.CopyVar(dcwrf, ts, varnames[i], -1, -1);\n            if (rc < 0) {\n                MyBase::SetErrMsg(\"Failed to copy variable %s\", varnames[i].c_str());\n                estatus = 1;\n            }\n        }\n    }\n\n    return estatus;\n}\n"
  },
  {
    "path": "apps/wrfvdccreate/CMakeLists.txt",
    "content": "add_executable (wrfvdccreate wrfvdccreate.cpp)\n\ntarget_link_libraries (wrfvdccreate common vdc)\n\nOpenMPInstall (\n\tTARGETS wrfvdccreate\n\tDESTINATION ${INSTALL_BIN_DIR}\n\tCOMPONENT Utilites\n\t)\n"
  },
  {
    "path": "apps/wrfvdccreate/wrfvdccreate.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string.h>\n#include <vector>\n#include <sstream>\n\n#include <vapor/OptionParser.h>\n#include <vapor/CFuncs.h>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/DCWRF.h>\n#include <vapor/FileUtils.h>\n#include <vapor/SetHDF5PluginPath.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct opt_t {\n    std::vector<size_t>     bs;\n    std::vector<size_t>     cratios;\n    string                  wname;\n    int                     nthreads;\n    std::vector<string>     vars;\n    OptionParser::Boolean_T force;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"bs\", 1, \"64:64:64\", \"Internal storage blocking factor expressed in grid points (NX:NY:NZ)\"},\n                                         {\"cratios\", 1, \"1:10:100:500\",\n                                          \"Colon delimited list compression ratios. \"\n                                          \"for 3D variables. The default is 1:10:100:500. The maximum \"\n                                          \"compression ratio is wavelet and block size dependent.\"},\n                                         {\"wname\", 1, \"bior4.4\",\n                                          \"Wavelet family used for compression \"\n                                          \"Valid values are bior1.1, bior1.3, \"\n                                          \"bior1.5, bior2.2, bior2.4 ,bior2.6, bior2.8, bior3.1, bior3.3, \"\n                                          \"bior3.5, bior3.7, bior3.9, bior4.4\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"vars\", 1, \"\",\n                                          \"Colon delimited list of 3D variable names (compressed) \"\n                                          \"to be included in \"\n                                          \"the VDC\"},\n                                         {\"force\", 0, \"\",\n                                          \"Create a new VDC master file even if a VDC data \"\n                                          \"directory already exists. Results may be undefined if settings between \"\n                                          \"the new master file and old data directory do not match.\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"bs\", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)},       {\"cratios\", Wasp::CvtToSize_tVec, &opt.cratios, sizeof(opt.cratios)},\n                                        {\"wname\", Wasp::CvtToCPPStr, &opt.wname, sizeof(opt.wname)}, {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"vars\", Wasp::CvtToStrVec, &opt.vars, sizeof(opt.vars)},    {\"force\", Wasp::CvtToBoolean, &opt.force, sizeof(opt.force)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},   {NULL}};\n\nstring ProgName;\n\nvoid defineMapProjection(const DCWRF &dcwrf, VDCNetCDF &vdc) { vdc.SetMapProjection(dcwrf.GetMapProjection()); }\n\nint main(int argc, char **argv)\n{\n    VAPoR::SetHDF5PluginPath();\n\n    OptionParser op;\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    //\n    // Parse command line arguments\n    //\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) { exit(1); }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) { exit(1); }\n\n    if (argc < 3) {\n        cerr << \"Usage: \" << ProgName << \" wrf_file1 wrf_file2 ... master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \"wrffiles... master.vdc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(0);\n    }\n\n    argc--;\n    argv++;\n    vector<string> wrffiles;\n    for (int i = 0; i < argc - 1; i++) wrffiles.push_back(argv[i]);\n    string master = argv[argc - 1];\n\n    if (FileUtils::Extension(master) != \"vdc\") { fprintf(stderr, \"Warning: VDC files should the extension .vdc\\n\"); }\n\n    VDCNetCDF vdc(opt.nthreads);\n\n    if (vdc.DataDirExists(master) && !opt.force) {\n        MyBase::SetErrMsg(\"Data directory exists and -force option not used. \"\n                          \"Remove directory %s or use -force\",\n                          vdc.GetDataDir(master).c_str());\n        exit(1);\n    }\n    if (FileUtils::Exists(master) && !opt.force) {\n        MyBase::SetErrMsg(\"\\\"%s\\\" already exists and -force option not used.\", master.c_str());\n        exit(1);\n    }\n\n    size_t chunksize = 1024 * 1024 * 4;\n    int    rc = vdc.Initialize(master, vector<string>(), VDC::W, opt.bs, chunksize);\n    if (rc < 0) exit(1);\n\n    DCWRF dcwrf;\n    rc = dcwrf.Initialize(wrffiles, vector<string>());\n    if (rc < 0) { exit(1); }\n\n    vector<string> dimnames = dcwrf.GetDimensionNames();\n    for (int i = 0; i < dimnames.size(); i++) {\n        DC::Dimension dim;\n        dcwrf.GetDimension(dimnames[i], dim, -1);\n        rc = vdc.DefineDimension(dim.GetName(), dim.GetLength());\n        if (rc < 0) { exit(1); }\n    }\n\n    //\n    // Define coordinate variables\n    //\n    vector<string> coordnames = dcwrf.GetCoordVarNames();\n    vector<size_t> cratios(1, 1);\n\n    for (int i = 0; i < coordnames.size(); i++) {\n        DC::CoordVar cvar;\n        dcwrf.GetCoordVarInfo(coordnames[i], cvar);\n\n        vector<string> sdimnames;\n        string         time_dimname;\n        bool           ok = dcwrf.GetVarDimNames(coordnames[i], sdimnames, time_dimname);\n        VAssert(ok);\n\n        rc = vdc.SetCompressionBlock(opt.wname, cratios);\n        if (rc < 0) exit(1);\n\n        if (cvar.GetUniform()) {\n            rc = vdc.DefineCoordVarUniform(cvar.GetName(), sdimnames, time_dimname, cvar.GetUnits(), cvar.GetAxis(), cvar.GetXType(), false);\n        } else {\n            rc = vdc.DefineCoordVar(cvar.GetName(), sdimnames, time_dimname, cvar.GetUnits(), cvar.GetAxis(), cvar.GetXType(), false);\n        }\n\n        if (rc < 0) { exit(1); }\n\n        rc = vdc.CopyAtt(dcwrf, cvar.GetName());\n        if (rc < 0) { return (1); }\n    }\n\n    defineMapProjection(dcwrf, vdc);\n\n    //\n    // Define data variables\n    //\n    for (int d = 0; d < 4; d++) {\n        vector<string> datanames = dcwrf.DC::GetDataVarNames(d);\n\n        //\n        // 1D coordinates are not blocked\n        //\n        string mywname;\n        bool   compress;\n        if (d < 2) {\n            mywname.clear();\n            compress = false;\n        } else {\n            mywname = opt.wname;\n            compress = true;\n        }\n\n        // Try to compute \"reasonable\" 1D & 2D compression ratios from 3D\n        // compression ratios\n        //\n        vector<size_t> cratios = opt.cratios;\n        for (int i = 0; i < cratios.size(); i++) {\n            size_t c = (size_t)pow((double)cratios[i], (double)((float)d / 3.0));\n            cratios[i] = c;\n        }\n\n        rc = vdc.SetCompressionBlock(mywname, cratios);\n        if (rc < 0) exit(1);\n\n        for (int i = 0; i < datanames.size(); i++) {\n            DC::DataVar dvar;\n            dcwrf.GetDataVarInfo(datanames[i], dvar);\n\n            vector<string> dimnames;\n            bool           ok = dcwrf.GetVarDimNames(datanames[i], false, dimnames);\n            VAssert(ok);\n\n            vector<string> coordvars;\n            ok = dcwrf.GetVarCoordVars(datanames[i], false, coordvars);\n            VAssert(ok);\n\n            rc = vdc.DefineDataVar(dvar.GetName(), dimnames, coordvars, dvar.GetUnits(), dvar.GetXType(), compress);\n\n            if (rc < 0) { exit(1); }\n\n            rc = vdc.CopyAtt(dcwrf, dvar.GetName());\n            if (rc < 0) { return (1); }\n        }\n    }\n\n    //\n    // Copy global attributes\n    //\n    {\n        vector<string> attnames = dcwrf.GetAttNames(\"\");\n        for (int j = 0; j < attnames.size(); j++) { vdc.CopyAtt(dcwrf, \"\", attnames[j]); }\n    }\n\n    rc = vdc.EndDefine();\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Failed to write VDC master file : %s\", master.c_str());\n        exit(1);\n    }\n\n    exit(0);\n}\n"
  },
  {
    "path": "buildutils/AppRun",
    "content": "#!/bin/bash\n\nexecutables=(\n    \"wrf2vdc\"\n    \"raw2wasp\"\n    \"wasp2raw\"\n    \"wrfvdccreate\"\n    \"raw2vdc\"\n    \"vdc2raw\"\n    \"cfvdccreate\"\n    \"vapor_check_udunits\"\n    \"vdcdump\"\n    \"ncdf2wasp\"\n    \"tiff2geotiff\"\n    \"wasp2ncdf\"\n    \"vapor\"\n    \"vaporversion\"\n    \"cf2vdc\"\n    \"vdccreate\"\n    \"vaporpychecker\"\n    \"vdccompare\"\n    \"waspcreate\"\n)\n\nbindir=\"$(dirname \"$0\")/bin\"\n\nif [ \"$#\" -eq 0 ]; then\n    # No arguments provided\n    # Launch vapor\n    exec \"$bindir/vapor\" \"$@\"\nelse \n    # Check if AppImage was given a valid executable\n    for exe in ${executables[@]}; do\n        if [ \"$1\" = \"$exe\" ] ; then\n            # An executable was provided\n            # Launch it with given args\n            exec \"$bindir/$1\" \"${@:2}\"\n            exit 0\n        fi  \n    done\n\n    # No executable found\n    echo Invalid argument: $@$'\\n'\n    echo If launching vapor with arguments, the vapor executable must be specified\n    echo IE - ./VAPOR-x86_64.Appimage vapor dataFile1 dataFile2 ...\n    echo IE - ./VAPOR-x86_64.Appimage vapor mySession.vs3$'\\n'\n    echo Usage: $0 [EXECUTABLE] [ARGS]\n    echo Available executables:\n    printf '\\t%s\\n' \"${executables[@]}\"\n    exit 1\nfi\n"
  },
  {
    "path": "buildutils/GetGitRevisionDescription.cmake",
    "content": "# - Returns a version string from Git\n#\n# These functions force a re-configure on each git commit so that you can\n# trust the values of the variables in your build system.\n#\n#  get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])\n#\n# Returns the refspec and sha hash of the current head revision\n#\n#  git_describe(<var> [<additional arguments to git describe> ...])\n#\n# Returns the results of git describe on the source tree, and adjusting\n# the output so that it tests false if an error occurs.\n#\n#  git_get_exact_tag(<var> [<additional arguments to git describe> ...])\n#\n# Returns the results of git describe --exact-match on the source tree,\n# and adjusting the output so that it tests false if there was no exact\n# matching tag.\n#\n#  git_local_changes(<var>)\n#\n# Returns either \"CLEAN\" or \"DIRTY\" with respect to uncommitted changes.\n# Uses the return code of \"git diff-index --quiet HEAD --\".\n# Does not regard untracked files.\n#\n# Requires CMake 2.6 or newer (uses the 'function' command)\n#\n# Original Author:\n# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>\n# http://academic.cleardefinition.com\n# Iowa State University HCI Graduate Program/VRAC\n#\n# Copyright Iowa State University 2009-2010.\n# Distributed under the Boost Software License, Version 1.0.\n# (See accompanying file LICENSE_1_0.txt or copy at\n# http://www.boost.org/LICENSE_1_0.txt)\n\nif(__get_git_revision_description)\n\treturn()\nendif()\nset(__get_git_revision_description YES)\n\n# We must run the following at \"include\" time, not at function call time,\n# to find the path to this module rather than the path to a calling list file\nget_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)\n\nfunction(get_git_head_revision _refspecvar _hashvar)\n\tset(GIT_PARENT_DIR \"${CMAKE_CURRENT_SOURCE_DIR}\")\n\tset(GIT_DIR \"${GIT_PARENT_DIR}/.git\")\n\twhile(NOT EXISTS \"${GIT_DIR}\")\t# .git dir not found, search parent directories\n\t\tset(GIT_PREVIOUS_PARENT \"${GIT_PARENT_DIR}\")\n\t\tget_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)\n\t\tif(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)\n\t\t\t# We have reached the root directory, we are not in git\n\t\t\tset(${_refspecvar} \"GITDIR-NOTFOUND\" PARENT_SCOPE)\n\t\t\tset(${_hashvar} \"GITDIR-NOTFOUND\" PARENT_SCOPE)\n\t\t\treturn()\n\t\tendif()\n\t\tset(GIT_DIR \"${GIT_PARENT_DIR}/.git\")\n\tendwhile()\n\t# check if this is a submodule\n\tif(NOT IS_DIRECTORY ${GIT_DIR})\n\t\tfile(READ ${GIT_DIR} submodule)\n\t\tstring(REGEX REPLACE \"gitdir: (.*)\\n$\" \"\\\\1\" GIT_DIR_RELATIVE ${submodule})\n\t\tget_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)\n\t\tget_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)\n\tendif()\n\tset(GIT_DATA \"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data\")\n\tif(NOT EXISTS \"${GIT_DATA}\")\n\t\tfile(MAKE_DIRECTORY \"${GIT_DATA}\")\n\tendif()\n\n\tif(NOT EXISTS \"${GIT_DIR}/HEAD\")\n\t\treturn()\n\tendif()\n\tset(HEAD_FILE \"${GIT_DATA}/HEAD\")\n\tconfigure_file(\"${GIT_DIR}/HEAD\" \"${HEAD_FILE}\" COPYONLY)\n\n\tconfigure_file(\"${_gitdescmoddir}/GetGitRevisionDescription.cmake.in\"\n\t\t\"${GIT_DATA}/grabRef.cmake\"\n\t\t@ONLY)\n\tinclude(\"${GIT_DATA}/grabRef.cmake\")\n\n\tset(${_refspecvar} \"${HEAD_REF}\" PARENT_SCOPE)\n\tset(${_hashvar} \"${HEAD_HASH}\" PARENT_SCOPE)\nendfunction()\n\nfunction(git_describe _var)\n\tif(NOT GIT_FOUND)\n\t\tfind_package(Git QUIET)\n\tendif()\n\tget_git_head_revision(refspec hash)\n\tif(NOT GIT_FOUND)\n\t\tset(${_var} \"GIT-NOTFOUND\" PARENT_SCOPE)\n\t\treturn()\n\tendif()\n\tif(NOT hash)\n\t\tset(${_var} \"HEAD-HASH-NOTFOUND\" PARENT_SCOPE)\n\t\treturn()\n\tendif()\n\n\t# TODO sanitize\n\t#if((${ARGN}\" MATCHES \"&&\") OR\n\t#\t(ARGN MATCHES \"||\") OR\n\t#\t(ARGN MATCHES \"\\\\;\"))\n\t#\tmessage(\"Please report the following error to the project!\")\n\t#\tmessage(FATAL_ERROR \"Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}\")\n\t#endif()\n\n\t#message(STATUS \"Arguments to execute_process: ${ARGN}\")\n\n\texecute_process(COMMAND\n\t\t\"${GIT_EXECUTABLE}\"\n\t\tdescribe\n\t\t${hash}\n\t\t${ARGN}\n\t\tWORKING_DIRECTORY\n\t\t\"${CMAKE_CURRENT_SOURCE_DIR}\"\n\t\tRESULT_VARIABLE\n\t\tres\n\t\tOUTPUT_VARIABLE\n\t\tout\n\t\tERROR_QUIET\n\t\tOUTPUT_STRIP_TRAILING_WHITESPACE)\n\tif(NOT res EQUAL 0)\n\t\tset(out \"${out}-${res}-NOTFOUND\")\n\tendif()\n\n\tset(${_var} \"${out}\" PARENT_SCOPE)\nendfunction()\n\nfunction(git_get_exact_tag _var)\n\tgit_describe(out --exact-match ${ARGN})\n\tset(${_var} \"${out}\" PARENT_SCOPE)\nendfunction()\n\nfunction(git_local_changes _var)\n\tif(NOT GIT_FOUND)\n\t\tfind_package(Git QUIET)\n\tendif()\n\tget_git_head_revision(refspec hash)\n\tif(NOT GIT_FOUND)\n\t\tset(${_var} \"GIT-NOTFOUND\" PARENT_SCOPE)\n\t\treturn()\n\tendif()\n\tif(NOT hash)\n\t\tset(${_var} \"HEAD-HASH-NOTFOUND\" PARENT_SCOPE)\n\t\treturn()\n\tendif()\n\n\texecute_process(COMMAND\n\t\t\"${GIT_EXECUTABLE}\"\n\t\tdiff-index --quiet HEAD --\n\t\tWORKING_DIRECTORY\n\t\t\"${CMAKE_CURRENT_SOURCE_DIR}\"\n\t\tRESULT_VARIABLE\n\t\tres\n\t\tOUTPUT_VARIABLE\n\t\tout\n\t\tERROR_QUIET\n\t\tOUTPUT_STRIP_TRAILING_WHITESPACE)\n\tif(res EQUAL 0)\n\t\tset(${_var} \"CLEAN\" PARENT_SCOPE)\n\telse()\n\t\tset(${_var} \"DIRTY\" PARENT_SCOPE)\n\tendif()\nendfunction()\n"
  },
  {
    "path": "buildutils/GetGitRevisionDescription.cmake.in",
    "content": "#\n# Internal file for GetGitRevisionDescription.cmake\n#\n# Requires CMake 2.6 or newer (uses the 'function' command)\n#\n# Original Author:\n# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>\n# http://academic.cleardefinition.com\n# Iowa State University HCI Graduate Program/VRAC\n#\n# Copyright Iowa State University 2009-2010.\n# Distributed under the Boost Software License, Version 1.0.\n# (See accompanying file LICENSE_1_0.txt or copy at\n# http://www.boost.org/LICENSE_1_0.txt)\n\nset(HEAD_HASH)\n\nfile(READ \"@HEAD_FILE@\" HEAD_CONTENTS LIMIT 1024)\n\nstring(STRIP \"${HEAD_CONTENTS}\" HEAD_CONTENTS)\nif(HEAD_CONTENTS MATCHES \"ref\")\n\t# named branch\n\tstring(REPLACE \"ref: \" \"\" HEAD_REF \"${HEAD_CONTENTS}\")\n\tif(EXISTS \"@GIT_DIR@/${HEAD_REF}\")\n\t\tconfigure_file(\"@GIT_DIR@/${HEAD_REF}\" \"@GIT_DATA@/head-ref\" COPYONLY)\n\telse()\n\t\tconfigure_file(\"@GIT_DIR@/packed-refs\" \"@GIT_DATA@/packed-refs\" COPYONLY)\n\t\tfile(READ \"@GIT_DATA@/packed-refs\" PACKED_REFS)\n\t\tif(${PACKED_REFS} MATCHES \"([0-9a-z]*) ${HEAD_REF}\")\n\t\t\tset(HEAD_HASH \"${CMAKE_MATCH_1}\")\n\t\tendif()\n\tendif()\nelse()\n\t# detached HEAD\n\tconfigure_file(\"@GIT_DIR@/HEAD\" \"@GIT_DATA@/head-ref\" COPYONLY)\nendif()\n\nif(NOT HEAD_HASH)\n\tfile(READ \"@GIT_DATA@/head-ref\" HEAD_HASH LIMIT 1024)\n\tstring(STRIP \"${HEAD_HASH}\" HEAD_HASH)\nendif()\n"
  },
  {
    "path": "buildutils/NSIS.preInstall.ini.in",
    "content": "; MessageBox MB_OK \"Pre Install Command\"\n\n; include for some of the windows messages defines\n!include \"winmessages.nsh\"\n\n; HKLM (all users) vs HKCU (current user) defines\n!define env_hklm 'HKLM \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\"'\n!define env_hkcu 'HKCU \"Environment\"'\n; set variable for local machine\n;\nWriteRegExpandStr ${env_hklm} \"VAPOR3_HOME\" $INSTDIR\n\n; and current user\n; WriteRegExpandStr ${env_hkcu} \"MYVAR\" \"MYVAL\"\n\n; make sure windows knows about the change\nSendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\n"
  },
  {
    "path": "buildutils/NSIS.preUnInstall.ini.in",
    "content": "; MessageBox MB_OK \"Pre Un Install Command\"\n\n; delete variable\nDeleteRegValue ${env_hklm} \"VAPOR3_HOME\"\n; DeleteRegValue ${env_hkcu} MYVAR\n\n; make sure windows knows about the change\nSendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\n"
  },
  {
    "path": "buildutils/NSIS.template.in",
    "content": "; CPack install script designed for a nmake build\r\n\r\n;--------------------------------\r\n; You must define these values\r\n\r\n  !define VERSION \"@CPACK_PACKAGE_VERSION@\"\r\n  !define PATCH  \"@CPACK_PACKAGE_VERSION_PATCH@\"\r\n  !define INST_DIR \"@CPACK_TEMPORARY_DIRECTORY@\"\r\n\r\n;--------------------------------\r\n;Variables\r\n\r\n  Var MUI_TEMP\r\n  Var STARTMENU_FOLDER\r\n  Var SV_ALLUSERS\r\n  Var START_MENU\r\n  Var DO_NOT_ADD_TO_PATH\r\n  Var ADD_TO_PATH_ALL_USERS\r\n  Var ADD_TO_PATH_CURRENT_USER\r\n  Var INSTALL_DESKTOP\r\n  Var IS_DEFAULT_INSTALLDIR\r\n;--------------------------------\r\n;Include Modern UI\r\n\r\n  !include \"MUI.nsh\"\r\n\r\n  ;Default installation folder\r\n  InstallDir \"@CPACK_NSIS_INSTALL_ROOT@\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\r\n\r\n;--------------------------------\r\n;General\r\n\r\n  ;Name and file\r\n  Name \"@CPACK_NSIS_PACKAGE_NAME@\"\r\n  OutFile \"@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@\"\r\n\r\n  ;Set compression\r\n  ;SetCompress off\r\n  SetCompressor @CPACK_NSIS_COMPRESSOR@\r\n\r\n  ;Require administrator access\r\n  RequestExecutionLevel admin\r\n\r\n@CPACK_NSIS_DEFINES@\r\n\r\n  !include Sections.nsh\r\n\r\n;--- Component support macros: ---\r\n; The code for the add/remove functionality is from:\r\n;   http://nsis.sourceforge.net/Add/Remove_Functionality\r\n; It has been modified slightly and extended to provide\r\n; inter-component dependencies.\r\nVar AR_SecFlags\r\nVar AR_RegFlags\r\n@CPACK_NSIS_SECTION_SELECTED_VARS@\r\n\r\n; Loads the \"selected\" flag for the section named SecName into the\r\n; variable VarName.\r\n!macro LoadSectionSelectedIntoVar SecName VarName\r\n SectionGetFlags ${${SecName}} $${VarName}\r\n IntOp $${VarName} $${VarName} & ${SF_SELECTED}  ;Turn off all other bits\r\n!macroend\r\n\r\n; Loads the value of a variable... can we get around this?\r\n!macro LoadVar VarName\r\n  IntOp $R0 0 + $${VarName}\r\n!macroend\r\n\r\n; Sets the value of a variable\r\n!macro StoreVar VarName IntValue\r\n  IntOp $${VarName} 0 + ${IntValue}\r\n!macroend\r\n\r\n!macro InitSection SecName\r\n  ;  This macro reads component installed flag from the registry and\r\n  ;changes checked state of the section on the components page.\r\n  ;Input: section index constant name specified in Section command.\r\n\r\n  ClearErrors\r\n  ;Reading component status from registry\r\n  ReadRegDWORD $AR_RegFlags HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\\Components\\${SecName}\" \"Installed\"\r\n  IfErrors \"default_${SecName}\"\r\n    ;Status will stay default if registry value not found\r\n    ;(component was never installed)\r\n  IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits\r\n  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading default section flags\r\n  IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE  ;Turn lowest (enabled) bit off\r\n  IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags      ;Change lowest bit\r\n\r\n  ; Note whether this component was installed before\r\n  !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags\r\n  IntOp $R0 $AR_RegFlags & $AR_RegFlags\r\n\r\n  ;Writing modified flags\r\n  SectionSetFlags ${${SecName}} $AR_SecFlags\r\n\r\n \"default_${SecName}:\"\r\n !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected\r\n!macroend\r\n\r\n!macro FinishSection SecName\r\n  ;  This macro reads section flag set by user and removes the section\r\n  ;if it is not selected.\r\n  ;Then it writes component installed flag to registry\r\n  ;Input: section index constant name specified in Section command.\r\n\r\n  SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading section flags\r\n  ;Checking lowest bit:\r\n  IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED}\r\n  IntCmp $AR_SecFlags 1 \"leave_${SecName}\"\r\n    ;Section is not selected:\r\n    ;Calling Section uninstall macro and writing zero installed flag\r\n    !insertmacro \"Remove_${${SecName}}\"\r\n    WriteRegDWORD HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\\Components\\${SecName}\" \\\r\n  \"Installed\" 0\r\n    Goto \"exit_${SecName}\"\r\n\r\n \"leave_${SecName}:\"\r\n    ;Section is selected:\r\n    WriteRegDWORD HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\\Components\\${SecName}\" \\\r\n  \"Installed\" 1\r\n\r\n \"exit_${SecName}:\"\r\n!macroend\r\n\r\n!macro RemoveSection_CPack SecName\r\n  ;  This macro is used to call section's Remove_... macro\r\n  ;from the uninstaller.\r\n  ;Input: section index constant name specified in Section command.\r\n\r\n  !insertmacro \"Remove_${${SecName}}\"\r\n!macroend\r\n\r\n; Determine whether the selection of SecName changed\r\n!macro MaybeSelectionChanged SecName\r\n  !insertmacro LoadVar ${SecName}_selected\r\n  SectionGetFlags ${${SecName}} $R1\r\n  IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits\r\n\r\n  ; See if the status has changed:\r\n  IntCmp $R0 $R1 \"${SecName}_unchanged\"\r\n  !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected\r\n\r\n  IntCmp $R1 ${SF_SELECTED} \"${SecName}_was_selected\"\r\n  !insertmacro \"Deselect_required_by_${SecName}\"\r\n  goto \"${SecName}_unchanged\"\r\n\r\n  \"${SecName}_was_selected:\"\r\n  !insertmacro \"Select_${SecName}_depends\"\r\n\r\n  \"${SecName}_unchanged:\"\r\n!macroend\r\n;--- End of Add/Remove macros ---\r\n\r\n;--------------------------------\r\n;Interface Settings\r\n\r\n  !define MUI_HEADERIMAGE\r\n  !define MUI_ABORTWARNING\r\n\r\n;----------------------------------------\r\n; based upon a script of \"Written by KiCHiK 2003-01-18 05:57:02\"\r\n;----------------------------------------\r\n!verbose 3\r\n!include \"WinMessages.NSH\"\r\n!verbose 4\r\n;====================================================\r\n; get_NT_environment\r\n;     Returns: the selected environment\r\n;     Output : head of the stack\r\n;====================================================\r\n!macro select_NT_profile UN\r\nFunction ${UN}select_NT_profile\r\n   StrCmp $ADD_TO_PATH_ALL_USERS \"1\" 0 environment_single\r\n      DetailPrint \"Selected environment for all users\"\r\n      Push \"all\"\r\n      Return\r\n   environment_single:\r\n      DetailPrint \"Selected environment for current user only.\"\r\n      Push \"current\"\r\n      Return\r\nFunctionEnd\r\n!macroend\r\n!insertmacro select_NT_profile \"\"\r\n!insertmacro select_NT_profile \"un.\"\r\n;----------------------------------------------------\r\n!define NT_current_env 'HKCU \"Environment\"'\r\n!define NT_all_env     'HKLM \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\"'\r\n\r\n!ifndef WriteEnvStr_RegKey\r\n  !ifdef ALL_USERS\r\n    !define WriteEnvStr_RegKey \\\r\n       'HKLM \"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\"'\r\n  !else\r\n    !define WriteEnvStr_RegKey 'HKCU \"Environment\"'\r\n  !endif\r\n!endif\r\n\r\n; AddToPath - Adds the given dir to the search path.\r\n;        Input - head of the stack\r\n;        Note - Win9x systems requires reboot\r\n\r\nFunction AddToPath\r\n  Exch $0\r\n  Push $1\r\n  Push $2\r\n  Push $3\r\n\r\n  # don't add if the path doesn't exist\r\n  IfFileExists \"$0\\*.*\" \"\" AddToPath_done\r\n\r\n  ReadEnvStr $1 PATH\r\n  ; if the path is too long for a NSIS variable NSIS will return a 0\r\n  ; length string.  If we find that, then warn and skip any path\r\n  ; modification as it will trash the existing path.\r\n  StrLen $2 $1\r\n  IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done\r\n    CheckPathLength_ShowPathWarning:\r\n    Messagebox MB_OK|MB_ICONEXCLAMATION \"Warning! PATH too long installer unable to modify PATH!\"\r\n    Goto AddToPath_done\r\n  CheckPathLength_Done:\r\n  Push \"$1;\"\r\n  Push \"$0;\"\r\n  Call StrStr\r\n  Pop $2\r\n  StrCmp $2 \"\" \"\" AddToPath_done\r\n  Push \"$1;\"\r\n  Push \"$0\\;\"\r\n  Call StrStr\r\n  Pop $2\r\n  StrCmp $2 \"\" \"\" AddToPath_done\r\n  GetFullPathName /SHORT $3 $0\r\n  Push \"$1;\"\r\n  Push \"$3;\"\r\n  Call StrStr\r\n  Pop $2\r\n  StrCmp $2 \"\" \"\" AddToPath_done\r\n  Push \"$1;\"\r\n  Push \"$3\\;\"\r\n  Call StrStr\r\n  Pop $2\r\n  StrCmp $2 \"\" \"\" AddToPath_done\r\n\r\n  Call IsNT\r\n  Pop $1\r\n  StrCmp $1 1 AddToPath_NT\r\n    ; Not on NT\r\n    StrCpy $1 $WINDIR 2\r\n    FileOpen $1 \"$1\\autoexec.bat\" a\r\n    FileSeek $1 -1 END\r\n    FileReadByte $1 $2\r\n    IntCmp $2 26 0 +2 +2 # DOS EOF\r\n      FileSeek $1 -1 END # write over EOF\r\n    FileWrite $1 \"$\\r$\\nSET PATH=%PATH%;$3$\\r$\\n\"\r\n    FileClose $1\r\n    SetRebootFlag true\r\n    Goto AddToPath_done\r\n\r\n  AddToPath_NT:\r\n    StrCmp $ADD_TO_PATH_ALL_USERS \"1\" ReadAllKey\r\n      ReadRegStr $1 ${NT_current_env} \"PATH\"\r\n      Goto DoTrim\r\n    ReadAllKey:\r\n      ReadRegStr $1 ${NT_all_env} \"PATH\"\r\n    DoTrim:\r\n    StrCmp $1 \"\" AddToPath_NTdoIt\r\n      Push $1\r\n      Call Trim\r\n      Pop $1\r\n      StrCpy $0 \"$1;$0\"\r\n    AddToPath_NTdoIt:\r\n      StrCmp $ADD_TO_PATH_ALL_USERS \"1\" WriteAllKey\r\n        WriteRegExpandStr ${NT_current_env} \"PATH\" $0\r\n        Goto DoSend\r\n      WriteAllKey:\r\n        WriteRegExpandStr ${NT_all_env} \"PATH\" $0\r\n      DoSend:\r\n      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\r\n\r\n  AddToPath_done:\r\n    Pop $3\r\n    Pop $2\r\n    Pop $1\r\n    Pop $0\r\nFunctionEnd\r\n\r\n\r\n; RemoveFromPath - Remove a given dir from the path\r\n;     Input: head of the stack\r\n\r\nFunction un.RemoveFromPath\r\n  Exch $0\r\n  Push $1\r\n  Push $2\r\n  Push $3\r\n  Push $4\r\n  Push $5\r\n  Push $6\r\n\r\n  IntFmt $6 \"%c\" 26 # DOS EOF\r\n\r\n  Call un.IsNT\r\n  Pop $1\r\n  StrCmp $1 1 unRemoveFromPath_NT\r\n    ; Not on NT\r\n    StrCpy $1 $WINDIR 2\r\n    FileOpen $1 \"$1\\autoexec.bat\" r\r\n    GetTempFileName $4\r\n    FileOpen $2 $4 w\r\n    GetFullPathName /SHORT $0 $0\r\n    StrCpy $0 \"SET PATH=%PATH%;$0\"\r\n    Goto unRemoveFromPath_dosLoop\r\n\r\n    unRemoveFromPath_dosLoop:\r\n      FileRead $1 $3\r\n      StrCpy $5 $3 1 -1 # read last char\r\n      StrCmp $5 $6 0 +2 # if DOS EOF\r\n        StrCpy $3 $3 -1 # remove DOS EOF so we can compare\r\n      StrCmp $3 \"$0$\\r$\\n\" unRemoveFromPath_dosLoopRemoveLine\r\n      StrCmp $3 \"$0$\\n\" unRemoveFromPath_dosLoopRemoveLine\r\n      StrCmp $3 \"$0\" unRemoveFromPath_dosLoopRemoveLine\r\n      StrCmp $3 \"\" unRemoveFromPath_dosLoopEnd\r\n      FileWrite $2 $3\r\n      Goto unRemoveFromPath_dosLoop\r\n      unRemoveFromPath_dosLoopRemoveLine:\r\n        SetRebootFlag true\r\n        Goto unRemoveFromPath_dosLoop\r\n\r\n    unRemoveFromPath_dosLoopEnd:\r\n      FileClose $2\r\n      FileClose $1\r\n      StrCpy $1 $WINDIR 2\r\n      Delete \"$1\\autoexec.bat\"\r\n      CopyFiles /SILENT $4 \"$1\\autoexec.bat\"\r\n      Delete $4\r\n      Goto unRemoveFromPath_done\r\n\r\n  unRemoveFromPath_NT:\r\n    StrCmp $ADD_TO_PATH_ALL_USERS \"1\" unReadAllKey\r\n      ReadRegStr $1 ${NT_current_env} \"PATH\"\r\n      Goto unDoTrim\r\n    unReadAllKey:\r\n      ReadRegStr $1 ${NT_all_env} \"PATH\"\r\n    unDoTrim:\r\n    StrCpy $5 $1 1 -1 # copy last char\r\n    StrCmp $5 \";\" +2 # if last char != ;\r\n      StrCpy $1 \"$1;\" # append ;\r\n    Push $1\r\n    Push \"$0;\"\r\n    Call un.StrStr ; Find `$0;` in $1\r\n    Pop $2 ; pos of our dir\r\n    StrCmp $2 \"\" unRemoveFromPath_done\r\n      ; else, it is in path\r\n      # $0 - path to add\r\n      # $1 - path var\r\n      StrLen $3 \"$0;\"\r\n      StrLen $4 $2\r\n      StrCpy $5 $1 -$4 # $5 is now the part before the path to remove\r\n      StrCpy $6 $2 \"\" $3 # $6 is now the part after the path to remove\r\n      StrCpy $3 $5$6\r\n\r\n      StrCpy $5 $3 1 -1 # copy last char\r\n      StrCmp $5 \";\" 0 +2 # if last char == ;\r\n        StrCpy $3 $3 -1 # remove last char\r\n\r\n      StrCmp $ADD_TO_PATH_ALL_USERS \"1\" unWriteAllKey\r\n        WriteRegExpandStr ${NT_current_env} \"PATH\" $3\r\n        Goto unDoSend\r\n      unWriteAllKey:\r\n        WriteRegExpandStr ${NT_all_env} \"PATH\" $3\r\n      unDoSend:\r\n      SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 \"STR:Environment\" /TIMEOUT=5000\r\n\r\n  unRemoveFromPath_done:\r\n    Pop $6\r\n    Pop $5\r\n    Pop $4\r\n    Pop $3\r\n    Pop $2\r\n    Pop $1\r\n    Pop $0\r\nFunctionEnd\r\n\r\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r\n; Uninstall sutff\r\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r\n\r\n###########################################\r\n#            Utility Functions            #\r\n###########################################\r\n\r\n;====================================================\r\n; IsNT - Returns 1 if the current system is NT, 0\r\n;        otherwise.\r\n;     Output: head of the stack\r\n;====================================================\r\n; IsNT\r\n; no input\r\n; output, top of the stack = 1 if NT or 0 if not\r\n;\r\n; Usage:\r\n;   Call IsNT\r\n;   Pop $R0\r\n;  ($R0 at this point is 1 or 0)\r\n\r\n!macro IsNT un\r\nFunction ${un}IsNT\r\n  Push $0\r\n  ReadRegStr $0 HKLM \"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\" CurrentVersion\r\n  StrCmp $0 \"\" 0 IsNT_yes\r\n  ; we are not NT.\r\n  Pop $0\r\n  Push 0\r\n  Return\r\n\r\n  IsNT_yes:\r\n    ; NT!!!\r\n    Pop $0\r\n    Push 1\r\nFunctionEnd\r\n!macroend\r\n!insertmacro IsNT \"\"\r\n!insertmacro IsNT \"un.\"\r\n\r\n; StrStr\r\n; input, top of stack = string to search for\r\n;        top of stack-1 = string to search in\r\n; output, top of stack (replaces with the portion of the string remaining)\r\n; modifies no other variables.\r\n;\r\n; Usage:\r\n;   Push \"this is a long ass string\"\r\n;   Push \"ass\"\r\n;   Call StrStr\r\n;   Pop $R0\r\n;  ($R0 at this point is \"ass string\")\r\n\r\n!macro StrStr un\r\nFunction ${un}StrStr\r\nExch $R1 ; st=haystack,old$R1, $R1=needle\r\n  Exch    ; st=old$R1,haystack\r\n  Exch $R2 ; st=old$R1,old$R2, $R2=haystack\r\n  Push $R3\r\n  Push $R4\r\n  Push $R5\r\n  StrLen $R3 $R1\r\n  StrCpy $R4 0\r\n  ; $R1=needle\r\n  ; $R2=haystack\r\n  ; $R3=len(needle)\r\n  ; $R4=cnt\r\n  ; $R5=tmp\r\n  loop:\r\n    StrCpy $R5 $R2 $R3 $R4\r\n    StrCmp $R5 $R1 done\r\n    StrCmp $R5 \"\" done\r\n    IntOp $R4 $R4 + 1\r\n    Goto loop\r\ndone:\r\n  StrCpy $R1 $R2 \"\" $R4\r\n  Pop $R5\r\n  Pop $R4\r\n  Pop $R3\r\n  Pop $R2\r\n  Exch $R1\r\nFunctionEnd\r\n!macroend\r\n!insertmacro StrStr \"\"\r\n!insertmacro StrStr \"un.\"\r\n\r\nFunction Trim ; Added by Pelaca\r\n\tExch $R1\r\n\tPush $R2\r\nLoop:\r\n\tStrCpy $R2 \"$R1\" 1 -1\r\n\tStrCmp \"$R2\" \" \" RTrim\r\n\tStrCmp \"$R2\" \"$\\n\" RTrim\r\n\tStrCmp \"$R2\" \"$\\r\" RTrim\r\n\tStrCmp \"$R2\" \";\" RTrim\r\n\tGoTo Done\r\nRTrim:\r\n\tStrCpy $R1 \"$R1\" -1\r\n\tGoto Loop\r\nDone:\r\n\tPop $R2\r\n\tExch $R1\r\nFunctionEnd\r\n\r\nFunction ConditionalAddToRegisty\r\n  Pop $0\r\n  Pop $1\r\n  StrCmp \"$0\" \"\" ConditionalAddToRegisty_EmptyString\r\n    WriteRegStr SHCTX \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \\\r\n    \"$1\" \"$0\"\r\n    ;MessageBox MB_OK \"Set Registry: '$1' to '$0'\"\r\n    DetailPrint \"Set install registry entry: '$1' to '$0'\"\r\n  ConditionalAddToRegisty_EmptyString:\r\nFunctionEnd\r\n\r\n;--------------------------------\r\n\r\n!ifdef CPACK_USES_DOWNLOAD\r\nFunction DownloadFile\r\n    IfFileExists $INSTDIR\\* +2\r\n    CreateDirectory $INSTDIR\r\n    Pop $0\r\n\r\n    ; Skip if already downloaded\r\n    IfFileExists $INSTDIR\\$0 0 +2\r\n    Return\r\n\r\n    StrCpy $1 \"@CPACK_DOWNLOAD_SITE@\"\r\n\r\n  try_again:\r\n    NSISdl::download \"$1/$0\" \"$INSTDIR\\$0\"\r\n\r\n    Pop $1\r\n    StrCmp $1 \"success\" success\r\n    StrCmp $1 \"Cancelled\" cancel\r\n    MessageBox MB_OK \"Download failed: $1\"\r\n  cancel:\r\n    Return\r\n  success:\r\nFunctionEnd\r\n!endif\r\n\r\n;--------------------------------\r\n; Installation types\r\n@CPACK_NSIS_INSTALLATION_TYPES@\r\n\r\n;--------------------------------\r\n; Component sections\r\n@CPACK_NSIS_COMPONENT_SECTIONS@\r\n\r\n;--------------------------------\r\n; Define some macro setting for the gui\r\n@CPACK_NSIS_INSTALLER_MUI_ICON_CODE@\r\n@CPACK_NSIS_INSTALLER_ICON_CODE@\r\n@CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE@\r\n@CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE@\r\n@CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@\r\n@CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@\r\n\r\n;--------------------------------\r\n;Pages\r\n  !insertmacro MUI_PAGE_WELCOME\r\n\r\n  !insertmacro MUI_PAGE_LICENSE \"@CPACK_RESOURCE_FILE_LICENSE@\"\r\n  Page custom InstallOptionsPage\r\n  !insertmacro MUI_PAGE_DIRECTORY\r\n\r\n  ;Start Menu Folder Page Configuration\r\n  !define MUI_STARTMENUPAGE_REGISTRY_ROOT \"SHCTX\"\r\n  !define MUI_STARTMENUPAGE_REGISTRY_KEY \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\"\r\n  !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME \"Start Menu Folder\"\r\n  !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER\r\n\r\n  @CPACK_NSIS_PAGE_COMPONENTS@\r\n\r\n  !insertmacro MUI_PAGE_INSTFILES\r\n  !insertmacro MUI_PAGE_FINISH\r\n\r\n  !insertmacro MUI_UNPAGE_CONFIRM\r\n  !insertmacro MUI_UNPAGE_INSTFILES\r\n\r\n;--------------------------------\r\n;Languages\r\n\r\n  !insertmacro MUI_LANGUAGE \"English\" ;first language is the default language\r\n  !insertmacro MUI_LANGUAGE \"Albanian\"\r\n  !insertmacro MUI_LANGUAGE \"Arabic\"\r\n  !insertmacro MUI_LANGUAGE \"Basque\"\r\n  !insertmacro MUI_LANGUAGE \"Belarusian\"\r\n  !insertmacro MUI_LANGUAGE \"Bosnian\"\r\n  !insertmacro MUI_LANGUAGE \"Breton\"\r\n  !insertmacro MUI_LANGUAGE \"Bulgarian\"\r\n  !insertmacro MUI_LANGUAGE \"Croatian\"\r\n  !insertmacro MUI_LANGUAGE \"Czech\"\r\n  !insertmacro MUI_LANGUAGE \"Danish\"\r\n  !insertmacro MUI_LANGUAGE \"Dutch\"\r\n  !insertmacro MUI_LANGUAGE \"Estonian\"\r\n  !insertmacro MUI_LANGUAGE \"Farsi\"\r\n  !insertmacro MUI_LANGUAGE \"Finnish\"\r\n  !insertmacro MUI_LANGUAGE \"French\"\r\n  !insertmacro MUI_LANGUAGE \"German\"\r\n  !insertmacro MUI_LANGUAGE \"Greek\"\r\n  !insertmacro MUI_LANGUAGE \"Hebrew\"\r\n  !insertmacro MUI_LANGUAGE \"Hungarian\"\r\n  !insertmacro MUI_LANGUAGE \"Icelandic\"\r\n  !insertmacro MUI_LANGUAGE \"Indonesian\"\r\n  !insertmacro MUI_LANGUAGE \"Irish\"\r\n  !insertmacro MUI_LANGUAGE \"Italian\"\r\n  !insertmacro MUI_LANGUAGE \"Japanese\"\r\n  !insertmacro MUI_LANGUAGE \"Korean\"\r\n  !insertmacro MUI_LANGUAGE \"Kurdish\"\r\n  !insertmacro MUI_LANGUAGE \"Latvian\"\r\n  !insertmacro MUI_LANGUAGE \"Lithuanian\"\r\n  !insertmacro MUI_LANGUAGE \"Luxembourgish\"\r\n  !insertmacro MUI_LANGUAGE \"Macedonian\"\r\n  !insertmacro MUI_LANGUAGE \"Malay\"\r\n  !insertmacro MUI_LANGUAGE \"Mongolian\"\r\n  !insertmacro MUI_LANGUAGE \"Norwegian\"\r\n  !insertmacro MUI_LANGUAGE \"Polish\"\r\n  !insertmacro MUI_LANGUAGE \"Portuguese\"\r\n  !insertmacro MUI_LANGUAGE \"PortugueseBR\"\r\n  !insertmacro MUI_LANGUAGE \"Romanian\"\r\n  !insertmacro MUI_LANGUAGE \"Russian\"\r\n  !insertmacro MUI_LANGUAGE \"Serbian\"\r\n  !insertmacro MUI_LANGUAGE \"SerbianLatin\"\r\n  !insertmacro MUI_LANGUAGE \"SimpChinese\"\r\n  !insertmacro MUI_LANGUAGE \"Slovak\"\r\n  !insertmacro MUI_LANGUAGE \"Slovenian\"\r\n  !insertmacro MUI_LANGUAGE \"Spanish\"\r\n  !insertmacro MUI_LANGUAGE \"Swedish\"\r\n  !insertmacro MUI_LANGUAGE \"Thai\"\r\n  !insertmacro MUI_LANGUAGE \"TradChinese\"\r\n  !insertmacro MUI_LANGUAGE \"Turkish\"\r\n  !insertmacro MUI_LANGUAGE \"Ukrainian\"\r\n  !insertmacro MUI_LANGUAGE \"Welsh\"\r\n\r\n\r\n;--------------------------------\r\n;Reserve Files\r\n\r\n  ;These files should be inserted before other files in the data block\r\n  ;Keep these lines before any File command\r\n  ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA)\r\n\r\n  ReserveFile \"NSIS.InstallOptions.ini\"\r\n  !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS\r\n\r\n;--------------------------------\r\n;Installer Sections\r\n\r\nSection \"-Core installation\"\r\n  ;Use the entire tree produced by the INSTALL target.  Keep the\r\n  ;list of directories here in sync with the RMDir commands below.\r\n  SetOutPath \"$INSTDIR\"\r\n  !include \"@CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@\"\r\n  @CPACK_NSIS_FULL_INSTALL@\r\n\r\n  ;Store installation folder\r\n  WriteRegStr SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"\" $INSTDIR\r\n\r\n  ;Create uninstaller\r\n  WriteUninstaller \"$INSTDIR\\Uninstall.exe\"\r\n  Push \"DisplayName\"\r\n  Push \"@CPACK_NSIS_DISPLAY_NAME@\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"DisplayVersion\"\r\n  Push \"@CPACK_PACKAGE_VERSION@\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"Publisher\"\r\n  Push \"@CPACK_PACKAGE_VENDOR@\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"UninstallString\"\r\n  Push \"$INSTDIR\\Uninstall.exe\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"NoRepair\"\r\n  Push \"1\"\r\n  Call ConditionalAddToRegisty\r\n\r\n  !ifdef CPACK_NSIS_ADD_REMOVE\r\n  ;Create add/remove functionality\r\n  Push \"ModifyPath\"\r\n  Push \"$INSTDIR\\AddRemove.exe\"\r\n  Call ConditionalAddToRegisty\r\n  !else\r\n  Push \"NoModify\"\r\n  Push \"1\"\r\n  Call ConditionalAddToRegisty\r\n  !endif\r\n\r\n  ; Optional registration\r\n  Push \"DisplayIcon\"\r\n  Push \"$INSTDIR\\@CPACK_NSIS_INSTALLED_ICON_NAME@\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"HelpLink\"\r\n  Push \"@CPACK_NSIS_HELP_LINK@\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"URLInfoAbout\"\r\n  Push \"@CPACK_NSIS_URL_INFO_ABOUT@\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"Contact\"\r\n  Push \"@CPACK_NSIS_CONTACT@\"\r\n  Call ConditionalAddToRegisty\r\n  !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP \"NSIS.InstallOptions.ini\" \"Field 5\" \"State\"\r\n  !insertmacro MUI_STARTMENU_WRITE_BEGIN Application\r\n\r\n  ;Create shortcuts\r\n  CreateDirectory \"$SMPROGRAMS\\$STARTMENU_FOLDER\"\r\n@CPACK_NSIS_CREATE_ICONS@\r\n@CPACK_NSIS_CREATE_ICONS_EXTRA@\r\n  CreateShortCut \"$SMPROGRAMS\\$STARTMENU_FOLDER\\Uninstall.lnk\" \"$INSTDIR\\Uninstall.exe\"\r\n\r\n  ;Read a value from an InstallOptions INI file\r\n  !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH \"NSIS.InstallOptions.ini\" \"Field 2\" \"State\"\r\n  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS \"NSIS.InstallOptions.ini\" \"Field 3\" \"State\"\r\n  !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER \"NSIS.InstallOptions.ini\" \"Field 4\" \"State\"\r\n\r\n  ; Write special uninstall registry entries\r\n  Push \"StartMenu\"\r\n  Push \"$STARTMENU_FOLDER\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"DoNotAddToPath\"\r\n  Push \"$DO_NOT_ADD_TO_PATH\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"AddToPathAllUsers\"\r\n  Push \"$ADD_TO_PATH_ALL_USERS\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"AddToPathCurrentUser\"\r\n  Push \"$ADD_TO_PATH_CURRENT_USER\"\r\n  Call ConditionalAddToRegisty\r\n  Push \"InstallToDesktop\"\r\n  Push \"$INSTALL_DESKTOP\"\r\n  Call ConditionalAddToRegisty\r\n\r\n  !insertmacro MUI_STARTMENU_WRITE_END\r\n\r\n@CPACK_NSIS_EXTRA_INSTALL_COMMANDS@\r\n\r\nSectionEnd\r\n\r\nSection \"-Add to path\"\r\n  Push $INSTDIR\\bin\r\n  StrCmp \"@CPACK_NSIS_MODIFY_PATH@\" \"ON\" 0 doNotAddToPath\r\n  StrCmp $DO_NOT_ADD_TO_PATH \"1\" doNotAddToPath 0\r\n    Call AddToPath\r\n  doNotAddToPath:\r\nSectionEnd\r\n\r\n;--------------------------------\r\n; Create custom pages\r\nFunction InstallOptionsPage\r\n  !insertmacro MUI_HEADER_TEXT \"Install Options\" \"Choose options for installing @CPACK_NSIS_PACKAGE_NAME@\"\r\n  !insertmacro MUI_INSTALLOPTIONS_DISPLAY \"NSIS.InstallOptions.ini\"\r\n\r\nFunctionEnd\r\n\r\n;--------------------------------\r\n; determine admin versus local install\r\nFunction un.onInit\r\n\r\n  ClearErrors\r\n  UserInfo::GetName\r\n  IfErrors noLM\r\n  Pop $0\r\n  UserInfo::GetAccountType\r\n  Pop $1\r\n  StrCmp $1 \"Admin\" 0 +3\r\n    SetShellVarContext all\r\n    ;MessageBox MB_OK 'User \"$0\" is in the Admin group'\r\n    Goto done\r\n  StrCmp $1 \"Power\" 0 +3\r\n    SetShellVarContext all\r\n    ;MessageBox MB_OK 'User \"$0\" is in the Power Users group'\r\n    Goto done\r\n\r\n  noLM:\r\n    ;Get installation folder from registry if available\r\n\r\n  done:\r\n\r\nFunctionEnd\r\n\r\n;--- Add/Remove callback functions: ---\r\n!macro SectionList MacroName\r\n  ;This macro used to perform operation on multiple sections.\r\n  ;List all of your components in following manner here.\r\n@CPACK_NSIS_COMPONENT_SECTION_LIST@\r\n!macroend\r\n\r\nSection -FinishComponents\r\n  ;Removes unselected components and writes component status to registry\r\n  !insertmacro SectionList \"FinishSection\"\r\n\r\n!ifdef CPACK_NSIS_ADD_REMOVE\r\n  ; Get the name of the installer executable\r\n  System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1'\r\n  StrCpy $R3 $R0\r\n\r\n  ; Strip off the last 13 characters, to see if we have AddRemove.exe\r\n  StrLen $R1 $R0\r\n  IntOp $R1 $R0 - 13\r\n  StrCpy $R2 $R0 13 $R1\r\n  StrCmp $R2 \"AddRemove.exe\" addremove_installed\r\n\r\n  ; We're not running AddRemove.exe, so install it\r\n  CopyFiles $R3 $INSTDIR\\AddRemove.exe\r\n\r\n  addremove_installed:\r\n!endif\r\nSectionEnd\r\n;--- End of Add/Remove callback functions ---\r\n\r\n;--------------------------------\r\n; Component dependencies\r\nFunction .onSelChange\r\n  !insertmacro SectionList MaybeSelectionChanged\r\nFunctionEnd\r\n\r\n;--------------------------------\r\n;Uninstaller Section\r\n\r\nSection \"Uninstall\"\r\n  ReadRegStr $START_MENU SHCTX \\\r\n   \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"StartMenu\"\r\n  ;MessageBox MB_OK \"Start menu is in: $START_MENU\"\r\n  ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \\\r\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"DoNotAddToPath\"\r\n  ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \\\r\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"AddToPathAllUsers\"\r\n  ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \\\r\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"AddToPathCurrentUser\"\r\n  ;MessageBox MB_OK \"Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS\"\r\n  ReadRegStr $INSTALL_DESKTOP SHCTX \\\r\n    \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"InstallToDesktop\"\r\n  ;MessageBox MB_OK \"Install to desktop: $INSTALL_DESKTOP \"\r\n\r\n!include \"@CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@\"\r\n\r\n  ;Remove files we installed.\r\n  ;Keep the list of directories here in sync with the File commands above.\r\n@CPACK_NSIS_DELETE_FILES@\r\n@CPACK_NSIS_DELETE_DIRECTORIES@\r\n\r\n!ifdef CPACK_NSIS_ADD_REMOVE\r\n  ;Remove the add/remove program\r\n  Delete \"$INSTDIR\\AddRemove.exe\"\r\n!endif\r\n\r\n  ;Remove the uninstaller itself.\r\n  Delete \"$INSTDIR\\Uninstall.exe\"\r\n  DeleteRegKey SHCTX \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\"\r\n\r\n  ;Remove the installation directory if it is empty.\r\n  RMDir \"$INSTDIR\"\r\n\r\n  ; Remove the registry entries.\r\n  DeleteRegKey SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\"\r\n\r\n  ; Removes all optional components\r\n  !insertmacro SectionList \"RemoveSection_CPack\"\r\n\r\n  !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP\r\n\r\n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Uninstall.lnk\"\r\n@CPACK_NSIS_DELETE_ICONS@\r\n@CPACK_NSIS_DELETE_ICONS_EXTRA@\r\n\r\n  ;Delete empty start menu parent diretories\r\n  StrCpy $MUI_TEMP \"$SMPROGRAMS\\$MUI_TEMP\"\r\n\r\n  startMenuDeleteLoop:\r\n    ClearErrors\r\n    RMDir $MUI_TEMP\r\n    GetFullPathName $MUI_TEMP \"$MUI_TEMP\\..\"\r\n\r\n    IfErrors startMenuDeleteLoopDone\r\n\r\n    StrCmp \"$MUI_TEMP\" \"$SMPROGRAMS\" startMenuDeleteLoopDone startMenuDeleteLoop\r\n  startMenuDeleteLoopDone:\r\n\r\n  ; If the user changed the shortcut, then untinstall may not work. This should\r\n  ; try to fix it.\r\n  StrCpy $MUI_TEMP \"$START_MENU\"\r\n  Delete \"$SMPROGRAMS\\$MUI_TEMP\\Uninstall.lnk\"\r\n@CPACK_NSIS_DELETE_ICONS_EXTRA@\r\n\r\n  ;Delete empty start menu parent diretories\r\n  StrCpy $MUI_TEMP \"$SMPROGRAMS\\$MUI_TEMP\"\r\n\r\n  secondStartMenuDeleteLoop:\r\n    ClearErrors\r\n    RMDir $MUI_TEMP\r\n    GetFullPathName $MUI_TEMP \"$MUI_TEMP\\..\"\r\n\r\n    IfErrors secondStartMenuDeleteLoopDone\r\n\r\n    StrCmp \"$MUI_TEMP\" \"$SMPROGRAMS\" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop\r\n  secondStartMenuDeleteLoopDone:\r\n\r\n  DeleteRegKey /ifempty SHCTX \"Software\\@CPACK_PACKAGE_VENDOR@\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\"\r\n\r\n  Push $INSTDIR\\bin\r\n  StrCmp $DO_NOT_ADD_TO_PATH_ \"1\" doNotRemoveFromPath 0\r\n    Call un.RemoveFromPath\r\n  doNotRemoveFromPath:\r\nSectionEnd\r\n\r\n;--------------------------------\r\n; determine admin versus local install\r\n; Is install for \"AllUsers\" or \"JustMe\"?\r\n; Default to \"JustMe\" - set to \"AllUsers\" if admin or on Win9x\r\n; This function is used for the very first \"custom page\" of the installer.\r\n; This custom page does not show up visibly, but it executes prior to the\r\n; first visible page and sets up $INSTDIR properly...\r\n; Choose different default installation folder based on SV_ALLUSERS...\r\n; \"Program Files\" for AllUsers, \"My Documents\" for JustMe...\r\n\r\nFunction .onInit\r\n  StrCmp \"@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@\" \"ON\" 0 inst\r\n\r\n  ReadRegStr $0 HKLM \"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\" \"UninstallString\"\r\n  StrCmp $0 \"\" inst\r\n\r\n  MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \\\r\n  \"@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\\n$\\nDo you want to uninstall the old version before installing the new one?\" \\\r\n  /SD IDYES IDYES uninst IDNO inst\r\n  Abort\r\n\r\n;Run the uninstaller\r\nuninst:\r\n  ClearErrors\r\n  StrLen $2 \"\\Uninstall.exe\"\r\n  StrCpy $3 $0 -$2 # remove \"\\Uninstall.exe\" from UninstallString to get path\r\n  ExecWait '\"$0\" /S _?=$3' ;Do not copy the uninstaller to a temp file\r\n\r\n  IfErrors uninst_failed inst\r\nuninst_failed:\r\n  MessageBox MB_OK|MB_ICONSTOP \"Uninstall failed.\"\r\n  Abort\r\n\r\n\r\ninst:\r\n  ; Reads components status for registry\r\n  !insertmacro SectionList \"InitSection\"\r\n\r\n  ; check to see if /D has been used to change\r\n  ; the install directory by comparing it to the\r\n  ; install directory that is expected to be the\r\n  ; default\r\n  StrCpy $IS_DEFAULT_INSTALLDIR 0\r\n  StrCmp \"$INSTDIR\" \"@CPACK_NSIS_INSTALL_ROOT@\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\" 0 +2\r\n    StrCpy $IS_DEFAULT_INSTALLDIR 1\r\n\r\n  StrCpy $SV_ALLUSERS \"JustMe\"\r\n  ; if default install dir then change the default\r\n  ; if it is installed for JustMe\r\n  StrCmp \"$IS_DEFAULT_INSTALLDIR\" \"1\" 0 +2\r\n    StrCpy $INSTDIR \"$DOCUMENTS\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\r\n\r\n  ClearErrors\r\n  UserInfo::GetName\r\n  IfErrors noLM\r\n  Pop $0\r\n  UserInfo::GetAccountType\r\n  Pop $1\r\n  StrCmp $1 \"Admin\" 0 +4\r\n    SetShellVarContext all\r\n    ;MessageBox MB_OK 'User \"$0\" is in the Admin group'\r\n    StrCpy $SV_ALLUSERS \"AllUsers\"\r\n    Goto done\r\n  StrCmp $1 \"Power\" 0 +4\r\n    SetShellVarContext all\r\n    ;MessageBox MB_OK 'User \"$0\" is in the Power Users group'\r\n    StrCpy $SV_ALLUSERS \"AllUsers\"\r\n    Goto done\r\n\r\n  noLM:\r\n    StrCpy $SV_ALLUSERS \"AllUsers\"\r\n    ;Get installation folder from registry if available\r\n\r\n  done:\r\n  StrCmp $SV_ALLUSERS \"AllUsers\" 0 +3\r\n    StrCmp \"$IS_DEFAULT_INSTALLDIR\" \"1\" 0 +2\r\n      StrCpy $INSTDIR \"@CPACK_NSIS_INSTALL_ROOT@\\@CPACK_PACKAGE_INSTALL_DIRECTORY@\"\r\n\r\n  StrCmp \"@CPACK_NSIS_MODIFY_PATH@\" \"ON\" 0 noOptionsPage\r\n    !insertmacro MUI_INSTALLOPTIONS_EXTRACT \"NSIS.InstallOptions.ini\"\r\n\r\n  noOptionsPage:\r\nFunctionEnd\r\n"
  },
  {
    "path": "buildutils/OpenMPInstaller.cmake",
    "content": "function (OpenMPInstall)\n    set(options )\n    set(oneValueArgs TARGETS DESTINATION COMPONENT)\n    set(multiValueArgs )\n    cmake_parse_arguments(VINSTALL \"${options}\" \"${oneValueArgs}\" \"${multiValueArgs}\" ${ARGN})\n\n    if (USE_OMP AND APPLE)\n        get_target_property(target_type ${VINSTALL_TARGETS} TYPE)\n        get_target_property(target_is_bundle ${VINSTALL_TARGETS} MACOSX_BUNDLE)\n        if (target_type STREQUAL \"EXECUTABLE\")\n            set (SRC_FILE ${VINSTALL_TARGETS})\n            set (SRC_DIR  ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})\n        elseif (target_type STREQUAL \"SHARED_LIBRARY\")\n            set (SRC_FILE lib${VINSTALL_TARGETS}.dylib)\n            set (SRC_DIR  ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})\n        else()\n            message(FATAL_ERROR \"Unsupported target type '${target_type}'\")\n        endif()\n\n        if (${target_is_bundle})\n            set (APP_BIN_DIR \"${SRC_FILE}.app/Contents/MacOS\")\n            set (SRC_PATH \"${SRC_DIR}/${APP_BIN_DIR}/${SRC_FILE}\")\n            set (FINAL_DESTINATION \"${VINSTALL_DESTINATION}/${APP_BIN_DIR}\")\n            set (BUNDLE_MSG \"(BUNDLE)\")\n        else()\n            set (SRC_PATH \"${SRC_DIR}/${SRC_FILE}\")\n            set (FINAL_DESTINATION \"${VINSTALL_DESTINATION}\")\n            set (BUNDLE_MSG \"\")\n        endif()\n\n        message(\"Generate OpenMP install script for ${VINSTALL_TARGETS} (${target_type}) ${BUNDLE_MSG}\")\n        # message(\"\\t SRC=\\\"${SRC_PATH}\\\"\")\n\n        set (MOD ${CMAKE_CURRENT_BINARY_DIR}/MOD_FOR_INST_${SRC_FILE})\n\n        install (\n            CODE\n            \"\n            message(\\\"Relinking OpenMP: ${VINSTALL_TARGETS}\\\")\n            configure_file(\\\"${SRC_PATH}\\\" \\\"${MOD}\\\" COPYONLY)\n            execute_process(COMMAND sh \\\"${CMAKE_SOURCE_DIR}/buildutils/renameomp.sh\\\" \\\"${MOD}\\\")\n            \"\n            COMPONENT ${VINSTALL_COMPONENT}\n            )\n\n        if (${target_is_bundle})\n            # This has to be called first to install cf bundle metadata\n            # since the install PROGRAMS just installs the binary, not the app\n            install (\n                TARGETS ${VINSTALL_TARGETS}\n                DESTINATION ${VINSTALL_DESTINATION}\n                COMPONENT ${VINSTALL_COMPONENT}\n                )\n        endif()\n\n        # install (CODE \"message(\\\"install (                           \\\")\")\n        # install (CODE \"message(\\\"    PROGRAMS ${MOD}                 \\\")\")\n        # install (CODE \"message(\\\"    DESTINATION ${FINAL_DESTINATION}\\\")\")\n        # install (CODE \"message(\\\"    COMPONENT ${VINSTALL_COMPONENT} \\\")\")\n        # install (CODE \"message(\\\"    RENAME ${SRC_FILE}              \\\")\")\n        # install (CODE \"message(\\\")                                   \\\")\")\n        install (\n            PROGRAMS ${MOD}\n            DESTINATION ${FINAL_DESTINATION}\n            COMPONENT ${VINSTALL_COMPONENT}\n            RENAME ${SRC_FILE}\n            )\n    else()\n        install (\n            TARGETS ${VINSTALL_TARGETS}\n            DESTINATION ${VINSTALL_DESTINATION}\n            COMPONENT ${VINSTALL_COMPONENT}\n            )\n    endif()\nendfunction()\n"
  },
  {
    "path": "buildutils/UtilityFunctions.cmake",
    "content": "FUNCTION(PREPEND var prefix)\n\tSET(listVar \"\")\n\tFOREACH(f ${ARGN})\n\t\tLIST(APPEND listVar \"${prefix}${f}\")\n\tENDFOREACH(f)\n\tSET(${var} \"${listVar}\" PARENT_SCOPE)\nENDFUNCTION(PREPEND)\n\nFUNCTION(APPEND var postfix)\n\tSET(listVar \"\")\n\tFOREACH(f ${ARGN})\n\t\tLIST(APPEND listVar \"${f}${postfix}\")\n\tENDFOREACH(f)\n\tSET(${var} \"${listVar}\" PARENT_SCOPE)\nENDFUNCTION(APPEND)\n"
  },
  {
    "path": "buildutils/codesignMacOS.sh",
    "content": "set +e\n\ninstallDir=\"/Applications\"\ndmgDir=\"tmp\"\n\nxattr -dr com.apple.quarantine $installDir/vapor.app\n\ndmgName=\"VAPOR3-`$installDir/vapor.app/Contents/MacOS/vaporversion -numeric`-\"\nif [[ `file $installDir/vapor.app/Contents/MacOS/vapor` == *arm64* ]]; then\n    dmgName=\"${dmgName}AppleSilicon.dmg\"\nelse\n    dmgName=\"${dmgName}macOSx86.dmg\"\nfi\n\n#for file in ${installDir}/vapor.app/Contents/Frameworks/*; do\n#    codesign --sign \"Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)\" --force --deep --timestamp --verbose $file\n#done\n\n# Deploy Qt with macdeployqt\n# N.B. Apple's notorization will give an \"bundle format is ambiguous (could be app or framework)\" if Qt's frameworks are missing symlinks\n# So, if copying the third party libraries use 'cp -a /old/libs /new/libs' and not 'cp -r /old/libs /new/libs' (-a and not -r)\n/usr/local/VAPOR-Deps/current/bin/macdeployqt ${installDir}/vapor.app -timestamp -sign-for-notarization=\"Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)\"\n\n# Codesign libraries and frameworks\nfind ${installDir}/vapor.app/Contents/Frameworks -type f -exec file {} + | grep -E 'Mach-O .* shared library' | cut -d: -f1 | while read -r file; do\n    codesign --sign \"Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)\" --timestamp --force --deep --verbose --options runtime \"$file\"\ndone\n\n# Codesign plugins and python\ndirectories=(\n    \"${installDir}/vapor.app/Contents/share/plugins/\"\n    \"${installDir}/vapor.app/Contents/Resources/\"\n    \"${installDir}/vapor.app/Contents/Resources/python/lib/\"\n    \"${installDir}/vapor.app/Contents/Resources/python/lib/python3.9/site-packages/numpy/.dylibs\"\n    \"${installDir}/vapor.app/Contents/Resources/python/lib/python3.9/site-packages/PIL/.dylibs\"\n    \"${installDir}/vapor.app/Contents/Resources/python/lib/python3.9/site-packages/scipy/.dylibs\"\n)\nfor dir in \"${directories[@]}\"; do\n    find \"$dir\" -type f \\( -name \"*.so\" -o -name \"*.dylib\" \\) | while read -r file; do\n        codesign --sign \"Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)\" --timestamp --force --deep --verbose $file\n    done\ndone\n\n# Codesign additional MacOS plugins\ncodesign --sign \"Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)\" --force --deep --verbose ${installDir}/vapor.app/Contents/MacOS/platforms/libqcocoa.dylib\ncodesign --sign \"Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)\" --force --deep --verbose ${installDir}/vapor.app/Contents/MacOS/styles/libqmacstyle.dylib\n\n# Codesign all vapor executables with timestamp and hardended runtime\nfor file in ${installDir}/vapor.app/Contents/MacOS/*; do\n    codesign --sign \"Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)\" --force --deep --timestamp --verbose --options runtime $file\ndone\n\n# Create .dmg that contains symlink to /Applications\nmkdir -p \"${dmgDir}\"\ncp -R \"${installDir}/vapor.app\" \"${dmgDir}\"\nln -s /Applications \"${dmgDir}/Applications\"\nhdiutil create -volname \"vapor\" -srcfolder ${dmgDir} -ov -format UDZO \"${installDir}/${dmgName}\"\nrm -rf \"${dmgDir}\"\n\n# Sign and notarize the .dmg\ncodesign --force --verify --verbose --sign \"Developer ID Application: University Corporation for Atmospheric Research (DQ4ZFL4KLF)\" ${installDir}/${dmgName}\nxcrun -v notarytool submit ${installDir}/${dmgName} --keychain-profile \"VAPOR3\" --wait\n\n# Staple the notarized .dmg\nxcrun stapler staple ${installDir}/${dmgName}\nxcrun stapler validate ${installDir}/${dmgName}\n\n# Fetch the notorization log\n# xcrun notarytool log --keychain-profile \"testApp-password\" <hash>\n"
  },
  {
    "path": "buildutils/copylibdeps.pl",
    "content": "#!/usr/bin/perl\n\nuse English;\nuse POSIX;\nuse Cwd;\nuse Cwd 'abs_path';\nuse File::Basename;\nuse File::Copy;\nuse File::Spec;\n\n$0 =~ s/.*\\///;\n$ProgName = $0;\n$Debug = 0;\n\nsub usage {\n\tmy($msg) = @_;\n\n\tif ($msg) {\n\t\tprintf STDERR \"$ProgName: $msg\\n\";\n\t}\n\n    my($format) = \"\\t%-12.12s  %-12.12s  %s\\n\";\n        \n\n\tprint STDERR \"Usage: $ProgName [options] targetlist... libdir\";\n\tprint STDERR \"\\nWhere \\\"options\\\" are:\\n\\n\";\n\tprintf STDERR $format, \"Option name\", \"Default\", \"Description\";\n\tprintf STDERR $format, \"------ ----\", \"-------\", \"-----------\";\n\tprintf STDERR $format, \"-exclude\", \"expression\", \"Paths to exclude\";\n\tprintf STDERR $format, \"-include\", \"expression\", \"Paths to include (override -exclude)\";\n\tprintf STDERR $format, \"-ldlibpath\", \"expression\", \"library search path\";\n\tprint STDERR \"\\n\";\n\n    \n    exit(1)\n\n\n}\n\n\nsub mysystem {\n\tmy(@cmd) = @_;\n\n\tprint \"cmd=@cmd\\n\";\n\n\tsystem(@cmd);\n\tif ($? != 0) {\n\t\tprint STDERR \"$ProgName: \\\"@cmd\\\" exited with error\\n\";\n\t\texit(1);\n\t}\n}\n\nsub copy_dir{\n\tmy($srcdir, $destdir) = @_;\n\n\tmy($volume, $parentdir, $file) = File::Spec->splitpath($srcdir);\n\n\t$tmpfile =  \"/tmp/$ProgName.$$.tar\";\n\n\t$cwd = getcwd();\n\tchdir $parentdir or die \"$ProgName: Can't cd to $parentdir: $!\\n\";\n\t@cmd = (\"tar\", \"-cf\", $tmpfile, \"$file\");\n\tmysystem(@cmd);\n\n\tchdir $cwd or die \"$ProgName: Can't cd to $cwd: $!\\n\";\n\tchdir $destdir or die \"$ProgName: Can't cd to $destdir: $!\\n\";\n\n\t@cmd = (\"tar\", \"-xf\", $tmpfile);\n\tmysystem(@cmd);\n\n\tchdir $cwd or die \"$ProgName: Can't cd to $cwd: $!\\n\";\n\n\tunlink $tmpfile;\n}\n\n\nsub chaselink {\n    my($path) = @_;\n\n    if (defined($link = readlink($path))) {\n\t\tif (! File::Spec->file_name_is_absolute($link)) {\n\t\t\tmy($name0,$dir0) = fileparse($path);\n\t\t\tmy($name1,$dir1) = fileparse($link);\n\n\t\t\t$link = \"$dir0\" . \"$name1\"; \n\t\t}\n\n        return(chaselink($link));\n    }\n    else {\n        return($path);\n    }   \n}\n\n\t\nsub get_deps {\n\tmy($target) = @_;\n\n\t#\n\t# ldd generates error message on 32bit version of libQtCore \n\t# \"Accessing a corrupted shared library\"\n\t#\n\tif (($Arch eq \"Linux\") && ( ($target =~ /libQtCore/))) {\n\t\tprintf STDERR \"$ProgName: SKIPPING $target\\n\";\n\t\treturn();\n\t}\n\n\tmy(@Deps) = ();\n\tmy($target_is_lib) = 1;\n\tmy(@lddcmd);\n\n\tmy($cmd) = \"/usr/bin/file $target\";\n\t$_ = `$cmd`;\n\tif ($?>>8) {\n\t\tprintf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\t\texit(1);\n\t}\n\tif ($_ =~ \"executable\") {\n\t\t$target_is_lib = 0;\n\t}\n\n\tif ($Arch eq \"Darwin\") {\n\t\t# Mac system\n\t\t@lddcmd = (\"/usr/bin/otool\", \"-L\"); \n\n\t} else {\n\t\t@lddcmd = (\"/usr/bin/ldd\");\n\t}\n\tmy ($cmd) = join(' ', @lddcmd, $target);\n\t$_ = `$cmd`;\n\tif ($?>>8) {\n\t\tprintf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\t\texit(1);\n\t}\n\tmy(@lines) = split /\\n/, $_;\n\n\tif (($Arch eq \"Darwin\") || ($Arch eq \"AIX\")) {\n\t\tshift @lines;\t# discard first line\n\t}\n\n\t# clyne - Fri Feb  5 12:20:50 MST 2016\n\t#\n\t# for .so files the second line is *not* the library name\n\t#\n\n\t#if (($Arch eq \"Darwin\") && $target_is_lib) {\n\t#shift @lines;\t# discard second line - the library name\n\t#}\n\n\n\n\n\t# Get base name of target without any extensions\n\t#\n\tmy ($tfname, $tdirs, $text) = fileparse($target, qr/\\..*/);\n\nLINE:\tforeach $line (@lines) {\n\t\tmy($lib);\n\t\t$line =~ s/^\\s+//;\n\t\tif ($Arch eq \"Darwin\") {\n\t\t\t($lib) = split(/\\s+/, $line);\n\t\t}\n\t\telsif ($Arch eq \"AIX\") {\n\t\t\t($lib) = split(/\\s+/, $line);\n\t\t\t$lib =~ s/\\(.*\\)//;\n\t\t\tnext LINE if ($lib eq \"/unix\");\n\t\t}\n\t\telse {\n\t\t\t($junk1, $junk2, $lib) = split(/\\s+/, $line);\n\t\t}\n\n\t\tnext LINE if (! defined($lib));\n\n\t\tif ($lib =~ \"not found\") {\n\t\t\tprintf STDERR \"$ProgName: Command \\\"$cmd\\\" failed - library $lib not found\\n\";\n\t\t\texit(1);\n\t\t}\n\n\t\tnext LINE if (($Arch eq \"Darwin\") && !( ($lib =~ /dylib/) || $lib =~ /framework/) );\n\t\tnext LINE if (($Arch eq \"Linux\") && !( ($lib =~ /\\.so/)));\n\n\t\t# Handle case where target name appears as its own dependency\n\t\t#\n\t\tmy ($fname, $dirs, $ext) = fileparse($lib, qr/\\..*/);\n\t\tnext LINE if (($Arch eq \"Darwin\") && ($tfname eq $fname));\n\n\t\tmy ($toss) = 0;\n\t\tforeach $exclude (@ExcludePaths) {\n\t\t\tif ($lib =~ m!$exclude!) {\n\t\t\t\t$toss = 1;\n\t\t\t}\n\t\t}\n\t\tif ($toss) {\n\t\t\tforeach $include (@IncludePaths) {\n\t\t\t\tif ($lib =~ m!$include!) {\n\t\t\t\t\t$toss = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (! $toss) {\n\t\t\tpush @Deps, $lib;\n\t\t}\n\t}\n\treturn(@Deps);\n}\n\n@IncludePaths = ();\n@ExcludePaths = ();\nwhile ($ARGV[0] =~ /^-/) {\n    $_ = shift @ARGV;\n\n    if (/^-exclude$/) {\n        defined($_ = shift @ARGV) || die \"Missing argument\";\n\t\tpush(@ExcludePaths, $_);\n    }\n    elsif (/^-arch$/) {\n        defined($Arch = shift @ARGV) || die \"Missing argument\";\n    }\n    elsif (/^-include$/) {\n        defined($_ = shift @ARGV) || die \"Missing argument\";\n\t\tpush(@IncludePaths, $_);\n    }\n    elsif (/^-ldlibpath$/) {\n        defined($_ = shift @ARGV) || die \"Missing argument\";\n\t\t$LD_LIBRARY_PATH = defined($LD_LIBRARY_PATH) ? \"$LD_LIBRARY_PATH:$_\" : $_;\n    }\n    else {\n        usage(\"Invalid option: $_\");\n    }\n}\n\n\nif (! (defined($Libdir = pop @ARGV))) {\n\tusage(\"Wrong # of arguments\");\n}\n$Libdir = abs_path($Libdir);\n\nif (! -d $Libdir) {\n\tprint STDERR \"$ProgName: Library directory $Libdir does not exist\\n\";\n\texit(1);\n}\n\n@Targets = @ARGV;\n\n#\n# Set LD environment variables for ld search path.\n# Needed for the ldd command only (Mac 'otool' ignores these)\n#\n$ENV{\"LD_LIBRARY_PATH\"} = $LD_LIBRARY_PATH;\n$ENV{\"LD_LIBRARYN32_PATH\"} = $LD_LIBRARY_PATH;\n$ENV{\"LD_LIBRARY64_PATH\"} = $LD_LIBRARY_PATH;\n\n#\n# Recursively look for library dependencies\n#\n@cpfiles = ();\nwhile (defined($target = shift(@Targets))) {\n\n\tif ($Debug) {print \"Target = $target\\n\";}\n\n\t@_ = get_deps($target);\n\n\tforeach $dep (@_) {\n\t\tif ($Debug) {print \"Dep = $dep\\n\";}\n\n\t\tif (! -f $dep) {\n\t\t\tprintf STDERR \"$ProgName: Library dependency $dep not found\\n\";\n\t\t\texit(1);\n\t\t}\n\n\t\t$match = 0;\n\t\tforeach $target (@Targets) {\n\t\t\t$match = 1 if ($dep eq $target);\n\t\t}\n\t\tif ($Arch ne \"AIX\") {\n\t\t\tpush @Targets, $dep if (! $match);\n\t\t}\n\n\t\t#\n\t\t# add library dependency to copy list if not already there\n\t\t#\n\t\t$match = 0;\n\t\tforeach $cpfile (@cpfiles) {\n\t\t\t$match = 1 if ($dep eq $cpfile);\n\t\t}\n\t\tpush @cpfiles, $dep if (! $match);\n\t}\n}\n\nforeach $_ (@cpfiles) {\n\t$dirname = abs_path(dirname($_));\n\tif ($dirname ne $Libdir) {\n\n\t\tif (! (($Arch eq \"Darwin\") && $_ =~ /framework/)) {\n\n\t\t\tmy($volume, $dir, $file) = File::Spec->splitpath($_);\n\n\t\t\tmy ($target) = File::Spec->catpath(\"\", $Libdir, $file);\n\n\t\t\tprint \"Copying $_ to $target\\n\";\n\t\t\tcopy($_,$target) || die \"$ProgName: file copy failed - $!\\n\";\n\t\t\tmy(@cmd) = (\"/bin/chmod\", \"+x\", $target);\n\t\t\tmysystem(@cmd);\n\n\t\t\tmy ($baselib) = $target;\n\t\t\tif ($Arch eq \"Darwin\") {\n\t\t\t\tif ($baselib =~ /(\\.[\\d+|.]+dylib)/) {\n\t\t\t\t\t$baselib =~ s/$1/.dylib/;\n\t\t\t\t}\n\t\t\t} \n\t\t\telse {\n\t\t\t\tif ($baselib =~ /(\\.so\\.[\\d+|.]+)/) {\n\t\t\t\t\t$baselib =~ s/$1/.so/;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (($baselib ne $target) && ! -e $baselib) {\n\t\t\t\tmy(@cmd) = (\"/bin/ln\", \"-s\", \"$file\", \"$baselib\");\n\t\t\t\tmysystem(@cmd);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t$dirname = $_;\n\t\t\t$dirname =~ s/(.*framework).*/$1/;\n\t\t\tcopy_dir($dirname, $Libdir);\n\t\t}\n\t}\n}\n\n\n\nexit 0;\n"
  },
  {
    "path": "buildutils/exports.awk",
    "content": "{\n        if ((($2 == \"T\") || ($2 == \"D\") || ($2 == \"B\")) \\\n                && ( substr($1,1,1) != \".\")) {\n            if (substr ($1, 1, 7) != \"__sinit\" &&\n                    substr ($1, 1, 7) != \"__sterm\") {\n                if (substr ($1, 1, 5) == \"__tf1\")\n                    print (substr ($1, 7))\n                else if (substr ($1, 1, 5) == \"__tf9\")\n                    print (substr ($1, 15))\n                else\n                    print $1\n            }\n        }\n    }\n\n"
  },
  {
    "path": "buildutils/fastdep.pl",
    "content": "# Copyright (c) 2001, Stanford University\n# All rights reserved.\n#\n# See the file LICENSE.txt for information on redistributing this software\n\nsub dir {\n\n  my ( $file ) = @_;\n\n  my ( $dir );\n  if ( $file =~ /\\// ) {\n    $file =~ /^(.*)\\/([^\\/])+$/;\n    $dir = $1;\n  } else {\n    $dir = \".\";\n  }\n\n  $dir .= \"/\";\n}\n\nsub includes {\n\n  my ( $file ) = @_;\n\n  return @{$inc{$file}} if ( $inc{$file} );\n\n  my ( @angles, @quotes );\n  return () unless open(SCAN, $file);\n  while (<SCAN>) {\n\n    next unless /^\\s*\\#/;\n    if ( /^\\s*\\#\\s*include\\s*([<\\\"])(.*)[>\\\"]/ ) {\n      if ( $1 eq \"<\" ) {\n\tpush @angles, $2;\n      } else {\n\tpush @quotes, $2;\n      }\n    }\n  }\n\n  close(SCAN);\n\n  my ( $dir ) = dir($file);\n  my ( @files, $f, $name );\n\n  while ( $name = pop @quotes ) {\n    $f = $dir . $name;\n    if ( -f $f ) {\n      push @files, $f;\n    } else {\n      push @angles, $name;\n    }\n  }\n\n  foreach $name ( @angles ) {\n    foreach $dir ( @incpath ) {\n      $f = $dir . $name;\n      if ( -f $f ) {\n\tpush @files, $f;\n\tlast;\n      }\n    }\n  }\n\n  $inc{$file} = \\@files;\n  @files;\n}\n\nsub depends {\n\n  my ( $file ) = @_;\n\n  my ( @files ) = ( @_ );\n  my ( %files );\n  while ( $f = pop @files ) {\n\n    next if exists $files{$f};\n    $files{$f} = 1;\n\n    push @files, includes($f);\n  }\n\n  keys %files;\n}\n\n$obj_prefix = \"\";\n$obj_suffix = ( $^O eq \"MSWin32\" ) ? \".obj\" : \".o\";\n@extra_targets = ();\n\nforeach $arg ( @ARGV ) {\n\n  if ( $arg =~ /^-I(.+)\\/$/ ) {\n    push @incpath, $1;\n  }\n  elsif ( $arg =~ /^-I(.+)$/ ) {\n    push @incpath, $1 . \"/\";\n  }\n  elsif ( $arg =~ /^--obj-prefix=(.*)$/ ) {\n    $obj_prefix = $1;\n  }\n  elsif ( $arg =~ /^--obj-suffix=(.*)$/ ) {\n    $obj_suffix = $1;\n  }\n  elsif ( $arg =~ /^--extra-target=(.*)$/ ) {\n    push @extra_targets, $1;\n  }\n  elsif ( $arg =~ /^-/ ) {\n    # skip it\n  }\n  else {\n    push @files, $arg;\n  }\n}\n\nforeach $file ( @files ) {\n\n  my ( $obj );\n\n  $file =~ /^(.*)\\.\\w+$/;\n  $obj  = $obj_prefix . $1 . $obj_suffix;\n  foreach $t ( @extra_targets ) {\n    $obj .= \" \" . $t;\n  }\n  foreach $file ( depends($file) ) {\n    print \"$obj: $file\\n\";\n  }\n}\n"
  },
  {
    "path": "buildutils/genAppImage.sh",
    "content": "#! /bin/bash\n\n# Exit on error and print commands to stdout\nset -ex\n\nexport VERSION=$1\nVAPOR=\"VAPOR3-$VERSION-Linux\"\nSRC_DIR=$2\n\n####\n# Install vapor into build dir for modification into an AppImage\n####\n\nmkdir -p $VAPOR\nrm -rf $VAPOR/* || true\n./$VAPOR.sh --skip-license --prefix=$VAPOR\n\ncp ${SRC_DIR}/buildutils/AppRun $VAPOR\ncp ${SRC_DIR}/buildutils/vapor.desktop $VAPOR\ncp ${SRC_DIR}/share/images/VAPOR.png $VAPOR\ncp ${SRC_DIR}/share/images/VAPOR.png .\n\n####\n# Produces a self-contained AppDir with Qt\n####\n\nlinuxdeployqt=linuxdeployqt-continuous-x86_64.AppImage\nrm $linuxdeployqt || true\nwget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/$linuxdeployqt\nchmod 755 $linuxdeployqt\n\nexport APPIMAGE_EXTRACT_AND_RUN=1\n\nTHIRD_PARTY_DIR=/usr/local/VAPOR-Deps/current;\\\nQt5_DIR=$THIRD_PARTY_DIR/lib/cmake/Qt5;\\\nLD_LIBRARY_PATH=$THIRD_PARTY_DIR/lib:\\\n/opt/intel/oneapi/mpi/latest/lib:\\\n$THIRD_PARTY_DIR/lib/python3.9/site-packages/Pillow.libs:\\\n$THIRD_PARTY_DIR/lib/python3.9/site-packages/scipy.libs:\\\n$THIRD_PARTY_DIR/lib/python3.9/site-packages/numpy.libs \\\n./$linuxdeployqt \\\n$VAPOR/vapor.desktop \\\n-qmake=$THIRD_PARTY_DIR/bin/qmake \\\n-appimage\n\n####\n# Produces an AppImage from an AppDir\n####\n\nappimagetool=appimagetool-x86_64.AppImage\nrm $appimagetool || true\nwget https://github.com/AppImage/appimagetool/releases/download/continuous/$appimagetool\nchmod 755 $appimagetool\n./$appimagetool $VAPOR\n"
  },
  {
    "path": "buildutils/gen_linux_shared_libs.pl",
    "content": "#!/usr/bin/env perl\n\nuse strict;\nuse warnings;\nuse File::Copy qw(copy);\n\nmy $tmpDir = \"/tmp/vapor_install_libs\";\n\nif (scalar @ARGV < 1) {\n\tprint \"Usage $0 input_bin [extra_lib [...]]\\n\";\n\texit;\n}\n\nif (not -B $ARGV[0]) {\n\tprint STDERR \"Error: File \\\"$ARGV[0]\\\" is not a binary file\\n\";\n\texit 1;\n}\n\nmy @extras;\nfor (my $i = 1; $i < scalar @ARGV; $i++) {\n\tpush @extras, $ARGV[$i];\n}\n\nmy $ldd = `ldd \"$ARGV[0]\"`;\nmy @libs;\n\nforeach (split(/\\n/, $ldd)) {\n\tchomp;\n\tpush @libs, $1 if m/=> (\\/glade\\S+\\.so\\S*)/;\n\tpush @libs, $1 if m/=> (\\/usr\\/local\\/VAPOR-Deps\\S+\\.so\\S*)/;\n\n\tforeach my $e (@extras) {\n\t\tpush @libs, $1 if m/.*$e.*=> (\\/.+.so\\S*)/;\n\t}\n}\n\nmkdir $tmpDir if (not -e $tmpDir);\n\nforeach my $l (@libs) {\n\tmy $real = $l;\n\twhile (-l $real) {\n\t\t$real = readlink $real;\n\t}\n\tif (not $real =~ /^\\//) {\n\t\t$l =~ m/^.*\\//;\n\t\t$real = $&.$real;\n\t}\n\t$l =~ m/[^\\/]+$/;\n\tmy $baseName = $&;\n\tcopy \"$real\", \"$tmpDir/$baseName\";\n    if ($!) {\n        print STDERR \"ERROR Failed to copy '$real' to '$tmpDir/$baseName'\\n\";\n        print STDERR \"ERROR $!\\n\";\n        die(1);\n    }\n\tprint \"$tmpDir/$baseName\\n\";\n}\n\n# use Data::Dumper qw(Dumper);\n# print Dumper \\@libs;\n"
  },
  {
    "path": "buildutils/install-sh",
    "content": "#!/bin/sh\n\n#\n# install - install a program, script, or datafile\n# This comes from X11R5; it is not part of GNU.\n#\n# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $\n#\n# This script is compatible with the BSD install script, but was written\n# from scratch.\n#\n\n\n# set DOITPROG to echo to test this script\n\n# Don't use :- since 4.3BSD and earlier shells don't like it.\ndoit=\"${DOITPROG-}\"\n\n\n# put in absolute paths if you don't have them in your path; or use env. vars.\n\nmvprog=\"${MVPROG-mv}\"\ncpprog=\"${CPPROG-cp}\"\nchmodprog=\"${CHMODPROG-chmod}\"\nchownprog=\"${CHOWNPROG-chown}\"\nchgrpprog=\"${CHGRPPROG-chgrp}\"\nstripprog=\"${STRIPPROG-strip}\"\nrmprog=\"${RMPROG-rm}\"\n\ninstcmd=\"$mvprog\"\nchmodcmd=\"\"\nchowncmd=\"\"\nchgrpcmd=\"\"\nstripcmd=\"\"\nrmcmd=\"$rmprog -f\"\nmvcmd=\"$mvprog\"\nsrc=\"\"\ndst=\"\"\n\nwhile [ x\"$1\" != x ]; do\n    case $1 in\n\t-c) instcmd=\"$cpprog\"\n\t    shift\n\t    continue;;\n\n\t-m) chmodcmd=\"$chmodprog $2\"\n\t    shift\n\t    shift\n\t    continue;;\n\n\t-o) chowncmd=\"$chownprog $2\"\n\t    shift\n\t    shift\n\t    continue;;\n\n\t-g) chgrpcmd=\"$chgrpprog $2\"\n\t    shift\n\t    shift\n\t    continue;;\n\n\t-s) stripcmd=\"$stripprog\"\n\t    shift\n\t    continue;;\n\n\t-S) stripcmd=\"$stripprog $2\"\n\t    shift\n\t    shift\n\t    continue;;\n\n\t*)  if [ x\"$src\" = x ]\n\t    then\n\t\tsrc=$1\n\t    else\n\t\tdst=$1\n\t    fi\n\t    shift\n\t    continue;;\n    esac\ndone\n\nif [ x\"$src\" = x ]\nthen\n\techo \"install:  no input file specified\"\n\texit 1\nfi\n\nif [ x\"$dst\" = x ]\nthen\n\techo \"install:  no destination specified\"\n\texit 1\nfi\n\n\n# If destination is a directory, append the input filename; if your system\n# does not like double slashes in filenames, you may need to add some logic\n\nif [ -d $dst ]\nthen\n\tdst=\"$dst\"/`basename $src`\nfi\n\n# Make a temp file name in the proper directory.\n\ndstdir=`dirname $dst`\ndsttmp=$dstdir/#inst.$$#\n\n# Move or copy the file name to the temp name\n\n$doit $instcmd $src $dsttmp\n\n# and set any options; do chmod last to preserve setuid bits\n\nif [ x\"$chowncmd\" != x ]; then $doit $chowncmd $dsttmp; fi\nif [ x\"$chgrpcmd\" != x ]; then $doit $chgrpcmd $dsttmp; fi\nif [ x\"$stripcmd\" != x ]; then $doit $stripcmd $dsttmp; fi\nif [ x\"$chmodcmd\" != x ]; then $doit $chmodcmd $dsttmp; fi\n\n# Now rename the file to the real destination.\n\n$doit $rmcmd $dst\n$doit $mvcmd $dsttmp $dst\n\n\nexit 0\n"
  },
  {
    "path": "buildutils/install_name.pl",
    "content": "#!/usr/bin/perl\n\nuse English;\nuse POSIX;\nuse Cwd;\nuse File::Basename;\n#use File::Glob;\nuse File::Copy;\nuse File::Spec;\nuse File::Find;\n\n$0 =~ s/.*\\///;\n$ProgName = $0;\n$Debug = 0;\n\nsub usage {\n\tmy($msg) = @_;\n\n\tif ($msg) {\n\t\tprintf STDERR \"$ProgName: $msg\\n\";\n\t}\n\n    my($format) = \"\\t%-12.12s  %-12.12s  %s\\n\";\n        \n\n\tprint STDERR \"Usage: $ProgName [options] targetlist... libdir\";\n\tprint STDERR \"\\nWhere \\\"options\\\" are:\\n\\n\";\n\tprintf STDERR $format, \"Option name\", \"Default\", \"Description\";\n\tprintf STDERR $format, \"------ ----\", \"-------\", \"-----------\";\n\tprintf STDERR $format, \"-exec_path\", \"\", \"Path to executables\";\n\tprintf STDERR $format, \"-ldlibpath\", \"\", \"library search path\";\n\tprint STDERR \"\\n\";\n\n    \n    exit(1)\n\n\n}\n\nsub mysystem {\n\tmy(@cmd) = @_;\n\n\tif ($Debug) {print \"cmd=@cmd\\n\";}\n\n\tsystem(@cmd);\n\tif ($? != 0) {\n\t\tprint STDERR \"$ProgName: \\\"@cmd\\\" exited with error\\n\";\n\t\texit(1);\n\t}\n}\n\nsub get_deps {\n\tmy($target) = @_;\n\n\t#\n\t# ldd generates error message on 32bit version of libQtCore \n\t# \"Accessing a corrupted shared library\"\n\t#\n\tif (($Arch eq \"Linux\") && ( ($target =~ /libQtCore/))) {\n\t\tprintf STDERR \"$ProgName: SKIPPING $target\\n\";\n\t\treturn();\n\t}\n\n\tmy(@Deps) = ();\n\tmy($target_is_lib) = 1;\n\tmy(@lddcmd);\n\n\tmy($cmd) = \"/usr/bin/file $target\";\n\t$_ = `$cmd`;\n\tif ($?>>8) {\n\t\tprintf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\t\texit(1);\n\t}\n\tif ($_ =~ \"executable\") {\n\t\t$target_is_lib = 0;\n\t}\n\n\tif ($Arch eq \"Darwin\") {\n\t\t# Mac system\n\t\t@lddcmd = (\"/usr/bin/otool\", \"-L\"); \n\n\t} else {\n\t\t@lddcmd = (\"/usr/bin/ldd\");\n\t}\n\tmy ($cmd) = join(' ', @lddcmd, $target);\n\t$_ = `$cmd`;\n\tif ($?>>8) {\n\t\tprintf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\t\texit(1);\n\t}\n\tmy(@lines) = split /\\n/, $_;\n\n\tif (($Arch eq \"Darwin\") || ($Arch eq \"AIX\")) {\n\t\tshift @lines;\t# discard first line\n\t}\n\n\t# clyne - Fri Feb  5 12:20:50 MST 2016\n\t#\n\t# for .so files the second line is *not* the library name\n\t#\n\n\t#if (($Arch eq \"Darwin\") && $target_is_lib) {\n\t#shift @lines;\t# discard second line - the library name\n\t#}\n\n\n\n\n\t# Get base name of target without any extensions\n\t#\n\tmy ($tfname, $tdirs, $text) = fileparse($target, qr/\\..*/);\n\nLINE:\tforeach $line (@lines) {\n\t\tmy($lib);\n\t\t$line =~ s/^\\s+//;\n\t\tif ($Arch eq \"Darwin\") {\n\t\t\t($lib) = split(/\\s+/, $line);\n\t\t}\n\t\telsif ($Arch eq \"AIX\") {\n\t\t\t($lib) = split(/\\s+/, $line);\n\t\t\t$lib =~ s/\\(.*\\)//;\n\t\t\tnext LINE if ($lib eq \"/unix\");\n\t\t}\n\t\telse {\n\t\t\t($junk1, $junk2, $lib) = split(/\\s+/, $line);\n\t\t}\n\n\t\tnext LINE if (! defined($lib));\n\n\t\tif ($lib =~ \"not found\") {\n\t\t\tprintf STDERR \"$ProgName: Command \\\"$cmd\\\" failed - library $lib not found\\n\";\n\t\t\texit(1);\n\t\t}\n\n\t\tnext LINE if (($Arch eq \"Darwin\") && !( ($lib =~ /dylib/) || $lib =~ /framework/) );\n\t\tnext LINE if (($Arch eq \"Linux\") && !( ($lib =~ /\\.so/)));\n\n\t\t# Handle case where target name appears as its own dependency\n\t\t#\n\t\tmy ($fname, $dirs, $ext) = fileparse($lib, qr/\\..*/);\n\t\tnext LINE if (($Arch eq \"Darwin\") && ($tfname eq $fname));\n\n\t\tmy ($toss) = 0;\n\t\tforeach $exclude (@ExcludePaths) {\n\t\t\tif ($lib =~ m!$exclude!) {\n\t\t\t\t$toss = 1;\n\t\t\t}\n\t\t}\n\t\tif ($toss) {\n\t\t\tforeach $include (@IncludePaths) {\n\t\t\t\tif ($lib =~ m!$include!) {\n\t\t\t\t\t$toss = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (! $toss) {\n\t\t\tpush @Deps, $lib;\n\t\t}\n\t}\n\treturn(@Deps);\n}\n\nsub want_libraries {\n    if (-f $File::Find::name) {\n\n\t\tmy ($cmd) = \"/usr/bin/file $File::Find::name\";\n\t\t$_ = `$cmd`;\n\t\tif ($?>>8) {\n\t\t\t#printf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\t\t\t#exit(1);\n\t\t\treturn;\n\t\t}\n\t\tif ($_ =~ \"Mach-O\" && $_ =~ \"library\") {\n\t\t\tpush (@WantedFiles, $File::Find::name);\n\t\t}\n    }\n} \n\nsub want_executables {\n    if (-f $File::Find::name) {\n\n\t\t# clyne - Tue Feb  2 20:17:17 MST 2016\n\t\t#\n\t\t# The /usr/bin/file command returns \"Linux/i386 core file\". Sigh.\n\t\t#\n\t\t#my ($cmd) = \"/usr/bin/file $File::Find::name\";\n\t\t#$_ = `$cmd`;\n\t\t#if ($?>>8) {\n\t\t\t#printf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\t\t\t#exit(1);\n\t\t#\treturn;\n\t\t#}\n\t\t#if ($_ =~ \"Mach-O\" && $_ =~ \"executable\") {\n\t\t#\tpush (@WantedFiles, $File::Find::name);\n\t\t#}\n\n\t\tmy ($cmd) = \"/usr/bin/otool -h $File::Find::name\";\n\t\t$_ = `$cmd`;\n\t\tif ($?>>8) {\n\t\t\t#printf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\t\t\t#exit(1);\n\t\t\treturn;\n\t\t}\n\t\tif ($_ =~ \"Mach header\") {\n\t\t\tpush (@WantedFiles, $File::Find::name);\n\t\t}\n    }\n} \n\nsub find_mach_o {\n\tmy($do_lib, @paths) = @_;\n\n\t@WantedFiles = ();\n\n\tif ($do_lib) {\n\t\tfind (\\&want_libraries, @paths);\n\t}\n\telse {\n\t\tfind (\\&want_executables, @paths);\n\t}\n\n\treturn(@WantedFiles);\n}\n\nsub get_relpath_to_libname {\n\tmy($libname, $exec_path, @libs) = @_;\n\n\tforeach $lib (@libs) {\n\t\tmy($vol_new, $dir_new, $file_new) = File::Spec->splitpath($lib);\n\n\t\tif ($libname eq $file_new) {\n\t\t\treturn (File::Spec->abs2rel($lib, $ExecPath));\n\t\t}\n\t}\n\treturn;\n}\n\nsub get_dep_libname {\n\tmy($dep) = @_;\n\n\t#\n\t# remove Mac OS macros\n\t#\n\t$dep =~ s/\\@executable_path//;\n\t$dep =~ s/\\@loader_path//;\n\t$dep =~ s/\\@rpath//;\n\n\tmy($vol, $dir, $libname) = File::Spec->splitpath($dep);\n\n\treturn ($libname);\n}\n\t\t\n\t\t\t\n\t\n\n#\n# Install path is hardwired :-(\n#\n$InstallExecPath = \"/Applications/VAPOR3/VAPOR.app/Contents/MacOS\";\n\n$ExecPath = \"\";\n@IncludePaths = ();\n@ExcludePaths = (\"^/System\", \"^/usr/lib\");\t# exclude everything by default\n@ExecutablePaths = ();\n$Arch = \"Darwin\";\t\t# only works on Mac OS\nwhile ($ARGV[0] =~ /^-/) {\n    $_ = shift @ARGV;\n\n    if (/^-include$/) {\n        defined($_ = shift @ARGV) || die \"Missing argument\";\n\t\tpush(@IncludePaths, $_);\n    }\n    elsif (/^-exec_path$/) {\n        defined($_ = shift @ARGV) || die \"Missing argument\";\n\t\tpush(@ExecutablePaths, $_);\n    }\n    else {\n        usage(\"Invalid option: $_\");\n    }\n}\n\n\nif (! (defined($ExecPath = pop @ARGV))) {\n\tusage(\"Wrong # of arguments\");\n}\n\nif (! -d $ExecPath) {\n\tprint STDERR \"$ProgName: Executable path $ExecPath does not exist\\n\";\n\texit(1);\n}\n\npush(@ExecutablePaths, $ExecPath);\n\n@LibSearchPaths = @ARGV;\n\n@Executables = find_mach_o(0, $ExecPath);\n@Libraries = find_mach_o(1, @LibSearchPaths);\n\npush(@IncludePaths, $ExecPath);\n\nforeach $target (@Executables) {\n\n\tif ($Debug) {print \"Target = $target\\n\";}\n\n\tmy(@Deps) = get_deps($target, @ExecutablePaths);\n\n\tforeach $dep (@Deps) {\n\n\t\tif ($Debug) {print \"dep = $dep\\n\";}\n\n\t\tmy ($libname) = get_dep_libname($dep);\n\t\tif (! defined($libname)) {\n\t\t\tprint STDERR \"$ProgName: Couldn't resolve name for $dep\\n\";\n\t\t\texit(1);\n\t\t}\n\n\t\tmy($rel_path) = get_relpath_to_libname($libname, $ExecPath, @Libraries);\n\t\tif (! defined($rel_path)) {\n\t\t\tprint STDERR \"$ProgName: Dependent library $dep not found\\n\";\n\t\t\tprint STDERR \"Looked for $libname in:\\n\";\n\t\t\tforeach $lib (@Libraries) {\n\t\t\t\tprint STDERR \"\t$lib\\n\";\n\t\t\t}\n\t\t\texit(1);\n\t\t}\n\n\t\t#\n\t\t# Wed May  6 12:18:32 MDT 2015\n\t\t# Hard code name to full application installation path. This makes\n\t\t# it easier for 3rd party applications to link to VAPOR libraries. \n\t\t#\n\t\tmy (@cmd) = (\n\t\t\t\"/usr/bin/install_name_tool\", \"-change\", $dep, \n\t\t\t\"$InstallExecPath/$rel_path\", $target\n\t\t);\n#\t\tmy (@cmd) = (\n#\t\t\t\"/usr/bin/install_name_tool\", \"-change\", $dep, \n#\t\t\t\"\\@executable_path/$rel_path\", $target\n#\t\t);\n\t\tmysystem(@cmd);\n\t}\n}\n\nforeach $target (@Libraries) {\n\n\tif ($Debug) {print \"Target = $target\\n\";}\n\n\tmy($rel_path) = File::Spec->abs2rel($target, $ExecPath);\n\tif (! defined($rel_path)) {\n\t\tprint STDERR \"$ProgName: No path from $target to $ExecPath\\n\";\n\t\texit(1);\n\t}\n\n\t#\n\t# Mon Nov 26 19:31:36 MST 2012 - clyne\n\t# Hard code name to full application installation path. This makes\n\t# it easier for 3rd party applications to link to VAPOR libraries. \n\t#\n\tmy($vol, $dir, $libname) = File::Spec->splitpath($target);\n\tmy (@cmd) = (\n\t\t\"/usr/bin/install_name_tool\", \"-id\", \n\t\t\"$InstallExecPath/$rel_path\", $target\n\t);\n#\tmy (@cmd) = (\n#\t\t\"/usr/bin/install_name_tool\", \"-id\", \n#\t\t\"\\@executable_path/$rel_path\", $target\n#\t);\n\tmysystem(@cmd);\n\n\tmy(@Deps) = get_deps($target, @ExecutablePaths);\n\n\tforeach $dep (@Deps) {\n\n\t\tif ($Debug) {print \"dep = $dep\\n\";}\n\n\t\tmy ($libname) = get_dep_libname($dep);\n\t\tif (! defined($libname)) {\n\t\t\tprint STDERR \"$ProgName: Couldn't resolve name for $dep\\n\";\n\t\t\texit(1);\n\t\t}\n\n\t\tmy($rel_path) = get_relpath_to_libname($libname, $ExecPath, @Libraries);\n\t\tif (! defined($rel_path)) {\n\t\t\tprint STDERR \"$ProgName: Dependent library $dep not found\\n\";\n\t\t\texit(1);\n\t\t}\n\n\t\tmy (@cmd) = (\n\t\t\t\"/usr/bin/install_name_tool\", \"-change\", $dep, \n\t\t\t\"$InstallExecPath/$rel_path\", $target\n\t\t);\n#\t\tmy (@cmd) = (\n#\t\t\t\"/usr/bin/install_name_tool\", \"-change\", $dep, \n#\t\t\t\"\\@executable_path/$rel_path\", $target\n#\t\t);\n\t\tmysystem(@cmd);\n\n\t}\n}\n\n\nexit 0;\n"
  },
  {
    "path": "buildutils/mklinks.pl",
    "content": "#!/usr/bin/perl\n\nuse English;\nuse POSIX;\nuse Cwd;\nuse File::Basename;\n#use File::Glob;\nuse File::Copy;\nuse File::Spec;\n\n$0 =~ s/.*\\///;\n$ProgName = $0;\n\nsub usage {\n\tmy($msg) = @_;\n\n\tif ($msg) {\n\t\tprintf STDERR \"$ProgName: $msg\\n\";\n\t}\n\n\tprintf STDERR \"Usage: %s libname application_path directory\\n\", $ProgName;\n\texit(1);\n}\n\n\nsub chaselink {\n    my($path) = @_;\n\n    if (defined($link = readlink($path))) {\n\t\tif (! File::Spec->file_name_is_absolute($link)) {\n\t\t\tmy($name0,$dir0) = fileparse($path);\n\t\t\tmy($name1,$dir1) = fileparse($link);\n\n\t\t\t$link = \"$dir0\" . \"$name1\"; \n\t\t}\n\n        return(chaselink($link));\n    }\n    else {\n        return($path);\n    }   \n}\n\nif (! (defined($Arch = shift @ARGV))) {\n\tusage(\"Wrong # of arguments\");\n}\nif (! (defined($Libname = shift @ARGV))) {\n\tusage(\"Wrong # of arguments\");\n}\nif (! (defined($Application = shift @ARGV))) {\n\tusage(\"Wrong # of arguments\");\n}\nif (! (defined($TargetDir = shift @ARGV))) {\n\tusage(\"Wrong # of arguments\");\n}\n\nif (defined(shift @ARGV)) {\n\tusage(\"Wrong # of arguments\");\n}\n\nif ($Arch eq \"Darwin\") {\n\t$cmd = \"/usr/bin/otool -L $Application\";\n} else {\n\t$cmd = \"/usr/bin/ldd $Application\";\n}\n\n$_ = `$cmd`;\nif ($?>>8) {\n\tprintf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\texit(1);\n}\n\n@matchs = ();\n@lines = split /\\n/, $_;\nforeach $line (@lines) {\n\tif ($line =~ $Libname) {\n\t\tpush @matchs, $line;\n\t}\n}\n\nif (@matchs < 1) {\n\tprintf STDERR \"$ProgName: WARNING : Library $Libname not found in application $Application\\n\";\n\texit(0);\n} \n\nif (@matchs > 1) {\n\tprintf STDERR \"$ProgName: Multiple instances of library $Libname found in application $Application\\n\";\n\texit(1);\n} \n\n# remove leading white space. Don't know why this is neccessary - split\n# should take care of it.\n#\n$matchs[0] =~ s/^\\s+//;\n\n@_ = split /\\s+/, $matchs[0];\nif ($Arch eq \"Darwin\") {\n\t$path = $_[0];\n}\nelse {\n\t$path = $_[2];\n}\n\n\nmy($name,$dir,$suffix) = fileparse($path);\n\n@libs = glob(\"$dir\" . $Libname . \"*\");\n\n@cpfiles = ();\n\nforeach $lib (@libs) {\n\n\tif (defined(readlink($lib))) {\n\t\t$link = chaselink($lib);\n\n\t\tmy($oldname,$olddir,) = fileparse($link);\n\t\tmy($newname,$newdir) = fileparse($lib);\n\n\t\tif ($oldname ne $newname) {\n\n\t\t\t$newname = \"$TargetDir\" . \"/\" . $newname;\n\n\t\t\tif (! eval { symlink(\"$oldname\",\"$newname\"); 1 }) {\n\t\t\t\tprintf STDERR \"$ProgName: symlink($oldname, $newname) : failed\\n\";\n\t\t\t\texit(1);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tpush @cpfiles, $link \n\t\t}\n\t}\n\telse {\n\t\tpush @cpfiles, $lib \n\t}\n}\n\nforeach $lib (@cpfiles) {\n\tcopy($lib, $TargetDir) or die \"Copy failed: $!\";\n\tmy($name,$dir,) = fileparse($lib);\n\tchmod 0755, $TargetDir . \"/\" . $name;\n}\n\nexit 0;\n"
  },
  {
    "path": "buildutils/patchelf/COPYING",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "buildutils/patchelf/elf.h",
    "content": "/* This file defines standard ELF types, structures, and macros.\n   Copyright (C) 1995-2003,2004,2005,2006,2007,2008\n    Free Software Foundation, Inc.\n   This file is part of the GNU C Library.\n\n   The GNU C Library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Lesser General Public\n   License as published by the Free Software Foundation; either\n   version 2.1 of the License, or (at your option) any later version.\n\n   The GNU C Library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Lesser General Public License for more details.\n\n   You should have received a copy of the GNU Lesser General Public\n   License along with the GNU C Library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA\n   02111-1307 USA.  */\n\n#ifndef _ELF_H\n#define _ELF_H 1\n\n/* Standard ELF types.  */\n\n#include <stdint.h>\n\n/* Type for a 16-bit quantity.  */\ntypedef uint16_t Elf32_Half;\ntypedef uint16_t Elf64_Half;\n\n/* Types for signed and unsigned 32-bit quantities.  */\ntypedef uint32_t Elf32_Word;\ntypedef int32_t  Elf32_Sword;\ntypedef uint32_t Elf64_Word;\ntypedef int32_t  Elf64_Sword;\n\n/* Types for signed and unsigned 64-bit quantities.  */\ntypedef uint64_t Elf32_Xword;\ntypedef int64_t  Elf32_Sxword;\ntypedef uint64_t Elf64_Xword;\ntypedef int64_t  Elf64_Sxword;\n\n/* Type of addresses.  */\ntypedef uint32_t Elf32_Addr;\ntypedef uint64_t Elf64_Addr;\n\n/* Type of file offsets.  */\ntypedef uint32_t Elf32_Off;\ntypedef uint64_t Elf64_Off;\n\n/* Type for section indices, which are 16-bit quantities.  */\ntypedef uint16_t Elf32_Section;\ntypedef uint16_t Elf64_Section;\n\n/* Type for version symbol information.  */\ntypedef Elf32_Half Elf32_Versym;\ntypedef Elf64_Half Elf64_Versym;\n\n/* The ELF file header.  This appears at the start of every ELF file.  */\n\n#define EI_NIDENT (16)\n\ntypedef struct {\n    unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */\n    Elf32_Half    e_type;             /* Object file type */\n    Elf32_Half    e_machine;          /* Architecture */\n    Elf32_Word    e_version;          /* Object file version */\n    Elf32_Addr    e_entry;            /* Entry point virtual address */\n    Elf32_Off     e_phoff;            /* Program header table file offset */\n    Elf32_Off     e_shoff;            /* Section header table file offset */\n    Elf32_Word    e_flags;            /* Processor-specific flags */\n    Elf32_Half    e_ehsize;           /* ELF header size in bytes */\n    Elf32_Half    e_phentsize;        /* Program header table entry size */\n    Elf32_Half    e_phnum;            /* Program header table entry count */\n    Elf32_Half    e_shentsize;        /* Section header table entry size */\n    Elf32_Half    e_shnum;            /* Section header table entry count */\n    Elf32_Half    e_shstrndx;         /* Section header string table index */\n} Elf32_Ehdr;\n\ntypedef struct {\n    unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */\n    Elf64_Half    e_type;             /* Object file type */\n    Elf64_Half    e_machine;          /* Architecture */\n    Elf64_Word    e_version;          /* Object file version */\n    Elf64_Addr    e_entry;            /* Entry point virtual address */\n    Elf64_Off     e_phoff;            /* Program header table file offset */\n    Elf64_Off     e_shoff;            /* Section header table file offset */\n    Elf64_Word    e_flags;            /* Processor-specific flags */\n    Elf64_Half    e_ehsize;           /* ELF header size in bytes */\n    Elf64_Half    e_phentsize;        /* Program header table entry size */\n    Elf64_Half    e_phnum;            /* Program header table entry count */\n    Elf64_Half    e_shentsize;        /* Section header table entry size */\n    Elf64_Half    e_shnum;            /* Section header table entry count */\n    Elf64_Half    e_shstrndx;         /* Section header string table index */\n} Elf64_Ehdr;\n\n/* Fields in the e_ident array.  The EI_* macros are indices into the\n   array.  The macros under each EI_* macro are the values the byte\n   may have.  */\n\n#define EI_MAG0 0    /* File identification byte 0 index */\n#define ELFMAG0 0x7f /* Magic number byte 0 */\n\n#define EI_MAG1 1   /* File identification byte 1 index */\n#define ELFMAG1 'E' /* Magic number byte 1 */\n\n#define EI_MAG2 2   /* File identification byte 2 index */\n#define ELFMAG2 'L' /* Magic number byte 2 */\n\n#define EI_MAG3 3   /* File identification byte 3 index */\n#define ELFMAG3 'F' /* Magic number byte 3 */\n\n/* Conglomeration of the identification bytes, for easy testing as a word.  */\n#define ELFMAG  \"\\177ELF\"\n#define SELFMAG 4\n\n#define EI_CLASS     4 /* File class byte index */\n#define ELFCLASSNONE 0 /* Invalid class */\n#define ELFCLASS32   1 /* 32-bit objects */\n#define ELFCLASS64   2 /* 64-bit objects */\n#define ELFCLASSNUM  3\n\n#define EI_DATA     5 /* Data encoding byte index */\n#define ELFDATANONE 0 /* Invalid data encoding */\n#define ELFDATA2LSB 1 /* 2's complement, little endian */\n#define ELFDATA2MSB 2 /* 2's complement, big endian */\n#define ELFDATANUM  3\n\n#define EI_VERSION 6 /* File version byte index */\n                     /* Value must be EV_CURRENT */\n\n#define EI_OSABI            7   /* OS ABI identification */\n#define ELFOSABI_NONE       0   /* UNIX System V ABI */\n#define ELFOSABI_SYSV       0   /* Alias.  */\n#define ELFOSABI_HPUX       1   /* HP-UX */\n#define ELFOSABI_NETBSD     2   /* NetBSD.  */\n#define ELFOSABI_LINUX      3   /* Linux.  */\n#define ELFOSABI_SOLARIS    6   /* Sun Solaris.  */\n#define ELFOSABI_AIX        7   /* IBM AIX.  */\n#define ELFOSABI_IRIX       8   /* SGI Irix.  */\n#define ELFOSABI_FREEBSD    9   /* FreeBSD.  */\n#define ELFOSABI_TRU64      10  /* Compaq TRU64 UNIX.  */\n#define ELFOSABI_MODESTO    11  /* Novell Modesto.  */\n#define ELFOSABI_OPENBSD    12  /* OpenBSD.  */\n#define ELFOSABI_ARM        97  /* ARM */\n#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */\n\n#define EI_ABIVERSION 8 /* ABI version */\n\n#define EI_PAD 9 /* Byte index of padding bytes */\n\n/* Legal values for e_type (object file type).  */\n\n#define ET_NONE   0      /* No file type */\n#define ET_REL    1      /* Relocatable file */\n#define ET_EXEC   2      /* Executable file */\n#define ET_DYN    3      /* Shared object file */\n#define ET_CORE   4      /* Core file */\n#define ET_NUM    5      /* Number of defined types */\n#define ET_LOOS   0xfe00 /* OS-specific range start */\n#define ET_HIOS   0xfeff /* OS-specific range end */\n#define ET_LOPROC 0xff00 /* Processor-specific range start */\n#define ET_HIPROC 0xffff /* Processor-specific range end */\n\n/* Legal values for e_machine (architecture).  */\n\n#define EM_NONE        0  /* No machine */\n#define EM_M32         1  /* AT&T WE 32100 */\n#define EM_SPARC       2  /* SUN SPARC */\n#define EM_386         3  /* Intel 80386 */\n#define EM_68K         4  /* Motorola m68k family */\n#define EM_88K         5  /* Motorola m88k family */\n#define EM_860         7  /* Intel 80860 */\n#define EM_MIPS        8  /* MIPS R3000 big-endian */\n#define EM_S370        9  /* IBM System/370 */\n#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */\n\n#define EM_PARISC      15 /* HPPA */\n#define EM_VPP500      17 /* Fujitsu VPP500 */\n#define EM_SPARC32PLUS 18 /* Sun's \"v8plus\" */\n#define EM_960         19 /* Intel 80960 */\n#define EM_PPC         20 /* PowerPC */\n#define EM_PPC64       21 /* PowerPC 64-bit */\n#define EM_S390        22 /* IBM S390 */\n\n#define EM_V800       36 /* NEC V800 series */\n#define EM_FR20       37 /* Fujitsu FR20 */\n#define EM_RH32       38 /* TRW RH-32 */\n#define EM_RCE        39 /* Motorola RCE */\n#define EM_ARM        40 /* ARM */\n#define EM_FAKE_ALPHA 41 /* Digital Alpha */\n#define EM_SH         42 /* Hitachi SH */\n#define EM_SPARCV9    43 /* SPARC v9 64-bit */\n#define EM_TRICORE    44 /* Siemens Tricore */\n#define EM_ARC        45 /* Argonaut RISC Core */\n#define EM_H8_300     46 /* Hitachi H8/300 */\n#define EM_H8_300H    47 /* Hitachi H8/300H */\n#define EM_H8S        48 /* Hitachi H8S */\n#define EM_H8_500     49 /* Hitachi H8/500 */\n#define EM_IA_64      50 /* Intel Merced */\n#define EM_MIPS_X     51 /* Stanford MIPS-X */\n#define EM_COLDFIRE   52 /* Motorola Coldfire */\n#define EM_68HC12     53 /* Motorola M68HC12 */\n#define EM_MMA        54 /* Fujitsu MMA Multimedia Accelerator*/\n#define EM_PCP        55 /* Siemens PCP */\n#define EM_NCPU       56 /* Sony nCPU embeeded RISC */\n#define EM_NDR1       57 /* Denso NDR1 microprocessor */\n#define EM_STARCORE   58 /* Motorola Start*Core processor */\n#define EM_ME16       59 /* Toyota ME16 processor */\n#define EM_ST100      60 /* STMicroelectronic ST100 processor */\n#define EM_TINYJ      61 /* Advanced Logic Corp. Tinyj emb.fam*/\n#define EM_X86_64     62 /* AMD x86-64 architecture */\n#define EM_PDSP       63 /* Sony DSP Processor */\n\n#define EM_FX66     66 /* Siemens FX66 microcontroller */\n#define EM_ST9PLUS  67 /* STMicroelectronics ST9+ 8/16 mc */\n#define EM_ST7      68 /* STmicroelectronics ST7 8 bit mc */\n#define EM_68HC16   69 /* Motorola MC68HC16 microcontroller */\n#define EM_68HC11   70 /* Motorola MC68HC11 microcontroller */\n#define EM_68HC08   71 /* Motorola MC68HC08 microcontroller */\n#define EM_68HC05   72 /* Motorola MC68HC05 microcontroller */\n#define EM_SVX      73 /* Silicon Graphics SVx */\n#define EM_ST19     74 /* STMicroelectronics ST19 8 bit mc */\n#define EM_VAX      75 /* Digital VAX */\n#define EM_CRIS     76 /* Axis Communications 32-bit embedded processor */\n#define EM_JAVELIN  77 /* Infineon Technologies 32-bit embedded processor */\n#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */\n#define EM_ZSP      79 /* LSI Logic 16-bit DSP Processor */\n#define EM_MMIX     80 /* Donald Knuth's educational 64-bit processor */\n#define EM_HUANY    81 /* Harvard University machine-independent object files */\n#define EM_PRISM    82 /* SiTera Prism */\n#define EM_AVR      83 /* Atmel AVR 8-bit microcontroller */\n#define EM_FR30     84 /* Fujitsu FR30 */\n#define EM_D10V     85 /* Mitsubishi D10V */\n#define EM_D30V     86 /* Mitsubishi D30V */\n#define EM_V850     87 /* NEC v850 */\n#define EM_M32R     88 /* Mitsubishi M32R */\n#define EM_MN10300  89 /* Matsushita MN10300 */\n#define EM_MN10200  90 /* Matsushita MN10200 */\n#define EM_PJ       91 /* picoJava */\n#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */\n#define EM_ARC_A5   93 /* ARC Cores Tangent-A5 */\n#define EM_XTENSA   94 /* Tensilica Xtensa Architecture */\n#define EM_NUM      95\n\n/* If it is necessary to assign new unofficial EM_* values, please\n   pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the\n   chances of collision with official or non-GNU unofficial values.  */\n\n#define EM_ALPHA 0x9026\n\n/* Legal values for e_version (version).  */\n\n#define EV_NONE    0 /* Invalid ELF version */\n#define EV_CURRENT 1 /* Current version */\n#define EV_NUM     2\n\n/* Section header.  */\n\ntypedef struct {\n    Elf32_Word sh_name;      /* Section name (string tbl index) */\n    Elf32_Word sh_type;      /* Section type */\n    Elf32_Word sh_flags;     /* Section flags */\n    Elf32_Addr sh_addr;      /* Section virtual addr at execution */\n    Elf32_Off  sh_offset;    /* Section file offset */\n    Elf32_Word sh_size;      /* Section size in bytes */\n    Elf32_Word sh_link;      /* Link to another section */\n    Elf32_Word sh_info;      /* Additional section information */\n    Elf32_Word sh_addralign; /* Section alignment */\n    Elf32_Word sh_entsize;   /* Entry size if section holds table */\n} Elf32_Shdr;\n\ntypedef struct {\n    Elf64_Word  sh_name;      /* Section name (string tbl index) */\n    Elf64_Word  sh_type;      /* Section type */\n    Elf64_Xword sh_flags;     /* Section flags */\n    Elf64_Addr  sh_addr;      /* Section virtual addr at execution */\n    Elf64_Off   sh_offset;    /* Section file offset */\n    Elf64_Xword sh_size;      /* Section size in bytes */\n    Elf64_Word  sh_link;      /* Link to another section */\n    Elf64_Word  sh_info;      /* Additional section information */\n    Elf64_Xword sh_addralign; /* Section alignment */\n    Elf64_Xword sh_entsize;   /* Entry size if section holds table */\n} Elf64_Shdr;\n\n/* Special section indices.  */\n\n#define SHN_UNDEF     0      /* Undefined section */\n#define SHN_LORESERVE 0xff00 /* Start of reserved indices */\n#define SHN_LOPROC    0xff00 /* Start of processor-specific */\n#define SHN_BEFORE                            \\\n    0xff00 /* Order section before all others \\\n  (Solaris).  */\n#define SHN_AFTER                                              \\\n    0xff01                   /* Order section after all others \\\n                    (Solaris).  */\n#define SHN_HIPROC    0xff1f /* End of processor-specific */\n#define SHN_LOOS      0xff20 /* Start of OS-specific */\n#define SHN_HIOS      0xff3f /* End of OS-specific */\n#define SHN_ABS       0xfff1 /* Associated symbol is absolute */\n#define SHN_COMMON    0xfff2 /* Associated symbol is common */\n#define SHN_XINDEX    0xffff /* Index is in extra table.  */\n#define SHN_HIRESERVE 0xffff /* End of reserved indices */\n\n/* Legal values for sh_type (section type).  */\n\n#define SHT_NULL           0          /* Section header table entry unused */\n#define SHT_PROGBITS       1          /* Program data */\n#define SHT_SYMTAB         2          /* Symbol table */\n#define SHT_STRTAB         3          /* String table */\n#define SHT_RELA           4          /* Relocation entries with addends */\n#define SHT_HASH           5          /* Symbol hash table */\n#define SHT_DYNAMIC        6          /* Dynamic linking information */\n#define SHT_NOTE           7          /* Notes */\n#define SHT_NOBITS         8          /* Program space with no data (bss) */\n#define SHT_REL            9          /* Relocation entries, no addends */\n#define SHT_SHLIB          10         /* Reserved */\n#define SHT_DYNSYM         11         /* Dynamic linker symbol table */\n#define SHT_INIT_ARRAY     14         /* Array of constructors */\n#define SHT_FINI_ARRAY     15         /* Array of destructors */\n#define SHT_PREINIT_ARRAY  16         /* Array of pre-constructors */\n#define SHT_GROUP          17         /* Section group */\n#define SHT_SYMTAB_SHNDX   18         /* Extended section indeces */\n#define SHT_NUM            19         /* Number of defined types.  */\n#define SHT_LOOS           0x60000000 /* Start OS-specific.  */\n#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes.  */\n#define SHT_GNU_HASH       0x6ffffff6 /* GNU-style hash table.  */\n#define SHT_GNU_LIBLIST    0x6ffffff7 /* Prelink library list */\n#define SHT_CHECKSUM       0x6ffffff8 /* Checksum for DSO content.  */\n#define SHT_LOSUNW         0x6ffffffa /* Sun-specific low bound.  */\n#define SHT_SUNW_move      0x6ffffffa\n#define SHT_SUNW_COMDAT    0x6ffffffb\n#define SHT_SUNW_syminfo   0x6ffffffc\n#define SHT_GNU_verdef     0x6ffffffd /* Version definition section.  */\n#define SHT_GNU_verneed    0x6ffffffe /* Version needs section.  */\n#define SHT_GNU_versym     0x6fffffff /* Version symbol table.  */\n#define SHT_HISUNW         0x6fffffff /* Sun-specific high bound.  */\n#define SHT_HIOS           0x6fffffff /* End OS-specific type */\n#define SHT_LOPROC         0x70000000 /* Start of processor-specific */\n#define SHT_HIPROC         0x7fffffff /* End of processor-specific */\n#define SHT_LOUSER         0x80000000 /* Start of application-specific */\n#define SHT_HIUSER         0x8fffffff /* End of application-specific */\n\n/* Legal values for sh_flags (section flags).  */\n\n#define SHF_WRITE      (1 << 0) /* Writable */\n#define SHF_ALLOC      (1 << 1) /* Occupies memory during execution */\n#define SHF_EXECINSTR  (1 << 2) /* Executable */\n#define SHF_MERGE      (1 << 4) /* Might be merged */\n#define SHF_STRINGS    (1 << 5) /* Contains nul-terminated strings */\n#define SHF_INFO_LINK  (1 << 6) /* `sh_info' contains SHT index */\n#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */\n#define SHF_OS_NONCONFORMING                                         \\\n    (1 << 8)                    /* Non-standard OS specific handling \\\n               required */\n#define SHF_GROUP    (1 << 9)   /* Section is member of a group.  */\n#define SHF_TLS      (1 << 10)  /* Section hold thread-local data.  */\n#define SHF_MASKOS   0x0ff00000 /* OS-specific.  */\n#define SHF_MASKPROC 0xf0000000 /* Processor-specific */\n#define SHF_ORDERED                           \\\n    (1 << 30) /* Special ordering requirement \\\n (Solaris).  */\n#define SHF_EXCLUDE                         \\\n    (1 << 31) /* Section is excluded unless \\\n referenced or allocated (Solaris).*/\n\n/* Section group handling.  */\n#define GRP_COMDAT 0x1 /* Mark group as COMDAT.  */\n\n/* Symbol table entry.  */\n\ntypedef struct {\n    Elf32_Word    st_name;  /* Symbol name (string tbl index) */\n    Elf32_Addr    st_value; /* Symbol value */\n    Elf32_Word    st_size;  /* Symbol size */\n    unsigned char st_info;  /* Symbol type and binding */\n    unsigned char st_other; /* Symbol visibility */\n    Elf32_Section st_shndx; /* Section index */\n} Elf32_Sym;\n\ntypedef struct {\n    Elf64_Word    st_name;  /* Symbol name (string tbl index) */\n    unsigned char st_info;  /* Symbol type and binding */\n    unsigned char st_other; /* Symbol visibility */\n    Elf64_Section st_shndx; /* Section index */\n    Elf64_Addr    st_value; /* Symbol value */\n    Elf64_Xword   st_size;  /* Symbol size */\n} Elf64_Sym;\n\n/* The syminfo section if available contains additional information about\n   every dynamic symbol.  */\n\ntypedef struct {\n    Elf32_Half si_boundto; /* Direct bindings, symbol bound to */\n    Elf32_Half si_flags;   /* Per symbol flags */\n} Elf32_Syminfo;\n\ntypedef struct {\n    Elf64_Half si_boundto; /* Direct bindings, symbol bound to */\n    Elf64_Half si_flags;   /* Per symbol flags */\n} Elf64_Syminfo;\n\n/* Possible values for si_boundto.  */\n#define SYMINFO_BT_SELF       0xffff /* Symbol bound to self */\n#define SYMINFO_BT_PARENT     0xfffe /* Symbol bound to parent */\n#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */\n\n/* Possible bitmasks for si_flags.  */\n#define SYMINFO_FLG_DIRECT   0x0001 /* Direct bound symbol */\n#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */\n#define SYMINFO_FLG_COPY     0x0004 /* Symbol is a copy-reloc */\n#define SYMINFO_FLG_LAZYLOAD                    \\\n    0x0008 /* Symbol bound to object to be lazy \\\nloaded */\n/* Syminfo version values.  */\n#define SYMINFO_NONE    0\n#define SYMINFO_CURRENT 1\n#define SYMINFO_NUM     2\n\n/* How to extract and insert information held in the st_info field.  */\n\n#define ELF32_ST_BIND(val)        (((unsigned char)(val)) >> 4)\n#define ELF32_ST_TYPE(val)        ((val)&0xf)\n#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf))\n\n/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.  */\n#define ELF64_ST_BIND(val)        ELF32_ST_BIND(val)\n#define ELF64_ST_TYPE(val)        ELF32_ST_TYPE(val)\n#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO((bind), (type))\n\n/* Legal values for ST_BIND subfield of st_info (symbol binding).  */\n\n#define STB_LOCAL  0  /* Local symbol */\n#define STB_GLOBAL 1  /* Global symbol */\n#define STB_WEAK   2  /* Weak symbol */\n#define STB_NUM    3  /* Number of defined types.  */\n#define STB_LOOS   10 /* Start of OS-specific */\n#define STB_HIOS   12 /* End of OS-specific */\n#define STB_LOPROC 13 /* Start of processor-specific */\n#define STB_HIPROC 15 /* End of processor-specific */\n\n/* Legal values for ST_TYPE subfield of st_info (symbol type).  */\n\n#define STT_NOTYPE  0  /* Symbol type is unspecified */\n#define STT_OBJECT  1  /* Symbol is a data object */\n#define STT_FUNC    2  /* Symbol is a code object */\n#define STT_SECTION 3  /* Symbol associated with a section */\n#define STT_FILE    4  /* Symbol's name is file name */\n#define STT_COMMON  5  /* Symbol is a common data object */\n#define STT_TLS     6  /* Symbol is thread-local data object*/\n#define STT_NUM     7  /* Number of defined types.  */\n#define STT_LOOS    10 /* Start of OS-specific */\n#define STT_HIOS    12 /* End of OS-specific */\n#define STT_LOPROC  13 /* Start of processor-specific */\n#define STT_HIPROC  15 /* End of processor-specific */\n\n/* Symbol table indices are found in the hash buckets and chain table\n   of a symbol hash table section.  This special index value indicates\n   the end of a chain, meaning no further symbols are found in that bucket.  */\n\n#define STN_UNDEF 0 /* End of a chain.  */\n\n/* How to extract and insert information held in the st_other field.  */\n\n#define ELF32_ST_VISIBILITY(o) ((o)&0x03)\n\n/* For ELF64 the definitions are the same.  */\n#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o)\n\n/* Symbol visibility specification encoded in the st_other field.  */\n#define STV_DEFAULT   0 /* Default symbol visibility rules */\n#define STV_INTERNAL  1 /* Processor specific hidden class */\n#define STV_HIDDEN    2 /* Sym unavailable in other modules */\n#define STV_PROTECTED 3 /* Not preemptible, not exported */\n\n/* Relocation table entry without addend (in section of type SHT_REL).  */\n\ntypedef struct {\n    Elf32_Addr r_offset; /* Address */\n    Elf32_Word r_info;   /* Relocation type and symbol index */\n} Elf32_Rel;\n\n/* I have seen two different definitions of the Elf64_Rel and\n   Elf64_Rela structures, so we'll leave them out until Novell (or\n   whoever) gets their act together.  */\n/* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */\n\ntypedef struct {\n    Elf64_Addr  r_offset; /* Address */\n    Elf64_Xword r_info;   /* Relocation type and symbol index */\n} Elf64_Rel;\n\n/* Relocation table entry with addend (in section of type SHT_RELA).  */\n\ntypedef struct {\n    Elf32_Addr  r_offset; /* Address */\n    Elf32_Word  r_info;   /* Relocation type and symbol index */\n    Elf32_Sword r_addend; /* Addend */\n} Elf32_Rela;\n\ntypedef struct {\n    Elf64_Addr   r_offset; /* Address */\n    Elf64_Xword  r_info;   /* Relocation type and symbol index */\n    Elf64_Sxword r_addend; /* Addend */\n} Elf64_Rela;\n\n/* How to extract and insert information held in the r_info field.  */\n\n#define ELF32_R_SYM(val)        ((val) >> 8)\n#define ELF32_R_TYPE(val)       ((val)&0xff)\n#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type)&0xff))\n\n#define ELF64_R_SYM(i)          ((i) >> 32)\n#define ELF64_R_TYPE(i)         ((i)&0xffffffff)\n#define ELF64_R_INFO(sym, type) ((((Elf64_Xword)(sym)) << 32) + (type))\n\n/* Program segment header.  */\n\ntypedef struct {\n    Elf32_Word p_type;   /* Segment type */\n    Elf32_Off  p_offset; /* Segment file offset */\n    Elf32_Addr p_vaddr;  /* Segment virtual address */\n    Elf32_Addr p_paddr;  /* Segment physical address */\n    Elf32_Word p_filesz; /* Segment size in file */\n    Elf32_Word p_memsz;  /* Segment size in memory */\n    Elf32_Word p_flags;  /* Segment flags */\n    Elf32_Word p_align;  /* Segment alignment */\n} Elf32_Phdr;\n\ntypedef struct {\n    Elf64_Word  p_type;   /* Segment type */\n    Elf64_Word  p_flags;  /* Segment flags */\n    Elf64_Off   p_offset; /* Segment file offset */\n    Elf64_Addr  p_vaddr;  /* Segment virtual address */\n    Elf64_Addr  p_paddr;  /* Segment physical address */\n    Elf64_Xword p_filesz; /* Segment size in file */\n    Elf64_Xword p_memsz;  /* Segment size in memory */\n    Elf64_Xword p_align;  /* Segment alignment */\n} Elf64_Phdr;\n\n/* Legal values for p_type (segment type).  */\n\n#define PT_NULL         0          /* Program header table entry unused */\n#define PT_LOAD         1          /* Loadable program segment */\n#define PT_DYNAMIC      2          /* Dynamic linking information */\n#define PT_INTERP       3          /* Program interpreter */\n#define PT_NOTE         4          /* Auxiliary information */\n#define PT_SHLIB        5          /* Reserved */\n#define PT_PHDR         6          /* Entry for header table itself */\n#define PT_TLS          7          /* Thread-local storage segment */\n#define PT_NUM          8          /* Number of defined types */\n#define PT_LOOS         0x60000000 /* Start of OS-specific */\n#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */\n#define PT_GNU_STACK    0x6474e551 /* Indicates stack executability */\n#define PT_GNU_RELRO    0x6474e552 /* Read-only after relocation */\n#define PT_LOSUNW       0x6ffffffa\n#define PT_SUNWBSS      0x6ffffffa /* Sun Specific segment */\n#define PT_SUNWSTACK    0x6ffffffb /* Stack segment */\n#define PT_HISUNW       0x6fffffff\n#define PT_HIOS         0x6fffffff /* End of OS-specific */\n#define PT_LOPROC       0x70000000 /* Start of processor-specific */\n#define PT_HIPROC       0x7fffffff /* End of processor-specific */\n\n/* Legal values for p_flags (segment flags).  */\n\n#define PF_X        (1 << 0)   /* Segment is executable */\n#define PF_W        (1 << 1)   /* Segment is writable */\n#define PF_R        (1 << 2)   /* Segment is readable */\n#define PF_MASKOS   0x0ff00000 /* OS-specific */\n#define PF_MASKPROC 0xf0000000 /* Processor-specific */\n\n/* Legal values for note segment descriptor types for core files. */\n\n#define NT_PRSTATUS   1          /* Contains copy of prstatus struct */\n#define NT_FPREGSET   2          /* Contains copy of fpregset struct */\n#define NT_PRPSINFO   3          /* Contains copy of prpsinfo struct */\n#define NT_PRXREG     4          /* Contains copy of prxregset struct */\n#define NT_TASKSTRUCT 4          /* Contains copy of task structure */\n#define NT_PLATFORM   5          /* String from sysinfo(SI_PLATFORM) */\n#define NT_AUXV       6          /* Contains copy of auxv array */\n#define NT_GWINDOWS   7          /* Contains copy of gwindows struct */\n#define NT_ASRS       8          /* Contains copy of asrset struct */\n#define NT_PSTATUS    10         /* Contains copy of pstatus struct */\n#define NT_PSINFO     13         /* Contains copy of psinfo struct */\n#define NT_PRCRED     14         /* Contains copy of prcred struct */\n#define NT_UTSNAME    15         /* Contains copy of utsname struct */\n#define NT_LWPSTATUS  16         /* Contains copy of lwpstatus struct */\n#define NT_LWPSINFO   17         /* Contains copy of lwpinfo struct */\n#define NT_PRFPXREG   20         /* Contains copy of fprxregset struct */\n#define NT_PRXFPREG   0x46e62b7f /* Contains copy of user_fxsr_struct */\n#define NT_PPC_VMX    0x100      /* PowerPC Altivec/VMX registers */\n#define NT_PPC_SPE    0x101      /* PowerPC SPE/EVR registers */\n#define NT_386_TLS    0x200      /* i386 TLS slots (struct user_desc) */\n\n/* Legal values for the note segment descriptor types for object files.  */\n\n#define NT_VERSION 1 /* Contains a version string.  */\n\n/* Dynamic section entry.  */\n\ntypedef struct {\n    Elf32_Sword d_tag; /* Dynamic entry type */\n    union {\n        Elf32_Word d_val; /* Integer value */\n        Elf32_Addr d_ptr; /* Address value */\n    } d_un;\n} Elf32_Dyn;\n\ntypedef struct {\n    Elf64_Sxword d_tag; /* Dynamic entry type */\n    union {\n        Elf64_Xword d_val; /* Integer value */\n        Elf64_Addr  d_ptr; /* Address value */\n    } d_un;\n} Elf64_Dyn;\n\n/* Legal values for d_tag (dynamic entry type).  */\n\n#define DT_NULL            0           /* Marks end of dynamic section */\n#define DT_NEEDED          1           /* Name of needed library */\n#define DT_PLTRELSZ        2           /* Size in bytes of PLT relocs */\n#define DT_PLTGOT          3           /* Processor defined value */\n#define DT_HASH            4           /* Address of symbol hash table */\n#define DT_STRTAB          5           /* Address of string table */\n#define DT_SYMTAB          6           /* Address of symbol table */\n#define DT_RELA            7           /* Address of Rela relocs */\n#define DT_RELASZ          8           /* Total size of Rela relocs */\n#define DT_RELAENT         9           /* Size of one Rela reloc */\n#define DT_STRSZ           10          /* Size of string table */\n#define DT_SYMENT          11          /* Size of one symbol table entry */\n#define DT_INIT            12          /* Address of init function */\n#define DT_FINI            13          /* Address of termination function */\n#define DT_SONAME          14          /* Name of shared object */\n#define DT_RPATH           15          /* Library search path (deprecated) */\n#define DT_SYMBOLIC        16          /* Start symbol search here */\n#define DT_REL             17          /* Address of Rel relocs */\n#define DT_RELSZ           18          /* Total size of Rel relocs */\n#define DT_RELENT          19          /* Size of one Rel reloc */\n#define DT_PLTREL          20          /* Type of reloc in PLT */\n#define DT_DEBUG           21          /* For debugging; unspecified */\n#define DT_TEXTREL         22          /* Reloc might modify .text */\n#define DT_JMPREL          23          /* Address of PLT relocs */\n#define DT_BIND_NOW        24          /* Process relocations of object */\n#define DT_INIT_ARRAY      25          /* Array with addresses of init fct */\n#define DT_FINI_ARRAY      26          /* Array with addresses of fini fct */\n#define DT_INIT_ARRAYSZ    27          /* Size in bytes of DT_INIT_ARRAY */\n#define DT_FINI_ARRAYSZ    28          /* Size in bytes of DT_FINI_ARRAY */\n#define DT_RUNPATH         29          /* Library search path */\n#define DT_FLAGS           30          /* Flags for the object being loaded */\n#define DT_ENCODING        32          /* Start of encoded range */\n#define DT_PREINIT_ARRAY   32          /* Array with addresses of preinit fct*/\n#define DT_PREINIT_ARRAYSZ 33          /* size in bytes of DT_PREINIT_ARRAY */\n#define DT_NUM             34          /* Number used */\n#define DT_LOOS            0x6000000d  /* Start of OS-specific */\n#define DT_HIOS            0x6ffff000  /* End of OS-specific */\n#define DT_LOPROC          0x70000000  /* Start of processor-specific */\n#define DT_HIPROC          0x7fffffff  /* End of processor-specific */\n#define DT_PROCNUM         DT_MIPS_NUM /* Most used by any processor */\n\n/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the\n   Dyn.d_un.d_val field of the Elf*_Dyn structure.  This follows Sun's\n   approach.  */\n#define DT_VALRNGLO       0x6ffffd00\n#define DT_GNU_PRELINKED  0x6ffffdf5 /* Prelinking timestamp */\n#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */\n#define DT_GNU_LIBLISTSZ  0x6ffffdf7 /* Size of library list */\n#define DT_CHECKSUM       0x6ffffdf8\n#define DT_PLTPADSZ       0x6ffffdf9\n#define DT_MOVEENT        0x6ffffdfa\n#define DT_MOVESZ         0x6ffffdfb\n#define DT_FEATURE_1      0x6ffffdfc /* Feature selection (DTF_*).  */\n#define DT_POSFLAG_1                                                      \\\n    0x6ffffdfd                       /* Flags for DT_* entries, effecting \\\n                        the following DT_* entry.  */\n#define DT_SYMINSZ        0x6ffffdfe /* Size of syminfo table (in bytes) */\n#define DT_SYMINENT       0x6ffffdff /* Entry size of syminfo */\n#define DT_VALRNGHI       0x6ffffdff\n#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */\n#define DT_VALNUM         12\n\n/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the\n   Dyn.d_un.d_ptr field of the Elf*_Dyn structure.\n\n   If any adjustment is made to the ELF object after it has been\n   built these entries will need to be adjusted.  */\n#define DT_ADDRRNGLO       0x6ffffe00\n#define DT_GNU_HASH        0x6ffffef5 /* GNU-style hash table.  */\n#define DT_TLSDESC_PLT     0x6ffffef6\n#define DT_TLSDESC_GOT     0x6ffffef7\n#define DT_GNU_CONFLICT    0x6ffffef8 /* Start of conflict section */\n#define DT_GNU_LIBLIST     0x6ffffef9 /* Library list */\n#define DT_CONFIG          0x6ffffefa /* Configuration information.  */\n#define DT_DEPAUDIT        0x6ffffefb /* Dependency auditing.  */\n#define DT_AUDIT           0x6ffffefc /* Object auditing.  */\n#define DT_PLTPAD          0x6ffffefd /* PLT padding.  */\n#define DT_MOVETAB         0x6ffffefe /* Move table.  */\n#define DT_SYMINFO         0x6ffffeff /* Syminfo table.  */\n#define DT_ADDRRNGHI       0x6ffffeff\n#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */\n#define DT_ADDRNUM         11\n\n/* The versioning entry types.  The next are defined as part of the\n   GNU extension.  */\n#define DT_VERSYM 0x6ffffff0\n\n#define DT_RELACOUNT 0x6ffffff9\n#define DT_RELCOUNT  0x6ffffffa\n\n/* These were chosen by Sun.  */\n#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below.  */\n#define DT_VERDEF                                                \\\n    0x6ffffffc                  /* Address of version definition \\\n                       table */\n#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */\n#define DT_VERNEED                                                                    \\\n    0x6ffffffe                                        /* Address of table with needed \\\n                                             versions */\n#define DT_VERNEEDNUM         0x6fffffff              /* Number of needed versions */\n#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */\n#define DT_VERSIONTAGNUM      16\n\n/* Sun added these machine-independent extensions in the \"processor-specific\"\n   range.  Be compatible.  */\n#define DT_AUXILIARY        0x7ffffffd /* Shared object to load before self */\n#define DT_FILTER           0x7fffffff /* Shared object to get values from */\n#define DT_EXTRATAGIDX(tag) ((Elf32_Word) - ((Elf32_Sword)(tag) << 1 >> 1) - 1)\n#define DT_EXTRANUM         3\n\n/* Values of `d_un.d_val' in the DT_FLAGS entry.  */\n#define DF_ORIGIN     0x00000001 /* Object may use DF_ORIGIN */\n#define DF_SYMBOLIC   0x00000002 /* Symbol resolutions starts here */\n#define DF_TEXTREL    0x00000004 /* Object contains text relocations */\n#define DF_BIND_NOW   0x00000008 /* No lazy binding for this object */\n#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */\n\n/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1\n   entry in the dynamic section.  */\n#define DF_1_NOW        0x00000001 /* Set RTLD_NOW for this object.  */\n#define DF_1_GLOBAL     0x00000002 /* Set RTLD_GLOBAL for this object.  */\n#define DF_1_GROUP      0x00000004 /* Set RTLD_GROUP for this object.  */\n#define DF_1_NODELETE   0x00000008 /* Set RTLD_NODELETE for this object.*/\n#define DF_1_LOADFLTR   0x00000010 /* Trigger filtee loading at runtime.*/\n#define DF_1_INITFIRST  0x00000020 /* Set RTLD_INITFIRST for this object*/\n#define DF_1_NOOPEN     0x00000040 /* Set RTLD_NOOPEN for this object.  */\n#define DF_1_ORIGIN     0x00000080 /* $ORIGIN must be handled.  */\n#define DF_1_DIRECT     0x00000100 /* Direct binding enabled.  */\n#define DF_1_TRANS      0x00000200\n#define DF_1_INTERPOSE  0x00000400 /* Object is used to interpose.  */\n#define DF_1_NODEFLIB   0x00000800 /* Ignore default lib search path.  */\n#define DF_1_NODUMP     0x00001000 /* Object can't be dldump'ed.  */\n#define DF_1_CONFALT    0x00002000 /* Configuration alternative created.*/\n#define DF_1_ENDFILTEE  0x00004000 /* Filtee terminates filters search. */\n#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */\n#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time.  */\n\n/* Flags for the feature selection in DT_FEATURE_1.  */\n#define DTF_1_PARINIT 0x00000001\n#define DTF_1_CONFEXP 0x00000002\n\n/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry.  */\n#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object.  */\n#define DF_P1_GROUPPERM                            \\\n    0x00000002 /* Symbols from next object are not \\\n  generally available.  */\n\n/* Version definition sections.  */\n\ntypedef struct {\n    Elf32_Half vd_version; /* Version revision */\n    Elf32_Half vd_flags;   /* Version information */\n    Elf32_Half vd_ndx;     /* Version Index */\n    Elf32_Half vd_cnt;     /* Number of associated aux entries */\n    Elf32_Word vd_hash;    /* Version name hash value */\n    Elf32_Word vd_aux;     /* Offset in bytes to verdaux array */\n    Elf32_Word vd_next;    /* Offset in bytes to next verdef\n                       entry */\n} Elf32_Verdef;\n\ntypedef struct {\n    Elf64_Half vd_version; /* Version revision */\n    Elf64_Half vd_flags;   /* Version information */\n    Elf64_Half vd_ndx;     /* Version Index */\n    Elf64_Half vd_cnt;     /* Number of associated aux entries */\n    Elf64_Word vd_hash;    /* Version name hash value */\n    Elf64_Word vd_aux;     /* Offset in bytes to verdaux array */\n    Elf64_Word vd_next;    /* Offset in bytes to next verdef\n                       entry */\n} Elf64_Verdef;\n\n/* Legal values for vd_version (version revision).  */\n#define VER_DEF_NONE    0 /* No version */\n#define VER_DEF_CURRENT 1 /* Current version */\n#define VER_DEF_NUM     2 /* Given version number */\n\n/* Legal values for vd_flags (version information flags).  */\n#define VER_FLG_BASE 0x1 /* Version definition of file itself */\n#define VER_FLG_WEAK 0x2 /* Weak version identifier */\n\n/* Versym symbol index values.  */\n#define VER_NDX_LOCAL     0      /* Symbol is local.  */\n#define VER_NDX_GLOBAL    1      /* Symbol is global.  */\n#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries.  */\n#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated.  */\n\n/* Auxialiary version information.  */\n\ntypedef struct {\n    Elf32_Word vda_name; /* Version or dependency names */\n    Elf32_Word vda_next; /* Offset in bytes to next verdaux\n                       entry */\n} Elf32_Verdaux;\n\ntypedef struct {\n    Elf64_Word vda_name; /* Version or dependency names */\n    Elf64_Word vda_next; /* Offset in bytes to next verdaux\n                       entry */\n} Elf64_Verdaux;\n\n/* Version dependency section.  */\n\ntypedef struct {\n    Elf32_Half vn_version; /* Version of structure */\n    Elf32_Half vn_cnt;     /* Number of associated aux entries */\n    Elf32_Word vn_file;    /* Offset of filename for this\n                       dependency */\n    Elf32_Word vn_aux;     /* Offset in bytes to vernaux array */\n    Elf32_Word vn_next;    /* Offset in bytes to next verneed\n                       entry */\n} Elf32_Verneed;\n\ntypedef struct {\n    Elf64_Half vn_version; /* Version of structure */\n    Elf64_Half vn_cnt;     /* Number of associated aux entries */\n    Elf64_Word vn_file;    /* Offset of filename for this\n                       dependency */\n    Elf64_Word vn_aux;     /* Offset in bytes to vernaux array */\n    Elf64_Word vn_next;    /* Offset in bytes to next verneed\n                       entry */\n} Elf64_Verneed;\n\n/* Legal values for vn_version (version revision).  */\n#define VER_NEED_NONE    0 /* No version */\n#define VER_NEED_CURRENT 1 /* Current version */\n#define VER_NEED_NUM     2 /* Given version number */\n\n/* Auxiliary needed version information.  */\n\ntypedef struct {\n    Elf32_Word vna_hash;  /* Hash value of dependency name */\n    Elf32_Half vna_flags; /* Dependency specific information */\n    Elf32_Half vna_other; /* Unused */\n    Elf32_Word vna_name;  /* Dependency name string offset */\n    Elf32_Word vna_next;  /* Offset in bytes to next vernaux\n                       entry */\n} Elf32_Vernaux;\n\ntypedef struct {\n    Elf64_Word vna_hash;  /* Hash value of dependency name */\n    Elf64_Half vna_flags; /* Dependency specific information */\n    Elf64_Half vna_other; /* Unused */\n    Elf64_Word vna_name;  /* Dependency name string offset */\n    Elf64_Word vna_next;  /* Offset in bytes to next vernaux\n                       entry */\n} Elf64_Vernaux;\n\n/* Legal values for vna_flags.  */\n#define VER_FLG_WEAK 0x2 /* Weak version identifier */\n\n/* Auxiliary vector.  */\n\n/* This vector is normally only used by the program interpreter.  The\n   usual definition in an ABI supplement uses the name auxv_t.  The\n   vector is not usually defined in a standard <elf.h> file, but it\n   can't hurt.  We rename it to avoid conflicts.  The sizes of these\n   types are an arrangement between the exec server and the program\n   interpreter, so we don't fully specify them here.  */\n\ntypedef struct {\n    uint32_t a_type; /* Entry type */\n    union {\n        uint32_t a_val; /* Integer value */\n                        /* We use to have pointer elements added here.  We cannot do that,\n     though, since it does not work when using 32-bit definitions\n     on 64-bit platforms and vice versa.  */\n    } a_un;\n} Elf32_auxv_t;\n\ntypedef struct {\n    uint64_t a_type; /* Entry type */\n    union {\n        uint64_t a_val; /* Integer value */\n                        /* We use to have pointer elements added here.  We cannot do that,\n     though, since it does not work when using 32-bit definitions\n     on 64-bit platforms and vice versa.  */\n    } a_un;\n} Elf64_auxv_t;\n\n/* Legal values for a_type (entry type).  */\n\n#define AT_NULL   0  /* End of vector */\n#define AT_IGNORE 1  /* Entry should be ignored */\n#define AT_EXECFD 2  /* File descriptor of program */\n#define AT_PHDR   3  /* Program headers for program */\n#define AT_PHENT  4  /* Size of program header entry */\n#define AT_PHNUM  5  /* Number of program headers */\n#define AT_PAGESZ 6  /* System page size */\n#define AT_BASE   7  /* Base address of interpreter */\n#define AT_FLAGS  8  /* Flags */\n#define AT_ENTRY  9  /* Entry point of program */\n#define AT_NOTELF 10 /* Program is not ELF */\n#define AT_UID    11 /* Real uid */\n#define AT_EUID   12 /* Effective uid */\n#define AT_GID    13 /* Real gid */\n#define AT_EGID   14 /* Effective gid */\n#define AT_CLKTCK 17 /* Frequency of times() */\n\n/* Some more special a_type values describing the hardware.  */\n#define AT_PLATFORM 15 /* String identifying platform.  */\n#define AT_HWCAP                        \\\n    16 /* Machine dependent hints about \\\n  processor capabilities.  */\n\n/* This entry gives some information about the FPU initialization\n   performed by the kernel.  */\n#define AT_FPUCW 18 /* Used FPU control word.  */\n\n/* Cache block sizes.  */\n#define AT_DCACHEBSIZE 19 /* Data cache block size.  */\n#define AT_ICACHEBSIZE 20 /* Instruction cache block size.  */\n#define AT_UCACHEBSIZE 21 /* Unified cache block size.  */\n\n/* A special ignored value for PPC, used by the kernel to control the\n   interpretation of the AUXV. Must be > 16.  */\n#define AT_IGNOREPPC 22 /* Entry should be ignored.  */\n\n#define AT_SECURE 23 /* Boolean, was exec setuid-like?  */\n\n#define AT_EXECFN 31 /* Filename of executable.  */\n\n/* Pointer to the global system page used for system calls and other\n   nice things.  */\n#define AT_SYSINFO      32\n#define AT_SYSINFO_EHDR 33\n\n/* Shapes of the caches.  Bits 0-3 contains associativity; bits 4-7 contains\n   log2 of line size; mask those to get cache size.  */\n#define AT_L1I_CACHESHAPE 34\n#define AT_L1D_CACHESHAPE 35\n#define AT_L2_CACHESHAPE  36\n#define AT_L3_CACHESHAPE  37\n\n/* Note section contents.  Each entry in the note section begins with\n   a header of a fixed form.  */\n\ntypedef struct {\n    Elf32_Word n_namesz; /* Length of the note's name.  */\n    Elf32_Word n_descsz; /* Length of the note's descriptor.  */\n    Elf32_Word n_type;   /* Type of the note.  */\n} Elf32_Nhdr;\n\ntypedef struct {\n    Elf64_Word n_namesz; /* Length of the note's name.  */\n    Elf64_Word n_descsz; /* Length of the note's descriptor.  */\n    Elf64_Word n_type;   /* Type of the note.  */\n} Elf64_Nhdr;\n\n/* Known names of notes.  */\n\n/* Solaris entries in the note section have this name.  */\n#define ELF_NOTE_SOLARIS \"SUNW Solaris\"\n\n/* Note entries for GNU systems have this name.  */\n#define ELF_NOTE_GNU \"GNU\"\n\n/* Defined types of notes for Solaris.  */\n\n/* Value of descriptor (one word) is desired pagesize for the binary.  */\n#define ELF_NOTE_PAGESIZE_HINT 1\n\n/* Defined note types for GNU systems.  */\n\n/* ABI information.  The descriptor consists of words:\n   word 0: OS descriptor\n   word 1: major version of the ABI\n   word 2: minor version of the ABI\n   word 3: subminor version of the ABI\n*/\n#define NT_GNU_ABI_TAG 1\n#define ELF_NOTE_ABI   NT_GNU_ABI_TAG /* Old name.  */\n\n/* Known OSes.  These values can appear in word 0 of an\n   NT_GNU_ABI_TAG note section entry.  */\n#define ELF_NOTE_OS_LINUX    0\n#define ELF_NOTE_OS_GNU      1\n#define ELF_NOTE_OS_SOLARIS2 2\n#define ELF_NOTE_OS_FREEBSD  3\n\n/* Synthetic hwcap information.  The descriptor begins with two words:\n   word 0: number of entries\n   word 1: bitmask of enabled entries\n   Then follow variable-length entries, one byte followed by a\n   '\\0'-terminated hwcap name string.  The byte gives the bit\n   number to test if enabled, (1U << bit) & bitmask.  */\n#define NT_GNU_HWCAP 2\n\n/* Build ID bits as generated by ld --build-id.\n   The descriptor consists of any nonzero number of bytes.  */\n#define NT_GNU_BUILD_ID 3\n\n/* Move records.  */\ntypedef struct {\n    Elf32_Xword m_value;   /* Symbol value.  */\n    Elf32_Word  m_info;    /* Size and index.  */\n    Elf32_Word  m_poffset; /* Symbol offset.  */\n    Elf32_Half  m_repeat;  /* Repeat count.  */\n    Elf32_Half  m_stride;  /* Stride info.  */\n} Elf32_Move;\n\ntypedef struct {\n    Elf64_Xword m_value;   /* Symbol value.  */\n    Elf64_Xword m_info;    /* Size and index.  */\n    Elf64_Xword m_poffset; /* Symbol offset.  */\n    Elf64_Half  m_repeat;  /* Repeat count.  */\n    Elf64_Half  m_stride;  /* Stride info.  */\n} Elf64_Move;\n\n/* Macro to construct move records.  */\n#define ELF32_M_SYM(info)       ((info) >> 8)\n#define ELF32_M_SIZE(info)      ((unsigned char)(info))\n#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size))\n\n#define ELF64_M_SYM(info)       ELF32_M_SYM(info)\n#define ELF64_M_SIZE(info)      ELF32_M_SIZE(info)\n#define ELF64_M_INFO(sym, size) ELF32_M_INFO(sym, size)\n\n/* Motorola 68k specific definitions.  */\n\n/* Values for Elf32_Ehdr.e_flags.  */\n#define EF_CPU32 0x00810000\n\n/* m68k relocs.  */\n\n#define R_68K_NONE     0  /* No reloc */\n#define R_68K_32       1  /* Direct 32 bit  */\n#define R_68K_16       2  /* Direct 16 bit  */\n#define R_68K_8        3  /* Direct 8 bit  */\n#define R_68K_PC32     4  /* PC relative 32 bit */\n#define R_68K_PC16     5  /* PC relative 16 bit */\n#define R_68K_PC8      6  /* PC relative 8 bit */\n#define R_68K_GOT32    7  /* 32 bit PC relative GOT entry */\n#define R_68K_GOT16    8  /* 16 bit PC relative GOT entry */\n#define R_68K_GOT8     9  /* 8 bit PC relative GOT entry */\n#define R_68K_GOT32O   10 /* 32 bit GOT offset */\n#define R_68K_GOT16O   11 /* 16 bit GOT offset */\n#define R_68K_GOT8O    12 /* 8 bit GOT offset */\n#define R_68K_PLT32    13 /* 32 bit PC relative PLT address */\n#define R_68K_PLT16    14 /* 16 bit PC relative PLT address */\n#define R_68K_PLT8     15 /* 8 bit PC relative PLT address */\n#define R_68K_PLT32O   16 /* 32 bit PLT offset */\n#define R_68K_PLT16O   17 /* 16 bit PLT offset */\n#define R_68K_PLT8O    18 /* 8 bit PLT offset */\n#define R_68K_COPY     19 /* Copy symbol at runtime */\n#define R_68K_GLOB_DAT 20 /* Create GOT entry */\n#define R_68K_JMP_SLOT 21 /* Create PLT entry */\n#define R_68K_RELATIVE 22 /* Adjust by program base */\n/* Keep this the last entry.  */\n#define R_68K_NUM 23\n\n/* Intel 80386 specific definitions.  */\n\n/* i386 relocs.  */\n\n#define R_386_NONE      0  /* No reloc */\n#define R_386_32        1  /* Direct 32 bit  */\n#define R_386_PC32      2  /* PC relative 32 bit */\n#define R_386_GOT32     3  /* 32 bit GOT entry */\n#define R_386_PLT32     4  /* 32 bit PLT address */\n#define R_386_COPY      5  /* Copy symbol at runtime */\n#define R_386_GLOB_DAT  6  /* Create GOT entry */\n#define R_386_JMP_SLOT  7  /* Create PLT entry */\n#define R_386_RELATIVE  8  /* Adjust by program base */\n#define R_386_GOTOFF    9  /* 32 bit offset to GOT */\n#define R_386_GOTPC     10 /* 32 bit PC relative offset to GOT */\n#define R_386_32PLT     11\n#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */\n#define R_386_TLS_IE                          \\\n    15 /* Address of GOT entry for static TLS \\\nblock offset */\n#define R_386_TLS_GOTIE                  \\\n    16 /* GOT entry for static TLS block \\\noffset */\n#define R_386_TLS_LE                    \\\n    17 /* Offset relative to static TLS \\\nblock */\n#define R_386_TLS_GD                       \\\n    18 /* Direct 32 bit for GNU version of \\\ngeneral dynamic thread local data */\n#define R_386_TLS_LDM                      \\\n    19 /* Direct 32 bit for GNU version of \\\nlocal dynamic thread local data            \\\nin LE code */\n#define R_386_16   20\n#define R_386_PC16 21\n#define R_386_8    22\n#define R_386_PC8  23\n#define R_386_TLS_GD_32                                           \\\n    24                       /* Direct 32 bit for general dynamic \\\n                thread local data */\n#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */\n#define R_386_TLS_GD_CALL                             \\\n    26                      /* Relocation for call to \\\n               __tls_get_addr() */\n#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */\n#define R_386_TLS_LDM_32                                         \\\n    28                        /* Direct 32 bit for local dynamic \\\n                 thread local data in LE code */\n#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */\n#define R_386_TLS_LDM_CALL                             \\\n    30                       /* Relocation for call to \\\n                __tls_get_addr() in LDM code */\n#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */\n#define R_386_TLS_LDO_32  32 /* Offset relative to TLS block */\n#define R_386_TLS_IE_32                    \\\n    33 /* GOT entry for negated static TLS \\\nblock offset */\n#define R_386_TLS_LE_32                                            \\\n    34                        /* Negated offset relative to static \\\n                 TLS block */\n#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */\n#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */\n#define R_386_TLS_TPOFF32  37 /* Negated offset in static TLS block */\n/* 38? */\n#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor.  */\n#define R_386_TLS_DESC_CALL          \\\n    40 /* Marker of call through TLS \\\ndescriptor for                       \\\nrelaxation.  */\n#define R_386_TLS_DESC              \\\n    41 /* TLS descriptor containing \\\npointer to code and to              \\\nargument, returning the TLS         \\\noffset for the symbol.  */\n/* Keep this the last entry.  */\n#define R_386_NUM 42\n\n/* SUN SPARC specific definitions.  */\n\n/* Legal values for ST_TYPE subfield of st_info (symbol type).  */\n\n#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */\n\n/* Values for Elf64_Ehdr.e_flags.  */\n\n#define EF_SPARCV9_MM     3\n#define EF_SPARCV9_TSO    0\n#define EF_SPARCV9_PSO    1\n#define EF_SPARCV9_RMO    2\n#define EF_SPARC_LEDATA   0x800000 /* little endian data */\n#define EF_SPARC_EXT_MASK 0xFFFF00\n#define EF_SPARC_32PLUS   0x000100 /* generic V8+ features */\n#define EF_SPARC_SUN_US1  0x000200 /* Sun UltraSPARC1 extensions */\n#define EF_SPARC_HAL_R1   0x000400 /* HAL R1 extensions */\n#define EF_SPARC_SUN_US3  0x000800 /* Sun UltraSPARCIII extensions */\n\n/* SPARC relocs.  */\n\n#define R_SPARC_NONE     0  /* No reloc */\n#define R_SPARC_8        1  /* Direct 8 bit */\n#define R_SPARC_16       2  /* Direct 16 bit */\n#define R_SPARC_32       3  /* Direct 32 bit */\n#define R_SPARC_DISP8    4  /* PC relative 8 bit */\n#define R_SPARC_DISP16   5  /* PC relative 16 bit */\n#define R_SPARC_DISP32   6  /* PC relative 32 bit */\n#define R_SPARC_WDISP30  7  /* PC relative 30 bit shifted */\n#define R_SPARC_WDISP22  8  /* PC relative 22 bit shifted */\n#define R_SPARC_HI22     9  /* High 22 bit */\n#define R_SPARC_22       10 /* Direct 22 bit */\n#define R_SPARC_13       11 /* Direct 13 bit */\n#define R_SPARC_LO10     12 /* Truncated 10 bit */\n#define R_SPARC_GOT10    13 /* Truncated 10 bit GOT entry */\n#define R_SPARC_GOT13    14 /* 13 bit GOT entry */\n#define R_SPARC_GOT22    15 /* 22 bit GOT entry shifted */\n#define R_SPARC_PC10     16 /* PC relative 10 bit truncated */\n#define R_SPARC_PC22     17 /* PC relative 22 bit shifted */\n#define R_SPARC_WPLT30   18 /* 30 bit PC relative PLT address */\n#define R_SPARC_COPY     19 /* Copy symbol at runtime */\n#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */\n#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */\n#define R_SPARC_RELATIVE 22 /* Adjust by program base */\n#define R_SPARC_UA32     23 /* Direct 32 bit unaligned */\n\n/* Additional Sparc64 relocs.  */\n\n#define R_SPARC_PLT32         24 /* Direct 32 bit ref to PLT entry */\n#define R_SPARC_HIPLT22       25 /* High 22 bit PLT entry */\n#define R_SPARC_LOPLT10       26 /* Truncated 10 bit PLT entry */\n#define R_SPARC_PCPLT32       27 /* PC rel 32 bit ref to PLT entry */\n#define R_SPARC_PCPLT22       28 /* PC rel high 22 bit PLT entry */\n#define R_SPARC_PCPLT10       29 /* PC rel trunc 10 bit PLT entry */\n#define R_SPARC_10            30 /* Direct 10 bit */\n#define R_SPARC_11            31 /* Direct 11 bit */\n#define R_SPARC_64            32 /* Direct 64 bit */\n#define R_SPARC_OLO10         33 /* 10bit with secondary 13bit addend */\n#define R_SPARC_HH22          34 /* Top 22 bits of direct 64 bit */\n#define R_SPARC_HM10          35 /* High middle 10 bits of ... */\n#define R_SPARC_LM22          36 /* Low middle 22 bits of ... */\n#define R_SPARC_PC_HH22       37 /* Top 22 bits of pc rel 64 bit */\n#define R_SPARC_PC_HM10       38 /* High middle 10 bit of ... */\n#define R_SPARC_PC_LM22       39 /* Low miggle 22 bits of ... */\n#define R_SPARC_WDISP16       40 /* PC relative 16 bit shifted */\n#define R_SPARC_WDISP19       41 /* PC relative 19 bit shifted */\n#define R_SPARC_7             43 /* Direct 7 bit */\n#define R_SPARC_5             44 /* Direct 5 bit */\n#define R_SPARC_6             45 /* Direct 6 bit */\n#define R_SPARC_DISP64        46 /* PC relative 64 bit */\n#define R_SPARC_PLT64         47 /* Direct 64 bit ref to PLT entry */\n#define R_SPARC_HIX22         48 /* High 22 bit complemented */\n#define R_SPARC_LOX10         49 /* Truncated 11 bit complemented */\n#define R_SPARC_H44           50 /* Direct high 12 of 44 bit */\n#define R_SPARC_M44           51 /* Direct mid 22 of 44 bit */\n#define R_SPARC_L44           52 /* Direct low 10 of 44 bit */\n#define R_SPARC_REGISTER      53 /* Global register usage */\n#define R_SPARC_UA64          54 /* Direct 64 bit unaligned */\n#define R_SPARC_UA16          55 /* Direct 16 bit unaligned */\n#define R_SPARC_TLS_GD_HI22   56\n#define R_SPARC_TLS_GD_LO10   57\n#define R_SPARC_TLS_GD_ADD    58\n#define R_SPARC_TLS_GD_CALL   59\n#define R_SPARC_TLS_LDM_HI22  60\n#define R_SPARC_TLS_LDM_LO10  61\n#define R_SPARC_TLS_LDM_ADD   62\n#define R_SPARC_TLS_LDM_CALL  63\n#define R_SPARC_TLS_LDO_HIX22 64\n#define R_SPARC_TLS_LDO_LOX10 65\n#define R_SPARC_TLS_LDO_ADD   66\n#define R_SPARC_TLS_IE_HI22   67\n#define R_SPARC_TLS_IE_LO10   68\n#define R_SPARC_TLS_IE_LD     69\n#define R_SPARC_TLS_IE_LDX    70\n#define R_SPARC_TLS_IE_ADD    71\n#define R_SPARC_TLS_LE_HIX22  72\n#define R_SPARC_TLS_LE_LOX10  73\n#define R_SPARC_TLS_DTPMOD32  74\n#define R_SPARC_TLS_DTPMOD64  75\n#define R_SPARC_TLS_DTPOFF32  76\n#define R_SPARC_TLS_DTPOFF64  77\n#define R_SPARC_TLS_TPOFF32   78\n#define R_SPARC_TLS_TPOFF64   79\n/* Keep this the last entry.  */\n#define R_SPARC_NUM 80\n\n/* For Sparc64, legal values for d_tag of Elf64_Dyn.  */\n\n#define DT_SPARC_REGISTER 0x70000001\n#define DT_SPARC_NUM      2\n\n/* Bits present in AT_HWCAP on SPARC.  */\n\n#define HWCAP_SPARC_FLUSH   1 /* The CPU supports flush insn.  */\n#define HWCAP_SPARC_STBAR   2\n#define HWCAP_SPARC_SWAP    4\n#define HWCAP_SPARC_MULDIV  8\n#define HWCAP_SPARC_V9      16 /* The CPU is v9, so v8plus is ok.  */\n#define HWCAP_SPARC_ULTRA3  32\n#define HWCAP_SPARC_BLKINIT 64 /* Sun4v with block-init/load-twin.  */\n#define HWCAP_SPARC_N2      128\n\n/* MIPS R3000 specific definitions.  */\n\n/* Legal values for e_flags field of Elf32_Ehdr.  */\n\n#define EF_MIPS_NOREORDER   1 /* A .noreorder directive was used */\n#define EF_MIPS_PIC         2 /* Contains PIC code */\n#define EF_MIPS_CPIC        4 /* Uses PIC calling sequence */\n#define EF_MIPS_XGOT        8\n#define EF_MIPS_64BIT_WHIRL 16\n#define EF_MIPS_ABI2        32\n#define EF_MIPS_ABI_ON32    64\n#define EF_MIPS_ARCH        0xf0000000 /* MIPS architecture level */\n\n/* Legal values for MIPS architecture level.  */\n\n#define EF_MIPS_ARCH_1  0x00000000 /* -mips1 code.  */\n#define EF_MIPS_ARCH_2  0x10000000 /* -mips2 code.  */\n#define EF_MIPS_ARCH_3  0x20000000 /* -mips3 code.  */\n#define EF_MIPS_ARCH_4  0x30000000 /* -mips4 code.  */\n#define EF_MIPS_ARCH_5  0x40000000 /* -mips5 code.  */\n#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code.  */\n#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code.  */\n\n/* The following are non-official names and should not be used.  */\n\n#define E_MIPS_ARCH_1  0x00000000 /* -mips1 code.  */\n#define E_MIPS_ARCH_2  0x10000000 /* -mips2 code.  */\n#define E_MIPS_ARCH_3  0x20000000 /* -mips3 code.  */\n#define E_MIPS_ARCH_4  0x30000000 /* -mips4 code.  */\n#define E_MIPS_ARCH_5  0x40000000 /* -mips5 code.  */\n#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code.  */\n#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code.  */\n\n/* Special section indices.  */\n\n#define SHN_MIPS_ACOMMON    0xff00 /* Allocated common symbols */\n#define SHN_MIPS_TEXT       0xff01 /* Allocated test symbols.  */\n#define SHN_MIPS_DATA       0xff02 /* Allocated data symbols.  */\n#define SHN_MIPS_SCOMMON    0xff03 /* Small common symbols */\n#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */\n\n/* Legal values for sh_type field of Elf32_Shdr.  */\n\n#define SHT_MIPS_LIBLIST       0x70000000 /* Shared objects used in link */\n#define SHT_MIPS_MSYM          0x70000001\n#define SHT_MIPS_CONFLICT      0x70000002 /* Conflicting symbols */\n#define SHT_MIPS_GPTAB         0x70000003 /* Global data area sizes */\n#define SHT_MIPS_UCODE         0x70000004 /* Reserved for SGI/MIPS compilers */\n#define SHT_MIPS_DEBUG         0x70000005 /* MIPS ECOFF debugging information*/\n#define SHT_MIPS_REGINFO       0x70000006 /* Register usage information */\n#define SHT_MIPS_PACKAGE       0x70000007\n#define SHT_MIPS_PACKSYM       0x70000008\n#define SHT_MIPS_RELD          0x70000009\n#define SHT_MIPS_IFACE         0x7000000b\n#define SHT_MIPS_CONTENT       0x7000000c\n#define SHT_MIPS_OPTIONS       0x7000000d /* Miscellaneous options.  */\n#define SHT_MIPS_SHDR          0x70000010\n#define SHT_MIPS_FDESC         0x70000011\n#define SHT_MIPS_EXTSYM        0x70000012\n#define SHT_MIPS_DENSE         0x70000013\n#define SHT_MIPS_PDESC         0x70000014\n#define SHT_MIPS_LOCSYM        0x70000015\n#define SHT_MIPS_AUXSYM        0x70000016\n#define SHT_MIPS_OPTSYM        0x70000017\n#define SHT_MIPS_LOCSTR        0x70000018\n#define SHT_MIPS_LINE          0x70000019\n#define SHT_MIPS_RFDESC        0x7000001a\n#define SHT_MIPS_DELTASYM      0x7000001b\n#define SHT_MIPS_DELTAINST     0x7000001c\n#define SHT_MIPS_DELTACLASS    0x7000001d\n#define SHT_MIPS_DWARF         0x7000001e /* DWARF debugging information.  */\n#define SHT_MIPS_DELTADECL     0x7000001f\n#define SHT_MIPS_SYMBOL_LIB    0x70000020\n#define SHT_MIPS_EVENTS        0x70000021 /* Event section.  */\n#define SHT_MIPS_TRANSLATE     0x70000022\n#define SHT_MIPS_PIXIE         0x70000023\n#define SHT_MIPS_XLATE         0x70000024\n#define SHT_MIPS_XLATE_DEBUG   0x70000025\n#define SHT_MIPS_WHIRL         0x70000026\n#define SHT_MIPS_EH_REGION     0x70000027\n#define SHT_MIPS_XLATE_OLD     0x70000028\n#define SHT_MIPS_PDR_EXCEPTION 0x70000029\n\n/* Legal values for sh_flags field of Elf32_Shdr.  */\n\n#define SHF_MIPS_GPREL   0x10000000 /* Must be part of global data area */\n#define SHF_MIPS_MERGE   0x20000000\n#define SHF_MIPS_ADDR    0x40000000\n#define SHF_MIPS_STRINGS 0x80000000\n#define SHF_MIPS_NOSTRIP 0x08000000\n#define SHF_MIPS_LOCAL   0x04000000\n#define SHF_MIPS_NAMES   0x02000000\n#define SHF_MIPS_NODUPE  0x01000000\n\n/* Symbol tables.  */\n\n/* MIPS specific values for `st_other'.  */\n#define STO_MIPS_DEFAULT         0x0\n#define STO_MIPS_INTERNAL        0x1\n#define STO_MIPS_HIDDEN          0x2\n#define STO_MIPS_PROTECTED       0x3\n#define STO_MIPS_PLT             0x8\n#define STO_MIPS_SC_ALIGN_UNUSED 0xff\n\n/* MIPS specific values for `st_info'.  */\n#define STB_MIPS_SPLIT_COMMON 13\n\n/* Entries found in sections of type SHT_MIPS_GPTAB.  */\n\ntypedef union {\n    struct {\n        Elf32_Word gt_current_g_value; /* -G value used for compilation */\n        Elf32_Word gt_unused;          /* Not used */\n    } gt_header;                       /* First entry in section */\n    struct {\n        Elf32_Word gt_g_value; /* If this value were used for -G */\n        Elf32_Word gt_bytes;   /* This many bytes would be used */\n    } gt_entry;                /* Subsequent entries in section */\n} Elf32_gptab;\n\n/* Entry found in sections of type SHT_MIPS_REGINFO.  */\n\ntypedef struct {\n    Elf32_Word  ri_gprmask;    /* General registers used */\n    Elf32_Word  ri_cprmask[4]; /* Coprocessor registers used */\n    Elf32_Sword ri_gp_value;   /* $gp register value */\n} Elf32_RegInfo;\n\n/* Entries found in sections of type SHT_MIPS_OPTIONS.  */\n\ntypedef struct {\n    unsigned char kind;    /* Determines interpretation of the\n                   variable part of descriptor.  */\n    unsigned char size;    /* Size of descriptor, including header.  */\n    Elf32_Section section; /* Section header index of section affected,\n                   0 for global options.  */\n    Elf32_Word info;       /* Kind-specific information.  */\n} Elf_Options;\n\n/* Values for `kind' field in Elf_Options.  */\n\n#define ODK_NULL       0 /* Undefined.  */\n#define ODK_REGINFO    1 /* Register usage information.  */\n#define ODK_EXCEPTIONS 2 /* Exception processing options.  */\n#define ODK_PAD        3 /* Section padding options.  */\n#define ODK_HWPATCH    4 /* Hardware workarounds performed */\n#define ODK_FILL       5 /* record the fill value used by the linker. */\n#define ODK_TAGS       6 /* reserve space for desktop tools to write. */\n#define ODK_HWAND      7 /* HW workarounds.  'AND' bits when merging. */\n#define ODK_HWOR       8 /* HW workarounds.  'OR' bits when merging.  */\n\n/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries.  */\n\n#define OEX_FPU_MIN   0x1f    /* FPE's which MUST be enabled.  */\n#define OEX_FPU_MAX   0x1f00  /* FPE's which MAY be enabled.  */\n#define OEX_PAGE0     0x10000 /* page zero must be mapped.  */\n#define OEX_SMM       0x20000 /* Force sequential memory mode?  */\n#define OEX_FPDBUG    0x40000 /* Force floating point debug mode?  */\n#define OEX_PRECISEFP OEX_FPDBUG\n#define OEX_DISMISS   0x80000 /* Dismiss invalid address faults?  */\n\n#define OEX_FPU_INVAL 0x10\n#define OEX_FPU_DIV0  0x08\n#define OEX_FPU_OFLO  0x04\n#define OEX_FPU_UFLO  0x02\n#define OEX_FPU_INEX  0x01\n\n/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry.  */\n\n#define OHW_R4KEOP    0x1 /* R4000 end-of-page patch.  */\n#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch.  */\n#define OHW_R5KEOP    0x4 /* R5000 end-of-page patch.  */\n#define OHW_R5KCVTL   0x8 /* R5000 cvt.[ds].l bug.  clean=1.  */\n\n#define OPAD_PREFIX  0x1\n#define OPAD_POSTFIX 0x2\n#define OPAD_SYMBOL  0x4\n\n/* Entry found in `.options' section.  */\n\ntypedef struct {\n    Elf32_Word hwp_flags1; /* Extra flags.  */\n    Elf32_Word hwp_flags2; /* Extra flags.  */\n} Elf_Options_Hw;\n\n/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries.  */\n\n#define OHWA0_R4KEOP_CHECKED 0x00000001\n#define OHWA1_R4KEOP_CLEAN   0x00000002\n\n/* MIPS relocs.  */\n\n#define R_MIPS_NONE    0  /* No reloc */\n#define R_MIPS_16      1  /* Direct 16 bit */\n#define R_MIPS_32      2  /* Direct 32 bit */\n#define R_MIPS_REL32   3  /* PC relative 32 bit */\n#define R_MIPS_26      4  /* Direct 26 bit shifted */\n#define R_MIPS_HI16    5  /* High 16 bit */\n#define R_MIPS_LO16    6  /* Low 16 bit */\n#define R_MIPS_GPREL16 7  /* GP relative 16 bit */\n#define R_MIPS_LITERAL 8  /* 16 bit literal entry */\n#define R_MIPS_GOT16   9  /* 16 bit GOT entry */\n#define R_MIPS_PC16    10 /* PC relative 16 bit */\n#define R_MIPS_CALL16  11 /* 16 bit GOT entry for function */\n#define R_MIPS_GPREL32 12 /* GP relative 32 bit */\n\n#define R_MIPS_SHIFT5          16\n#define R_MIPS_SHIFT6          17\n#define R_MIPS_64              18\n#define R_MIPS_GOT_DISP        19\n#define R_MIPS_GOT_PAGE        20\n#define R_MIPS_GOT_OFST        21\n#define R_MIPS_GOT_HI16        22\n#define R_MIPS_GOT_LO16        23\n#define R_MIPS_SUB             24\n#define R_MIPS_INSERT_A        25\n#define R_MIPS_INSERT_B        26\n#define R_MIPS_DELETE          27\n#define R_MIPS_HIGHER          28\n#define R_MIPS_HIGHEST         29\n#define R_MIPS_CALL_HI16       30\n#define R_MIPS_CALL_LO16       31\n#define R_MIPS_SCN_DISP        32\n#define R_MIPS_REL16           33\n#define R_MIPS_ADD_IMMEDIATE   34\n#define R_MIPS_PJUMP           35\n#define R_MIPS_RELGOT          36\n#define R_MIPS_JALR            37\n#define R_MIPS_TLS_DTPMOD32    38 /* Module number 32 bit */\n#define R_MIPS_TLS_DTPREL32    39 /* Module-relative offset 32 bit */\n#define R_MIPS_TLS_DTPMOD64    40 /* Module number 64 bit */\n#define R_MIPS_TLS_DTPREL64    41 /* Module-relative offset 64 bit */\n#define R_MIPS_TLS_GD          42 /* 16 bit GOT offset for GD */\n#define R_MIPS_TLS_LDM         43 /* 16 bit GOT offset for LDM */\n#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */\n#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */\n#define R_MIPS_TLS_GOTTPREL    46 /* 16 bit GOT offset for IE */\n#define R_MIPS_TLS_TPREL32     47 /* TP-relative offset, 32 bit */\n#define R_MIPS_TLS_TPREL64     48 /* TP-relative offset, 64 bit */\n#define R_MIPS_TLS_TPREL_HI16  49 /* TP-relative offset, high 16 bits */\n#define R_MIPS_TLS_TPREL_LO16  50 /* TP-relative offset, low 16 bits */\n#define R_MIPS_GLOB_DAT        51\n#define R_MIPS_COPY            126\n#define R_MIPS_JUMP_SLOT       127\n/* Keep this the last entry.  */\n#define R_MIPS_NUM 128\n\n/* Legal values for p_type field of Elf32_Phdr.  */\n\n#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */\n#define PT_MIPS_RTPROC  0x70000001 /* Runtime procedure table. */\n#define PT_MIPS_OPTIONS 0x70000002\n\n/* Special program header types.  */\n\n#define PF_MIPS_LOCAL 0x10000000\n\n/* Legal values for d_tag field of Elf32_Dyn.  */\n\n#define DT_MIPS_RLD_VERSION  0x70000001 /* Runtime linker interface version */\n#define DT_MIPS_TIME_STAMP   0x70000002 /* Timestamp */\n#define DT_MIPS_ICHECKSUM    0x70000003 /* Checksum */\n#define DT_MIPS_IVERSION     0x70000004 /* Version string (string tbl index) */\n#define DT_MIPS_FLAGS        0x70000005 /* Flags */\n#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */\n#define DT_MIPS_MSYM         0x70000007\n#define DT_MIPS_CONFLICT     0x70000008 /* Address of CONFLICT section */\n#define DT_MIPS_LIBLIST      0x70000009 /* Address of LIBLIST section */\n#define DT_MIPS_LOCAL_GOTNO  0x7000000a /* Number of local GOT entries */\n#define DT_MIPS_CONFLICTNO   0x7000000b /* Number of CONFLICT entries */\n#define DT_MIPS_LIBLISTNO    0x70000010 /* Number of LIBLIST entries */\n#define DT_MIPS_SYMTABNO     0x70000011 /* Number of DYNSYM entries */\n#define DT_MIPS_UNREFEXTNO   0x70000012 /* First external DYNSYM */\n#define DT_MIPS_GOTSYM       0x70000013 /* First GOT entry in DYNSYM */\n#define DT_MIPS_HIPAGENO     0x70000014 /* Number of GOT page table entries */\n#define DT_MIPS_RLD_MAP      0x70000016 /* Address of run time loader map.  */\n#define DT_MIPS_DELTA_CLASS  0x70000017 /* Delta C++ class definition.  */\n#define DT_MIPS_DELTA_CLASS_NO                                    \\\n    0x70000018                            /* Number of entries in \\\n                     DT_MIPS_DELTA_CLASS.  */\n#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances.  */\n#define DT_MIPS_DELTA_INSTANCE_NO                              \\\n    0x7000001a                         /* Number of entries in \\\n                  DT_MIPS_DELTA_INSTANCE.  */\n#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations.  */\n#define DT_MIPS_DELTA_RELOC_NO         \\\n    0x7000001c /* Number of entries in \\\nDT_MIPS_DELTA_RELOC.  */\n#define DT_MIPS_DELTA_SYM                  \\\n    0x7000001d /* Delta symbols that Delta \\\nrelocations refer to.  */\n#define DT_MIPS_DELTA_SYM_NO           \\\n    0x7000001e /* Number of entries in \\\nDT_MIPS_DELTA_SYM.  */\n#define DT_MIPS_DELTA_CLASSSYM                \\\n    0x70000020 /* Delta symbols that hold the \\\nclass declaration.  */\n#define DT_MIPS_DELTA_CLASSSYM_NO                                   \\\n    0x70000021                              /* Number of entries in \\\n                       DT_MIPS_DELTA_CLASSSYM.  */\n#define DT_MIPS_CXX_FLAGS        0x70000022 /* Flags indicating for C++ flavor.  */\n#define DT_MIPS_PIXIE_INIT       0x70000023\n#define DT_MIPS_SYMBOL_LIB       0x70000024\n#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025\n#define DT_MIPS_LOCAL_GOTIDX     0x70000026\n#define DT_MIPS_HIDDEN_GOTIDX    0x70000027\n#define DT_MIPS_PROTECTED_GOTIDX 0x70000028\n#define DT_MIPS_OPTIONS          0x70000029 /* Address of .options.  */\n#define DT_MIPS_INTERFACE        0x7000002a /* Address of .interface.  */\n#define DT_MIPS_DYNSTR_ALIGN     0x7000002b\n#define DT_MIPS_INTERFACE_SIZE   0x7000002c /* Size of the .interface section. */\n#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR        \\\n    0x7000002d /* Address of rld_text_rsolve \\\nfunction stored in GOT.  */\n#define DT_MIPS_PERF_SUFFIX                                                  \\\n    0x7000002e                          /* Default suffix of dso to be added \\\n                       by rld on dlopen() calls.  */\n#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */\n#define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */\n#define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */\n/* The address of .got.plt in an executable using the new non-PIC ABI.  */\n#define DT_MIPS_PLTGOT 0x70000032\n/* The base of the PLT in an executable using the new non-PIC ABI if that\n   PLT is writable.  For a non-writable PLT, this is omitted or has a zero\n   value.  */\n#define DT_MIPS_RWPLT 0x70000034\n#define DT_MIPS_NUM   0x35\n\n/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */\n\n#define RHF_NONE                   0        /* No flags */\n#define RHF_QUICKSTART             (1 << 0) /* Use quickstart */\n#define RHF_NOTPOT                 (1 << 1) /* Hash size not power of 2 */\n#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */\n#define RHF_NO_MOVE                (1 << 3)\n#define RHF_SGI_ONLY               (1 << 4)\n#define RHF_GUARANTEE_INIT         (1 << 5)\n#define RHF_DELTA_C_PLUS_PLUS      (1 << 6)\n#define RHF_GUARANTEE_START_INIT   (1 << 7)\n#define RHF_PIXIE                  (1 << 8)\n#define RHF_DEFAULT_DELAY_LOAD     (1 << 9)\n#define RHF_REQUICKSTART           (1 << 10)\n#define RHF_REQUICKSTARTED         (1 << 11)\n#define RHF_CORD                   (1 << 12)\n#define RHF_NO_UNRES_UNDEF         (1 << 13)\n#define RHF_RLD_ORDER_SAFE         (1 << 14)\n\n/* Entries found in sections of type SHT_MIPS_LIBLIST.  */\n\ntypedef struct {\n    Elf32_Word l_name;       /* Name (string table index) */\n    Elf32_Word l_time_stamp; /* Timestamp */\n    Elf32_Word l_checksum;   /* Checksum */\n    Elf32_Word l_version;    /* Interface version */\n    Elf32_Word l_flags;      /* Flags */\n} Elf32_Lib;\n\ntypedef struct {\n    Elf64_Word l_name;       /* Name (string table index) */\n    Elf64_Word l_time_stamp; /* Timestamp */\n    Elf64_Word l_checksum;   /* Checksum */\n    Elf64_Word l_version;    /* Interface version */\n    Elf64_Word l_flags;      /* Flags */\n} Elf64_Lib;\n\n/* Legal values for l_flags.  */\n\n#define LL_NONE           0\n#define LL_EXACT_MATCH    (1 << 0) /* Require exact match */\n#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */\n#define LL_REQUIRE_MINOR  (1 << 2)\n#define LL_EXPORTS        (1 << 3)\n#define LL_DELAY_LOAD     (1 << 4)\n#define LL_DELTA          (1 << 5)\n\n/* Entries found in sections of type SHT_MIPS_CONFLICT.  */\n\ntypedef Elf32_Addr Elf32_Conflict;\n\n/* HPPA specific definitions.  */\n\n/* Legal values for e_flags field of Elf32_Ehdr.  */\n\n#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference.  */\n#define EF_PARISC_EXT     0x00020000 /* Program uses arch. extensions. */\n#define EF_PARISC_LSB     0x00040000 /* Program expects little endian. */\n#define EF_PARISC_WIDE    0x00080000 /* Program expects wide mode.  */\n#define EF_PARISC_NO_KABP                                          \\\n    0x00100000                        /* No kernel assisted branch \\\n                         prediction.  */\n#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping.  */\n#define EF_PARISC_ARCH     0x0000ffff /* Architecture version.  */\n\n/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */\n\n#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian.  */\n#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian.  */\n#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian.  */\n\n/* Additional section indeces.  */\n\n#define SHN_PARISC_ANSI_COMMON                                           \\\n    0xff00                            /* Section for tenatively declared \\\n                     symbols in ANSI C.  */\n#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model.  */\n\n/* Legal values for sh_type field of Elf32_Shdr.  */\n\n#define SHT_PARISC_EXT    0x70000000 /* Contains product specific ext. */\n#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information.  */\n#define SHT_PARISC_DOC    0x70000002 /* Debug info for optimized code. */\n\n/* Legal values for sh_flags field of Elf32_Shdr.  */\n\n#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */\n#define SHF_PARISC_HUGE  0x40000000 /* Section far from gp.  */\n#define SHF_PARISC_SBP   0x80000000 /* Static branch prediction code. */\n\n/* Legal values for ST_TYPE subfield of st_info (symbol type).  */\n\n#define STT_PARISC_MILLICODE 13 /* Millicode function entry point.  */\n\n#define STT_HP_OPAQUE (STT_LOOS + 0x1)\n#define STT_HP_STUB   (STT_LOOS + 0x2)\n\n/* HPPA relocs.  */\n\n#define R_PARISC_NONE           0   /* No reloc.  */\n#define R_PARISC_DIR32          1   /* Direct 32-bit reference.  */\n#define R_PARISC_DIR21L         2   /* Left 21 bits of eff. address.  */\n#define R_PARISC_DIR17R         3   /* Right 17 bits of eff. address.  */\n#define R_PARISC_DIR17F         4   /* 17 bits of eff. address.  */\n#define R_PARISC_DIR14R         6   /* Right 14 bits of eff. address.  */\n#define R_PARISC_PCREL32        9   /* 32-bit rel. address.  */\n#define R_PARISC_PCREL21L       10  /* Left 21 bits of rel. address.  */\n#define R_PARISC_PCREL17R       11  /* Right 17 bits of rel. address.  */\n#define R_PARISC_PCREL17F       12  /* 17 bits of rel. address.  */\n#define R_PARISC_PCREL14R       14  /* Right 14 bits of rel. address.  */\n#define R_PARISC_DPREL21L       18  /* Left 21 bits of rel. address.  */\n#define R_PARISC_DPREL14R       22  /* Right 14 bits of rel. address.  */\n#define R_PARISC_GPREL21L       26  /* GP-relative, left 21 bits.  */\n#define R_PARISC_GPREL14R       30  /* GP-relative, right 14 bits.  */\n#define R_PARISC_LTOFF21L       34  /* LT-relative, left 21 bits.  */\n#define R_PARISC_LTOFF14R       38  /* LT-relative, right 14 bits.  */\n#define R_PARISC_SECREL32       41  /* 32 bits section rel. address.  */\n#define R_PARISC_SEGBASE        48  /* No relocation, set segment base.  */\n#define R_PARISC_SEGREL32       49  /* 32 bits segment rel. address.  */\n#define R_PARISC_PLTOFF21L      50  /* PLT rel. address, left 21 bits.  */\n#define R_PARISC_PLTOFF14R      54  /* PLT rel. address, right 14 bits.  */\n#define R_PARISC_LTOFF_FPTR32   57  /* 32 bits LT-rel. function pointer. */\n#define R_PARISC_LTOFF_FPTR21L  58  /* LT-rel. fct ptr, left 21 bits. */\n#define R_PARISC_LTOFF_FPTR14R  62  /* LT-rel. fct ptr, right 14 bits. */\n#define R_PARISC_FPTR64         64  /* 64 bits function address.  */\n#define R_PARISC_PLABEL32       65  /* 32 bits function address.  */\n#define R_PARISC_PLABEL21L      66  /* Left 21 bits of fdesc address.  */\n#define R_PARISC_PLABEL14R      70  /* Right 14 bits of fdesc address.  */\n#define R_PARISC_PCREL64        72  /* 64 bits PC-rel. address.  */\n#define R_PARISC_PCREL22F       74  /* 22 bits PC-rel. address.  */\n#define R_PARISC_PCREL14WR      75  /* PC-rel. address, right 14 bits.  */\n#define R_PARISC_PCREL14DR      76  /* PC rel. address, right 14 bits.  */\n#define R_PARISC_PCREL16F       77  /* 16 bits PC-rel. address.  */\n#define R_PARISC_PCREL16WF      78  /* 16 bits PC-rel. address.  */\n#define R_PARISC_PCREL16DF      79  /* 16 bits PC-rel. address.  */\n#define R_PARISC_DIR64          80  /* 64 bits of eff. address.  */\n#define R_PARISC_DIR14WR        83  /* 14 bits of eff. address.  */\n#define R_PARISC_DIR14DR        84  /* 14 bits of eff. address.  */\n#define R_PARISC_DIR16F         85  /* 16 bits of eff. address.  */\n#define R_PARISC_DIR16WF        86  /* 16 bits of eff. address.  */\n#define R_PARISC_DIR16DF        87  /* 16 bits of eff. address.  */\n#define R_PARISC_GPREL64        88  /* 64 bits of GP-rel. address.  */\n#define R_PARISC_GPREL14WR      91  /* GP-rel. address, right 14 bits.  */\n#define R_PARISC_GPREL14DR      92  /* GP-rel. address, right 14 bits.  */\n#define R_PARISC_GPREL16F       93  /* 16 bits GP-rel. address.  */\n#define R_PARISC_GPREL16WF      94  /* 16 bits GP-rel. address.  */\n#define R_PARISC_GPREL16DF      95  /* 16 bits GP-rel. address.  */\n#define R_PARISC_LTOFF64        96  /* 64 bits LT-rel. address.  */\n#define R_PARISC_LTOFF14WR      99  /* LT-rel. address, right 14 bits.  */\n#define R_PARISC_LTOFF14DR      100 /* LT-rel. address, right 14 bits.  */\n#define R_PARISC_LTOFF16F       101 /* 16 bits LT-rel. address.  */\n#define R_PARISC_LTOFF16WF      102 /* 16 bits LT-rel. address.  */\n#define R_PARISC_LTOFF16DF      103 /* 16 bits LT-rel. address.  */\n#define R_PARISC_SECREL64       104 /* 64 bits section rel. address.  */\n#define R_PARISC_SEGREL64       112 /* 64 bits segment rel. address.  */\n#define R_PARISC_PLTOFF14WR     115 /* PLT-rel. address, right 14 bits.  */\n#define R_PARISC_PLTOFF14DR     116 /* PLT-rel. address, right 14 bits.  */\n#define R_PARISC_PLTOFF16F      117 /* 16 bits LT-rel. address.  */\n#define R_PARISC_PLTOFF16WF     118 /* 16 bits PLT-rel. address.  */\n#define R_PARISC_PLTOFF16DF     119 /* 16 bits PLT-rel. address.  */\n#define R_PARISC_LTOFF_FPTR64   120 /* 64 bits LT-rel. function ptr.  */\n#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */\n#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */\n#define R_PARISC_LTOFF_FPTR16F  125 /* 16 bits LT-rel. function ptr.  */\n#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr.  */\n#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr.  */\n#define R_PARISC_LORESERVE      128\n#define R_PARISC_COPY           128 /* Copy relocation.  */\n#define R_PARISC_IPLT           129 /* Dynamic reloc, imported PLT */\n#define R_PARISC_EPLT           130 /* Dynamic reloc, exported PLT */\n#define R_PARISC_TPREL32        153 /* 32 bits TP-rel. address.  */\n#define R_PARISC_TPREL21L       154 /* TP-rel. address, left 21 bits.  */\n#define R_PARISC_TPREL14R       158 /* TP-rel. address, right 14 bits.  */\n#define R_PARISC_LTOFF_TP21L    162 /* LT-TP-rel. address, left 21 bits. */\n#define R_PARISC_LTOFF_TP14R    166 /* LT-TP-rel. address, right 14 bits.*/\n#define R_PARISC_LTOFF_TP14F    167 /* 14 bits LT-TP-rel. address.  */\n#define R_PARISC_TPREL64        216 /* 64 bits TP-rel. address.  */\n#define R_PARISC_TPREL14WR      219 /* TP-rel. address, right 14 bits.  */\n#define R_PARISC_TPREL14DR      220 /* TP-rel. address, right 14 bits.  */\n#define R_PARISC_TPREL16F       221 /* 16 bits TP-rel. address.  */\n#define R_PARISC_TPREL16WF      222 /* 16 bits TP-rel. address.  */\n#define R_PARISC_TPREL16DF      223 /* 16 bits TP-rel. address.  */\n#define R_PARISC_LTOFF_TP64     224 /* 64 bits LT-TP-rel. address.  */\n#define R_PARISC_LTOFF_TP14WR   227 /* LT-TP-rel. address, right 14 bits.*/\n#define R_PARISC_LTOFF_TP14DR   228 /* LT-TP-rel. address, right 14 bits.*/\n#define R_PARISC_LTOFF_TP16F    229 /* 16 bits LT-TP-rel. address.  */\n#define R_PARISC_LTOFF_TP16WF   230 /* 16 bits LT-TP-rel. address.  */\n#define R_PARISC_LTOFF_TP16DF   231 /* 16 bits LT-TP-rel. address.  */\n#define R_PARISC_GNU_VTENTRY    232\n#define R_PARISC_GNU_VTINHERIT  233\n#define R_PARISC_TLS_GD21L      234 /* GD 21-bit left.  */\n#define R_PARISC_TLS_GD14R      235 /* GD 14-bit right.  */\n#define R_PARISC_TLS_GDCALL     236 /* GD call to __t_g_a.  */\n#define R_PARISC_TLS_LDM21L     237 /* LD module 21-bit left.  */\n#define R_PARISC_TLS_LDM14R     238 /* LD module 14-bit right.  */\n#define R_PARISC_TLS_LDMCALL    239 /* LD module call to __t_g_a.  */\n#define R_PARISC_TLS_LDO21L     240 /* LD offset 21-bit left.  */\n#define R_PARISC_TLS_LDO14R     241 /* LD offset 14-bit right.  */\n#define R_PARISC_TLS_DTPMOD32   242 /* DTP module 32-bit.  */\n#define R_PARISC_TLS_DTPMOD64   243 /* DTP module 64-bit.  */\n#define R_PARISC_TLS_DTPOFF32   244 /* DTP offset 32-bit.  */\n#define R_PARISC_TLS_DTPOFF64   245 /* DTP offset 32-bit.  */\n#define R_PARISC_TLS_LE21L      R_PARISC_TPREL21L\n#define R_PARISC_TLS_LE14R      R_PARISC_TPREL14R\n#define R_PARISC_TLS_IE21L      R_PARISC_LTOFF_TP21L\n#define R_PARISC_TLS_IE14R      R_PARISC_LTOFF_TP14R\n#define R_PARISC_TLS_TPREL32    R_PARISC_TPREL32\n#define R_PARISC_TLS_TPREL64    R_PARISC_TPREL64\n#define R_PARISC_HIRESERVE      255\n\n/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */\n\n#define PT_HP_TLS           (PT_LOOS + 0x0)\n#define PT_HP_CORE_NONE     (PT_LOOS + 0x1)\n#define PT_HP_CORE_VERSION  (PT_LOOS + 0x2)\n#define PT_HP_CORE_KERNEL   (PT_LOOS + 0x3)\n#define PT_HP_CORE_COMM     (PT_LOOS + 0x4)\n#define PT_HP_CORE_PROC     (PT_LOOS + 0x5)\n#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)\n#define PT_HP_CORE_STACK    (PT_LOOS + 0x7)\n#define PT_HP_CORE_SHM      (PT_LOOS + 0x8)\n#define PT_HP_CORE_MMF      (PT_LOOS + 0x9)\n#define PT_HP_PARALLEL      (PT_LOOS + 0x10)\n#define PT_HP_FASTBIND      (PT_LOOS + 0x11)\n#define PT_HP_OPT_ANNOT     (PT_LOOS + 0x12)\n#define PT_HP_HSL_ANNOT     (PT_LOOS + 0x13)\n#define PT_HP_STACK         (PT_LOOS + 0x14)\n\n#define PT_PARISC_ARCHEXT 0x70000000\n#define PT_PARISC_UNWIND  0x70000001\n\n/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */\n\n#define PF_PARISC_SBP 0x08000000\n\n#define PF_HP_PAGE_SIZE   0x00100000\n#define PF_HP_FAR_SHARED  0x00200000\n#define PF_HP_NEAR_SHARED 0x00400000\n#define PF_HP_CODE        0x01000000\n#define PF_HP_MODIFY      0x02000000\n#define PF_HP_LAZYSWAP    0x04000000\n#define PF_HP_SBP         0x08000000\n\n/* Alpha specific definitions.  */\n\n/* Legal values for e_flags field of Elf64_Ehdr.  */\n\n#define EF_ALPHA_32BIT    1 /* All addresses must be < 2GB.  */\n#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist.  */\n\n/* Legal values for sh_type field of Elf64_Shdr.  */\n\n/* These two are primerily concerned with ECOFF debugging info.  */\n#define SHT_ALPHA_DEBUG   0x70000001\n#define SHT_ALPHA_REGINFO 0x70000002\n\n/* Legal values for sh_flags field of Elf64_Shdr.  */\n\n#define SHF_ALPHA_GPREL 0x10000000\n\n/* Legal values for st_other field of Elf64_Sym.  */\n#define STO_ALPHA_NOPV       0x80 /* No PV required.  */\n#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp.  */\n\n/* Alpha relocs.  */\n\n#define R_ALPHA_NONE      0  /* No reloc */\n#define R_ALPHA_REFLONG   1  /* Direct 32 bit */\n#define R_ALPHA_REFQUAD   2  /* Direct 64 bit */\n#define R_ALPHA_GPREL32   3  /* GP relative 32 bit */\n#define R_ALPHA_LITERAL   4  /* GP relative 16 bit w/optimization */\n#define R_ALPHA_LITUSE    5  /* Optimization hint for LITERAL */\n#define R_ALPHA_GPDISP    6  /* Add displacement to GP */\n#define R_ALPHA_BRADDR    7  /* PC+4 relative 23 bit shifted */\n#define R_ALPHA_HINT      8  /* PC+4 relative 16 bit shifted */\n#define R_ALPHA_SREL16    9  /* PC relative 16 bit */\n#define R_ALPHA_SREL32    10 /* PC relative 32 bit */\n#define R_ALPHA_SREL64    11 /* PC relative 64 bit */\n#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */\n#define R_ALPHA_GPRELLOW  18 /* GP relative 32 bit, low 16 bits */\n#define R_ALPHA_GPREL16   19 /* GP relative 16 bit */\n#define R_ALPHA_COPY      24 /* Copy symbol at runtime */\n#define R_ALPHA_GLOB_DAT  25 /* Create GOT entry */\n#define R_ALPHA_JMP_SLOT  26 /* Create PLT entry */\n#define R_ALPHA_RELATIVE  27 /* Adjust by program base */\n#define R_ALPHA_TLS_GD_HI 28\n#define R_ALPHA_TLSGD     29\n#define R_ALPHA_TLS_LDM   30\n#define R_ALPHA_DTPMOD64  31\n#define R_ALPHA_GOTDTPREL 32\n#define R_ALPHA_DTPREL64  33\n#define R_ALPHA_DTPRELHI  34\n#define R_ALPHA_DTPRELLO  35\n#define R_ALPHA_DTPREL16  36\n#define R_ALPHA_GOTTPREL  37\n#define R_ALPHA_TPREL64   38\n#define R_ALPHA_TPRELHI   39\n#define R_ALPHA_TPRELLO   40\n#define R_ALPHA_TPREL16   41\n/* Keep this the last entry.  */\n#define R_ALPHA_NUM 46\n\n/* Magic values of the LITUSE relocation addend.  */\n#define LITUSE_ALPHA_ADDR    0\n#define LITUSE_ALPHA_BASE    1\n#define LITUSE_ALPHA_BYTOFF  2\n#define LITUSE_ALPHA_JSR     3\n#define LITUSE_ALPHA_TLS_GD  4\n#define LITUSE_ALPHA_TLS_LDM 5\n\n/* Legal values for d_tag of Elf64_Dyn.  */\n#define DT_ALPHA_PLTRO (DT_LOPROC + 0)\n#define DT_ALPHA_NUM   1\n\n/* PowerPC specific declarations */\n\n/* Values for Elf32/64_Ehdr.e_flags.  */\n#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */\n\n/* Cygnus local bits below */\n#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/\n#define EF_PPC_RELOCATABLE_LIB              \\\n    0x00008000 /* PowerPC -mrelocatable-lib \\\nflag */\n\n/* PowerPC relocations defined by the ABIs */\n#define R_PPC_NONE            0\n#define R_PPC_ADDR32          1 /* 32bit absolute address */\n#define R_PPC_ADDR24          2 /* 26bit address, 2 bits ignored.  */\n#define R_PPC_ADDR16          3 /* 16bit absolute address */\n#define R_PPC_ADDR16_LO       4 /* lower 16bit of absolute address */\n#define R_PPC_ADDR16_HI       5 /* high 16bit of absolute address */\n#define R_PPC_ADDR16_HA       6 /* adjusted high 16bit */\n#define R_PPC_ADDR14          7 /* 16bit address, 2 bits ignored */\n#define R_PPC_ADDR14_BRTAKEN  8\n#define R_PPC_ADDR14_BRNTAKEN 9\n#define R_PPC_REL24           10 /* PC relative 26 bit */\n#define R_PPC_REL14           11 /* PC relative 16 bit */\n#define R_PPC_REL14_BRTAKEN   12\n#define R_PPC_REL14_BRNTAKEN  13\n#define R_PPC_GOT16           14\n#define R_PPC_GOT16_LO        15\n#define R_PPC_GOT16_HI        16\n#define R_PPC_GOT16_HA        17\n#define R_PPC_PLTREL24        18\n#define R_PPC_COPY            19\n#define R_PPC_GLOB_DAT        20\n#define R_PPC_JMP_SLOT        21\n#define R_PPC_RELATIVE        22\n#define R_PPC_LOCAL24PC       23\n#define R_PPC_UADDR32         24\n#define R_PPC_UADDR16         25\n#define R_PPC_REL32           26\n#define R_PPC_PLT32           27\n#define R_PPC_PLTREL32        28\n#define R_PPC_PLT16_LO        29\n#define R_PPC_PLT16_HI        30\n#define R_PPC_PLT16_HA        31\n#define R_PPC_SDAREL16        32\n#define R_PPC_SECTOFF         33\n#define R_PPC_SECTOFF_LO      34\n#define R_PPC_SECTOFF_HI      35\n#define R_PPC_SECTOFF_HA      36\n\n/* PowerPC relocations defined for the TLS access ABI.  */\n#define R_PPC_TLS             67 /* none\t(sym+add)@tls */\n#define R_PPC_DTPMOD32        68 /* word32\t(sym+add)@dtpmod */\n#define R_PPC_TPREL16         69 /* half16*\t(sym+add)@tprel */\n#define R_PPC_TPREL16_LO      70 /* half16\t(sym+add)@tprel@l */\n#define R_PPC_TPREL16_HI      71 /* half16\t(sym+add)@tprel@h */\n#define R_PPC_TPREL16_HA      72 /* half16\t(sym+add)@tprel@ha */\n#define R_PPC_TPREL32         73 /* word32\t(sym+add)@tprel */\n#define R_PPC_DTPREL16        74 /* half16*\t(sym+add)@dtprel */\n#define R_PPC_DTPREL16_LO     75 /* half16\t(sym+add)@dtprel@l */\n#define R_PPC_DTPREL16_HI     76 /* half16\t(sym+add)@dtprel@h */\n#define R_PPC_DTPREL16_HA     77 /* half16\t(sym+add)@dtprel@ha */\n#define R_PPC_DTPREL32        78 /* word32\t(sym+add)@dtprel */\n#define R_PPC_GOT_TLSGD16     79 /* half16*\t(sym+add)@got@tlsgd */\n#define R_PPC_GOT_TLSGD16_LO  80 /* half16\t(sym+add)@got@tlsgd@l */\n#define R_PPC_GOT_TLSGD16_HI  81 /* half16\t(sym+add)@got@tlsgd@h */\n#define R_PPC_GOT_TLSGD16_HA  82 /* half16\t(sym+add)@got@tlsgd@ha */\n#define R_PPC_GOT_TLSLD16     83 /* half16*\t(sym+add)@got@tlsld */\n#define R_PPC_GOT_TLSLD16_LO  84 /* half16\t(sym+add)@got@tlsld@l */\n#define R_PPC_GOT_TLSLD16_HI  85 /* half16\t(sym+add)@got@tlsld@h */\n#define R_PPC_GOT_TLSLD16_HA  86 /* half16\t(sym+add)@got@tlsld@ha */\n#define R_PPC_GOT_TPREL16     87 /* half16*\t(sym+add)@got@tprel */\n#define R_PPC_GOT_TPREL16_LO  88 /* half16\t(sym+add)@got@tprel@l */\n#define R_PPC_GOT_TPREL16_HI  89 /* half16\t(sym+add)@got@tprel@h */\n#define R_PPC_GOT_TPREL16_HA  90 /* half16\t(sym+add)@got@tprel@ha */\n#define R_PPC_GOT_DTPREL16    91 /* half16*\t(sym+add)@got@dtprel */\n#define R_PPC_GOT_DTPREL16_LO 92 /* half16*\t(sym+add)@got@dtprel@l */\n#define R_PPC_GOT_DTPREL16_HI 93 /* half16*\t(sym+add)@got@dtprel@h */\n#define R_PPC_GOT_DTPREL16_HA 94 /* half16*\t(sym+add)@got@dtprel@ha */\n\n/* Keep this the last entry.  */\n#define R_PPC_NUM 95\n\n/* The remaining relocs are from the Embedded ELF ABI, and are not\n   in the SVR4 ELF ABI.  */\n#define R_PPC_EMB_NADDR32    101\n#define R_PPC_EMB_NADDR16    102\n#define R_PPC_EMB_NADDR16_LO 103\n#define R_PPC_EMB_NADDR16_HI 104\n#define R_PPC_EMB_NADDR16_HA 105\n#define R_PPC_EMB_SDAI16     106\n#define R_PPC_EMB_SDA2I16    107\n#define R_PPC_EMB_SDA2REL    108\n#define R_PPC_EMB_SDA21      109 /* 16 bit offset in SDA */\n#define R_PPC_EMB_MRKREF     110\n#define R_PPC_EMB_RELSEC16   111\n#define R_PPC_EMB_RELST_LO   112\n#define R_PPC_EMB_RELST_HI   113\n#define R_PPC_EMB_RELST_HA   114\n#define R_PPC_EMB_BIT_FLD    115\n#define R_PPC_EMB_RELSDA     116 /* 16 bit relative offset in SDA */\n\n/* Diab tool relocations.  */\n#define R_PPC_DIAB_SDA21_LO  180 /* like EMB_SDA21, but lower 16 bit */\n#define R_PPC_DIAB_SDA21_HI  181 /* like EMB_SDA21, but high 16 bit */\n#define R_PPC_DIAB_SDA21_HA  182 /* like EMB_SDA21, adjusted high 16 */\n#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */\n#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */\n#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */\n\n/* GNU relocs used in PIC code sequences.  */\n#define R_PPC_REL16    249 /* word32   (sym-.) */\n#define R_PPC_REL16_LO 250 /* half16   (sym-.)@l */\n#define R_PPC_REL16_HI 251 /* half16   (sym-.)@h */\n#define R_PPC_REL16_HA 252 /* half16   (sym-.)@ha */\n\n/* This is a phony reloc to handle any old fashioned TOC16 references\n   that may still be in object files.  */\n#define R_PPC_TOC16 255\n\n/* PowerPC specific values for the Dyn d_tag field.  */\n#define DT_PPC_GOT (DT_LOPROC + 0)\n#define DT_PPC_NUM 1\n\n/* PowerPC64 relocations defined by the ABIs */\n#define R_PPC64_NONE            R_PPC_NONE\n#define R_PPC64_ADDR32          R_PPC_ADDR32    /* 32bit absolute address */\n#define R_PPC64_ADDR24          R_PPC_ADDR24    /* 26bit address, word aligned */\n#define R_PPC64_ADDR16          R_PPC_ADDR16    /* 16bit absolute address */\n#define R_PPC64_ADDR16_LO       R_PPC_ADDR16_LO /* lower 16bits of address */\n#define R_PPC64_ADDR16_HI       R_PPC_ADDR16_HI /* high 16bits of address. */\n#define R_PPC64_ADDR16_HA       R_PPC_ADDR16_HA /* adjusted high 16bits.  */\n#define R_PPC64_ADDR14          R_PPC_ADDR14    /* 16bit address, word aligned */\n#define R_PPC64_ADDR14_BRTAKEN  R_PPC_ADDR14_BRTAKEN\n#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN\n#define R_PPC64_REL24           R_PPC_REL24 /* PC-rel. 26 bit, word aligned */\n#define R_PPC64_REL14           R_PPC_REL14 /* PC relative 16 bit */\n#define R_PPC64_REL14_BRTAKEN   R_PPC_REL14_BRTAKEN\n#define R_PPC64_REL14_BRNTAKEN  R_PPC_REL14_BRNTAKEN\n#define R_PPC64_GOT16           R_PPC_GOT16\n#define R_PPC64_GOT16_LO        R_PPC_GOT16_LO\n#define R_PPC64_GOT16_HI        R_PPC_GOT16_HI\n#define R_PPC64_GOT16_HA        R_PPC_GOT16_HA\n\n#define R_PPC64_COPY     R_PPC_COPY\n#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT\n#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT\n#define R_PPC64_RELATIVE R_PPC_RELATIVE\n\n#define R_PPC64_UADDR32  R_PPC_UADDR32\n#define R_PPC64_UADDR16  R_PPC_UADDR16\n#define R_PPC64_REL32    R_PPC_REL32\n#define R_PPC64_PLT32    R_PPC_PLT32\n#define R_PPC64_PLTREL32 R_PPC_PLTREL32\n#define R_PPC64_PLT16_LO R_PPC_PLT16_LO\n#define R_PPC64_PLT16_HI R_PPC_PLT16_HI\n#define R_PPC64_PLT16_HA R_PPC_PLT16_HA\n\n#define R_PPC64_SECTOFF         R_PPC_SECTOFF\n#define R_PPC64_SECTOFF_LO      R_PPC_SECTOFF_LO\n#define R_PPC64_SECTOFF_HI      R_PPC_SECTOFF_HI\n#define R_PPC64_SECTOFF_HA      R_PPC_SECTOFF_HA\n#define R_PPC64_ADDR30          37 /* word30 (S + A - P) >> 2 */\n#define R_PPC64_ADDR64          38 /* doubleword64 S + A */\n#define R_PPC64_ADDR16_HIGHER   39 /* half16 #higher(S + A) */\n#define R_PPC64_ADDR16_HIGHERA  40 /* half16 #highera(S + A) */\n#define R_PPC64_ADDR16_HIGHEST  41 /* half16 #highest(S + A) */\n#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */\n#define R_PPC64_UADDR64         43 /* doubleword64 S + A */\n#define R_PPC64_REL64           44 /* doubleword64 S + A - P */\n#define R_PPC64_PLT64           45 /* doubleword64 L + A */\n#define R_PPC64_PLTREL64        46 /* doubleword64 L + A - P */\n#define R_PPC64_TOC16           47 /* half16* S + A - .TOC */\n#define R_PPC64_TOC16_LO        48 /* half16 #lo(S + A - .TOC.) */\n#define R_PPC64_TOC16_HI        49 /* half16 #hi(S + A - .TOC.) */\n#define R_PPC64_TOC16_HA        50 /* half16 #ha(S + A - .TOC.) */\n#define R_PPC64_TOC             51 /* doubleword64 .TOC */\n#define R_PPC64_PLTGOT16        52 /* half16* M + A */\n#define R_PPC64_PLTGOT16_LO     53 /* half16 #lo(M + A) */\n#define R_PPC64_PLTGOT16_HI     54 /* half16 #hi(M + A) */\n#define R_PPC64_PLTGOT16_HA     55 /* half16 #ha(M + A) */\n\n#define R_PPC64_ADDR16_DS      56 /* half16ds* (S + A) >> 2 */\n#define R_PPC64_ADDR16_LO_DS   57 /* half16ds  #lo(S + A) >> 2 */\n#define R_PPC64_GOT16_DS       58 /* half16ds* (G + A) >> 2 */\n#define R_PPC64_GOT16_LO_DS    59 /* half16ds  #lo(G + A) >> 2 */\n#define R_PPC64_PLT16_LO_DS    60 /* half16ds  #lo(L + A) >> 2 */\n#define R_PPC64_SECTOFF_DS     61 /* half16ds* (R + A) >> 2 */\n#define R_PPC64_SECTOFF_LO_DS  62 /* half16ds  #lo(R + A) >> 2 */\n#define R_PPC64_TOC16_DS       63 /* half16ds* (S + A - .TOC.) >> 2 */\n#define R_PPC64_TOC16_LO_DS    64 /* half16ds  #lo(S + A - .TOC.) >> 2 */\n#define R_PPC64_PLTGOT16_DS    65 /* half16ds* (M + A) >> 2 */\n#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds  #lo(M + A) >> 2 */\n\n/* PowerPC64 relocations defined for the TLS access ABI.  */\n#define R_PPC64_TLS                67  /* none\t(sym+add)@tls */\n#define R_PPC64_DTPMOD64           68  /* doubleword64 (sym+add)@dtpmod */\n#define R_PPC64_TPREL16            69  /* half16*\t(sym+add)@tprel */\n#define R_PPC64_TPREL16_LO         70  /* half16\t(sym+add)@tprel@l */\n#define R_PPC64_TPREL16_HI         71  /* half16\t(sym+add)@tprel@h */\n#define R_PPC64_TPREL16_HA         72  /* half16\t(sym+add)@tprel@ha */\n#define R_PPC64_TPREL64            73  /* doubleword64 (sym+add)@tprel */\n#define R_PPC64_DTPREL16           74  /* half16*\t(sym+add)@dtprel */\n#define R_PPC64_DTPREL16_LO        75  /* half16\t(sym+add)@dtprel@l */\n#define R_PPC64_DTPREL16_HI        76  /* half16\t(sym+add)@dtprel@h */\n#define R_PPC64_DTPREL16_HA        77  /* half16\t(sym+add)@dtprel@ha */\n#define R_PPC64_DTPREL64           78  /* doubleword64 (sym+add)@dtprel */\n#define R_PPC64_GOT_TLSGD16        79  /* half16*\t(sym+add)@got@tlsgd */\n#define R_PPC64_GOT_TLSGD16_LO     80  /* half16\t(sym+add)@got@tlsgd@l */\n#define R_PPC64_GOT_TLSGD16_HI     81  /* half16\t(sym+add)@got@tlsgd@h */\n#define R_PPC64_GOT_TLSGD16_HA     82  /* half16\t(sym+add)@got@tlsgd@ha */\n#define R_PPC64_GOT_TLSLD16        83  /* half16*\t(sym+add)@got@tlsld */\n#define R_PPC64_GOT_TLSLD16_LO     84  /* half16\t(sym+add)@got@tlsld@l */\n#define R_PPC64_GOT_TLSLD16_HI     85  /* half16\t(sym+add)@got@tlsld@h */\n#define R_PPC64_GOT_TLSLD16_HA     86  /* half16\t(sym+add)@got@tlsld@ha */\n#define R_PPC64_GOT_TPREL16_DS     87  /* half16ds*\t(sym+add)@got@tprel */\n#define R_PPC64_GOT_TPREL16_LO_DS  88  /* half16ds (sym+add)@got@tprel@l */\n#define R_PPC64_GOT_TPREL16_HI     89  /* half16\t(sym+add)@got@tprel@h */\n#define R_PPC64_GOT_TPREL16_HA     90  /* half16\t(sym+add)@got@tprel@ha */\n#define R_PPC64_GOT_DTPREL16_DS    91  /* half16ds*\t(sym+add)@got@dtprel */\n#define R_PPC64_GOT_DTPREL16_LO_DS 92  /* half16ds (sym+add)@got@dtprel@l */\n#define R_PPC64_GOT_DTPREL16_HI    93  /* half16\t(sym+add)@got@dtprel@h */\n#define R_PPC64_GOT_DTPREL16_HA    94  /* half16\t(sym+add)@got@dtprel@ha */\n#define R_PPC64_TPREL16_DS         95  /* half16ds*\t(sym+add)@tprel */\n#define R_PPC64_TPREL16_LO_DS      96  /* half16ds\t(sym+add)@tprel@l */\n#define R_PPC64_TPREL16_HIGHER     97  /* half16\t(sym+add)@tprel@higher */\n#define R_PPC64_TPREL16_HIGHERA    98  /* half16\t(sym+add)@tprel@highera */\n#define R_PPC64_TPREL16_HIGHEST    99  /* half16\t(sym+add)@tprel@highest */\n#define R_PPC64_TPREL16_HIGHESTA   100 /* half16\t(sym+add)@tprel@highesta */\n#define R_PPC64_DTPREL16_DS        101 /* half16ds* (sym+add)@dtprel */\n#define R_PPC64_DTPREL16_LO_DS     102 /* half16ds\t(sym+add)@dtprel@l */\n#define R_PPC64_DTPREL16_HIGHER    103 /* half16\t(sym+add)@dtprel@higher */\n#define R_PPC64_DTPREL16_HIGHERA   104 /* half16\t(sym+add)@dtprel@highera */\n#define R_PPC64_DTPREL16_HIGHEST   105 /* half16\t(sym+add)@dtprel@highest */\n#define R_PPC64_DTPREL16_HIGHESTA  106 /* half16\t(sym+add)@dtprel@highesta */\n\n/* Keep this the last entry.  */\n#define R_PPC64_NUM 107\n\n/* PowerPC64 specific values for the Dyn d_tag field.  */\n#define DT_PPC64_GLINK (DT_LOPROC + 0)\n#define DT_PPC64_OPD   (DT_LOPROC + 1)\n#define DT_PPC64_OPDSZ (DT_LOPROC + 2)\n#define DT_PPC64_NUM   3\n\n/* ARM specific declarations */\n\n/* Processor specific flags for the ELF header e_flags field.  */\n#define EF_ARM_RELEXEC    0x01\n#define EF_ARM_HASENTRY   0x02\n#define EF_ARM_INTERWORK  0x04\n#define EF_ARM_APCS_26    0x08\n#define EF_ARM_APCS_FLOAT 0x10\n#define EF_ARM_PIC        0x20\n#define EF_ARM_ALIGN8     0x40 /* 8-bit structure alignment is in use */\n#define EF_ARM_NEW_ABI    0x80\n#define EF_ARM_OLD_ABI    0x100\n\n/* Other constants defined in the ARM ELF spec. version B-01.  */\n/* NB. These conflict with values defined above.  */\n#define EF_ARM_SYMSARESORTED    0x04\n#define EF_ARM_DYNSYMSUSESEGIDX 0x08\n#define EF_ARM_MAPSYMSFIRST     0x10\n#define EF_ARM_EABIMASK         0XFF000000\n\n#define EF_ARM_EABI_VERSION(flags) ((flags)&EF_ARM_EABIMASK)\n#define EF_ARM_EABI_UNKNOWN        0x00000000\n#define EF_ARM_EABI_VER1           0x01000000\n#define EF_ARM_EABI_VER2           0x02000000\n\n/* Additional symbol types for Thumb */\n#define STT_ARM_TFUNC 0xd\n\n/* ARM-specific values for sh_flags */\n#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */\n#define SHF_ARM_COMDEF                            \\\n    0x80000000 /* Section may be multiply defined \\\nin the input to a link step */\n\n/* ARM-specific program header flags */\n#define PF_ARM_SB                               \\\n    0x10000000 /* Segment contains the location \\\naddressed by the static base */\n\n/* Processor specific values for the Phdr p_type field.  */\n#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */\n\n/* ARM relocs.  */\n\n#define R_ARM_NONE            0 /* No reloc */\n#define R_ARM_PC24            1 /* PC relative 26 bit branch */\n#define R_ARM_ABS32           2 /* Direct 32 bit  */\n#define R_ARM_REL32           3 /* PC relative 32 bit */\n#define R_ARM_PC13            4\n#define R_ARM_ABS16           5 /* Direct 16 bit */\n#define R_ARM_ABS12           6 /* Direct 12 bit */\n#define R_ARM_THM_ABS5        7\n#define R_ARM_ABS8            8 /* Direct 8 bit */\n#define R_ARM_SBREL32         9\n#define R_ARM_THM_PC22        10\n#define R_ARM_THM_PC8         11\n#define R_ARM_AMP_VCALL9      12\n#define R_ARM_SWI24           13\n#define R_ARM_THM_SWI8        14\n#define R_ARM_XPC25           15\n#define R_ARM_THM_XPC22       16\n#define R_ARM_TLS_DTPMOD32    17 /* ID of module containing symbol */\n#define R_ARM_TLS_DTPOFF32    18 /* Offset in TLS block */\n#define R_ARM_TLS_TPOFF32     19 /* Offset in static TLS block */\n#define R_ARM_COPY            20 /* Copy symbol at runtime */\n#define R_ARM_GLOB_DAT        21 /* Create GOT entry */\n#define R_ARM_JUMP_SLOT       22 /* Create PLT entry */\n#define R_ARM_RELATIVE        23 /* Adjust by program base */\n#define R_ARM_GOTOFF          24 /* 32 bit offset to GOT */\n#define R_ARM_GOTPC           25 /* 32 bit PC relative offset to GOT */\n#define R_ARM_GOT32           26 /* 32 bit GOT entry */\n#define R_ARM_PLT32           27 /* 32 bit PLT address */\n#define R_ARM_ALU_PCREL_7_0   32\n#define R_ARM_ALU_PCREL_15_8  33\n#define R_ARM_ALU_PCREL_23_15 34\n#define R_ARM_LDR_SBREL_11_0  35\n#define R_ARM_ALU_SBREL_19_12 36\n#define R_ARM_ALU_SBREL_27_20 37\n#define R_ARM_GNU_VTENTRY     100\n#define R_ARM_GNU_VTINHERIT   101\n#define R_ARM_THM_PC11        102 /* thumb unconditional branch */\n#define R_ARM_THM_PC9         103 /* thumb conditional branch */\n#define R_ARM_TLS_GD32                      \\\n    104 /* PC-rel 32 bit for global dynamic \\\nthread local data */\n#define R_ARM_TLS_LDM32                    \\\n    105 /* PC-rel 32 bit for local dynamic \\\nthread local data */\n#define R_ARM_TLS_LDO32                  \\\n    106 /* 32 bit offset relative to TLS \\\nblock */\n#define R_ARM_TLS_IE32                    \\\n    107 /* PC-rel 32 bit for GOT entry of \\\nstatic TLS block offset */\n#define R_ARM_TLS_LE32                      \\\n    108 /* 32 bit offset relative to static \\\nTLS block */\n#define R_ARM_RXPC25    249\n#define R_ARM_RSBREL32  250\n#define R_ARM_THM_RPC22 251\n#define R_ARM_RREL32    252\n#define R_ARM_RABS22    253\n#define R_ARM_RPC24     254\n#define R_ARM_RBASE     255\n/* Keep this the last entry.  */\n#define R_ARM_NUM 256\n\n/* IA-64 specific declarations.  */\n\n/* Processor specific flags for the Ehdr e_flags field.  */\n#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */\n#define EF_IA_64_ABI64  0x00000010 /* 64-bit ABI */\n#define EF_IA_64_ARCH   0xff000000 /* arch. version mask */\n\n/* Processor specific values for the Phdr p_type field.  */\n#define PT_IA_64_ARCHEXT     (PT_LOPROC + 0) /* arch extension bits */\n#define PT_IA_64_UNWIND      (PT_LOPROC + 1) /* ia64 unwind bits */\n#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12)\n#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13)\n#define PT_IA_64_HP_STACK    (PT_LOOS + 0x14)\n\n/* Processor specific flags for the Phdr p_flags field.  */\n#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */\n\n/* Processor specific values for the Shdr sh_type field.  */\n#define SHT_IA_64_EXT    (SHT_LOPROC + 0) /* extension bits */\n#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */\n\n/* Processor specific flags for the Shdr sh_flags field.  */\n#define SHF_IA_64_SHORT   0x10000000 /* section near gp */\n#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */\n\n/* Processor specific values for the Dyn d_tag field.  */\n#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)\n#define DT_IA_64_NUM         1\n\n/* IA-64 relocations.  */\n#define R_IA64_NONE            0x00 /* none */\n#define R_IA64_IMM14           0x21 /* symbol + addend, add imm14 */\n#define R_IA64_IMM22           0x22 /* symbol + addend, add imm22 */\n#define R_IA64_IMM64           0x23 /* symbol + addend, mov imm64 */\n#define R_IA64_DIR32MSB        0x24 /* symbol + addend, data4 MSB */\n#define R_IA64_DIR32LSB        0x25 /* symbol + addend, data4 LSB */\n#define R_IA64_DIR64MSB        0x26 /* symbol + addend, data8 MSB */\n#define R_IA64_DIR64LSB        0x27 /* symbol + addend, data8 LSB */\n#define R_IA64_GPREL22         0x2a /* @gprel(sym + add), add imm22 */\n#define R_IA64_GPREL64I        0x2b /* @gprel(sym + add), mov imm64 */\n#define R_IA64_GPREL32MSB      0x2c /* @gprel(sym + add), data4 MSB */\n#define R_IA64_GPREL32LSB      0x2d /* @gprel(sym + add), data4 LSB */\n#define R_IA64_GPREL64MSB      0x2e /* @gprel(sym + add), data8 MSB */\n#define R_IA64_GPREL64LSB      0x2f /* @gprel(sym + add), data8 LSB */\n#define R_IA64_LTOFF22         0x32 /* @ltoff(sym + add), add imm22 */\n#define R_IA64_LTOFF64I        0x33 /* @ltoff(sym + add), mov imm64 */\n#define R_IA64_PLTOFF22        0x3a /* @pltoff(sym + add), add imm22 */\n#define R_IA64_PLTOFF64I       0x3b /* @pltoff(sym + add), mov imm64 */\n#define R_IA64_PLTOFF64MSB     0x3e /* @pltoff(sym + add), data8 MSB */\n#define R_IA64_PLTOFF64LSB     0x3f /* @pltoff(sym + add), data8 LSB */\n#define R_IA64_FPTR64I         0x43 /* @fptr(sym + add), mov imm64 */\n#define R_IA64_FPTR32MSB       0x44 /* @fptr(sym + add), data4 MSB */\n#define R_IA64_FPTR32LSB       0x45 /* @fptr(sym + add), data4 LSB */\n#define R_IA64_FPTR64MSB       0x46 /* @fptr(sym + add), data8 MSB */\n#define R_IA64_FPTR64LSB       0x47 /* @fptr(sym + add), data8 LSB */\n#define R_IA64_PCREL60B        0x48 /* @pcrel(sym + add), brl */\n#define R_IA64_PCREL21B        0x49 /* @pcrel(sym + add), ptb, call */\n#define R_IA64_PCREL21M        0x4a /* @pcrel(sym + add), chk.s */\n#define R_IA64_PCREL21F        0x4b /* @pcrel(sym + add), fchkf */\n#define R_IA64_PCREL32MSB      0x4c /* @pcrel(sym + add), data4 MSB */\n#define R_IA64_PCREL32LSB      0x4d /* @pcrel(sym + add), data4 LSB */\n#define R_IA64_PCREL64MSB      0x4e /* @pcrel(sym + add), data8 MSB */\n#define R_IA64_PCREL64LSB      0x4f /* @pcrel(sym + add), data8 LSB */\n#define R_IA64_LTOFF_FPTR22    0x52 /* @ltoff(@fptr(s+a)), imm22 */\n#define R_IA64_LTOFF_FPTR64I   0x53 /* @ltoff(@fptr(s+a)), imm64 */\n#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */\n#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */\n#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */\n#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */\n#define R_IA64_SEGREL32MSB     0x5c /* @segrel(sym + add), data4 MSB */\n#define R_IA64_SEGREL32LSB     0x5d /* @segrel(sym + add), data4 LSB */\n#define R_IA64_SEGREL64MSB     0x5e /* @segrel(sym + add), data8 MSB */\n#define R_IA64_SEGREL64LSB     0x5f /* @segrel(sym + add), data8 LSB */\n#define R_IA64_SECREL32MSB     0x64 /* @secrel(sym + add), data4 MSB */\n#define R_IA64_SECREL32LSB     0x65 /* @secrel(sym + add), data4 LSB */\n#define R_IA64_SECREL64MSB     0x66 /* @secrel(sym + add), data8 MSB */\n#define R_IA64_SECREL64LSB     0x67 /* @secrel(sym + add), data8 LSB */\n#define R_IA64_REL32MSB        0x6c /* data 4 + REL */\n#define R_IA64_REL32LSB        0x6d /* data 4 + REL */\n#define R_IA64_REL64MSB        0x6e /* data 8 + REL */\n#define R_IA64_REL64LSB        0x6f /* data 8 + REL */\n#define R_IA64_LTV32MSB        0x74 /* symbol + addend, data4 MSB */\n#define R_IA64_LTV32LSB        0x75 /* symbol + addend, data4 LSB */\n#define R_IA64_LTV64MSB        0x76 /* symbol + addend, data8 MSB */\n#define R_IA64_LTV64LSB        0x77 /* symbol + addend, data8 LSB */\n#define R_IA64_PCREL21BI       0x79 /* @pcrel(sym + add), 21bit inst */\n#define R_IA64_PCREL22         0x7a /* @pcrel(sym + add), 22bit inst */\n#define R_IA64_PCREL64I        0x7b /* @pcrel(sym + add), 64bit inst */\n#define R_IA64_IPLTMSB         0x80 /* dynamic reloc, imported PLT, MSB */\n#define R_IA64_IPLTLSB         0x81 /* dynamic reloc, imported PLT, LSB */\n#define R_IA64_COPY            0x84 /* copy relocation */\n#define R_IA64_SUB             0x85 /* Addend and symbol difference */\n#define R_IA64_LTOFF22X        0x86 /* LTOFF22, relaxable.  */\n#define R_IA64_LDXMOV          0x87 /* Use of LTOFF22X.  */\n#define R_IA64_TPREL14         0x91 /* @tprel(sym + add), imm14 */\n#define R_IA64_TPREL22         0x92 /* @tprel(sym + add), imm22 */\n#define R_IA64_TPREL64I        0x93 /* @tprel(sym + add), imm64 */\n#define R_IA64_TPREL64MSB      0x96 /* @tprel(sym + add), data8 MSB */\n#define R_IA64_TPREL64LSB      0x97 /* @tprel(sym + add), data8 LSB */\n#define R_IA64_LTOFF_TPREL22   0x9a /* @ltoff(@tprel(s+a)), imm2 */\n#define R_IA64_DTPMOD64MSB     0xa6 /* @dtpmod(sym + add), data8 MSB */\n#define R_IA64_DTPMOD64LSB     0xa7 /* @dtpmod(sym + add), data8 LSB */\n#define R_IA64_LTOFF_DTPMOD22  0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */\n#define R_IA64_DTPREL14        0xb1 /* @dtprel(sym + add), imm14 */\n#define R_IA64_DTPREL22        0xb2 /* @dtprel(sym + add), imm22 */\n#define R_IA64_DTPREL64I       0xb3 /* @dtprel(sym + add), imm64 */\n#define R_IA64_DTPREL32MSB     0xb4 /* @dtprel(sym + add), data4 MSB */\n#define R_IA64_DTPREL32LSB     0xb5 /* @dtprel(sym + add), data4 LSB */\n#define R_IA64_DTPREL64MSB     0xb6 /* @dtprel(sym + add), data8 MSB */\n#define R_IA64_DTPREL64LSB     0xb7 /* @dtprel(sym + add), data8 LSB */\n#define R_IA64_LTOFF_DTPREL22  0xba /* @ltoff(@dtprel(s+a)), imm22 */\n\n/* SH specific declarations */\n\n/* SH relocs.  */\n#define R_SH_NONE          0\n#define R_SH_DIR32         1\n#define R_SH_REL32         2\n#define R_SH_DIR8WPN       3\n#define R_SH_IND12W        4\n#define R_SH_DIR8WPL       5\n#define R_SH_DIR8WPZ       6\n#define R_SH_DIR8BP        7\n#define R_SH_DIR8W         8\n#define R_SH_DIR8L         9\n#define R_SH_SWITCH16      25\n#define R_SH_SWITCH32      26\n#define R_SH_USES          27\n#define R_SH_COUNT         28\n#define R_SH_ALIGN         29\n#define R_SH_CODE          30\n#define R_SH_DATA          31\n#define R_SH_LABEL         32\n#define R_SH_SWITCH8       33\n#define R_SH_GNU_VTINHERIT 34\n#define R_SH_GNU_VTENTRY   35\n#define R_SH_TLS_GD_32     144\n#define R_SH_TLS_LD_32     145\n#define R_SH_TLS_LDO_32    146\n#define R_SH_TLS_IE_32     147\n#define R_SH_TLS_LE_32     148\n#define R_SH_TLS_DTPMOD32  149\n#define R_SH_TLS_DTPOFF32  150\n#define R_SH_TLS_TPOFF32   151\n#define R_SH_GOT32         160\n#define R_SH_PLT32         161\n#define R_SH_COPY          162\n#define R_SH_GLOB_DAT      163\n#define R_SH_JMP_SLOT      164\n#define R_SH_RELATIVE      165\n#define R_SH_GOTOFF        166\n#define R_SH_GOTPC         167\n/* Keep this the last entry.  */\n#define R_SH_NUM 256\n\n/* Additional s390 relocs */\n\n#define R_390_NONE      0  /* No reloc.  */\n#define R_390_8         1  /* Direct 8 bit.  */\n#define R_390_12        2  /* Direct 12 bit.  */\n#define R_390_16        3  /* Direct 16 bit.  */\n#define R_390_32        4  /* Direct 32 bit.  */\n#define R_390_PC32      5  /* PC relative 32 bit.\t*/\n#define R_390_GOT12     6  /* 12 bit GOT offset.  */\n#define R_390_GOT32     7  /* 32 bit GOT offset.  */\n#define R_390_PLT32     8  /* 32 bit PC relative PLT address.  */\n#define R_390_COPY      9  /* Copy symbol at runtime.  */\n#define R_390_GLOB_DAT  10 /* Create GOT entry.  */\n#define R_390_JMP_SLOT  11 /* Create PLT entry.  */\n#define R_390_RELATIVE  12 /* Adjust by program base.  */\n#define R_390_GOTOFF32  13 /* 32 bit offset to GOT.\t */\n#define R_390_GOTPC     14 /* 32 bit PC relative offset to GOT.  */\n#define R_390_GOT16     15 /* 16 bit GOT offset.  */\n#define R_390_PC16      16 /* PC relative 16 bit.\t*/\n#define R_390_PC16DBL   17 /* PC relative 16 bit shifted by 1.  */\n#define R_390_PLT16DBL  18 /* 16 bit PC rel. PLT shifted by 1.  */\n#define R_390_PC32DBL   19 /* PC relative 32 bit shifted by 1.  */\n#define R_390_PLT32DBL  20 /* 32 bit PC rel. PLT shifted by 1.  */\n#define R_390_GOTPCDBL  21 /* 32 bit PC rel. GOT shifted by 1.  */\n#define R_390_64        22 /* Direct 64 bit.  */\n#define R_390_PC64      23 /* PC relative 64 bit.\t*/\n#define R_390_GOT64     24 /* 64 bit GOT offset.  */\n#define R_390_PLT64     25 /* 64 bit PC relative PLT address.  */\n#define R_390_GOTENT    26 /* 32 bit PC rel. to GOT entry >> 1. */\n#define R_390_GOTOFF16  27 /* 16 bit offset to GOT. */\n#define R_390_GOTOFF64  28 /* 64 bit offset to GOT. */\n#define R_390_GOTPLT12  29 /* 12 bit offset to jump slot.\t*/\n#define R_390_GOTPLT16  30 /* 16 bit offset to jump slot.\t*/\n#define R_390_GOTPLT32  31 /* 32 bit offset to jump slot.\t*/\n#define R_390_GOTPLT64  32 /* 64 bit offset to jump slot.\t*/\n#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot.  */\n#define R_390_PLTOFF16  34 /* 16 bit offset from GOT to PLT. */\n#define R_390_PLTOFF32  35 /* 32 bit offset from GOT to PLT. */\n#define R_390_PLTOFF64  36 /* 16 bit offset from GOT to PLT. */\n#define R_390_TLS_LOAD  37 /* Tag for load insn in TLS code.  */\n#define R_390_TLS_GDCALL                   \\\n    38 /* Tag for function call in general \\\ndynamic TLS code. */\n#define R_390_TLS_LDCALL                 \\\n    39 /* Tag for function call in local \\\ndynamic TLS code. */\n#define R_390_TLS_GD32                      \\\n    40 /* Direct 32 bit for general dynamic \\\nthread local data.  */\n#define R_390_TLS_GD64                      \\\n    41 /* Direct 64 bit for general dynamic \\\nthread local data.  */\n#define R_390_TLS_GOTIE12                  \\\n    42 /* 12 bit GOT offset for static TLS \\\nblock offset.  */\n#define R_390_TLS_GOTIE32                  \\\n    43 /* 32 bit GOT offset for static TLS \\\nblock offset.  */\n#define R_390_TLS_GOTIE64                  \\\n    44 /* 64 bit GOT offset for static TLS \\\nblock offset. */\n#define R_390_TLS_LDM32                   \\\n    45 /* Direct 32 bit for local dynamic \\\nthread local data in LE code.  */\n#define R_390_TLS_LDM64                   \\\n    46 /* Direct 64 bit for local dynamic \\\nthread local data in LE code.  */\n#define R_390_TLS_IE32                    \\\n    47 /* 32 bit address of GOT entry for \\\nnegated static TLS block offset.  */\n#define R_390_TLS_IE64                    \\\n    48 /* 64 bit address of GOT entry for \\\nnegated static TLS block offset.  */\n#define R_390_TLS_IEENT                       \\\n    49 /* 32 bit rel. offset to GOT entry for \\\nnegated static TLS block offset.  */\n#define R_390_TLS_LE32                      \\\n    50 /* 32 bit negated offset relative to \\\nstatic TLS block.  */\n#define R_390_TLS_LE64                      \\\n    51 /* 64 bit negated offset relative to \\\nstatic TLS block.  */\n#define R_390_TLS_LDO32                 \\\n    52 /* 32 bit offset relative to TLS \\\nblock.  */\n#define R_390_TLS_LDO64                                      \\\n    53                      /* 64 bit offset relative to TLS \\\n                   block.  */\n#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol.  */\n#define R_390_TLS_DTPOFF 55 /* Offset in TLS block.\t */\n#define R_390_TLS_TPOFF                                   \\\n    56                    /* Negated offset in static TLS \\\n                 block.  */\n#define R_390_20       57 /* Direct 20 bit.  */\n#define R_390_GOT20    58 /* 20 bit GOT offset.  */\n#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot.  */\n#define R_390_TLS_GOTIE20                  \\\n    60 /* 20 bit GOT offset for static TLS \\\nblock offset.  */\n/* Keep this the last entry.  */\n#define R_390_NUM 61\n\n/* CRIS relocations.  */\n#define R_CRIS_NONE          0\n#define R_CRIS_8             1\n#define R_CRIS_16            2\n#define R_CRIS_32            3\n#define R_CRIS_8_PCREL       4\n#define R_CRIS_16_PCREL      5\n#define R_CRIS_32_PCREL      6\n#define R_CRIS_GNU_VTINHERIT 7\n#define R_CRIS_GNU_VTENTRY   8\n#define R_CRIS_COPY          9\n#define R_CRIS_GLOB_DAT      10\n#define R_CRIS_JUMP_SLOT     11\n#define R_CRIS_RELATIVE      12\n#define R_CRIS_16_GOT        13\n#define R_CRIS_32_GOT        14\n#define R_CRIS_16_GOTPLT     15\n#define R_CRIS_32_GOTPLT     16\n#define R_CRIS_32_GOTREL     17\n#define R_CRIS_32_PLT_GOTREL 18\n#define R_CRIS_32_PLT_PCREL  19\n\n#define R_CRIS_NUM 20\n\n/* AMD x86-64 relocations.  */\n#define R_X86_64_NONE      0 /* No reloc */\n#define R_X86_64_64        1 /* Direct 64 bit  */\n#define R_X86_64_PC32      2 /* PC relative 32 bit signed */\n#define R_X86_64_GOT32     3 /* 32 bit GOT entry */\n#define R_X86_64_PLT32     4 /* 32 bit PLT address */\n#define R_X86_64_COPY      5 /* Copy symbol at runtime */\n#define R_X86_64_GLOB_DAT  6 /* Create GOT entry */\n#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */\n#define R_X86_64_RELATIVE  8 /* Adjust by program base */\n#define R_X86_64_GOTPCREL                                 \\\n    9                        /* 32 bit signed PC relative \\\n                    offset to GOT */\n#define R_X86_64_32       10 /* Direct 32 bit zero extended */\n#define R_X86_64_32S      11 /* Direct 32 bit sign extended */\n#define R_X86_64_16       12 /* Direct 16 bit zero extended */\n#define R_X86_64_PC16     13 /* 16 bit sign extended pc relative */\n#define R_X86_64_8        14 /* Direct 8 bit sign extended  */\n#define R_X86_64_PC8      15 /* 8 bit sign extended pc relative */\n#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */\n#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */\n#define R_X86_64_TPOFF64  18 /* Offset in initial TLS block */\n#define R_X86_64_TLSGD                     \\\n    19 /* 32 bit signed PC relative offset \\\nto two GOT entries for GD symbol */\n#define R_X86_64_TLSLD                                           \\\n    20                       /* 32 bit signed PC relative offset \\\n                    to two GOT entries for LD symbol */\n#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */\n#define R_X86_64_GOTTPOFF                                        \\\n    22                       /* 32 bit signed PC relative offset \\\n                    to GOT entry for IE symbol */\n#define R_X86_64_TPOFF32  23 /* Offset in initial TLS block */\n#define R_X86_64_PC64     24 /* PC relative 64 bit */\n#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */\n#define R_X86_64_GOTPC32            \\\n    26 /* 32 bit signed pc relative \\\noffset to GOT */\n/* 27 .. 33 */\n#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor.  */\n#define R_X86_64_TLSDESC_CALL                              \\\n    35                      /* Marker for call through TLS \\\n               descriptor.  */\n#define R_X86_64_TLSDESC 36 /* TLS descriptor.  */\n\n#define R_X86_64_NUM 37\n\n/* AM33 relocations.  */\n#define R_MN10300_NONE          0  /* No reloc.  */\n#define R_MN10300_32            1  /* Direct 32 bit.  */\n#define R_MN10300_16            2  /* Direct 16 bit.  */\n#define R_MN10300_8             3  /* Direct 8 bit.  */\n#define R_MN10300_PCREL32       4  /* PC-relative 32-bit.  */\n#define R_MN10300_PCREL16       5  /* PC-relative 16-bit signed.  */\n#define R_MN10300_PCREL8        6  /* PC-relative 8-bit signed.  */\n#define R_MN10300_GNU_VTINHERIT 7  /* Ancient C++ vtable garbage... */\n#define R_MN10300_GNU_VTENTRY   8  /* ... collection annotation.  */\n#define R_MN10300_24            9  /* Direct 24 bit.  */\n#define R_MN10300_GOTPC32       10 /* 32-bit PCrel offset to GOT.  */\n#define R_MN10300_GOTPC16       11 /* 16-bit PCrel offset to GOT.  */\n#define R_MN10300_GOTOFF32      12 /* 32-bit offset from GOT.  */\n#define R_MN10300_GOTOFF24      13 /* 24-bit offset from GOT.  */\n#define R_MN10300_GOTOFF16      14 /* 16-bit offset from GOT.  */\n#define R_MN10300_PLT32         15 /* 32-bit PCrel to PLT entry.  */\n#define R_MN10300_PLT16         16 /* 16-bit PCrel to PLT entry.  */\n#define R_MN10300_GOT32         17 /* 32-bit offset to GOT entry.  */\n#define R_MN10300_GOT24         18 /* 24-bit offset to GOT entry.  */\n#define R_MN10300_GOT16         19 /* 16-bit offset to GOT entry.  */\n#define R_MN10300_COPY          20 /* Copy symbol at runtime.  */\n#define R_MN10300_GLOB_DAT      21 /* Create GOT entry.  */\n#define R_MN10300_JMP_SLOT      22 /* Create PLT entry.  */\n#define R_MN10300_RELATIVE      23 /* Adjust by program base.  */\n\n#define R_MN10300_NUM 24\n\n/* M32R relocs.  */\n#define R_M32R_NONE          0  /* No reloc. */\n#define R_M32R_16            1  /* Direct 16 bit. */\n#define R_M32R_32            2  /* Direct 32 bit. */\n#define R_M32R_24            3  /* Direct 24 bit. */\n#define R_M32R_10_PCREL      4  /* PC relative 10 bit shifted. */\n#define R_M32R_18_PCREL      5  /* PC relative 18 bit shifted. */\n#define R_M32R_26_PCREL      6  /* PC relative 26 bit shifted. */\n#define R_M32R_HI16_ULO      7  /* High 16 bit with unsigned low. */\n#define R_M32R_HI16_SLO      8  /* High 16 bit with signed low. */\n#define R_M32R_LO16          9  /* Low 16 bit. */\n#define R_M32R_SDA16         10 /* 16 bit offset in SDA. */\n#define R_M32R_GNU_VTINHERIT 11\n#define R_M32R_GNU_VTENTRY   12\n/* M32R relocs use SHT_RELA.  */\n#define R_M32R_16_RELA            33 /* Direct 16 bit. */\n#define R_M32R_32_RELA            34 /* Direct 32 bit. */\n#define R_M32R_24_RELA            35 /* Direct 24 bit. */\n#define R_M32R_10_PCREL_RELA      36 /* PC relative 10 bit shifted. */\n#define R_M32R_18_PCREL_RELA      37 /* PC relative 18 bit shifted. */\n#define R_M32R_26_PCREL_RELA      38 /* PC relative 26 bit shifted. */\n#define R_M32R_HI16_ULO_RELA      39 /* High 16 bit with unsigned low */\n#define R_M32R_HI16_SLO_RELA      40 /* High 16 bit with signed low */\n#define R_M32R_LO16_RELA          41 /* Low 16 bit */\n#define R_M32R_SDA16_RELA         42 /* 16 bit offset in SDA */\n#define R_M32R_RELA_GNU_VTINHERIT 43\n#define R_M32R_RELA_GNU_VTENTRY   44\n#define R_M32R_REL32              45 /* PC relative 32 bit.  */\n\n#define R_M32R_GOT24     48 /* 24 bit GOT entry */\n#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */\n#define R_M32R_COPY      50 /* Copy symbol at runtime */\n#define R_M32R_GLOB_DAT  51 /* Create GOT entry */\n#define R_M32R_JMP_SLOT  52 /* Create PLT entry */\n#define R_M32R_RELATIVE  53 /* Adjust by program base */\n#define R_M32R_GOTOFF    54 /* 24 bit offset to GOT */\n#define R_M32R_GOTPC24   55 /* 24 bit PC relative offset to GOT */\n#define R_M32R_GOT16_HI_ULO                   \\\n    56 /* High 16 bit GOT entry with unsigned \\\nlow */\n#define R_M32R_GOT16_HI_SLO                                     \\\n    57                     /* High 16 bit GOT entry with signed \\\n                  low */\n#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */\n#define R_M32R_GOTPC_HI_ULO                 \\\n    59 /* High 16 bit PC relative offset to \\\nGOT with unsigned low */\n#define R_M32R_GOTPC_HI_SLO                 \\\n    60 /* High 16 bit PC relative offset to \\\nGOT with signed low */\n#define R_M32R_GOTPC_LO                    \\\n    61 /* Low 16 bit PC relative offset to \\\nGOT */\n#define R_M32R_GOTOFF_HI_ULO        \\\n    62 /* High 16 bit offset to GOT \\\nwith unsigned low */\n#define R_M32R_GOTOFF_HI_SLO                              \\\n    63                       /* High 16 bit offset to GOT \\\n                with signed low */\n#define R_M32R_GOTOFF_LO 64  /* Low 16 bit offset to GOT */\n#define R_M32R_NUM       256 /* Keep this the last entry. */\n\n#endif /* elf.h */\n"
  },
  {
    "path": "buildutils/patchelf/patchelf.cpp",
    "content": "#include <string>\n#include <vector>\n#include <set>\n#include <map>\n#include <algorithm>\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <assert.h>\n#include <string.h>\n#include <errno.h>\n\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include <fcntl.h>\n#include <limits.h>\n\n#include \"elf.h\"\n\nusing namespace std;\n\n#ifdef MIPSEL\n/* The lemote fuloong 2f kernel defconfig sets a page size of 16KB */\nconst unsigned int pageSize = 4096 * 4;\n#else\nconst unsigned int pageSize = 4096;\n#endif\n\nstatic bool debugMode = false;\n\nstatic bool forceRPath = false;\n\nstatic string fileName;\n\noff_t          fileSize, maxSize;\nunsigned char *contents = 0;\n\n#define ElfFileParams     class Elf_Ehdr, class Elf_Phdr, class Elf_Shdr, class Elf_Addr, class Elf_Off, class Elf_Dyn, class Elf_Sym\n#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym\n\ntemplate<ElfFileParams> class ElfFile {\n    Elf_Ehdr *       hdr;\n    vector<Elf_Phdr> phdrs;\n    vector<Elf_Shdr> shdrs;\n\n    bool littleEndian;\n\n    bool changed;\n\n    bool isExecutable;\n\n    typedef string                   SectionName;\n    typedef map<SectionName, string> ReplacedSections;\n\n    ReplacedSections replacedSections;\n\n    string sectionNames; /* content of the .shstrtab section */\n\n    /* Align on 4 or 8 bytes boundaries on 32- or 64-bit platforms\n       respectively. */\n    unsigned int sectionAlignment;\n\n    vector<SectionName> sectionsByOldIndex;\n\npublic:\n    ElfFile()\n    {\n        changed = false;\n        sectionAlignment = sizeof(Elf_Off);\n    }\n\n    bool isChanged() { return changed; }\n\n    void parse();\n\nprivate:\n    struct CompPhdr {\n        ElfFile *elfFile;\n        bool     operator()(const Elf_Phdr &x, const Elf_Phdr &y)\n        {\n            if (x.p_type == PT_PHDR) return true;\n            if (y.p_type == PT_PHDR) return false;\n            return elfFile->rdi(x.p_paddr) < elfFile->rdi(y.p_paddr);\n        }\n    };\n\n    friend struct CompPhdr;\n\n    void sortPhdrs();\n\n    struct CompShdr {\n        ElfFile *elfFile;\n        bool     operator()(const Elf_Shdr &x, const Elf_Shdr &y) { return elfFile->rdi(x.sh_offset) < elfFile->rdi(y.sh_offset); }\n    };\n\n    friend struct CompShdr;\n\n    void sortShdrs();\n\n    void shiftFile(unsigned int extraPages, Elf_Addr startPage);\n\n    string getSectionName(const Elf_Shdr &shdr);\n\n    Elf_Shdr &findSection(const SectionName &sectionName);\n\n    Elf_Shdr *findSection2(const SectionName &sectionName);\n\n    unsigned int findSection3(const SectionName &sectionName);\n\n    string &replaceSection(const SectionName &sectionName, unsigned int size);\n\n    void writeReplacedSections(Elf_Off &curOff, Elf_Addr startAddr, Elf_Off startOffset);\n\n    void rewriteHeaders(Elf_Addr phdrAddress);\n\n    void rewriteSectionsLibrary();\n\n    void rewriteSectionsExecutable();\n\npublic:\n    void rewriteSections();\n\n    string getInterpreter();\n\n    void setInterpreter(const string &newInterpreter);\n\n    typedef enum { rpPrint, rpShrink, rpSet } RPathOp;\n\n    void modifyRPath(RPathOp op, string newRPath);\n\n    void removeNeeded(set<string> libs);\n\nprivate:\n    /* Convert an integer in big or little endian representation (as\n       specified by the ELF header) to this platform's integer\n       representation. */\n    template<class I> I rdi(I i);\n\n    /* Convert back to the ELF representation. */\n    template<class I> I wri(I &t, unsigned long long i)\n    {\n        t = rdi((I)i);\n        return i;\n    }\n};\n\n/* !!! G++ creates broken code if this function is inlined, don't know\n   why... */\ntemplate<ElfFileParams> template<class I> I ElfFile<ElfFileParamNames>::rdi(I i)\n{\n    I r = 0;\n    if (littleEndian) {\n        for (unsigned int n = 0; n < sizeof(I); ++n) { r |= ((I) * (((unsigned char *)&i) + n)) << (n * 8); }\n    } else {\n        for (unsigned int n = 0; n < sizeof(I); ++n) { r |= ((I) * (((unsigned char *)&i) + n)) << ((sizeof(I) - n - 1) * 8); }\n    }\n    return r;\n}\n\n/* Ugly: used to erase DT_RUNPATH when using --force-rpath. */\n#define DT_IGNORE 0x00726e67\n\nstatic void debug(const char *format, ...)\n{\n    if (debugMode) {\n        va_list ap;\n        va_start(ap, format);\n        vfprintf(stderr, format, ap);\n        va_end(ap);\n    }\n}\n\nstatic void error(string msg)\n{\n    if (errno)\n        perror(msg.c_str());\n    else\n        fprintf(stderr, \"%s\\n\", msg.c_str());\n    exit(1);\n}\n\nstatic void growFile(off_t newSize)\n{\n    if (newSize > maxSize) error(\"maximum file size exceeded\");\n    if (newSize <= fileSize) return;\n    if (newSize > fileSize) memset(contents + fileSize, 0, newSize - fileSize);\n    fileSize = newSize;\n}\n\nstatic void readFile(string fileName, mode_t *fileMode)\n{\n    struct stat st;\n    if (stat(fileName.c_str(), &st) != 0) error(\"stat\");\n    fileSize = st.st_size;\n    *fileMode = st.st_mode;\n    maxSize = fileSize + 8 * 1024 * 1024;\n\n    contents = (unsigned char *)malloc(fileSize + maxSize);\n    if (!contents) abort();\n\n    int fd = open(fileName.c_str(), O_RDONLY);\n    if (fd == -1) error(\"open\");\n\n    if (read(fd, contents, fileSize) != fileSize) error(\"read\");\n\n    close(fd);\n}\n\nstatic void checkPointer(void *p, unsigned int size)\n{\n    unsigned char *q = (unsigned char *)p;\n    assert(q >= contents && q + size <= contents + fileSize);\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::parse()\n{\n    isExecutable = false;\n\n    /* Check the ELF header for basic validity. */\n    if (fileSize < (off_t)sizeof(Elf_Ehdr)) error(\"missing ELF header\");\n\n    hdr = (Elf_Ehdr *)contents;\n\n    if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) error(\"not an ELF executable\");\n\n    littleEndian = contents[EI_DATA] == ELFDATA2LSB;\n\n    if (rdi(hdr->e_type) != ET_EXEC && rdi(hdr->e_type) != ET_DYN) error(\"wrong ELF type\");\n\n    if ((off_t)(rdi(hdr->e_phoff) + rdi(hdr->e_phnum) * rdi(hdr->e_phentsize)) > fileSize) error(\"missing program headers\");\n\n    if ((off_t)(rdi(hdr->e_shoff) + rdi(hdr->e_shnum) * rdi(hdr->e_shentsize)) > fileSize) error(\"missing section headers\");\n\n    if (rdi(hdr->e_phentsize) != sizeof(Elf_Phdr)) error(\"program headers have wrong size\");\n\n    /* Copy the program and section headers. */\n    for (int i = 0; i < rdi(hdr->e_phnum); ++i) {\n        phdrs.push_back(*((Elf_Phdr *)(contents + rdi(hdr->e_phoff)) + i));\n        if (rdi(phdrs[i].p_type) == PT_INTERP) isExecutable = true;\n    }\n\n    for (int i = 0; i < rdi(hdr->e_shnum); ++i) shdrs.push_back(*((Elf_Shdr *)(contents + rdi(hdr->e_shoff)) + i));\n\n    /* Get the section header string table section (\".shstrtab\").  Its\n       index in the section header table is given by e_shstrndx field\n       of the ELF header. */\n    unsigned int shstrtabIndex = rdi(hdr->e_shstrndx);\n    assert(shstrtabIndex < shdrs.size());\n    unsigned int shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);\n    char *       shstrtab = (char *)contents + rdi(shdrs[shstrtabIndex].sh_offset);\n    checkPointer(shstrtab, shstrtabSize);\n\n    assert(shstrtabSize > 0);\n    assert(shstrtab[shstrtabSize - 1] == 0);\n\n    sectionNames = string(shstrtab, shstrtabSize);\n\n    sectionsByOldIndex.resize(hdr->e_shnum);\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) sectionsByOldIndex[i] = getSectionName(shdrs[i]);\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::sortPhdrs()\n{\n    /* Sort the segments by offset. */\n    CompPhdr comp;\n    comp.elfFile = this;\n    sort(phdrs.begin(), phdrs.end(), comp);\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::sortShdrs()\n{\n    /* Translate sh_link mappings to section names, since sorting the\n       sections will invalidate the sh_link fields. */\n    map<SectionName, SectionName> linkage;\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)\n        if (rdi(shdrs[i].sh_link) != 0) linkage[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_link)]);\n\n    /* Idem for sh_info on certain sections. */\n    map<SectionName, SectionName> info;\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)\n        if (rdi(shdrs[i].sh_info) != 0 && (rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA)) info[getSectionName(shdrs[i])] = getSectionName(shdrs[rdi(shdrs[i].sh_info)]);\n\n    /* Idem for the index of the .shstrtab section in the ELF header. */\n    SectionName shstrtabName = getSectionName(shdrs[rdi(hdr->e_shstrndx)]);\n\n    /* Sort the sections by offset. */\n    CompShdr comp;\n    comp.elfFile = this;\n    sort(shdrs.begin(), shdrs.end(), comp);\n\n    /* Restore the sh_link mappings. */\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)\n        if (rdi(shdrs[i].sh_link) != 0) wri(shdrs[i].sh_link, findSection3(linkage[getSectionName(shdrs[i])]));\n\n    /* And the st_info mappings. */\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)\n        if (rdi(shdrs[i].sh_info) != 0 && (rdi(shdrs[i].sh_type) == SHT_REL || rdi(shdrs[i].sh_type) == SHT_RELA)) wri(shdrs[i].sh_info, findSection3(info[getSectionName(shdrs[i])]));\n\n    /* And the .shstrtab index. */\n    wri(hdr->e_shstrndx, findSection3(shstrtabName));\n}\n\nstatic void writeFile(string fileName, mode_t fileMode)\n{\n    string fileName2 = fileName + \"_patchelf_tmp\";\n\n    int fd = open(fileName2.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0700);\n    if (fd == -1) error(\"open\");\n\n    if (write(fd, contents, fileSize) != fileSize) error(\"write\");\n\n    if (close(fd) != 0) error(\"close\");\n\n    if (chmod(fileName2.c_str(), fileMode) != 0) error(\"chmod\");\n\n    if (rename(fileName2.c_str(), fileName.c_str()) != 0) error(\"rename\");\n}\n\nstatic unsigned int roundUp(unsigned int n, unsigned int m) { return ((n - 1) / m + 1) * m; }\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, Elf_Addr startPage)\n{\n    /* Move the entire contents of the file `extraPages' pages\n       further. */\n    unsigned int oldSize = fileSize;\n    unsigned int shift = extraPages * pageSize;\n    growFile(fileSize + extraPages * pageSize);\n    memmove(contents + extraPages * pageSize, contents, oldSize);\n    memset(contents + sizeof(Elf_Ehdr), 0, shift - sizeof(Elf_Ehdr));\n\n    /* Adjust the ELF header. */\n    wri(hdr->e_phoff, sizeof(Elf_Ehdr));\n    wri(hdr->e_shoff, rdi(hdr->e_shoff) + shift);\n\n    /* Update the offsets in the section headers. */\n    for (int i = 1; i < rdi(hdr->e_shnum); ++i) wri(shdrs[i].sh_offset, rdi(shdrs[i].sh_offset) + shift);\n\n    /* Update the offsets in the program headers. */\n    for (int i = 0; i < rdi(hdr->e_phnum); ++i) {\n        wri(phdrs[i].p_offset, rdi(phdrs[i].p_offset) + shift);\n        if (rdi(phdrs[i].p_align) != 0 && (rdi(phdrs[i].p_vaddr) - rdi(phdrs[i].p_offset)) % rdi(phdrs[i].p_align) != 0) {\n            debug(\"changing alignment of program header %d from %d to %d\\n\", i, rdi(phdrs[i].p_align), pageSize);\n            wri(phdrs[i].p_align, pageSize);\n        }\n    }\n\n    /* Add a segment that maps the new program/section headers and\n       PT_INTERP segment into memory.  Otherwise glibc will choke. */\n    phdrs.resize(rdi(hdr->e_phnum) + 1);\n    wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1);\n    Elf_Phdr &phdr = phdrs[rdi(hdr->e_phnum) - 1];\n    wri(phdr.p_type, PT_LOAD);\n    wri(phdr.p_offset, 0);\n    wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));\n    wri(phdr.p_filesz, wri(phdr.p_memsz, shift));\n    wri(phdr.p_flags, PF_R | PF_W);\n    wri(phdr.p_align, pageSize);\n}\n\ntemplate<ElfFileParams> string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr &shdr) { return string(sectionNames.c_str() + rdi(shdr.sh_name)); }\n\ntemplate<ElfFileParams> Elf_Shdr &ElfFile<ElfFileParamNames>::findSection(const SectionName &sectionName)\n{\n    Elf_Shdr *shdr = findSection2(sectionName);\n    if (!shdr) error(\"cannot find section \" + sectionName);\n    return *shdr;\n}\n\ntemplate<ElfFileParams> Elf_Shdr *ElfFile<ElfFileParamNames>::findSection2(const SectionName &sectionName)\n{\n    unsigned int i = findSection3(sectionName);\n    return i ? &shdrs[i] : 0;\n}\n\ntemplate<ElfFileParams> unsigned int ElfFile<ElfFileParamNames>::findSection3(const SectionName &sectionName)\n{\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)\n        if (getSectionName(shdrs[i]) == sectionName) return i;\n    return 0;\n}\n\ntemplate<ElfFileParams> string &ElfFile<ElfFileParamNames>::replaceSection(const SectionName &sectionName, unsigned int size)\n{\n    ReplacedSections::iterator i = replacedSections.find(sectionName);\n    string                     s;\n\n    if (i != replacedSections.end()) {\n        s = string(i->second);\n    } else {\n        Elf_Shdr &shdr = findSection(sectionName);\n        s = string((char *)contents + rdi(shdr.sh_offset), rdi(shdr.sh_size));\n    }\n\n    s.resize(size);\n    replacedSections[sectionName] = s;\n\n    return replacedSections[sectionName];\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off &curOff, Elf_Addr startAddr, Elf_Off startOffset)\n{\n    /* Overwrite the old section contents with 'X's.  Do this\n       *before* writing the new section contents (below) to prevent\n       clobbering previously written new section contents. */\n    for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) {\n        string    sectionName = i->first;\n        Elf_Shdr &shdr = findSection(sectionName);\n        memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));\n    }\n\n    for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) {\n        string    sectionName = i->first;\n        Elf_Shdr &shdr = findSection(sectionName);\n        debug(\"rewriting section `%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\\n\", sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i->second.size());\n\n        memcpy(contents + curOff, (unsigned char *)i->second.c_str(), i->second.size());\n\n        /* Update the section header for this section. */\n        wri(shdr.sh_offset, curOff);\n        wri(shdr.sh_addr, startAddr + (curOff - startOffset));\n        wri(shdr.sh_size, i->second.size());\n        wri(shdr.sh_addralign, sectionAlignment);\n\n        /* If this is the .interp section, then the PT_INTERP segment\n           must be sync'ed with it. */\n        if (sectionName == \".interp\") {\n            for (unsigned int j = 0; j < phdrs.size(); ++j)\n                if (rdi(phdrs[j].p_type) == PT_INTERP) {\n                    phdrs[j].p_offset = shdr.sh_offset;\n                    phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr;\n                    phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size;\n                }\n        }\n\n        /* If this is the .dynamic section, then the PT_DYNAMIC segment\n           must be sync'ed with it. */\n        if (sectionName == \".dynamic\") {\n            for (unsigned int j = 0; j < phdrs.size(); ++j)\n                if (rdi(phdrs[j].p_type) == PT_DYNAMIC) {\n                    phdrs[j].p_offset = shdr.sh_offset;\n                    phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr;\n                    phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size;\n                }\n        }\n\n        curOff += roundUp(i->second.size(), sectionAlignment);\n    }\n\n    replacedSections.clear();\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()\n{\n    /* For dynamic libraries, we just place the replacement sections\n       at the end of the file.  They're mapped into memory by a\n       PT_LOAD segment located directly after the last virtual address\n       page of other segments. */\n    Elf_Addr startPage = 0;\n    for (unsigned int i = 0; i < phdrs.size(); ++i) {\n        Elf_Addr thisPage = roundUp(rdi(phdrs[i].p_vaddr) + rdi(phdrs[i].p_memsz), pageSize);\n        if (thisPage > startPage) startPage = thisPage;\n    }\n\n    debug(\"last page is 0x%llx\\n\", (unsigned long long)startPage);\n\n    /* Compute the total space needed for the replaced sections and\n       the program headers. */\n    off_t neededSpace = (phdrs.size() + 1) * sizeof(Elf_Phdr);\n    for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) neededSpace += roundUp(i->second.size(), sectionAlignment);\n    debug(\"needed space is %d\\n\", neededSpace);\n\n    size_t startOffset = roundUp(fileSize, pageSize);\n\n    growFile(startOffset + neededSpace);\n\n    /* Even though this file is of type ET_DYN, it could actually be\n       an executable.  For instance, Gold produces executables marked\n       ET_DYN.  In that case we can still hit the kernel bug that\n       necessitated rewriteSectionsExecutable().  However, such\n       executables also tend to start at virtual address 0, so\n       rewriteSectionsExecutable() won't work because it doesn't have\n       any virtual address space to grow downwards into.  As a\n       workaround, make sure that the virtual address of our new\n       PT_LOAD segment relative to the first PT_LOAD segment is equal\n       to its offset; otherwise we hit the kernel bug.  This may\n       require creating a hole in the executable.  The bigger the size\n       of the uninitialised data segment, the bigger the hole. */\n    if (isExecutable) {\n        if (startOffset >= startPage) {\n            debug(\"shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\\n\", startOffset - startPage);\n        } else {\n            size_t hole = startPage - startOffset;\n            /* Print a warning, because the hole could be very big. */\n            fprintf(stderr, \"warning: working around a Linux kernel bug by creating a hole of %zu bytes in ‘%s’\\n\", hole, fileName.c_str());\n            assert(hole % pageSize == 0);\n            /* !!! We could create an actual hole in the file here,\n               but it's probably not worth the effort. */\n            growFile(fileSize + hole);\n            startOffset += hole;\n        }\n        startPage = startOffset;\n    }\n\n    /* Add a segment that maps the replaced sections and program\n       headers into memory. */\n    phdrs.resize(rdi(hdr->e_phnum) + 1);\n    wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1);\n    Elf_Phdr &phdr = phdrs[rdi(hdr->e_phnum) - 1];\n    wri(phdr.p_type, PT_LOAD);\n    wri(phdr.p_offset, startOffset);\n    wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));\n    wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));\n    wri(phdr.p_flags, PF_R | PF_W);\n    wri(phdr.p_align, pageSize);\n\n    /* Write out the replaced sections. */\n    Elf_Off curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr);\n    writeReplacedSections(curOff, startPage, startOffset);\n    assert((off_t)curOff == startOffset + neededSpace);\n\n    /* Move the program header to the start of the new area. */\n    wri(hdr->e_phoff, startOffset);\n\n    rewriteHeaders(startPage);\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()\n{\n    /* Sort the sections by offset, otherwise we won't correctly find\n       all the sections before the last replaced section. */\n    sortShdrs();\n\n    /* What is the index of the last replaced section? */\n    unsigned int lastReplaced = 0;\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) {\n        string sectionName = getSectionName(shdrs[i]);\n        if (replacedSections.find(sectionName) != replacedSections.end()) {\n            debug(\"using replaced section `%s'\\n\", sectionName.c_str());\n            lastReplaced = i;\n        }\n    }\n\n    assert(lastReplaced != 0);\n\n    debug(\"last replaced is %d\\n\", lastReplaced);\n\n    /* Try to replace all sections before that, as far as possible.\n       Stop when we reach an irreplacable section (such as one of type\n       SHT_PROGBITS).  These cannot be moved in virtual address space\n       since that would invalidate absolute references to them. */\n    assert(lastReplaced + 1 < shdrs.size()); /* !!! I'm lazy. */\n    size_t   startOffset = rdi(shdrs[lastReplaced + 1].sh_offset);\n    Elf_Addr startAddr = rdi(shdrs[lastReplaced + 1].sh_addr);\n    string   prevSection;\n    for (unsigned int i = 1; i <= lastReplaced; ++i) {\n        Elf_Shdr &shdr(shdrs[i]);\n        string    sectionName = getSectionName(shdr);\n        debug(\"looking at section `%s'\\n\", sectionName.c_str());\n        /* !!! Why do we stop after a .dynstr section? I can't\n           remember! */\n        if ((rdi(shdr.sh_type) == SHT_PROGBITS && sectionName != \".interp\") || prevSection == \".dynstr\") {\n            startOffset = rdi(shdr.sh_offset);\n            startAddr = rdi(shdr.sh_addr);\n            lastReplaced = i - 1;\n            break;\n        } else {\n            if (replacedSections.find(sectionName) == replacedSections.end()) {\n                debug(\"replacing section `%s' which is in the way\\n\", sectionName.c_str());\n                replaceSection(sectionName, rdi(shdr.sh_size));\n            }\n        }\n        prevSection = sectionName;\n    }\n\n    debug(\"first reserved offset/addr is 0x%x/0x%llx\\n\", startOffset, (unsigned long long)startAddr);\n\n    assert(startAddr % pageSize == startOffset % pageSize);\n    Elf_Addr firstPage = startAddr - startOffset;\n    debug(\"first page is 0x%llx\\n\", (unsigned long long)firstPage);\n\n    /* Right now we assume that the section headers are somewhere near\n       the end, which appears to be the case most of the time.\n       Therefore they're not accidentally overwritten by the replaced\n       sections. !!!  Fix this. */\n    assert((off_t)rdi(hdr->e_shoff) >= startOffset);\n\n    /* Compute the total space needed for the replaced sections, the\n       ELF header, and the program headers. */\n    size_t neededSpace = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr);\n    for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) neededSpace += roundUp(i->second.size(), sectionAlignment);\n\n    debug(\"needed space is %d\\n\", neededSpace);\n\n    /* If we need more space at the start of the file, then grow the\n       file by the minimum number of pages and adjust internal\n       offsets. */\n    if (neededSpace > startOffset) {\n        /* We also need an additional program header, so adjust for that. */\n        neededSpace += sizeof(Elf_Phdr);\n        debug(\"needed space is %d\\n\", neededSpace);\n\n        unsigned int neededPages = roundUp(neededSpace - startOffset, pageSize) / pageSize;\n        debug(\"needed pages is %d\\n\", neededPages);\n        if (neededPages * pageSize > firstPage) error(\"virtual address space underrun!\");\n\n        firstPage -= neededPages * pageSize;\n        startOffset += neededPages * pageSize;\n\n        shiftFile(neededPages, firstPage);\n    }\n\n    /* Clear out the free space. */\n    Elf_Off curOff = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr);\n    debug(\"clearing first %d bytes\\n\", startOffset - curOff);\n    memset(contents + curOff, 0, startOffset - curOff);\n\n    /* Write out the replaced sections. */\n    writeReplacedSections(curOff, firstPage, 0);\n    assert((off_t)curOff == neededSpace);\n\n    rewriteHeaders(firstPage + rdi(hdr->e_phoff));\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::rewriteSections()\n{\n    if (replacedSections.empty()) return;\n\n    for (ReplacedSections::iterator i = replacedSections.begin(); i != replacedSections.end(); ++i) debug(\"replacing section `%s' with size %d\\n\", i->first.c_str(), i->second.size());\n\n    if (rdi(hdr->e_type) == ET_DYN) {\n        debug(\"this is a dynamic library\\n\");\n        rewriteSectionsLibrary();\n    } else if (rdi(hdr->e_type) == ET_EXEC) {\n        debug(\"this is an executable\\n\");\n        rewriteSectionsExecutable();\n    } else\n        error(\"unknown ELF type\");\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)\n{\n    /* Rewrite the program header table. */\n\n    /* If there is a segment for the program header table, update it.\n       (According to the ELF spec, it must be the first entry.) */\n    if (rdi(phdrs[0].p_type) == PT_PHDR) {\n        phdrs[0].p_offset = hdr->e_phoff;\n        wri(phdrs[0].p_vaddr, wri(phdrs[0].p_paddr, phdrAddress));\n        wri(phdrs[0].p_filesz, wri(phdrs[0].p_memsz, phdrs.size() * sizeof(Elf_Phdr)));\n    }\n\n    sortPhdrs();\n\n    for (unsigned int i = 0; i < phdrs.size(); ++i) *((Elf_Phdr *)(contents + rdi(hdr->e_phoff)) + i) = phdrs[i];\n\n    /* Rewrite the section header table.  For neatness, keep the\n       sections sorted. */\n    assert(rdi(hdr->e_shnum) == shdrs.size());\n    sortShdrs();\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) *((Elf_Shdr *)(contents + rdi(hdr->e_shoff)) + i) = shdrs[i];\n\n    /* Update all those nasty virtual addresses in the .dynamic\n       section.  Note that not all executables have .dynamic sections\n       (e.g., those produced by klibc's klcc). */\n    Elf_Shdr *shdrDynamic = findSection2(\".dynamic\");\n    if (shdrDynamic) {\n        Elf_Dyn *    dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic->sh_offset));\n        unsigned int d_tag;\n        for (; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++)\n            if (d_tag == DT_STRTAB)\n                dyn->d_un.d_ptr = findSection(\".dynstr\").sh_addr;\n            else if (d_tag == DT_STRSZ)\n                dyn->d_un.d_val = findSection(\".dynstr\").sh_size;\n            else if (d_tag == DT_SYMTAB)\n                dyn->d_un.d_ptr = findSection(\".dynsym\").sh_addr;\n            else if (d_tag == DT_HASH)\n                dyn->d_un.d_ptr = findSection(\".hash\").sh_addr;\n            else if (d_tag == DT_GNU_HASH)\n                dyn->d_un.d_ptr = findSection(\".gnu.hash\").sh_addr;\n            else if (d_tag == DT_JMPREL) {\n                Elf_Shdr *shdr = findSection2(\".rel.plt\");\n                if (!shdr) shdr = findSection2(\".rela.plt\");          /* 64-bit Linux, x86-64 */\n                if (!shdr) shdr = findSection2(\".rela.IA_64.pltoff\"); /* 64-bit Linux, IA-64 */\n                if (!shdr) error(\"cannot find section corresponding to DT_JMPREL\");\n                dyn->d_un.d_ptr = shdr->sh_addr;\n            } else if (d_tag == DT_REL) { /* !!! hack! */\n                Elf_Shdr *shdr = findSection2(\".rel.dyn\");\n                /* no idea if this makes sense, but it was needed for some\n                   program */\n                if (!shdr) shdr = findSection2(\".rel.got\");\n                if (!shdr) error(\"cannot find .rel.dyn or .rel.got\");\n                dyn->d_un.d_ptr = shdr->sh_addr;\n            } else if (d_tag == DT_RELA)\n                dyn->d_un.d_ptr = findSection(\".rela.dyn\").sh_addr; /* PPC Linux */\n            else if (d_tag == DT_VERNEED)\n                dyn->d_un.d_ptr = findSection(\".gnu.version_r\").sh_addr;\n            else if (d_tag == DT_VERSYM)\n                dyn->d_un.d_ptr = findSection(\".gnu.version\").sh_addr;\n    }\n\n    /* Rewrite the .dynsym section.  It contains the indices of the\n       sections in which symbols appear, so these need to be\n       remapped. */\n    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) {\n        if (rdi(shdrs[i].sh_type) != SHT_SYMTAB && rdi(shdrs[i].sh_type) != SHT_DYNSYM) continue;\n        debug(\"rewriting symbol table section %d\\n\", i);\n        for (size_t entry = 0; (entry + 1) * sizeof(Elf_Sym) <= rdi(shdrs[i].sh_size); entry++) {\n            Elf_Sym *    sym = (Elf_Sym *)(contents + rdi(shdrs[i].sh_offset) + entry * sizeof(Elf_Sym));\n            unsigned int shndx = rdi(sym->st_shndx);\n            if (shndx != SHN_UNDEF && shndx < SHN_LORESERVE) {\n                if (shndx >= sectionsByOldIndex.size()) {\n                    fprintf(stderr, \"warning: entry %d in symbol table refers to a non-existent section, skipping\\n\", shndx);\n                    continue;\n                }\n                string section = sectionsByOldIndex.at(shndx);\n                assert(!section.empty());\n                unsigned int newIndex = findSection3(section);    // inefficient\n                // debug(\"rewriting symbol %d: index = %d (%s) -> %d\\n\", entry, shndx, section.c_str(), newIndex);\n                wri(sym->st_shndx, newIndex);\n                /* Rewrite st_value.  FIXME: we should do this for all\n                   types, but most don't actually change. */\n                if (ELF32_ST_TYPE(rdi(sym->st_info)) == STT_SECTION) wri(sym->st_value, rdi(shdrs[newIndex].sh_addr));\n            }\n        }\n    }\n}\n\nstatic void setSubstr(string &s, unsigned int pos, const string &t)\n{\n    assert(pos + t.size() <= s.size());\n    copy(t.begin(), t.end(), s.begin() + pos);\n}\n\ntemplate<ElfFileParams> string ElfFile<ElfFileParamNames>::getInterpreter()\n{\n    Elf_Shdr &shdr = findSection(\".interp\");\n    return string((char *)contents + rdi(shdr.sh_offset), rdi(shdr.sh_size));\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::setInterpreter(const string &newInterpreter)\n{\n    string &section = replaceSection(\".interp\", newInterpreter.size() + 1);\n    setSubstr(section, 0, newInterpreter + '\\0');\n    changed = true;\n}\n\nstatic void concatToRPath(string &rpath, const string &path)\n{\n    if (!rpath.empty()) rpath += \":\";\n    rpath += path;\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)\n{\n    Elf_Shdr &shdrDynamic = findSection(\".dynamic\");\n\n    /* !!! We assume that the virtual address in the DT_STRTAB entry\n       of the dynamic section corresponds to the .dynstr section. */\n    Elf_Shdr &shdrDynStr = findSection(\".dynstr\");\n    char *    strTab = (char *)contents + rdi(shdrDynStr.sh_offset);\n\n    /* Find the DT_STRTAB entry in the dynamic section. */\n    Elf_Dyn *dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset));\n    Elf_Addr strTabAddr = 0;\n    for (; rdi(dyn->d_tag) != DT_NULL; dyn++)\n        if (rdi(dyn->d_tag) == DT_STRTAB) strTabAddr = rdi(dyn->d_un.d_ptr);\n    if (!strTabAddr) error(\"strange: no string table\");\n\n    assert(strTabAddr == rdi(shdrDynStr.sh_addr));\n\n    /* Walk through the dynamic section, look for the RPATH/RUNPATH\n       entry.\n\n       According to the ld.so docs, DT_RPATH is obsolete, we should\n       use DT_RUNPATH.  DT_RUNPATH has two advantages: it can be\n       overriden by LD_LIBRARY_PATH, and it's scoped (the DT_RUNPATH\n       for an executable or library doesn't affect the search path for\n       libraries used by it).  DT_RPATH is ignored if DT_RUNPATH is\n       present.  The binutils `ld' still generates only DT_RPATH,\n       unless you use its `--enable-new-dtag' option, in which case it\n       generates a DT_RPATH and DT_RUNPATH pointing at the same\n       string. */\n    static vector<string> neededLibs;\n    dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset));\n    Elf_Dyn *dynRPath = 0, *dynRunPath = 0;\n    char *   rpath = 0;\n    for (; rdi(dyn->d_tag) != DT_NULL; dyn++) {\n        if (rdi(dyn->d_tag) == DT_RPATH) {\n            dynRPath = dyn;\n            /* Only use DT_RPATH if there is no DT_RUNPATH. */\n            if (!dynRunPath) rpath = strTab + rdi(dyn->d_un.d_val);\n        } else if (rdi(dyn->d_tag) == DT_RUNPATH) {\n            dynRunPath = dyn;\n            rpath = strTab + rdi(dyn->d_un.d_val);\n        } else if (rdi(dyn->d_tag) == DT_NEEDED)\n            neededLibs.push_back(string(strTab + rdi(dyn->d_un.d_val)));\n    }\n\n    if (op == rpPrint) {\n        printf(\"%s\\n\", rpath ? rpath : \"\");\n        return;\n    }\n\n    if (op == rpShrink && !rpath) {\n        debug(\"no RPATH to shrink\\n\");\n        return;\n    }\n\n    /* For each directory in the RPATH, check if it contains any\n       needed library. */\n    if (op == rpShrink) {\n        static vector<bool> neededLibFound(neededLibs.size(), false);\n\n        newRPath = \"\";\n\n        char *pos = rpath;\n        while (*pos) {\n            char *end = strchr(pos, ':');\n            if (!end) end = strchr(pos, 0);\n\n            /* Get the name of the directory. */\n            string dirName(pos, end - pos);\n            if (*end == ':') ++end;\n            pos = end;\n\n            /* Non-absolute entries are allowed (e.g., the special\n               \"$ORIGIN\" hack). */\n            if (dirName[0] != '/') {\n                concatToRPath(newRPath, dirName);\n                continue;\n            }\n\n            /* For each library that we haven't found yet, see if it\n               exists in this directory. */\n            bool libFound = false;\n            for (unsigned int j = 0; j < neededLibs.size(); ++j)\n                if (!neededLibFound[j]) {\n                    string      libName = dirName + \"/\" + neededLibs[j];\n                    struct stat st;\n                    if (stat(libName.c_str(), &st) == 0) {\n                        neededLibFound[j] = true;\n                        libFound = true;\n                    }\n                }\n\n            if (!libFound)\n                debug(\"removing directory `%s' from RPATH\\n\", dirName.c_str());\n            else\n                concatToRPath(newRPath, dirName);\n        }\n    }\n\n    if (string(rpath ? rpath : \"\") == newRPath) return;\n\n    changed = true;\n\n    /* Zero out the previous rpath to prevent retained dependencies in\n       Nix. */\n    unsigned int rpathSize = 0;\n    if (rpath) {\n        rpathSize = strlen(rpath);\n        memset(rpath, 'X', rpathSize);\n    }\n\n    debug(\"new rpath is `%s'\\n\", newRPath.c_str());\n\n    if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */\n        dynRPath->d_tag = DT_RUNPATH;\n        dynRunPath = dynRPath;\n        dynRPath = 0;\n    }\n\n    if (forceRPath && dynRPath && dynRunPath) { /* convert DT_RUNPATH to DT_RPATH */\n        dynRunPath->d_tag = DT_IGNORE;\n    }\n\n    if (newRPath.size() <= rpathSize) {\n        strcpy(rpath, newRPath.c_str());\n        return;\n    }\n\n    /* Grow the .dynstr section to make room for the new RPATH. */\n    debug(\"rpath is too long, resizing...\\n\");\n\n    string &newDynStr = replaceSection(\".dynstr\", rdi(shdrDynStr.sh_size) + newRPath.size() + 1);\n    setSubstr(newDynStr, rdi(shdrDynStr.sh_size), newRPath + '\\0');\n\n    /* Update the DT_RUNPATH and DT_RPATH entries. */\n    if (dynRunPath || dynRPath) {\n        if (dynRunPath) dynRunPath->d_un.d_val = shdrDynStr.sh_size;\n        if (dynRPath) dynRPath->d_un.d_val = shdrDynStr.sh_size;\n    }\n\n    else {\n        /* There is no DT_RUNPATH entry in the .dynamic section, so we\n           have to grow the .dynamic section. */\n        string &newDynamic = replaceSection(\".dynamic\", rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));\n\n        unsigned int idx = 0;\n        for (; rdi(((Elf_Dyn *)newDynamic.c_str())[idx].d_tag) != DT_NULL; idx++)\n            ;\n        debug(\"DT_NULL index is %d\\n\", idx);\n\n        /* Shift all entries down by one. */\n        setSubstr(newDynamic, sizeof(Elf_Dyn), string(newDynamic, 0, sizeof(Elf_Dyn) * (idx + 1)));\n\n        /* Add the DT_RUNPATH entry at the top. */\n        Elf_Dyn newDyn;\n        wri(newDyn.d_tag, forceRPath ? DT_RPATH : DT_RUNPATH);\n        newDyn.d_un.d_val = shdrDynStr.sh_size;\n        setSubstr(newDynamic, 0, string((char *)&newDyn, sizeof(Elf_Dyn)));\n    }\n}\n\ntemplate<ElfFileParams> void ElfFile<ElfFileParamNames>::removeNeeded(set<string> libs)\n{\n    if (libs.empty()) return;\n\n    Elf_Shdr &shdrDynamic = findSection(\".dynamic\");\n    Elf_Shdr &shdrDynStr = findSection(\".dynstr\");\n    char *    strTab = (char *)contents + rdi(shdrDynStr.sh_offset);\n\n    Elf_Dyn *dyn = (Elf_Dyn *)(contents + rdi(shdrDynamic.sh_offset));\n    Elf_Dyn *last = dyn;\n    for (; rdi(dyn->d_tag) != DT_NULL; dyn++) {\n        if (rdi(dyn->d_tag) == DT_NEEDED) {\n            char *name = strTab + rdi(dyn->d_un.d_val);\n            if (libs.find(name) != libs.end()) {\n                debug(\"removing DT_NEEDED entry `%s'\\n\", name);\n                changed = true;\n            } else {\n                debug(\"keeping DT_NEEDED entry `%s'\\n\", name);\n                *last++ = *dyn;\n            }\n        } else\n            *last++ = *dyn;\n    }\n\n    memset(last, 0, sizeof(Elf_Dyn) * (dyn - last));\n}\n\nstatic bool   printInterpreter = false;\nstatic string newInterpreter;\n\nstatic bool        shrinkRPath = false;\nstatic bool        setRPath = false;\nstatic bool        printRPath = false;\nstatic string      newRPath;\nstatic set<string> neededLibsToRemove;\n\ntemplate<class ElfFile> static void patchElf2(ElfFile &elfFile, mode_t fileMode)\n{\n    elfFile.parse();\n\n    if (printInterpreter) printf(\"%s\\n\", elfFile.getInterpreter().c_str());\n\n    if (newInterpreter != \"\") elfFile.setInterpreter(newInterpreter);\n\n    if (printRPath) elfFile.modifyRPath(elfFile.rpPrint, \"\");\n\n    if (shrinkRPath)\n        elfFile.modifyRPath(elfFile.rpShrink, \"\");\n    else if (setRPath)\n        elfFile.modifyRPath(elfFile.rpSet, newRPath);\n\n    elfFile.removeNeeded(neededLibsToRemove);\n\n    if (elfFile.isChanged()) {\n        elfFile.rewriteSections();\n        writeFile(fileName, fileMode);\n    }\n}\n\nstatic void patchElf()\n{\n    if (!printInterpreter && !printRPath) debug(\"patching ELF file `%s'\\n\", fileName.c_str());\n\n    mode_t fileMode;\n\n    readFile(fileName, &fileMode);\n\n    /* Check the ELF header for basic validity. */\n    if (fileSize < (off_t)sizeof(Elf32_Ehdr)) error(\"missing ELF header\");\n\n    if (memcmp(contents, ELFMAG, SELFMAG) != 0) error(\"not an ELF executable\");\n\n    if (contents[EI_CLASS] == ELFCLASS32 && contents[EI_VERSION] == EV_CURRENT) {\n        ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym> elfFile;\n        patchElf2(elfFile, fileMode);\n    } else if (contents[EI_CLASS] == ELFCLASS64 && contents[EI_VERSION] == EV_CURRENT) {\n        ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym> elfFile;\n        patchElf2(elfFile, fileMode);\n    } else {\n        error(\"ELF executable is not 32/64-bit, little/big-endian, version 1\");\n    }\n}\n\nvoid showHelp(const string &progName)\n{\n    fprintf(stderr, \"syntax: %s\\n\\\n  [--set-interpreter FILENAME]\\n\\\n  [--print-interpreter]\\n\\\n  [--set-rpath RPATH]\\n\\\n  [--shrink-rpath]\\n\\\n  [--print-rpath]\\n\\\n  [--force-rpath]\\n\\\n  [--remove-needed LIBRARY]\\n\\\n  [--debug]\\n\\\n  [--version]\\n\\\n  FILENAME\\n\",\n            progName.c_str());\n}\n\nint main(int argc, char **argv)\n{\n    if (argc <= 1) {\n        showHelp(argv[0]);\n        return 1;\n    }\n\n    if (getenv(\"PATCHELF_DEBUG\") != 0) debugMode = true;\n\n    int i;\n    for (i = 1; i < argc; ++i) {\n        string arg(argv[i]);\n        if (arg == \"--set-interpreter\" || arg == \"--interpreter\") {\n            if (++i == argc) error(\"missing argument\");\n            newInterpreter = argv[i];\n        } else if (arg == \"--print-interpreter\") {\n            printInterpreter = true;\n        } else if (arg == \"--shrink-rpath\") {\n            shrinkRPath = true;\n        } else if (arg == \"--set-rpath\") {\n            if (++i == argc) error(\"missing argument\");\n            setRPath = true;\n            newRPath = argv[i];\n        } else if (arg == \"--print-rpath\") {\n            printRPath = true;\n        } else if (arg == \"--force-rpath\") {\n            /* Generally we prefer to emit DT_RUNPATH instead of\n               DT_RPATH, as the latter is obsolete.  However, there is\n               a slight semantic difference: DT_RUNPATH is \"scoped\",\n               it only affects the executable or library in question,\n               not its recursive imports.  So maybe you really want to\n               force the use of DT_RPATH.  That's what this option\n               does.  Without it, DT_RPATH (if encountered) is\n               converted to DT_RUNPATH, and if neither is present, a\n               DT_RUNPATH is added.  With it, DT_RPATH isn't converted\n               to DT_RUNPATH, and if neither is present, a DT_RPATH is\n               added. */\n            forceRPath = true;\n        } else if (arg == \"--remove-needed\") {\n            if (++i == argc) error(\"missing argument\");\n            neededLibsToRemove.insert(argv[i]);\n        } else if (arg == \"--debug\") {\n            debugMode = true;\n        } else if (arg == \"--help\") {\n            showHelp(argv[0]);\n            return 0;\n        } else if (arg == \"--version\") {\n            printf(PACKAGE_STRING \"\\n\");\n            return 0;\n        } else\n            break;\n    }\n\n    if (i == argc) error(\"missing filename\");\n    fileName = argv[i];\n\n    patchElf();\n\n    return 0;\n}\n"
  },
  {
    "path": "buildutils/postflight",
    "content": "#!/bin/csh -f\n# This postflight script echoes the values of the available\n# arguments and environmental variables.\n#\n\necho \"Start postflight script\"\necho \"\"\necho \"Finished postflight script\"\nexit 0\n"
  },
  {
    "path": "buildutils/postinstall",
    "content": "#!/bin/csh -f\n# This postinstall script echoes the values of the available\n# arguments and environmental variables.\n#\n\necho \"Start postinstall script\"\necho \"\"\n\nset InstDest = $argv[2]\n\nset vapor_root = $InstDest/VAPOR3/VAPOR.app\nset bindir = $vapor_root/Contents/MacOS\nset lib_search_dirs = $bindir\nset mandir = $vapor_root/Contents/share/man\nset sharedir = $vapor_root/Contents/share\n\nset sedcmd = sed\nif (-e /bin/sed) set sedcmd = /bin/sed\nif (-e /usr/bin/sed) set sedcmd = /usr/bin/sed\n\n\n#\n# Edit the user environment setup scripts\n#\nset old0 = 'set[    ][  ]*root[     ][  ]*=.*$'\nset new0 = \"set root = $vapor_root\"\nset old1 = 'set[    ][  ]*lib_search_dirs[  ][  ]*=.*$'\nset new1 = \"set lib_search_dirs = $lib_search_dirs\"\nset old2 = 'set[    ][  ]*bindir[   ][  ]*=.*$'\nset new2 = \"set bindir = $bindir\"\nset old3 = 'set[    ][  ]*mandir[   ][  ]*=.*$'\nset new3 = \"set mandir = $mandir\"\nset old4 = 'set[    ][  ]*sharedir[   ][  ]*=.*$'\nset new4 = \"set sharedir = $sharedir\"\n$sedcmd -e \"s#$old0#$new0#\" -e \"s#$old1#$new1#\"  -e \"s#$old2#$new2#\"  -e \"s#$old3#$new3#\" -e \"s#$old4#$new4#\" < $bindir/vapor-setup.csh >! $bindir/vapor-setup.tmp\n/bin/mv $bindir/vapor-setup.tmp $bindir/vapor-setup.csh\n\n\nset old0 = 'root=.*$'\nset new0 = \"root=$vapor_root\"\nset old1 = 'lib_search_dirs=.*$'\nset new1 = \"lib_search_dirs=$lib_search_dirs\"\nset old2 = 'bindir=.*$'\nset new2 = \"bindir=$bindir\"\nset old3 = 'mandir=.*$'\nset new3 = \"mandir=$mandir\"\nset old4 = 'sharedir=.*$'\nset new4 = \"sharedir=$sharedir\"\n$sedcmd -e \"s#$old0#$new0#\" -e \"s#$old1#$new1#\" -e \"s#$old2#$new2#\" -e \"s#$old3#$new3#\" -e \"s#$old4#$new4#\" < $bindir/vapor-setup.sh >! $bindir/vapor-setup.tmp\n/bin/mv $bindir/vapor-setup.tmp $bindir/vapor-setup.sh\n\necho \"Finish postinstall script\"\nexit 0\n"
  },
  {
    "path": "buildutils/postupgrade",
    "content": "#!/bin/csh -f\n# This postupgrade script echoes the values of the available\n# arguments and environmental variables.\n#\n\necho \"Start postupgrade script\"\necho \"\"\n\nset InstDest = $argv[2]\n\nset vapor_root = $InstDest/VAPOR3/VAPOR.app\nset bindir = $vapor_root/Contents/MacOS\nset lib_search_dirs = $bindir\nset mandir = $vapor_root/Contents/share/man\nset sharedir = $vapor_root/Contents/share\n\nset sedcmd = sed\nif (-e /bin/sed) set sedcmd = /bin/sed\nif (-e /usr/bin/sed) set sedcmd = /usr/bin/sed\n\n\n#\n# Edit the user environment setup scripts\n#\nset old0 = 'set[    ][  ]*root[     ][  ]*=.*$'\nset new0 = \"set root = $vapor_root\"\nset old1 = 'set[    ][  ]*lib_search_dirs[  ][  ]*=.*$'\nset new1 = \"set lib_search_dirs = $lib_search_dirs\"\nset old2 = 'set[    ][  ]*bindir[   ][  ]*=.*$'\nset new2 = \"set bindir = $bindir\"\nset old3 = 'set[    ][  ]*mandir[   ][  ]*=.*$'\nset new3 = \"set mandir = $mandir\"\nset old4 = 'set[    ][  ]*sharedir[   ][  ]*=.*$'\nset new4 = \"set sharedir = $sharedir\"\n$sedcmd -e \"s#$old0#$new0#\" -e \"s#$old1#$new1#\"  -e \"s#$old2#$new2#\"  -e \"s#$old3#$new3#\" -e \"s#$old4#$new4#\" < $bindir/vapor-setup.csh >! $bindir/vapor-setup.tmp\n/bin/mv $bindir/vapor-setup.tmp $bindir/vapor-setup.csh\n\n\nset old0 = 'root=.*$'\nset new0 = \"root=$vapor_root\"\nset old1 = 'lib_search_dirs=.*$'\nset new1 = \"lib_search_dirs=$lib_search_dirs\"\nset old2 = 'bindir=.*$'\nset new2 = \"bindir=$bindir\"\nset old3 = 'mandir=.*$'\nset new3 = \"mandir=$mandir\"\nset old4 = 'sharedir=.*$'\nset new4 = \"sharedir=$sharedir\"\n$sedcmd -e \"s#$old0#$new0#\" -e \"s#$old1#$new1#\" -e \"s#$old2#$new2#\" -e \"s#$old3#$new3#\" -e \"s#$old4#$new4#\" < $bindir/vapor-setup.sh >! $bindir/vapor-setup.tmp\n/bin/mv $bindir/vapor-setup.tmp $bindir/vapor-setup.sh\n\necho \"Finish postupgrade script\"\nexit 0\n"
  },
  {
    "path": "buildutils/renameomp.sh",
    "content": "#!/bin/bash\n\nLIB=\"`otool -L \"$1\" | grep -F libomp | xargs | cut -d\\  -f1`\"\ninstall_name_tool -change \"$LIB\" \"@rpath/libomp.dylib\" \"$1\"\n"
  },
  {
    "path": "buildutils/sgiinstall.sh",
    "content": "#!/bin/sh \n\n#\n\nflags=\"\"\ndst=\"\"\nsrc=\"\"\ndostrip=\"\"\nowner=\"\"\nmode=\"\"\n\nwhile [ x$1 != x ]; do\n    case $1 in \n\t-c) shift\n\t    continue;;\n\n\t-m) flags=\"$flags $1 $2 \"\n\t    mode=\"$2\"\n\t    shift\n\t    shift\n\t    continue;;\n\n\t-o) flags=\"$flags -u $2 \"\n\t    owner=\"$2\"\n\t    shift\n\t    shift\n\t    continue;;\n\n\t-g) flags=\"$flags $1 $2 \"\n\t    shift\n\t    shift\n\t    continue;;\n\n\t-s) dostrip=\"strip\"\n\t    shift\n\t    continue;;\n\n\t*)  if [ x$src = x ] \n\t    then\n\t\tsrc=$1\n\t    else\n\t\tdst=$1\n\t    fi\n\t    shift\n\t    continue;;\n    esac\ndone\n\ncase \"$mode\" in\n\"\")\n\t;;\n*)\n\tcase \"$owner\" in\n\t\"\")\n#\t\tflags=\"$flags -u root\"\n\t\t;;\n\tesac\n\t;;\nesac\n\nif [ x$src = x ] \nthen\n\techo \"$0:  no input file specified\"\n\texit 1\nfi\n\nif [ x$dst = x ] \nthen\n\techo \"$0:  no destination specified\"\n\texit 1\nfi\n\n\n# set up some variable to be used later\n\nrmcmd=\"\"\nsrcdir=\".\"\n\n# if the destination isn't a directory we'll need to copy it first\n\nif [ ! -d $dst ]\nthen\n\tdstbase=`basename $dst`\n\tcp $src /tmp/$dstbase\n\trmcmd=\"rm -f /tmp/$dstbase\"\n\tsrc=$dstbase\n\tsrcdir=/tmp\n\tdst=\"`echo $dst | sed 's,^\\(.*\\)/.*$,\\1,'`\"\n\tif [ x$dst = x ]\n\tthen\n\t\tdst=\".\"\n\tfi\nfi\n\n\n# If the src file has a directory, copy it to /tmp to make install happy\n\nsrcbase=`basename $src`\n\nif [ \"$src\" != \"$srcbase\" ] && [ \"$src\" != \"./$srcbase\" ] \nthen\n\tcp $src /tmp/$srcbase\n\tsrc=$srcbase\n\tsrcdir=/tmp\n\trmcmd=\"rm -f /tmp/$srcbase\"\nfi\n\n# do the actual install\n\nif [ -f /usr/sbin/install ]\nthen\n\tinstallcmd=/usr/sbin/install\nelif [ -f /etc/install ]\nthen\n\tinstallcmd=/etc/install\nelse\n\tinstallcmd=install\nfi\n\n# This rm is commented out because some people want to be able to\n# install through symbolic links.  Uncomment it if it offends you.\n# rm -f $dst/$srcbase\n(cd $srcdir ; $installcmd -f $dst $flags $src)\n\nif [ x$dostrip = xstrip ]\nthen\n\tstrip $dst/$srcbase\nfi\n\n# and clean up\n\n$rmcmd\n\n"
  },
  {
    "path": "buildutils/vapor.desktop",
    "content": "[Desktop Entry]\nType=Application\nName=VAPOR\nComment=Visualization and Analysis Platform for Ocean, Atmosphere, and Solar Researchers\nExec=bin/vapor\nIcon=VAPOR\nCategories=Science;Geoscience;DataVisualization;\n"
  },
  {
    "path": "conda/vapor/build.sh",
    "content": "#!/bin/sh\n\n# Inputs\n[[ -z \"$DEBUG_BUILD\" ]] && DEBUG_BUILD=true\n\nCMAKE_EXTRA=\"\"\n\n# The env can be either PREFIX or BUILD_PREFIX depending on the build requirements.\n# Conda does not configure its variables accordingly.\nexport ENV=\"$BUILD_PREFIX\"\n\nexport PATH=\"$ENV/bin:$PATH\"\n\n# Conda will sometimes set PYTHON to a path that does not exist\nexport PYTHON=\"`which python`\"\n\nif $DEBUG_BUILD; then\n    # If optimizations are disabled, need to disable fortify source otherwise will get barraged with warnings\n    export CPPFLAGS=\"`echo $CPPFLAGS|sed 's/-D_FORTIFY_SOURCE=2//g'`\"\n    \n    CMAKE_EXTRA=\"$CMAKE_EXTRA -DCMAKE_BUILD_TYPE=Debug\"\nelse\n    CMAKE_EXTRA=\"$CMAKE_EXTRA -DCMAKE_BUILD_TYPE=Release\"\nfi\nCMAKE_EXTRA=\"$CMAKE_EXTRA -DINSTALLER_OMIT_MAPS=ON\"\n\n# Ignore extra warnings\nexport CPPFLAGS=\" \\\n    $CPPFLAGS \\\n    -Wno-unused-function \\\n    -Wno-conversion-null \\\n    -Wno-deprecated-declarations \\\n    -Wno-catch-value \\\n    -Wno-unknown-warning-option \\\n    -Wno-array-parameter \\\n    \"\n\n# Vapor legacy configuration\nexport CPPFLAGS=\"-isystem $ENV/include/freetype2 $CPPFLAGS\"\n\nexport CPPFLAGS=\"$CPPFLAGS -isystem $ENV/include\"\n\n# cmake ignores CPPFLAGS\nexport CXXFLAGS=\"$CXXFLAGS $CPPFLAGS\"\nexport CFLAGS=\"$CFLAGS $CPPFLAGS\"\n\n# Conda will sometimes set these to invalid values which end up breaking the build\nunset CMAKE_ARGS\nunset CMAKE_PREFIX_PATH\n\n# Prevent linking outside libraries\nexport CMAKE_LIBRARY_PATH=\"$PREFIX/lib:$BUILD_PREFIX/lib\"\nexport CMAKE_PREFIX_PATH=\"$PREFIX:$BUILD_PREFIX\"\n# CMAKE_EXTRA=\"$CMAKE_EXTRA -DCMAKE_FIND_FRAMEWORK=NEVER\"\n# CMAKE_EXTRA=\"$CMAKE_EXTRA -DCMAKE_FIND_APPBUNDLE=NEVER\"\n\n# When conda messes up the build environment it not only points the python install target to the wrong root,\n# it also sometimes points it to the wrong version of python.\nSP_DIR=\"`python -c 'import site; print(site.getsitepackages()[0].replace(\\\"'$BUILD_PREFIX'\\\", \\\"'$PREFIX'\\\"))'`\"\n# It also will sometimes decide not to make this dir\nmkdir -p \"$SP_DIR\"\n\n# Our third party libs have a non-standard copy of the GTE library so it is packaged and extracted here.\nunzip -d include buildutils/GTE.zip\n\n\nmkdir -p build\ncd build\n\ncmake .. \\\n    -G 'Unix Makefiles' \\\n    -DCONDA_BUILD=ON \\\n    -DBUILD_PYTHON=ON \\\n    -DBUILD_DOC=ON \\\n    -DBUILD_UTL=OFF \\\n    -DBUILD_GUI=OFF \\\n    -DBUILD_OSP=OFF \\\n    -DPython_EXECUTABLE=\"$PYTHON\" \\\n    -DCMAKE_INSTALL_PREFIX=\"$PREFIX\" \\\n    $CMAKE_EXTRA \\\n\n\n\nmake -j$(($CPU_COUNT+1))\nmake doc\nmake install\n\n"
  },
  {
    "path": "conda/vapor/jupyter_installer_fix.py",
    "content": "import argparse\nimport os\nimport shutil\n\nparser = argparse.ArgumentParser()\nparser.add_argument('-n', '--dryRun', action='store_true')\nparser.add_argument('-w', '--widgetDir', required=True)\nparser.add_argument('-o', '--outRootDir', required=True)\nargs = parser.parse_args()\nprint(args)\n\nwidgetRoot = args.widgetDir\nwidgetSetup = f\"{widgetRoot}/setup.py\"\nroot = args.outRootDir\n\nassert(os.path.isdir(widgetRoot))\n\ndef nullFunc(ret=None):\n    return lambda *args, **kwargs: ret\n\nimport setuptools\nsetuptools.setup = nullFunc()\n\nimport jupyter_packaging\njupyter_packaging.create_cmdclass = nullFunc(ret=dict())\njupyter_packaging.combine_commands = nullFunc()\njupyter_packaging.install_npm = nullFunc()\n\nwith open(widgetSetup) as f:\n    exec(compile(f.read(), widgetSetup, \"exec\"))\n\n# print(\"data_files_spec =\", data_files_spec)\n\ntoInstall = jupyter_packaging.get_data_files(data_specs=data_files_spec, top=widgetRoot)\n\nfor outDir, files in toInstall:\n    outDir = root + \"/\" + outDir\n    if not args.dryRun:\n        os.makedirs(outDir, exist_ok=True)\n\n    for file in files:\n        print(f\"Install {file} in {outDir}\")\n        if not args.dryRun:\n            shutil.copy(widgetRoot+\"/\"+file, outDir)\n"
  },
  {
    "path": "conda/vapor/make_installer.sh",
    "content": "echo Generating vapor installer\necho\necho NOTE: Due to the oddities of conda, this should not be run from the directory from which you also build.\necho NOTE: If you do, make sure to remove any generated files before calling conda build again.\necho\n\nCHANNEL=__vapor_install_temp_vapor-channel\nmkdir -p $CHANNEL/linux-64/\ncp `find $CONDA_PREFIX -name 'vapor*.bz2'` $CHANNEL/linux-64/\nconda index $CHANNEL\n\ncat > install_vapor.sh << EOF\n[ \"\" = \"\\$CONDA_PREFIX\" ] && echo This installer requires conda && exit 1\n[ \"\" != \"\\`conda list | grep -v '^#'\\`\" ] && echo Please run in empty conda environment && exit 1\ntail -n +___START_LINE___ \"\\$0\" | tar -xf -\nconda install -c conda-forge -c file:/\\`pwd\\`/$CHANNEL vapor\nrm -rf $CHANNEL\necho\necho Vapor installed\necho Examples can be found at \\$CONDA_PREFIX/lib/python3.9/site-packages/vapor/examples\necho Examples jupyter notebooks can be found at \\$CONDA_PREFIX/lib/python3.9/site-packages/vapor/example_notebooks\necho\nexit\n\n___START_EMBEDDED_DATA___\nEOF\n\nLINE=`grep -n ___START_EMBEDDED_DATA___ install_vapor.sh | tail -n1 | cut -f1 -d:`\nLINE=$(($LINE+1))\nsed -i \"s/___START_LINE___/$LINE/g\" install_vapor.sh\n\ntar -cf - $CHANNEL >> install_vapor.sh\n\nrm -rf $CHANNEL\n\necho Done\n"
  },
  {
    "path": "conda/vapor/meta.yaml",
    "content": "package:\n  name: vapor\n  version: \"3.11.0\"\n\nsource:\n  git_url: https://github.com/NCAR/VAPOR.git\n\nbuild:\n  skip_compile_pyc:\n    - \"*.py\"\n  script_env:\n  - DEBUG_BUILD\n\nrequirements:\n  build:\n    # Build-Only\n    # ==========================================\n    - {{ compiler('cxx') }}\n    - make=4.3\n    - cmake=3.21.3\n    - unzip=6.0\n    - jupytext=1.13.8 # Generate notebooks\n    - doxygen=1.9.1\n    - esbuild\n    - git\n    # Both\n    # (Needs to be specified manually in both rather than just in host because otherwise conda will install multiple versions of some packages and break the install)\n    # ==========================================\n    - python=3.9\n    - proj=7.2.0\n    - glm=0.9.9.4\n    - jpeg=9e\n{% if osx and arm64 %}\n    - numpy=1.21.4\n    - assimp=5.0.1\n    - freetype=2.10.4\n    - hdf5=1.12.1\n    - geotiff=1.6.0\n    - udunits2=2.2.28\n    - netcdf4=1.5.8\n    - libtiff=4.3|4.4\n    - mesalib=21.2.5\n    - expat=2.4\n    - libcxx=14.0\n{% else %}\n    - numpy=1.26\n    - assimp=5.3\n    - freetype=2.12\n    - hdf5=1.12\n    - geotiff=1.6\n    - udunits2=2.2\n    - netcdf4=1.6\n    - libtiff=4.4\n    - mesalib=23.0.2\n    - expat=2.7\n    - libcxx=18\n    - libxcrypt # [linux]\n{% endif %}\n  run:\n    # Run only\n    - xarray=2022 #=2022.3.0\n    - ipython=8 #=8.3.0 \n    - jupyter=1 #=1.0.0\n    - hdf5plugin=4\n    - vapor-maps=1.0 # [not os.environ.get('DEBUG_BUILD', '1').lower() in ('true', '1', '')]\n    - wurlitzer\n    - bqplot\n    - anywidget\n    # Both\n    - python=3.9 # pin_compatible('python') sometimes selects incompatible python (e.g. pin_compatible(python=3.9) selects python=3.10)\n    - {{ pin_compatible('numpy') }}\n    - {{ pin_compatible('assimp') }}\n    - {{ pin_compatible('freetype') }}\n    - {{ pin_compatible('hdf5') }}\n    - {{ pin_compatible('jpeg') }}\n    - {{ pin_compatible('geotiff') }}\n    - {{ pin_compatible('udunits2') }}\n    - {{ pin_compatible('netcdf4') }}\n    - {{ pin_compatible('proj') }}\n    - {{ pin_compatible('glm') }}\n    - {{ pin_compatible('mesalib') }}\n    - {{ pin_compatible('expat') }}\n    - {{ pin_compatible('libcxx') }}\n{% if osx and arm64 %}\n    - cppyy=2.2 # If this is in build conda will load an old clang compiler which fails to compile macOS headers\n    - matplotlib=3 #=3.3.2\n    - py-opencv=4 #=4.5.3\n    - libtiff=4.3|4.4 # pin_compatible pins an incompatible version\n{% else %}\n    - cppyy=3.5       # [osx]\n    - cppyy=3.1.2     # [linux]\n    - matplotlib=3.10 # [osx]\n    - matplotlib=3.9  # [linux]\n    - py-opencv=4.6\n    - {{ pin_compatible('libtiff') }}\n{% endif %}\n\n\nabout:\n  home: https://www.vapor.ucar.edu\n  license: MIT\n  summary: VAPOR is the Visualization and Analysis Platform for Ocean, Atmosphere, and Solar Researchers\n  dev_url: https://github.com/NCAR/VAPOR\n\n"
  },
  {
    "path": "conda/vapor-maps/meta.yaml",
    "content": "package:\n  name: vapor-maps\n  version: \"1.0.0\"\n\nsource:\n  - url: https://github.com/NCAR/VAPOR-Data/archive/refs/tags/1.0.tar.gz\n\nbuild:\n  noarch: generic\n  script: |\n    DEST=\"$PREFIX/share/images\"\n    install -d \"$DEST\"\n    cp -r images/NaturalEarth* \"$DEST\"\n\n"
  },
  {
    "path": "conda/vapor-maps-extra/meta.yaml",
    "content": "package:\n  name: vapor-maps-extra\n  version: \"1.0.0\"\n\nsource:\n  - url: https://github.com/NCAR/VAPOR-Data/archive/refs/tags/1.0.tar.gz\n\nbuild:\n  noarch: generic\n  script: |\n    DEST=\"$PREFIX/share/images\"\n    install -d \"$DEST\"\n    cp -r images/BigBlueMarble* images/*.tif \"$DEST\"\n"
  },
  {
    "path": "include/CMakeLists.txt",
    "content": ""
  },
  {
    "path": "include/vapor/Advection.h",
    "content": "/*\n * This class performances advection calculations.\n * It also holds all the particles resulting from an advection.\n */\n\n#ifndef ADVECTION_H\n#define ADVECTION_H\n\n#include \"vapor/Particle.h\"\n#include \"vapor/Field.h\"\n#include \"vapor/common.h\"\n#include <string>\n#include <vector>\n\nnamespace flow {\nclass FLOW_API Advection final {\npublic:\n    enum class ADVECTION_METHOD {\n        EULER = 0,\n        RK4 = 1    // Runge-Kutta 4th order\n    };\n\n    // Constructor and destructor\n    Advection();\n\n    //\n    // Major action functions\n    //\n    // Advect all particles as long as they are within spatial and temporal boundary\n    // for a specified number if steps.\n    int AdvectSteps(Field *velocityField, double deltaT, size_t maxSteps, bool fixedStepSize, ADVECTION_METHOD method = ADVECTION_METHOD::RK4);\n    // Advect as many steps as necessary to reach a certain time: targetT.\n    // Note: it only considers particles that have already passed startT.\n    int AdvectTillTime(Field *velocityField, double startT, double deltaT, double targetT, bool fixedStepSize, ADVECTION_METHOD method = ADVECTION_METHOD::RK4);\n\n    // Retrieve field values of a particle based on its location, and put the result in\n    // the \"value\" field or the \"properties\" field of a particle\n    //   If \"skipNonZero\" is true, then this function only overwrites zeros.\n    //   Otherwise, it will overwrite values anyway.\n    int CalculateParticleValues(Field *scalarField, bool skipNonZero);\n    int CalculateParticleIntegratedValues(Field *scalarField, const bool skipNonZero, const float distScale = 1.f, const std::vector<double> &integrateWithinVolumeMin = {-FLT_MAX, -FLT_MAX, -FLT_MAX},\n                                          const std::vector<double> &integrateWithinVolumeMax = {FLT_MAX, FLT_MAX, FLT_MAX});\n    void SetAllStreamValuesToFinalValue(int realNSamples);\n    int CalculateParticleProperties(Field *scalarField);\n\n    void CalculateParticleHistogram(std::vector<double> &bounds, std::vector<long> &bins);\n\n    // Reset all particle values to zero\n    void ResetParticleValues();\n    // Clear all existing properties of a particle\n    void ClearParticleProperties();\n    // Clear particle property with a certain name.\n    // If the the specified property name does not exist, then nothing is done.\n    void RemoveParticleProperty(const std::string &);\n\n    // Set advection basics\n    void UseSeedParticles(const std::vector<Particle> &seeds);\n\n    // Retrieve the resulting particles as \"streams.\"\n    size_t                       GetNumberOfStreams() const;\n    const std::vector<Particle> &GetStreamAt(size_t i) const;\n\n    // Retrieve the maximum number of particles in any stream\n    size_t GetMaxNumOfPart() const;\n\n    // Query properties (most are properties of the velocity field)\n    int CheckReady() const;\n\n    // Specify periodicity, and periodic bounds on each dimension\n    void SetXPeriodicity(bool, float min, float max);\n    void SetYPeriodicity(bool, float min, float max);\n    void SetZPeriodicity(bool, float min, float max);\n\n    // Retrieve the names of value variable and property variables.\n    auto GetValueVarName() const -> std::string;\n    auto GetPropertyVarNames() const -> std::vector<std::string>;\n\nprivate:\n    std::vector<std::vector<Particle>> _streams;\n    std::string                        _valueVarName;\n    std::vector<std::string>           _propertyVarNames;\n\n    const float      _lowerAngle, _upperAngle;          // Thresholds for step size adjustment\n    float            _lowerAngleCos, _upperAngleCos;    // Cosine values of the threshold angles\n    std::vector<int> _separatorCount; // how many separators does each stream have.\n                                      // Useful to determine how many steps are there in a stream.\n    // If the advection is performed in a periodic fashion along one or more dimensions.\n    // These variables are **not** intended to be decided by Advection, but by someone\n    // who's more knowledgeable about the field.\n    std::array<bool, 3> _isPeriodic;          // is it periodic in X, Y, Z dimensions?\n    std::array<glm::vec2, 3> _periodicBounds; // periodic boundaries in X, Y, Z dimensions\n\n    // Advection methods here could assume all input is valid.\n    int _advectEuler(Field *, const Particle &, double deltaT,    // Input\n                     Particle &p1) const;                         // Output\n    int _advectRK4(Field *, const Particle &, double deltaT,      // Input\n                   Particle &p1) const;                           // Output\n\n    // Get an adjust factor for deltaT based on how curvy the past two steps are.\n    //   A value in range (0.0, 1.0) means shrink deltaT.\n    //   A value in range (1.0, inf) means enlarge deltaT.\n    //   A value equals to 1.0 means not touching deltaT.\n    float _calcAdjustFactor(const Particle &past2, const Particle &past1, const Particle &current) const;\n\n    // Adjust input \"val\" according to the bound specified by min and max.\n    // Returns the value after adjustment.\n    float _applyPeriodic(float val, float min, float max) const;\n\n    // Print return code if it's non-zero and compiled in debug mode.\n    void _printNonZero(int rtn, const char *file, const char *func, int line) const;\n\n    void _calculateParticleIntegratedValue(Particle &p, const Particle &prev, const Field *scalarField, const bool skipNonZero, const float distScale,\n                                           const std::vector<double> &integrateWithinVolumeMin, const std::vector<double> &integrateWithinVolumeMax) const;\n    static bool _isParticleInsideVolume(const Particle &p, const std::vector<double> &min, const std::vector<double> &max);\n};\n}; // namespace flow\n\n#endif\n"
  },
  {
    "path": "include/vapor/AdvectionIO.h",
    "content": "/*\n * Define input/output operations given an Advection.\n * Specifically, it can read a list of seeds for the advection class to start with,\n * and also output the trajectory of advectios to a text file.\n */\n\n#ifndef ADVECTION_IO_H\n#define ADVECTION_IO_H\n\n#include <iostream>\n#include \"vapor/Advection.h\"\n\nnamespace flow {\n// Output a certain number of steps from an advection.\n// When `append == false`, a header will also be output; otherwise, only trajectories are output.\nFLOW_API auto OutputFlowlinesNumSteps(const Advection *adv, const char *filename, size_t numStep, const std::string &proj4string, bool append) -> int;\n\n// Output trajectory to a maximum time.\n// When `append == false`, a header will also be output; otherwise, only trajectories are output.\nFLOW_API auto OutputFlowlinesMaxTime(const Advection *adv, const char *filename, double maxTime, const std::string &proj4string, bool append) -> int;\n\n// Input a list of seeds from lines of CSVs.\n// In case of any error occurs, it returns an empty list.\nFLOW_API auto InputSeedsCSV(const std::string &filename) -> std::vector<flow::Particle>;\n\n};    // namespace flow\n#endif\n"
  },
  {
    "path": "include/vapor/AnimationParams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tAnimationParams.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJanuary 2005\n//\n//\tDescription:\tDefines the AnimationParams class\n//\t\tThis is derived from the Params class\n//\t\tIt contains all the parameters required for animation\n\n//\n#ifndef ANIMATIONPARAMS_H\n#define ANIMATIONPARAMS_H\n\n#include <vapor/ParamsBase.h>\n\n//! \\class AnimationParams\n//! \\ingroup Public_Params\n//! \\brief A class that specifies parameters used in animation\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    February 2014\n\n//! When this class is local, it controls the time-steps in one visualizer.\n//! The global (shared) AnimationParams controls the animation in any number of visualizers.\n\nclass PARAMS_API AnimationParams : public VAPoR::ParamsBase {\npublic:\n    enum CaptureMode { SingleImage, TimeSeries };\n    enum CaptureType { TIFF, PNG };\n\n    AnimationParams(ParamsBase::StateSave *ssave);\n\n    AnimationParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node);\n\n    virtual ~AnimationParams();\n\n    //! Identify the current data timestep being used\n    //! \\retval long current time step\n    //\n    size_t GetCurrentTimestep() const { return (size_t)GetValueLong(_currentTimestepTag, 0); }\n\n    //! Set the current data timestep being used\n    //! \\param long current time step\n    //! \\retval int 0 if successful\n    //\n    void SetCurrentTimestep(size_t ts)\n    {\n        SetValueLong(_currentTimestepTag, \"Set timestep\", (long)ts);\n    }\n\n    //! Identify the starting time step currently set in the UI.\n    //! \\retval int starting frame number.\n    //\n    size_t GetStartTimestep() const { return (size_t)GetValueLong(_startTimestepTag, 0); }\n\n    //! set the starting time step\n    //! \\param int starting timestep\n    //! \\retval int 0 if successful\n    //\n    void SetStartTimestep(size_t ts) { \n        SetValueLong(_startTimestepTag, \"Set start timestep\", (long)ts);\n        SetValueLong(CaptureStartTag, \"Set end timestep for image capture\", (long)ts); \n    }\n\n    //! Identify the ending time step used during playback\n    //! \\retval int ending timestep\n    //\n    size_t GetEndTimestep() const { return (size_t)GetValueLong(_endTimestepTag, (long)0); }\n\n    //! set the ending time step\n    //! \\param int ending timestep\n    //! \\retval int 0 if success\n    //\n    void SetEndTimestep(size_t val) { \n        SetValueLong(_endTimestepTag, \"Set end timestep\", (long)val);\n        SetValueLong(CaptureEndTag, \"Set end timestep for image capture\", (long)val); \n    }\n\n    //! Get the current play direction\n    //! \\retval bool True if playing backwards\n    //\n    bool GetPlayBackwards() const { return GetValueLong(_playBackwardsTag, 0); }\n\n    //! Set the play direction\n    //! \\param int play direction\n    //\n    void SetPlayBackwards(bool val) { SetValueLong(_playBackwardsTag, \"Set play direction\", (long)val); }\n\n    //! Determine max frames per second\n    //! \\retval double max frames per second\n    //\n    double GetMaxFrameRate() { return GetValueDouble(_maxRateTag, 1.0); }\n\n    //! Set max frames per second\n    //! \\param double fps\n    //! \\retval int 0 if successful\n    //!\n    void SetMaxFrameRate(double rate) { SetValueDouble(_maxRateTag, \"Set max frame rate\", rate); }\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"AnimationParams\"); }\n\npublic:\n    static const string _maxRateTag;\n    static const string _startTimestepTag;\n    static const string _endTimestepTag;\n    static const string _playBackwardsTag;\n    static const string _currentTimestepTag;\n    static const string CaptureModeTag;\n    static const string CaptureTypeTag;\n    static const string CaptureStartTag;\n    static const string CaptureEndTag;\n    static const string CaptureFileNameTag;\n    static const string CaptureFileDirTag;\n    static const string CaptureFileTimeTag;\n    static const string CaptureTimeSeriesFileNameTag;\n    static const string CaptureTimeSeriesTimeTag;\n\nprivate:\n    //! Put a params instance into default state with no data.\n    void _init();\n};\n\n#endif    // ANIMATIONPARAMS_H\n"
  },
  {
    "path": "include/vapor/AnnotationParams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2015\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tAnnotationParams.h\n//\n//\tAuthor:\tScott Pearse\n//\t\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune 2015\n//\n//\tDescription:\tDefines the AnnotationParams class.\n//\t\tThis class supports parameters associted with the\n//\t\tvizfeature panel, describing the visual features in the visualizer\n//\n#ifndef ANNOTATIONPARAMS_H\n#define ANNOTATIONPARAMS_H\n\n#include <vector>\n\n#include <vapor/common.h>\n#include <vapor/ParamsBase.h>\n#include <vapor/AxisAnnotation.h>\n\nusing namespace Wasp;\n\nnamespace VAPoR {\n\nclass XmlNode;\n\n//! \\class AnnotationParams\n//! \\ingroup Public_Params\n//! \\brief A class for describing visual features displayed in the visualizer.\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date\tJune 2015\n\n//! The AnnotationParams class controls various features displayed in the visualizers\n//! There is a global AnnotationParams, that\n//! is shared by all windows whose vizfeature is set to \"global\".  There is also\n//! a local AnnotationParams for each window, that users can select whenever there are multiple windows.\n//! When local settings are used, they only affect one currently active visualizer.\n//! The AnnotationParams class also has several methods that are useful in setting up data requests from the DataMgr.\n//!\nclass PARAMS_API AnnotationParams : public ParamsBase {\npublic:\n    //! Create a AnnotationParams object from scratch\n    //\n    AnnotationParams(ParamsBase::StateSave *ssave);\n\n    //! Create a AnnotationParams object from an existing XmlNode tree\n    //\n    AnnotationParams(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    //! Copy from already existing instance\n    //\n    AnnotationParams(const AnnotationParams &rhs);\n\n    virtual ~AnnotationParams(){};\n\n    void GetDomainColor(double color[3]) const;\n    void GetDomainColor(std::vector<double> &color) const { _getColor(color, _domainColorTag); }\n\n    void SetDomainColor(vector<double> color);\n\n    bool GetUseDomainFrame() const { return (0 != GetValueLong(_domainFrameTag, (long)false)); }\n    void SetUseDomainFrame(bool onOff) { SetValueLong(_domainFrameTag, \"toggle domain frame\", (long)onOff); }\n\n    bool GetUseRegionFrame() const { return (0 != GetValueLong(_regionFrameTag, (long)false)); }\n    void SetUseRegionFrame(bool onOff) { SetValueLong(_regionFrameTag, \"toggle region frame\", (long)onOff); }\n\n    void GetRegionColor(double color[3]) const;\n    void GetRegionColor(std::vector<double> &color) const { _getColor(color, _regionColorTag); }\n\n    void SetRegionColor(vector<double> color);\n\n    void GetBackgroundColor(double color[3]) const;\n    void GetBackgroundColor(std::vector<double> &color) const { _getColor(color, _backgroundColorTag); }\n\n    void SetBackgroundColor(std::vector<double> color);\n\n    string GetCurrentAxisDataMgrName() const;\n    void   SetCurrentAxisDataMgrName(string dataMgr = \"default\");\n\n    AxisAnnotation *GetAxisAnnotation();\n\n    void SetAxisFontSize(int size);\n    int  GetAxisFontSize();\n\n    double GetTimeLLX() const;\n    void   SetTimeLLX(double llx);\n\n    double GetTimeLLY() const;\n    void   SetTimeLLY(double lly);\n\n    std::vector<double>       GetTimeColor() const;\n    template<typename T> void GetTimeColor(T color[]) const { m_getColor(color, _timeColorTag); };\n    void                      SetTimeColor(std::vector<double> color);\n\n    int  GetTimeType() const;\n    void SetTimeType(int type);\n\n    int  GetTimeSize() const;\n    void SetTimeSize(int size);\n\n\n    bool   GetAxisArrowEnabled() const;\n    double GetAxisArrowSize() const;\n    double GetAxisArrowXPos() const;\n    double GetAxisArrowYPos() const;\n\n    void SetAxisArrowEnabled(bool enabled);\n    void SetAxisArrowSize(double pos);\n    void SetAxisArrowXPos(double pos);\n    void SetAxisArrowYPos(double pos);\n\n    static string GetClassType() { return (\"AnnotationParams\"); }\n\n    static const string AxisArrowSizeTag;\n    static const string AxisArrowXPosTag;\n    static const string AxisArrowYPosTag;\n    static const string AxisArrowEnabledTag;\n\nprivate:\n    ParamsContainer *_axisAnnotations;\n\npublic:\n    static const string _domainColorTag;\n    static const string _domainFrameTag;\n    static const string _regionFrameTag;\n    static const string _regionColorTag;\n\n    static const string _axisColorTag;\n    static const string _axisDigitsTag;\n    static const string _axisTextHeightTag;\n    static const string _axisFontSizeTag;\n    static const string _ticWidthTag;\n    static const string _ticDirsTag;\n    static const string _ticSizeTag;\n    static const string _minTicsTag;\n    static const string _maxTicsTag;\n    static const string _numTicsTag;\n    static const string _axisOriginTag;\n    static const string _backgroundColorTag;\n    static const string _axisAnnotationEnabledTag;\n    static const string _axisAnnotationsTag;\n    static const string _latLonAxesTag;\n\n    static const string   _currentAxisDataMgrTag;\n    static vector<double> _previousStretch;\n\n    static const string _timeLLXTag;\n    static const string _timeLLYTag;\n    static const string _timeColorTag;\n    static const string _timeTypeTag;\n    static const string _timeSizeTag;\n\n    static const string _projStringTag;\n\nprivate:\n    void _init();\n\n    template<typename T> void m_getColor(T color[3], string tag) const\n    {\n        vector<double> defaultv(3, 1.0);\n        vector<double> val = GetValueDoubleVec(tag, defaultv);\n        for (int i = 0; i < val.size(); i++) {\n            color[i] = val[i];\n            if (color[i] < 0.0) color[i] = 0.0;\n            if (color[i] > 1.0) color[i] = 1.0;\n        }\n    }\n    // void m_getColor(double color[3], string tag) const;\n    void _getColor(vector<double> &color, string tag) const;\n    void m_setColor(vector<double> color, string tag, string msg);\n};\n\n};        // namespace VAPoR\n#endif    // ANNOTATIONPARAMS_H\n"
  },
  {
    "path": "include/vapor/AnnotationRenderer.h",
    "content": "//-- AnnotationRenderer.h ----------------------------------------------------------\n//\n//                   Copyright (C)  2011\n//     University Corporation for Atmospheric Research\n//                   All Rights Reserved\n//\n//----------------------------------------------------------------------------\n//\n//      File:           AnnotationRenderer.h\n//\n//      Author:         Alan Norton\n//\n//\n//      Description:  Definition of AnnotationRenderer class\n//\n//\n//\n//----------------------------------------------------------------------------\n\n#ifndef ANNOTATIONRENDERER_H\n#define ANNOTATIONRENDERER_H\n\n#include <vapor/Grid.h>\n#include <vapor/Renderer.h>\n#include <vapor/Transform.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/GLManager.h>\n\nnamespace VAPoR {\n\nclass DataStatus;\nstruct GLManager;\n\n//! \\class AnnotationRenderer\n//! \\brief Class that draws various geometry as specified by AnnotationParams\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date July 2015\n\nclass RENDER_API AnnotationRenderer : public MyBase {\nprivate:\n    struct billboard;\n\npublic:\n    //! Constructor, must invoke Renderer constructor\n    AnnotationRenderer(const ParamsMgr *pm, const DataStatus *dataStatus, string winName);\n\n    //! Method to initialize GL rendering.  Must be called from a GL context.\n    void InitializeGL(GLManager *glManager);\n\n    //! Destructor\n    virtual ~AnnotationRenderer();\n\n    //! Render the in-scene features\n    void InScenePaint(size_t ts);\n\n    //! Render the overlay features\n    void OverlayPaint(size_t ts);\n\n    void AddText(string text, int x, int y, int size, float color[3], int type = 0);\n    void AddTextNormalizedCoords(string text, float x, float y, int size, float color[3], int type = 0);\n\n    void DrawText();\n\n    void DrawText(vector<billboard> billboards);\n\n    void ClearText(int type = -1);\n\n    //! Draw Axis arrows\n    void DrawAxisArrows();\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Clear all the text objects\n    void invalidateCache();\n#endif\n\nprotected:\nprivate:\n    struct billboard {\n        string text;\n        double x;\n        double y;\n        float  xn;\n        float  yn;\n        int    size;\n        float  color[3];\n    };\n    vector<billboard> _billboards;\n    vector<billboard> _timeAnnot;\n    vector<billboard> _axisAnnot;\n    vector<billboard> _miscAnnot;\n\n    const ParamsMgr * m_paramsMgr;\n    const DataStatus *m_dataStatus;\n    string            m_winName;\n    GLManager *       _glManager;\n    int               _currentTimestep;\n    string            _fontFile;\n    string            _fontName;\n\n    void _drawAxes(std::vector<double> min, std::vector<double> max, std::vector<double> origin, std::vector<double> color, double width);\n    void _drawTic(double startPosn[], double endPosn[], double width, std::vector<double> color);\n    void _drawTimeAnnotation();\n\n    void _makeTransformMatrix(const Transform *transform, glm::mat4 &transformMatrix) const;\n\n    void _applyDataMgrCornerToDomain(std::vector<double> &domainExtents, const glm::vec4 &dataMgrCorner, const glm::mat4 &transformMatrix) const;\n\n    void _getDataMgrCorner(const int cornerNumber, glm::vec4 &dataMgrCorner, const CoordType &minDataMgrExtents, const CoordType &maxDataMgrExtents) const;\n\n    void _applyDataMgrToDomainExtents(std::vector<double> &domainExtents, const CoordType &dataMgrMinExts, const CoordType &dataMgrMaxExts, const Transform *transform) const;\n\n    void _calculateDomainExtents(std::vector<double> &domainExtents) const;\n\n    void drawDomainFrame(const std::vector<double> corners) const;\n\n    std::vector<double> getDomainExtents() const;\n    AxisAnnotation *    getCurrentAxisAnnotation();\n    string              getCurrentDataMgrName() const;\n    void                scaleNormalizedCoordinatesToWorld(std::vector<double> &coords, string dataMgrName);\n\n    //! Configure the MVP matrix for drawing axis orientation arrows.  These\n    //! arrows are drawn on top of the scene at an X/Y pixel location.  Users\n    //! define this location by selecting an X and Y value between 0 and 1,\n    //! which correspond to the minimum and maximum pixel id's on the X and Y\n    //! axes.\n    void _configureMatrixForArrows(MatrixManager *matrixManager);\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Render the region frame\n    void drawRegionBounds(size_t ts) const;\n#endif\n\n    // Draw the axis lines, while building text labels.\n    //\n    void drawAxisTics(AxisAnnotation *aa = NULL);\n    void drawAxisTics(AxisAnnotation *aa, std::vector<double> minTic, std::vector<double> maxTic);\n\n    void       applyTransform(Transform *t);\n    void       renderText(double text, double coords[], AxisAnnotation *aa = NULL);\n    Transform *getTransform(string dataMgr = \"\");\n    void       convertPointToLonLat(double &xCoord, double &yCoord);\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Static method to convert axis coordinates between user and lat-lon\n    //! It is OK for outputs to equal corresponding inputs.\n    //! \\param[in] toLatLon indicates whether conversion is to LatLon (true) or to user (false)\n    //! \\param[in] ticDirs are directions of tics on each axis.\n    //! \\param[in] fromMinTic is a 3-vector indicating minimum tic coordinates being mapped.\n    //! \\param[in] fromMaxTic is a 3-vector indicating maximum tic coordinates being mapped.\n    //! \\param[in] fromOrigin is a 3-vector indicating origin coordinates being mapped.\n    //! \\param[in] fromTicLength is a 3-vector indicating tic lengths before conversion\n    //! \\param[out] toMinTic is result 3-vector of minimum tic coordinates\n    //! \\param[out] toMaxTic is result 3-vector of maximum tic coordinates\n    //! \\param[out] toOrigin is result 3-vector of origin coordinates\n    //! \\param[out] toTicLength is a 3-vector indicating tic lengths after conversion\n    static void ConvertAxes(bool toLatLon, const vector<long> ticDirs, const vector<double> fromMinTic, const vector<double> fromMaxTic, const vector<double> fromOrigin,\n                            const vector<double> fromTicLength, double toMinTic[3], double toMaxTic[3], double toOrigin[3], double toTicLength[3]);\n\n    // This method converts lon lat to user coords, assuming a \"flat\" earth so axes will not wrap.\n    static void flatConvertFromLonLat(double x[2], double minLon, double maxLon, double minX, double maxX);\n\n#endif\n};\n\n};    // namespace VAPoR\n\n#endif    // ANNOTATIONRENDERER_H\n"
  },
  {
    "path": "include/vapor/AnnotationsParams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2015\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tAnnotationsParams.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune 2015\n//\n//\tDescription:\tDefines the AnnotationsParams class.\n//\t\tThis class supports parameters associted with the\n//\t\tvizfeature panel, describing the visual features in the visualizer\n//\n#ifndef ANNOTATIONSPARAMS_H\n#define ANNOTATIONSPARAMS_H\n\n#include <vector>\n\n#include <vapor/common.h>\n#include <vapor/ParamsBase.h>\n#include <vapor/AxisAnnotation.h>\n\nusing namespace Wasp;\n\nnamespace VAPoR {\n\nclass XmlNode;\n\n//! \\class AnnotationsParams\n//! \\ingroup Public_Params\n//! \\brief A class for describing visual features displayed in the visualizer.\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    June 2015\n\n//! The AnnotationsParams class controls various features displayed in the visualizers\n//! There is a global AnnotationsParams, that\n//! is shared by all windows whose vizfeature is set to \"global\".  There is also\n//! a local AnnotationsParams for each window, that users can select whenever there are multiple windows.\n//! When local settings are used, they only affect one currently active visualizer.\n//! The AnnotationsParams class also has several methods that are useful in setting up data requests from the DataMgr.\n//!\nclass PARAMS_API AnnotationsParams : public ParamsBase {\npublic:\n    //! Create a AnnotationsParams object from scratch\n    //\n    AnnotationsParams(ParamsBase::StateSave *ssave);\n\n    //! Create a AnnotationsParams object from an existing XmlNode tree\n    //\n    AnnotationsParams(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    //! Copy from already existing instance\n    //\n    AnnotationsParams(const AnnotationsParams &rhs);\n\n    virtual ~AnnotationsParams(){};\n\n    //! Obtain domain frame color\n    void GetDomainColor(double color[3]) const;\n    void GetDomainColor(std::vector<double> &color) const { _getColor(color, _domainColorTag); }\n\n    //! Set domain frame color\n    void SetDomainColor(vector<double> color);\n\n    bool GetUseDomainFrame() const { return (0 != GetValueLong(_domainFrameTag, (long)false)); }\n    void SetUseDomainFrame(bool onOff) { SetValueLong(_domainFrameTag, \"toggle domain frame\", (long)onOff); }\n\n    bool GetUseRegionFrame() const { return (0 != GetValueLong(_regionFrameTag, (long)false)); }\n    void SetUseRegionFrame(bool onOff) { SetValueLong(_regionFrameTag, \"toggle region frame\", (long)onOff); }\n\n    //! Obtain region frame color\n    void GetRegionColor(double color[3]) const;\n    void GetRegionColor(std::vector<double> &color) const { _getColor(color, _regionColorTag); }\n\n    //! Set region frame color\n    void SetRegionColor(vector<double> color);\n\n    //! Obtain background color\n    void GetBackgroundColor(double color[3]) const;\n    void GetBackgroundColor(std::vector<double> &color) const { _getColor(color, _backgroundColorTag); }\n\n    //! Set background color\n    void SetBackgroundColor(std::vector<double> color);\n\n    string GetCurrentAxisDataMgrName() const;\n    void   SetCurrentAxisDataMgrName(string dataMgr);\n\n    AxisAnnotation *GetAxisAnnotation(string dataMgr = \"\");\n\n    void                SetAxisArrowCoords(std::vector<double> coords);\n    std::vector<double> GetAxisArrowCoords() const;\n\n    bool GetShowAxisArrows() const;\n    void SetShowAxisArrows(bool val);\n\n    void SetAxisFontSize(int size);\n    int  GetAxisFontSize();\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"AnnotationsParams\"); }\n\nprivate:\n#ifdef VAPOR3_0_0_ALPHA\n    static void changeStretch(vector<double> prevStretch, vector<double> newStretch);\n#endif\n\n    ParamsContainer *_axisAnnotations;\n\n    static const string _domainColorTag;\n    static const string _domainFrameTag;\n    static const string _regionFrameTag;\n    static const string _regionColorTag;\n\n    static const string _axisColorTag;\n    static const string _axisDigitsTag;\n    static const string _axisTextHeightTag;\n    static const string _axisFontSizeTag;\n    static const string _ticWidthTag;\n    static const string _ticDirsTag;\n    static const string _ticSizeTag;\n    static const string _minTicsTag;\n    static const string _maxTicsTag;\n    static const string _numTicsTag;\n    static const string _axisOriginTag;\n    static const string _backgroundColorTag;\n    static const string _axisAnnotationEnabledTag;\n    static const string _axisAnnotationsTag;\n    static const string _latLonAxesTag;\n\n    static const string   _axisArrowCoordsTag;\n    static const string   _showAxisArrowsTag;\n    static const string   _currentAxisDataMgrTag;\n    static vector<double> _previousStretch;\n\n    void _init();\n\n    void m_getColor(double color[3], string tag) const;\n    void _getColor(vector<double> &color, string tag) const;\n    void m_setColor(vector<double> color, string tag, string msg);\n};\n\n};        // namespace VAPoR\n#endif    // ANNOTATIONSPARAMS_H\n"
  },
  {
    "path": "include/vapor/ArbitrarilyOrientedRegularGrid.h",
    "content": "#pragma once\n\n#include <ostream>\n#include <vector>\n#include <vapor/common.h>\n#include <vapor/RegularGrid.h>\n#include <glm/glm.hpp>\n\n// clang-format off\n\n//! A struct that describes a 2D plane that will sample a 3D grid through that grid's extents.\n//! The 2D plane will have an equal number of samples on its side, determined by sideSize.  Users\n//! will need to define an origin for the 2D plane, as well as its rotation in degrees on the X, Y,\n//! and Z axes.  \nstruct planeDescription {\n    size_t sideSize;\n    std::vector<double> origin;\n    std::vector<double> normal;\n    VAPoR::CoordType boxMin;\n    VAPoR::CoordType boxMax;\n};\n\nnamespace VAPoR {\n\n//! Create a 2D RegularGrid that is rotated along an arbitrary orientation.  This new grid\n//! samples a given 3D Grid object along a plane, through that grid's extents.  The \"planeDescription\" \n//! variable includes parameters that define the 2D plane's origin, rotation, and valid extents.  Points on the\n//! 2D RegularGrid that are outside of the valid extents will be assigned as missingValues.  This Grid class\n//! will always be valid, even if the the plane's description lies outside of the box.  In this case, the\n//! plane will contain all missing values.\n//!\n//! Note: The boxMin and boxMax values within the planeDescription should come from\n//! the current RenderParams' Box class.  \n//!\n//! \\param[in] grid3d A variable's 3D grid to be sampled along a plane, to generate a 2D grid object\n//! \\param[in] description A set of std::vector<dobule> values that define the origin, rotation, and extents of the returned 2D grid\n//! \\param[in] dims The sampling rate that the new grid will be defined upon, along its X and Y axes\n//! \\param[out] data An array of sideSize*sideSize values that contain floating point values of the sampled data.\n//!\n\nclass VDF_API ArbitrarilyOrientedRegularGrid : public RegularGrid {\npublic:\n    ArbitrarilyOrientedRegularGrid(\n        const VAPoR::Grid* grid3d,\n        planeDescription& pd,\n        const DimsType& dims\n    );\n\n    ArbitrarilyOrientedRegularGrid() = default;\n    virtual ~ArbitrarilyOrientedRegularGrid();\n\n    static std::string GetClassType() { return (\"ArbitrarilyOrientedRegular\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    //! \\copydoc Grid::GetUserCoordinates()\n    //\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override;\n\n    // Deleted fuctions that use CoordType\n    virtual void GetUserCoordinates (size_t i, size_t j, size_t k, double &x, double &y, double &z) = delete;\n    virtual void GetUserExtents (CoordType &minu, CoordType &maxu) = delete;\n    virtual void GetBoundingBox (const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) = delete;\n    virtual bool GetEnclosingRegion (const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) = delete;\n    virtual bool GetIndicesCell (const CoordType &coords, DimsType &indices) = delete;\n    virtual bool InsideGrid (const CoordType &coords) = delete;\n    virtual void ClampCoord (const CoordType &coords, CoordType &cCoords) = delete;\n    \n    static glm::vec3 GetNormalFromRotations(const std::vector<double> &rotations);\n    static std::pair<float, float> GetOffsetRange(const planeDescription &pd);\n\nprivate:\n    std::vector<glm::tvec2<double, glm::highp>> _rectangle2D;\n    size_t _sideSize;\n    glm::tvec3<double, glm::highp> _normal, _origin, _axis1, _axis2;\n    float* _myBlks;\n\n    void _makeEmptyGrid();\n\n    void _populateData(\n        const VAPoR::Grid *grid,\n        const planeDescription& description\n    );\n\n    void _getMinimumAreaRectangle(\n        const std::vector<glm::tvec3<double, glm::highp>>& vertices\n    );\n\n    void _findIntercepts(\n        const VAPoR::CoordType& boxMin,\n        const VAPoR::CoordType& boxMax,\n        std::vector<glm::tvec3<double, glm::highp>> &vertices\n    );\n\n    glm::tvec3<double, glm::highp> _getOrthogonal(\n        const glm::tvec3<double, glm::highp>& u\n    );\n    \n    void _rotate();\n};\n};    // namespace VAPoR\n\n// clang-format on\n"
  },
  {
    "path": "include/vapor/AxisAnnotation.h",
    "content": "#ifndef AXISANNOTATION_H\n#define AXISANNOTATION_H\n/*\n * This class describes a viewpoint\n */\n#include <vapor/ParamsBase.h>\n\nnamespace VAPoR {\n\n//! \\class AxisAnnotation\n//! \\ingroup Public_Params\n//! \\brief class that indicates location and direction of view\n//! \\author Scott Pearse\n//! \\version 3.0\n//! \\date January 2018\n\n//! \\par\n//! This class contains all the parameters associated with axis annotations,\n//! for a DataMgr or Renderer.\n\nclass PARAMS_API AxisAnnotation : public ParamsBase {\npublic:\n    enum Flags {};\n\n    AxisAnnotation(ParamsBase::StateSave *ssave);\n    AxisAnnotation(ParamsBase::StateSave *ssave, XmlNode *node);\n    virtual ~AxisAnnotation();\n\n    void Initialize();\n\n    void SetAxisAnnotationEnabled(bool val);\n    bool GetAxisAnnotationEnabled() const;\n\n    vector<double> GetAxisBackgroundColor() const;\n    void           GetAxisBackgroundColor(float bgColor[]) const;\n    void           SetAxisBackgroundColor(vector<double> color);\n\n    vector<double> GetAxisColor() const;\n    void           SetAxisColor(vector<double> color);\n\n    void           SetNumTics(vector<double> ticnums);\n    vector<double> GetNumTics() const;\n\n    void           SetAxisOrigin(vector<double> orig);\n    vector<double> GetAxisOrigin() const;\n\n    void           SetMinTics(vector<double> ticmins);\n    vector<double> GetMinTics() const;\n\n    void           SetMaxTics(vector<double> ticmaxs);\n    vector<double> GetMaxTics() const;\n\n    void           SetTicSize(vector<double> ticsizes);\n    vector<double> GetTicSize() const;\n\n    void SetXTicDir(double dir);\n    int  GetXTicDir() const;\n\n    void SetYTicDir(double dir);\n    int  GetYTicDir() const;\n\n    void SetZTicDir(double dir);\n    int  GetZTicDir() const;\n\n    void           SetTicDirs(vector<double> ticdirs);\n    vector<double> GetTicDirs() const;\n\n    double GetTicWidth() const;\n    void   SetTicWidth(double val);\n\n    long GetAxisTextHeight() const;\n    void SetAxisTextHeight(long val);\n\n    long GetAxisDigits() const;\n    void SetAxisDigits(long val);\n\n    void SetLatLonAxesEnabled(bool val);\n    bool GetLatLonAxesEnabled() const;\n\n    string GetDataMgrName() const;\n    void   SetDataMgrName(string dataMgr);\n\n    bool GetShowAxisArrows() const;\n    void SetShowAxisArrows(bool val);\n\n    void SetAxisFontSize(int size);\n    int  GetAxisFontSize() const;\n\n    bool GetAxisAnnotationInitialized() const;\n    void SetAxisAnnotationInitialized(bool val);\n\n    static string GetClassType() { return (\"AxisAnnotation\"); }\n\n    static const string _colorTag;\n    static const string _digitsTag;\n    static const string _textHeightTag;\n    static const string _fontSizeTag;\n    static const string _ticWidthTag;\n    static const string _ticDirsTag;\n    static const string _ticSizeTag;\n    static const string _minTicsTag;\n    static const string _maxTicsTag;\n    static const string _numTicsTag;\n    static const string _originTag;\n    static const string _backgroundColorTag;\n    static const string _annotationEnabledTag;\n    static const string _latLonAxesTag;\n    static const string _dataMgrTag;\n    static const string _initializedTag;\n};\n};    // namespace VAPoR\n\n#endif    // AXISANNOTATION_H\n"
  },
  {
    "path": "include/vapor/BOVCollection.h",
    "content": "#pragma once\n\n#include <array>\n#include <iostream>\n#include <vapor/MyBase.h>\n#include <vapor/utils.h>\n#include <vapor/DC.h>\n\nnamespace VAPoR {\n\nclass BOVCollection : public Wasp::MyBase {\npublic:\n    enum class parseCodes { PARSE_ERROR = -1, NOT_FOUND = 0, FOUND = 1 };\n\n    BOVCollection();\n    int Initialize(const std::vector<std::string> &paths);\n\n    std::vector<std::string>   GetDataVariableNames() const;\n    std::string                GetTimeDimension() const;\n    std::vector<float>         GetUserTimes() const;\n    float                      GetUserTime(size_t ts) const { return GetUserTimes()[ts]; };\n    std::array<size_t, 3>      GetDataSize() const;\n    std::array<std::string, 3> GetSpatialDimensions() const;\n    DC::XType                  GetDataFormat() const;\n    std::array<double, 3>      GetBrickOrigin() const;\n    std::array<double, 3>      GetBrickSize() const;\n\n    template<class T> int ReadRegion(std::string varname, size_t ts, const std::vector<size_t> &min, const std::vector<size_t> &max, T region);\n\nprivate:\n    std::string _currentFilePath;\n\n    float                    _time;\n    std::vector<float>       _times;\n    std::string              _dataFile;\n    std::vector<std::string> _dataFiles;\n    std::array<size_t, 3>    _gridSize;\n    DC::XType                _dataFormat;\n    std::string              _variable;\n    std::vector<std::string> _variables;\n    std::array<double, 3>    _brickOrigin;\n    std::array<double, 3>    _brickSize;\n    size_t                   _byteOffset;\n\n    // These values are currently parsed and assigned, but are unimplemented (not used)\n    bool                  _divideBrick;\n    std::string           _dataEndian;\n    std::string           _centering;\n    int                   _dataComponents;\n    std::array<size_t, 3> _dataBricklets;\n\n    // Placeholder variables to store values read from BOV descriptor files.\n    // These values must be consistent among BOV files, and are validated before\n    // assigning to \"actual\" values such as _gridSize, declaired above.\n    DC::XType             _tmpDataFormat;\n    std::array<double, 3> _tmpBrickOrigin;\n    std::array<double, 3> _tmpBrickSize;\n    size_t                _tmpByteOffset;\n\n    // Note - _tmpGridSize is an array of int type\n    //      - _gridSize is of type size_t\n    //      The reason for this is when we caluclate data indices like so...\n    //\n    //      int xSize = INT_MAX\n    //      int ySize = INT_MAX\n    //      int zSize = INT_MAX\n    //      size_t index = xSize*ySize*zSize;\n    //\n    //      ...the rvalue causes integer overflow.\n    //\n    //      _tmpGridSize cannot be an array of size_t because users may write\n    //      negative values.  The parser uses std::stringstream to convert\n    //      strings to different datatypes.  Unfortunately it does not fail when\n    //      converting negative string values such as \"-10\" to a size_t.  Rather,\n    //      it converts \"-10\" to a large positive value\".\n    //\n    //      Therefore, we read the values in with _tmpGridSize as integers,\n    //      and then assign the integers to _gridSize if validation passes.\n    //      (Validation in this case: ensure non-negative values, and consistency across files)\n    std::array<int, 3> _tmpGridSize;\n\n    bool _gridSizeAssigned;\n    bool _formatAssigned;\n    bool _brickOriginAssigned;\n    bool _brickSizeAssigned;\n    bool _byteOffsetAssigned;\n\n    // _dataFileMap allows us to access binary data files with a\n    // varname/timestep pair\n    std::map<std::string, std::map<float, std::string>> _dataFileMap;\n\n    std::array<std::string, 3> _spatialDimensions;\n    int                        _validateParsedValues();\n    std::string                _timeDimension;\n\n    int  _parseHeader(std::ifstream &header);\n    int  _populateDataFileMap();\n\n    template<typename T> int _findToken(const std::string &token, std::string &line, T &value, bool verbose = false);\n    template<typename T> int _findToken(const std::string &token, std::string &line, std::array<T, 3> &value, bool verbose = false);\n\n    void _findTokenValue(std::string &line) const;\n\n    int _sizeOfFormat(DC::XType) const;\n\n    int _invalidVarNameError() const;\n    int _invalidFileSizeError(size_t numElements) const;\n    int _invalidFileError() const;\n    int _invalidDimensionError(const std::string &token) const;\n    int _invalidFormatError(const std::string &token) const;\n    int _failureToReadError(const std::string &token) const;\n    int _inconsistentValueError(const std::string &token) const;\n    int _invalidValueError(const std::string &token) const;\n    int _missingValueError(const std::string &token) const;\n\n    static const std::string TIME_TOKEN;\n    static const std::string DATA_FILE_TOKEN;\n    static const std::string GRID_SIZE_TOKEN;\n    static const std::string FORMAT_TOKEN;\n    static const std::string VARIABLE_TOKEN;\n    static const std::string ORIGIN_TOKEN;\n    static const std::string BRICK_SIZE_TOKEN;\n    static const std::string OFFSET_TOKEN;\n\n    // These tokens are currently parsed but are not used\n    static const std::string ENDIAN_TOKEN;\n    static const std::string CENTERING_TOKEN;\n    static const std::string DIVIDE_BRICK_TOKEN;\n    static const std::string DATA_BRICKLETS_TOKEN;\n    static const std::string DATA_COMPONENTS_TOKEN;\n\n    static const double                _defaultTime;\n    static const std::string           _defaultFile;\n    static const DC::XType             _defaultFormat;\n    static const std::string           _defaultVar;\n    static const size_t                _defaultByteOffset;\n    static const std::array<double, 3> _defaultOrigin;\n    static const std::array<double, 3> _defaultBrickSize;\n    static const std::array<size_t, 3> _defaultGridSize;\n\n    // These defaults are currently unimplemented in the BOV reader logic\n    static const std::string           _defaultEndian;\n    static const std::string           _defaultCentering;\n    static const bool                  _defaultDivBrick;\n    static const std::array<size_t, 3> _defaultBricklets;\n    static const size_t                _defaultComponents;\n\n    static const std::string _xDim;\n    static const std::string _yDim;\n    static const std::string _zDim;\n    static const std::string _timeDim;\n\n    static const std::string _byteFormatString;\n    static const std::string _shortFormatString;\n    static const std::string _intFormatString;\n    static const std::string _floatFormatString;\n    static const std::string _doubleFormatString;\n};\n\n// Make gcc happy by moving template specialization outside of the class body\n//\ntemplate<> int BOVCollection::_findToken<DC::XType>(const std::string &token, std::string &line, DC::XType &value, bool verbose);\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/BarbParams.h",
    "content": "\n#ifndef BARBPARAMS_H\n#define BARBPARAMS_H\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\n//! \\class BarbParams\n//! \\brief Class that supports drawing Barbs based on 2D or 3D vector field\n//! \\author Scott Pearse\n//! \\version 3.0\n//! \\date June 2017\nclass PARAMS_API BarbParams : public RenderParams {\npublic:\n    BarbParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n\n    BarbParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~BarbParams();\n\n    bool GetNeedToRecalculateScales() const { return (bool)GetValueDouble(_needToRecalculateScalesTag, 0.0); }\n\n    void SetNeedToRecalculateScales(bool val);\n\n    //! Get the length scaling factor\n    //! \\retval double scale factor\n    //\n    double GetLengthScale() const { return GetValueDouble(_lengthScaleTag, 1.f); }\n\n    void SetLengthScale(double val) { SetValueDouble(_lengthScaleTag, \"Barb length\", val); }\n\n    //! Determine the size of the discrete grid\n    //! E.g. the grid on which barbs are placed.\n    //! \\retval vector<long> grid\n    const vector<long> GetGrid() const\n    {\n        vector<long> dims(3);\n        dims[0] = GetValueLong(_xBarbsCountTag, 10);\n        dims[1] = GetValueLong(_yBarbsCountTag, 10);\n        dims[2] = GetValueLong(_zBarbsCountTag, 1);\n        return dims;\n    }\n\n    //! Specify the size of a discrete grid\n    //! E.g. the grid on which barbs are placed.\n    //! \\param[in] int array of size 3 - Specifies the barb distribution on the X, Y, and Z axes.\n    void SetGrid(const int grid[3])\n    {\n        SetValueLong(_xBarbsCountTag, \"\", grid[0]);\n        SetValueLong(_yBarbsCountTag, \"\", grid[1]);\n        SetValueLong(_zBarbsCountTag, \"\", grid[2]);\n    }\n\n    //! Query line thickness as a multiplier that's applied to the default value.\n    //! \\retval double line thickness.\n    double GetLineThickness() const { return GetValueDouble(_thicknessScaleTag, 1.f); }\n\n    //! Set line thickness as a multiplier that's applied to the default value.\n    //! \\param[in] double - Line thickness.\n    void SetLineThickness(double val) { SetValueDouble(_thicknessScaleTag, \"Barb thickness\", val); }\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"BarbParams\"); }\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override\n    {\n        for (const auto &p : GetFieldVariableNames()) {\n            if (!p.empty()) return _dataMgr->GetVarTopologyDim(p);\n        }\n        return GetBox()->IsPlanar() ? 2 : 3;\n    }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override\n    {\n        if (UseSingleColor())\n            return \"\";\n        else\n            return GetColorMapVariableName();\n    }\n\nprotected:\n    virtual bool GetUseSingleColorDefault() const override { return true; }\n\nprivate:\n    void _init();\n\npublic:\n    static const string _needToRecalculateScalesTag;\n    static const string _lengthScaleTag;\n    static const string _thicknessScaleTag;\n    //! Number of barbs displayed on X axis\n    static const string _xBarbsCountTag;\n    //! Number of barbs displayed on Y axis\n    static const string _yBarbsCountTag;\n    //! Number of barbs displayed on Z axis\n    static const string _zBarbsCountTag;\n    static const string _alignGridTag;\n    static const string _alignGridStridesTag;\n    static const string _varsAre3dTag;\n\n};    // End of Class BarbParams\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/BarbRenderer.h",
    "content": "//**************************************************************\n//\n// Copyright (C) 2017\n// University Corporation for Atmospheric Research\n// All Rights Reserved\n//\n// *************************************************************\n\n#ifndef VAPOR_BARBRENDERER_H\n#define VAPOR_BARBRENDERER_H\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <vapor/DataMgr.h>\n#include <vapor/utils.h>\n#include <vapor/Renderer.h>\n#include <vapor/Grid.h>\n#include <vapor/BarbParams.h>\n\nnamespace VAPoR {\n\n//! \\class BarbRenderer\n//! \\brief Class that draws the barbs as specified by BarbParams\n//! \\author Scott Pearse and Alan Norton\n//! \\version 3.0\n//! \\date June 2017\n\nclass RENDER_API BarbRenderer : public Renderer {\npublic:\n    BarbRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    virtual ~BarbRenderer();\n\n    static string GetClassType() { return (\"Barb\"); }\n\nprotected:\n    virtual std::string _getColorbarVariableName() const;\n\nprivate:\n    vector<string> _fieldVariables;    // old, used instead of _currentVarname\n    double         _vectorScaleFactor;\n    double         _maxThickness;\n\n    vector<double> _currentBoxMinExts;\n    vector<double> _currentBoxMaxExts;\n\n    string         _currentHgtVar;\n    vector<double> _currentBoxMinExtsTex;\n    vector<double> _currentBoxMaxExtsTex;\n\n    double _maxValue;\n\n    void _getMagnitudeAtPoint(std::vector<VAPoR::Grid *> variables, float point[3]);\n\n    void _recalculateScales(std::vector<VAPoR::Grid *> &varData, int ts);\n\n    double _getDomainHypotenuse(size_t ts) const;\n\n    void _setDefaultLengthAndThicknessScales(size_t ts, const std::vector<VAPoR::Grid *> &varData, const BarbParams *bParams);\n\n    void _getGridRequirements(int &ts, int &refLevel, int &lod, CoordType &minExts, CoordType &maxExts) const;\n\n    //! \\copydoc Renderer::_initializeGL()\n    virtual int _initializeGL();\n\n    //! \\copydoc Renderer::_paintGL()\n    virtual int _paintGL(bool fast);\n\n    int _generateBarbs();\n\n    int _getVectorVarGrids(int ts, int refLevel, int lod, CoordType minExts, CoordType maxExts, std::vector<VAPoR::Grid *> &varData);\n\n    int _getVarGrid(int ts, int refLevel, int lod, string varName, CoordType minExts, CoordType maxExts, std::vector<VAPoR::Grid *> &varData);\n\n    void _setUpLightingAndColor();\n\n    void _reFormatExtents(vector<float> &rakeExts) const;\n\n    void _makeRakeGrid(vector<int> &rakeGrid) const;\n\n    //! Protected method that performs rendering of all barbs.\n    //! \\param[in] DataMgr* current DataMgr\n    //! \\param[in] const BarbParams* associated BarbParams\n    //! \\param[in] int actualRefLevel refinement level to be rendered.\n    //! \\param[in] float vectorScale Scale factor to be applied to barbs.\n    //! \\param[in] float barbRadius Radius of barbs in voxel diameters.\n    //! \\param[in] Grid Grid used in rendering.\n    //! The first three are the vector field, Grid[3] is the Height variable, Grid[4] is the color variable.\n    //! \\retval int zero if successful\n    //\tint performRendering(BarbParams* rParams,\n    //\t\tint actualRefLevel,\n    //\t\tvector <Grid *> variableData\n    //\t);\n\n    float _getHeightOffset(Grid *heightVar, float xCoord, float yCoord, bool &missing) const;\n\n    bool _makeCLUT(float clut[1024]) const;\n\n    void _getDirection(float direction[3], std::vector<Grid *> varData, float xCoord, float yCoord, float zCoord, bool &missing) const;\n\n    vector<double> _getScales();\n\n    float _calculateLength(float start[3], float end[3]) const;\n\n    void _makeStartAndEndPoint(float start[3], float end[3], float direction[3]);\n\n    void _getStrides(vector<float> &strides, vector<int> &rakeGrid, vector<float> &rakeExts) const;\n\n    bool _defineBarb(const std::vector<Grid *>, float start[3], float end[3], float *value, bool doColorMapping, const float clut[1024]);\n\n    void _operateOnGrid(vector<Grid *> variableData, bool drawBarb = true);\n\n    bool _getColorMapping(float val, const float clut[256 * 4]);\n\n    float _calculateDirVec(const float start[3], const float end[3], float dirVec[3]);\n\n    void _drawBackOfBarb(const float dirVec[3], const float startVertex[3]) const;\n\n    void _drawCylinderSides(const float nextNormal[3], const float nextVertex[3], const float startNormal[3], const float startVertex[3]) const;\n\n    void _drawBarbHead(const float dirVec[3], const float vertexPoint[3], const float startNormal[3], const float startVertex[3]) const;\n\n    //! Protected method to draw one barb (a hexagonal tube with a cone barbhead)\n    //! \\param[in] const float startPoint[3] beginning position of barb\n    //! \\param[in] const float endPoint[3] ending position of barb\n    // void drawBarb(const float startPoint[3], const float endPoint[3]);\n    void _drawBarb(const std::vector<Grid *> variableData, const float startPoint[3], bool doColorMapping, const float clut[1024]);\n\n    void _setBarbColor(float value, const float clut[1024], double crange[2]) const;\n\n    struct Barb;\n    void _drawBarb(Barb b, bool doColorMapping, const float clut[1024], double crange[2]);\n\n#ifdef DEBUG\n    _printBackDiameter(const float startVertex[18]) const;\n#endif\n\n    struct {\n        vector<string> fieldVarNames;\n        string         heightVarName;\n        string         colorVarName;\n        size_t         ts;\n        int            level;\n        int            lod;\n        bool           useSingleColor;\n        float          constantColor[3];\n        double         lineThickness;\n        double         opacity;\n        double         lengthScale;\n        vector<long>   grid;\n        vector<double> boxMin, boxMax;\n        float          minMapValue;\n        float          maxMapValue;\n        float          colorSamples[10][3];\n        float          alphaSamples[10];\n        bool           needToRecalc;\n    } _cacheParams;\n\n    bool _isCacheDirty() const;\n    void _saveCacheParams();\n\n    void _clearCache() { _cacheParams.fieldVarNames.clear(); }\n\n    struct Barb {\n        float startPoint[3];\n        float endPoint[3];\n        float value;\n        float lengthScalar;\n    };\n\n    vector<Barb> _barbCache;\n};\n\n};    // namespace VAPoR\n\n#endif    // VAPOR_BARBRENDERER_H\n"
  },
  {
    "path": "include/vapor/Base16StringStream.h",
    "content": "#pragma once\n\n#include <streambuf>\n#include <ostream>\n#include <istream>\n#include <memory>\n#include <vapor/common.h>\n\n\n//! \\class Base16StreamBuf\n//!\n//! \\brief A custom std stream buffer that saves data piped through it into a base16 encoded string.\n//!\n//! \\author Stanislaw Jaroszynski\n\nclass COMMON_API Base16StreamBuf : public std::streambuf {\npublic:\n    std::string      _string;\n    int              _i = 0;\n    virtual int_type overflow(int_type c) override;\n};\n\n\n//! \\class Base16StringStream\n//!\n//! \\brief An implementation similar to std::stringstream which results in a base16 encoded string.\n//!\n//! \\author Stanislaw Jaroszynski\n\nclass COMMON_API Base16StringStream : public std::ostream {\n    Base16StreamBuf _buf;\n\npublic:\n    Base16StringStream() : std::ostream(&_buf) {}\n    const std::string &ToString() { return _buf._string; }\n};\n\n\n\n//! \\class Base16DecoderStream\n//!\n//! \\brief Creates a raw std istream from a base16 encoded string.\n//!\n//! \\author Stanislaw Jaroszynski\n\nclass COMMON_API Base16DecoderStream : public std::istream {\n    struct MemBuf : std::streambuf {\n        MemBuf(char *buf, size_t size) { this->setg(buf, buf, buf + size); }\n    };\n\n    static void Base16Decode(const std::string &in, char *out);\n\n    std::unique_ptr<char> _data;\n    MemBuf                _buf;\n\npublic:\n    Base16DecoderStream(const std::string &s);\n};\n"
  },
  {
    "path": "include/vapor/BlkMemMgr.h",
    "content": "//\n//      $Id$\n//\n\n#ifndef _BlkMemMgr_h_\n#define _BlkMemMgr_h_\n\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\n\n//\n//! \\class BlkMemMgr\n//! \\brief The Wasp BlkMemMgr class\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! A block-based memory allocator. Allocates contiguous runs of\n//! memory blocks from a memory pool of user defined size.\n//!\n//! N.B. the memory pool is stored in a static class member and\n//! can only be freed by calling RequestMemSize() with a zero value\n//! after all instances of this class have been destroyed\n//\nclass BlkMemMgr : public Wasp::MyBase {\npublic:\n    //! Initialize a memory allocator\n    //\n    //! Initialize a block-based memory allocator\n    //\n    BlkMemMgr();\n    virtual ~BlkMemMgr();\n\n    //! Alloc space from memory pool\n    //\n    //! Return a pointer to the specified amount of memory from the memory pool\n    //! \\param[in] num_blks Size of memory region requested in blocks\n    //! \\param[in] fill If true, the allocated memory will be cleared to zero\n    //! \\retval ptr A pointer to the requested memory pool\n    //\n    void *Alloc(size_t num_blks, bool fill = false);\n\n    //! Free memory\n    //\n    //! Frees memory previosly allocated with the \\b Alloc() method.\n    //! \\param[in] ptr Pointer to memory returned by previous call to\n    //! \\b Alloc().\n    void FreeMem(void *ptr);\n\n    //! Set the size of the memory pool used by the memory allocator\n    //\n    //! Initialize a block-based memory allocator. The static memory pool\n    //! is not changed until the first instance of an object of this\n    //! class is created, or if there are no instances of objects the\n    //! memmory pool is changed immediately. The only way to free memory\n    //! from the static memory pool is to call this static method with\n    //! either \\p blk_size or \\p num_blks set to zero.\n    //!\n    //! \\param[in] blk_size Size of a single memory block in bytes\n    //! \\param[in] num_blks Size of memory pool in blocks. This is the\n    //! maximum amount that will be available through subsequent\n    //! \\b Alloc() calls.\n    //! \\param[in] page_aligned If true, start address of memory pool\n    //! will be page aligned\n    //\n    static int RequestMemSize(size_t blk_size, size_t num_blks, bool page_aligned = true);\n\n    static size_t GetBlkSize() { return (_blk_size); }\n\nprivate:\n    typedef struct {\n        size_t _nfree;    // number of contiguous free blocks\n        size_t _nused;    // number of contiguous used blocks\n        void * _blk;      // pointer to first free/used block\n    } _mem_allocation_t;\n\n    static vector<vector<_mem_allocation_t>> _mem_regions;\n    static vector<size_t>                    _mem_region_sizes;    // size of mem in blocks\n    static vector<unsigned char *>           _blks;                // memory pool\n\n    static size_t _mem_size_max_req;    // max requested size of mem in blocks\n    static bool   _page_aligned_req;    // requested page align memory\n    static size_t _blk_size_req;        // requested size of block in bytes\n\n    static size_t _mem_size_max;    // max size of mem in blocks\n    static bool   _page_aligned;    // page align memory\n    static size_t _blk_size;        // size of block in bytes\n\n    static int _ref_count;    // # instances of object.\n\n    static int _Reinit(size_t n);\n};\n};    // namespace VAPoR\n\n#endif    //\t_BlkMemMgr_h_\n"
  },
  {
    "path": "include/vapor/BookmarkParams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tBookmarkParams\n//\n//\tAuthor:\t\tStas Jaroszynski\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n\n#pragma once\n\n#include <vapor/ParamsBase.h>\n\nclass MouseModeParams;\n\nclass PARAMS_API BookmarkParams : public VAPoR::ParamsBase {\npublic:\n    BookmarkParams(VAPoR::ParamsBase::StateSave *ssave);\n    BookmarkParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node);\n    BookmarkParams(const BookmarkParams &rhs);\n\n    static string GetClassType() { return (\"BookmarkParams\"); }\n\n    static const string NameTag;\n    static const string DataTag;\n    static const string IconDataTag;\n    static const string IconSizeTag;\n\n    void   SetName(const string &name) { SetValueString(NameTag, \"\", name); }\n    string GetName() const { return GetValueString(NameTag, \"\"); }\n\n    void   SetData(const string &data) { SetValueString(DataTag, \"\", data); }\n    string GetData() const { return GetValueString(DataTag, \"\"); }\n\n    string GetIconData() const { return GetValueString(IconDataTag, \"\"); }\n    int    GetIconSize() const { return GetValueLong(IconSizeTag, 0); }\n\n    size_t GetIconDataSize() const\n    {\n        size_t s = GetIconSize();\n        return s * s * 3;\n    }\n\n    void SetIcon(int size, const string &data)\n    {\n        SetIconData(data);\n        SetIconSize(size);\n    }\n\n    static int DefaultIconSize() { return 32; }\n\nprivate:\n    void SetIconData(const string &data) { SetValueString(IconDataTag, \"\", data); }\n    void SetIconSize(int size) { SetValueLong(IconSizeTag, \"\", size); }\n    void _init();\n};\n"
  },
  {
    "path": "include/vapor/Box.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2011\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tBox.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tApril 2011\n//\n//\tDescription:\tDefines the Box class\n//\t\tThis supports control of a 2D or 3D box-shaped region that can be\n//\t\trotated and changed over time.\n//\n#ifndef BOX_H\n#define BOX_H\n\n#include <vapor/ParamsBase.h>\n#include <vapor/Grid.h>\n\nnamespace VAPoR {\n\n//! \\class Box\n//! \\ingroup Public_Params\n//! \\brief 3D or 2D box with options for orientation angles .\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    March 2014\n\n//! The Box class supports various rectangular boxes, possibly rotated,\n//! used in VAPOR to specify extents and also used in Manipulators.\n//!\nclass PARAMS_API Box : public ParamsBase {\npublic:\n    enum Orientation { XY = 0, XZ = 1, YZ = 2, XYZ = 3 };\n\n    //! Create a Box object from scratch\n    //\n    Box(ParamsBase::StateSave *ssave, string name = Box::GetClassType());\n\n    //! Create a Box object from an existing XmlNode tree\n    //\n    Box(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~Box();\n\n    //! Set the box min and max extents\n    //!\n    //! Set the extents of the box.\n    //!\n    //! \\param[in] minExt 2 or 3-element vector containing the minimum coordinates\n    //! of the box, specified in the order X, Y, Z\n    //! \\param[in] maxExt 2 or 3-element vector containing the maximum coordinates\n    //! of the box, specified in the order X, Y, Z\n    //!\n    //\n    virtual void SetExtents(const vector<double> &minExt, const vector<double> &maxExt);\n    virtual void SetExtents(const VAPoR::CoordType &minExt, const VAPoR::CoordType &maxExt);\n\n    //! Get the box min and max extents\n    //!\n    //! Get the box's coordinate extents.  If IsPlanar() is true a 2-element\n    //! array is returned for \\p minExt and \\p maxExt, if false a\n    //! 3-element array is returned.\n    //!\n    //! \\param[out] minExt 2 or 3-element vector containing the minimum\n    //! coordinates\n    //! of the box, specified in the order X, Y, Z\n    //! \\param[out] maxExt 2 or 3-element vector containing the\n    //! maximum coordinates\n    //! of the box, specified in the order X, Y, Z\n    //!\n    //! \\sa IsPlanar(), GetOrientation(), SetExtents()\n    //\n    void GetExtents(vector<double> &minExt, vector<double> &maxExt) const;\n    void GetExtents(VAPoR::CoordType &minExt, VAPoR::CoordType &maxExt) const;\n\n    //! Indicate whether or not the box is constrained to be planar.\n    //!\n    //! \\retval bool True if the box is planar\n    //!\n    //! \\sa GetOrientation()\n    //\n    bool IsPlanar() const;\n\n    //! Constain the box to be planar or not\n    //!\n    //! Set the value of the planar state, indicating whether or not\n    //! the box is constrained to be planar.\n    //!\n    //! \\param[in] value bool indicates whether or be planar\n    //!\n    //! \\sa SetExtents()\n    //\n    void SetPlanar(bool value);\n\n    //! Indicate the orientation of a (2D) box\n    //! This is 0,1, or 2 based on the axis orthogonal to the box.\n    //! A 0 indiciates the XY plane, 1 indicates the XZ plane, and 2 YZ plane\n    //! axis.\n    //!\n    //! \\retval int The plane that the box resides in, if planar. Otherwise\n    //! the return value is meaningless.\n    //!\n    //! \\sa IsPlanar()\n    //\n    int GetOrientation() const { return GetValueLong(Box::m_orientationTag, XY); }\n\n    //! Set the value of the orientation state, indicating the axis\n    //! orthogonal to a 2D box\n    //!\n    //! \\param[in] value long indicates the orientation value\n    //!\n    //! \\sa IsPlanar(), GetOrientation()\n    //\n    void SetOrientation(long value) { SetValueLong(Box::m_orientationTag, \"Set box orientation\", (long)value); }\n\n#if 0\n\t//! Get the stretched local box extents as a float array.  If timestep is >= 0, then get it just\n\t//! for the specified timestep\n\t//! \\param[out] extents[6] float Returned extents\n\t//! \\param[in] timestep int Specific time step being retrieved, or -1 for generic time steps\n\t//! \\retcode int zero if successful.\n\tint GetStretchedLocalExtents(double extents[6], int timestep = -1);\n\n\t//! Get the local box extents as a vector.  First 6 values are default; additional\n\t//! values are associated with non-default regions\n\t//! \\sa GetTimes()\n\t//!\n\t//! \\param[out] extents const vector<double>& returned extents\n\tvector<double>  GetLocalExtents() const \n  { \n    const vector<double> localExtents(6, 0);\n\t\treturn GetValueDoubleVec(_extentsTag, localExtents);\n\t}\n\n\t//! Specify the local extents.  If time step is -1, then set the generic extents.\n\t//! Otherwise set the extents for a specific timestep.\n\t//! \\param[in] extents vector<double>& Six doubles that will be new extents\n\t//! \\param[in] timestep int Specified time step, or -1 for generic times\n\t//! \\retval int zero if successful.\n\tvoid SetLocalExtents(const vector<double>& extents, int timestep = -1);\n\n\tvoid SetLocalExtents(\n\t\tconst vector<double>& minExt, const vector<double>& maxExt, \n\t\tint timestep = -1\n\t) {\n\t\tVAssert(minExt.size() == maxExt.size() && minExt.size() == 3);\n\t\tvector <double> extents = minExt;\n\t\textents.insert(extents.end(), maxExt.begin(), maxExt.end());\n\t\tSetLocalExtents(extents, timestep);\n\t}\n\n\t//! Specify the local extents as a double array.  If time step is -1, then set the generic extents.\n\t//! Otherwise set the extents for a specific timestep.\n\t//! \\param[in] double extents[6] 6 doubles that will be new extents\n\t//! \\param[in] int timestep specified time step, or -1 for generic times\n\t//! \\retval int zero if successful.\n\tvoid SetLocalExtents(const double extents[6], int timestep = -1);\n\n\t//! Specify the local extents as a float array.  If time step is -1, then set the generic extents.\n\t//! Otherwise set the extents for a specific timestep.\n\t//! \\param[in] float extents[6]\n\t//! \\param[in] int timestep specified time step, or -1 for generic times\n\t//! \\retval int zero if successful.\n\tvoid SetLocalExtents(const float extents[6], int timestep = -1);\n#endif\n\n#if 0\n\t//! Specify the stretched local extents as a float array.  If time step is -1, then set the generic extents.\n\t//! Otherwise set the extents for a specific timestep.\n\t//! \\param[in] float extents[6]\n\t//! \\param[in] int timestep specified time step, or -1 for generic times\n\t//! \\retval int zero if successful.\n\tvoid SetStretchedLocalExtents(const double extents[6], int timestep = -1);\n#endif\n\n    //! Get the three orientation angles (theta, phi, psi)\n    //! Defaults to empty vector if no angles are set.\n    //! \\retval const vector<double> vector of length 3 of angles.\n    vector<double> GetAngles() const\n    {\n        const vector<double> defaultAngles(3, 0.);\n        return GetValueDoubleVec(Box::m_anglesTag, defaultAngles);\n    }\n\n#if 0\n\t//! Get the angles as a double array\n\t//! \\param [out] double angles[3] array of three doubles for theta, phi, psi\n\t//! \\retval int zero if successful\n\tvoid GetAngles(double ang[3]){\n\t\tconst vector<double> angv = GetAngles();\n\t\tfor (int i=0; i<3; i++) ang[i] = angv[i];\n\t}\n\n\t//! Get the angles as a float array\n\t//! \\param [out] angles[3] float array of three floats for theta, phi, psi\n\t//! \\retval zero if successful\n\tvoid GetAngles(float ang[3]){\n\t\tconst vector<double> angv = GetAngles();\n\t\tfor (int i=0; i<3; i++) ang[i] = angv[i];\n\t}\n#endif\n\n    //! Set the angles from a double array\n    //! \\param [in] ang double[3] array of three doubles for theta, phi, psi\n    //! \\retval int zero on success\n    void SetAngles(const double angles[3])\n    {\n        vector<double> ang;\n        for (int i = 0; i < 3; i++) ang.push_back(angles[i]);\n        SetValueDoubleVec(m_anglesTag, \"change box angles\", ang);\n    }\n\n    //! Set the angles from a float array\n    //! \\param [in] angles float[3] array of three floats for theta, phi, psi\n    //! \\retval int zero on success\n    void SetAngles(const float angles[3])\n    {\n        vector<double> angl;\n        for (int i = 0; i < 3; i++) angl.push_back((double)angles[i]);\n        SetValueDoubleVec(m_anglesTag, \"change box angles\", angl);\n    }\n\n    //! Set the three orientation angles (theta, phi, psi) from a vector of doubles\n    //! \\param[in] vals const vector<double>& vector of length 3 of angles.\n    void SetAngles(const vector<double> &vals) { SetValueDoubleVec(m_anglesTag, \"Change box angles\", vals); }\n#if 0\n\t//! Get the time(s) as a long vector.\n\t//! The first one should be negative, marking the default extents.\n\t//! Subsequent times are nonnegative integers indicating times for nondefault extents.\n\t//! Number of times should be 1/6 of the number of extents values\n\t//! \\sa GetExtents()\n\t//! \\retval vector<long>& vector of longs\n\tconst vector<long> GetTimes() { \n\t\treturn( GetValueLongVec(Box::_timesTag));\n\t}\n\t//! Set the time(s) as a long vector.\n\t//! The first one should be negative, marking the default extents.\n\t//! Subsequent times are nonnegative integers indicating times for nondefault extents.\n\t//! This vector should be the same size as the extents vector.\n\t//! \\param [in] const vector<long>& vector of times\n\tvoid SetTimes(const vector<long>& times) { \n\t\tSetValueLongVec(Box::_timesTag, \"Change box times\",times);\n\t}\n\n\tvoid buildLocalCoordTransform(\n\t\tdouble transformMatrix[12], double extraThickness, \n\t\tint timestep, double rotation = 0., int axis= -1\n\t) const;\n#endif\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"BoxParams\"); }\n\nprivate:\n#if 0\n//! method supports rotated boxes such as probe\n//! Specifies an axis-aligned box containing the rotated box.\n//! By default it just finds the box extents.\n//! Caller must supply extents array, which gets its values filled in.\n//! \\param[out] float[6] Extents of containing box\n//! \\params[in] rotated indicates if the box is possibly rotated\n\tvoid calcContainingBoxExtents(\n\t\tdouble extents[6], bool rotated = false\n\t) const {\n\n\t\tif (!rotated) GetLocalExtents(extents,-1);\n\t\telse calcRotatedBoxExtents(extents);\n\n\t}\n\n//! If the box is rotated, this method calculated the minimal axis-aligned extents\n//! containing all 8 corners of the box.\n//! \\param[out] double extents[6] is smallest extents containing the box.\n\tvoid calcRotatedBoxExtents(double extents[6]) const;\n\n//! method supports rotated boxes such as probe\n//! Specifies an axis-aligned box containing the stretched rotated box.\n//! By default it just finds the box extents.\n//! Caller must supply extents array, which gets its values filled in.\n//! \\param[out] float[6] Extents of containing box\n//! \\params[in] rotated indicates if the box is possibly rotated\n\tvoid calcContainingStretchedBoxExtents(\n\t\tdouble extents[6], bool rotated = false\n\t) const {\n\n\t\tVAssert( ! rotated);\n\t\tif (!rotated) GetStretchedLocalExtents(extents,-1);\n\t\t//else calcRotatedStretchedBoxExtents(extents);\n\n\t}\n\n\n//! If the box is rotated, this method calculated the minimal axis-aligned extents\n//! of a stretched box containing all 8 corners of the box.\n//! \\param[out] double extents[6] is smallest extents containing the box.\n\tvoid calcRotatedStretchedBoxExtents(\n\t\tvector <double> stretchFactors, double extents[6]\n\t) const;\n\n\n\t//Used only by params with rotated boxes:\n\tbool cropToBox(const double boxExts[6]);\n\tbool intersectRotatedBox(double boxexts[6], double pointFound[3], double probeCoords[2]);\n\tbool fitToBox(const double boxExts[6]);\n\tvoid setBoxToExtents(const double extents[6]);\n\tint interceptBox(const double boxExts[6], double intercept[6][3]);\n\n\tvoid getRotatedVoxelExtents(string varname, float voxdims[2], int numRefinements);\n\n\n\tvoid rotateAndRenormalize(int axis, double rotVal);\n\t///@}\n\n\n\tvoid convertThetaPhiPsi(\n\t\tdouble *newTheta, double* newPhi, double* newPsi, \n\t\tint axis, double rotation\n\t) const;\n\n\t//Not part of public API\n\tvoid calcLocalBoxCorners(\n\t\tdouble corners[8][3], float extraThickness, int timestep, \n\t\tdouble rotation = 0., int axis = -1\n\t) const ;\n\n#endif\n\npublic:\n    static const string m_anglesTag;\n    static const string m_extentsTag;\n    static const string m_planarTag;\n    static const string m_orientationTag;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/CFuncs.h",
    "content": "//\n//      $Id$\n//\n//************************************************************************\n//\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t*\n//     University Corporation for Atmospheric Research\t\t*\n//\t\t     All Rights Reserved\t\t\t*\n//\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tMon Nov 29 11:49:03 MST 2004\n//\n//\tDescription:\tA collection of common C system routines that\n//\t\t\t\t\taren't always portable across OS platforms\n//\n\n#ifndef _CFuncs_h_\n#define _CFuncs_h_\n\n#include <cmath>\n#include <string>\n#include <vapor/common.h>\n\nnamespace Wasp {\n\nCOMMON_API void Splitpath(std::string path, std::string &volume, std::string &dir, std::string &file, bool nofile);\n\nCOMMON_API double GetTime();\n\nCOMMON_API int MkDirHier(const std::string &dir);\n\nCOMMON_API std::string GetEnvironmentalVariable(const std::string &name);\n\n};    // namespace Wasp\n\n#endif    // _CFuncs_h_\n"
  },
  {
    "path": "include/vapor/CMakeConfig.h",
    "content": "#ifndef CMAKECONFIG_H\n#define CMAKECONFIG_H\n\n#include <string>\n\n#define CMakeConfigStringType std::string\n\nextern const int MAJOR;\nextern const int MINOR;\nextern const int MICRO;\n\nextern const CMakeConfigStringType VERSION_RC;\nextern const CMakeConfigStringType VERSION_DATE;\nextern const CMakeConfigStringType VERSION_COMMIT;\nextern const CMakeConfigStringType VERSION_STRING;\nextern const CMakeConfigStringType VERSION_STRING_FULL;\n\nextern const CMakeConfigStringType BUILD_TYPE;\nextern const CMakeConfigStringType SOURCE_DIR;\nextern const CMakeConfigStringType THIRD_PARTY_DIR;\n\nextern const CMakeConfigStringType PYTHON_VERSION;\nextern const CMakeConfigStringType PYTHON_DIR;\nextern const CMakeConfigStringType PYTHON_PATH;\n\n#endif\n"
  },
  {
    "path": "include/vapor/CalcEngineMgr.h",
    "content": "#pragma once\n\n#include <vector>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\nclass DataStatus;\nclass ParamsMgr;\nclass PyEngine;\nclass ControlExec;\n\n//! \\class CalcEngineMgr\n//! \\brief A class for managing CalcEngine class instances\n//! \\author John Clyne\n//\nclass RENDER_API CalcEngineMgr : public Wasp::MyBase {\npublic:\n    //! Constructor for CalcEngineMgr class\n    //!\n    //! \\param[in] dataMgr A pointer to a DataMgr instance upon which derived\n    //! variables created by this class will be managed.\n    //\n    CalcEngineMgr(DataStatus *dataStatus, ParamsMgr *paramsMgr)\n    {\n        VAssert(dataStatus != NULL);\n        VAssert(paramsMgr != NULL);\n\n        _dataStatus = dataStatus;\n        _paramsMgr = paramsMgr;\n    }\n\n    ~CalcEngineMgr();\n\n    int AddFunction(string scriptType, string dataSetName, string scriptName, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames,\n                    const vector<string> &outputVarMeshes, bool coordFlag = false);\n\n    void RemoveFunction(string scriptType, string dataSetName, string scriptName);\n\n    bool GetFunctionScript(string scriptType, string datasetName, string scriptName, string &script, vector<string> &inputVarNames, vector<string> &outputVarNames, vector<string> &outputVarMeshes,\n                           bool &coordFlag);\n\n    string GetFunctionStdout(string scriptType, string dataSetName, string scriptName);\n\n    std::vector<string> GetFunctionNames(string scriptType, string datasetName);\n\n    //! Rebuild from params database\n    //!\n    //! When invoked this method rebuilds internal state using the ParamsMgr\n    //! \\p paramsMgr passed in to the constructor\n    //\n    void ReinitFromState();\n\n    //! Remove all functions added with AddFunction()\n    //!\n    //! \\sa AddFunction()\n    void Clean() { _clean(); }\n\n    void SyncWithParams();\n\nprivate:\n    const DataStatus *_dataStatus;\n    const ParamsMgr * _paramsMgr;\n\n    CalcEngineMgr() {}\n    void _clean();\n    void SetCacheDirty() {\n        _isDataCacheDirty = true;\n        _wasCacheDirty = true;\n    }\n\n    std::map<string, PyEngine *> _pyScripts;\n\n    bool _isDataCacheDirty;\n    bool _wasCacheDirty;\n    friend class ControlExec;\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/ColorMap.h",
    "content": "//--ColorMap.h ---------------------------------------------------------\n//\n// Copyright (C) 2006 Kenny Gruchalla.  All rights reserved.\n//\n// A map from data value to/from color.\n//\n//----------------------------------------------------------------------------\n\n#ifndef ColorMap_H\n#define ColorMap_H\n\n#include <vapor/ParamsBase.h>\n#include <vapor/TFInterpolator.h>\n\nnamespace VAPoR {\n\nclass PARAMS_API ColorMap : public ParamsBase {\npublic:\n    class PARAMS_API Color {\n    public:\n        Color();\n        Color(float h, float s, float v);\n        Color(double h, double s, double v);\n        Color(const Color &color);\n\n        void toRGB(float *rgb) const;\n\n        void  hue(float h) { _hue = h; }\n        float hue() const { return _hue; }\n\n        void  sat(float s) { _sat = s; }\n        float sat() const { return _sat; }\n\n        void  val(float v) { _val = v; }\n        float val() const { return _val; }\n\n    private:\n        float _hue;\n        float _sat;\n        float _val;\n    };\n\n    //! Create a ColorMap object from scratch\n    //\n    ColorMap(ParamsBase::StateSave *ssave);\n\n    //! Create a ColorMap object from an existing XmlNode tree\n    //\n    ColorMap(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~ColorMap();\n\n    void clear();\n\n    TFInterpolator::type GetInterpType() const\n    {\n        long defaultv = TFInterpolator::diverging;\n        return (TFInterpolator::type)GetValueLong(_interpTypeTag, defaultv);\n    }\n    void SetInterpType(TFInterpolator::type t);\n    void SetUseWhitespace(bool enabled);\n    bool GetUseWhitespace() const;\n\n    int numControlPoints() const { return (int)(GetControlPoints().size() / 4); }\n\n    Color controlPointColor(int index) const;\n    void  controlPointColor(int index, Color color);\n\n    float controlPointValue(int index) const;    // Data Coordinates\n    float controlPointValueNormalized(int index) const;\n    void  controlPointValue(int index, float value);    // Data Coordinates\n    void  controlPointValueNormalized(int index, float value);\n\n    void addControlPointAt(float value);\n    int  addNormControlPointAt(float value);\n    void addControlPointAt(float value, Color color);\n    int  addNormControlPoint(float normValue, Color color);\n    void deleteControlPoint(int index);\n\n    void move(int index, float delta);\n\n    Color color(float value) const;\n    Color colorNormalized(float nv) const;\n    Color getDivergingColor(float ratio, float index) const;\n    Color getCorrectiveDivergingColor(float ratio, float index) const;\n\n    // Method to obtain the control points as a double vector, with\n    // 4 entries for each control point\n    // in the order hue,sat,value, datavalue\n    vector<double> GetControlPoints() const;\n\n    void SetControlPoints(const vector<double> &controlPoints);\n\n    //!\n    //! The minimum value is stored as normalized coordinates in the parameter\n    //! space. Therefore, the color map will change relative to any changes in\n    //! the parameter space. True???\n    //\n    void           SetDataBounds(const vector<double> &bounds);\n    vector<double> GetDataBounds() const;\n\n    float minValue() const { return (GetDataBounds()[0]); }\n    float maxValue() const { return (GetDataBounds()[1]); }\n\n    void Reverse();\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"ColorMapParams\"); }\n\npublic:\n    static const string _controlPointsTag;\n    static const string _interpTypeTag;\n    static const string _useWhitespaceTag;\n    static const string _dataBoundsTag;\n\nprivate:\n    int leftIndex(float val) const;\n};\n\nclass PARAMS_API ARGB {\npublic:\n    ARGB(int r, int g, int b) { _argbvalue = ((r & 255) << 16) | ((g & 255) << 8) | (b & 255); }\n\nprivate:\n    unsigned int _argbvalue;\n};\n};    // namespace VAPoR\n\n#endif    // ColorMap_H\n"
  },
  {
    "path": "include/vapor/ColorbarPbase.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tColorbarPbase.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tFebruary 2016\n//\n//\tDescription:\tDefines the ColorbarPbase class, derived from ParamsBase.\n//\t\tThis supports parameters controlling the display of color bars.\n//\n#ifndef COLORBARPBASE_H\n#define COLORBARPBASE_H\n\n#include <vapor/ParamsBase.h>\n\nnamespace VAPoR {\n\n//! \\class ColorbarPbase\n//! \\ingroup Public_Params\n//! \\brief Settings for color bar displayed in scene\n//! Intended to be used in any Params class\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date   February 2016\n\n//! The ColorbarPbase class is a ParamsBase class that manages the settings associated with a color bar.\n//! There is a corresponding ColorbarFrame class in the GUI that manages display of these settings.\n//!\n//!\n//!\nclass PARAMS_API ColorbarPbase : public ParamsBase {\npublic:\n    //! Create a ColorbarPbase object from scratch\n    //\n    ColorbarPbase(ParamsBase::StateSave *ssave);\n\n    //! Create a ColorbarPbase object from an existing XmlNode tree\n    //\n    ColorbarPbase(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~ColorbarPbase();\n\n    //! Get the X,Y corner (upper left) coordinates\n    //! Relative to [0,1]\n    //! \\retval pair of x,y coordinates\n    vector<double> GetCornerPosition() const;\n\n    //! Set the X,Y corner (upper left) coordinates\n    //! Relative to [0,1]\n    //! \\param[in] posn = x,y coordinates\n    void SetCornerPosition(vector<double> posn);\n\n    //! Get the X,Y size\n    //! Relative to [0,1]\n    //! \\retval pair of x,y sizes\n    vector<double> GetSize() const;\n\n    //! Set the X,Y sizes\n    //! Relative to [0,1]\n    //! \\param[in] posn = x,y sizes\n    void SetSize(vector<double> sz);\n\n    //! Get the title text\n    //! (displayed after variable name)\n    //! \\retval title\n    string GetTitle() const { return GetValueString(_colorbarTitleTag, \"\"); }\n\n    //! Set the title text\n    //! \\param[in] text to display\n    void SetTitle(string text) { SetValueString(_colorbarTitleTag, \"Set colorbar title\", text); }\n\n    //! Determine if colorbar is enabled\n    //! \\return true if enabled\n    bool IsEnabled() const { return (GetValueLong(_colorbarEnabledTag, (long)false) != 0); }\n\n    //! Enable or disable colorbar\n    //! \\param[in] bool true if enabled\n    void SetEnabled(bool val) { SetValueLong(_colorbarEnabledTag, \"enable/disable colorbar\", val); }\n\n    //! Determine colorbar text size\n    //! \\return pointsize\n    long GetFontSize() const;\n\n    //! Set colorbar text size\n    //! \\param[in] val text point size\n    void SetFontSize(long val);\n\n    //! Determine colorbar num tics\n    //! \\return number of tics\n    long GetNumTicks() const;\n\n    //! Set colorbar number of tic marks\n    //! \\param[in] val number of tics\n    void SetNumTicks(long val);\n\n    //! Determine colorbar num digits to display\n    //! \\return number of digits\n    long GetNumDigits() const;\n\n    //! Set colorbar number of digits\n    //! \\param[in] val number of digits\n    void SetNumDigits(long val);\n\n    //! Get the background color\n    //! as an rgb triple\n    //! \\retval rgb color\n    vector<double> GetBackgroundColor() const;\n\n    //! Set the background color as an rgb triple\n    //! \\param[in] color = (r,g,b)\n    void SetBackgroundColor(vector<double> color);\n\n    vector<double> GetForegroundColor() const;\n    void SetForegroundColor(vector<double> color);\n\n    //! Copy the settings (except enablement, title, and position) to another ColobarPbase.\n    //! \\param[in] target ColorbarPbase that is target of the copy.\n    void copyTo(ColorbarPbase *target);\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"ColorBarSettingParams\"); }\n\npublic:\n    static const string _colorbarBackColorTag;\n    static const string _colorbarFrontColorTag;\n    static const string _colorbarSizeXTag;\n    static const string _colorbarSizeYTag;\n    static const string _colorbarPositionXTag;\n    static const string _colorbarPositionYTag;\n    static const string _colorbarFontSizeTag;\n    static const string _colorbarNumDigitsTag;\n    static const string _colorbarTitleTag;\n    static const string _colorbarNumTicksTag;\n    static const string _colorbarEnabledTag;\n\n    static const string UseScientificNotationTag;\n};\n};        // namespace VAPoR\n#endif    // COLORBARPBASE_H\n"
  },
  {
    "path": "include/vapor/ColorbarRenderer.h",
    "content": "#pragma once\n\n#include <functional>\n#include <string>\n\nnamespace VAPoR {\nstruct GLManager;\nclass RenderParams;\nclass MapperFunction;\n\n//! \\class ColorbarRenderer\n//! \\ingroup Public_Render\n//! \\brief Renders annotation colorbar for a given Mapper Function\n//! \\author Stanislaw Jaroszynski\n//!\nclass ColorbarRenderer {\npublic:\n    static void Render(GLManager *glm, RenderParams *rp);\n\nprivate:\n    static std::function<std::string(float)> makeFormatter(MapperFunction *mf, int sigFigs, bool scientific);\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/Compressor.h",
    "content": "//\n// $Id$\n//\n\n#ifndef _Compressor_h_\n#define _Compressor_h_\n\n#include <vector>\n#include \"SignificanceMap.h\"\n#include \"MatWaveWavedec.h\"\n\nnamespace VAPoR {\n\n//! \\class Compressor\n//! \\brief A class for managing data set metadata\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//!\n//! This class performs either lossy compression\n//! decomposition on an array with an arbitrary\n//! number of dimensions (up to 3 presently). Compression\n//! is performed by transforming\n//! data with a wavelet transform, sorting the resulting\n//! coefficients, and returning the n largest magnitude coefficients.\n//\nclass WASP_API Compressor : public MatWaveWavedec {\npublic:\n    //! Constructor for compressor class\n    //!\n    //! This construct initializes a Compressor class object for use\n    //! in compression or decomposition. The parameter \\p wname specifies\n    //! the name of the wavelet to use for subsequent wavelet transforms.\n    //! The parameter \\p wmode specifies the boundary extention mode\n    //! to employ for transforms.\n    //! For non-periodic data the biorthogonal wavelets with a\n    //! with an appropriate symetric extension are recommended.\n    //!\n    //! \\param[in] dims Vector specifying dimensions of arrays to be compressed\n    //! \\param[in] wname Name of wavelet to use in transform\n    //! \\param[in] wmode Boundary extention mode\n    //!\n    //! \\sa MatWaveBase, WaveFiltBase\n    //\n    Compressor(std::vector<size_t> dims, const string &wname, const string &mode);\n    Compressor(std::vector<size_t> dims, const string &wname);\n\n    virtual ~Compressor();\n\n    //! Compress an array\n    //!\n    //! This method compresses an input array and returns a compressed version\n    //! of the data. Compression is performed by wavelet transforming the data\n    //! and sorting the resulting wavelet coefficients. Only the largest\n    //! \\p dst_arr_len coefficients are returned.\n    //!\n    //! \\param[in] src_arr The input array. The dimensions are determined\n    //! by the constructor's \\p dims parameter.\n    //! \\param[out] dst_arr The output array that will contain the largest\n    //! \\p dst_arr_len coefficients from the transformed input array. \\p dst_arr\n    //! must point to enough space to contain \\p dst_arr_len elements.\n    //! \\param[out] dst_arr_len Length of \\p dst_arr.\n    //! \\param[in,out] A signficance map that, upon return, will provide\n    //! the coordinates of the output coefficents returned.\n    //!\n    //! \\retval status A negative value indicates failure\n    //! \\sa SignificanceMap, KeepAppOnOff()\n    //\n    int Compress(const float *src_arr, float *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap);\n    int Compress(const double *src_arr, double *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap);\n    int Compress(const int *src_arr, int *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap);\n    int Compress(const long *src_arr, long *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap);\n\n    //! Decompress an array previously compressed with Compress()\n    //!\n    //! \\param[in] src_arr The input array containing the coefficients\n    //! previsously computed by Compress().\n    //! \\param[out] dst_arr The output array that will contain uncompressed\n    //! array. \\p dst_arr\n    //! must point to enough space to contain The entire uncompressed array\n    //! \\param[in] The signficance map that returned by Compress()\n    //! for \\p src_arr\n    //!\n    //! \\retval status A negative value indicates failure\n    //! \\sa Compress()\n    //\n    int Decompress(const float *src_arr, float *dst_arr, SignificanceMap *sigmap);\n    int Decompress(const double *src_arr, double *dst_arr, SignificanceMap *sigmap);\n    int Decompress(const int *src_arr, int *dst_arr, SignificanceMap *sigmap);\n    int Decompress(const long *src_arr, long *dst_arr, SignificanceMap *sigmap);\n\n    //! Decompose an array into a series of approximations of increasingly\n    //! better fidelity.\n    //!\n    //! This method performs a wavelet decomposition of an array, sorts\n    //! the resulting coefficients from largest to smallest, and returns\n    //! the sorted coefficients as a collection of \\p n sets, S<sub>i</sub>.\n    //! The absolute value\n    //! of each element of a set S<sub>i</sub> will be less than each\n    //! element of a set S<sub>i+1</sub>.\n    //!\n    //! \\param[in] src_arr The input array. The dimensions are determined\n    //! by the constructor's \\p dims parameter.\n    //!\n    //! \\param[out] dst_arr The output array that will contain all of\n    //! the sorted coefficients for each collection S<sub>i</sub>.\n    //!\n    //! \\param[in] dst_arr_lens A vector whose size determines the number\n    //! of collections S<sub>i</sub>, and whose elements specify the number\n    //! of elements in each collection S<sub>i</sub>. The sum of all elements\n    //! of \\p dst_arr_lens must be less than or equal the total number of wavelet\n    //! coefficients generated by the wavelet transform. The total is given\n    //! by the size of the vector returned by GetSigMapShape().\n    //!\n    //! \\param[out] sigmaps An array of significance maps, one map for\n    //! each coefficient collection, S<sub>i</sub>\n    //!\n    //! \\retval status A negative value indicates failure\n    //! \\sa SignificanceMap, KeepAppOnOff(), Compress()\n    //\n    int Decompose(const float *src_arr, float *dst_arr, const vector<size_t> &dst_arr_lens, vector<SignificanceMap> &sigmaps);\n    int Decompose(const double *src_arr, double *dst_arr, const vector<size_t> &dst_arr_lens, vector<SignificanceMap> &sigmaps);\n    int Decompose(const int *src_arr, int *dst_arr, const vector<size_t> &dst_arr_lens, vector<SignificanceMap> &sigmaps);\n    int Decompose(const long *src_arr, long *dst_arr, const vector<size_t> &dst_arr_lens, vector<SignificanceMap> &sigmaps);\n\n    //! Reconstruct a signal decomposed with Decompose()\n    //!\n    //! This method reconstructs a signal previosly decomposed with Decompose().\n    //! Partial reconstructions are possible using one of two methods, both\n    //! of which may be combined. In the first the a subset of\n    //! coefficient collections S<sub>i</sub> may be used for reconstruction.\n    //! In this case missing coefficients are simply treated as having\n    //! value zero.  Note that arbitrary S<sub>i</sub> cannot be specified: the\n    //! collections must be ordered with <em>i</em> less than or equal to\n    //! the total number of collections returned by Decompose().\n    //!\n    //! The second method of partial reconstruction is to limit the number of\n    //! inverse wavelet transforms applied to the coefficients. In this case\n    //! the reconstructed array will be coarsened (contain fewer elements)\n    //! than the original. The dimensions of the reconstructed array\n    //! are given by GetDimension().\n    //!\n    //! \\param[in] src_arr The input array containing the coefficients\n    //! previsously computed by Decompose().\n    //!\n    //! \\param[out] dst_arr The output array containing reconstructed signal.\n    //! The dimensions of \\p dst_arr are determined by GetDimension(). If\n    //! \\p l is -1, the dimensions will be the same as those specified by\n    //! the class constructor's \\p dims parameter\n    //!\n    //! \\param[in] sigmaps An array of significance maps previosly returned\n    //! by Decompose()\n    //!\n    //! \\param[in] l The refinement level. \\p l must be in the range -1 to\n    //! max, where max is the value returned by GetNumLevels(). If \\p is -1\n    //! its value will be set to max. A value of zero coresponds to the\n    //! approximation level coefficients.\n    //!\n    //! \\retval status A negative value indicates failure\n    //! \\sa SignificanceMap, KeepAppOnOff(), Compress()\n    //!\n    int Reconstruct(const float *src_arr, float *dst_arr, vector<SignificanceMap> &sigmaps, int l);\n    int Reconstruct(const double *src_arr, double *dst_arr, vector<SignificanceMap> &sigmaps, int l);\n    int Reconstruct(const int *src_arr, int *dst_arr, vector<SignificanceMap> &sigmaps, int l);\n    int Reconstruct(const long *src_arr, long *dst_arr, vector<SignificanceMap> &sigmaps, int l);\n\n    //! Return true if the given grid array is compressible\n    //!\n    //! Return true if the given grid array is compressible based on\n    //! it's dimension and the requested wavelet. I.e. returns true\n    //! if at least one dimension is wide enough for a single wavelet transform\n    //!\n    //! \\param[in] dims Vector specifying dimensions of arrays to be compressed\n    //! \\param[in] wname Name of wavelet to use in transform\n    //! \\param[in] wmode Boundary extention mode\n    //!\n    //! \\sa MatWaveBase, WaveFiltBase\n    //!\n    // static bool IsCompressible(\n    //\tstd::vector <size_t> dims, const string &wavename, const string &mode\n    //);\n\n    //! Returns the shape of significance maps based on constructor\n    //!\n    //! This method returns the shape of any significance maps configured\n    //! by the Compress() or Decompose() method based on parameters passed\n    //! to the class constructor.\n    //!\n    //! \\param[out] dims A vector describing the shap (dimensions) of a\n    //! significance map\n    //!\n    //! \\sa SignificanceMap, Compress(), Decompose()\n    //!\n    void GetSigMapShape(std::vector<size_t> &dims) const\n    {\n        dims.clear();\n        dims.push_back(_CLen);\n    };\n\n    //! Returns the number of wavelet coefficients resulting from\n    //! a forward wavelet transformation of an array.\n    //!\n    //! Returns the number of wavelet coefficients resulting from\n    //! a forward wavelet transformation of an array based on\n    //! the parameters supplied to the class constructor. The\n    //! number of coefficients resulting from a wavelet transform\n    //! is a function of the dimensions of the array, the wavlet\n    //! familiy used, the boundary handling method, and the number of\n    //! transformation levels.\n    //!\n    //! \\note For periodic boundary handling, or symetric wavelets matched\n    //! with appropriate symetric boundary handling, the number of coefficients\n    //! in the transform is guaranteed to match the number of coefficients\n    //! in the input array.\n    //!\n    //! \\sa Compress(), Decompose()\n    //!\n    size_t GetNumWaveCoeffs() const { return (_CLen); };\n\n    //! Returns the size of an encoded SignficanceMap()\n    //!\n    //! Returns the size in bytes of an encoded SignificanceMap()\n    //! used to store \\p num_entries entries.\n    //!\n    //! \\sa Compress(), Decompose()\n    //!\n    size_t GetSigMapSize(size_t num_entries) const\n    {\n        std::vector<size_t> dims;\n        dims.push_back(GetNumWaveCoeffs());\n        return (SignificanceMap::GetMapSize(dims, num_entries));\n    };\n\n    //! Returns the dimensions of a reconstructed array\n    //!\n    //! This method returns the dimensions of an array reconstructed with\n    //! either the Reconstruct() or Decompress() methods. The parameter\n    //! \\p l specifies the number of inverse transformation passes\n    //! applied in the range -1 to max, where max is the value returned by\n    //! GetNumLevels(). A value of -1 corresponds to max levels. A value of\n    //! zero implies no inverse transformations are performed (the dimensions\n    //! returned are those of the wavelet approximation coefficients).\n    //!\n    //! \\param[out] dims The dimensions of the reconstructed array.\n    //! \\param[in] l The number of inverse transforms to apply\n    //!\n    //! \\sa Compressor(), GetNumLevels()\n\n    void GetDimension(vector<size_t> &dims, int l) const;\n\n    //! Returns the number of transformation levels\n    //!\n    //! Returns the number of forward or inverse wavelet transformations\n    //! applied to compress or fully reconstruct an array. The number of\n    //! of transforms is determined by a combination of the wavelet,\n    //! the boundary extension handling method, and the dimensions of the\n    //! array.\n    //!\n    //! \\retval nlevels Number of transformation levels\n    //\n    int GetNumLevels() const { return (_nlevels); };\n\n    //! Returns the number of coefficients in the smallest allowable compression\n    //!\n    //! Returns the minimum number of wavelet coefficients allowable\n    //! after compression.\n    //! The minimum number of\n    //! of coefficients is determined by a combination of the wavelet,\n    //! the boundary extension handling method, the dimensions of the\n    //! array, and the setting of KeepAppOnOff()\n    //!\n    //! \\retval nlevels Number of transformation levels\n    //\n    size_t GetMinCompression() const;\n\n    //! Set or get the keep approximations attribute\n    //!\n    //! When set, this attribute ensures that all wavelet approximation\n    //! coefficients are retained during compression or decomposition. Setting\n    //! this attribute will decrease the maximum possible compression, but may\n    //! significantly improve the fidelity of the approximation\n    //!\n    bool &KeepAppOnOff() { return (_keepapp); };\n\n    //! Set or get the min range clamping attribute\n    //!\n    //! When set, this attribute will clamp the minimum data value\n    //! reconstructed to the value of ClampMin(). I.e. all data values\n    //! reconstructed by Decompress() or Reconstruct() will be greater\n    //! than or equal to the value returned by ClampMin(). By default\n    //! clamping is disabled.\n    //!\n    //! \\sa ClampMin(), Decompress(), Reconstruct()\n    //!\n    bool &ClampMinOnOff() { return (_clamp_min_flag); };\n\n    //! Set or get the minimum range clamp value\n    //!\n    //! \\sa ClampMinOnOff(), Decompress(), Reconstruct()\n    //!\n    double &ClampMin() { return (_clamp_min); };\n\n    //! Set or get the max range clamping attribute\n    //!\n    //! When set, this attribute will clamp the maximum data value\n    //! reconstructed to the value of ClampMax(). I.e. all data values\n    //! reconstructed by Decompress() or Reconstruct() will be less\n    //! than or equal to the value returned by ClampMax(). By default\n    //! clamping is disabled.\n    //!\n    //! \\sa ClampMin(), Decompress(), Reconstruct()\n    //!\n    bool &ClampMaxOnOff() { return (_clamp_max_flag); };\n\n    //! Set or get the maximum range clamp value\n    //!\n    //! \\sa ClampMaxOnOff(), Decompress(), Reconstruct()\n    //!\n    double &ClampMax() { return (_clamp_max); };\n\n    //! Set or get the epsilon attribute\n    //!\n    //! When set, this attribute will compare the absolute value of\n    //! reconstructed data with Epsilon(). If abs(v) is less than epsilon\n    //! the value of v is set to 0.0.\n    //! By default\n    //! the epsilon comparison is disabled.\n    //!\n    //! \\sa Epsilon(), Decompress(), Reconstruct()\n    //!\n    bool &EpsilonOnOff() { return (_epsilon_flag); };\n\n    //! Set or get the epsilon value\n    //!\n    //! \\sa EpsilonOnOff(), Decompress(), Reconstruct()\n    //!\n    double &Epsilon() { return (_epsilon); };\n\n    static bool CompressionInfo(vector<size_t> dims, const string wavename, bool keepapp, size_t &nlevels, size_t &maxcratio);\n\n    friend std::ostream &operator<<(std::ostream &o, const Compressor &rhs);\n\nprivate:\n    vector<size_t> _dims;        // dimensions of array\n    int            _nlevels;     // Number of wavelet transformation levels\n    vector<void *> _indexvec;    // used to sort wavelet coefficients\n    size_t         _nx;\n    size_t         _ny;\n    size_t         _nz;\n    double *       _C;    // storage for wavelet coefficients\n    size_t         _CLen;\n    size_t *       _L;    // wavelet coefficient book keeping array\n    size_t         _LLen;\n    bool           _keepapp;    // if true, approximation coeffs are not used in compression\n    bool           _clamp_min_flag;\n    bool           _clamp_max_flag;\n    bool           _epsilon_flag;\n    double         _clamp_min;\n    double         _clamp_max;\n    double         _epsilon;\n\n    void _Compressor(std::vector<size_t> dims);\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/ConstantGrid.h",
    "content": "#ifndef CONSTANTGRID_H\n#define CONSTANTGRID_H\n\n/*\n * This class represents a constant field. That means,\n * querying values from any location of this field will return that constant value.\n *\n * It also implements pure virtual functions of the Grid class in the simplest possible fashion,\n * but those functions do not perform any calculation, and should not be used.\n *\n * Finally, a DataMgr would not return a ConstantGrid at any occasion; rather, this\n * class is supposed to be created and used locally by its user.\n */\n\n#include \"vapor/Grid.h\"\n\nnamespace VAPoR {\n\nclass VDF_API ConstantGrid : public Grid {\npublic:\n    // The constant value is specified via the constructor\n    // It also requires specification of the dimentionality.\n    ConstantGrid(float v, size_t d);\n\n    //\n    // Useful functions of ConstantGrid.\n    // Additional ones could be added when needed.\n    //\n    // The following four GetValue methods all return the constant value of this grid.\n    float GetConstantValue() const;\n    float GetValue(const CoordType &coords) const override;\n    float GetValueNearestNeighbor(const CoordType &coords) const override;\n    float GetValueLinear(const CoordType &coords) const override;\n\n    // This version of ConstantGrid is considered to have infinity extents,\n    // so the following method will return numerical mins and maxes.\n    // Note: other flavors of ConstantGrids may have specific user extents.\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override;\n    // Similarly, this will always return true.\n    virtual bool InsideGrid(const CoordType &coords) const override;\n\n    std::string GetType() const override;\n\n    // Overwrites the same function from Grid, which will always give you a zero.\n    virtual size_t GetTopologyDim() const override;\n\nprivate:\n    //\n    // Pure virtual functions from Grid class.\n    // They do nothing and return meaningless values.\n    // Do not use!\n    //\n    DimsType                   GetCoordDimensions(size_t) const override;\n    size_t                     GetGeometryDim() const override;\n    const DimsType &           GetNodeDimensions() const override;\n    const size_t               GetNumNodeDimensions() const override;\n    const DimsType &           GetCellDimensions() const override;\n    const size_t               GetNumCellDimensions() const override;\n    void                       GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override {}\n    bool                       GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override { return (false); }\n    virtual void               GetUserCoordinates(const DimsType &, CoordType &) const override {}\n    bool                       GetIndicesCell(const CoordType &coords, DimsType &indices) const override;\n    bool                       GetCellNodes(const DimsType &, std::vector<DimsType> &) const override;\n    bool                       GetCellNeighbors(const DimsType &, std::vector<DimsType> &) const override;\n    bool                       GetNodeCells(const DimsType &, std::vector<DimsType> &) const override;\n    size_t                     GetMaxVertexPerFace() const override;\n    size_t                     GetMaxVertexPerCell() const override;\n    void                       ClampCoord(const CoordType &coords, CoordType &cCoords) const override { cCoords = coords; }\n    ConstCoordItr              ConstCoordBegin() const override;\n    ConstCoordItr              ConstCoordEnd() const override;\n\n    // Private data member that holds this constant value.\n    const float  _value;\n    const size_t _topologyDim;    // Not to be confused with _topologyDimension in\n                                  // the base Grid class, which is private to Grid.\n\n    mutable VAPoR::DimsType _duplicate;\n\n};    // end ConstantGrid class\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/ContourParams.h",
    "content": "\n#ifndef CONTOURPARAMS_H\n#define CONTOURPARAMS_H\n\n#include <string>\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\n// class ContourParams::Contours;\n\n//! \\class ContourParams\n//! \\brief Class that supports drawing Contours based on 2D or 3D vector field\n//! \\author Scott Pearse\n//! \\version 3.0\n//! \\date June 2017\nclass PARAMS_API ContourParams : public RenderParams {\npublic:\n    class Contours;\n\n    ContourParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n\n    ContourParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n\n    ContourParams(const ContourParams &rhs);\n\n    ContourParams &operator=(const ContourParams &rhs);\n\n    virtual ~ContourParams();\n\n    Contours *GetCurrentContours();\n\n    void MakeNewContours(string varName);\n    void GenerateContourValues(double start, double spacing, int num, Contours *c = nullptr);\n\n    //! Determine line thickness in voxels\n    //! \\retval double line thickness\n    double GetLineThickness() const { return (GetValueDouble(_thicknessScaleTag, 1.0)); }\n\n    void SetLineThickness(double val) { SetValueDouble(_thicknessScaleTag, \"Contour thickness\", val); }\n\n    int GetContourCount();\n\n    double GetContourMin();\n\n    double GetContourSpacing();\n\n    double GetContourMax();\n\n    void SetContourCount(int num);\n    void SetContourMin(double val);\n    void SetContourSpacing(double val);\n\n    void GetLineColor(int lineNum, float color[3]);\n\n    void SetLineColor(vector<double> vec) { SetValueDoubleVec(_lineColorTag, \"Line color\", vec); }\n\n    void SetLockToTF(bool lock);\n\n    bool GetLockToTF() const;\n\n    bool           HasIsoValues() const override { return true; }\n    vector<double> GetIsoValues(const string &variable) override;\n    void           SetIsoValues(const string &variable, const vector<double> &values) override;\n\n    vector<double> GetContourValues(const string &varName);\n    void           SetContourValues(const string &varName, const vector<double> &vals);\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"ContourParams\"); }\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return _dataMgr->GetVarTopologyDim(GetVariableName()); }\n    virtual bool   GetOrientable() const override { return true; }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override { return GetVariableName(); }\n\n    int GetNumDigits() const\n    {\n        double val = GetValueDouble(_numDigitsTag, 1.0);\n        return (int)val;\n    }\n\n    void SetNumDigits(int digits) { SetValueDouble(_numDigitsTag, \"Number of digits in contour annotation\", digits); }\n\n    int GetTextDensity() const\n    {\n        double val = GetValueDouble(_textDensityTag, 1.0);\n        return (int)val;\n    }\n\n    void SetTextDensity(int density) { SetValueDouble(_textDensityTag, \"Density of contour annotations\", density); }\n\n    bool GetTextEnabled() const;\n    void SetTFLock(bool lock);\n    bool GetTFLock();\n\nprivate:\n    void                _init();\n    static const string _thicknessScaleTag;\n    static const string _lineColorTag;\n    static const string _contoursTag;\n    static const string _numDigitsTag;\n    static const string _textDensityTag;\n    static const string _textEnabledTag;\n    static const string _lockToTFTag;\n    ParamsContainer *   _contours;\n\n    vector<CoordType> _slicePlaneQuad;\n\npublic:\n    class PARAMS_API Contours : public ParamsBase {\n    public:\n        Contours(ParamsBase::StateSave *ssave);\n\n        Contours(ParamsBase::StateSave *ssave, XmlNode *node);\n\n        virtual ~Contours();\n\n        vector<double> GetContourValues() const\n        {\n            vector<double> defaultv(7, 0.);\n            if (!_node->HasElementDouble(_valuesTag)) return defaultv;\n\n            vector<double> val = GetValueDoubleVec(_valuesTag);\n            return val;\n        }\n\n        void SetContourValues(vector<double> vals) { SetValueDoubleVec(_valuesTag, \"Set contour values\", vals); }\n\n        double        GetMin() const;\n        int           GetCount() const;      // {\n        double        GetSpacing() const;    //{\n        static string GetClassType() { return (\"Contours\"); }\n\n    private:\n        static const string _valuesTag;\n    };\n\n};    // End of Class ContourParams\n\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/ContourRenderer.h",
    "content": "//************************************************************************\n//                                                                       *\n//                          Copyright (C)  2018                          *\n//            University Corporation for Atmospheric Research            *\n//                          All Rights Reserved                          *\n//                                                                       *\n//************************************************************************/\n//\n//  File:   ContourRenderer.cpp\n//\n//  Author: Stas Jaroszynski\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:   March 2018\n//\n//  Description:\n//          Definition of ContourRenderer\n//\n#ifndef CONTOURRENDERER_H\n#define CONTOURRENDERER_H\n\n#include <vapor/glutil.h>\n#include \"vapor/VAssert.h\"\n#include <vapor/Renderer.h>\n#include <vapor/ContourParams.h>\n#include <vapor/ShaderProgram.h>\n#include <vapor/Texture.h>\n\n#include <glm/glm.hpp>\n\nnamespace VAPoR {\n\nclass DataMgr;\n\n//! \\class ContourRenderer\n//! \\brief Class that draws the contours (contours) as specified by IsolineParams\n//! \\author Stas Jaroszynski\n//! \\version 1.0\n//! \\date March 2018\nclass RENDER_API ContourRenderer : public Renderer {\npublic:\n    ContourRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    virtual ~ContourRenderer();\n\n    static string GetClassType() { return (\"Contour\"); }\n\n    //! \\copydoc Renderer::_initializeGL()\n    virtual int _initializeGL();\n    //! \\copydoc Renderer::_paintGL()\n    virtual int _paintGL(bool fast);\n\nprivate:\n    GLuint       _VAO, _VBO;\n    Texture1D    _lutTexture;\n    unsigned int _nVertices;\n\n    struct VertexData;\n    struct {\n        string         varName;\n        string         heightVarName;\n        size_t         ts;\n        int            level;\n        int            lod;\n        double         lineThickness;\n        vector<double> boxMin, boxMax;\n        vector<double> contourValues;\n        vector<double> sliceRotation;\n        vector<double> sliceNormal;\n        vector<double> sliceOrigin;\n        double         sliceOffset;\n        double         sliceResolution;\n        int            sliceOrientationMode;\n\n\n    } _cacheParams;\n\n    int  _buildCache(bool fast);\n    bool _isCacheDirty() const;\n    void _saveCacheParams();\n\n    void _clearCache() { _cacheParams.varName.clear(); }\n\n    vector<glm::vec3> _sliceQuad;\n    glm::vec3         _finalOrigin;\n};\n\n};    // namespace VAPoR\n\n#endif    // CONTOURRENDERER_H\n"
  },
  {
    "path": "include/vapor/ControlExecutive.h",
    "content": "\n#ifndef ControlExec_h\n#define ControlExec_h\n\n#include <string>\n#include <vector>\n#include <map>\n\n#include <vapor/ParamsMgr.h>\n#include <vapor/GLManager.h>\n#include <vapor/DataStatus.h>\n\nusing namespace std;\nnamespace VAPoR {\n\nclass CalcEngineMgr;\nclass Visualizer;\nclass DataStatus;\nclass VisualizerGLContextManager;\n\n//! \\class ControlExec\n//! \\ingroup Public\n//! \\brief Provides API for VAPOR visualizer User Interfaces (UIs)\n//\n\nclass RENDER_API ControlExec : public MyBase {\npublic:\n    //! Initialize the control executive\n    //!\n    //! \\param[in] appParamsNames A vector of unique ParamsBase class\n    //! \\param[in] cacheSizeMB Size of data cache expressed in Megabytes\n    //!\n    //! names that will be passed to the ParamsMgr constructor\n    //!\n    //! \\sa ParamsMgr();\n    //\n    ControlExec(ParamsMgr *pm, size_t cacheSize = 1000, int nThreads = 0);\n    ControlExec() : ControlExec(new ParamsMgr) {}\n    virtual ~ControlExec();\n\n    //! Set the ControlExec to a default state:\n    //! Remove all visualizers\n    //\n    virtual void LoadState();\n\n    //! Load state from an Xml tree\n    //!\n    //! Load state from an Xml state tree. Any unrecognized nodes\n    //! in the tree are simply ignored.\n    //!\n    //! \\sa ParamsMgr::LoadState(const XmlNode *node);\n    //\n    virtual void LoadState(const XmlNode *node);\n\n    class RelAndAbsPathsExistException : public std::exception {\n    public:\n        const std::string AbsolutePath;\n        const std::string RelativePath;\n        RelAndAbsPathsExistException(const std::string &absolute, const std::string &relative)\n                : AbsolutePath(absolute), RelativePath(relative) {}\n    };\n    enum class LoadStateRelAndAbsPathsExistAction { Ask, LoadAbs, LoadRel };\n\n    //!\tRestore the session state from a session state file\n    //!\n    //! This method sets the session state based on the contents of the\n    //! session file specified by \\p file. It also has the side effect\n    //! of deactivating all renderers and unloading any data set\n    //! previously loaded by LoadData(). If successful, the state of all\n    //! Params objects may have changed.\n    //!\n    //! \\param[in] file\tPath to the input file\n    //!\n    //! \\return status A negative int indicates failure. If the method\n    //! fails the session state remains unchanged\n    //!\n    //\n    virtual int LoadState(string stateFile, LoadStateRelAndAbsPathsExistAction relAndAbsPathsExistAction = LoadStateRelAndAbsPathsExistAction::LoadAbs);\n\n    //! Set number of execution threads\n    //!\n    //! Set the number of execution threads. If \\p nThreads == 0, the\n    //! default,\n    //! the system will attempt to set the number of threads equal to\n    //! the number of cores detected. Has no effect until\n    //! the next data set is loaded.\n    //\n    void SetNumThreads(size_t nthreads);\n\n    size_t GetNumThreads() const;\n\n    //! Set the data cache size\n    //!\n    //! Set the size of the data cache in MBs.\n    //! Has no effect until\n    //! the next data set is loaded.\n    //!\n    //! \\sa DataMgr\n    //\n    void SetCacheSize(size_t sizeMB);\n\n    //! Create a new visualizer\n    //!\n    //! This method creates a new visualizer. A visualizer is a drawable\n    //! OpenGL object (e.g. window or pbuffer). The caller is responsible\n    //! for establishing an OpenGL drawable object and making its context\n    //! current before calling NewVisualizer().\n    //!\n    //! \\param[in] name Specifies the name for the new visualizer.\n    //! If name visualizer with name \\p name already exists the\n    //! existing visualizer will be destroyed and a new one created\n    //! with the same name.\n    //!\n    //! \\param[in] withDatasets is the list of currently opened datasets.\n    //! When a dataset is loaded, it loops over the existing visualizers\n    //! and adds params for the currently loading dataset. Since datasets\n    //! could've been loaded prior to the creation of this visualizer,\n    //! they need to be manually added here.\n    //!\n    //! \\note Need to establish what OpenGL state mgt, if any, is performed\n    //! by UI. For example, who calls swapbuffers?\n    //!\n    //! \\note Since the UI is responsible for setting up the graphics\n    //! contexts we may need a method that allows the ControlExec\n    //! to provide\n    //! hints about what kind of graphics context is needed\n    //! (e.g. double buffering)\n    //\n    int NewVisualizer(string name);\n\n    void SyncWithParams();\n    void EnforceDefaultAppState();\n\n\n    //! Delete an existing visualizer\n    //!\n    //! Deletes visualizer and all of its renderers\n    //!\n    //! \\param[in] name handle to existing visualizer returned by\n    //! NewVisualizer(). This method is a no-op if a Visualizer named\n    //! \\p name doesn't exist\n    //!\n    //! \\param[in] hasOpenGLContext If true it is the callers job to ensure\n    //! that the OpenGL Context for the window \\p winName is active. In\n    //! this case the renderer is destroyed immediately. If false the\n    //! renderer is queue'd for later destruction\n    //! when \\p winName has an active OpenGL context.\n    //!\n    //\n    void RemoveVisualizer(string name, bool hasOpenGLContext = false);\n\n    //! Removes objects associated with visualizer params.\n    void CleanupVisualizer(string winName, bool hasOpenGLContext);\n\n    //! Perform OpenGL initialization of specified visualizer\n    //!\n    //! \\param[in] name handle to existing visualizer returned by\n    //! NewVisualizer(). This method is a no-op if a Visualizer named\n    //!\n    //! This method should be called by the UI once before any\n    //! rendering is performed.\n    //! The UI should make the OGL context associated with \\p viz\n    //! current prior to calling this method.\n    //\n    int InitializeViz(string name, GLManager *glManager);\n\n    //! Notify the control executive that a drawing object has\n    //! changed size.\n    //!\n    //! \\param[in] name handle to existing visualizer returned by\n    //! NewVisualizer().\n    //! \\param[in] width Width of visualizer\n    //! \\param[in] height Height of visualizer\n    //!\n    //! This method should be called by the UI whenever the drawing\n    //! object (e.g. window) associated with \\p viz has changed size.\n    //! The UI should make the OGL context associated with \\p viz\n    //! current prior to calling this method.\n    //\n    int ResizeViz(string name, int width, int height);\n    \n    void ClearRenderCache(const string &winName, const string &inst);\n    void ClearAllRenderCaches();\n\n    GLManager::Vendor GetGPUVendor() const;\n\n    //! Determine how many visualizer windows are present\n    //! \\return number of visualizers\n    //!\n    int GetNumVisualizers() const { return (int)_visualizers.size(); }\n\n    //! Return the names of all of the defined visualizers\n    //!\n    vector<string> GetVisualizerNames() const;\n\n    //! Render the contents of a drawable\n    //!\n    //! Tells the control executive to invoke all active renderers associated\n    //! with the visualizer \\p name. The control executive may elect to\n    //! ignore this method if it believes the rendering state to be current,\n    //! unless \\p force is true.\n    //!\n    //! The UI should make the OGL context associated with \\p viz\n    //! current prior to calling this method.\n    //!\n    //! \\param[in] name handle to existing visualizer returned by\n    //! NewVisualizer().\n    //!\t\\param[in] force If true all active renderers will rerender\n    //! their scenes. If false, rendering will only be performed if\n    //! the params objects associated with any of the active renderers\n    //! on this visualizer have changed state.\n    //! \\return rc is 0 if actual painting occurred, -1 if not.\n    //!\n    //!\n    int Paint(string name, bool force = false);\n\n    //! Activate or Deactivate a renderer\n\n    //!\n    //! Create and activate a new renderer instance.\n    //! This renderer instance is inserted in the queue of active renderers\n    //! for the visualizer.\n    //! To deactivate a renderer, the associated Renderer instance is removed\n    //! from the queue of active renderers in the Visualizer, and then deleted.\n    //!\n    //! \\param[in] winName The visualizer associated with this renderer\n    //! \\param[in] type The type of renderer; i.e. the tag for the RenderParams.\n    //! \\param[in] renderName The instance name associated with this\n    //! renderer.\n    //! \\param[in] on A boolean indicating if the renderer is to be made\n    //! active (true) or inactive (off)\n    //!\n    //! \\return status A negative int is returned on failure, indicating that\n    //! the renderer cannot be activated\n    //\n    int ActivateRender(string winName, string dataSetName, string renderType, string renderName, bool on);\n\n    //! Remove (destroy) the indicated renderer\n    //!\n    //! \\param[in] hasOpenGLContext If true it is the callers job to ensure that the\n    //! OpenGL Context for the window \\p winName is active. In this case the renderer\n    //! is destroyed immediately. If false the renderer is queue'd for later destruction\n    //! when \\p winName has an active OpenGL context.\n    //!\n    void RemoveRenderer(string winName, string dataSetName, string renderType, string renderName, bool hasOpenGLContext);\n\n    //! Remove (destroy) all renderers on this window\n    //!\n    //! \\param[in] hasOpenGLContext If true it is the callers job to ensure that the\n    //! OpenGL Context for the window \\p winName is active. In this case the renderer\n    //! is destroyed immediately. If false the renderer is queue'd for later destruction\n    //! when \\p winName has an active OpenGL context.\n    //!\n    void RemoveAllRenderers(string winName, bool hasOpenGLContext = false, bool removeFromParamsFlag=true);\n\n    //! Obtain the ParamsMgr, for use in accessing the Params instances.\n    //! \\return ParamsMgr*\n    //\n    ParamsMgr *GetParamsMgr() const { return _paramsMgr; }\n\n    //! Save the current session state to a file\n    //!\n    //! This method saves all current session state information\n    //! to the file specified by path \\p file. All session state information\n    //! is stored in Params objects and their derivatives\n    //!\n    //! \\param[in] file\tPath to the output file\n    //!\n    //! \\return status A negative int indicates failure\n    //!\n    //! \\sa RestoreSession()\n    //\n    int SaveSession(string file);\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Save user preferences to a file\n    //!\n    //! This method saves all preference information\n    //! to the file specified by path \\p file.\n    //!\n    //! \\param[in] file\tPath to the output file\n    //!\n    //! \\return status A negative int indicates failure\n    //!\n    //! \\sa RestorePreferences()\n    //\n    int SavePreferences(string file);\n\n    //!\tRestore the preferences from a preference file\n    //!\n    //! This method sets the preferences based on the contents of the\n    //! preferences file specified by \\p file.\n    //!\n    //! \\param[in] file\tPath to the input file\n    //!\n    //! \\return status A negative int indicates failure. If the method\n    //! fails the preferences remain unchanged (is it possible to\n    //! guarantee this? )\n    //!\n    //! \\sa SavePreferences()\n    //\n    int RestorePreferences(string file);\n#endif\n\n    //! Load a data set into the current session\n    //!\n    //! Loads a data set specified by the list of files in \\p files\n    //!\n    //! \\param[in] files A vector of data file paths. For data sets\n    //! not containing explicit time information the ordering of\n    //! time varying data will be determined by the order of the files\n    //! in \\p files.\n    //!\n    //!\n    //! \\note The proposed DataMgr API doesn't provide methods to easily\n    //! query some of the information that will be required by the UI, for\n    //! example, the coordinate extents of a variable. These methods\n    //! should either be added to the DataMgr, or the current DataStatus\n    //! class might be cleaned up. Hence, DataInfo might be an enhanced\n    //! DataMgr, or a class object designed specifically for returning\n    //! metadata to the UI.\n    //! \\note (AN) It would be much better to incorporate the\n    //! DataStatus methods into\n    //! the DataMgr class, rather than keeping them separate.\n    //\n    int OpenData(const std::vector<string> &files, string dataSetName, string type = \"vdc\");\n\n    //! Unloads the specified data set\n    //!\n    void CloseData(string dataSetName);\n\n    //! Return list of currently open data set names\n    //!\n    //! \\sa OpenData(), CloseData()\n    //\n    std::vector<string> GetDataNames() const { return (_dataStatus->GetDataMgrNames()); }\n\n    //! Obtain the current DataStatus\n    //! Needed to store in GUI when the DataStatus changes.\n    //! \\return DataStatus*\n    DataStatus *GetDataStatus() const { return _dataStatus; }\n\n    //! Get RenderParams for an active renderer\n    //!\n    //! Return the RenderParams for a render of type \\p renderType, associated\n    //! the visualizer \\p winName, and named \\p instName\n    //! with the specified\n    //\n    RenderParams *GetRenderParams(string winName, string dataSetName, string renderType, string instName) const;\n\n    //! Get all activated render class names\n    //!\n    //! Get a list of all render class names currently active for\n    //! the visualizer named by \\p winName\n    //!\n    std::vector<string> GetRenderClassNames(string winName) const;\n\n    //! Get all activated render class instance names\n    //!\n    //! Get a list of all render class instance names currently active for\n    //! the visualizer named by \\p winName of type \\p renderType\n    //!\n    std::vector<string> GetRenderInstances(string winName, string renderType) const;\n\n    //! Get all available render class types\n    //!\n    //! Return a vector of all availble render class type names\n    //!\n    static vector<string> GetAllRenderClasses();\n\n    //! Lookup window, data set, and class name from a render instance name\n    //!\n    //! This method returns the window name \\p winName, data set name\n    //! \\p dataSetName, and render type \\p rendererType that are associated\n    //! with the render instance name \\p instName.\n    //!\n    //! \\retval status True on success, false if \\p instName is not a previously\n    //! defined render instance name\n    //!\n    //! \\sa ActivateRender\n    //\n    bool RenderLookup(string instName, string &winName, string &dataSetName, string &rendererType) const;\n\n    string MakeRendererNameUnique(string name) const;\n\n    //! Enable or disable state saving\n    //!\n    //! Enable or disable session state saving. When enabled all state\n    //! changes are recorded and it is possible to undo previous changes,\n    //! or save current session state to a file\n    //!\n    //! State saving is disabled by default\n    //!\n    //! \\sa Undo(), Redo(), SaveSession()\n    //\n    void SetSaveStateEnabled(bool enabled) { _paramsMgr->SetSaveStateEnabled(enabled); }\n\n    bool GetSaveStateEnabled() const { return (_paramsMgr->GetSaveStateEnabled()); }\n\n    //! Re-base state saving\n    //!\n    //! Set's the base state to the current node\n    //!\n    void RebaseStateSave() { _paramsMgr->RebaseStateSave(); }\n\n    //! Capture the next rendered image to a file\n    //! When this method is called, the next time Paint() is called for\n    //! the specified visualizer, the rendered image\n    //! will be written to the specified (.jpg, .tif, ...) file.\n    //! The UI must call Paint(viz, true) after this method is called.\n    //! If this is called concurrently with a call to Paint(), the\n    //! image will not be captured until that rendering completes\n    //! and another Paint() is initiated.\n    //! Only one image will be captured.\n    //! \\param[in] filename is either .jpg, .tif, or .tiff file name to capture\n    //! \\param[in] viz Valid visualizer handle\n    int EnableImageCapture(string filename, string winName, bool fast=false);\n\n    //! Start or stop capturing a sequence of rendered images\n    //! When this method is called, the next time Paint() is called for\n    //! the specified visualizer, the rendered image\n    //! will be written to the specified (.jpg, .tif, ...) file.\n    //! The UI must call Paint(viz, true) after this method is called.\n    //! Subsequent renders in the same visualizer will result in capture to a file\n    //! and the filename will be incremented by 1.\n    //! The starting filename should terminate with digits to permit incrementing.\n    //! filename is ignored if capture is being disabled\n\n    //! \\param[in] viz Valid visualizer handle\n    //! \\param[in] doEnable true to start capture, false to end.\n    //! \\param[in] filestart is either .jpg, .tif, or .tiff file\n    //! name for first capture.  Ignored if doEnable = false.\n    //!\n    int EnableAnimationCapture(string winName, bool doEnable, string filename = \"\");\n\n    //! Make string conformant for library\n    //!\n    //! Many of the methods provided by the API accept string arguments\n    //! defining names of objects. These user-defined names must conform\n    //! to Xml element name requirements:\n    //!\n    //! \\li Element names are case-sensitive\n    //! \\li Element names must start with a letter or underscore\n    //! \\li Element names cannot start with the letters xml (or XML, or Xml, etc)\n    //! \\li Element names can contain letters, digits, hyphens,\n    //! underscores, and periods\n    //! \\li Element names cannot contain spaces\n    //!\n    //! This method ensures \\p s is conformant, returning a possibly\n    //! modified string meeting the above requirements\n    //!\n    //! \\param[in] s a string\n    //! \\retval Returns \\p s, possibly modified to be XML element conformant\n    //\n    static string MakeStringConformant(string s);\n\n    //! Add a variable calculation function\n    //!\n    //! This method adds one or more derived variables to the data set\n    //! specified by \\p dataSetName.\n    //! Each derived variable is calculated on-the-fly as needed\n    //! by executing\n    //! the script \\p script.\n    //!\n    //! \\param[in] scriptName A string identifier for the collection\n    //! of derived variables\n    //! computed by \\p script\n    //!\n    //! \\param[in] scriptType The language the script contained in \\p script\n    //! is implemented in. Currently the only accepted value is \"Python\".\n    //!\n    //! \\param[in] dataSetName The name of the data set for which this\n    //! script is to be run. See DataStatus::GetDataMgrNames()\n    //!\n    //! \\param[in] script A script that will be invoked each time\n    //! one of the variables listed in \\p outputs is accessed. The scope of\n    //! the script will contain NumPy Array (numpy.array) variables named\n    //! in \\p inputs.\n    //!\n    //! \\param[in] inputVarNames A list of input variable names. The named\n    //! variables will be made available in the scope of the Python\n    //! script as NumPy Arrays. The variables must exist as native variables\n    //! of the dataset named by \\p dataSetName. I.e. Input variables cannot\n    //! be derived variables themselves.\n    //!\n    //! \\param[in] outputVarNames A list of derived variable names. The named\n    //! variables are expected to be computed by \\p script as NumPy Arrays\n    //! and will appear as derived variables in the dataset named by\n    //! \\p dataSetName.\n    //!\n    //! \\param[in] outVarMeshes A list of output mesh names, one for each output\n    //! variable listed in \\p outputVarNames. The output mesh names must be known\n    //! to the dataset. Each output variable created by \\p script is expected\n    //! to be sampled by the named mesh. See DataMgr::GetMesh()\n    //!\n    //! \\retval status A negative integer is returned on failure and an error\n    //! message is reported with MyBase::SetErrMsg(). AddFunction() will fail\n    //! if any of the output variables named in \\p outputVarNames already exist\n    //! in the dataset as returned by DataMgr::GetDataVarNames(), or if any of\n    //! the output mesh names in \\p outVarMeshes are not known to the\n    //! DataMgr (see DataMgr::GetMeshNames())\n    //!\n    //! \\note The Python script \\p script is executed when one of the output\n    //! variables is read. Depending on the region requested only a subset\n    //! of the native variable may be provided to \\p script as a NumPy\n    //! array. Currently this occurs if all of the input variables named\n    //! by \\p inputs and the requested output variable are sampled on the\n    //! same mesh.\n    //!\n    //! \\sa PyEngine::AddFunction(), CalcEngineMgr::AddFunction()\n    //\n    int AddFunction(string scriptType, string dataSetName, string scriptName, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames,\n                    const vector<string> &outputVarMeshes, bool coordFlag = false);\n\n    //! Remove a previously defined function\n    //!\n    //! This method removes the function previously created by AddFunction()\n    //! All of the associated derived variables are\n    //! removed from the dataset. The method is a no-op if \\p scriptName is not\n    //! an active function.\n    //!\n    //! \\param[in] scriptType Language of script. Currently only \"Python\" is\n    //! supported\n    //!\n    //! \\param[in] dataSetName Name of data set for which \\p scriptName is to\n    //! be removed.\n    //!\n    //! \\param[in] scriptName Name of script to remove\n    //!\n    //! \\sa PyEngineMgr::RemoveFunction()\n    //\n    void RemoveFunction(string scriptType, string dataSetName, string scriptName);\n\n    //! Return the script for a named function\n    //!\n    //! This method returns as a string the script associated with the\n    //! function named by \\p name. It also returns the input and output\n    //! variable names, and the output variable mesh names.\n    //!\n    //! \\param[in] scriptType Type of script\n    //! \\param[in] dataSetName Name of data set\n    //! \\param[in] scriptName Name of script\n    //!\n    //! \\param[out] script Script returned as a string\n    //! \\param[out] inputVarNames Vector of input variable names to script\n    //! \\param[out] outputVarNames Vector of output variable names generated\n    //! by script\n    //! \\param[out] outputVarMeshes Vector of output variable mesh names\n    //! associated with \\p outputVarNames\n    //!\n    //! \\retval status Returns true upon success. If the tupple \\p scriptName\n    //! \\p dataSetName, \\p scriptName is invalid false is returned.\n    //!\n    //! \\sa AddFunction(), RemoveFunction()\n    //\n    bool GetFunction(string scriptType, string dataSetName, string scriptName, string &script, vector<string> &inputVarNames, vector<string> &outputVarNames, vector<string> &outputVarMeshes,\n                     bool &coordFlag) const;\n\n    //! Return any standard output from the last invocation of a script\n    //!\n    //! This method returns as a string any standard output from the last\n    //! (most recent) invocation of the named script\n    //\n    string GetFunctionStdout(string scriptType, string dataSetName, string scriptName) const;\n\n    //! Return a list of all active function names\n    //!\n    //! This method returns a vector of names for all active (not previously\n    //! removed) functions created with AddFunction() for the specified\n    //! dataset \\p dataSetName and the specifed script language type \\p scriptType\n    //!\n    //! \\sa AddFunction();\n    //!\n    std::vector<string> GetFunctionNames(string scriptType, string dataSetName) const;\n\n    void SetVisualizerGLContextManager(VisualizerGLContextManager *mgr) { _vizGLMgr = mgr; }\n\n    template <class T> T* GetParams() const\n    {\n        return (T*)GetParamsMgr()->GetParams(T::GetClassType());\n    }\n\n    // \"was\" allows other components synced after CE to act accordingly\n    bool WasDataCacheDirty() const;\n    void SetDataCacheDirty(const string &dataset=\"\", const string &variable=\"\") {\n        _dataStatus->SetCacheDirty(dataset, variable);\n    }\n\nprivate:\n    ParamsMgr *                    _paramsMgr;\n    DataStatus *                   _dataStatus;\n    CalcEngineMgr *                _calcEngineMgr;\n    VisualizerGLContextManager *   _vizGLMgr = nullptr;\n    std::map<string, Visualizer *> _visualizers;\n    \n    string _dataCachedProjStr;\n\n    GLManager::Vendor _cachedVendor = GLManager::Vendor::Unknown;\n\n    //! obtain an existing visualizer\n    //! \\param[in] viz Handle of desired visualizer\n    //! \\return pointer to specified visualizer\n    //!\n    Visualizer *getVisualizer(string winName) const\n    {\n        std::map<string, Visualizer *>::const_iterator it;\n        it = _visualizers.find(winName);\n        if (it == _visualizers.end()) return NULL;\n        return it->second;\n    }\n\n    void syncVisualizersWithParams();\n    void syncDatasetsWithParams();\n\n    void _removeRendererHelper(string winName, string dataSetName, string paramsType, string renderName, bool hasOpenGLContext);\n\n    void _autoStretchExtents(string dataSetName);\n\n    void _setDefaultOrigin(string datasetName);\n};\n};    // namespace VAPoR\n\n#endif    // ControlExec_h\n"
  },
  {
    "path": "include/vapor/CurvilinearGrid.h",
    "content": "#ifndef _CurvilinearGrid_\n#define _CurvilinearGrid_\n#include <vapor/common.h>\n#include <vapor/Grid.h>\n#include <vapor/RegularGrid.h>\n#include <vapor/QuadTreeRectangleP.h>\n\nnamespace VAPoR {\n//! \\class CurvilinearGrid\n//!\n//! \\brief This class implements a 2D or 3D curvilinear grid.\n//!\n//! This class implements a 2D or 3D curvilinear grid: a\n//! specialization of StructuredGrid class where cells are\n//! quadrilaterals (2D), or cuboids (3D). Hence, curvlinear grids are\n//! topologically, but the location of each grid point is expressed\n//! by functions:\n//!\n//! \\code\n//! x = X(i,j)\n//! y = Y(i,j)\n//! z = Z(i,j,k)\n//! \\endcode\n//!\n//! or\n//!\n//! \\code\n//! x = X(i,j)\n//! y = Y(i,j)\n//! z = Z(k)\n//! \\endcode\n//!\n//\nclass VDF_API CurvilinearGrid : public StructuredGrid {\npublic:\n    //! \\copydoc StructuredGrid::StructuredGrid()\n    //!\n    //! Construct a vetically stretched, horizontally curvlinear 3D grid\n    //!\n    //! This constructor instantiates a curvilinear grid  where the x,y,z\n    //! user coordinates are expressed as follows:\n    //!\n    //! \\code\n    //! x = X(i,j)\n    //! y = Y(i,j)\n    //! z = Z(k)\n    //! \\endcode\n    //!\n    //! The X and Y user coordinates are specified with \\p xrg and \\p yrg,\n    //! respectively, and the Z coordinates  are specified by the\n    //! vector \\p zcoords.\n    //!\n    //! Adds new parameters:\n    //!\n    //! \\param[in] xrg A 2D RegularGrid instance whose\n    //! I and J dimensionality matches that of this class instance, and whose\n    //! values specify the X user coordinates.\n    //! \\param[in] yrg A 2D RegularGrid instance whose\n    //! I and J dimensionality matches that of this class instance, and whose\n    //! values specify the Y user coordinates.\n    //! \\param[in] zcoords  A 1D vector whose size matches that of the K\n    //! dimension of this class, and whose values specify the Z user coordinates.\n    //! \\param[in] qtr A QuadTreeRectangleP instance that contains a quad tree\n    //! that may be used to find the cell(s) containing a given point\n    //! expressed in user coordintes. if \\p qtr is NULL the class will\n    //! generate its own QuadTreeRectangleP instance.\n    //!\n    //!\n    //! \\sa RegularGrid()\n    //\n    CurvilinearGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, const std::vector<double> &zcoords,\n                    std::shared_ptr<const QuadTreeRectangleP> qtr);\n    CurvilinearGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg,\n                    const std::vector<double> &zcoords, std::shared_ptr<const QuadTreeRectangleP> qtr);\n\n    //! \\copydoc StructuredGrid::StructuredGrid()\n    //!\n    //! Construct a layered, horizontally curvlinear 3D grid\n    //!\n    //! This constructor instantiates a curvilinear grid  where the x,y,z\n    //! user coordinates are expressed as follows:\n    //!\n    //! \\code\n    //! x = X(i,j)\n    //! y = Y(i,j)\n    //! z = Z(i,j,k)\n    //! \\endcode\n    //!\n    //! The X and Y user coordinates are specified with \\p xrg and \\p yrg,\n    //! respectively, and the Z coordinates  are specified by the\n    //! \\p zrg\n    //!\n    //! Adds new parameters:\n    //!\n    //! \\param[in] xrg A 2D RegularGrid instance whose\n    //! I and J dimensionality matches that of this class instance, and whose\n    //! values specify the X user coordinates.\n    //! \\param[in] yrg A 2D RegularGrid instance whose\n    //! I and J dimensionality matches that of this class instance, and whose\n    //! values specify the Y user coordinates.\n    //! \\param[in] zrg A 3D RegularGrid instance whose\n    //! I, J, K dimensionality matches that of this class instance, and whose\n    //! values specify the Z user coordinates.\n    //! \\param[in] qtr A QuadTreeRectangleP instance that contains a quad tree\n    //! that may be used to find the cell(s) containing a given point\n    //! expressed in user coordintes. if \\p qtr is NULL the class will\n    //! generate its own QuadTreeRectangleP instance.\n    //!\n    //!\n    //! \\sa RegularGrid()\n    //\n    CurvilinearGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg,\n                    std::shared_ptr<const QuadTreeRectangleP> qtr);\n    CurvilinearGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg,\n                    std::shared_ptr<const QuadTreeRectangleP> qtr);\n\n    //! \\copydoc StructuredGrid::StructuredGrid()\n    //!\n    //! Construct a curvlinear 2D grid\n    //!\n    //! This constructor instantiates a curvilinear grid  where the x,y\n    //! user coordinates are expressed as follows:\n    //!\n    //! \\code\n    //! x = X(i,j)\n    //! y = Y(i,j)\n    //! \\endcode\n    //!\n    //! The X and Y user coordinates are specified with \\p xrg and \\p yrg,\n    //! respectively.\n    //!\n    //! Adds new parameters:\n    //!\n    //! \\param[in] xrg A 2D RegularGrid instance whose\n    //! I and J dimensionality matches that of this class instance, and whose\n    //! values specify the X user coordinates.\n    //! \\param[in] yrg A 2D RegularGrid instance whose\n    //! I and J dimensionality matches that of this class instance, and whose\n    //! values specify the Y user coordinates.\n    //! \\param[in] qtr A QuadTreeRectangleP instance that contains a quad tree\n    //! that may be used to find the cell(s) containing a given point\n    //! expressed in user coordintes. if \\p qtr is NULL the class will\n    //! generate its own QuadTreeRectangleP instance.\n    //!\n    //!\n    //! \\sa RegularGrid()\n    //\n    CurvilinearGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, std::shared_ptr<const QuadTreeRectangleP> qtr);\n    CurvilinearGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg,\n                    std::shared_ptr<const QuadTreeRectangleP> qtr);\n\n    CurvilinearGrid() = default;\n    virtual ~CurvilinearGrid()\n    {\n        if (_qtr) {\n            _qtr = nullptr;    // qtr is a C++ shared pointer\n        }\n    }\n\n    std::shared_ptr<const QuadTreeRectangleP> GetQuadTreeRectangle() const { return (_qtr); }\n\n    static std::string GetClassType() { return (\"Curvilinear\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    virtual DimsType GetCoordDimensions(size_t dim) const override;\n\n    virtual size_t GetGeometryDim() const override { return (GetTopologyDim()); };\n\n    // \\copydoc GetGrid::GetBoundingBox()\n    //\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override;\n\n    // \\copydoc GetGrid::GetUserCoordinates()\n    //\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override;\n\n    //! \\copydoc Grid::GetIndicesCell\n    //!\n    virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override;\n\n    // \\copydoc GetGrid::InsideGrid()\n    //\n    virtual bool InsideGrid(const CoordType &coords) const override;\n\n    //! Returns reference to RegularGrid instance containing X user coordinates\n    //!\n    //! Returns reference to RegularGrid instance passed to constructor\n    //! containing X user coordinates\n    //!\n    const RegularGrid &GetXRG() const { return (_xrg); };\n\n    //! Returns reference to RegularGrid instance containing Y user coordinates\n    //!\n    //! Returns reference to RegularGrid instance passed to constructor\n    //! containing Y user coordinates\n    //!\n    const RegularGrid &GetYRG() const { return (_yrg); };\n\n    //! Returns reference to vector containing Z user coordinates\n    //!\n    //! Returns reference to vector passed to constructor\n    //! containing Z user coordinates\n    //!\n    const std::vector<double> &GetZCoords() const { return (_zcoords); };\n\n    class ConstCoordItrCG : public Grid::ConstCoordItrAbstract {\n    public:\n        ConstCoordItrCG(const CurvilinearGrid *cg, bool begin);\n        ConstCoordItrCG(const ConstCoordItrCG &rhs);\n\n        ConstCoordItrCG();\n        virtual ~ConstCoordItrCG() {}\n\n        virtual void            next();\n        virtual void            next(const long &offset);\n        virtual ConstCoordType &deref() const { return (_coords); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const\n        {\n            const ConstCoordItrCG *itrptr = static_cast<const ConstCoordItrCG *>(rhs);\n\n            return (_index == itrptr->_index);\n        }\n\n        virtual std::unique_ptr<ConstCoordItrAbstract> clone() const { return std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrCG(*this)); };\n\n    private:\n        const CurvilinearGrid *_cg;\n        DimsType               _index;\n        CoordType              _coords;\n        ConstIterator          _xCoordItr;\n        ConstIterator          _yCoordItr;\n        ConstIterator          _zCoordItr;\n        bool                   _terrainFollowing;\n    };\n\n    virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrCG(this, true))); }\n    virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrCG(this, false))); }\n\nprotected:\n    virtual float GetValueNearestNeighbor(const CoordType &coords) const override;\n\n    virtual float GetValueLinear(const CoordType &coords) const override;\n\n    // \\copydoc GetGrid::GetUserExtents()\n    //\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override;\n\nprivate:\n    std::vector<double>                       _zcoords;\n    CoordType                                 _minu = {{0.0, 0.0, 0.0}};\n    CoordType                                 _maxu = {{0.0, 0.0, 0.0}};\n    RegularGrid                               _xrg;\n    RegularGrid                               _yrg;\n    RegularGrid                               _zrg;\n    bool                                      _terrainFollowing;\n    std::shared_ptr<const QuadTreeRectangleP> _qtr;\n\n    void _curvilinearGrid(const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg, const std::vector<double> &zcoords, std::shared_ptr<const QuadTreeRectangleP> qtr);\n\n    bool _insideFace(const DimsType &face, double pt[2], double lambda[4], std::vector<DimsType> &nodes) const;\n\n    bool _insideGrid(double x, double y, double z, size_t &i, size_t &j, size_t &k, double lambda[4], double zwgt[2]) const;\n\n    void _getIndicesHelper(const std::vector<double> &coords, std::vector<size_t> &indices) const;\n\n    bool _insideGridHelperStretched(double z, size_t &k, double zwgt[2]) const;\n\n    bool _insideGridHelperTerrain(double x, double y, double z, const size_t &i, const size_t &j, size_t &k, double zwgt[2]) const;\n\n    std::shared_ptr<QuadTreeRectangleP> _makeQuadTreeRectangle() const;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/DC.h",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <vapor/MyBase.h>\n\n#ifndef _DC_H_\n    #define _DC_H_\n\nnamespace VAPoR {\n\n//!\n//! \\class DC\n//! \\ingroup Public_VDC\n//!\n//! \\brief A Template Method design pattern for reading a collection of data.\n//!\n//! \\author John Clyne\n//! \\date    January, 2015\n//!\n//! The Data Collection (DC) class defines an Template Method for\n//! reading metadata and sampled\n//! data from a data collection.  A data collection is a set of\n//! related data, most typically the discrete outputs from a single numerical\n//! simulation. The DC class is a Template Method: if provides an\n//! abstract interface for accessing a data collection, and a set of\n//! protected pure virtual functions that must be implemented by\n//! derived classes providing access to a particular file format.\n//!\n//! Variables in a DC may have 1, 2, or 3 topological dimensions, and 0 or 1\n//! temporal dimensions.\n//!\n//! The DC is structured in the spirit of the \"NetCDF Climate and Forecast\n//! (CF) Metadata Conventions\", version 1.6, 5, December 2011.\n//! It supports only a subset of the CF functionality (e.g. there is no\n//! support for \"Discrete Sampling Geometries\"). Moreover, it is\n//! more restrictive than the CF in a number of areas. Particular\n//! items of note include:\n//!\n//! \\li The API supports variables with 0 to 3 topological dimensions only.\n//!\n//! \\li Coordinate variables representing time must be 1D\n//!\n//! \\li All data variables have a \"coordinate\" attribute identifying\n//! the coordinate (or auxiliary coordinate) variables associated with\n//! each axis\n//!\n//! \\li To be consistent with VAPOR, when specified in vector form the\n//! ordering of dimension lengths\n//! and dimension names is from fastest varying dimension to slowest.\n//! For example, if\n//! 'dims' is a vector of dimensions, then dims[0] is the fastest varying\n//! dimension, dim[1] is the next fastest, and so on. This ordering is the\n//! opposite of the ordering used by NetCDF.\n//!\n//! \\li The API supports unstructured grids and attempts to follow\n//! the UGRID conventions.\n//!\n//! This class inherits from Wasp::MyBase. Unless otherwise documented\n//! any method that returns an integer value is returning status. A negative\n//! value indicates failure. Error messages are logged via\n//! Wasp::MyBase::SetErrMsg(). Methods that return a boolean do\n//! not, unless otherwise documented, log an error message upon\n//! failure (return of false).\n//!\n//! \\param level\n//! \\parblock\n//! Grid refinement level for multiresolution variables.\n//! Compressed variables in the DC, if they exist, have a multi-resolution\n//! representation: the sampling grid for multi-resolution variables\n//! is hierarchical, and the dimension lengths of adjacent levels in the\n//! hierarchy differ by a factor of two. The \\p level parameter is\n//! used to select a particular depth of the hierarchy.\n//!\n//! To provide maximum flexibility as well as compatibility with previous\n//! versions of the DC the interpretation of \\p level is somewhat\n//! complex. Both positive and negative values may be used to specify\n//! the refinement level and have different interpretations.\n//!\n//! For positive\n//! values of \\p level, a value of \\b 0 indicates the coarsest\n//! member of the\n//! grid hierarchy. A value of \\b 1 indicates the next grid refinement\n//! after the coarsest, and so on. Using postive values the finest level\n//! in the hierarchy is given by GetNumRefLevels() - 1. Values of \\p level\n//! that are greater than GetNumRefLevels() - 1 are treated as if they\n//! were equal to GetNumRefLevels() - 1.\n//!\n//! For negative values of \\p level a value of -1 indicates the\n//! variable's native grid resolution (the finest resolution available).\n//! A value of -2 indicates the next coarsest member in the hierarchy after\n//! the finest, and so\n//! on. Using negative values the coarsest available level in the hierarchy is\n//! given by negating the value returned by GetNumRefLevels(). Values of\n//! \\p level that are less than the negation of GetNumRefLevels() are\n//! treated as if they were equal to the negation of the GetNumRefLevels()\n//! return value.\n//! \\endparblock\n//! \\param lod\n//! \\parblock\n//! The level-of-detail parameter, \\p lod, selects\n//! the approximation level for a compressed variable.\n//! The \\p lod parameter is similar to the \\p level parameter in that it\n//! provides control over accuracy of a compressed variable. However, instead\n//! of selecting the grid resolution the \\p lod parameter controls\n//! the compression factor by indexing into the \\p cratios vector (see below).\n//! As with the \\p level parameter, both positive and negative values may be\n//! used to index into \\p cratios and\n//! different interpretations.\n//!\n//! For positive\n//! values of \\p lod, a value of \\b 0 indicates the\n//! the first element of \\p cratios, a value of \\b 1 indicates\n//! the second element, and so on up to the size of the\n//! \\p cratios vector (See DC::GetCRatios()).\n//!\n//! For negative values of \\p lod a value of \\b -1 indexes the\n//! last element of \\p cratios, a value of \\b -2 indexes the\n//! second to last element, and so on.\n//! Using negative values the first element of \\p cratios - the greatest\n//! compression rate - is indexed by negating the size of the\n//! \\p cratios vector.\n//! \\endparblock\n//! \\param cratios A monotonically decreasing vector of\n//! compression ratios. Compressed variables in the DC are stored\n//! with a fixed, finite number of compression factors. The \\p cratios\n//! vector is used to specify the available compression factors (ratios).\n//! A compression factor of 1 indicates no compression (1:1). A value\n//! of 2 indciates two to one compression (2:1), and so on. The minimum\n//! valid value of \\p cratios is \\b 1. The maximum value is determined\n//! by a number of factors and can be obtained using the CompressionInfo()\n//! method.\n//!\n//! \\param bs An ordered list of block dimensions that specifies the\n//! spatial block decomposition of the variable. The rank of \\p bs may be less\n//! than that of a variable's array dimensions (or empty), in which case only\n//! the \\b n fastest varying variable dimensions will be blocked, where\n//! \\b n is the rank of \\p bs. The ordering of the dimensions in \\p bs\n//! is from fastest to slowest. A block is the basic unit of compression\n//! in the DC: variables are decomposed into blocks, and individual blocks\n//! are compressed independently. Note, the time dimension is never blocked.\n//!\n//! \\param wname Name of wavelet used for transforming compressed\n//! variables between wavelet and physical space. Valid values\n//! are \"bior1.1\", \"bior1.3\", \"bior1.5\", \"bior2.2\", \"bior2.4\",\n//! \"bior2.6\", \"bior2.8\", \"bior3.1\", \"bior3.3\", \"bior3.5\", \"bior3.7\",\n//! \"bior3.9\", \"bior4.4\"\n//!\n//!\nclass VDF_API DC : public Wasp::MyBase {\npublic:\n    //! External storage types for primitive data\n    //\n    enum XType { INVALID = -1, FLOAT, DOUBLE, UINT8, INT8, INT32, INT64, TEXT };\n\n    //! \\class Dimension\n    //!\n    //! \\brief Metadata describing a named dimension length\n    //!\n    //! Describes an array dimension with a name and an\n    //! associated length. Dimension lengths may vary (e.g. over time).\n    //!\n    class Dimension {\n    public:\n        Dimension()\n        {\n            _name.clear();\n            _lengths.clear();\n        }\n\n        //! Dimension class constructor for multi-length dimension\n        //!\n        //! \\param[in] name The name of dimension\n        //! \\param[in] lengths A vector of dimension lengths.\n        //!\n        Dimension(std::string name, std::vector<size_t> lengths)\n        {\n            _name = name;\n            _lengths = lengths;\n        };\n\n        //! Dimension class constructor for constant-length dimension\n        //!\n        //! \\param[in] name The name of dimension\n        //! \\param[in] length The dimension length.\n        //!\n        Dimension(std::string name, size_t length)\n        {\n            _name = name;\n            _lengths.clear();\n            _lengths.push_back(length);\n        };\n\n        virtual ~Dimension(){};\n\n        //! Get dimension name\n        //\n        string GetName() const { return (_name); };\n\n        //! Return dimension length\n        //!\n        //! For a multi-length dimension the first length is returned\n        //!\n        size_t GetLength() const { return (_lengths.size() ? _lengths[0] : 0); };\n\n        //! Return a dimension length\n        //!\n        //! \\param[in] index Return the length of the dimension for the indicated\n        //! element. If \\p index is out of range the value 0 is returned\n        //!\n        size_t GetLength(size_t index) const { return (index < _lengths.size() ? _lengths[index] : 0); };\n\n        //! Return boolean indicating whether dimension can vary over time\n        //!\n        //! This method returns true if the dimesion length can vary over time.\n        //\n        bool IsTimeVarying() const { return (_lengths.size() > 1); }\n\n        friend std::ostream &operator<<(std::ostream &o, const Dimension &dimension);\n\n    private:\n        string              _name;\n        std::vector<size_t> _lengths;\n    };\n\n    //! \\class Mesh\n    //! \\version 3.1\n    //!\n    //! \\brief Metadata describing a computational mesh\n    //!\n    //! This class describes the properties of a computational mesh upon\n    //! which data variables are sampled. The class can represent both\n    //! structured and unstructured grids.\n    //! The design of the Mesh class is inspired by the capabilities of the\n    //! UGRID conventions:\n    //! <a href=http://ugrid-conventions.github.io/ugrid-conventions/>UGRID</a>\n    //!\n    //! Towards that end we adopt some of UGRID's terminology:\n    //!\n    //! \\b Definitions\n    //!\n    //! \\li \\b node A point, a coordinate pair or triplet: the most basic\n    //! element of the topology. Aka \"vertext\".\n    //!\n    //! \\li \\b edge A line bounded by two nodes.\n    //!\n    //! \\li \\b face A plane or surface enclosed by a set of edges. In a 2D\n    //! horizontal application one may consider the word \"polygon\", but in the\n    //! hierarchy of elements the word \"face\" is most common.\n    //!\n    //! \\li \\b volume A volume enclosed by a set of faces. Aka \"cell\".\n    //!\n    //! \\li \\b topology The topology defines the connectivity of the\n    //! vertices and defines the elements.\n    //!\n    //! \\param[in] name A string containing the name of the mesh.\n    //!\n    //! \\param[in] coord_vars A list of names of the coordinate variables,\n    //! each specifying the X, Y, or Z spatial coordinates for the nodes\n    //! in the mesh.  If a coordinate variable for an X, Y, or Z axis\n    //! is not specified the node's coordinate's for the missing axis are\n    //! assumed to be zero. The dimensionality of the coordinate variable\n    //! may be less than that of the dimensionality of the grid, in which\n    //! case the coordinates along the unspecified dimension are assumed\n    //! invariant.\n    //!\n    //! \\param[in] max_nodes_per_face Specifies maximum number of nodes\n    //! (or edges) a face of the mesh may have.\n    //!\n    //! \\param[in] max_faces_per_node Specifies maximum number of faces\n    //! that may share a node\n    //!\n    //! \\param[in] node_dim_name A string containing the name of the dimension\n    //! specifying the total number of nodes in the unstructured\n    //! portion of the mesh; for layered-grid unstructured meshes \\p node_dim_name\n    //! specifies the number of nodes in a single layer\n    //!\n    //! \\param[in] face_dim_name A string containing the name of the dimension\n    //! specifying the total number of faces in the unstructured\n    //! portion of the mesh; for layered-grid unstructured meshes \\p face_dim_name\n    //! specifies the number of faces in a single layer\n    //!\n    //! \\param[in] face_node_var  The name of a 2D Auxiliary variable\n    //! (See DC:AuxVar) with\n    //! integer type identifying for\n    //! every face the indices of its corner nodes. The corner nodes should be\n    //! specified in anticlockwise direction as viewed from above The\n    //! connectivity array will be a matrix of size\n    //! face_dim x \\p max_nodes_per_face, where face_dim is the length of the\n    //! dimension named by \\p face_dim_name, and is the slowest varying\n    //! of the two dimensions. If a face has less corner nodes\n    //! \\p max_nodes_per_face then the last node indices shall be equal to -1.\n    //! Indecies start from zero.\n    //!\n    //! \\param[in] node_face_var  The name of a 2D Auxiliary variable\n    //! (See DC:AuxVar) with\n    //! integer type identifying for\n    //! every node the indices of the faces that share the node.\n    //! The faces should be\n    //! specified in anticlockwise direction as viewed from above The\n    //! connectivity array will be a matrix of size\n    //! node_dim x \\p max_faces_per_node , where node_dim is the length of the\n    //! dimension named by \\p node_dim_name, and is the slowest varying\n    //! of the two dimensions. If a node has less faces then\n    //! \\p max_faces_per_node then the last face indices shall be equal to -1.\n    //! Indecies start from zero.\n    //!\n    //! \\note The \\p node_face_var is not defined by the UGRID conventions\n    //!\n    class Mesh {\n    public:\n        //! Type of mesh\n        //\n        enum Type {\n            STRUCTURED,         //!< A structured mesh\n            UNSTRUC_2D,         //!< An unstructured mesh with 2D topology\n            UNSTRUC_LAYERED,    //!< An unstructured layered mesh\n            UNSTRUC_3D          //!< An fully unstructured mesh with 3D topology\n        };\n\n        //! Location of sampled data variables within the mesh\n        //\n        enum Location {\n            NODE,     //!< Samples located at mesh nodes\n            EDGE,     //!< Samples located at mesh edge centers\n            FACE,     //!< Samples located at mesh face centers\n            VOLUME    //!< Samples located at mesh volume centers\n        };\n\n        Mesh()\n        {\n            _name.clear();\n            _dim_names.clear();\n            _coord_vars.clear();\n            _max_nodes_per_face = 0;\n            _max_faces_per_node = 0;\n            _node_dim_name.clear();\n            _face_dim_name.clear();\n            _layers_dim_name.clear();\n            _face_node_var.clear();\n            _node_face_var.clear();\n            _face_edge_var.clear();\n            _face_face_var.clear();\n            _edge_dim_name.clear();\n            _edge_node_var.clear();\n            _edge_face_var.clear();\n            _mtype = STRUCTURED;\n        }\n\n        //! Construct structured mesh\n        //!\n        //! This method constructs a structured mesh.\n        //!\n        //! \\param[in] name Name of the mesh. If \\p name is the empty string\n        //! a name will be created from the concatenation of the elements\n        //! of the \\p dim_names parameter\n        //!\n        //! \\param[in] dim_names An ordered list of names of the\n        //! spatial dimensions of\n        //! the mesh. The ordering is from fastest varying dimension to slowest.\n        //! The number of elements in \\p dim_names determines the dimensionality\n        //! of the mesh, but not, in general, the topological dimension of the\n        //! mesh. The rank of \\p dim_names defines\n        //! the topological dimension.\n        //!\n        Mesh(std::string name, std::vector<string> dim_names, std::vector<string> coord_vars);\n\n        //! Construct unstructured 2D mesh\n        //!\n        //! This method constructs an unstructured mesh with 2D topology.\n        //!\n        Mesh(std::string name, size_t max_nodes_per_face, size_t max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::vector<std::string> coord_vars,\n             std::string face_node_var, std::string node_face_var);\n\n        //! Construct unstructured layered mesh\n        //!\n        //! This method constructs an unstructured layered mesh.\n        //!\n        //! \\param[in] layers_dim_name Name of dimension specifying the number\n        //! of layers in the mesh.\n        //\n        Mesh(std::string name, size_t max_nodes_per_face, size_t max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::string layers_dim_name,\n             std::vector<std::string> coord_vars, std::string face_node_var, std::string node_face_var);\n\n        //! Construct unstructured 3d mesh\n        //!\n        //! This method constructs an unstructured 3d mesh.\n        //!\n        //! \\param[in] layers_dim_name Name of dimension specifying the number\n        //! of layers in the mesh.\n        //\n        Mesh(std::string name, int max_nodes_per_face, int max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::vector<string> coord_vars);\n\n        //! Return the type of mesh\n        //!\n        //! Returns one of:\n        //!\n        //! \\li \\c STRUCTURED A structured mesh\n        //!\n        //! \\li \\c UNSTRUC_2D An unstructured mesh with 2D topology\n        //!\n        //! \\li \\c UNSTRUC_LAYERED An unstructured layered mesh\n        //!\n        //! \\li \\c UNSTRUC_3D An fully unstructured mesh with 3D topology\n        //!\n        //!\n        Mesh::Type GetMeshType() const { return (_mtype); }\n\n        //! Get mesh name\n        //\n        string GetName() const { return (_name); };\n\n        //! Get dim names\n        //!\n        //! Returns ordered list of dimension names for the mesh nodes. The\n        //! ordering is from fastest to slowest varying dimension.\n        //! For\n        //! structured meshes the size of the returned vector matches the\n        //! topological dimensionality of the mesh.\n        //!\n        //! For\n        //! unstructured meshes the returned contains the names of the\n        //! node dimensions.\n        //\n        std::vector<string> GetDimNames() const { return (_dim_names); };\n\n        //! Get coordinate variable names\n        //!\n        //! Returns the list of coordinate variable names associated with\n        //! the nodes of the mesh.\n        //\n        std::vector<string> GetCoordVars() const { return (_coord_vars); };\n        void                SetCoordVars(std::vector<string> coord_vars) { _coord_vars = coord_vars; };\n\n        //! Get geometric dimension of cells\n        //!\n        //! Returns the geometric dimension of the cells in the mesh. I.e.\n        //! the number of spatial spatial coordinates for each grid point.\n        //! Valid values are 0..3. The geometric dimension must be equal to\n        //! or greater than the topology dimension.\n        //!\n        //! \\sa GetTopologyDim()\n        //\n        size_t GetGeometryDim() const { return (_coord_vars.size()); }\n\n        //! Get the maximum number of nodes per face\n        //!\n        //! Return the maximum number of nodes that a face in the mesh may have.\n        //! For structured meshes this value is always four.\n        //!\n        size_t GetMaxNodesPerFace() const { return (_max_nodes_per_face); };\n\n        //! Get the maximum number of faces per node\n        //!\n        //! Return the maximum number of faces that a node in the mesh may have.\n        //! For structured meshes this value is always four.\n        //!\n        size_t GetMaxFacesPerNode() const { return (_max_faces_per_node); };\n\n        //! Get the name of the node dimension\n        //!\n        //! For unstructured meshes this method returns the name of the\n        //! node dimension. For structured meshes an emptry string is returned.\n        //!\n        string GetNodeDimName() const { return (_node_dim_name); };\n\n        //! Get the name of the face dimension\n        //!\n        //! For unstructured meshes this method returns the name of the\n        //! face dimension. For structured meshes an emptry string is returned.\n        //!\n        string GetFaceDimName() const { return (_face_dim_name); };\n\n        //! Get the name of the layers dimension\n        //!\n        //! For unstructured layered meshes this method returns the name of the\n        //! node dimension. For other meshes an empty string is returned.\n        //!\n        string GetLayersDimName() const { return (_layers_dim_name); };\n\n        //! Get the name of face node connectivity var\n        //!\n        //! Return the name of the face node connecity variable\n        //!\n        string GetFaceNodeVar() const { return (_face_node_var); }\n        void   SetFaceNodeVar(std::string face_node_var)\n        {\n            if (_mtype == STRUCTURED) return;\n            _face_node_var = face_node_var;\n        }\n\n        //! Get the name of node face connectivity var\n        //!\n        //! Return the name of the node face connecity variable\n        //!\n        string GetNodeFaceVar() const { return (_node_face_var); }\n        void   SetNodeFaceVar(std::string node_face_var)\n        {\n            if (_mtype == STRUCTURED) return;\n            _node_face_var = node_face_var;\n        }\n\n        //! Set the name of the optional edge dimension\n        //!\n        //! For unstructured meshes this method sets the name of the optional\n        //! edge dimension. It is only needed if data are located on mesh edges.\n        //!\n        //! \\param[in] edge_dim_name Name of the edge dimension\n        //!\n        void SetEdgeDimName(std::string edge_dim_name)\n        {\n            if (_mtype == STRUCTURED) return;\n            _edge_dim_name = edge_dim_name;\n        }\n\n        //! Get the name of the optional edge dimension\n        //!\n        //! This method gets the name of the optional\n        //! edge dimension. If not explicitly set with SetEdgeDimName() an\n        //! empty string is returned.\n        //!\n        std::string GetEdgeDimName() const { return (_edge_dim_name); }\n\n        //! Set the name of optional edge node connectivity index variable\n        //!\n        //! For meshes with data located on edges this method specifies the\n        //! name of an index variable identifying for every edge the indices of its\n        //! begining and ending nodes. The connectivity array will thus be a matrix\n        //! of size edge_dim x 2, where edge_dim is the dimension length named\n        //! by edge_dim_name.\n        //!\n        //! \\sa GetEdgeDimName()\n        //!\n        void SetEdgeNodeVar(std::string edge_node_var)\n        {\n            if (_mtype == STRUCTURED) return;\n            _edge_node_var = edge_node_var;\n        }\n\n        //! Get the name of optional edge node connectivity index variable\n        //!\n        //! An emptry string is returned if not explicitly set with\n        //! SetEdgeNodeVar()\n        //\n        std::string GetEdgeNodeVar() const { return (_edge_node_var); }\n\n        //! Set the name of optional face edge connectivity index variable\n        //!\n        //! The name of an optional 2D Auxiliary variable\n        //! (See DC:AuxVar) with\n        //! integer type.\n        //! If specified, names an index variable identifying\n        //! for every face the indices of its edges. The edges should be specified\n        //! in anticlockwise direction as viewed from above. This connectivity\n        //! array will be a matrix of size face_dim x max_faces_per_node,\n        //! where face_dim is the dimension length named by \\p face_dim_name,\n        //! and is the slowest varying of the two dimensions.\n        //!  If a face\n        //! has less corners/edges than max_faces_per_node then the last edge\n        //! indices shall be equal to -1. The starting index is 0.\n        //!\n        //\n        void SetFaceEdgeVar(std::string face_edge_var)\n        {\n            if (_mtype == STRUCTURED) return;\n            _face_edge_var = face_edge_var;\n        }\n\n        //! Get the name of optional face edge connectivity index variable\n        //!\n        //! An emptry string is returned if not explicitly set with\n        //! SetFaceEdgeVar()\n        //\n        std::string GetFaceEdgeVar() const { return (_face_edge_var); }\n\n        //! Set the name of optional face-face connectivity index variable\n        //!\n        //! The name of an optional 2D Auxiliary variable\n        //! (See DC:AuxVar) with\n        //! integer type.\n        //! If specified, names an index variable identifying\n        //! for every face the indices of its adjacent faces. The faces should\n        //! be specified\n        //! in anticlockwise direction as viewed from above. This connectivity\n        //! array will be a matrix of size face_dim x max_faces_per_node, where\n        //! face_dim is the dimension length named by \\p face_dim_name, and\n        //! is the slowest varying of the two dimensions. If a face\n        //! has less corners/edges than max_faces_per_node then the last face\n        //! indices shall be equal to -1. The starting index is 0.\n        //!\n        //\n        void SetFaceFaceVar(std::string face_face_var)\n        {\n            if (_mtype == STRUCTURED) return;\n            _face_face_var = face_face_var;\n        }\n\n        //! Get the name of optional face edge connectivity index variable\n        //!\n        //! An emptry string is returned if not explicitly set with\n        //! SetFaceFaceVar()\n        //\n        std::string GetFaceFaceVar() const { return (_face_face_var); }\n\n        //! Set the name of optional edge-face connectivity index variable\n        //!\n        //! The name of an optional 2D Auxiliary variable\n        //! (See DC:AuxVar) with\n        //! integer type.\n        //! If specified, names an index variable identifying\n        //! for every edge the indices of its adjacent faces.\n        //! This connectivity array is thus a matrix of size edge_dim x 2,\n        //! where edge_dim is the dimension length named by \\p edge_dim_name, and\n        //! is the slowest varying of the two dimensions. It is\n        //! intended to be used in combination with data defined on edges.\n        //! The starting index is 0.\n        //!\n        //! \\sa SetEdgeDimName()\n        //\n        void SetEdgeFaceVar(std::string edge_face_var)\n        {\n            if (_mtype == STRUCTURED) return;\n            _edge_face_var = edge_face_var;\n        }\n\n        //! Get the name of optional face edge connectivity index variable\n        //!\n        //! An emptry string is returned if not explicitly set with\n        //! SetEdgeFaceVar()\n        //\n        std::string GetEdgeFaceVar() const { return (_edge_face_var); }\n\n        //! Get topological dimension of the mesh\n        //!\n        //! Return the number of topological dimensions for the mesh cells. Valid\n        //! values are in the range 0..3, with, for example, 0 corresponding\n        //! to points; 1 to lines; 2 to triangles, quadrilaterals, etc.; and\n        //! 3 to hexahedron, tetrahedron, etc.\n        //!\n        //! \\sa GetGeometryDim()\n        //\n        size_t GetTopologyDim() const;\n\n        //! Generate a mesh name from a list of strings. The\n        //! generated name is simply the join of the elements of \\p s\n        //! using 'x' as a delimiter\n        //\n        static string MakeMeshName(std::vector<string> s);\n\n        friend std::ostream &operator<<(std::ostream &o, const Mesh &mesh);\n\n    private:\n        string              _name;\n        std::vector<string> _dim_names;\n        std::vector<string> _coord_vars;\n        size_t              _max_nodes_per_face;\n        size_t              _max_faces_per_node;\n        string              _node_dim_name;\n        string              _face_dim_name;\n        string              _layers_dim_name;\n        string              _face_node_var;\n        string              _node_face_var;\n        string              _face_edge_var;\n        string              _face_face_var;\n        string              _edge_dim_name;\n        string              _edge_node_var;\n        string              _edge_face_var;\n        Mesh::Type          _mtype;\n\n        void _Mesh(string name, std::vector<string> coord_vars, int max_nodes_per_face, int max_faces_per_node, Type type);\n    };\n\n    //! \\class Attribute\n    //!\n    //! \\brief Variable or global metadata\n    //!\n    class Attribute {\n    public:\n        Attribute()\n        {\n            _name = \"\";\n            _type = FLOAT;\n            _values.clear();\n        };\n\n        //! Attribute constructor\n        //!\n        //! \\param[in] name The name of the attribute\n        //! \\param[in] type External representation format\n        //! \\param[in] values A vector specifying the attribute's values\n        //\n        Attribute(string name, XType type, const std::vector<float> &values);\n        Attribute(string name, XType type, const std::vector<double> &values);\n        Attribute(string name, XType type, const std::vector<int> &values);\n        Attribute(string name, XType type, const std::vector<long> &values);\n        Attribute(string name, XType type, const string &values);\n        Attribute(string name, XType type)\n        {\n            _name = name;\n            _type = type;\n            _values.clear();\n        };\n        virtual ~Attribute(){};\n\n        //! Get attribute name\n        //\n        string GetName() const { return (_name); };\n\n        //! Get an attribute's external representation type\n        //\n        XType GetXType() const { return (_type); };\n\n        //! Get an attribute's value(s)\n        //!\n        //! Get the value(s) for an attribute, performing type conversion\n        //! as necessary from the external storage type to the desired type\n        //!\n\t\tVDF_API void GetValues(std::vector<float> &values) const;\n\t\tVDF_API void GetValues(std::vector<double> &values) const;\n\t\tVDF_API void GetValues(std::vector<int> &values) const;\n\t\tVDF_API void GetValues(std::vector<long> &values) const;\n\t\tVDF_API void GetValues(string &values) const;\n\n        //! Set an attribute's value(s)\n        //!\n        //! Set the value(s) for an attribute, performing type conversion\n        //! as necessary to meet the external storage type.\n        //!\n        void SetValues(const std::vector<float> &values);\n        void SetValues(const std::vector<double> &values);\n        void SetValues(const std::vector<int> &values);\n        void SetValues(const std::vector<long> &values);\n        void SetValues(const string &values);\n\n        friend std::ostream &operator<<(std::ostream &o, const Attribute &attr);\n\n    private:\n        string _name;\n        XType  _type;\n        union podunion {\n            float  f;\n            double d;\n            int    i;\n            long   l;\n            char   c;\n        };\n        std::vector<podunion> _values;\n    };\n\n    //! \\class BaseVar\n    //!\n    //! \\brief Base class for storing variable metadata\n    //\n    class BaseVar {\n    public:\n        BaseVar()\n        {\n            _name.clear();\n            _units.clear();\n            _type = FLOAT;\n            _wname.clear();\n            _cratios.clear();\n            _periodic.clear();\n            _atts.clear();\n        }\n\n        //! Constructor\n        //!\n        //! \\param[in] name The variable's name\n        //!\n        //! \\param[in] units A string recognized by Udunits-2 specifying the\n        //! unit measure for the variable. An empty string indicates that the\n        //! variable is unitless.\n        //! \\param[in] type The external storage type for variable data\n        //! \\param[in] wname The wavelet family name for compressed variables\n        //! \\param[in] cratios Specifies a vector of compression factors for\n        //! compressed variable definitions. If empty, or if cratios.size()==1\n        //! and cratios[0]==1, the variable is not\n        //! compressed\n        //!\n        //! \\deprecated Results are undefined if the rank of\n        //! of \\p periodic does not match that of \\p dimensions.\n        //!\n        BaseVar(string name, string units, XType type, string wname, std::vector<size_t> cratios, std::vector<bool> periodic)\n        : _name(name), _units(units), _type(type), _wname(wname), _cratios(cratios), _periodic(periodic)\n        {\n            if (_cratios.size() == 0) _cratios.push_back(1);\n        };\n\n        //! No compression constructor\n        //!\n        //! \\param[in] name The variable's name\n        //! \\deprecated \\param[in] dimensions An ordered vector\n        //! specifying the variable's spatial\n        //! and/or temporal dimensions\n        //!\n        //! \\param[in] units A string recognized by Udunits-2 specifying the\n        //! unit measure for the variable. An empty string indicates that the\n        //! variable is unitless.\n        //! \\param[in] type The external storage type for variable data\n        //! factor for the variable.\n        //! \\deprecated \\param[in] periodic An ordered array of booleans\n        //! specifying the\n        //! spatial boundary periodicity.\n        //! Results are undefined if the rank of\n        //! of \\p periodic does not match that of \\p dimensions.\n        //!\n        BaseVar(string name, string units, XType type, std::vector<bool> periodic);\n\n        virtual ~BaseVar(){};\n\n        //! Get variable name\n        //\n        string GetName() const { return (_name); };\n        void   SetName(string name) { _name = name; };\n\n        //! Access variable units\n        //\n        string GetUnits() const { return (_units); };\n        void   SetUnits(string units) { _units = units; };\n\n        //! Access variable external storage type\n        //\n        XType GetXType() const { return (_type); };\n        void  SetXType(XType type) { _type = type; };\n\n        //! Access variable's wavelet family name\n        //\n        string GetWName() const { return (_wname); };\n        void   SetWName(string wname) { _wname = wname; };\n\n        //! Access variable's compression ratios\n        //\n        std::vector<size_t> GetCRatios() const { return (_cratios); };\n\n        void SetCRatios(std::vector<size_t> cratios)\n        {\n            _cratios = cratios;\n            if (_cratios.size() == 0) _cratios.push_back(1);\n        };\n\n        //! \\deprecated Access variable bounary periodic\n        //\n        std::vector<bool> GetPeriodic() const { return (_periodic); };\n        void              SetPeriodic(std::vector<bool> periodic) { _periodic = periodic; };\n\n        //! Access variable attributes\n        //\n        const std::map<string, Attribute> &GetAttributes() const { return (_atts); };\n        void                               SetAttributes(std::map<string, Attribute> &atts) { _atts = atts; };\n\n        bool GetAttribute(string name, Attribute &att) const\n        {\n            std::map<string, Attribute>::const_iterator itr = _atts.find(name);\n            if (itr == _atts.end()) return (false);\n            att = itr->second;\n            return (true);\n        }\n\n        void SetAttribute(const Attribute &att) { _atts[att.GetName()] = att; }\n\n        //! Return true if no wavelet is defined\n        //\n        bool IsCompressed() const { return (!_wname.empty()); };\n\n        friend std::ostream &operator<<(std::ostream &o, const BaseVar &var);\n\n    private:\n        string                      _name;\n        string                      _units;\n        XType                       _type;\n        string                      _wname;\n        std::vector<size_t>         _cratios;\n        std::vector<bool>           _periodic;\n        std::map<string, Attribute> _atts;\n    };\n\n    //! \\class CoordVar\n    //! \\brief Coordinate variable metadata\n    //\n    class CoordVar : public BaseVar {\n    public:\n        CoordVar()\n        {\n            _dim_names.clear();\n            _time_dim_name.clear();\n            _axis = 0;\n            _uniform = true;\n        }\n\n        //! Construct coordinate variable\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type, bool compressed,\n        //!  string wname,\n        //!  std::vector <size_t> cratios,\n        //!  std::vector <bool> periodic)\n        //!\n        //! \\param[in] dim_names An ordered list of names of the spatial\n        //! dimensions of\n        //! the coordinate variable. The ordering is from fastest varying\n        //! dimension to slowest.\n        //! The number of elements in \\p dim_names determines the dimensionality\n        //! of the coordinate variable.\n        //!\n        //! \\param[in] time_dim_name Name of time varying dimension, if any. If\n        //! the coordinate variable varies over time this parameter names\n        //! the time dimension. If \\p time_dim_name is the empty string\n        //! the coordiante variable is constant over time.\n        //!\n        //! \\param[in] axis an int in the range 0..3 indicating the coordinate\n        //! axis, one of X, Y, Z, or T, respectively\n        //! \\param[in] uniform A bool indicating whether the coordinate variable\n        //! is uniformly sampled.\n        //\n        CoordVar(string name, string units, XType type, string wname, std::vector<size_t> cratios, std::vector<bool> periodic, std::vector<string> dim_names, string time_dim_name, int axis,\n                 bool uniform)\n        : BaseVar(name, units, type, wname, cratios, periodic), _dim_names(dim_names), _time_dim_name(time_dim_name), _axis(axis), _uniform(uniform)\n        {\n        }\n\n        //! Construct coordinate variable without compression\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type, std::vector <bool> periodic)\n        //!\n        //! \\param[in] dim_names An ordered list of names of the spatial\n        //! dimensions of\n        //! the coordinate variable. The ordering is from fastest varying\n        //! dimension to slowest.\n        //! The number of elements in \\p dim_names determines the dimensionality\n        //! of the coordinate variable.\n        //!\n        //! \\param[in] time_dim_name Name of time varying dimension, if any. If\n        //! the coordinate variable varies over time this parameter names\n        //! the time dimension. If \\p time_dim_name is the empty string\n        //! the coordiante variable is constant over time.\n        //!\n        //! \\param[in] axis an int in the range 0..3 indicating the coordinate\n        //! axis, one of X, Y, Z, or T, respectively\n        //! \\param[in] uniform A bool indicating whether the coordinate variable\n        //! is uniformly sampled.\n        //\n        CoordVar(string name, string units, XType type, std::vector<bool> periodic, int axis, bool uniform, std::vector<string> dim_names, string time_dim_name)\n        : BaseVar(name, units, type, periodic), _dim_names(dim_names), _time_dim_name(time_dim_name), _axis(axis), _uniform(uniform)\n        {\n        }\n\n        virtual ~CoordVar(){};\n\n        //! Access coordinate variable spatial dimension names\n        //! \\version 3.1\n        //\n        std::vector<string> GetDimNames() const { return (_dim_names); };\n        void                SetDimNames(std::vector<string> dim_names) { _dim_names = dim_names; };\n\n        //! Access coordinate variable time dimension name\n        //! \\version 3.1\n        //\n        string GetTimeDimName() const { return (_time_dim_name); };\n        void   SetTimeDimName(string time_dim_name) { _time_dim_name = time_dim_name; };\n\n        //! Access coordinate variable axis\n        //\n        int  GetAxis() const { return (_axis); };\n        void SetAxis(int axis) { _axis = axis; };\n\n        //! Access coordinate variable uniform sampling flag\n        //\n        bool GetUniform() const { return (_uniform); };\n        void SetUniform(bool uniform) { _uniform = uniform; };\n\n        friend std::ostream &operator<<(std::ostream &o, const CoordVar &var);\n\n    private:\n        std::vector<string> _dim_names;\n        string              _time_dim_name;\n        int                 _axis;\n        bool                _uniform;\n    };\n\n    //! \\class DataVar\n    //! \\brief Data variable metadata\n    //!\n    //! This class defines metadata associatd with a Data variable\n    //!\n    class DataVar : public BaseVar {\n    public:\n        DataVar()\n        {\n            _mesh.clear();\n            _time_coord_var.clear();\n            _location = Mesh::NODE;\n            _maskvar.clear();\n            _has_missing = false;\n            _missing_value = 0.0;\n        }\n\n        //! Construct Data variable definition with missing values\n        //!\n        //! Elements of the variable whose value matches that specified by\n        //! \\p missing_value are considered invalid\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type,\n        //!  string wname,\n        //!  std::vector <size_t> cratios,\n        //!  std::vector <bool> periodic)\n        //!\n        //! \\param[in] mesh Name of mesh upon which this variable is sampled\n        //!\n        //! \\param[in] time_coord_var Name of time coordinate variable. If\n        //! the variable is time varying this parameter provides the name of\n        //! it's time coordinate variable. If the variable is invariant over time\n        //! \\p time_coord_var should be the empty string.\n        //!\n        //! \\param[in] location Location of samples on Mesh. Samples can be\n        //! located at the Mesh nodes, edge centers, face centers, or\n        //! volume centers.\n        //!\n        //! \\param[in] missing_value  Value of the missing value indicator\n        //!\n        DataVar(string name, string units, XType type, string wname, std::vector<size_t> cratios, std::vector<bool> periodic, string mesh, string time_coord_var, Mesh::Location location,\n                double missing_value)\n        : BaseVar(name, units, type, wname, cratios, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(\"\"), _has_missing(true), _missing_value(missing_value)\n        {\n        }\n\n        //! Construct Data variable definition with a mask variable\n        //!\n        //! This version of the constructor specifies the name of a variable\n        //! \\p varmask whose contents indicate the presense or absense of invalid\n        //! entries in the data variable. The contents of the mask array are treated\n        //! as booleans, true values indicating valid data. The rank of of the\n        //! variable may be less than or equal to that of \\p name. The dimensions\n        //! of \\p maskvar must match the fastest varying dimensions of \\p name.\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type,\n        //!  string wname,\n        //!  std::vector <size_t> cratios,\n        //!  std::vector <bool> periodic)\n        //!\n        //! \\param[in] mesh Name of mesh upon which this variable is sampled\n        //!\n        //! \\param[in] time_coord_var Name of time coordinate variable. If\n        //! the variable is time varying this parameter provides the name of\n        //! it's time coordinate variable. If the variable is invariant over time\n        //! \\p time_coord_var should be the empty string.\n        //!\n        //! \\param[in] location Location of samples on Mesh. Samples can be\n        //! located at the Mesh nodes, edge centers, face centers, or\n        //! volume centers.\n        //!\n        //! \\param[in] missing_value  Value used to fill masked values\n        //! \\param[in] maskvar  Name of variable containing mask array.\n        //!\n        DataVar(string name, string units, XType type, string wname, std::vector<size_t> cratios, std::vector<bool> periodic, string mesh, string time_coord_var, Mesh::Location location,\n                double missing_value, string maskvar)\n        : BaseVar(name, units, type, wname, cratios, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(maskvar), _has_missing(true), _missing_value(missing_value)\n        {\n        }\n\n        //! Construct Data variable definition without missing values\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type,\n        //!  string wname,\n        //!  std::vector <size_t> cratios,\n        //!  vector <bool> periodic)\n        //!\n        //! \\deprecated \\param[in] coord_vars Names of coordinate variables\n        //! associated\n        //! with this variables dimensions\n        //!\n        //! \\param[in] mesh Name of mesh upon which this variable is sampled\n        //!\n        //! \\param[in] time_coord_var Name of time coordinate variable. If\n        //! the variable is time varying this parameter provides the name of\n        //! it's time coordinate variable. If the variable is invariant over time\n        //! \\p time_coord_var should be the empty string.\n        //!\n        //! \\param[in] location Location of samples on Mesh. Samples can be\n        //! located at the Mesh nodes, edge centers, face centers, or\n        //! volume centers.\n        //!\n        DataVar(string name, string units, XType type, string wname, std::vector<size_t> cratios, std::vector<bool> periodic, string mesh, string time_coord_var, Mesh::Location location)\n        : BaseVar(name, units, type, wname, cratios, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(\"\"), _has_missing(false), _missing_value(0.0)\n        {\n        }\n\n        //! Construct Data variable definition with missing values but no compression\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type,\n        //!  std::vector <bool> periodic)\n        //!\n        //! \\deprecated \\param[in] coord_vars Names of coordinate variables\n        //! associated\n        //! with this variables dimensions\n        //!\n        //! \\param[in] mesh Name of mesh upon which this variable is sampled\n        //!\n        //! \\param[in] time_coord_var Name of time coordinate variable. If\n        //! the variable is time varying this parameter provides the name of\n        //! it's time coordinate variable. If the variable is invariant over time\n        //! \\p time_coord_var should be the empty string.\n        //!\n        //! \\param[in] location Location of samples on Mesh. Samples can be\n        //! located at the Mesh nodes, edge centers, face centers, or\n        //! volume centers.\n        //!\n        //! \\param[in] missing_value  Value of the missing value indicator\n        //!\n        DataVar(string name, string units, XType type, std::vector<bool> periodic, string mesh, string time_coord_var, Mesh::Location location, double missing_value)\n        : BaseVar(name, units, type, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(\"\"), _has_missing(true), _missing_value(missing_value)\n        {\n        }\n\n        //! Construct Data variable definition with a mask but no compression\n        //!\n        //! This version of the constructor specifies the name of a variable\n        //! \\p varmask whose contents indicate the presense or absense of invalid\n        //! entries in the data variable. The contents of the mask array are treated\n        //! as booleans, true values indicating valid data. The rank of of the\n        //! variable may be less than or equal to that of \\p name. The dimensions\n        //! of \\p maskvar must match the fastest varying dimensions of \\p name.\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type,\n        //!  std::vector <bool> periodic)\n        //!\n        //! \\deprecated \\param[in] coord_vars Names of coordinate\n        //! variables associated\n        //!\n        //! \\param[in] mesh Name of mesh upon which this variable is sampled\n        //!\n        //! \\param[in] time_coord_var Name of time coordinate variable. If\n        //! the variable is time varying this parameter provides the name of\n        //! it's time coordinate variable. If the variable is invariant over time\n        //! \\p time_coord_var should be the empty string.\n        //!\n        //! \\param[in] location Location of samples on Mesh. Samples can be\n        //! located at the Mesh nodes, edge centers, face centers, or\n        //! volume centers.\n        //!\n        //! with this variables dimensions\n        //! \\param[in] missing_value  Value used to fill masked values\n        //! \\param[in] maskvar  Name of variable containing mask array.\n        //!\n        DataVar(string name, string units, XType type, std::vector<bool> periodic, string mesh, string time_coord_var, Mesh::Location location, double missing_value, string maskvar)\n        : BaseVar(name, units, type, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(maskvar), _has_missing(true), _missing_value(missing_value)\n        {\n        }\n\n        //! Construct Data variable definition with no missing values or compression\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type,\n        //!  std::vector <bool> periodic)\n        //!\n        //! \\param[in] coord_vars Names of coordinate variables associated\n        //! with this variables dimensions\n        //!\n        //! \\param[in] time_coord_var Name of time coordinate variable. If\n        //! the variable is time varying this parameter provides the name of\n        //! it's time coordinate variable. If the variable is invariant over time\n        //! \\p time_coord_var should be the empty string.\n        //!\n        //!\n        DataVar(string name, string units, XType type, std::vector<bool> periodic, string mesh, string time_coord_var, Mesh::Location location)\n        : BaseVar(name, units, type, periodic), _mesh(mesh), _time_coord_var(time_coord_var), _location(location), _maskvar(\"\"), _has_missing(false), _missing_value(0.0)\n        {\n        }\n\n        virtual ~DataVar(){};\n\n        //! Access variable's mesh name\n        //! \\version 3.1\n        //\n        string GetMeshName() const { return (_mesh); };\n        void   SetMeshName(string mesh) { _mesh = mesh; };\n\n        //! Access variable's time coordinate variable name\n        //! \\version 3.1\n        //\n        string GetTimeCoordVar() const { return (_time_coord_var); }\n        void   SetTimeCoordVar(string time_coord_var) { _time_coord_var = time_coord_var; }\n\n        //! Access variable's sampling location on mesh\n        //! \\version 3.1\n        //\n        Mesh::Location GetSamplingLocation() const { return (_location); }\n\n        //! Access data variable's mask variable names\n        //\n        string GetMaskvar() const { return (_maskvar); };\n        void   SetMaskvar(string maskvar) { _maskvar = maskvar; };\n\n        //! Access data variable's missing data flag\n        //\n        bool GetHasMissing() const { return (_has_missing); };\n        void SetHasMissing(bool has_missing) { _has_missing = has_missing; };\n\n        //! Access data variable's missing data value\n        //\n        double GetMissingValue() const { return (_missing_value); };\n        void   SetMissingValue(double missing_value) { _missing_value = missing_value; };\n\n        VDF_API friend std::ostream &operator<<(std::ostream &o, const DataVar &var);\n\n    private:\n        string         _mesh;\n        string         _time_coord_var;\n        Mesh::Location _location;\n        string         _maskvar;\n        bool           _has_missing;\n        double         _missing_value;\n    };\n\n    //! \\class AuxVar\n    //! \\version 3.1\n    //!\n    //! \\brief Auxiliary variable metadata\n    //!\n    //! This class defines metadata associatd with an Auxiliary variable.\n    //! An Auxiliary variable is neither a data variable, nor a coordinate\n    //! variable.\n    //!\n    class AuxVar : public BaseVar {\n    public:\n        AuxVar()\n        {\n            _dim_names.clear();\n            _offset = 0;\n        }\n\n        //! Construct Auxiliary variable definition\n        //!\n        //! \\copydetails BaseVar(string name,\n        //!  string units, XType type,\n        //!  string wname,\n        //!  std::vector <size_t> cratios,\n        //!  std::vector <bool> periodic)\n        //!\n        //! \\param[in] dim_names An ordered list of names of the dimensions of\n        //! the coordinate variable. The ordering is from fastest varying\n        //! dimension to slowest.\n        //! The number of elements in \\p dim_names determines the dimensionality\n        //! of the auxiliary variable.\n        //!\n        AuxVar(string name, string units, XType type, string wname, std::vector<size_t> cratios, std::vector<bool> periodic, std::vector<string> dim_names)\n        : BaseVar(name, units, type, wname, cratios, periodic), _dim_names(dim_names), _offset(0)\n        {\n        }\n\n        virtual ~AuxVar(){};\n\n        //! Access Auxiliary variable dimension names\n        //\n        std::vector<string> GetDimNames() const { return (_dim_names); };\n        void                SetDimNames(std::vector<string> dim_names) { _dim_names = dim_names; };\n\n        //! Access Auxiliary variable's offset\n        //!\n        //! The value of \\p offset should be added to the Auxiliary variable's data\n        //\n        long GetOffset() const { return (_offset); };\n        void SetOffset(long offset) { _offset = offset; };\n\n        VDF_API friend std::ostream &operator<<(std::ostream &o, const AuxVar &var);\n\n    private:\n        std::vector<string> _dim_names;\n        long                _offset;\n    };\n\n    //! Class constuctor\n    //!\n    //!\n    DC();\n\n    virtual ~DC(){};\n\n    //! Initialize the DC class\n    //!\n    //! Prepare a DC for reading. This method prepares\n    //! the master DC file indicated by \\p path for reading.\n    //! The method should be called immediately after the constructor,\n    //! before any other class methods. This method\n    //! exists only because C++ constructors can not return error codes.\n    //!\n    //! \\param[in] path Path name of file that contains, or will\n    //! contain, the DC master file for this data collection\n    //!\n    //! \\param[in] options A vector of option pairs (name, value) that\n    //! may be accepted by the derived class.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //\n    virtual int Initialize(const std::vector<string> &paths, const std::vector<string> &options = std::vector<string>()) { return (initialize(paths, options)); }\n\n    //! Return a dimensions's definition\n    //!\n    //! This method returns the definition of the dimension named\n    //! by \\p dimname as a reference to a DC::Dimension object. If\n    //! \\p dimname is not defined as a dimension then the name of \\p dimension\n    //! will be the empty string()\n    //!\n    //! \\param[in] dimname A string specifying the name of the dimension.\n    //! \\param[out] dimension The returned Dimension object reference\n    //! \\retval bool If the named dimension can not be found false is returned.\n    //!\n    virtual bool GetDimension(string dimname, DC::Dimension &dimension, long ts) const { return (getDimension(dimname, dimension, ts)); }\n\n    //! Return names of all defined dimensions\n    //!\n    //! This method returns the list of names of all of the dimensions\n    //! defined in the DC.\n    //!\n    virtual std::vector<string> GetDimensionNames() const { return (getDimensionNames()); }\n\n    //! Return names of all defined meshes\n    //!\n    //! This method returns the list of names of all of the meshes\n    //! defined in the DC.\n    //!\n    virtual std::vector<string> GetMeshNames() const { return (getMeshNames()); }\n\n    //! Return a Mesh's definition\n    //!\n    //! This method returns the definition of the mesh named\n    //! by \\p mesh_name as a reference to a DC::Mesh object.\n    //!\n    //! \\param[in] mesh_name A string specifying the name of the Mesh.\n    //! \\param[out] mesh The returned Mesh object reference\n    //! \\retval bool If the named mesh can not be found false is returned.\n    //!\n    virtual bool GetMesh(string mesh_name, DC::Mesh &mesh) const { return (getMesh(mesh_name, mesh)); }\n\n    //! Return the ordered list of dimensions for a mesh\n    //!\n    //! This method is a convenience function that returns the ordered\n    //! vector of dimension lengths for the mesh named \\p mesh. If \\p mesh\n    //! is unknown, or invalid false is returned.\n    //!\n    //! \\sa DC::GetMesh(), DC::GetDimension()\n    //\n    virtual bool GetMeshDimLens(const string &mesh_name, std::vector<size_t> &dims, long ts = -1) const;\n\n    //! Return the ordered list of dimension names for a mesh\n    //!\n    //! This method is a convenience function that returns the ordered\n    //! vector of dimension names for the mesh named \\p mesh. If \\p mesh\n    //! is unknown, or invalid false is returned.\n    //!\n    //! \\sa DC::GetMesh(), DC::GetDimension()\n    //\n    virtual bool GetMeshDimNames(const string &mesh_name, std::vector<string> &dimnames) const;\n\n    //! Return a coordinate variable's definition\n    //!\n    //! Return a reference to a DC::CoordVar object describing\n    //! the coordinate variable named by \\p varname\n    //!\n    //! \\param[in] varname A string specifying the name of the coordinate\n    //! variable.\n    //! \\param[out] coordvar A CoordVar object containing the definition\n    //! of the named variable.\n    //! \\retval bool False is returned if the named coordinate variable does\n    //! not exist, and the contents of \\p cvar will be undefined.\n    //!\n    virtual bool GetCoordVarInfo(string varname, DC::CoordVar &cvar) const { return (getCoordVarInfo(varname, cvar)); }\n\n    //! Return a data variable's definition\n    //!\n    //! Return a reference to a DC::DataVar object describing\n    //! the data variable named by \\p varname\n    //!\n    //! \\param[in] varname A string specifying the name of the variable.\n    //! \\param[out] datavar A DataVar object containing the definition\n    //! of the named Data variable.\n    //!\n    //! \\retval bool If the named data variable cannot be found false\n    //! is returned and the values of \\p datavar are undefined.\n    //!\n    virtual bool GetDataVarInfo(string varname, DC::DataVar &datavar) const { return (getDataVarInfo(varname, datavar)); }\n\n    //! Return metadata about an auxiliary variable\n    //!\n    //! If the variable \\p varname is defined as an auxiliary\n    //! variable its metadata will\n    //! be returned in \\p var.\n    //!\n    //! \\retval bool If the named variable cannot be found false\n    //! is returned and the values of \\p var are undefined.\n    //!\n    //! \\sa GetDataVarInfo(), GetCoordVarInfo()\n    //\n    virtual bool GetAuxVarInfo(string varname, DC::AuxVar &var) const { return (getAuxVarInfo(varname, var)); }\n\n    //! Return metadata about a data or coordinate variable\n    //!\n    //! If the variable \\p varname is defined as either a\n    //! data or coordinate variable its metadata will\n    //! be returned in \\p var.\n    //!\n    //! \\retval bool If the named variable cannot be found false\n    //! is returned and the values of \\p var are undefined.\n    //!\n    //! \\sa GetDataVarInfo(), GetCoordVarInfo()\n    //\n    virtual bool GetBaseVarInfo(string varname, DC::BaseVar &var) const { return (getBaseVarInfo(varname, var)); }\n\n    //! Return a list of names for all of the defined data variables.\n    //!\n    //! Returns a list of names for all data variables defined\n    //!\n    //! \\sa DC::DataVar\n    //\n    virtual std::vector<string> GetDataVarNames() const { return (getDataVarNames()); }\n\n    //! Return a list of names for all of the defined coordinate variables.\n    //!\n    //! Returns a list of names for all coordinate variables defined\n    //!\n    //! \\sa DC::CoordVar\n    //\n    virtual std::vector<string> GetCoordVarNames() const { return (getCoordVarNames()); }\n\n    //! Return a list of names for all of the defined Auxiliary variables.\n    //!\n    //! Returns a list of names for all Auxiliary variables defined\n    //!\n    //! \\sa DC::AuxVar\n    //\n    virtual std::vector<string> GetAuxVarNames() const { return (getAuxVarNames()); }\n\n    //! Return the number of refinement levels for the indicated variable\n    //!\n    //! Compressed variables may have a multi-resolution grid representation.\n    //! This method returns the number of levels in the hiearchy. A value\n    //! of one indicates that only the native resolution is available.\n    //! A value of two indicates that two levels, the native plus the\n    //! next coarsest are available, and so on.\n    //!\n    //! \\param[in] varname Data or coordinate variable name.\n    //!\n    //! \\retval num If \\p varname is unknown one is returned. if \\p varname\n    //! is not compressed (has no multi-resolution representation) one is\n    //! returned. Otherwise the total number of levels in the multi-resolution\n    //! hierarchy are returned.\n    //\n    virtual size_t GetNumRefLevels(string varname) const { return (getNumRefLevels(varname)); }\n\n    //! Read an attribute\n    //!\n    //! This method reads an attribute from the DC. The attribute can either\n    //! be \"global\", if \\p varname is the empty string, or bound to a variable\n    //! if \\p varname indentifies a variable in the DC.\n    //!\n    //! \\param[in] varname The name of the variable the attribute is bound to,\n    //! or the empty string if the attribute is global\n    //! \\param[in] attname The attributes name\n    //! \\param[out] type The primitive data type storage format.\n    //! This is the type that will be used to store the\n    //! attribute on disk\n    //! \\param[out] values A vector to contain the returned floating point\n    //! attribute values\n    //!\n    //! \\retval status True is returned on success. False is returned if either\n    //! the variable or the attribute is undefined.\n    //!\n    //\n    virtual bool GetAtt(string varname, string attname, vector<double> &values) const { return (getAtt(varname, attname, values)); }\n\n    virtual bool GetAtt(string varname, string attname, vector<long> &values) const { return (getAtt(varname, attname, values)); }\n\n    virtual bool GetAtt(string varname, string attname, string &values) const { return (getAtt(varname, attname, values)); }\n\n    //! Return a list of available attribute's names\n    //!\n    //! Returns a vector of all attribute names for the\n    //! variable, \\p varname. If \\p varname is the empty string the names\n    //! of all of the global attributes are returned. If \\p varname is\n    //! not defined an empty vector is returned.\n    //!\n    //! \\param[in] varname The name of the variable to query,\n    //! or the empty string if the names of global attributes are desired.\n    //! \\retval attnames A vector of returned attribute names\n    //!\n    //! \\sa GetAtt()\n    //\n    virtual std::vector<string> GetAttNames(string varname) const { return (getAttNames(varname)); }\n\n    //! Return the external data type for an attribute\n    //!\n    //! Returns the external storage type of the named variable attribute.\n    //!\n    //! \\param[in] varname The name of the variable to query,\n    //! or the empty string if the names of global attributes are desired.\n    //! \\param[in] name Name of the attribute.\n    //!\n    //! \\retval If an attribute named by \\p name does not exist, a\n    //! negative value is returned.\n    //!\n    virtual XType GetAttType(string varname, string attname) const { return (getAttType(varname, attname)); }\n\n    //! Return a variable's array dimension lengths at a specified refinement level\n    //!\n    //! Compressed variables may have a multi-resolution grid representation.\n    //! This method returns the variable's ordered array\n    //! dimension lengths,\n    //! and block dimensions\n    //! at the multiresolution refinement level specified by \\p level.\n    //!\n    //! If the variable named by \\p varname is not compressed the variable's\n    //! native dimensions are returned.\n    //!\n    //! \\note The number of elements in \\p dims_at_level will match that of\n    //! \\p bs_at_level.  If the data are not blocked the value of each\n    //! element of \\p bs_at_level will be 1.\n    //!\n    //! \\param[in] varname Data or coordinate variable name.\n    //! \\param[in] level Specifies a member of a multi-resolution variable's\n    //! grid hierarchy as described above.\n    //! \\param[out] dims_at_level An ordered vector containing the variable's\n    //! dimensions at the specified refinement level\n    //! \\param[out] bs_at_level An ordered vector containing the variable's\n    //! block dimensions at the specified refinement level\n    //!\n    //! \\retval status Zero is returned upon success, otherwise -1.\n    //!\n    //! \\note For unstructured grids the number of dimensions may be\n    //! less than the topological dimension returned by DC::Mesh::GetTopologyDim().\n    //!\n    //! \\sa VAPoR::DC, DC::DataVar::GetBS(), DC::GetVarDimLens()\n    //\n    virtual int GetDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts = -1) const\n    {\n        return (getDimLensAtLevel(varname, level, dims_at_level, bs_at_level, ts));\n    }\n\n    //! Return a variable's array dimension lengths\n    //!\n    //! This method is equivalent to calling GetDimLensAtLevel() with \\p level\n    //! equal to -1\n    //!\n    virtual int GetDimLens(string varname, std::vector<size_t> &dims, long ts = -1)\n    {\n        vector<size_t> dummy;\n        return (GetDimLensAtLevel(varname, -1, dims, dummy, ts));\n    }\n\n    //! Return default Proj4 map projection string.\n    //!\n    //! For georeference data sets that have map projections this\n    //! method returns the default properly formatted Proj4 projection string\n    //! for mapping from geographic to cartographic coordinates.\n    //! If no\n    //! projection exists, an empty string is returned.\n    //!\n    //! \\retval  projstring An empty string if a Proj4 map projection is\n    //! not available for the named variable, otherwise a properly\n    //! formatted Proj4 projection\n    //! string is returned.\n    //!\n    //\n    virtual string GetMapProjection() const { return (getMapProjection()); }\n\n    //! Open the named variable for reading\n    //!\n    //! This method prepares a data or coordinate variable, indicated by a\n    //! variable name and time step pair, for subsequent read operations by\n    //! methods of this class.  The value of the refinement levels\n    //! parameter, \\p level, indicates the resolution of the volume in\n    //! the multiresolution hierarchy as described by GetDimLensAtLevel().\n    //!\n    //! The level-of-detail parameter, \\p lod, selects\n    //! the approximation level. Valid values for \\p lod are integers in\n    //! the range 0..n-1, where \\e n is returned by\n    //! DC::BaseVar::GetCRatios().size(), or the value -1 may be used\n    //! to select the best approximation available.\n    //!\n    //! An error occurs, indicated by a negative return value, if the\n    //! volume identified by the {varname, timestep, level, lod} tupple\n    //! is not available. Note the availability of a volume can be tested\n    //! with the VariableExists() method.\n    //!\n    //! \\param[in] ts Time step of the variable to read. This is the integer\n    //! offset into the variable's temporal dimension. If the variable\n    //! does not have a temporal dimension \\p ts is ignored.\n    //! \\param[in] varname Name of the variable to read\n    //! \\param[in] level Refinement level of the variable. Ignored if the\n    //! variable is not compressed.\n    //! \\param[in] lod Approximation level of the variable. A value of -1\n    //! indicates the maximum approximation level defined for the DC.\n    //! Ignored if the variable is not compressed.\n    //!\n    //! \\retval status Returns a non-negative file descriptor on success\n    //!\n    //!\n    //! \\sa GetNumRefLevels(), DC::BaseVar::GetCRatios(), OpenVariableRead()\n    //\n    virtual int OpenVariableRead(size_t ts, string varname, int level = 0, int lod = 0) { return (_openVariableRead(ts, varname, level, lod)); }\n\n    //! Close the currently opened variable\n    //!\n    //! Close the handle for variable opened with OpenVariableRead()\n    //! \\param[in] fd A valid file descriptor returned by OpenVariableRead()\n    //!\n    //! \\sa  OpenVariableRead()\n    //\n    virtual int CloseVariable(int fd) { return (_closeVariable(fd)); }\n\n    //! Read all spatial values of the currently opened variable\n    //!\n    //! This method reads, and decompresses as necessary,\n    //!  the contents of the currently opened variable into the array\n    //! \\p data. The number of values\n    //! read into \\p data is given by the product of the spatial\n    //! dimensions of the open variable at the refinement level specified.\n    //!\n    //! It is the caller's responsibility to ensure \\p data points\n    //! to adequate space.\n    //!\n    //! \\param[in] fd A valid file descriptor returned by OpenVariableRead()\n    //! \\param[out] data An array of data to be written\n    //! \\retval status Returns a non-negative value on success\n    //!\n    //! \\sa OpenVariableRead()\n    //\n    int virtual Read(int fd, float *data) { return (_readTemplate(fd, data)); }\n    int virtual Read(int fd, double *data) { return (_readTemplate(fd, data)); }\n    int virtual Read(int fd, int *data) { return (_readTemplate(fd, data)); }\n\n    //! Read a single slice of data from the currently opened variable\n    //!\n    //! Decompress, as necessary, and read a single hyperslice of\n    //! data from the variable\n    //! indicated by the most recent call to OpenVariableRead().\n    //! The dimensions and number of slices are given by\n    //! GetHyperSliceInfo().\n    //!\n    //! This method should be called exactly NZ times for each opened variable,\n    //! where NZ is the dimension of slowest varying dimension returned by\n    //! GetDimLensAtLevel().\n    //!\n    //! It is the caller's responsibility to ensure \\p slice points\n    //! to adequate space.\n    //!\n    //! \\param[in] fd A valid file descriptor returned by OpenVariableRead()\n    //! \\param[out] slice A slice of data\n    //! \\retval status Returns a non-negative value on success\n    //!\n    //! \\sa OpenVariableRead(), GetHyperSliceInfo()\n    //!\n    virtual int ReadSlice(int fd, float *slice) { return (_readSliceTemplate(fd, slice)); }\n    virtual int ReadSlice(int fd, double *slice) { return (_readSliceTemplate(fd, slice)); }\n    virtual int ReadSlice(int fd, int *slice) { return (_readSliceTemplate(fd, slice)); }\n\n    //! Read in and return a subregion from the currently opened\n    //! variable\n    //!\n    //! This method reads and returns a subset of variable data.\n    //! The \\p min and \\p max vectors, whose dimensions must match the\n    //! spatial rank of the currently opened variable, identify the minimum and\n    //! maximum extents, in grid coordinates, of the subregion of interest. The\n    //! minimum and maximum valid values of an element of \\b min or \\b max\n    //! are \\b 0 and\n    //! \\b n-1, respectively, where \\b n is the length of the associated\n    //! dimension at the opened refinement level.\n    //!\n    //! The region\n    //! returned is stored in the memory region pointed to by \\p region. It\n    //! is the caller's responsbility to ensure adequate space is available.\n    //!\n    //! \\param[in] fd A valid file descriptor returned by OpenVariableRead()\n    //! \\param[in] min Minimum region extents in grid coordinates\n    //! \\param[in] max Maximum region extents in grid coordinates\n    //! \\param[out] region The requested volume subregion\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //! \\sa OpenVariableRead(), GetDimLensAtLevel(), GetDimensionNames()\n    //\n    virtual int ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (readRegion(fd, min, max, region)); }\n    virtual int ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { return (readRegion(fd, min, max, region)); }\n    virtual int ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (readRegion(fd, min, max, region)); }\n\n\n    //! Read an entire variable in one call\n    //!\n    //! This method reads and entire variable (all time steps, all grid points)\n    //! from a DC.  This is the simplest interface for reading data from\n    //! a DC. If the variable is split across multiple files GetVar()\n    //! ensures that the data are correctly gathered and assembled into memory\n    //! Any variables currently opened with OpenVariableRead() are first closed.\n    //! Thus variables need not be opened with OpenVariableRead() prior to\n    //! calling GetVar();\n    //!\n    //! It is an error to call this method in \\b define mode\n    //!\n    //! \\param[in] varname Name of the variable to write\n    //! \\param[in] level Refinement level of the variable.\n    //! Ignored if the variable is not compressed.\n    //! \\param[in] lod Approximation level of the variable. A value of -1\n    //! indicates the maximum approximation level defined for the DC.\n    //! Ignored if the variable is not compressed.\n    //! \\param[out] data Pointer to where data will be copied. It is the\n    //! caller's responsbility to ensure \\p data points to sufficient memory.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //\n    virtual int GetVar(string varname, int level, int lod, float *data) { return (_getVarTemplate(varname, level, lod, data)); }\n    virtual int GetVar(string varname, int level, int lod, double *data) { return (_getVarTemplate(varname, level, lod, data)); }\n    virtual int GetVar(string varname, int level, int lod, int *data) { return (_getVarTemplate(varname, level, lod, data)); }\n\n    //! Read an entire variable at a given time step in one call\n    //!\n    //! This method reads and entire variable (all grid points) at\n    //! time step \\p ts\n    //! from a DC.  This is the simplest interface for reading data from\n    //! a DC.\n    //! Any variables currently opened with OpenVariableRead() are first closed.\n    //! Thus variables need not be opened with OpenVariableRead() prior to\n    //! calling GetVar();\n    //!\n    //! It is an error to call this method in \\b define mode\n    //!\n    //! \\param[in] ts Time step of the variable to write. This is the integer\n    //! offset into the variable's temporal dimension. If the variable\n    //! does not have a temporal dimension \\p ts is ignored.\n    //! \\param[in] varname Name of the variable to write\n    //! \\param[in] level Refinement level of the variable.\n    //! Ignored if the variable is not compressed.\n    //! \\param[in] lod Approximation level of the variable. A value of -1\n    //! indicates the maximum approximation level defined for the DC.\n    //! Ignored if the variable is not compressed.\n    //! \\param[out] data Pointer to where data will be copied. It is the\n    //! caller's responsbility to ensure \\p data points to sufficient memory.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //\n    virtual int GetVar(size_t ts, string varname, int level, int lod, float *data) { return (_getVarTemplate(ts, varname, level, lod, data)); }\n    virtual int GetVar(size_t ts, string varname, int level, int lod, double *data) { return (_getVarTemplate(ts, varname, level, lod, data)); }\n    virtual int GetVar(size_t ts, string varname, int level, int lod, int *data) { return (_getVarTemplate(ts, varname, level, lod, data)); }\n\n    //! Returns true if indicated data volume is available\n    //!\n    //! Returns true if the variable identified by the timestep, variable\n    //! name, refinement level, and level-of-detail is present in\n    //! the data set. Returns false if\n    //! the variable is not available.\n    //!\n    //! \\param[in] ts A valid time step between 0 and GetNumTimesteps()-1\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] reflevel Refinement level requested.\n    //! \\param[in] lod Compression level of detail requested.\n    //! refinement level contained in the DC.\n    //\n    virtual bool VariableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const { return (variableExists(ts, varname, reflevel, lod)); };\n\n    //! Get dimensions of hyperslice read by ReadSlice\n    //!\n    //! Returns the dimensions of a hyperslice when the variable\n    //! \\p varname is opened at level \\p level and read using ReadSlice();\n    //!\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] reflevel Refinement level requested.\n    //! \\param[out] dims An ordered vector containing the variable's\n    //! hyperslice dimensions at the specified refinement level\n    //! \\param[out] nslice Number of hyperslices\n    //!\n    //! \\sa GetDimLensAtLevel(), OpenVariableRead(), ReadSlice()\n    //!\n    virtual int GetHyperSliceInfo(string varname, int level, std::vector<size_t> &dims, size_t &nslice, long ts = -1);\n\n    //! Return a list of data variables with a given topological dimension\n    //!\n    //! Returns a list of all data variables defined having a\n    //! a topological dimension \\p ndim.\n    //!\n    //! \\param[in] ndim Topological dimension\n    //!\n    //! \\sa GetVarTopologyDim()\n    //\n    virtual std::vector<string> GetDataVarNames(int ndim) const;\n\n    //\n    //! Return an ordered list of the variables dimensions\n    //!\n    //! Returns a list of a variables dimensions ordered from fastest\n    //! to slowest. If \\p time is true and the variable is time varying\n    //! the time dimension will be included. The time dimension is always\n    //! the slowest varying dimension.\n    //!\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] spatial If true only return spatial dimensions\n    //!\n    //! \\param[out] dimensions Ordered list of variable dimensions\n    //! on success.\n    //!\n    //! \\retval Returns true upon success, false if the variable is\n    //! not defined.\n    //!\n    //\n    virtual bool GetVarDimensions(string varname, bool spatial, vector<DC::Dimension> &dimensions, long ts) const;\n\n    //\n    //! Return an ordered list of the variables dimension lengths\n    //!\n    //! Returns a list of a variables dimension lengths ordered from fastest\n    //! to slowest. If \\p spatial is true and the variable is time varying\n    //! the time dimension will be included. The time dimension is always\n    //! the slowest varying dimension.\n    //!\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] spatial If true only return spatial dimensions\n    //!\n    //! \\param[out] dimensions Ordered list of variable dimension lengths\n    //! on success.\n    //!\n    //! \\retval Returns true upon success, false if the variable is\n    //! not defined.\n    //!\n    //\n    virtual bool GetVarDimLens(string varname, bool spatial, vector<size_t> &dimlens, long ts = -1) const;\n\n    //! Return an ordered list of the variables dimension lengths\n    //!\n    //! Returns a list of a variable's spatial dimension lengths ordered from\n    //! fastest to slowest, and, if the variable is time varying, the variable's\n    //! time dimension lengths is returned as well.\n    //!\n    //! \\param[in] varname A valid variable name\n    //! \\param[out] sdimlens Ordered list of variable spatial dimension lengths\n    //! on success.\n    //! \\param[out] time_dimlen The variable's time dimension length. If\n    //! the variable is not time varying \\p time_dim_length will be set to 0.\n    //!\n    //! \\retval Returns true upon success, false if the variable is\n    //! not defined.\n    //!\n    //\n    virtual bool GetVarDimLens(string varname, vector<size_t> &sdimlens, size_t &time_dimlen, long ts = -1) const;\n\n    //! Return an ordered list of the variables dimension names\n    //!\n    //! Returns a list of a variables dimension names ordered from fastest\n    //! to slowest. If \\p spatial is true and the variable is time varying\n    //! the time dimension names will be included. The time dimension is always\n    //! the slowest varying dimension.\n    //!\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] spatial If true only return spatial dimensions\n    //!\n    //! \\param[out] dimensions Ordered list of variable dimension names\n    //! on success.\n    //!\n    //! \\retval Returns true upon success, false if the variable is\n    //! not defined.\n    //!\n    //\n    virtual bool GetVarDimNames(string varname, bool spatial, vector<string> &dimnames) const;\n\n    //! Return an ordered list of the variables dimension names\n    //!\n    //! Returns a list of a variable's spatial dimension names ordered from\n    //! fastest to slowest, and, if the variable is time varying, the variable's\n    //! time dimension name is returned as well.\n    //!\n    //! \\param[in] varname A valid variable name\n    //! \\param[out] sdimnames Ordered list of variable spatial dimension names\n    //! on success.\n    //! \\param[out] time_dimname The variable's time dimension name. If\n    //! the variable is not time varying \\p time_dim_name will be set to the\n    //! emptry string.\n    //!\n    //! \\retval Returns true upon success, false if the variable is\n    //! not defined.\n    //!\n    //\n    virtual bool GetVarDimNames(string varname, vector<string> &sdimnames, string &time_dimname) const;\n\n    //! Return the topological dimension of a variable\n    //!\n    //! Return the topological dimension of the mesh the defines\n    //! the variable data \\p varname\n    //!\n    //! \\retval dim Topological dimension or zero if variable is not known\n    //!\n    //! \\sa DC::Mesh::GetTopologyDim()\n    //\n    virtual size_t GetVarTopologyDim(string varname) const;\n\n    //! Return the geometric dimension of a variable\n    //!\n    //! Return the geometric dimension of the mesh the defines\n    //! the variable data \\p varname. I.e. return the number of spatial coordinate\n    //! variables associated with each node in the mesh.\n    //!\n    //! \\retval dim Geometric dimension or zero if variable is not known\n    //!\n    //! \\sa DC::Mesh::GetGeometryDim()\n    //\n    virtual size_t GetVarGeometryDim(string varname) const;\n\n    //! Return a boolean indicating whether a variable is time varying\n    //!\n    //! This method returns \\b true if the variable named by \\p varname is\n    //! a DataVar and it has a time coordiante\n    //! (See DataVar::GetTimeCoord()), or if the variable is a CoordVar and\n    //! its axis is time. Otherwise false is returnd.\n    //!\n    //! \\param[in] varname A string specifying the name of the variable.\n    //! \\retval bool Returns true if variable \\p varname exists and is\n    //! time varying.\n    //!\n    virtual bool IsTimeVarying(string varname) const;\n\n    //! Return a boolean indicating whether a variable is compressed\n    //!\n    //! This method returns \\b true if the variable named by \\p varname is defined\n    //! and it has a compressed representation. If either of these conditions\n    //! is not true the method returns false.\n    //!\n    //! \\param[in] varname A string specifying the name of the variable.\n    //! \\retval bool Returns true if variable \\p varname exists and is\n    //! compressed\n    //!\n    //\n    virtual bool IsCompressed(string varname) const;\n\n    //! Return the time dimension length for a variable\n    //!\n    //! Returns the number of time steps (length of the time dimension)\n    //! for which a variable is defined. If \\p varname does not have a\n    //! time coordinate 1 is returned. If \\p varname is not defined\n    //! as a variable zero is returned;\n    //!\n    //! \\param[in] varname A string specifying the name of the variable.\n    //! \\retval count The length of the time dimension, or a negative\n    //! int if \\p varname is undefined.\n    //!\n    //! \\retval n Returns the number of time steps for which the variable is\n    //! defined, or zero if the variable is not defined.\n    //!\n    //! \\sa IsTimeVarying()\n    //!\n    //\n    virtual int GetNumTimeSteps(string varname) const;\n\n    //! Return the compression ratio vector for the indicated variable\n    //!\n    //! Return the compression ratio vector for the indicated variable.\n    //! The vector returned contains an ordered list of available\n    //! compression ratios for the variable named by \\p variable.\n    //! If the variable is not compressed, or the variable named\n    //! \\p varname does not exist, the \\p cratios parameter will\n    //! contain a single element, one.\n    //!\n    //! \\retval cratios Ordered vector of compression ratios\n    //!\n    //\n    virtual std::vector<size_t> GetCRatios(string varname) const;\n\n    //! Return a boolean indicating whether a variable is a data variable\n    //!\n    //! This method returns \\b true if a data variable is defined\n    //! with the name \\p varname.  Otherwise the method returns false.\n    //!\n    //! \\retval bool Returns true if \\p varname names a defined data variable\n    //!\n    virtual bool IsDataVar(string varname) const\n    {\n        vector<string> names = GetDataVarNames();\n        return (find(names.begin(), names.end(), varname) != names.end());\n    }\n\n    //! Return a boolean indicating whether a variable is a coordinate variable\n    //!\n    //! This method returns \\b true if a coordinate variable is defined\n    //! with the name \\p varname.  Otherwise the method returns false.\n    //!\n    //! \\retval bool Returns true if \\p varname names a defined coordinate\n    //! variable\n    //!\n    virtual bool IsCoordVar(string varname) const\n    {\n        vector<string> names = GetCoordVarNames();\n        return (find(names.begin(), names.end(), varname) != names.end());\n    }\n\n    //! Return a boolean indicating whether a variable is an Auxiliary variable\n    //! \\version 3.1\n    //!\n    //! This method returns \\b true if a Auxiliary variable is defined\n    //! with the name \\p varname.  Otherwise the method returns false.\n    //!\n    //! \\retval bool Returns true if \\p varname names a defined Auxiliary\n    //! variable\n    //!\n    virtual bool IsAuxVar(string varname) const\n    {\n        vector<string> names = GetAuxVarNames();\n        return (find(names.begin(), names.end(), varname) != names.end());\n    }\n\n    //! Return an ordered list of a data variable's coordinate names\n    //!\n    //! Returns a list of a coordinate variable names for the variable\n    //! \\p varname, ordered from fastest\n    //! to slowest. If \\p spatial is true and the variable is time varying\n    //! the time coordinate variable name will be included. The time\n    //! coordinate variable is always\n    //! the slowest varying coordinate axis\n    //!\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] spatial If true only return spatial dimensions\n    //!\n    //! \\param[out] coordvars Ordered list of coordinate variable names.\n    //!\n    //! \\retval Returns true upon success, false if the variable is\n    //! not defined.\n    //!\n    //\n    virtual bool GetVarCoordVars(string varname, bool spatial, std::vector<string> &coord_vars) const;\n\n    //! Get mesh connectivity variables for a data variable\n    //!\n    //! Return the mesh connectivity variables for a data variable. For\n    //! a structured grid all connectivity variables will be empty. For\n    //! an unstructured mesh only the \\p face_node_var, \\p node_face_var\n    //! are guaranteed to be set to valid variable names\n    //!\n    bool GetVarConnVars(string varname, string &face_node_var, string &node_face_var, string &face_edge_var, string &face_face_var, string &edge_node_var, string &edge_face_var) const;\n\n    //! Get the rank of a variable\n    //!\n    //! This method returns the number of rank of the array describing a\n    //! variable. For structured data variables the rank is equal to\n    //! the topological dimension (See GetTopologyDim()).\n    //!\n    //! \\param[in] varname Name of variable to query\n    //!\n    //! \\retval Array rank. A value between 0 and 3, inclusive. If\n    //! \\p varname is unknown 0 is returned.\n    //!\n    virtual size_t GetNumDimensions(string varname) const;\n\n    //! Return a list of all of the available time coordinate variables\n    //!\n    //! This method returns all time coordinate variables defined\n    //!\n    std::vector<string> GetTimeCoordVarNames() const;\n\n    class VDF_API FileTable {\n    public:\n        FileTable();\n        virtual ~FileTable();\n\n        class FileObject {\n        public:\n            FileObject() : _ts(0), _varname(\"\"), _level(0), _lod(0), _slice(0), _aux(0) {}\n\n            FileObject(size_t ts, string varname, int level = 0, int lod = 0, int aux = 0) : _ts(ts), _varname(varname), _level(level), _lod(lod), _slice(0), _aux(aux) {}\n\n            size_t GetTS() const { return (_ts); }\n            string GetVarname() const { return (_varname); }\n            int    GetLevel() const { return (_level); }\n            int    GetLOD() const { return (_lod); }\n            int    GetSlice() const { return (_slice); }\n            void   SetSlice(int slice) { _slice = slice; }\n            int    GetAux() const { return (_aux); }\n\n        private:\n            size_t _ts;\n            string _varname;\n            int    _level;\n            int    _lod;\n            int    _slice;\n            int    _aux;\n        };\n\n        int         AddEntry(FileObject *obj);\n        FileObject *GetEntry(int fd) const;\n        void        RemoveEntry(int fd);\n        vector<int> GetEntries() const;\n\n    private:\n        std::vector<FileTable::FileObject *> _table;\n    };\n\nprotected:\n    DC::FileTable _fileTable;\n\n    //! \\copydoc Initialize()\n    //\n    virtual int initialize(const std::vector<string> &paths, const std::vector<string> &options = std::vector<string>()) = 0;\n\n    //! \\copydoc GetDimension()\n    //\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const = 0;\n\n    //! \\copydoc GetDimension()\n    //\n    virtual bool getDimension(string dimname, DC::Dimension &dimension, long ts) const { return getDimension(dimname, dimension); };\n\n    //! \\copydoc GetDimensionNames()\n    //\n    virtual std::vector<string> getDimensionNames() const = 0;\n\n    //! \\copydoc GetMeshNames()\n    //\n    virtual std::vector<string> getMeshNames() const = 0;\n\n    //! \\copydoc GetMesh()\n    //\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const = 0;\n\n    //! \\copydoc GetCoordVarInfo()\n    //\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const = 0;\n\n    //! \\copydoc GetDataVarInfo()\n    //\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const = 0;\n\n    //! \\copydoc GetAuxVarInfo()\n    //\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const = 0;\n\n    //! \\copydoc GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const = 0;\n\n    //! \\copydoc GetDataVarNames()\n    //\n    virtual std::vector<string> getDataVarNames() const = 0;\n\n    //! \\copydoc GetCoordVarNames()\n    //\n    virtual std::vector<string> getCoordVarNames() const = 0;\n\n    //! \\copydoc GetAuxVarNames()\n    //\n    virtual std::vector<string> getAuxVarNames() const = 0;\n\n    //! \\copydoc GetNumRefLevels()\n    //\n    virtual size_t getNumRefLevels(string varname) const = 0;\n\n    //! \\copydoc GetAtt(string varname, string attname, vector <double> &values)\n    //\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const = 0;\n\n    //! \\copydoc GetAtt(string varname, string attname, vector <long> &values)\n    //\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const = 0;\n\n    //! \\copydoc GetAtt(string varname, string attname, string &values)\n    //\n    virtual bool getAtt(string varname, string attname, string &values) const = 0;\n\n    //! \\copydoc GetAttNames()\n    //\n    virtual std::vector<string> getAttNames(string varname) const = 0;\n\n    //! \\copydoc GetAttType()\n    //\n    virtual XType getAttType(string varname, string attname) const = 0;\n\n    //! \\copydoc GetBlockSize()\n    //\n    virtual vector<size_t> getBlockSize() const { return (vector<size_t>()); }\n\n    //! \\copydoc GetDimLensAtLevel()\n    //\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const = 0;\n\n    //! \\copydoc GetDimLensAtLevel()\n    //\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const\n    {\n        return getDimLensAtLevel(varname, level, dims_at_level, bs_at_level);\n    };\n\n    //! \\copydoc GetMapProjection()\n    //\n    virtual string getMapProjection() const = 0;\n\n    //! \\copydoc OpenVariableRead()\n    //\n    virtual int openVariableRead(size_t ts, string varname, int level = 0, int lod = 0) = 0;\n\n    //! \\copydoc CloseVariable()\n    //\n    virtual int closeVariable(int fd) = 0;\n\n    //! \\copydoc ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) = 0;\n\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) = 0;\n\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) = 0;\n\n    //! \\copydoc VariableExists()\n    //\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const = 0;\n\nprivate:\n    virtual bool _getCoordVarDimensions(string varname, bool spatial, vector<DC::Dimension> &dimensions, long ts) const;\n\n    virtual bool _getDataVarDimensions(string varname, bool spatial, vector<DC::Dimension> &dimensions, long ts) const;\n\n    virtual bool _getAuxVarDimensions(string varname, vector<DC::Dimension> &dimensions, long ts) const;\n\n    vector<size_t> _getBlockSize() const;\n\n    virtual int _openVariableRead(size_t ts, string varname, int level = 0, int lod = 0);\n\n    virtual int _closeVariable(int fd);\n\n    template<class T> int _readSliceTemplate(int fd, T *slice);\n\n    template<class T> int _readTemplate(int fd, T *data);\n\n    template<class T> int _getVarTemplate(string varname, int level, int lod, T *data);\n\n    template<class T> int _getVarTemplate(size_t ts, string varname, int level, int lod, T *data);\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/DCBOV.h",
    "content": "#pragma once\n\n#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <vapor/MyBase.h>\n#include <vapor/NetCDFCFCollection.h>\n#include <vapor/Proj4API.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/utils.h>\n#include <vapor/DC.h>\n#include <vapor/BOVCollection.h>\n\nnamespace VAPoR {\n\nclass BOVCollection;\n\n// Example BOV header file, bovA1.bov\n//\n// # TIME is a floating point value specifying the timestep being read in DATA_FILE\n// TIME: 1.1\n//\n// # DATA_FILE points to a binary data file.  It can be a full file path, or a path relative to the BOV header.\n// DATA_FILE: bovA1.bin\n//\n// # The data size corresponds to NX,NY,NZ in the above example code.  It must contain three values\n// DATA_SIZE: 10 10 10\n//\n// # Allowable values for DATA_FORMAT are: INT,FLOAT,DOUBLE\n// DATA_FORMAT: FLOAT\n//\n// # VARIABLE is a string that specifies the variable being read in DATA_FILE.  Must be alphanumeric (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-)\n// VARIABLE: myVariable\n//\n// # BRICK_ORIGIN lets you specify a new coordinate system origin for # the mesh that will be created to suit your data.  It must contain three values.\n// BRICK_ORIGIN: 0. 0. 0.\n//\n// # BRICK_SIZE lets you specify the size of the brick on X, Y, and Z.  It must contain three values.\n// BRICK_SIZE: 10. 20. 5.\n//\n// # BYTE_OFFSET is optional and lets you specify some number of\n// # bytes to skip at the front of the file. This can be useful for # skipping the 4-byte header that Fortran tends to write to files. # If your file does not have a header then DO NOT USE\n// BYTE_OFFSET. BYTE_OFFSET: 4\n\n//!\n//! \\class DCBOV\n//! \\ingroup Public_VDCBOV\n//!\n//! \\brief Class for reading a \"Brick of Values\", explained in section 3.1 (page 11) in the\n//! following VisIt document: https://github.com/NCAR/VAPOR/files/6341067/GettingDataIntoVisIt2.0.0.pdf\n//!\n//! The following BOV tags are mandatory for Vapor to ingest data:\n//! - DATA_FILE    (type: string)\n//! - DATA_SIZE    (type: three integer values that are >1)\n//! - DATA_FORMAT  (type: string of either INT, FLOAT, or DOUBLE)\n//! - TIME         (type: one floating point value.  May not be equal to FLT_MIN)\n//!\n//! The following BOV tags are optional:\n//! - BRICK_ORIGIN (type: three floating point values,   default: 0., 0., 0.)\n//! - BRICK_SIZE   (type: three floating point values,   default: 1., 1., 1.)\n//! - VARIABLE     (type: one alphanumeric string value, default: \"brickVar\")\n//! - BYTE_OFFSET  (type: one integer value,             default: 0)\n//!\n//! The following BOV tags are currently unsupported.  They can be included in a BOV header,\n//! but they will be unused.\n//! - DATA_ENDIAN\n//! - CENTERING\n//! - DIVIDE_BRICK\n//! - DATA_BRICKLETS\n//! - DATA_COMPONENTS\n//!\n//! Each .bov file can only refer to a single data file for a single variable, at a single timestep.\n//! If duplicate key/value pairs exist in a BOV header, the value closest to the bottom of the file will be used.\n//! If duplicate values exist for whatever reason, all entries must be valid (except for DATA_FILE, which gets validated after parsing)\n//! Scientific notation is supported for floating point values like BRICK_ORIGIN and BRICK_SIZE.\n//! Scientific notation is not supported for integer values like DATA_SIZE.\n//! DATA_SIZE must contain three values greater than 1.\n//! Wild card characters are not currently supported in the DATA_FILE token.\n//! VARIABLE must be alphanumeric (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-)\n//!\n//! \\author Scott Pearse\n//! \\date    May, 2021\n//!\nclass VDF_API DCBOV : public VAPoR::DC {\npublic:\n    //! Class constuctor\n    //!\n    //!\n    DCBOV();\n    virtual ~DCBOV();\n\nprotected:\n    //! Initialize the DCBOV class\n    //!\n    //! Prepare a BOV data set for reading. This method prepares\n    //! the DCBOV class for reading the files indicated by\n    //! \\p paths.\n    //! The method should be called immediately after the constructor,\n    //! before any other class methods. This method\n    //! exists only because C++ constructors can not return error codes.\n    //!\n    //! \\param[in] path A single BOV header file describing a the structore of a \"Brick\n    //! of raw IEEE floating point numbers stored in a file.\n    //! a single CF model run.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa EndDefine();\n    //\n    virtual int initialize(const vector<string> &paths, const std::vector<string> &options);\n\n    //! \\copydoc DC::getDimension()\n    //!\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const;\n\n    //! \\copydoc DC::getDimensionNames()\n    //!\n    virtual std::vector<string> getDimensionNames() const;\n\n    //! \\copydoc DC::getMeshNames()\n    //!\n    std::vector<string> getMeshNames() const;\n\n    //! \\copydoc DC::getMesh()\n    //!\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc DC::GetCoordVarInfo()\n    //!\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const;\n\n    //! \\copydoc DC::GetDataVarInfo()\n    //!\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const;\n\n    //! \\copydoc DC::GetAuxVarInfo()\n    //!\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const { return (false); }\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const;\n\n    //! \\copydoc DC::GetDataVarNames()\n    //!\n    virtual std::vector<string> getDataVarNames() const;\n\n    virtual std::vector<string> getAuxVarNames() const { return (vector<string>()); }\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual std::vector<string> getCoordVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual size_t getNumRefLevels(string varname) const { return (1); }\n\n    //! \\copydoc DC::GetMapProjection()\n    //!\n    virtual string getMapProjection() const { return (\"\"); }\n\n    //! \\copydoc DC::GetAtt()\n    //!\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const;\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const;\n    virtual bool getAtt(string varname, string attname, string &values) const;\n\n    //! \\copydoc DC::GetAttNames()\n    //!\n    virtual std::vector<string> getAttNames(string varname) const;\n\n    //! \\copydoc DC::GetAttType()\n    //!\n    virtual XType getAttType(string varname, string attname) const;\n\n    //! \\copydoc DC::GetDimLensAtLevel()\n    //!\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    //! \\copydoc DC::OpenVariableRead()\n    //!\n    virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCBOV::openVariableRead(ts, varname)); }\n\n    virtual int openVariableRead(size_t ts, string varname);\n\n    //! \\copydoc DC::CloseVariable()\n    //!\n    virtual int closeVariable(int fd);\n\n    //! \\copydoc DC::ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\n    //! \\copydoc DC::VariableExists()\n    //!\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\nprivate:\n    VAPoR::UDUnits _udunits;\n\n    BOVCollection *_bovCollection;\n\n    string                          _varname;\n    std::map<string, DC::Dimension> _dimsMap;\n    std::map<string, DC::CoordVar>  _coordVarsMap;\n    std::map<string, DC::Mesh>      _meshMap;\n    std::map<string, DC::DataVar>   _dataVarsMap;\n    std::map<string, string>        _coordVarKeys;\n\n    void _InitCoordinates();\n\n    void _InitDimensions();\n\n    void _InitVars();\n\n    int _isCoordinateVariable(std::string variable) const;\n\n    template<class T> void _generateCoordinates(int dim, const vector<size_t> &min, const vector<size_t> &max, T *region) const;\n\n    template<class T> int _readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region);\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/DCCF.h",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <memory>\n#include <vapor/MyBase.h>\n#include <vapor/NetCDFCFCollection.h>\n#include <vapor/Proj4API.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/utils.h>\n#include <vapor/DC.h>\n\n#ifndef _DCCF_H_\n    #define _DCCF_H_\n\nnamespace VAPoR {\n\n\n//!\n//! \\class DCCF\n//! \\ingroup Public_VDCCF\n//!\n//! \\brief Class for reading a NetCDF Climate Forecast (CF)  data set\n//! stored as a series\n//! of NetCDF files.\n//!\n//! \\author John Clyne\n//! \\date    March, 2015\n//!\nclass VDF_API DCCF : public VAPoR::DC {\npublic:\n    //! Class constuctor\n    //!\n    //!\n    DCCF();\n    virtual ~DCCF();\n    \n    int BuildCache();\n    int Reinitialize();\n\nprotected:\n    NetCDFCFCollection *_ncdfc = nullptr;\n    vector<string> _paths;\n\n    //! Initialize the DCCF class\n    //!\n    //! Prepare a CF data set for reading. This method prepares\n    //! the DCCF class for reading the files indicated by\n    //! \\p paths.\n    //! The method should be called immediately after the constructor,\n    //! before any other class methods. This method\n    //! exists only because C++ constructors can not return error codes.\n    //!\n    //! \\param[in] path A list of CF NetCDF files comprising the output of\n    //! a single CF model run.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa EndDefine();\n    //\n    virtual int initialize(const vector<string> &paths, const std::vector<string> &options);\n    virtual int initialize_impl(const vector<string> &paths, const std::vector<string> &options, \n                                std::unique_ptr<NetCDFCFCollection> ncdfc);\n\n    //! \\copydoc DC::getDimension()\n    //!\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const;\n\n    //! \\copydoc DC::getDimensionNames()\n    //!\n    virtual std::vector<string> getDimensionNames() const;\n\n    //! \\copydoc DC::getMeshNames()\n    //!\n    std::vector<string> getMeshNames() const;\n\n    //! \\copydoc DC::getMesh()\n    //!\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc DC::GetCoordVarInfo()\n    //!\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const;\n\n    //! \\copydoc DC::GetDataVarInfo()\n    //!\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const;\n\n    //! \\copydoc DC::GetAuxVarInfo()\n    //!\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const;\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const;\n\n    //! \\copydoc DC::GetDataVarNames()\n    //!\n    virtual std::vector<string> getDataVarNames() const;\n\n    virtual std::vector<string> getAuxVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual std::vector<string> getCoordVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual size_t getNumRefLevels(string varname) const { return (1); }\n\n    //! \\copydoc DC::GetMapProjection()\n    //!\n    virtual string getMapProjection() const\n    {\n        // Projections not supported yet :-(\n        //\n        return (_proj4String);\n    }\n\n    //! \\copydoc DC::GetAtt()\n    //!\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const;\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const;\n    virtual bool getAtt(string varname, string attname, string &values) const;\n\n    //! \\copydoc DC::GetAttNames()\n    //!\n    virtual std::vector<string> getAttNames(string varname) const;\n\n    //! \\copydoc DC::GetAttType()\n    //!\n    virtual XType getAttType(string varname, string attname) const;\n\n    //! \\copydoc DC::GetDimLensAtLevel()\n    //!\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    //! \\copydoc DC::OpenVariableRead()\n    //!\n    virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCCF::openVariableRead(ts, varname)); }\n\n    virtual int openVariableRead(size_t ts, string varname);\n\n    //! \\copydoc DC::CloseVariable()\n    //!\n    virtual int closeVariable(int fd);\n\n    //! \\copydoc DC::ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\n    //! \\copydoc DC::VariableExists()\n    //!\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\n    virtual int initDimensions(NetCDFCFCollection *ncdfc, std::map<string, DC::Dimension> &dimsMap);\n\n    virtual int initCoordinates(NetCDFCFCollection *ncdfc, std::map<string, DC::CoordVar> &coordVarsMap);\n\n    virtual int addCoordvars(NetCDFCFCollection *ncdfc, const vector<string> &cvars, std::map<string, DC::CoordVar> &coordVarsMap);\n\n    virtual int initDataVars(NetCDFCFCollection *ncdfc, std::map<string, DC::DataVar> &dataVarsMap);\n\n    virtual int initAuxilliaryVars(NetCDFCFCollection *ncdfc, std::map<string, DC::AuxVar> &auxVarsMap);\n\n    virtual int initMesh(NetCDFCFCollection *ncdfc, std::map<string, DC::Mesh> &_meshMap);\n\n    virtual int getVarCoordinates(NetCDFCFCollection *ncdfc, string varname, vector<string> &sdimnames, vector<string> &scoordvars, string &time_dim_name, string &time_coordvar) const;\n\n\nprivate:\n    VAPoR::UDUnits _udunits;\n\n    string                                      _proj4String;\n    std::map<string, DC::Dimension>             _dimsMap;\n    std::map<string, DC::CoordVar>              _coordVarsMap;\n    std::map<string, DC::Mesh>                  _meshMap;\n    std::map<string, DC::DataVar>               _dataVarsMap;\n    std::map<string, DC::AuxVar>                _auxVarsMap;\n\n    int _initHorizontalCoordinates(NetCDFCFCollection *ncdfc, std::map<string, DC::CoordVar> &coordVarsMap);\n\n    int _initVerticalCoordinates(NetCDFCFCollection *ncdfc, std::map<string, DC::CoordVar> &coordVarsMap);\n\n    int _initTimeCoordinates(NetCDFCFCollection *ncdfc, std::map<string, DC::CoordVar> &coordVarsMap);\n\n    // Return true if a 1D variable has uniform, absolute deltas between elements\n    //\n    bool _isUniform(NetCDFCFCollection *ncdfc, string varname);\n\n\n    template<class T> int _readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region);\n\n    template<class T> bool _getAttTemplate(string varname, string attname, T &values) const;\n\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/DCMPAS.h",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <vapor/MyBase.h>\n#include <vapor/NetCDFCollection.h>\n#include <vapor/DerivedVar.h>\n#include <vapor/DerivedVarMgr.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/utils.h>\n#include <vapor/DC.h>\n\n#ifndef _DCMPAS_H_\n    #define _DCMPAS_H_\n\nnamespace VAPoR {\n\nclass DerivedCoordVar_WRFTime;\n\n//!\n//! \\class DCMPAS\n//! \\ingroup Public_VDCMPAS\n//!\n//! \\brief Class for reading a NetCDF Climate Forecast (MPAS)  data set\n//! stored as a series\n//! of NetCDF files.\n//!\n//! \\author John Clyne\n//! \\date    March, 2015\n//!\nclass VDF_API DCMPAS : public VAPoR::DC {\npublic:\n    //! Class constuctor\n    //!\n    //!\n    DCMPAS();\n    virtual ~DCMPAS();\n\nprotected:\n    //! Initialize the DCMPAS class\n    //!\n    //! Prepare a MPAS data set for reading. This method prepares\n    //! the DCMPAS class for reading the files indicated by\n    //! \\p paths.\n    //! The method should be called immediately after the constructor,\n    //! before any other class methods. This method\n    //! exists only because C++ constructors can not return error codes.\n    //!\n    //! \\param[in] path A list of MPAS NetCDF files comprising the output of\n    //! a single MPAS model run.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa EndDefine();\n    //\n    virtual int initialize(const vector<string> &paths, const std::vector<string> &options);\n\n    //! \\copydoc DC::GetDimension()\n    //!\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const;\n\n    //! \\copydoc DC::getDimensionNames()\n    //!\n    virtual std::vector<string> getDimensionNames() const;\n\n    //! \\copydoc DC::getMeshNames()\n    //!\n    std::vector<string> getMeshNames() const;\n\n    //! \\copydoc DC::getMesh()\n    //!\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc DC::GetCoordVarInfo()\n    //!\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const;\n\n    //! \\copydoc DC::GetDataVarInfo()\n    //!\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const;\n\n    //! \\copydoc DC::GetAuxVarInfo()\n    //\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const;\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const;\n\n    //! \\copydoc DC::GetDataVarNames()\n    //!\n    virtual std::vector<string> getDataVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual std::vector<string> getCoordVarNames() const;\n\n    virtual std::vector<string> getAuxVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual size_t getNumRefLevels(string varname) const { return (1); }\n\n    //! \\copydoc DC::GetMapProjection()\n    //!\n    virtual string getMapProjection() const { return (\"+proj=eqc +ellps=WGS84 +lon_0=0.0 +lat_0=0.0\"); }\n\n    //! \\copydoc DC::GetAtt()\n    //!\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const;\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const;\n    virtual bool getAtt(string varname, string attname, string &values) const;\n\n    //! \\copydoc DC::GetAttNames()\n    //!\n    virtual std::vector<string> getAttNames(string varname) const;\n\n    //! \\copydoc DC::GetAttType()\n    //!\n    virtual XType getAttType(string varname, string attname) const;\n\n    //! \\copydoc DC::GetDimLensAtLevel()\n    //!\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual int openVariableRead(size_t ts, string varname, int, int);\n\n    //! \\copydoc DC::CloseVariable()\n    //!\n    virtual int closeVariable(int fd);\n\n    //! \\copydoc DC::ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\n    //! \\copydoc DC::VariableExists()\n    //!\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\nprivate:\n    NetCDFCollection *_ncdfc;\n    VAPoR::UDUnits    _udunits;\n    DerivedVarMgr     _dvm;\n    bool              _hasVertical;    // has 3D data (i.e. vertical data)\n\n    class MPASFileObject : public DC::FileTable::FileObject {\n    public:\n        MPASFileObject(size_t ts, string varname, int level, int lod, int fd, bool derivedFlag) : FileObject(ts, varname, level, lod, fd), _derivedFlag(derivedFlag) {}\n\n        bool GetDerivedFlag() const { return (_derivedFlag); }\n\n    private:\n        bool _derivedFlag;\n    };\n\n    std::map<string, DC::Dimension> _dimsMap;\n    std::map<string, DC::CoordVar>  _coordVarsMap;\n    std::map<string, DC::Mesh>      _meshMap;\n    std::map<string, DC::DataVar>   _dataVarsMap;\n    std::map<string, DC::AuxVar>    _auxVarsMap;\n    std::vector<string>             _cellVars;\n    std::vector<string>             _pointVars;\n    std::vector<string>             _edgeVars;\n    Wasp::SmartBuf                  _nEdgesOnCellBuf;\n    Wasp::SmartBuf                  _lonCellSmartBuf;\n    Wasp::SmartBuf                  _lonVertexSmartBuf;\n\n    int _InitDerivedVars(NetCDFCollection *ncdfc);\n    int _InitCoordvars(NetCDFCollection *ncdfc);\n\n    int _InitVerticalCoordinatesDerivedAtmosphere(NetCDFCollection *ncdfc);\n    int _InitVerticalCoordinatesDerivedOcean(NetCDFCollection *ncdfc);\n\n    int  _CheckRequiredFields(NetCDFCollection *ncdfc) const;\n    bool _HasVertical(NetCDFCollection *ncdfc) const;\n\n    int _InitDimensions(NetCDFCollection *ncdfc);\n\n    int _GetVarCoordinates(NetCDFCollection *ncdfc, string varname, vector<string> &sdimnames, vector<string> &scoordvars, string &time_dim_name, string &time_coordvar);\n\n    int _InitMeshes(NetCDFCollection *ncdfc);\n    int _InitAuxVars(NetCDFCollection *ncdfc);\n    int _InitDataVars(NetCDFCollection *ncdfc);\n\n    vector<string> _GetSpatialDimNames(NetCDFCollection *ncdfc, string varname) const;\n\n    bool _isAtmosphere(NetCDFCollection *ncdfc) const;\n    bool _isOcean(NetCDFCollection *ncdfc) const;\n\n    bool _isCoordVar(string varname) const;\n    bool _isDataVar(string varname) const;\n\n    int  _read_nEdgesOnCell(size_t ts);\n    void _addMissingFlag(int *data) const;\n    int  _readVarToSmartBuf(size_t ts, string varname, Wasp::SmartBuf &smartBuf);\n    int  _readCoordinates(size_t ts);\n\n    void _splitOnBoundary(string varname, int *connData) const;\n\n    int _readRegionTransposed(MPASFileObject *w, const vector<size_t> &min, const vector<size_t> &max, float *region);\n\n    int _readRegionEdgeVariable(MPASFileObject *w, const vector<size_t> &min, const vector<size_t> &max, float *region);\n\n    template<class T> int _readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region);\n\n    template<class T> bool _getAttTemplate(string varname, string attname, T &values) const;\n\n    // Derive vertical coordinate variable for dual mesh from primary mesh\n    //\n    class DerivedCoordVertFromCell : public DerivedCoordVar {\n    public:\n        DerivedCoordVertFromCell(string derivedVarName, string derivedDimName, DC *dc, string inName, string cellsOnVertexName);\n\n        int Initialize();\n\n        bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n        bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n        virtual std::vector<string> GetInputs() const { return (std::vector<string>{_inName}); }\n\n        int GetDimLensAtLevel(int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n        int OpenVariableRead(size_t ts, int, int);\n\n        int CloseVariable(int fd);\n\n        int ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region);\n\n        bool VariableExists(size_t ts, int, int) const;\n\n    private:\n        string       _derivedDimName;\n        DC *         _dc;\n        string       _inName;\n        string       _cellsOnVertexName;\n        DC::CoordVar _coordVarInfo;\n\n        float *_getCellData();\n\n        int *_getCellsOnVertex(size_t i0, size_t i1, int &vertexDegree);\n    };\n\n    // Derive Uzonal and Umeridional data variable\n    //\n    class DerivedZonalMeridonal : public DerivedDataVar {\n    public:\n        DerivedZonalMeridonal(string derivedVarName, DC *dc, NetCDFCollection *ncdfc, string normalVarName, string tangentialVarName, bool zonalFlag);\n\n        int Initialize();\n\n        bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n        bool GetDataVarInfo(DC::DataVar &cvar) const;\n\n        virtual std::vector<string> GetInputs() const { return (std::vector<string>{_normalVarName, _tangentialVarName}); }\n\n        int GetDimLensAtLevel(int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n        int OpenVariableRead(size_t ts, int, int);\n\n        int CloseVariable(int fd);\n\n        int ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region);\n\n        bool VariableExists(size_t ts, int, int) const;\n\n    private:\n        DC *              _dc;\n        NetCDFCollection *_ncdfc;\n        string            _normalVarName;\n        string            _tangentialVarName;\n        bool              _zonalFlag;\n        DC::DataVar       _dataVarInfo;\n    };\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/DCMelanie.h",
    "content": "#ifdef BUILD_DC_MELANIE\n\n    #include <vector>\n    #include <algorithm>\n    #include <map>\n    #include <iostream>\n    #include <vapor/MyBase.h>\n    #include <vapor/NetCDFCFCollection.h>\n    #include <vapor/Proj4API.h>\n    #include <vapor/UDUnitsClass.h>\n    #include <vapor/utils.h>\n    #include <vapor/DC.h>\n    #include <vapor/STLUtils.h>\n\n    #ifndef _DCMelanie_H_\n        #define _DCMelanie_H_\n\nnamespace VAPoR {\n\n\nclass VDF_API DCMelanie : public VAPoR::DC {\npublic:\n    DCMelanie();\n    virtual ~DCMelanie();\n\nprotected:\n    //! Initialize the DCMelanie class\n    //!\n    //! Prepare a CF data set for reading. This method prepares\n    //! the DCMelanie class for reading the files indicated by\n    //! \\p paths.\n    //! The method should be called immediately after the constructor,\n    //! before any other class methods. This method\n    //! exists only because C++ constructors can not return error codes.\n    //!\n    //! \\param[in] path A list of CF NetCDF files comprising the output of\n    //! a single CF model run.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa EndDefine();\n    //\n    virtual int initialize(const vector<string> &paths, const std::vector<string> &options);\n\n\n    //! \\copydoc DC::getDimension()\n    //!\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const;\n\n    //! \\copydoc DC::getDimensionNames()\n    //!\n    virtual std::vector<string> getDimensionNames() const;\n\n    //! \\copydoc DC::getMeshNames()\n    //!\n    std::vector<string> getMeshNames() const;\n\n    //! \\copydoc DC::getMesh()\n    //!\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc DC::GetCoordVarInfo()\n    //!\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const;\n\n    //! \\copydoc DC::GetDataVarInfo()\n    //!\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const;\n\n    //! \\copydoc DC::GetAuxVarInfo()\n    //!\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const;\n\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const;\n\n\n\n    //! \\copydoc DC::GetDataVarNames()\n    //!\n    virtual std::vector<string> getDataVarNames() const;\n\n    virtual std::vector<string> getAuxVarNames() const;\n\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual std::vector<string> getCoordVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual size_t getNumRefLevels(string varname) const { return (1); }\n\n    //! \\copydoc DC::GetMapProjection()\n    //!\n    virtual string getMapProjection() const\n    {\n        // Projections not supported yet :-(\n        //\n        return (_proj4String);\n    }\n\n    //! \\copydoc DC::GetAtt()\n    //!\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const;\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const;\n    virtual bool getAtt(string varname, string attname, string &values) const;\n\n    //! \\copydoc DC::GetAttNames()\n    //!\n    virtual std::vector<string> getAttNames(string varname) const;\n\n    //! \\copydoc DC::GetAttType()\n    //!\n    virtual XType getAttType(string varname, string attname) const;\n\n    //! \\copydoc DC::GetDimLensAtLevel()\n    //!\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n\n    //! \\copydoc DC::OpenVariableRead()\n    //!\n    virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCMelanie::openVariableRead(ts, varname)); }\n\n    virtual int openVariableRead(size_t ts, string varname);\n\n\n    //! \\copydoc DC::CloseVariable()\n    //!\n    virtual int closeVariable(int fd);\n\n    //! \\copydoc DC::ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\n    //! \\copydoc DC::VariableExists()\n    //!\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\nprivate:\n    NetCDFCFCollection *_ncdfc;\n    VAPoR::UDUnits      _udunits;\n\n    string                                      _proj4String;\n    std::map<string, DC::Dimension>             _dimsMap;\n    std::map<string, DC::CoordVar>              _coordVarsMap;\n    std::map<string, DC::AuxVar>                _auxVarsMap;\n    std::map<string, DC::Mesh>                  _meshMap;\n    std::map<string, DC::DataVar>               _dataVarsMap;\n    std::map<string, string>                    _coordVarKeys;\n    std::map<string, string>                    _sanitizedToOriginalMap;\n    std::vector<NetCDFCollection::DerivedVar *> _derivedVars;\n\n    const string          nodeFaceVar = \"cellsOnVertex\";\n    const string          faceNodeVar = \"verticesOnCell\";\n    const vector<string>  fakeVars = {nodeFaceVar, faceNodeVar};\n    int                   fakeVarsFileCounterStart = 10000;\n    int                   fakeVarsFileCounter = fakeVarsFileCounterStart;\n    std::map<int, string> _fdMap;\n\n\n    string sanitizeVarName(const string &name);\n    string getOriginalVarName(const string &name) const;\n\n    template<class T> int _readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region);\n\n    template<class T> bool _getAttTemplate(string varname, string attname, T &values) const;\n};\n};    // namespace VAPoR\n\n    #endif\n#endif\n"
  },
  {
    "path": "include/vapor/DCP.h",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <vapor/MyBase.h>\n#include <vapor/NetCDFCFCollection.h>\n#include <vapor/Proj4API.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/utils.h>\n#include <vapor/DC.h>\n#include <vapor/STLUtils.h>\n\n#ifndef _DCP_H_\n    #define _DCP_H_\n\n//! This enables a beta feature which automatically generates particle density fields\n//! when importing particle data. In it's current state, if DCP_ENABLE_PARTICLE_DENSITY\n//! is set to 1, it will work but the volume will have a fixed grid size and it uses a sub-optimal sampling algorithm.\n    #define DCP_ENABLE_PARTICLE_DENSITY 0\n\nnamespace VAPoR {\n\n\n//! DCP is a simple daa format for particle data. The full specification can be found at\n//! vapor/share/doc/DCP_Format.md\n\nclass VDF_API DCP : public VAPoR::DC {\npublic:\n    DCP();\n    virtual ~DCP();\n\nprotected:\n    //! Initialize the DCP class\n    //!\n    //! Prepare a CF data set for reading. This method prepares\n    //! the DCP class for reading the files indicated by\n    //! \\p paths.\n    //! The method should be called immediately after the constructor,\n    //! before any other class methods. This method\n    //! exists only because C++ constructors can not return error codes.\n    //!\n    //! \\param[in] path A list of CF NetCDF files comprising the output of\n    //! a single CF model run.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa EndDefine();\n    //\n    virtual int initialize(const vector<string> &paths, const std::vector<string> &options);\n\n\n    //! \\copydoc DC::getDimension()\n    //!\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const;\n    virtual bool getDimension(string dimname, DC::Dimension &dimension, long ts) const;\n\n    //! \\copydoc DC::getDimensionNames()\n    //!\n    virtual std::vector<string> getDimensionNames() const;\n\n    //! \\copydoc DC::getMeshNames()\n    //!\n    std::vector<string> getMeshNames() const;\n\n    //! \\copydoc DC::getMesh()\n    //!\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc DC::GetCoordVarInfo()\n    //!\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const;\n\n    //! \\copydoc DC::GetDataVarInfo()\n    //!\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const;\n\n    //! \\copydoc DC::GetAuxVarInfo()\n    //!\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const;\n\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const;\n\n\n\n    //! \\copydoc DC::GetDataVarNames()\n    //!\n    virtual std::vector<string> getDataVarNames() const;\n\n    virtual std::vector<string> getAuxVarNames() const;\n\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual std::vector<string> getCoordVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual size_t getNumRefLevels(string varname) const { return (1); }\n\n    //! \\copydoc DC::GetMapProjection()\n    //!\n    virtual string getMapProjection() const\n    {\n        // Projections not supported yet :-(\n        //\n        return (_proj4String);\n    }\n\n    //! \\copydoc DC::GetAtt()\n    //!\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const;\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const;\n    virtual bool getAtt(string varname, string attname, string &values) const;\n\n    //! \\copydoc DC::GetAttNames()\n    //!\n    virtual std::vector<string> getAttNames(string varname) const;\n\n    //! \\copydoc DC::GetAttType()\n    //!\n    virtual XType getAttType(string varname, string attname) const;\n\n    //! \\copydoc DC::GetDimLensAtLevel()\n    //!\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const;\n\n\n    //! \\copydoc DC::OpenVariableRead()\n    //!\n    virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCP::openVariableRead(ts, varname)); }\n\n    virtual int openVariableRead(size_t ts, string varname);\n\n\n    //! \\copydoc DC::CloseVariable()\n    //!\n    virtual int closeVariable(int fd);\n\n    //! \\copydoc DC::ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\n\n    //! \\copydoc DC::VariableExists()\n    //!\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\nprivate:\n    NetCDFCollection *_ncdfc;\n    VAPoR::UDUnits    _udunits;\n\n    string                          _proj4String;\n    std::map<string, DC::Dimension> _dimsMap;\n    std::map<string, DC::CoordVar>  _coordVarsMap;\n    std::map<string, DC::AuxVar>    _auxVarsMap;\n    std::map<string, DC::Mesh>      _meshMap;\n    std::map<string, DC::DataVar>   _dataVarsMap;\n    std::map<string, string>        _coordVarKeys;\n    std::map<string, string>        _sanitizedToOriginalMap;\n\n    const string          _nodeFaceVar = \"cellsOnVertex\";\n    const string          _faceNodeVar = \"verticesOnCell\";\n    const string          _fakeEmptyVar = \"empty\";\n    vector<string>        _fakeVars = {_nodeFaceVar, _faceNodeVar};\n    int                   _fakeVarsFileCounterStart = 10000;\n    int                   _fakeVarsFileCounter = _fakeVarsFileCounterStart;\n    std::map<int, string> _fdMap;\n\n\n    string sanitizeVarName(const string &name);\n    string getOriginalVarName(const string &name) const;\n    bool   isCoordVar(const string &var) const;\n    int    getAxis(const string &var) const;\n    string getUnits(const string &var) const;\n    string getTimeCoordVar(const string &var) const;\n\n    template<class T> int _readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region);\n\n    template<class T> bool _getAttTemplate(string varname, string attname, T &values) const;\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/DCRAM.h",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <vapor/MyBase.h>\n#include <vapor/NetCDFCFCollection.h>\n#include <vapor/Proj4API.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/utils.h>\n#include <vapor/DC.h>\n#include <vapor/STLUtils.h>\n\n#pragma once\n\nnamespace VAPoR {\n\n\n//! \\class DCRAM\n//! \\brief DCRAM is a virtual data collection used to allow data to be loaded from ram. Specifically, this is used by PythonDataMgr\n//! \\author Stas Jaroszynski\n\nclass VDF_API DCRAM : public VAPoR::DC {\npublic:\n    DCRAM();\n    virtual ~DCRAM();\n    \n    void Test();\n    \n    void AddDimension(const DC::Dimension &dim);\n    void AddMesh(const DC::Mesh &mesh);\n    void AddCoordVar(const DC::CoordVar &var, const float *buf);\n    void AddDataVar(const DC::DataVar &var, const float *buf);\n\nprotected:\n    map<string, float*> _dataMap;\n    \n    void copyVarData(const DC::BaseVar &var, const float *buf, const size_t size);\n    \n    //! \\copydoc DC::Initialize()\n    //!\n    virtual int initialize(const vector<string> &paths, const std::vector<string> &options);\n\n\n    //! \\copydoc DC::getDimension()\n    //!\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const;\n    virtual bool getDimension(string dimname, DC::Dimension &dimension, long ts) const;\n\n    //! \\copydoc DC::getDimensionNames()\n    //!\n    virtual std::vector<string> getDimensionNames() const;\n\n    //! \\copydoc DC::getMeshNames()\n    //!\n    std::vector<string> getMeshNames() const;\n\n    //! \\copydoc DC::getMesh()\n    //!\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc DC::GetCoordVarInfo()\n    //!\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const;\n\n    //! \\copydoc DC::GetDataVarInfo()\n    //!\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const;\n\n    //! \\copydoc DC::GetAuxVarInfo()\n    //!\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const;\n\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const;\n\n\n\n    //! \\copydoc DC::GetDataVarNames()\n    //!\n    virtual std::vector<string> getDataVarNames() const;\n\n    virtual std::vector<string> getAuxVarNames() const;\n\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual std::vector<string> getCoordVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual size_t getNumRefLevels(string varname) const { return (1); }\n\n    //! \\copydoc DC::GetMapProjection()\n    //!\n    virtual string getMapProjection() const\n    {\n        return \"\";\n    }\n\n    //! \\copydoc DC::GetAtt()\n    //!\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const;\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const;\n    virtual bool getAtt(string varname, string attname, string &values) const;\n\n    //! \\copydoc DC::GetAttNames()\n    //!\n    virtual std::vector<string> getAttNames(string varname) const;\n\n    //! \\copydoc DC::GetAttType()\n    //!\n    virtual XType getAttType(string varname, string attname) const;\n\n    //! \\copydoc DC::GetDimLensAtLevel()\n    //!\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const;\n\n\n    //! \\copydoc DC::OpenVariableRead()\n    //!\n    virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCRAM::openVariableRead(ts, varname)); }\n\n    virtual int openVariableRead(size_t ts, string varname);\n\n\n    //! \\copydoc DC::CloseVariable()\n    //!\n    virtual int closeVariable(int fd);\n\n    //! \\copydoc DC::ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { VAssert(!\"DCRAM: double data not supported\"); return -1; }\n\n    //! \\copydoc DC::ReadRegionBlock()\n    //!\n    virtual int readRegionBlock(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); };\n    virtual int readRegionBlock(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegionBlock(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { VAssert(!\"DCRAM: double data not supported\"); return -1; }\n\n    //! \\copydoc DC::VariableExists()\n    //!\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\nprivate:\n    std::map<string, DC::Dimension> _dimsMap;\n    std::map<string, DC::CoordVar>  _coordVarsMap;\n    std::map<string, DC::AuxVar>    _auxVarsMap;\n    std::map<string, DC::Mesh>      _meshMap;\n    std::map<string, DC::DataVar>   _dataVarsMap;\n\n    int                   _fakeVarsFileCounterStart = 10000;\n    int                   _fakeVarsFileCounter = _fakeVarsFileCounterStart;\n    std::map<int, string> _fdMap;\n\n\n    template<class T> int _readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region);\n\n    template<class T> bool _getAttTemplate(string varname, string attname, T &values) const;\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/DCUGRID.h",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <vapor/MyBase.h>\n#include <vapor/NetCDFCFCollection.h>\n#include <vapor/DerivedVar.h>\n#include <vapor/DerivedVarMgr.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/utils.h>\n#include <vapor/DCCF.h>\n\n#pragma once\n\nnamespace VAPoR {\n\n//!\n//! \\class DCUGRID\n//! \\ingroup Public_VDCUGRID\n//!\n//! \\brief Class for reading a UGRID data set\n//! stored as a series\n//! of NetCDF files: https://ugrid-conventions.github.io/ugrid-conventions/\n//!\n//! \\author John Clyne\n//! \\date    July, 2021\n//!\nclass VDF_API DCUGRID : public VAPoR::DCCF {\npublic:\n    int OpenVariableRead(size_t ts, string varname, int level = 0, int lod = 0) override;\n\n    int Read(int fd, int *data) override;\n    int ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *data) override;\n\n    int CloseVariable(int fd) override;\n\nprotected:\n    int initialize(const vector<string> &paths, const std::vector<string> &options) override;\n\n    int initAuxilliaryVars(NetCDFCFCollection *ncdfc, std::map<string, DC::AuxVar> &auxVarsMap) override;\n\n    int initDataVars(NetCDFCFCollection *ncdfc, std::map<string, DC::DataVar> &dataVarsMap) override;\n\n    int initMesh(NetCDFCFCollection *ncdfc, std::map<string, DC::Mesh> &meshMap) override;\n\n    string getMapProjection() const override { return (\"+proj=eqc +ellps=WGS84 +lon_0=0.0 +lat_0=0.0\"); }\n\nprivate:\n    // Struct to contain the most general form of UGRID mesh\n    //\n    struct uGridMeshType {\n        int            topology;\n        vector<string> nodeCoordinates;\n        string         faceNodeConnectivity;\n        string         faceDimension;\n        string         edgeNodeConnectivity;\n        string         edgeDimension;\n        string         faceEdgeConnectivity;\n        string         faceFaceConnectivity;\n        string         edgeFaceConnectivity;\n        string         boundaryNodeConnectivity;\n        vector<string> faceCoordinates;\n        vector<string> edgeCoordinates;\n    };\n    std::map<string, uGridMeshType> _uGridMeshMap;\n\n    std::map<string, vector<int>> _faceNodeConnectivityMap;\n    std::map<int, string>         _openConnectivityMaps;\n\n    string _getLayeredVerticalCoordVar(NetCDFCFCollection *ncdfc, string varName) const;\n\n    void _getUGridMeshFromFile(NetCDFCFCollection *ncdfc, string meshVarName, uGridMeshType &m);\n\n    string _getMeshNodeDimName(NetCDFCFCollection *ncdf, const uGridMeshType &m) const;\n\n    string _getMeshFaceDimName(NetCDFCFCollection *ncdf, const uGridMeshType &m) const;\n\n    size_t _getMeshMaxNodesPerFace(NetCDFCFCollection *ncdf, const uGridMeshType &m) const;\n\n    bool _getVarTimeCoords(NetCDFCFCollection *ncdfc, string varName, string &coordName) const;\n\n    int _initFaceNodeConnectivityMap(NetCDFCFCollection *ncdfc);\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/DCUtils.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2018\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tDCUtils.h\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tFebruary 2018\n//\n//\tDescription:\tDefines the DC free functions.\n//\n//  These  functions operate on instances of the DC class.\n//\n#ifndef DCUTILS_H\n#define DCUTILS_H\n\n#include <vector>\n#include <string>\n#include <map>\n#include <vapor/DC.h>\n\nnamespace VAPoR {\n\nclass NetCDFCollection;\n\nnamespace DCUtils {\n\nint CopyAtt(const NetCDFCollection &ncdfc, string varname, string attname, DC::BaseVar &var);\n\nint CopyAtt(const NetCDFCollection &ncdfc, string varname, DC::BaseVar &var);\n\n};    // namespace DCUtils\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/DCWRF.h",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <vapor/MyBase.h>\n#include <vapor/NetCDFCollection.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/DerivedVarMgr.h>\n#include <vapor/DerivedVar.h>\n#include <vapor/DC.h>\n\n#ifndef _DCWRF_H_\n    #define _DCWRF_H_\n\nnamespace VAPoR {\n\nclass DerivedCoordVar_CF1D;\nclass DerivedCoordVar_WRFTime;\nclass DerivedCoordVar_Staggered;\n\n//!\n//! \\class DCWRF\n//! \\ingroup Public_VDCWRF\n//!\n//! \\brief Class for reading a WRF data set stored as a series\n//! of NetCDF files.\n//!\n//! \\author John Clyne\n//! \\date    January, 2015\n//!\nclass VDF_API DCWRF : public VAPoR::DC {\npublic:\n    //! Class constuctor\n    //!\n    //!\n    DCWRF();\n    virtual ~DCWRF();\n\nprotected:\n    //! Initialize the DCWRF class\n    //!\n    //! Prepare a WRF data set for reading. This method prepares\n    //! the DCWRF class for reading the files indicated by\n    //! \\p paths.\n    //! The method should be called immediately after the constructor,\n    //! before any other class methods. This method\n    //! exists only because C++ constructors can not return error codes.\n    //!\n    //! \\param[in] path A list of WRF NetCDF files comprising the output of\n    //! a single WRF model run.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa EndDefine();\n    //\n    virtual int initialize(const vector<string> &paths, const std::vector<string> &options);\n\n    //! \\copydoc DC::GetDimension()\n    //!\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const;\n\n    //! \\copydoc DC::getDimensionNames()\n    //!\n    virtual std::vector<string> getDimensionNames() const;\n\n    //! \\copydoc DC::getMeshNames()\n    //!\n    std::vector<string> getMeshNames() const;\n\n    //! \\copydoc DC::GetMesh()\n    //!\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc DC::GetCoordVarInfo()\n    //!\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const;\n\n    //! \\copydoc DC::GetDataVarInfo()\n    //!\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavar) const;\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &var) const { return (false); }\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &var) const;\n\n    //! \\copydoc DC::GetDataVarNames()\n    //!\n    virtual std::vector<string> getDataVarNames() const;\n\n    //! \\copydoc DC::GetCoordVarNames()\n    //!\n    virtual std::vector<string> getCoordVarNames() const;\n\n    virtual std::vector<string> getAuxVarNames() const { return (vector<string>()); }\n\n    //! \\copydoc DC::GetNumRefLevels()\n    //!\n    virtual size_t getNumRefLevels(string varname) const { return (1); }\n\n    //! \\copydoc DC::GetMapProjection()\n    //!\n    virtual string getMapProjection() const;\n\n    //! \\copydoc DC::GetAtt()\n    //!\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const;\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const;\n    virtual bool getAtt(string varname, string attname, string &values) const;\n\n    //! \\copydoc DC::GetAttNames()\n    //!\n    virtual std::vector<string> getAttNames(string varname) const;\n\n    //! \\copydoc DC::GetAttType()\n    //!\n    virtual XType getAttType(string varname, string attname) const;\n\n    //! \\copydoc DC::GetDimLensAtLevel()\n    //!\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    //! \\copydoc DC::OpenVariableRead()\n    //!\n    virtual int openVariableRead(size_t ts, string varname, int, int) { return (DCWRF::openVariableRead(ts, varname)); }\n\n    virtual int openVariableRead(size_t ts, string varname);\n\n    //! \\copydoc DC::CloseVariable()\n    //!\n    virtual int closeVariable(int fd);\n\n    //! \\copydoc DC::ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); }\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\n    //! \\copydoc DC::VariableExists()\n    //!\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\nprivate:\n    NetCDFCollection *_ncdfc;\n    VAPoR::UDUnits    _udunits;\n\n    //\n    // Various attributes from a WRF data file needed for computing map\n    // projections\n    //\n    float _dx;\n    float _dy;\n    float _cen_lat;\n    float _cen_lon;\n    float _true_lat1;\n    float _true_lat2;\n    float _pole_lat;\n    float _pole_lon;\n    float _grav;\n    float _radius;\n    float _p2si;\n    float _mapProj;\n\n    string        _proj4String;\n    DerivedVarMgr _dvm;\n\n    class WRFFileObject : public DC::FileTable::FileObject {\n    public:\n        WRFFileObject(size_t ts, string varname, int level, int lod, int fd, bool derivedFlag) : FileObject(ts, varname, level, lod, fd), _derivedFlag(derivedFlag) {}\n\n        bool GetDerivedFlag() const { return (_derivedFlag); }\n\n    private:\n        bool _derivedFlag;\n    };\n\n    std::vector<DerivedVar *> _derivedVars;\n\n    DerivedCoordVar_WRFTime *_derivedTime;\n\n    std::map<string, DC::Dimension> _dimsMap;\n    std::map<string, DC::CoordVar>  _coordVarsMap;\n    std::map<string, DC::Mesh>      _meshMap;\n    std::map<string, DC::DataVar>   _dataVarsMap;\n    std::vector<size_t>             _timeLookup;\n\n    vector<size_t> _GetSpatialDims(NetCDFCollection *ncdfc, string varname) const;\n\n    vector<string> _GetSpatialDimNames(NetCDFCollection *ncdfc, string varname) const;\n\n    int _InitAtts(NetCDFCollection *ncdfc);\n\n    int _GetProj4String(NetCDFCollection *ncdfc, float radius, int map_proj, string &projstring);\n\n    bool _isConstantValuedVariable(NetCDFCollection *ncdfc, string varname) const;\n\n    bool _isIdealized(NetCDFCollection *ncdfc) const;\n\n    bool _isWRFSFIRE(NetCDFCollection *ncdfc) const;\n\n    int _InitProjection(NetCDFCollection *ncdfc, float radius);\n\n    DerivedCoordVar_CF2D *_makeDerivedHorizontalIdealized(NetCDFCollection *ncdfc, string name, string &timeDimName, vector<string> &spaceDimNames);\n\n    DerivedCoordVar_Staggered *_makeDerivedHorizontalStaggered(NetCDFCollection *ncdfc, string name, string &timeDimName, vector<string> &spaceDimNames);\n\n    int _InitHorizontalCoordinatesHelper(NetCDFCollection *ncdfc, string name, int axis);\n\n    int _InitHorizontalCoordinates(NetCDFCollection *ncdfc);\n\n    DerivedCoordVar_CF1D *_InitVerticalCoordinatesHelper(string varName, string dimName);\n\n    int _InitVerticalCoordinates(NetCDFCollection *ncdfc);\n\n    int _InitTime(NetCDFCollection *ncdfc);\n\n    int _InitDimensions(NetCDFCollection *ncdfc);\n\n    int _GetCoordVars(NetCDFCollection *ncdfc, string varname, vector<string> &cvarnames);\n\n    bool _GetVarCoordinates(NetCDFCollection *ncdfc, string varname, std::vector<string> &dimnames, std::vector<string> &coordvars, string &time_dim_name, string &time_coordvar);\n\n    int _InitVars(NetCDFCollection *ncdfc);\n\n    template<class T> int _readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region);\n\n    template<class T> bool _getAttTemplate(string varname, string attname, T &values) const;\n\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/DataMgr.h",
    "content": "#include <vector>\n#include <iostream>\n#include <list>\n#include \"vapor/VAssert.h\"\n#include <vapor/BlkMemMgr.h>\n#include <vapor/DC.h>\n#include <vapor/MyBase.h>\n#include <vapor/RegularGrid.h>\n#include <vapor/StretchedGrid.h>\n#include <vapor/LayeredGrid.h>\n#include <vapor/CurvilinearGrid.h>\n#include <vapor/UnstructuredGrid2D.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/GridHelper.h>\n#include <vapor/DerivedVarMgr.h>\n\n#ifndef DataMgvV3_0_h\n    #define DataMgvV3_0_h\n\nusing namespace std;\n\nnamespace VAPoR {\nclass PipeLine;\nclass DerivedVar;\nclass DerivedDataVar;\nclass DerivedCoordVar;\n\n//! \\class DataMgr\n//! \\brief A cache based data reader\n//! \\author John Clyne\n//!\n//! The DataMgr class is an abstract class that defines public methods for\n//! accessing (reading) 1D, 2D and 3D field variables. The class implements a\n//! memory cache to speed data access -- once a variable is read it is\n//! stored in cache for subsequent access. The DataMgr class is abstract:\n//! it declares a number of public and protected pure virtual methods\n//! that must be\n//! implemented by specializations of this class to allow access to particular\n//! file formats.\n//!\n//! This class inherits from Wasp::MyBase. Unless otherwise documented\n//! any method that returns an integer value is returning status. A negative\n//! value indicates failure. Error messages are logged via\n//! Wasp::MyBase::SetErrMsg().\n//!\n//! Methods that return a boolean do\n//! not, unless otherwise documented, log an error message upon\n//! failure (return of false).\n//!\n//! \\param level\n//! \\parblock\n//! Grid refinement level for multiresolution variables.\n//! Compressed variables in the VDC have a multi-resolution\n//! representation: the sampling grid for multi-resolution variables\n//! is hierarchical, and the dimension lengths of adjacent levels in the\n//! hierarchy differ by a factor of two. The \\p level parameter is\n//! used to select a particular depth of the hierarchy.\n//!\n//! To provide maximum flexibility as well as compatibility with previous\n//! versions of the VDC the interpretation of \\p level is somewhat\n//! complex. Both positive and negative values may be used to specify\n//! the refinement level and have different interpretations.\n//!\n//! For positive\n//! values of \\p level, a value of \\b 0 indicates the coarsest\n//! member of the\n//! grid hierarchy. A value of \\b 1 indicates the next grid refinement\n//! after the coarsest, and so on. Using postive values the finest level\n//! in the hierarchy is given by GetNumRefLevels() - 1. Values of \\p level\n//! that are greater than GetNumRefLevels() - 1 are treated as if they\n//! were equal to GetNumRefLevels() - 1.\n//!\n//! For negative values of \\p level a value of -1 indicates the\n//! variable's native grid resolution (the finest resolution available).\n//! A value of -2 indicates the next coarsest member in the hierarchy after\n//! the finest, and so\n//! on. Using negative values the coarsest available level in the hierarchy is\n//! given by negating the value returned by GetNumRefLevels(). Values of\n//! \\p level that are less than the negation of GetNumRefLevels() are\n//! treated as if they were equal to the negation of the GetNumRefLevels()\n//! return value.\n//! \\endparblock\n//!\n//! \\param lod\n//! \\parblock\n//! The level-of-detail parameter, \\p lod, selects\n//! the approximation level for a compressed variable.\n//! The \\p lod parameter is similar to the \\p level parameter in that it\n//! provides control over accuracy of a compressed variable. However, instead\n//! of selecting the grid resolution the \\p lod parameter controls\n//! the compression factor by indexing into the \\p cratios vector (see below).\n//! As with the \\p level parameter, both positive and negative values may be\n//! used to index into \\p cratios and\n//! different interpretations.\n//!\n//! For positive\n//! values of \\p lod, a value of \\b 0 indicates the\n//! the first element of \\p cratios, a value of \\b 1 indicates\n//! the second element, and so on up to the size of the\n//! \\p cratios vector (See DC::GetCRatios()).\n//!\n//! For negative values of \\p lod a value of \\b -1 indexes the\n//! last element of \\p cratios, a value of \\b -2 indexes the\n//! second to last element, and so on.\n//! Using negative values the first element of \\p cratios - the greatest\n//! compression rate - is indexed by negating the size of the\n//! \\p cratios vector.\n//! \\endparblock\n//\nclass VDF_API DataMgr : public Wasp::MyBase {\npublic:\n    //! Constructor for the DataMgr class.\n    //!\n    //! The DataMgr will attempt to cache previously read data and coordinate\n    //! variables in memory. The \\p mem_size specifies the requested cache\n    //! size in MEGABYTES!!!\n    //!\n    //! \\param[in] format A string indicating the format of data collection.\n    //!\n    //! \\param[in] mem_size Size of memory cache to be created, specified\n    //! in MEGABYTES!! If 0, not restriction is placed on the cache size; the DataMgr will\n    //! attempt to allocate as much memory is needed.\n    //!\n    //! \\param[in] numthreads Number of parallel execution threads\n    //! to be run during encoding and decoding of compressed data. A value\n    //! of 0, the default, indicates that the thread count should be\n    //! determined by the environment in a platform-specific manner, for\n    //! example using sysconf(_SC_NPROCESSORS_ONLN) under *nix OSes.\n    //!\n    //\n    DataMgr(string format, size_t mem_size, int nthreads = 0);\n\n    virtual ~DataMgr();\n\n    //! Initialize the class\n    //!\n    //! This method must be called to initialize the DataMgr class with\n    //! a list of input data files.\n    //!\n    //! \\param[in] files A list of file paths\n    //!\n    //! \\retval status A negative int is returned on failure and an error\n    //! message will be logged with MyBase::SetErrMsg()\n    //!\n    //\n    virtual int Initialize(const vector<string> &paths, const std::vector<string> &options);\n\n    //! \\copydoc DC::GetDimensionNames()\n    //\n    std::vector<string> GetDimensionNames() const\n    {\n        VAssert(_dc);\n        return (_dc->GetDimensionNames());\n    }\n\n    //! \\copydoc DC::GetAtt(string, string, vector<double>&)\n    //\n    bool GetAtt (string varname, string attname, vector< double > &values) const\n    {\n        VAssert(_dc);\n        return (_dc->GetAtt(varname, attname, values));\n    }\n\n    //! \\copydoc DC::GetAtt(string, string, vector<long>&)\n    //\n    bool GetAtt (string varname, string attname, vector<long> &values) const\n    {\n        VAssert(_dc);\n        return (_dc->GetAtt(varname, attname, values));\n    }\n\n    //! \\copydoc DC::GetAtt(string, string, string&)\n    //\n    bool GetAtt (string varname, string attname, string &values) const\n    {\n        VAssert(_dc);\n        return (_dc->GetAtt(varname, attname, values));\n    }\n\n    //! \\copydoc DC::GetAttNames(string)\n    //\n    std::vector<string> GetAttNames(string varname) const\n    {\n        VAssert(_dc);\n        return (_dc->GetAttNames(varname));\n    }\n\n    //! \\copydoc DC::GetAttType(string, string)\n    //\n    DC::XType GetAttType(string varname, string attname) const\n    {\n        VAssert(_dc);\n        return (_dc->GetAttType(varname, attname));\n    }\n\n    //! \\copydoc DC::GetDimension()\n    //\n    bool GetDimension(string dimname, DC::Dimension &dimension, long ts) const\n    {\n        VAssert(_dc);\n        return (_dc->GetDimension(dimname, dimension, ts));\n    }\n    \n    //! Returns the length of a dimension at a given timestep\n    //!\n    //! \\retval length A negative int is returned on failure\n    //!\n    long GetDimensionLength(string name, long ts) const\n    {\n        VAssert(_dc);\n        DC::Dimension dimension;\n        bool ok = GetDimension(name, dimension, ts);\n        if (ok)\n            return dimension.GetLength();\n        return -1;\n    }\n\n    //! \\copydoc DC::GetMeshNames()\n    //\n    std::vector<string> GetMeshNames() const\n    {\n        VAssert(_dc);\n        return (_dc->GetMeshNames());\n    }\n\n    //! \\copydoc DC::GetMesh()\n    //\n    bool GetMesh(string meshname, DC::Mesh &mesh) const;\n\n    DC::Mesh GetMesh(string meshname) const {\n        DC::Mesh mesh;\n        GetMesh(meshname, mesh);\n        return mesh;\n    }\n\n    //! Return a list of names for all of the defined data variables.\n    //!\n    //! This method returns a list of all data variables defined\n    //! in the data set.\n    //!\n    //! \\retval list A vector containing a list of all the data variable names\n    //!\n    //! \\sa GetCoordVarNames()\n    //!\n    //! \\test New in 3.0\n    virtual std::vector<string> GetDataVarNames() const;\n\n    //! Return a list of data variables with a given spatial dimension rank\n    //!\n    //! This method returns a list of all data variables defined\n    //! in the data set with the specified dimension rank (number of dimensions).\n    //! Data variables may have 0 to 3 spatial dimensions\n    //!\n    //! \\param[in] ndim Variable rank (number of dimensions)\n    //!\n    //! \\retval list A vector containing a list of all the data variable names\n    //! with the specified number of dimensions (rank).\n    //!\n    //! \\test New in 3.0\n    enum class VarType { Any, Scalar, Particle };\n    virtual std::vector<string> GetDataVarNames(int ndim, VarType type = VarType::Any) const;\n\n    //! Return a list of names for all of the defined coordinate variables.\n    //!\n    //! This method returns a list of all coordinate variables defined\n    //! in the data set.\n    //!\n    //! \\retval list A vector containing a list of all the coordinate\n    //! variable names\n    //!\n    //! \\sa GetDataVarNames()\n    //!\n    virtual std::vector<string> GetCoordVarNames() const;\n\n    //! Get time coordinates\n    //!\n    //! Get a sorted list of all time coordinates defined for the\n    //! data set. Multiple time coordinate variables may be defined. This method\n    //! collects the time coordinates from all time coordinate variables\n    //! and sorts them into a single, global time coordinate variable.\n    //!\n    //! \\note Need to deal with different units (e.g. seconds and days).\n    //! \\note Should methods that take a time step argument \\p ts expect\n    //! \"local\" or \"global\" time steps\n    //!\n    void GetTimeCoordinates(std::vector<double> &timecoords) const { timecoords = _timeCoordinates; };\n\n    const std::vector<double> &GetTimeCoordinates() const { return (_timeCoordinates); };\n\n    //! Get time coordinate var name\n    //!\n    //! Return the name of the time coordinate variable. If no time coordinate\n    //! variable is defined the empty string is returned.\n    //\n    string GetTimeCoordVarName() const;\n\n    bool HasTimeVaryingCoordinates() const;\n    bool HasMovingDomain() const;\n\n    //! Return an ordered list of a data variable's coordinate names\n    //!\n    //! Returns a list of a coordinate variable names for the variable\n    //! \\p varname, ordered from fastest\n    //! to slowest. If \\p spatial is true and the variable is time varying\n    //! the time coordinate variable name will be included. The time\n    //! coordinate variable is always\n    //! the slowest varying coordinate axis\n    //!\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] spatial If true only return spatial dimensions\n    //!\n    //! \\param[out] coordvars Ordered list of coordinate variable names.\n    //!\n    //! \\retval Returns true upon success, false if the variable is\n    //! not defined.\n    //!\n    //\n    virtual bool GetVarCoordVars(string varname, bool spatial, std::vector<string> &coord_vars) const;\n    vector<string> GetVarCoordVars(string varname, bool spatial) const;\n\n    //! Return a data variable's definition\n    //!\n    //! Return a reference to a DC::DataVar object describing\n    //! the data variable named by \\p varname\n    //!\n    //! \\param[in] varname A string specifying the name of the variable.\n    //! \\param[out] datavar A DataVar object containing the definition\n    //! of the named Data variable.\n    //!\n    //! \\retval bool If true the method was successful. If false the\n    //! named variable is invalid (unknown)\n    //!\n    //! \\sa GetCoordVarInfo()\n    //!\n    bool GetDataVarInfo(string varname, VAPoR::DC::DataVar &datavar) const;\n\n    //! Return metadata about a data or coordinate variable\n    //!\n    //! If the variable \\p varname is defined as either a\n    //! data or coordinate variable its metadata will\n    //! be returned in \\p var.\n    //!\n    //! \\retval bool If true the method was successful. If false the\n    //! named variable is invalid (unknown)\n    //!\n    //! \\sa GetDataVarInfo(), GetCoordVarInfo()\n    //\n    bool GetBaseVarInfo(string varname, VAPoR::DC::BaseVar &var) const;\n\n    //! Return a coordinate variable's definition\n    //!\n    //! Return a reference to a DC::CoordVar object describing\n    //! the coordinate variable named by \\p varname\n    //!\n    //! \\param[in] varname A string specifying the name of the coordinate\n    //! variable.\n    //! \\param[out] coordvar A CoordVar object containing the definition\n    //! of the named variable.\n    //!\n    //! \\retval bool If true the method was successful. If false the\n    //! named variable is invalid (unknown)\n    //!\n    //! \\sa GetDataVarInfo()\n    //!\n    bool GetCoordVarInfo(string varname, VAPoR::DC::CoordVar &cvar) const;\n\n    //! Return a boolean indicating whether a variable is time varying\n    //!\n    //! This method returns \\b true if the variable named by \\p varname\n    //! is defined and it has a time axis dimension. If either of these conditions\n    //! is not true the method returns false.\n    //!\n    //! \\param[in] varname A string specifying the name of the variable.\n    //! \\retval bool Returns true if variable \\p varname exists and is\n    //! time varying.\n    //!\n    bool IsTimeVarying(string varname) const;\n\n    //! Return a boolean indicating whether a variable is compressed\n    //!\n    //! This method returns \\b true if the variable named by \\p varname is defined\n    //! and it has a compressed representation. If either of these conditions\n    //! is not true the method returns false.\n    //!\n    //! \\param[in] varname A string specifying the name of the variable.\n    //! \\retval bool Returns true if variable \\p varname exists and is\n    //! compressed\n    //!\n    //! \\sa DefineCoordVar(), DefineDataVar(), DC::BaseVar::GetCompressed()\n    //\n    bool IsCompressed(string varname) const;\n\n    //! Return the time dimension length for a variable\n    //!\n    //! Returns the number of time steps (length of the time dimension)\n    //! for which a variable is defined. If \\p varname does not have a\n    //! time coordinate 1 is returned. If \\p varname is not defined\n    //! as a variable a negative int is returned.\n    //!\n    //! \\param[in] varname A string specifying the name of the variable.\n    //! \\retval count The length of the time dimension, or a negative\n    //! int if \\p varname is undefined.\n    //!\n    //! \\sa IsTimeVarying()\n    //\n    int GetNumTimeSteps(string varname) const;\n\n    //! Return the maximum time dimension length for this data set\n    //!\n    //! Returns the number of time steps (length of the time dimension)\n    //! for any variable is defined.\n    //\n    int GetNumTimeSteps() const;\n\n    //! \\copydoc DC::GetNumRefLevels()\n    //\n    size_t GetNumRefLevels(string varname) const;\n\n    //! \\copydoc DC::GetCRatios()\n    //\n    std::vector<size_t> GetCRatios(string varname) const;\n\n    //! Read and return variable data\n    //!\n    //! Reads all data for the data or coordinate variable named by \\p varname\n    //! for the time step, refinement level, and leve-of-detail indicated\n    //! by \\p ts, \\p level, and \\p lod, respectively.\n    //!\n    //! \\param[in] ts\n    //! An integer offset into the time coordinate variable\n    //! returned by GetTimeCoordinates() indicting the time step of the\n    //! variable to access.\n    //!\n    //! \\param[in] varname The name of the data or coordinate variable to access\n    //!\n    //! \\param[in] level Grid refinement level. See DataMgr\n    //!\n    //! \\param[in] lod The level-of-detail parameter, \\p lod, selects\n    //! the approximation level. See DataMgr.\n    //\n    VAPoR::Grid *GetVariable(size_t ts, string varname, int level, int lod, bool lock = false);\n\n    //! Read and return a variable hyperslab\n    //!\n    //! This method is identical to the GetVariable() method, however,\n    //! a subregion is specified in the user coordinate system.\n    //! \\p min and \\p max specify the minimum and maximum extents of an\n    //! axis-aligned bounding box containing the region of interest. The\n    //! VAPoR::Grid object returned contains the intersection\n    //! between the\n    //! specified\n    //! hyperslab and the variable's spatial domain (which is not necessarily\n    //! rectangular or axis-aligned).\n    //! If the requested hyperslab lies entirely outside of the domain of the\n    //! requested variable NULL is returned\n    //!\n    //! \\param[in] min A one, two, or three element array specifying the\n    //! minimum extents, in user coordinates, of an axis-aligned box defining\n    //! the region-of-interest. The spatial dimensionality of the variable\n    //! determines the number of elements in \\p min.\n    //!\n    //! \\param[in] max A one, two, or three element array specifying the\n    //! maximum extents, in user coordinates, of an axis-aligned box defining\n    //! the region-of-interest. The spatial dimensionality of the variable\n    //! determines the number of elements in \\p max.\n    //!\n    //! \\note The Grid structure returned is allocated from the heap.\n    //! it is the caller's responsiblity to delete the returned object\n    //! when it is no longer in use.\n    //!\n    VAPoR::Grid *GetVariable(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, bool lock = false);\n\n    VAPoR::Grid *GetVariable(size_t ts, string varname, int level, int lod, DimsType min, DimsType max, bool lock = false);\n\n    //! Compute the coordinate extents of a variable\n    //!\n    //! This method finds the spatial domain extents of a variable\n    //!\n    //! This method returns the min and max extents\n    //! specified in user\n    //! coordinates, of the smallest axis-aligned bounding box that is\n    //! guaranteed to contain\n    //! the variable(s) indicated by \\p varname, and the given refinement level,\n    //! \\p level\n    //!\n    int GetVariableExtents(size_t ts, string varname, int level, int lod, CoordType &min, CoordType &max);\n\n    //! Compute the min and max value of a variable\n    //!\n    //! This method finds the minimum and maximum value of a variable\n    //!\n    //! \\param[out] range A two element vector containing the minimum and maximum\n    //! value, respectively, for the variable \\p varname at the specified\n    //! time step, lod, etc.\n    //\n    int GetDataRange(size_t ts, string varname, int level, int lod, std::vector<double> &range);\n\n    //! Compute min and max value of a variable within a specified ROI\n    //!\n    //! This method finds the minimum and maximum value of a variable within\n    //! the region of interest (ROI) specified by \\p min and \\p max. Note, the\n    //! results returned by this method are equivalent to calling the\n    //! Grid::GetRange() method on a grid returned by DataMgr::GetVariable\n    //! using the same arguments provided here.\n    //\n    int GetDataRange(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, std::vector<double> &range);\n\n    //! \\copydoc DC::GetDimLensAtLevel()\n    //!\n    virtual int GetDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, long ts) const\n    {\n        std::vector<size_t> dummy;\n        return (GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts));\n    }\n\n    //! Return a variable's array dimension lengths\n    //!\n    //! This method is equivalent to calling GetDimLensAtLevel() with \\p level\n    //! equal to -1\n    //!\n    virtual int GetDimLens(string varname, std::vector<size_t> &dims, long ts) { return (GetDimLensAtLevel(varname, -1, dims, ts)); }\n\n    std::vector<size_t> GetDimLens(string varname) {\n        std::vector<size_t> dims;\n        GetDimLens(varname, dims, 0);\n        return dims;\n    }\n\n    //! Unlock a floating-point region of memory\n    //!\n    //! Decrement the lock counter associatd with a\n    //! region of memory, and if zero,\n    //! unlock region of memory previously locked with GetVariable().\n    //! When the lock counter reaches zero the region is simply\n    //! marked available for\n    //! internal garbage collection during subsequent GetVariable() calls\n    //!\n    //! \\param[in] rg A pointer to a Grid previosly\n    //! returned by GetVariable()\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //!\n    //! \\sa GetVariable()\n    //\n    void UnlockGrid(const VAPoR::Grid *rg);\n\n    //! \\copydoc DC::GetNumDimensions(\n    //!   string varname\n    //! ) const;\n    //\n    size_t GetNumDimensions(string varname) const;\n\n    //! \\copydoc DC:GetVarTopologyDim()\n    //!\n    size_t GetVarTopologyDim(string varname) const;\n\n    //! \\copydoc DC:GetVarGeometryDim()\n    //!\n    size_t GetVarGeometryDim(string varname) const;\n\n    //! Clear the memory cache\n    //!\n    //! This method clears the internal memory cache of all entries\n    //\n    void Clear();\n\n    //! Returns true if indicated data volume is available\n    //!\n    //! Returns true if the variable identified by the timestep, variable\n    //! name, refinement level, and level-of-detail is present in\n    //! the data set. Returns false if\n    //! the variable is not available.\n    //!\n    //! \\param[in] ts A valid time step between 0 and GetNumTimesteps()-1\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] level Refinement level requested.\n    //! \\param[in] lod Compression level of detail requested.\n    //! refinement level contained in the DC.\n    //\n    virtual bool VariableExists(size_t ts, string varname, int level = 0, int lod = 0) const;\n\n    //! \\copydoc DC::GetMapProjection() const;\n    //\n    virtual string GetMapProjection() const { return (_proj4String); }\n\n    //! \\copydoc DC::GetMapProjectionDefault() const;\n    //\n    virtual string GetMapProjectionDefault() const { return (_proj4StringDefault); }\n\n    #ifdef VAPOR3_0_0_ALPHA\n\n    //!\n    //! Add a pipeline stage to produce derived variables\n    //!\n    //! Add a new pipline stage for derived variable calculation. If a\n    //! pipeline already exists with the same\n    //! name it is replaced. The output variable names are added to\n    //! the list of variables available for this data\n    //! set (see GetVariables3D, etc.).\n    //!\n    //! An error occurs if:\n    //!\n    //! \\li The output variable names match any of the native variable\n    //! names - variable names returned via _GetVariables3D(), etc.\n    //! \\li The output variable names match the output variable names\n    //! of pipeline stage previously added with NewPipeline()\n    //! \\li A circular dependency is introduced by adding \\p pipeline\n    //!\n    //! \\retval status A negative int is returned on failure.\n    //!\n    int NewPipeline(PipeLine *pipeline);\n\n    //!\n    //! Remove the named pipline if it exists. Otherwise this method is a\n    //! no-op\n    //!\n    //! \\param[in] name The name of the pipeline as returned by\n    //! PipeLine::GetName()\n    //!\n    void RemovePipeline(string name);\n    #endif\n\n    //! Return true if the named variable is the output of a pipeline\n    //!\n    //! This method returns true if \\p varname matches a variable name\n    //! in the output list (PipeLine::GetOutputs()) of any pipeline added\n    //! with NewPipeline()\n    //!\n    //! \\sa NewPipeline()\n    //\n    bool IsVariableDerived(string varname) const;\n\n    //! Return true if the named variable is availble from the derived\n    //! classes data access methods.\n    //!\n    //! A return value of true does not imply that the variable can\n    //! be read (\\see VariableExists()), only that it is part of the\n    //! data set known to the derived class\n    //!\n    //! \\sa NewPipeline()\n    //\n    bool IsVariableNative(string varname) const;\n\n    int AddDerivedVar(DerivedDataVar *derivedVar);\n\n    void RemoveDerivedVar(string varname);\n\n    //! Purge the cache of a variable\n    //!\n    //! \\param[in] varname is the variable name\n    //!\n    void PurgeVariable(string varname);\n\n    class BlkExts {\n    public:\n        BlkExts(){};\n        BlkExts(const DimsType &bmin, const DimsType &bmax);\n\n        void Insert(const DimsType &bcoord, const CoordType &min, const CoordType &max);\n\n        bool Intersect(const CoordType &min, const CoordType &max, DimsType &bmin, DimsType &bmax, int nCoords = 3) const;\n\n        friend std::ostream &operator<<(std::ostream &o, const BlkExts &b);\n\n    private:\n        DimsType               _bmin = {{0, 0, 0}};\n        DimsType               _bmax = {{0, 0, 0}};\n        std::vector<CoordType> _mins;\n        std::vector<CoordType> _maxs;\n    };\n\nprotected:\n    //\n    // Cache for various metadata attributes\n    //\n    template<typename C> class VarInfoCache {\n    public:\n        //\n        //\n        void Set(size_t ts, std::vector<string> varnames, int level, int lod, string key, const std::vector<C> &values);\n\n        void Set(size_t ts, string varname, int level, int lod, string key, const std::vector<C> &values)\n        {\n            std::vector<string> varnames;\n            varnames.push_back(varname);\n            Set(ts, varnames, level, lod, key, values);\n        }\n\n        bool Get(size_t ts, std::vector<string> varnames, int level, int lod, string key, std::vector<C> &values) const;\n\n        bool Get(size_t ts, string varname, int level, int lod, string key, std::vector<C> &values) const\n        {\n            std::vector<string> varnames;\n            varnames.push_back(varname);\n            return Get(ts, varnames, level, lod, key, values);\n        }\n\n        void Purge(size_t ts, std::vector<string> varnames, int level, int lod, string key);\n        void Purge(size_t ts, string varname, int level, int lod, string key)\n        {\n            std::vector<string> varnames;\n            varnames.push_back(varname);\n            Purge(ts, varnames, level, lod, key);\n        }\n        void Purge(std::vector<string> varnames);\n\n        void Clear() { _cache.clear(); }\n\n        static string _make_hash(string key, size_t ts, std::vector<string> cvars, int level, int lod);\n\n        void _decode_hash(const string &hash, string &key, size_t &ts, vector<string> &varnames, int &level, int &lod);\n\n    private:\n        std::map<string, std::vector<C>> _cache;\n    };\n\n    mutable std::map<std::pair<VarType, size_t>, std::vector<string>> _dataVarNamesCache;\n\n    string _format;\n    int    _nthreads;\n    size_t _mem_size;\n\n    DC *              _dc;\n    VAPoR::UDUnits    _udunits;\n    VAPoR::GridHelper _gridHelper;\n\n    DerivedVarMgr _dvm;\n    bool          _doTransformHorizontal;\n    bool          _doTransformVertical;\n    string        _openVarName;\n\n    std::vector<double> _timeCoordinates;\n    string              _proj4String;\n    string              _proj4StringDefault;\n    DimsType            _bs;\n\n    typedef struct {\n        size_t              ts;\n        string              varname;\n        int                 level;\n        int                 lod;\n        DimsType            bmin;\n        DimsType            bmax;\n        int                 lock_counter;\n        void *              blks;\n    } region_t;\n\n    // a list of all allocated regions\n    std::list<region_t> _regionsList;\n\n    VAPoR::BlkMemMgr *_blk_mem_mgr;\n\n    std::vector<PipeLine *> _PipeLines;\n\n    mutable VarInfoCache<size_t> _varInfoCacheSize_T;\n    mutable VarInfoCache<double> _varInfoCacheDouble;\n    mutable VarInfoCache<void *> _varInfoCacheVoidPtr;\n\n    std::map<string, BlkExts> _blkExtsCache;\n\n    std::map<const Grid *, vector<float *>> _lockedFloatBlks;\n    std::map<const Grid *, vector<int *>>   _lockedIntBlks;\n\n    // Get the immediate variable dependencies of a variable\n    //\n    std::vector<string> _get_var_dependencies_1(string varname) const;\n\n    // Recursively get all of the dependencies of a list of variables.\n    // Handles cycles in the dependency graph\n    //\n    std::vector<string> _get_var_dependencies_all(std::vector<string> varnames, std::vector<string> dependencies) const;\n\n    // Return true if native data has a transformable horizontal coordinate\n    //\n    bool _hasHorizontalXForm() const;\n\n    // Return true if native mesh has a transformable horizontal coordinate\n    //\n    bool _hasHorizontalXForm(string meshname) const;\n\n    bool _get_coord_vars(string varname, std::vector<string> &scvars, string &tcvar) const;\n\n    bool _get_coord_vars(string varname, vector<DC::CoordVar> &scvarsinfo, DC::CoordVar &tcvarinfo) const;\n\n    int _initTimeCoord();\n\n    int _get_default_projection(string &projection);\n\n    VAPoR::RegularGrid *_make_grid_regular(const DimsType &dims, const std::vector<float *> &blkvec, DimsType &bs, DimsType &bmin, const DimsType &bmax) const;\n\n    VAPoR::StretchedGrid *_make_grid_stretched(const DimsType &dims, const std::vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const;\n\n    VAPoR::LayeredGrid *_make_grid_layered(const DimsType &dims, const std::vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const;\n\n    VAPoR::CurvilinearGrid *_make_grid_curvilinear(size_t ts, int level, int lod, const vector<DC::CoordVar> &cvarsinfo, const DimsType &dims, const std::vector<float *> &blkvec, const DimsType &bs,\n                                                   const DimsType &bmin, const DimsType &bmax);\n\n    void _ugrid_setup(const DC::DataVar &var, DimsType &vertexDims, DimsType &faceDims, DimsType &edgeDims,\n                      UnstructuredGrid::Location &location,    // node,face, edge\n                      size_t &maxVertexPerFace, size_t &maxFacePerVertex, long &vertexOffset, long &faceOffset, long ts) const;\n\n    UnstructuredGrid2D *_make_grid_unstructured2d(size_t ts, int level, int lod, const DC::DataVar &dvarinfo, const vector<DC::CoordVar> &cvarsinfo, const DimsType, const vector<float *> &blkvec,\n                                                  const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector<int *> &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin,\n                                                  const DimsType &conn_bmax);\n\n    VAPoR::Grid *_make_grid(size_t ts, int level, int lod, const VAPoR::DC::DataVar &var, const DimsType &roi_dims, const DimsType &dims, const std::vector<float *> &blkvec,\n                            const std::vector<DimsType> &bsvec, const std::vector<DimsType> &bminvec, const std::vector<DimsType> &bmaxvec, const vector<int *> &conn_blkvec,\n                            const vector<DimsType> &conn_bsvec, const vector<DimsType> &conn_bminvec, const vector<DimsType> &conn_bmaxvec);\n\n    string _get_grid_type(string varname) const;\n\n    int _find_bounding_grid(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, DimsType &min_ui, DimsType &max_ui);\n\n    void _setupCoordVecsHelper(string data_varname, const DimsType &data_dimlens, const DimsType &data_bmin, const DimsType &data_bmax, string coord_varname, int order, DimsType &coord_dimlens,\n                               DimsType &coord_bmin, DimsType &coord_bmax, bool structured, long ts) const;\n\n    int _setupCoordVecs(size_t ts, string varname, int level, int lod, const DimsType &min, const DimsType &max, vector<string> &varnames, DimsType &roi_dims, vector<DimsType> &dimsvec,\n                        vector<DimsType> &bsvec, vector<DimsType> &bminvec, vector<DimsType> &bmaxvec, bool structured) const;\n\n    int _setupConnVecs(size_t ts, string varname, int level, int lod, vector<string> &varnames, vector<DimsType> &dimsvec, vector<DimsType> &bsvec, vector<DimsType> &bminvec,\n                       vector<DimsType> &bmaxvec) const;\n\n    VAPoR::Grid *_getVariable(size_t ts, string varname, int level, int lod, bool lock, bool dataless);\n\n    VAPoR::Grid *_getVariable(size_t ts, string varname, int level, int lod, DimsType min, DimsType max, bool lock, bool dataless);\n\n    int _parseOptions(vector<string> &options);\n\n    template<typename T> T *_get_region_from_cache(size_t ts, string varname, int level, int lod, const DimsType &bmin, const DimsType &bmax, bool lock);\n\n    template<typename T>\n    int _get_unblocked_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_min, const DimsType &grid_max, T *blks);\n\n    template<typename T>\n    int _get_blocked_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &file_bs, const DimsType &file_dims, const DimsType &grid_dims, const DimsType &grid_bs,\n                                    const DimsType &grid_min, const DimsType &grid_max, T *blks);\n\n    template<typename T>\n    T *_get_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_bmin, const DimsType &grid_bmax, bool lock);\n\n    template<typename T> T *_get_region(size_t ts, string varname, int level, int lod, int nlods, const DimsType &dims, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, bool lock);\n\n    template<typename T>\n    int _get_regions(size_t ts, const std::vector<string> &varnames, int level, int lod, bool lock, const std::vector<DimsType> &dimsvec, const std::vector<DimsType> &bsvec,\n                     const std::vector<DimsType> &bminvec, const std::vector<DimsType> &bmaxvec, std::vector<T *> &blkvec);\n\n    void _unlock_blocks(const void *blks);\n\n    std::vector<string> _get_native_variables() const;\n\n    void *_alloc_region(size_t ts, string varname, int level, int lod, DimsType bmin, DimsType bmax, DimsType bs, int element_sz, bool lock, bool fill);\n\n    void _free_region(size_t ts, string varname, int level, int lod, DimsType bmin, DimsType bmax, bool forceFlag = false);\n\n    bool _free_lru();\n    void _free_var(string varname);\n\n    int _level_correction(string varname, int &level) const;\n    int _lod_correction(string varname, int &lod) const;\n\n    vector<string> _getDataVarNamesDerived(int ndim) const;\n\n    bool _hasCoordForAxis(vector<string> coord_vars, int axis) const;\n\n    string _defaultCoordVar(const DC::Mesh &m, int axis) const;\n\n    void _assignHorizontalCoords(vector<string> &coord_vars) const;\n\n    bool _getVarDimensions(string varname, vector<DC::Dimension> &dimensions, long ts) const;\n\n    bool _getDataVarDimensions(string varname, vector<DC::Dimension> &dimensions, long ts) const;\n\n    bool _getCoordVarDimensions(string varname, vector<DC::Dimension> &dimensions, long ts) const;\n\n    bool _getVarDimNames(string varname, vector<string> &dimnames) const;\n\n    bool _isDataVar(string varname) const\n    {\n        vector<string> names = GetDataVarNames();\n        return (find(names.begin(), names.end(), varname) != names.end());\n    }\n\n    bool _isCoordVar(string varname) const\n    {\n        vector<string> names = GetCoordVarNames();\n        return (find(names.begin(), names.end(), varname) != names.end());\n    }\n\n    bool _getVarConnVars(string varname, string &face_node_var, string &node_face_var, string &face_edge_var, string &face_face_var, string &edge_node_var, string &edge_face_var) const;\n\n    DerivedVar *     _getDerivedVar(string varname) const;\n    DerivedDataVar * _getDerivedDataVar(string varname) const;\n    DerivedCoordVar *_getDerivedCoordVar(string varname) const;\n\n    int _openVariableRead(size_t ts, string varname, int level, int lod);\n\n    template<class T> int _readRegion(int fd, const DimsType &min, const DimsType &max, size_t ndims, T *region);\n    int                   _closeVariable(int fd);\n\n    template<class T> int _getVar(string varname, int level, int lod, T *data);\n\n    template<class T> int _getVar(size_t ts, string varname, int level, int lod, T *data);\n\n    void _getLonExtents(std::vector<float> &lons, DimsType dims, float &min, float &max) const;\n\n    void _getLatExtents(std::vector<float> &lons, DimsType dims, float &min, float &max) const;\n\n    int _getCoordPairExtents(string lon, string lat, float &lonmin, float &lonmax, float &latmin, float &latmax, long ts);\n\n    int _initProj4StringDefault();\n\n    int _initHorizontalCoordVars();\n\n    int _initVerticalCoordVars();\n\n    bool _hasVerticalXForm() const;\n\n    bool _hasVerticalXForm(string meshname, string &standard_name, string &formula_terms) const;\n\n    bool _hasVerticalXForm(string meshname) const\n    {\n        string standard_name, formula_terms;\n        return (_hasVerticalXForm(meshname, standard_name, formula_terms));\n    }\n\n    bool _isCoordVarInUse(string varName) const;\n\n    // Hide public DC::GetDimLensAtLevel by making it private\n    //\n    virtual int GetDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const;\n};\n\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/DataMgrFactory.h",
    "content": "//\n//      $Id$\n//\n\n#ifndef _DataMgrFactory_h_\n#define _DataMgrFactory_h_\n\n#include <vector>\n#include <string>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\nclass VDF_API DataMgrFactory : public Wasp::MyBase {\npublic:\n    static DataMgr *New(const vector<string> &files, size_t mem_size, string ftype = \"vdf\");\n};\n\n};    // namespace VAPoR\n\n#endif    //\t_DataMgrFactory_h_\n"
  },
  {
    "path": "include/vapor/DataMgrUtils.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2017\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tDataMgrUtils.h\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tFebruary 2017\n//\n//\tDescription:\tDefines the DataMgrUtils free functions.\n//\n//  These  functions operate on instances of the DataMgr class.\n//\n#ifndef DATAMGRUTILS_H\n#define DATAMGRUTILS_H\n\n#include <vector>\n#include <string>\n#include <map>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\nnamespace DataMgrUtils {\n\n//! Return the maximum available transform level for a variable.\n//!\n//! This method checks for the existence of a variable at all\n//! available transform levels (see DataMgr::GetNumRefLevels()), and\n//! returns the highest available level. The minimum level is zero\n//! and the max is DataMgr::GetNumRefLevels() - 1.\n//!\n//! \\param[in] timestep Time Step\n//! \\param[in] varname variable name\n//! \\param[out] maxXForm Maximum available level\n//!\n//! \\return status Return true on success. Return false if the no\n//! transform levels exist e.g. the variable does not exist.\n//\nVDF_API bool MaxXFormPresent(const DataMgr *dataMgr, size_t timestep, string varname, size_t &maxXForm);\n\n//! Return the maximum available LOD level for a variable.\n//!\n//! This method checks for the existence of a variable at all\n//! available levels of detail (see DataMgr::GetCRatios()), and\n//! returns the highest available level. The minimum level is zero\n//! and the max is DataMgr::GetCRatios().size() - 1.\n//!\n//! \\param[in] timestep Time Step\n//! \\param[in] varname variable name\n//! \\param[out] maxLOD Maximum available level\n//!\n//! \\return status Return true on success. Return false if the no\n//! LOD levels exist e.g. the variable does not exist.\n//\nVDF_API bool MaxLODPresent(const DataMgr *dataMgr, size_t timestep, string varname, size_t &maxLOD);\n\n//! Convert Projected Coordinate System coordinates to lon/lat in-place.\n//!\n//! Perform in-place conversion of an array of interleaved pairs of\n//! coordinates from PCS\n//! to lon-lat coordinates. The input pairs are ordered X, then Y. The output\n//! pairs are ordered Longitude, then Latitude\n//! Return false if can't do it.\n//!\n//! \\param[in/out] coords coordinates to be converted\n//! \\param[in] npoints Number of points to convert.\n//! \\return true if successful\n//!\nVDF_API int ConvertPCSToLonLat(const DataMgr *dataMgr, double coords[], int npoints = 1);\n\nVDF_API int ConvertPCSToLonLat(string projString, double coords[], int npoints = 1);\n\n//! Convert lon/lat coordinates to Projected Coordinate System coordinates,\n//!  in-place.\n//!\n//! Perform in-place conversion of an array of interleaved pairs of\n//! coordinates from lon-lat\n//! to PCS coordinates. The input pairs are ordered longitude, then\n//! latitude. The output\n//! pairs are ordered X, then Y\n//! Return false if can't do it.\n//!\n//! \\param[in/out] coords coordinates to be converted\n//! \\param[in] npoints Number of points to convert.\n//! \\return true if successful\n//!\nVDF_API int ConvertLonLatToPCS(const DataMgr *dataMgr, double coords[], int npoints = 1);\n\nVDF_API int ConvertLonLatToPCS(string projString, double coords[], int npoints = 1);\n\n//! Method that obtains one or more regular grids at specified timestep,\n//! extents, refinement, and lod.\n//! If the data is available, but not at the requested extents,\n//! refinement or lod, then the extents may\n//! be reduced, and the data accuracy may be reduced.\n//!\n//! All variables must have same spatial dimensionality\n//!\n//! \\param[in] ts timestep being requested\n//! \\param[in] variable name(s) being requested\n//! \\param[in] minExtsReq Minimum requested extents\n//! \\param[in] maxExtsReq Maximum requested extents\n//! \\param[in/out] *refLevel : requested refinement may be\n//! reduced if only a lower level is available\n//! \\param[in] useLowerAccuracy If true use lower accuracy data then\n//! requested if the requested accuracy is not available\n//! \\param[in/out] *lod : requested lod may be reduced if only\n//! a lower lod is available.\n//! \\param[out] grid is a vector of Grid* pointers, one\n//! for each variable\n//! \\param[in] lock : if false, the default, UnlockGrids() will be called on each of the grids\n//! after they are all successfully allocated. Otherwise, the the grids will be locked in\n//! memory until released by an explicit call to UnlockGrids()\n//\ntemplate<typename T>\nVDF_API int GetGrids(DataMgr *dataMgr, size_t ts, const vector<string> &varnames, const T &minExtsReq, const T &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, std::vector<Grid *> &grids,\n                     bool lock = false);\n\nVDF_API int GetGrids(DataMgr *dataMgr, size_t ts, string varname, const CoordType &minExtsReq, const CoordType &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr,\n                     bool lock = false);\n\nVDF_API int GetGrids(DataMgr *dataMgr, size_t ts, string varname, const DimsType &minExtsReq, const DimsType &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr,\n                     bool lock = false);\n\nVDF_API int GetGrids(DataMgr *dataMgr, size_t ts, const vector<string> &varnames, bool useLowerAccuracy, int *refLevel, int *lod, std::vector<Grid *> &grids, bool lock = false);\n\nVDF_API int GetGrids(DataMgr *dataMgr, size_t ts, string varname, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr, bool lock = false);\n\nVDF_API void UnlockGrids(DataMgr *dataMgr, const std::vector<Grid *> &grids);\n\n//! Get the spatial coordinate axes for a variable\n//!\n//! Returns the ordered (fastest to slowest varying) coordinate axis\n//! for a named variable.\n//!\n//! \\param[in] varname Name of variable\n//! \\param[out] axes Ordered list of axis indecies. The range of possible\n//! axes values is [0..2], with 0 corresponding to the X coordinate axis,\n//! 1 corresponding to Y, and 2 to Z.\n//!\nbool GetAxes(const DataMgr *dataMgr, string varname, vector<int> &axes);\n\n//! Get a variables coordinate extents\n//!\n//! Get the minimum and maximum coordinate extents of a name variable\n//! at a given time step. The extents are returned in \\p minExts and\n//! \\p maxExts. The size of these vectors will match the dimensionality\n//! of the variable. The GetAxes() method can be used to determine which\n//! coordinate axes the returned extents correspond to.\n//!\n//! If \\p varname is an empty string the function scans the list of\n//! available data variables looking for the highest dimension variable\n//! available.\n//!\n//! \\param[in] timestep Time step of variable. Ignored for variables that\n//! are not time-varying.\n//! \\param[in] Name of variable\n//! \\param[out] minExts A vector whose size matches the dimensionality\n//! of the variable, and containing the minimum ordered coordinate\n//! extents of \\p varname at time step \\p timestep.\n//! \\param[out] maxExts A vector whose size matches the dimensionality\n//! of the variable, and containing the maximum ordered coordinate\n//! extents of \\p varname at time step \\p timestep.\n//!\n//! \\sa GetAxes()\n//\nVDF_API bool GetExtents(DataMgr *dataMgr, size_t timestep, string varname, int refLevel, int lod, CoordType &minExts, CoordType &maxExts);\n\n//! Get coordinate extents for one or more variables.\n//!\n//! Get the minimum and maximum coordinate extents of a list of variables\n//! at a given time step. This function handles variables with mixed\n//! dimensionality, and 2D variables that are defined on different planes.\n//! The extents are returned in \\p minExts and\n//! \\p maxExts.\n//!\n//! \\param[in] timestep Time step of variable. Ignored for variables that\n//! are not time-varying.\n//! \\param[in] Name of variable\n//! \\param[out] minExts A vector whose size matches the dimensionality\n//! of the variable, and containing the minimum ordered coordinate\n//! extents of \\p varname at time step \\p timestep.\n//! \\param[out] maxExts A vector whose size matches the dimensionality\n//! of the variable, and containing the maximum ordered coordinate\n//! extents of \\p varname at time step \\p timestep.\n//!\n//! \\param[out] axes A vector indicating the axis of each coordinate\n//! returned in \\p minExts and \\p maxExts. See GetAxes()\n//!\n//! \\sa GetAxes()\n//\nVDF_API bool GetExtents(DataMgr *dataMgr, size_t timestep, const vector<string> &varnames, int refLevel, int lod, CoordType &minExts, CoordType &maxExts, vector<int> &axes);\n\n//! Used by the histo for calculating some meta data.\nVDF_API int GetDefaultMetaInfoStride(DataMgr *dataMgr, std::string varname, int refinementLevel);\n\n//! Get default z value at the base of the domain.  Useful\n//! for applying a height value to 2D renderers.\n//! \\param[in] dataMgr Current (valid) dataMgr\n//! \\retval default height value for current dataset\nVDF_API double Get2DRendererDefaultZ(DataMgr *dataMgr, size_t ts, int refLevel, int lod);\n\n//! Find the first variable that exists\n//!\n//! This function searches a data collection looking over all\n//! time steps and variable names for the first available\n//! variable it can find with a given dimension \\p ndim, refinement level\n//! \\p level, and level of detail \\p lod. A variable is \"available\" if\n//! DataMgr::VariableExists() returns true\n//!\n//! \\param[in] ndim Number of spatial dimensions\n//!\n//! \\param[out] varname Returns the name of the first variable found\n//! \\param[out] ts Returns the time step of the first variable found\n//! \\retval status Returns true if a variable is found, false otherwise\n//!\n//! \\sa DataMgr::VariableExists()\n//\nVDF_API bool GetFirstExistingVariable(DataMgr *dataMgr, int level, int lod, int ndim, string &varname, size_t &ts);\n\n//! Find the first variable that exists at a given time step\n//!\n//! This function searches a data collection looking over all\n//! variable names for the first available\n//! variable it can find with a given dimension \\p ndim, time step \\p ts,\n//! refinement level\n//! \\p level, and level of detail \\p lod. A variable is \"available\" if\n//! DataMgr::VariableExists() returns true\n//!\n//! \\param[in] ndim Number of spatial dimensions\n//!\n//! \\param[out] varname Returns the name of the first variable found\n//! \\retval status Returns true if a variable is found, false otherwise\n//!\n//! \\sa DataMgr::VariableExists()\n//\nVDF_API bool GetFirstExistingVariable(DataMgr *dataMgr, size_t ts, int level, int lod, int ndim, string &varname);\n\n#ifdef VAPOR3_0_0_ALPHA\n\n//! Determine the size of a voxel in user coordinates, along a specific dimension,\n//! or its maximum or minimum dimension\n//! \\param[in] timestep of variable used to determine dimensions\n//! \\param[in] varname Variable name used for determining dimension.\n//! \\param[in] reflevel Refinement level at which voxel is measured, or -1 for maximum ref level\n//! \\param[in] dir is 0,1,2 for x,y,z dimension.  Dir is -1 for maximum, -2 for minimum.\ndouble getVoxelSize(size_t timestep, string varname, int refLevel, int dir);\n\n//! Determine the number of active 3D variables.  This includes 3D variables in the VDC as well as any 3D derived variables\n//! \\return number of active 3D variables\nint getNumActiveVariables3D() { return _dataMgr->GetDataVarNames(3).size(); }\n//! Determine the number of active 2D variables.  This includes 2D variables in the VDC as well as any 2D derived variables\n//! \\return number of active 2D variables\nint getNumActiveVariables2D() { return _dataMgr->GetDataVarNames(2).size(); }\n//! Determine the number of active variables.  This includes variables in the VDC as well as any derived variables\n//! \\return number of active variables\nint getNumActiveVariables() { return getNumActiveVariables3D() + getNumActiveVariables2D(); }\n\n//! Map corners of box to voxel coordinates.\n//! Result is zero if box does not lie in data domain.\n//! \\param[in] box is Box to be mapped\n//! \\param[in] varname Name of variable whose coordinates to use\n//! \\param[in] refLevel is refinement level to be used in the mapping\n//! \\param[in] lod is LOD level to be used for the mapping\n//! \\param[in] timestep is time step to use in the mapping\n//! \\param[out] voxExts Voxel extents of box, zeroes if not in data bounds\nvoid mapBoxToVox(Box *box, string varname, int refLevel, int lod, int timestep, size_t voxExts[6]);\n\n#endif\n\n};        // namespace DataMgrUtils\n};        // namespace VAPoR\n#endif    // DATAMGRUTILS_H\n"
  },
  {
    "path": "include/vapor/DataStatus.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tDataStatus.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tFebruary 2006\n//\n//\tDescription:\tDefines the DataStatus class.\n//  This class maintains information about the data that is currently\n//  loaded.  Maintained and accessed mostly through the Session\n#ifndef DATASTATUS_H\n#define DATASTATUS_H\n\n#include <vector>\n#include <string>\n#include <map>\n#include <vapor/common.h>\n#include <vapor/DataMgr.h>\n#include <vapor/ParamsMgr.h>\n\nnamespace VAPoR {\n\n//! \\class DataStatus\n//! \\ingroup Public_Params\n//! \\brief A class for describing the currently loaded dataset\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    January 2016\n//!\n//! The DataStatus class keeps track of available variables, timesteps, resolutions, and data ranges.\n//! It is constructed by the Session whenever a new metadata is loaded.\n//! It keeps a lazily evaluated value of min/max of each variable for each timestep.\n//! Variables can be referenced using the variable name, the session variable num (a numbering all the variables in\n//! the session) or by the active variable num.  Active variables are all those in the metadata plus all\n//! the derived variables, and are a subset of the session variables.\n//! Session variables are those that were specified in the session plus those that are derived, and these may not all be available in the metadata.\n//! To support using active variables and session variable nums,\n//! mappings are provided between active names/nums and session nums, and also between variable names and\n//! their 2D and 3D session variable numbers and active variable numbers.\n\nclass PARAMS_API DataStatus {\npublic:\n    DataStatus(size_t cacheSize, int nThreads = 0);\n    DataStatus() { DataStatus(1000); }\n    virtual ~DataStatus();\n\n    int Open(const std::vector<string> &files, const std::vector<string> &options, string name, string format);\n\n    void Close(string name);\n\n    // const DataMrgV3_0 *GetDataMgr(string name) const;\n    DataMgr *GetDataMgr(string name) const;\n\n    vector<string> GetDataMgrNames() const;\n\n    //! Get domain extents for all active variables\n    //!\n    //! This method returns the union of the domain extents for\n    //! all active variables on the window named by \\p winName.\n    //! A variable is considered active if it\n    //! it currrently in use by an enabled RenderParams instance.\n    //!\n    //! The domain extents returned are always 3D. I.e. \\p minExts\n    //! and \\p maxExts will always have three elements.\n    //!\n    //! If no variable is active all elements of \\p minExts will be zero,\n    //! and all elements of maxExts will be one.\n    //!\n    //! \\param[in] datasetName If provided, will only return extents for\n    //! that dataset.\n    //!\n    //! \\param[in] paramsMgr Active variables are determined by\n    //! querying the ParamsMgr.\n    //! \\param[out] minExts\n    //!\n    //! \\sa ParamsMgr::GetRenderParams()\n    //\n    void GetActiveExtents(const ParamsMgr *paramsMgr, string winName, string datasetName, size_t ts, CoordType &minExts, CoordType &maxExts) const;\n\n    void GetActiveExtents(const ParamsMgr *paramsMgr, string winName, size_t ts, CoordType &minExts, CoordType &maxExts) const;\n\n    void GetActiveExtents(const ParamsMgr *paramsMgr, size_t ts, CoordType &minExts, CoordType &maxExts) const;\n\n    //! Return the aggregated time coordinates for all data sets\n    //!\n    //! This method returns the aggregated time coordinates in\n    //! user defined units for all of the currently opened data sets\n    //! The time coordinates vector monotonically increasing, and contains\n    //! no duplicates.\n    //!\n    //! \\sa GetTimeCoordsFormatted()\n    //\n    const vector<double> &GetTimeCoordinates() const { return (_timeCoords); }\n\n    //! Returns a vector of formatted time coordinate strings\n    //!\n    //! This method interprets the values returned by GetTimeCoordinates()\n    //! as seconds since the EPOCH and uses UDUNITS2 to encode the values\n    //! the values as year, month, day, hour, minute, second, which are\n    //! then formatted as a date-time string.\n    //\n    const vector<string> &GetTimeCoordsFormatted() const { return (_timeCoordsFormatted); }\n\n    //! Map a global to a local time step\n    //!\n    //! Map the global time step \\p ts to the closest \"local\" time step\n    //! in the data set named by \\p dataSetName. If \\p ts is greater\n    //! than or equal to GetTimeCoordinates().size then the last time\n    //! step in \\p dataSetName is returned.\n    //!\n    //! \\return local_ts Returns the local time step, or zero if\n    //! \\p dataSetName is not recognized.\n    //!\n    //! \\sa GetTimeCoordinates().\n    //\n    size_t MapGlobalToLocalTimeStep(string dataSetName, size_t ts) const;\n\n    //! Map a local time step to a global time step range\n    //!\n    //! Map the local time step \\p local_ts for the data set named\n    //! \\p dataSetName to the possible range of global\n    //!\n    //!\n    //! \\sa GetTimeCoordinates().\n    //\n    void MapLocalToGlobalTimeRange(string dataSetName, size_t local_ts, size_t &min_ts, size_t &max_ts) const;\n\n    //! Set number of execution threads\n    //!\n    //! Set the number of execution threads. If \\p nThreads == 0, the\n    //! default,\n    //! the system will attempt to set the number of threads equal to\n    //! the number of cores detected. Has no effect until\n    //! the next data set is loaded.\n    //\n    void SetNumThreads(size_t nthreads) { _nThreads = nthreads; }\n\n    size_t GetNumThreads() const { return _nThreads; }\n\n    //! Set the data cache size\n    //!\n    //! Set the size of the data cache in MBs.\n    //! Has no effect until\n    //! the next data set is loaded.\n    //!\n    //! \\sa DataMgr\n    //\n    void SetCacheSize(size_t sizeMB) { _cacheSize = sizeMB; }\n\n    string GetMapProjection() const;\n    string GetMapProjectionDefault(string dataSetName) const;\n\n    //! Determine the minimum time step for which there is any data.\n    //! \\retval size_t value of smallest time step\n    size_t getMinTimestep() { return 0; }\n\n    //! Determine the maximum time step for which there is any data.\n    //! \\retval size_t value of largest time step\n    size_t getMaxTimestep() { return _timeCoords.size() ? _timeCoords.size() - 1 : 0; }\n\n    //! Determine the maximum refinement level present for a variable at a timestep\n\n    bool WasCacheDirty() const { return _wasCacheDirty; }\n    void SetCacheDirty(const string &dataset=\"\", const string &variable=\"\") {\n        (void)dataset;\n        (void)variable;\n        _isDataCacheDirty = true;\n        _wasCacheDirty = true;\n    }\n\nprivate:\n    typedef struct {\n        std::vector<string> varnames;\n        int                 refLevel;\n        int                 compLevel;\n    } var_info_t;\n\n    void _getExtents(size_t ts, const map<string, std::vector<var_info_t>> &variables, CoordType &minExt, CoordType &maxExt) const;\n\n    map<string, vector<var_info_t>> _getFirstVar(string dataSetName, size_t &ts) const;\n\n    void reset_time();\n    void reset_time_helper();\n\n#ifndef DOXYGEN_SKIP_THIS\n\n    size_t                      _cacheSize;\n    int                         _nThreads;\n    map<string, DataMgr *>      _dataMgrs;\n    map<string, vector<size_t>> _timeMap;\n    vector<double>              _timeCoords;\n    vector<string>              _timeCoordsFormatted;\n    bool                        _isDataCacheDirty;\n    bool                        _wasCacheDirty;\n\n#endif    // DOXYGEN_SKIP_THIS\n\n    friend class ControlExec;\n};\n\n};        // namespace VAPoR\n#endif    // DATASTATUS_H\n"
  },
  {
    "path": "include/vapor/DatasetsParams.h",
    "content": "\n#pragma once\n\n#include <string>\n#include <vapor/ParamsBase.h>\n\nnamespace VAPoR {\n\n//\n// A collection of Dataset params\n//\n// These are not the dataset params. These are the python script generated var params.\n//\nclass PARAMS_API DatasetsParams : public ParamsBase {\npublic:\n    DatasetsParams(ParamsBase::StateSave *ssave);\n\n    DatasetsParams(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    DatasetsParams(const DatasetsParams &rhs);\n\n    DatasetsParams &operator=(const DatasetsParams &rhs);\n\n    virtual ~DatasetsParams();\n\n    void SetScript(string datasetName, string name, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames, const vector<string> &outputVarMeshes, bool coordFlag);\n\n    bool GetScript(string datasetName, string name, string &script, vector<string> &inputVarNames, vector<string> &outputVarNames, vector<string> &outputVarMeshes, bool &coordFlag) const;\n\n    void RemoveDataset(string datasetName) { _datasets->Remove(datasetName); }\n\n    void RemoveScript(string datasetName, string scriptName);\n\n    vector<string> GetScriptNames(string datasetName) const;\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"DatasetsParams\"); }\n\nprivate:\n    static const string _datasetsTag;\n\n    ParamsContainer *_datasets;\n};\n\n//\n// Dataset params\n//\nclass PARAMS_API DatasetParams : public ParamsBase {\npublic:\n    DatasetParams(ParamsBase::StateSave *ssave);\n\n    DatasetParams(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    DatasetParams(const DatasetParams &rhs);\n\n    DatasetParams &operator=(const DatasetParams &rhs);\n\n    virtual ~DatasetParams();\n\n    void SetScript(string name, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames, const vector<string> &outputVarMeshes, bool coordFlag);\n\n    bool GetScript(string name, string &script, vector<string> &inputVarNames, vector<string> &outputVarNames, vector<string> &outputVarMeshes, bool &coordFlag) const;\n\n    void RemoveScript(string name) { _scripts->Remove(name); }\n\n    vector<string> GetScriptNames() const { return (_scripts->GetNames()); }\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"DatasetParams\"); }\n\n    class PARAMS_API ScriptParams : public ParamsBase {\n    public:\n        ScriptParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, ScriptParams::GetClassType()) {}\n\n        ScriptParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\n        virtual ~ScriptParams() {}\n\n        void SetScript(string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames, const vector<string> &outputVarMeshes, bool coordFlag)\n        {\n            _ssave->BeginGroup(\"Set derived variable script\");\n\n            SetValueString(_scriptTag, \"\", script);\n            SetValueStringVec(_inputVarNamesTag, \"\", inputVarNames);\n            SetValueStringVec(_outputVarNamesTag, \"\", outputVarNames);\n            SetValueStringVec(_outputVarMeshesTag, \"\", outputVarMeshes);\n            SetValueLong(_coordFlagTag, \"\", 0);\n\n            _ssave->EndGroup();\n        }\n\n        void GetScript(string &script, vector<string> &inputVarNames, vector<string> &outputVarNames, vector<string> &outputVarMeshes, bool &coordFlag)\n        {\n            script = GetValueString(_scriptTag, \"\");\n            inputVarNames = GetValueStringVec(_inputVarNamesTag);\n            outputVarNames = GetValueStringVec(_outputVarNamesTag);\n            outputVarMeshes = GetValueStringVec(_outputVarMeshesTag);\n            coordFlag = GetValueLong(_coordFlagTag, 0);\n        }\n\n        static string GetClassType() { return (\"ScriptParams\"); }\n\n    private:\n        static const string _scriptTag;\n        static const string _inputVarNamesTag;\n        static const string _outputVarNamesTag;\n        static const string _outputVarMeshesTag;\n        static const string _coordFlagTag;\n    };\n\nprivate:\n    static const string _datasetTag;\n    static const string _scriptsTag;\n\n    ParamsContainer *_scripts;\n\n};    // End of Class DatasetParams\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/DerivedParticleDensity.h",
    "content": "#pragma once\n\n#include <vapor/DerivedVar.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\nclass DerivedParticleDensity : public DerivedDataVar {\n    DC *     _dc;\n    string   _meshName;\n    DataMgr *_dataMgr;\n\npublic:\n    DerivedParticleDensity(string varName, DC *dc, string meshName, DataMgr *dataMgr);\n    virtual int                 Initialize() override;\n    virtual int                 OpenVariableRead(size_t ts, int level = 0, int lod = 0) override;\n    virtual int                 CloseVariable(int fd) override;\n    virtual int                 ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region) override;\n    virtual int                 GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const override;\n    virtual bool                VariableExists(size_t ts, int reflevel, int lod) const override;\n    virtual bool                GetBaseVarInfo(DC::BaseVar &var) const override;\n    virtual bool                GetDataVarInfo(DC::DataVar &cvar) const override;\n    virtual std::vector<string> GetInputs() const override;\n\nprotected:\n    string _dataVar;\n\n    virtual void compute(Grid *inGrid, float *output, int xd, int yd, int zd, size_t realNP) const;\n};\n\n\nclass DerivedParticleAverage : public DerivedParticleDensity {\npublic:\n    DerivedParticleAverage(string varName, DC *dc, string meshName, DataMgr *dataMgr, string inputVar);\n    virtual int Initialize() override { return 0; }\n\nprotected:\n    virtual void compute(Grid *inGrid, float *output, int xd, int yd, int zd, size_t realNP) const override;\n};\n\n\nclass DerivedCoordVar1DSpan : public DerivedCoordVar_CF1D {\n    DC *   _dc;\n    float  _minExt, _maxExt;\n    string _inputCoordVar;\n\npublic:\n    DerivedCoordVar1DSpan(string derivedVarName, DC *dc, string dimName, int axis, string units, float minExt, float maxExt);\n    DerivedCoordVar1DSpan(string derivedVarName, DC *dc, string dimName, int axis, string units, string inputCoordVar);\n    virtual ~DerivedCoordVar1DSpan() {}\n    virtual int                 ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region) override;\n    virtual std::vector<string> GetInputs() const override;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/DerivedVar.h",
    "content": "#include <iostream>\n#include <functional>\n#include <vapor/DC.h>\n#include <vapor/MyBase.h>\n#include <vapor/Proj4API.h>\n#include <vapor/UDUnitsClass.h>\n\n#ifndef _DERIVEDVAR_H_\n    #define _DERIVEDVAR_H_\n\nnamespace VAPoR {\n\nclass NetCDFCollection;\n\n//!\n//! \\class DerivedVar\n//!\n//! \\brief Derived variable abstract class\n//!\n//! This abstract base class defines an API for the internal creation of\n//! derived data and coordinate variables. Derived variables may be used\n//! to support the results of a data operator (e.g. computing wind speed\n//! from velocity component variables), creating of a dimensioned coordinate\n//! variable from a dimensionless one (e.g. supporting the CF conventions\n//! \\a formula_terms attribute), resampling a variable to a different mesh (\n//! resampling a staggered variable to an unstaggered mesh), or\n//! conversion of units (e.g. converting formatted time strings to time\n//! in seconds).\n//!\n//! \\author John Clyne\n//! \\date    January, 2017\n//!\n//!\nclass VDF_API DerivedVar : public Wasp::MyBase {\npublic:\n    DerivedVar(string varName) { _derivedVarName = varName; };\n\n    virtual ~DerivedVar() {}\n\n    virtual int Initialize() = 0;\n\n    string GetName() const { return (_derivedVarName); }\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const = 0;\n\n    virtual bool GetAtt(string attname, std::vector<double> &values) const\n    {\n        values.clear();\n        return (false);\n    }\n\n    virtual bool GetAtt(string attname, std::vector<long> &values) const\n    {\n        values.clear();\n        return (false);\n    }\n\n    virtual bool GetAtt(string attname, string &values) const\n    {\n        values.clear();\n        return (false);\n    }\n\n    virtual std::vector<string> GetAttNames() const { return (std::vector<string>()); }\n\n    virtual DC::XType GetAttType(string attname) const { return (DC::INVALID); }\n\n    virtual std::vector<string> GetInputs() const = 0;\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const = 0;\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const { return GetDimLensAtLevel(level, dims_at_level, bs_at_level); }\n\n    virtual size_t GetNumRefLevels() const { return (1); }\n\n    virtual std::vector<size_t> GetCRatios() const { return (std::vector<size_t>(1, 1)); }\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0) = 0;\n\n    virtual int CloseVariable(int fd) = 0;\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region) = 0;\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, double *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const = 0;\n\nprotected:\n    string        _derivedVarName;\n    DC::FileTable _fileTable;\n\n    int _getVar(DC *dc, size_t ts, string varname, int level, int lod, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region) const;\n\n    int _getVarDestagger(DC *dc, size_t ts, string varname, int level, int lod, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region, int stagDim) const;\n\n};\n\n//!\n//! \\class DerivedCoordVar\n//!\n//! \\brief Derived coordinate variable abstract class\n//!\n//! \\author John Clyne\n//! \\date   Februrary, 2018\n//!\n//!\nclass VDF_API DerivedCoordVar : public DerivedVar {\npublic:\n    DerivedCoordVar(string varName) : DerivedVar(varName) {}\n    virtual ~DerivedCoordVar() {}\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const = 0;\n};\n\n//!\n//! \\class DerivedCFVertCoordVar\n//!\n//! \\brief Derived coordinate variable abstract class\n//!\n//! \\author John Clyne\n//! \\date   July, 2018\n//!\n//!\nclass VDF_API DerivedCFVertCoordVar : public DerivedCoordVar {\npublic:\n    DerivedCFVertCoordVar(string varName, DC *dc, string mesh, string formula) : DerivedCoordVar(varName), _dc(dc), _mesh(mesh), _formula(formula) {}\n\n    virtual ~DerivedCFVertCoordVar() {}\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const = 0;\n\n    //! Parse a CF conventions forumla string into terms and variables\n    //!\n    //! This static method parse the CF conventions\n    //! formula string, typically\n    //! associated with the \\a formula_terms attribute, into a std::map\n    //! of term names and variable names.\n    //!\n    //! If \\p formula cannot be parsed false is returned.\n    //!\n    //! \\param[in] formula : A formatted CF formula string\n    //! \\param[out] parse_terms A map from term names to variable names\n    //!\n    //! \\sa http://cfconventions.org/\n    //!\n    static bool ParseFormula(string formula_terms, map<string, string> &parsed_terms);\n\n    //! validate that a CF conventions forumla string is syntactically correct\n    //!\n    //! This static method checks to see if \\p formula contains a\n    //! syntactically valid  CF conventions formula string, typically\n    //! associated with the \\a formula_terms attribute, and ensures\n    //! that all of required formula terms in \\p required_terms\n    //! are present in the forumla string. If either of these conditions are\n    //! not met the method returns false, otherwise true is returned\n    //!\n    //! \\param[in] required_terms : A vector of term names required to\n    //! be found in \\p formula\n    //! \\param[in] formula : A formatted CF formula string\n    //!\n    //! \\sa http://cfconventions.org/\n    //!\n    static bool ValidFormula(const vector<string> &required_terms, string formula);\n\nprotected:\n    DC *   _dc;\n    string _mesh;\n    string _formula;\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// DerivedCFVertCoordVarFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nclass VDF_API DerivedCFVertCoordVarFactory {\npublic:\n    static DerivedCFVertCoordVarFactory *Instance()\n    {\n        static DerivedCFVertCoordVarFactory instance;\n        return &instance;\n    }\n\n    void RegisterFactoryFunction(string name, function<DerivedCFVertCoordVar *(DC *, string, string)> classFactoryFunction)\n    {\n        // register the class factory function\n        _factoryFunctionRegistry[name] = classFactoryFunction;\n    }\n\n    DerivedCFVertCoordVar *(CreateInstance(string standard_name, DC *, string, string));\n\n    vector<string> GetFactoryNames() const;\n\nprivate:\n    map<string, function<DerivedCFVertCoordVar *(DC *, string, string)>> _factoryFunctionRegistry;\n\n    DerivedCFVertCoordVarFactory() {}\n    DerivedCFVertCoordVarFactory(const DerivedCFVertCoordVarFactory &) {}\n    DerivedCFVertCoordVarFactory &operator=(const DerivedCFVertCoordVarFactory &) { return *this; }\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// DerivedCFVertCoordVarFactoryRegistrar Class\n//\n// Register DerivedCFVertCoordVar derived class with:\n//\n//\tstatic DerivedCFVertCoordVarFactoryRegistrar<class> registrar(\"standard_name\");\n//\n// where 'class' is a class derived from 'DerivedCFVertCoordVar', and\n// \"standard_name\" is the value of the CF \"standard_name\" attribute.\n//\n/////////////////////////////////////////////////////////////////////////\n\ntemplate<class T> class DerivedCFVertCoordVarFactoryRegistrar {\npublic:\n    DerivedCFVertCoordVarFactoryRegistrar(string standard_name)\n    {\n        // register the class factory function\n        //\n        DerivedCFVertCoordVarFactory::Instance()->RegisterFactoryFunction(standard_name, [](DC *dc, string mesh, string formula) -> DerivedCFVertCoordVar * { return new T(dc, mesh, formula); });\n    }\n};\n\n//!\n//! \\class DerivedDataVar\n//!\n//! \\brief Derived data variable abstract class\n//!\n//! \\author John Clyne\n//! \\date   Februrary, 2018\n//!\n//!\nclass VDF_API DerivedDataVar : public DerivedVar {\npublic:\n    DerivedDataVar(string varName) : DerivedVar(varName) {}\n    virtual ~DerivedDataVar() {}\n\n    virtual bool GetDataVarInfo(DC::DataVar &cvar) const = 0;\n};\n\n//!\n//! \\class DerivedCoordVar_PCSFromLatLon\n//!\n//! \\brief Derived PCS coordinate variable from lat-lon coordinate pairs\n//!\n//! \\author John Clyne\n//! \\date   Februrary, 2018\n//!\n//!\nclass VDF_API DerivedCoordVar_PCSFromLatLon : public DerivedCoordVar {\npublic:\n    DerivedCoordVar_PCSFromLatLon(string derivedVarName, DC *dc, std::vector<string> inNames, string proj4String, bool uGridFlag, bool lonFlag);\n    virtual ~DerivedCoordVar_PCSFromLatLon() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>{_lonName, _latName}); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\nprivate:\n    DC *                _dc;\n    string              _proj4String;\n    string              _lonName;\n    string              _latName;\n    string              _xCoordName;\n    string              _yCoordName;\n    bool                _make2DFlag;\n    bool                _uGridFlag;\n    bool                _lonFlag;\n    std::vector<size_t> _dimLens;\n    Proj4API            _proj4API;\n    DC::CoordVar        _coordVarInfo;\n\n    int _setupVar();\n\n    int _readRegionHelperCylindrical(DC::FileTable::FileObject *f, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n    int _readRegionHelper1D(DC::FileTable::FileObject *f, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n    int _readRegionHelper2D(DC::FileTable::FileObject *f, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n};\n\n//!\n//! \\class DerivedCoordVar_CF1D\n//!\n//! \\brief Derived 1D CF conventions coordinate variable using\n//! grid coordinates\n//!\n//! \\author John Clyne\n//! \\date   Februrary, 2018\n//!\n//!\nclass VDF_API DerivedCoordVar_CF1D : public DerivedCoordVar {\npublic:\n    DerivedCoordVar_CF1D(string derivedVarName, DC *dc, string dimName, int axis, string units);\n    virtual ~DerivedCoordVar_CF1D() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>()); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const;\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\nprivate:\n    DC *         _dc;\n    string       _dimName;\n    DC::CoordVar _coordVarInfo;\n};\n\n//!\n//! \\class DerivedCoordVar_CF2D\n//!\n//! \\brief Derived 2D CF conventions coordinate variable . Coordinates\n//! are provided by \\p data, whose length must be dimlens[0] * dimLens[1]\n//!\n//! \\author John Clyne\n//! \\date   Februrary, 2018\n//!\n//!\nclass VDF_API DerivedCoordVar_CF2D : public DerivedCoordVar {\npublic:\n    DerivedCoordVar_CF2D(string derivedVarName, std::vector<string> dimNames, std::vector<size_t> dimLens, int axis, string units, const vector<float> &data);\n    virtual ~DerivedCoordVar_CF2D() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>()); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\nprivate:\n    std::vector<string> _dimNames;\n    std::vector<size_t> _dimLens;\n    std::vector<float>  _data;\n    DC::CoordVar        _coordVarInfo;\n};\n\n//!\n//! \\class DerivedCoordVar_WRFTime\n//!\n//! \\brief Derived WRF Time coordinate variable\n//!\n//! \\author John Clyne\n//! \\date   Februrary, 2018\n//!\n//!\nclass VDF_API DerivedCoordVar_WRFTime : public DerivedCoordVar {\npublic:\n    DerivedCoordVar_WRFTime(string derivedVarName, NetCDFCollection *ncdfc, string wrfTimeVar, string dimName, float p2si = 1.0);\n    virtual ~DerivedCoordVar_WRFTime() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>{_wrfTimeVar}); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, double *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\n    size_t TimeLookup(size_t ts) const { return (ts < _timePerm.size() ? _timePerm[ts] : 0); }\n\nprivate:\n    NetCDFCollection * _ncdfc;\n    std::vector<double> _times;\n    std::vector<int>   _timePerm;\n    string             _wrfTimeVar;\n    float              _p2si;\n    size_t             _ovr_ts;\n    DC::CoordVar       _coordVarInfo;\n\n    int _encodeTime(UDUnits &udunits, const vector<string> &timeStrings, vector<double> &times) const;\n};\n\n//!\n//! \\class DerivedCoordVar_TimeInSeconds\n//!\n//! \\brief Derived time coordinate variable\n//!\n//! \\author John Clyne\n//! \\date   Februrary, 2018\n//!\n//!\nclass VDF_API DerivedCoordVar_TimeInSeconds : public DerivedCoordVar {\npublic:\n    DerivedCoordVar_TimeInSeconds(string derivedVarName, DC *dc, string nativeTimeVar, string dimName);\n    virtual ~DerivedCoordVar_TimeInSeconds() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>{_nativeTimeVar}); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, double *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\n    const vector<double> &GetTimes() const { return (_times); }\n\nprivate:\n    DC *                _dc;\n    std::vector<double> _times;\n    string              _nativeTimeVar;\n    DC::CoordVar        _coordVarInfo;\n};\n\n//!\n//! \\class DerivedCoordVar_Time\n//!\n//! \\brief Synthesize a time coordinate variable\n//!\n//! Creates a time coordinate variable with \\p n user times, running\n//! from 0.0 to n-1.\n//!\n//! \\author John Clyne\n//! \\date   Novermber, 2020\n//!\n//!\nclass VDF_API DerivedCoordVar_Time : public DerivedCoordVar {\npublic:\n    DerivedCoordVar_Time(string derivedVarName, string dimName, size_t n);\n    virtual ~DerivedCoordVar_Time() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>()); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\n    const vector<double> &GetTimes() const { return (_times); }\n\nprivate:\n    std::vector<double> _times;\n    DC::CoordVar        _coordVarInfo;\n};\n\nclass VDF_API DerivedCoordVar_Staggered : public DerivedCoordVar {\npublic:\n    DerivedCoordVar_Staggered(string derivedVarName, string stagDimName, DC *dc, string inName, string dimName);\n    virtual ~DerivedCoordVar_Staggered() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>{_inName}); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\nprivate:\n    string       _inName;\n    string       _stagDimName;\n    string       _dimName;\n    DC *         _dc;\n    DC::CoordVar _coordVarInfo;\n    int          _stagDim;\n};\n\nclass VDF_API DerivedCoordVar_UnStaggered : public DerivedCoordVar {\npublic:\n    DerivedCoordVar_UnStaggered(string derivedVarName, string unstagDimName, DC *dc, string inName, string dimName);\n    virtual ~DerivedCoordVar_UnStaggered() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>{_inName}); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\nprivate:\n    string       _inName;\n    string       _unstagDimName;\n    string       _dimName;\n    DC *         _dc;\n    DC::CoordVar _coordVarInfo;\n    int          _stagDim;\n};\n\nclass VDF_API DerivedCoordVarStandardWRF_Terrain : public DerivedCFVertCoordVar {\npublic:\n    DerivedCoordVarStandardWRF_Terrain(DC *dc, string mesh, string formula);\n    virtual ~DerivedCoordVarStandardWRF_Terrain() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const { return (std::vector<string>{\"PH\", \"PHB\"}); }\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual size_t GetNumRefLevels() const { return (_dc->GetNumRefLevels(_PHVar)); }\n\n    virtual std::vector<size_t> GetCRatios() const { return (_dc->GetCRatios(_PHVar)); }\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\n    static bool ValidFormula(string formula);\n\nprivate:\n    string       _PHVar;\n    string       _PHBVar;\n    float        _grav;\n    DC::CoordVar _coordVarInfo;\n};\n\n//! \\class DerivedCoordVarStandardOceanSCoordinate\n//!\n//! \\brief Convert a CF parameterless vertical coordinate to an Ocean\n//! s-coordinate, generic form 1 or 2\n//!\n//! This derived class converts a dimensionless sigma coordinate variable\n//! to either a Ocean s-coordinate, generic form 1 or 2\n//!\n//! \\sa http://cfconventions.org/\n//\nclass VDF_API DerivedCoordVarStandardOceanSCoordinate : public DerivedCFVertCoordVar {\npublic:\n    DerivedCoordVarStandardOceanSCoordinate(DC *dc, string mesh, string formula);\n    virtual ~DerivedCoordVarStandardOceanSCoordinate() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const;\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual size_t GetNumRefLevels() const { return (1); }\n\n    virtual std::vector<size_t> GetCRatios() const { return (std::vector<size_t>(1, 1)); }\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\n    static bool ValidFormula(string formula);\n\nprivate:\n    string       _standard_name;\n    string       _sVar;\n    string       _CVar;\n    string       _etaVar;\n    string       _depthVar;\n    string       _depth_cVar;\n    double       _CVarMV;\n    double       _etaVarMV;\n    double       _depthVarMV;\n    bool         _destaggerEtaXDim;\n    bool         _destaggerEtaYDim;\n    bool         _destaggerDepthXDim;\n    bool         _destaggerDepthYDim;\n    DC::CoordVar _coordVarInfo;\n\n    int  initialize_missing_values();\n    int  initialize_stagger_flags();\n    void compute_g1(const vector<size_t> &min, const vector<size_t> &max, const float *s, const float *C, const float *eta, const float *depth, float depth_c, float *region) const;\n    void compute_g2(const vector<size_t> &min, const vector<size_t> &max, const float *s, const float *C, const float *eta, const float *depth, float depth_c, float *region) const;\n};\n\n//! \\class DerivedCoordVarStandardAHSPC\n//!\n//! \\brief Convert a CF parameterless vertical coordinate to an Ocean\n//! s-coordinate, generic form 1 or 2\n//!\n//! This derived class converts a dimensionless sigma coordinate variable\n//! to either a Ocean s-coordinate, generic form 1 or 2\n//!\n//! \\sa http://cfconventions.org/\n//\nclass VDF_API DerivedCoordVarStandardAHSPC : public DerivedCFVertCoordVar {\npublic:\n    DerivedCoordVarStandardAHSPC(DC *dc, string mesh, string formula);\n    virtual ~DerivedCoordVarStandardAHSPC() {}\n\n    virtual int Initialize();\n\n    virtual bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n    virtual bool GetCoordVarInfo(DC::CoordVar &cvar) const;\n\n    virtual std::vector<string> GetInputs() const;\n\n    virtual int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    virtual size_t GetNumRefLevels() const { return (1); }\n\n    virtual std::vector<size_t> GetCRatios() const { return (std::vector<size_t>(1, 1)); }\n\n    virtual int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n    virtual int CloseVariable(int fd);\n\n    virtual int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n    virtual bool VariableExists(size_t ts, int reflevel, int lod) const;\n\n    static bool ValidFormula(string formula);\n\nprivate:\n    string _standard_name;\n    string _aVar;\n    string _apVar;\n    string _bVar;\n    string _p0Var;\n    string _psVar;\n    double _psVarMV;\n\n    DC::CoordVar _coordVarInfo;\n\n    int  initialize_missing_values();\n    void compute_a(const vector<size_t> &min, const vector<size_t> &max, const float *a, const float *b, const float *ps, float p0, float *region) const;\n};\n\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/DerivedVarMgr.h",
    "content": "#include <iostream>\n#include <vapor/MyBase.h>\n#include <vapor/DC.h>\n#include <vapor/DerivedVar.h>\n\n#ifndef _DERIVEDVARMGR_H_\n    #define _DERIVEDVARMGR_H_\n\nnamespace VAPoR {\n\n//!\n//! \\class DerivedVarMgr\n//!\n//! \\brief Derived variables constructed from other variables\n//!\n//! \\author John Clyne\n//! \\date    January, 2017\n//!\n//!\nclass VDF_API DerivedVarMgr : public VAPoR::DC {\npublic:\n    //! Class constuctor\n    //!\n    DerivedVarMgr();\n\n    virtual ~DerivedVarMgr(){};\n\n    void AddCoordVar(DerivedCoordVar *cvar);\n\n    void AddDataVar(DerivedDataVar *dvar);\n\n    void RemoveVar(const DerivedVar *var);\n\n    DerivedVar *GetVar(string name) const;\n\n    bool HasVar(string name) const { return (GetVar(name) != NULL); }\n\n    void AddMesh(const Mesh &m);\n\nprotected:\n    //! \\copydoc Initialize()\n    //\n    virtual int initialize(const std::vector<string> &paths, const std::vector<string> &options = std::vector<string>());\n\n    //! \\copydoc GetDimension()\n    //\n    virtual bool getDimension(string dimname, DC::Dimension &dimension) const { return (false); }\n\n    //! \\copydoc GetDimensionNames()\n    //\n    virtual std::vector<string> getDimensionNames() const { return (std::vector<string>()); }\n\n    //! \\copydoc GetMeshNames()\n    //\n    virtual std::vector<string> getMeshNames() const;\n\n    //! \\copydoc GetMesh()\n    //\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc GetCoordVarInfo()\n    //\n    virtual bool getCoordVarInfo(string varname, DC::CoordVar &cvarInfo) const;\n\n    //! \\copydoc GetDataVarInfo()\n    //\n    virtual bool getDataVarInfo(string varname, DC::DataVar &datavarInfo) const;\n\n    //! \\copydoc GetAuxVarInfo()\n    //\n    virtual bool getAuxVarInfo(string varname, DC::AuxVar &varInfo) const { return (false); }\n\n    //! \\copydoc GetBaseVarInfo()\n    //\n    virtual bool getBaseVarInfo(string varname, DC::BaseVar &varInfo) const;\n\n    //! \\copydoc GetDataVarNames()\n    //\n    virtual std::vector<string> getDataVarNames() const;\n\n    //! \\copydoc GetCoordVarNames()\n    //\n    virtual std::vector<string> getCoordVarNames() const;\n\n    //! \\copydoc GetAuxVarNames()\n    //\n    virtual std::vector<string> getAuxVarNames() const { return (std::vector<string>()); }\n\n    //! \\copydoc GetNumRefLevels()\n    //\n    virtual size_t getNumRefLevels(string varname) const;\n\n    //! \\copydoc GetAtt(string varname, string attname, vector <double> &values)\n    //\n    virtual bool getAtt(string varname, string attname, vector<double> &values) const;\n\n    //! \\copydoc GetAtt(string varname, string attname, vector <long> &values)\n    //\n    virtual bool getAtt(string varname, string attname, vector<long> &values) const;\n\n    //! \\copydoc GetAtt(string varname, string attname, string &values)\n    //\n    virtual bool getAtt(string varname, string attname, string &values) const;\n\n    //! \\copydoc GetAttNames()\n    //\n    virtual std::vector<string> getAttNames(string varname) const;\n\n    //! \\copydoc GetAttType()\n    //\n    virtual XType getAttType(string varname, string attname) const;\n\n    //! \\copydoc GetDimLensAtLevel()\n    //\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n    //! \\copydoc GetMapProjection()\n    //\n    virtual string getMapProjection() const { return (string(\"\")); }\n\n    //! \\copydoc OpenVariableRead()\n    //\n    virtual int openVariableRead(size_t ts, string varname, int level = 0, int lod = 0);\n\n    //! \\copydoc CloseVariable()\n    //\n    virtual int closeVariable(int fd);\n\n    //! \\copydoc ReadRegion()\n    //\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region);\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region);\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (-1); }\n\n    //! \\copydoc VariableExists()\n    //\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\nprivate:\n    std::map<string, DerivedVar *>      _vars;\n    std::map<string, DerivedDataVar *>  _dataVars;\n    std::map<string, DerivedCoordVar *> _coordVars;\n    std::map<string, Mesh>              _meshes;\n\n    DerivedVar *     _getVar(string name) const;\n    DerivedDataVar * _getDataVar(string name) const;\n    DerivedCoordVar *_getCoordVar(string name) const;\n\nprivate:\n    DC::FileTable _fileTable;\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/EasyThreads.h",
    "content": "\r\n#ifndef _EasyThreads_h_\r\n#define _EasyThreads_h_\r\n\r\n#include <vector>\r\n\r\n#ifndef WIN32\r\n    #include <pthread.h>\r\n#else\r\n    #include <windows.h>\r\n    #include <process.h>\r\n#endif\r\n#include \"MyBase.h\"\r\n\r\nnamespace Wasp {\r\n\r\nclass COMMON_API EasyThreads : public MyBase {\r\npublic:\r\n    EasyThreads(int nthreads);\r\n    ~EasyThreads();\r\n    int         ParRun(void *(*start)(void *), std::vector<void *> arg);\r\n    int         ParRun(void *(*start)(void *), void **arg);\r\n    int         Barrier();\r\n    int         MutexLock();\r\n    int         MutexUnlock();\r\n    static void Decompose(int n, int size, int rank, int *offset, int *length);\r\n    static int  NProc();\r\n    int         GetNumThreads() const { return (nthreads_c); }\r\n\r\nprivate:\r\n#ifndef WIN32\r\n\r\n    int             nthreads_c;\r\n    pthread_t *     threads_c;\r\n    pthread_attr_t  attr_c;\r\n    pthread_cond_t  cond_c;\r\n    pthread_mutex_t barrier_lock_c;\r\n    pthread_mutex_t mutex_lock_c;\r\n    int             block_c;\r\n    int             count_c;    // counters for barrier\r\n\r\n#else\r\n\r\n    bool    initialized_c;\r\n    int     nblocked_c;\r\n    int     nthreads_c;\r\n    HANDLE *threads_c;\r\n    HANDLE *mutices_c;\r\n    HANDLE *bMutices_c;\r\n    HANDLE  mutex_c;\r\n    HANDLE  bMutex_c;\r\n\r\n#endif\r\n};\r\n\r\n};    // namespace Wasp\r\n\r\n#endif\r\n"
  },
  {
    "path": "include/vapor/Field.h",
    "content": "/*\n * The base class of all possible fields for flow integration.\n */\n\n#ifndef FIELD_H\n#define FIELD_H\n\n#include <string>\n#include <array>\n#include <glm/glm.hpp>\n#include <vapor/common.h>\n\nnamespace flow {\nclass FLOW_API Field {\npublic:\n    // Constructor and destructor.\n    // This class complies with rule of zero.\n    Field() = default;\n    virtual ~Field() = default;\n\n    //\n    // If a given position at a given time is inside of this field\n    //\n    virtual bool InsideVolumeVelocity(double time, glm::vec3 pos) const = 0;\n    virtual bool InsideVolumeScalar(double time, glm::vec3 pos) const = 0;\n\n    //\n    // Retrieve the number of time steps in this field\n    //\n    virtual uint32_t GetNumberOfTimesteps() const = 0;\n\n    //\n    // Get the field value at a certain position, at a certain time.\n    //\n    virtual int GetScalar(double time, glm::vec3 pos,    // input\n                          float &val) const = 0;         // output\n\n    //\n    // Get the velocity value at a certain position, at a certain time.\n    //\n    virtual int GetVelocity(double time, glm::vec3 pos,    // input\n                            glm::vec3 &vel) const = 0;     // output\n\n    //\n    // Returns the number of empty velocity variable names.\n    // It is 3 when the object is newly created, or is used to represent a scalar field\n    //\n    int GetNumOfEmptyVelocityNames() const;\n\n    //\n    // Provide an option to cache and lock certain parameters.\n    // Both functions return 0 on success.\n    //\n    virtual auto LockParams() -> int = 0;\n    virtual auto UnlockParams() -> int = 0;\n\n    // Class members\n    bool                       IsSteady = false;\n    std::string                ScalarName = \"\";\n    std::array<std::string, 3> VelocityNames = {{\"\", \"\", \"\"}};\n};\n};    // namespace flow\n\n#endif\n"
  },
  {
    "path": "include/vapor/FileUtils.h",
    "content": "#pragma once\n\n#include <vapor/common.h>\n#include <string>\n#include <vector>\n#include <initializer_list>\n\nnamespace Wasp {\nnamespace FileUtils {\n\nenum class FileType { File, Directory, Other, Does_Not_Exist };\n\nextern COMMON_API const std::string Separator;\n\nCOMMON_API std::string ReadFileToString(const std::string &path);\nCOMMON_API std::string HomeDir();\nCOMMON_API std::string Basename(const std::string &path);\nCOMMON_API std::string Dirname(const std::string &path);\nCOMMON_API std::string Realpath(const std::string &path);\nCOMMON_API std::string Relpath(std::string path, std::string to);\nCOMMON_API std::string CommonAncestor(const std::vector<std::string> &paths);\nCOMMON_API std::string Extension(const std::string &path);\nCOMMON_API std::string RemoveExtension(const std::string &path);\nCOMMON_API std::string POSIXPathToWindows(std::string path);\nCOMMON_API std::string POSIXPathToCurrentOS(const std::string &path);\nCOMMON_API std::string CleanupPath(std::string path);\nCOMMON_API long        GetFileModifiedTime(const std::string &path);\nCOMMON_API bool        IsPathAbsolute(const std::string &path);\nCOMMON_API bool        Exists(const std::string &path);\nCOMMON_API bool        IsRegularFile(const std::string &path);\nCOMMON_API bool        IsDirectory(const std::string &path);\nCOMMON_API bool        IsSubpath(const std::string &dir, const std::string &path);\nCOMMON_API bool        AreSameFile(const std::string &pathA, const std::string &pathB);\nCOMMON_API FileType    GetFileType(const std::string &path);\nCOMMON_API long long   GetFileSize(const std::string &path);\nCOMMON_API std::vector<std::string> ListFiles(const std::string &path);\n\n//! @code JoinPaths({\"home\", \"a/b\"}); @endcode\nCOMMON_API std::string JoinPaths(const std::vector<std::string> &paths);\nCOMMON_API std::vector<std::string> SplitPath(std::string path);\n\nCOMMON_API int MakeDir(const std::string &path);\n\nCOMMON_API const char *LegacyBasename(const char *path);\n\n}    // namespace FileUtils\n}    // namespace Wasp\n"
  },
  {
    "path": "include/vapor/FlowParams.h",
    "content": "#ifndef FLOWPARAMS_H\n#define FLOWPARAMS_H\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n#include <vector>\n#include <utility>\n\nnamespace VAPoR {\n\n//\n// These two enums are used across params, GUI, and renderer.\n// Note: use static_cast to cast between them and int types.\n//\nenum class FlowSeedMode : int { UNIFORM = 0, RANDOM = 1, RANDOM_BIAS = 2, LIST = 3 };\nenum class FlowDir : int { FORWARD = 0, BACKWARD = 1, BI_DIR = 2 };\n\nclass FlowParams;\nclass PARAMS_API FakeRakeBox : public Box {\n    string _tag;\n\npublic:\n    using Box::Box;\n    FlowParams *parent = nullptr;\n\n    void Initialize(string tag);\n    void SetExtents(const vector<double> &minExt, const vector<double> &maxExt) override;\n};\n\nclass PARAMS_API FlowParams : public RenderParams {\n    StateSave    _fakeRakeStateSave;\n    FakeRakeBox *_fakeRakeBox = nullptr;\n    FakeRakeBox *_fakeIntegrationBox = nullptr;\n    bool         _initialized = false;\n\n    void   _setRakeCenter(int dim, double center);\n    double _getRakeCenter(int dim);\n\npublic:\n    enum RenderType { RenderTypeStream, RenderTypeSamples, RenderTypeDensity };\n    enum GlpyhType { GlpyhTypeSphere, GlpyhTypeArrow };\n\n    // Constructors\n    FlowParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave);\n    FlowParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *xmlNode);\n\n    FlowParams(const FlowParams &rhs);\n    FlowParams &operator=(const FlowParams &rhs);\n\n    virtual ~FlowParams();\n\n    virtual int Initialize() override;\n\n    static std::string GetClassType() { return (\"FlowParams\"); }\n\n    //! \\copydoc RenderParams::SetDefaultVariables()\n    void SetDefaultVariables(int dim = 3, bool secondaryColormapVariable = false) override;\n\n    //! Sets the type of flow rendering algorithm being used.\n    //! \\details Steady flow (streamlines) renders time-invariant trajectories that follow a vector field at a single timestep.\\n\n    //! Unsteady flow (pathlines) render time-variant trajectories that advect through the timeseries of a loaded dataset.\n    //! \\param[in] bool - Steady/streamlines = true, Unsteady/pathlines = false\n    void SetIsSteady(bool steady);\n    \n    //! Gets the type of flow rendering algorithm being used.\n    //! \\copydetails FlowParams::SetIsSteady(bool)\n    //! \\retval bool - Steady/streamlines = true, Unsteady/pathlines = false\n    bool GetIsSteady() const;\n\n    //! Get the multiplier being applied to the flow advection algorithm.\n    //! \\details If there happens to be a mismatch between the units of your data's domain and the units of a variable such as wind speed,\\n\n    //! you can scale the wind field with this parameter.  IE - If your data's domain is written in kilometers but your wind\\n\n    //! vectors are in meters, you can apply a velocity multiplyer of 0.001 to correct the mismatch.\n    //! \\retval double - Velocity field multiplier for flow rendering\n    double GetVelocityMultiplier() const;\n\n    //! Get the multiplier being applied to the first step size of flow integration.\n    //! \\details VAPOR estimates a step size to be applied to the first step of flow integration,\\n\n    //!          and then dynamically adjusts that value afterwards. However, VAPOR may fail to produce a proper estimate \\n\n    //!          (mostly too big of an estimate) and result in obviously wrong flow lines. \\n\n    //!          In such cases, users may manually apply a multiplier to the first step size.\n    //! \\retval double - First step size multiplier for flow rendering.\n    double GetFirstStepSizeMultiplier() const;\n\n    //! Get the boolean that indicates if the flow advection uses fixed step sizes.\n    //! \\details VAPOR adjusts its advection step sizes automatically based on the curvature of the past few steps.\\n\n    //!          This behavior, however, can be disabled, in which case the user-provided step size will be used.\\n\n    //! \\retval bool - If VAPOR uses fixed advection steps.\n    bool GetUseFixedAdvectionSteps() const;\n\n    //! Get the fixed advection step size to be used.\n    //! \\copydetails FlowParams::GetUseFixedAdvectionSteps()\n    //! \\retval double - Fixed advection step size to be used.\n    double GetFixedAdvectionStepSize() const;\n    \n    //! Set the multiplier being applied to the flow advection algorithm.\n    //! \\copydetails FlowParams::GetVelocityMultiplier()\n    //! \\param[in] double - Velocity field multiplier for flow rendering\n    void SetVelocityMultiplier(double);\n    \n    //! Set the multiplier being applied to the first step size of flow advection.\n    //! \\copydetails FlowParams::GetFirstStepSizeMultiplier()\n    //! \\param[in] double - Velocity field multiplier for flow rendering\n    void SetFirstStepSizeMultiplier(double);\n\n    //! Set the boolean that indicates if the flow advection uses fixed step sizes.\n    //! \\copydetails FlowParams::GetUseFixedAdvectionSteps()\n    //! \\param[in] bool - If VAPOR uses fixed advection steps.\n    void SetUseFixedAdvectionSteps(bool);\n\n    //! Set the fixed advection step size to be used.\n    //! \\copydetails FlowParams::GetUseFixedAdvectionSteps()\n    //! \\param[in] bool - User-specified value to be used for fixed step advection.\n    void SetFixedAdvectionStepSize(double);\n\n    //! Get the target number of steps to advect a steady flow line (aka a streamline).\n    //! \\copydetails FlowParams::SetSteadyNumOfSteps()\n    //! \\retval long - The number of steps a steady flow line targets to advect.\n    long GetSteadyNumOfSteps() const;\n    \n    //! Set the target number of steps to advect a steady flow line (aka a streamline).\n    //! \\details Note 1: Advection can terminate before hitting the specified target number of steps. Common reasons are 1) it travels \\n\n    //!         out of the volume, and 2) it enters a \"sink\" where velocity is zero and no longer travels.\\n\n    //! Note 2: The advection step size is adjusted internally based on the current curvature, so even with the same steps\\n\n    //!         being advected, the lengths of advected trajectories can still differ.\n    //! \\param[in] long - The number of steps a steady flow line targets to advect.\n    void SetSteadyNumOfSteps(long);\n\n    //! Get the mode for generating seeds (points of origin) for the flow renderer.\n    //! \\retval int - The current seed generation mode for the flow renderer. 0 = Gridded, 1 = Random, 2 = Random with bias, 3 = List of seeds\n    int  GetSeedGenMode() const;\n    \n    //! Set the mode for generating seeds (points of origin) for the flow renderer.\n    //! \\param[in] int - The current seed generation mode for the flow renderer. 0 = Gridded, 1 = Random, 2 = Random with bias, 3 = List of seeds\n    void SetSeedGenMode(int);\n\n    //! Enable or disable the writing of flow renderer data values to a text file.\n    //! \\param[in] bool - Enable (true) or disable (false) the writing of trajectory data values to a text file.\n    void SetNeedFlowlineOutput(bool);\n    \n    //! Inquire whether the writing of flow renderer data values are being written to a text file.\n    //! \\retval bool - Enable (true) or disable (false) the writing of trajectory data values to a text file.\n    bool GetNeedFlowlineOutput() const;\n\n    //! Get the current flow renderer's advection direction.\n    //! \\retval int - The advection direction for the current flow renderer.  (0 = forward, 1 = backward, 2 = bi-directional)\n    int  GetFlowDirection() const;\n    \n    //! Set the current flow renderer's advection direction.\n    //! \\param[in] int - The advection direction for the current flow renderer.  (0 = forward, 1 = backward, 2 = bi-directional)\n    void SetFlowDirection(int);\n\n    //! Get the file name/path to a file containing a list of seed points to advect from.\n    //! \\details See https://ncar.github.io/VaporDocumentationWebsite/vaporApplicationReference/flowRenderer.html#seed-distribution-settings\n    //! \\retval string - A file path containing a defined list of seed points to advect from\n    std::string GetSeedInputFilename() const;\n    \n    //! Set the file name/path to a file containing a list of seed points to advect from.\n    //! \\copydetails FlowParams::GetSeedInputFilename()\n    //! \\param[in] string - A file path containing a defined list of seed points to advect from\n    void SetSeedInputFilename(const std::string &);\n\n    //! This will return the file path to the text file that data will be written to when outputing flow lines.\n    //! \\retval string - The file path of the data file that contains sample values along streamlines/pathlines.\n    std::string GetFlowlineOutputFilename() const;\n    \n    //! Sets the file path to the text file that flowline output will be written to.\n    //! \\param[in] string - The file path of the data file that contains sample data along streamlines/pathlines.\n    void SetFlowlineOutputFilename(const std::string &);\n\n    //! If more than one variable is being sampled along flowlines and is being written to an output file, this returns those variables.\n    //! \\retval std::vector<std::string> - A vector containing the variables being written to the specified output file name.\n    std::vector<std::string> GetFlowOutputMoreVariables() const;\n\n    //! One or more variable to be sampled along flowlines and written to an output file.\n    //! \\param[in] std::vector<std::string> - A vector containing the variables being written to the specified output file name.\n    void SetFlowOutputMoreVariables(std::vector<std::string> vars);\n\n    //! Inquires whether the current flow advection scheme is periodic.\n    //! \\details IE - Do pathlines or streamlines continue on the opposite side of the domain when the exit it?  Similar to when PAC-MAN exits the right side of the screen, and re-enters on the left.\\n\n    //! Note: this result vector could be of size 2 or 3.\n    //! \\retval std::vector<bool> - A vector consisting of booleans that indicate periodicity on the X, Y, and Z axes.  (false = non-periodic, true = periodic)\n    std::vector<bool> GetPeriodic() const;\n\n    //! Gets whether the current flow advection scheme is periodic.\n    //! \\copydetails FlowParams::GetPeriodic()\n    //! \\param[in] std::vector<bool> - A vector consisting of booleans that indicate periodicity on the X, Y, and Z axes.  (false = non-periodic, true = periodic)\n    void SetPeriodic(const std::vector<bool> &);\n\n    /*\n     * 6 values to represent a rake in this particular order:\n     * xmin, xmax, ymin, ymax, zmin, zmax\n     * If the rake wasn't set by users, it returns a vector containing nans.\n     * If it represents a 2D area, then it will contain the first 4 elements.\n     */\n    Box *              GetRakeBox();\n    std::vector<float> GetRake() const;\n    void               SetRake(const std::vector<float> &);\n\n    Box *GetIntegrationBox();\n    void SetIntegrationVolume(const std::vector<float> &);\n\n    //! Returns the number of seed points on the X, Y, and Z axes if the seeding distribution is Gridded, as determined by GetSeedGenMode() \n    //! \\retval std::vector<long> - Number of seeds distributed on the X, Y, and Z axes.\n    std::vector<long> GetGridNumOfSeeds() const;\n    \n    //! Sets the number of seed points on the X, Y, and Z axes if the seeding distribution is Gridded, as determined by GetSeedGenMode()\n    //! \\retval std::vector<long> - Number of seeds distributed on the X, Y, and Z axes.\n    void SetGridNumOfSeeds(const std::vector<long> &);\n\n    //! Returns the number of seed points randomly generated if the seeding distribution is randomly generated, as determined by GetSeedGenMode()\n    //! \\retval long - Number of seeds randomly distributed within the seeding rake region.\n    long GetRandomNumOfSeeds() const;\n    \n    //! Sets the number of seed points randomly generated if the seeding distribution is randomly generated, as determined by GetSeedGenMode()\n    //! \\param[in] long - Number of seeds randomly distributed within the seeding rake region.\n    void SetRandomNumOfSeeds(long);\n\n    //! Returns the bias variable that randomly seeded flow-lines are distributed towards if the seed generation mode is \"Random w/ Bias.\"\n    //! \\retval string - The variable that seeds are biased distributed for.\n    std::string GetRakeBiasVariable() const;\n    \n    //! Sets the bias variable that randomly seeded flow-lines are distributed towards if the seed generation mode is \"Random w/ Bias.\"\n    //! \\retval string - The variable that seeds are biased distributed for.\n    void SetRakeBiasVariable(const std::string &);\n\n    //! When randomly seeding flowlines with bias towards along a chosen variable's distribution, this returns the bias strength.  \n    //! \\details Negative bias will place seeds at locations where the bias value has low values.  Positive bias will place seeds where the bias variable has high values.\n    //! \\retval int - The bias of the seed distribution.\n    long GetRakeBiasStrength() const;\n\n    //! When randomly seeding flowlines with bias towards along a chosen variable's distribution, this sets the bias strength.\n    //! \\copydetails\n    //! \\param[in] long - The bias of the seed distribution.\n    void SetRakeBiasStrength(long);\n\n\n    int  GetPastNumOfTimeSteps() const;\n    void SetPastNumOfTimeSteps(int);\n\n    //! Returns the interval that new pathlines are injected into the scene.\n    //! \\retval int - The seed injection interval.\n    int  GetSeedInjInterval() const;\n    \n    //! Sets the interval w.r.t. the time steps that new pathlines are injected into the scene.\n    //! For example, 1 means that seeds are injected at every time step, and 2 means that seeds are injected at every other time step. Note  \"time step\" refers to the data set time step, not the integration time step\n    //! \\param[in] int - The seed injection interval.\n    void SetSeedInjInterval(int);\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override\n    {\n        for (const auto &p : GetFieldVariableNames()) {\n            if (!p.empty()) return _dataMgr->GetVarTopologyDim(p);\n        }\n        return GetBox()->IsPlanar() ? 2 : 3;\n    }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override\n    {\n        if (UseSingleColor())\n            return \"\";\n        else\n            return GetColorMapVariableName();\n    }\n\n    //! Get the rake's center position on the X axis\n    //! \\retval X rake center\n    double GetXRakeCenter();\n\n    //! Set the rake's center position on the X axis\n    //! \\param[in] Rake center position on X axis\n    void SetXRakeCenter(double center);\n\n    //! Get the rake's center position on the Y axis\n    //! \\retval Y rake center\n    double GetYRakeCenter();\n\n    //! Set the rake's center position on the Y axis\n    //! \\param[in] Rake center position on Y axis\n    void SetYRakeCenter(double center);\n\n    //! Get the rake's center position on the Z axis\n    //! \\retval Z rake center\n    double GetZRakeCenter();\n\n    //! Set the rake's center position on the Z axis\n    //! \\param[in] Rake center position on Z axis\n    void SetZRakeCenter(double center);\n\n    //! The rendering type that represents the flow paths.\n    //! See RenderType enum class.\n    static const std::string RenderTypeTag;\n\n    static const std::string RenderRadiusBaseTag;\n\n    //! Scales the radius of the flow tube rendering.\n    //! Applies data of type: double.\n    //! Typical values: 0.1 to 5.0.\n    //! Valid values: DBL_MIN to DBL_MAX.\n    static const std::string RenderRadiusScalarTag;\n\n    //! Toggles between rendering 2d glyphs and 3d geometry of the render type.\n    //! Applies data of type: bool.\n    //! Valid values: 0 = off, 1 = on.\n    static const std::string RenderGeom3DTag;\n\n    static const std::string RenderLightAtCameraTag;\n\n    //! Draws the direction of the flow stream.\n    //! Applies data of type: bool.\n    //! Valid values: 0 = off, 1 = on.\n    static const std::string RenderShowStreamDirTag;\n    \n    //! When rendering samples, determines whether samples are rendered as circles or arrows.\n    //! Applies data of type: long.\n    //! Valid values: 0 = FloatParams::GlyphTypeSphere, 1 = FloatParams::GlyphTypeArrow.\n    static const std::string RenderGlyphTypeTag;\n\n    //! When rendering samples, draw every N samples.\n    //! Applies data of type: int.\n    //! Typical values: 1 to 20.\n    //! Valid values: INT_MIN to INT_MAX.\n    static const std::string RenderGlyphStrideTag;\n\n    //! When rendering samples, only draw the leading sample in a path.\n    //! Applies data of type: bool.\n    //! Valid values: 0 = off, 1 = on.\n    static const std::string RenderGlyphOnlyLeadingTag;\n\n    //! Falloff parameter for the flow density rendering mode as specified in\n    //! https://www.researchgate.net/publication/261329939_Trajectory_Density_Projection_for_Vector_Field_Visualization\n    //! Applies data of type: double.\n    //! Typical values: 0.5 to 10.0.\n    //! Valid values: DBL_MIN to DBL_MAX.\n    static const std::string RenderDensityFalloffTag;\n\n    //! ToneMapping parameter for the flow density rendering mode as specified in\n    //! https://www.researchgate.net/publication/261329939_Trajectory_Density_Projection_for_Vector_Field_Visualization\n    //! Applies data of type: double.\n    //! Typical values: 0.0 to 1.0.\n    //! Valid values: DBL_MIN to DBL_MAX.\n    static const std::string RenderDensityToneMappingTag;\n\n    //! Applies transparency to the tails of pathlines and streamlines.\n    //! Applies data of type: bool.\n    //! Valid values: 0 = off, 1 = on.\n    static const std::string RenderFadeTailTag;\n\n    //! Specifies the starting integration step for fading a flow line's tail.\n    //! Applies data of type: int.\n    //! Typical values: 1 to 100.\n    //! Valid values: INT_MIN to INT_MAX.\n    static const std::string RenderFadeTailStartTag;\n\n\n    //! Specifies the stopping integration step for fading a flow line's tail.\n    //! Applies data of type: int.\n    //! Typical values: 1 to 100.\n    //! Valid values: INT_MIN to INT_MAX.\n    static const std::string RenderFadeTailStopTag;\n\n    //! Specifies the length of a faded flow line when animating steady flow.\n    //! Applies data of type: int.\n    //! Typical values: 1 to 100.\n    //! Valid values: INT_MIN to INT_MAX.\n    static const std::string RenderFadeTailLengthTag;\n\n    //! Specifies the Phong Ambient lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model).\n    //! Applies data of type: double.\n    //! Typical values: 0.0 to 1.0.\n    //! Valid values: DBL_MIN to DBL_MAX.\n    static const std::string PhongAmbientTag;\n\n    //! Specifies the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model).\n    //! Applies data of type: double.\n    //! Typical values: 0.0 to 1.0.\n    //! Valid values: DBL_MIN to DBL_MAX.\n    static const std::string PhongDiffuseTag;\n\n    //! Specifies the Phong Specular lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model).\n    //! Applies data of type: double.\n    //! Typical values: 0.0 to 1.0.\n    //! Valid values: DBL_MIN to DBL_MAX.\n    static const std::string PhongSpecularTag;\n\n    //! Specifies the Phong Shininess lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model).\n    //! Applies data of type: double.\n    //! Typical values: 0.0 to 100.0.\n    //! Valid values: DBL_MIN to DBL_MAX.\n    static const std::string PhongShininessTag;\n\n    static const std::string _isSteadyTag;\n    static const std::string _velocityMultiplierTag;\n    static const std::string _firstStepSizeMultiplierTag;\n    static const std::string _fixedAdvectionStepTag;\n    static const std::string _fixedAdvectionStepSizeTag;\n    static const std::string _steadyNumOfStepsTag;\n    static const std::string _seedGenModeTag;\n    static const std::string _seedInputFilenameTag;\n    static const std::string _flowlineOutputFilenameTag;\n    static const std::string _flowOutputMoreVariablesTag;\n    static const std::string _flowDirectionTag;\n    static const std::string _needFlowlineOutputTag;\n    static const std::string _xPeriodicTag;\n    static const std::string _yPeriodicTag;\n    static const std::string _zPeriodicTag;\n    static const std::string _rakeTag;\n    static const std::string _doIntegrationTag;\n    static const std::string _integrationScalarTag;\n    static const std::string _integrationSetAllToFinalValueTag;\n    static const std::string _integrationBoxTag;\n    static const std::string _rakeBiasVariable;\n    static const std::string _rakeBiasStrength;\n    static const std::string _pastNumOfTimeSteps;\n    static const std::string _seedInjInterval;\n    static const std::string _xGridNumOfSeedsTag;\n    static const std::string _yGridNumOfSeedsTag;\n    static const std::string _zGridNumOfSeedsTag;\n    static const std::string _randomNumOfSeedsTag;\n\n    // maps between ints and \"human readable\" strings\n    const std::vector<std::pair<int, std::string>> _seed2Str = {{static_cast<int>(FlowSeedMode::UNIFORM), \"\"},    // default value\n                                                                {static_cast<int>(FlowSeedMode::UNIFORM), \"UNIFORM\"},\n                                                                {static_cast<int>(FlowSeedMode::RANDOM), \"RANDOM\"},\n                                                                {static_cast<int>(FlowSeedMode::RANDOM_BIAS), \"RANDOM_BIAS\"},\n                                                                {static_cast<int>(FlowSeedMode::LIST), \"LIST\"}};\n\n    const std::vector<std::pair<int, std::string>> _dir2Str = {{static_cast<int>(FlowDir::FORWARD), \"\"},    // default value\n                                                               {static_cast<int>(FlowDir::FORWARD), \"FORWARD\"},\n                                                               {static_cast<int>(FlowDir::BACKWARD), \"BACKWARD\"},\n                                                               {static_cast<int>(FlowDir::BI_DIR), \"BI_DIRECTIONAL\"}};\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/FlowRenderer.h",
    "content": "#ifndef FLOWRENDERER_H\n#define FLOWRENDERER_H\n\n#include \"vapor/glutil.h\"\n#include \"vapor/Renderer.h\"\n#include \"vapor/FlowParams.h\"\n#include \"vapor/GLManager.h\"\n#include \"vapor/Advection.h\"\n#include \"vapor/VaporField.h\"\n\n#include <glm/glm.hpp>\n\nnamespace VAPoR {\n\nclass RENDER_API FlowRenderer final : public Renderer {\npublic:\n    FlowRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr);\n\n    // Rule of five\n    ~FlowRenderer();\n    FlowRenderer(const FlowRenderer &) = delete;\n    FlowRenderer(const FlowRenderer &&) = delete;\n    FlowRenderer &operator=(const FlowRenderer &) = delete;\n    FlowRenderer &operator=(const FlowRenderer &&) = delete;\n\n    static std::string GetClassType() { return (\"Flow\"); }\n\nprotected:\n    virtual std::string _getColorbarVariableName() const override;\n\nprivate:\n    // Define two enums for this class use only\n    enum class FlowStatus {\n        SIMPLE_OUTOFDATE,    // When variable name or compression is out of date,\n        TIME_STEP_OOD,       // Existing particles are good, but need to advect more\n        UPTODATE             // Everything is up-to-date\n    };\n\n    // C++ stuff: pure virtual functions from Renderer\n    int  _initializeGL() override;\n    int  _paintGL(bool fast) override;\n    void _clearCache() override{};\n\n    // Member variables\n    flow::Advection     _advection;\n    flow::VaporField    _velocityField;\n    flow::VaporField    _colorField;\n    std::vector<float>  _colorMap;\n    std::vector<double> _timestamps;\n    float               _colorMapRange[3];    // min, max, and their diff\n\n    bool _advectionComplete = false;\n    bool _coloringComplete = false;\n\n    // A few variables to keep the current advection states.\n    // Some of them are initialized to be at an illegal state.\n    int _cache_refinementLevel = 0;\n    int _cache_compressionLevel = 0;\n\n    double             _cache_velocityMltp = 1.0;\n    double             _cache_firstStepSizeMltp = 1.0;\n    bool               _cache_isSteady = false;\n    long               _cache_steadyNumOfSteps = 0;\n    size_t             _cache_currentTS = 0;\n    std::vector<bool>  _cache_periodic{false, false, false};\n    std::vector<float> _cache_rake{0.f, 0.f, 0.f, 0.f, 0.f, 0.f};\n    std::vector<long>  _cache_gridNumOfSeeds{5, 5, 5};\n    long               _cache_randNumOfSeeds = 5;\n    int                _cache_seedInjInterval = 0;\n    int                _cache_pastNumOfTimeSteps = 0;\n    long               _cache_rakeBiasStrength = 0;\n    double             _cache_deltaT = 0.05;\n    FlowSeedMode       _cache_seedGenMode = FlowSeedMode::UNIFORM;\n    FlowDir            _cache_flowDir = FlowDir::FORWARD;\n    FlowStatus         _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    FlowStatus         _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    FlowStatus         _renderStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    std::string        _cache_rakeBiasVariable;\n    std::string        _cache_seedInputFilename;\n    bool                _cache_doIntegration;\n    bool                _cache_integrationSetAllToFinalValue;\n    float               _cache_integrationDistScalar;\n    std::vector<double> _cache_integrationVolume;\n    bool                _cache_useFixedAdvectionSteps = false;\n    double              _cache_fixedAdvectionStepSize = 0.0;\n\n    // This Advection class is only used in bi-directional advection mode\n    std::unique_ptr<flow::Advection> _2ndAdvection;\n\n    // Member variables for OpenGL\n    const GLint    _colorMapTexOffset;\n    ShaderProgram *_shader = nullptr;\n    GLuint         _vertexArrayId = 0;\n    GLuint         _vertexBufferId = 0;\n    GLuint         _colorMapTexId = 0;\n\n    unsigned int _VAO = 0;\n    unsigned int _VBO = 0;\n    vector<int>  _streamSizes;\n\n    //\n    // Member functions\n    //\n    int _genSeedsRakeUniform(std::vector<flow::Particle> &seeds) const;\n    int _genSeedsRakeRandom(std::vector<flow::Particle> &seeds) const;\n    int _genSeedsRakeRandomBiased(std::vector<flow::Particle> &seeds) const;\n    int _genSeedsFromList(std::vector<flow::Particle> &seeds) const;\n\n    int       _renderFromAnAdvectionLegacy(const flow::Advection *, FlowParams *, bool fast);\n    int       _renderAdvection(const flow::Advection *adv);\n    int       _renderAdvectionHelper(bool renderDirection = false);\n    void      _prepareColormap(FlowParams *);\n    void      _particleHelper1(std::vector<float> &vec, const flow::Particle &p, bool singleColor) const;\n    int       _drawALineStrip(const float *buf, size_t numOfParts, bool singleColor) const;\n    void      _restoreGLState() const;\n    glm::vec3 _getScales();\n\n    // Update values of _cache_* and _state_* member variables.\n    int _updateFlowCacheAndStates(const FlowParams *);\n\n    int _updateAdvectionPeriodicity(flow::Advection *advc);\n\n    int _outputFlowLines();\n\n    void _dupSeedsNewTime(std::vector<flow::Particle> &seeds,\n                          size_t                       firstN,    // First N particles to duplicate\n                          double                       newTime) const;                  // New time to assign to particles\n\n    // Print return code if it's non-zero and compiled in debug mode.\n    void _printNonZero(int rtn, const char *file, const char *func, int line) const;\n\n};    // End of class FlowRenderer\n\n};    // End of namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/Font.h",
    "content": "#pragma once\n\n#include <string>\n#include <map>\n#include <glm/glm.hpp>\n#include \"vapor/MyBase.h\"\n\n#include <ft2build.h>\n#include FT_FREETYPE_H\n\nnamespace VAPoR {\n\nstruct GLManager;\n\n//! \\class Font\n//! \\ingroup Public_Render\n//!\n//! \\brief Renders charachter glyphs using FreeType2\n//! This class does not do any transformation, formatting,\n//! etc., please use the TextLabel class for that.\n//!\n//! \\author Stanislaw Jaroszynski\n\nclass RENDER_API Font : public Wasp::MyBase {\n    struct Glyph {\n        unsigned int textureID;\n        int          sizeX;\n        int          sizeY;\n        int          bearingX;\n        int          bearingY;\n        long         advance;\n    };\n\n    GLManager *_glManager;\n    FT_Library _library;\n    FT_Face    _face;\n\n    std::map<int, Glyph> _glyphMap;\n    int                  _size;\n    unsigned int         _VAO, _VBO;\n\n    bool  LoadGlyph(int c);\n    Glyph GetGlyph(int c);\n\npublic:\n    Font(GLManager *glManager, const std::string &path, int size, FT_Library library = nullptr);\n    ~Font();\n\n    //! Draws text in pixel coordinates i.e. if font is 10px,\n    //! text will be 10 OpenGL units tall.\n    //!\n    //! \\param[in] text\n    //! \\param[in] color default is white\n    //!\n    void DrawText(const std::string &text, const glm::vec4 &color = glm::vec4(1));\n\n    //! Returns pixel dimensions of text\n    //!\n    glm::vec2 TextDimensions(const std::string &text);\n    float     LineHeight() const;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/FontManager.h",
    "content": "#pragma once\n\n#include \"vapor/IResourceManager.h\"\n#include \"vapor/Font.h\"\n\nnamespace VAPoR {\n\nstruct GLManager;\n\nclass RENDER_API FontManager : public IResourceManager<std::pair<std::string, unsigned int>, Font> {\n    GLManager *_glManager;\n    FT_Library _library;\n\npublic:\n    FontManager(GLManager *glManager);\n    ~FontManager();\n\n    Font *GetFont(const std::string &name, unsigned int size);\n    int   LoadResourceByKey(const std::pair<std::string, unsigned int> &key);\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/Framebuffer.h",
    "content": "#pragma once\n\n#include <vapor/NonCopyableMixin.h>\n#include <vapor/Texture.h>\n\nnamespace VAPoR {\n\n//! \\class Framebuffer\n//! \\ingroup Public_Render\n//! \\brief Wrapper class for an OpenGL Framebuffer\n//! \\author Stas Jaroszynski\n//! \\version 1.0\n//! \\date May 2019\n//!\n//! This class is intended to be used as a member object for a renderer.\n//! Any use of this class (including the destructor and except the constructor)\n//! must occur inside the correct OpenGL context.\n//!\n//! To use a depth buffer, EnableDepthBuffer must be called before calling\n//! Generate()\n//!\n\nclass Framebuffer : private NonCopyableMixin {\n    unsigned int _id = 0;\n    int          _width = 0;\n    int          _height = 0;\n    bool         _hasDepthBuffer = false;\n    Texture2D    _colorBuffer;\n    Texture2D    _depthBuffer;\n\npublic:\n    ~Framebuffer();\n\n    int         Generate();\n    bool        Initialized() const;\n    bool        IsComplete() const;\n    int         GetStatus() const;\n    const char *GetStatusString() const;\n    static const char *GetStatusString(int status);\n    void        Bind();\n    void        UnBind();\n    void        SetSize(int width, int height);\n    void        GetSize(int *width, int *height) const;\n    int         MakeRenderTarget();\n    void        EnableDepthBuffer();\n\n    const Texture2D *GetColorTexture() const;\n    const Texture2D *GetDepthTexture() const;\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/GLManager.h",
    "content": "#pragma once\n\n#include \"vapor/ShaderManager.h\"\n#include \"vapor/MatrixManager.h\"\n\nnamespace VAPoR {\n\nclass LegacyGL;\nclass FontManager;\n\n//! \\class GLManager\n//! \\ingroup Public_Render\n//!\n//! \\brief Contains references to context scope OpenGL data\n//!\n//! \\author Stanislaw Jaroszynski\n\nstruct RENDER_API GLManager {\n    ShaderManager *shaderManager;\n    FontManager *  fontManager;\n    MatrixManager *matrixManager;\n    LegacyGL *     legacy;\n\n    GLManager();\n    ~GLManager();\n\n    //! \\retval vector<int>[4] from glGetIntegerv(GL_VIEWPORT)\n    //!\n    static std::vector<int> GetViewport();\n    static glm::vec2        GetViewportSize();\n\n    //! Utility function that pushes the current matrix state and\n    //! sets up a pixel coorinate 2D orthographic projection\n    //!\n    void PixelCoordinateSystemPush();\n    void PixelCoordinateSystemPop();\n\n    enum class Vendor { Intel, Nvidia, AMD, Mesa, Other, Unknown };\n\n    static Vendor GetVendor();\n    static void   GetGLVersion(int *major, int *minor);\n    static int    GetGLSLVersion();\n    static bool   IsCurrentOpenGLVersionSupported();\n    static bool   CheckError();\n\n#ifndef NDEBUG\n    //! Draws the depth buffer in the top right corner\n    //!\n    void ShowDepthBuffer();\n#endif\n    static void * BeginTimer();\n    static double EndTimer(void *startTime);\n\nprivate:\n    static Vendor _cachedVendor;\n\n    void _queryVendor();\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/GUIStateParams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tGUIStateParams\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tAugust 2016\n//\n//\tDescription:\tMaintains various GUI state settings\n//\n#ifndef GUISTATEPARAMS_H\n#define GUISTATEPARAMS_H\n\n#include <vapor/ParamsBase.h>\n\nclass MouseModeParams;\nclass BookmarkParams;\n\nclass PARAMS_API GUIStateParams : public VAPoR::ParamsBase {\npublic:\n    GUIStateParams(VAPoR::ParamsBase::StateSave *ssave);\n\n    GUIStateParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node);\n\n    GUIStateParams(const GUIStateParams &rhs);\n\n    GUIStateParams &operator=(const GUIStateParams &rhs);\n\n    virtual ~GUIStateParams();\n\n    string GetActiveVizName() const;\n    void   SetActiveVizName(string vizWin);\n\n    //! Get active renderer class and instance name for a visualizer\n    //\n    void GetActiveRenderer(string vizWin, string &renderType, string &renderInst) const;\n    string GetActiveRendererInst() const;\n\n    //! Get active renderer class and instance name for a visualizer\n    //\n    void SetActiveRenderer(string vizWin, string renderType, string renderInst);\n\n    string GetActiveDataset() const ;\n    void SetActiveDataset(string name);\n\n    //! method identifies the current session file\n    //! \\retval session file path\n    string GetCurrentSessionFile() const;\n\n    //! method sets the current session file path\n    //! \\param[in] path string\n    void SetCurrentSessionFile(string path);\n\n    //! Get names of currently opened data sets\n    //!\n    std::vector<string> GetOpenDataSetNames() const { return (m_openDataSets->GetNames()); }\n\n    std::vector<string> GetOpenDataSetPaths(string dataSetName) const;\n    std::vector<string> GetOpenDataSetRelativePaths(string dataSetName) const;\n\n    string GetOpenDataSetFormat(string dataSetName) const;\n\n    void RemoveOpenDataSet(string dataSetName) { m_openDataSets->Remove(dataSetName); }\n\n    void InsertOpenDataSet(string dataSetName, string format, const std::vector<string> &paths, const std::vector<string> &relPaths={});\n\n    //! method sets the current session path\n    //! \\param[in] path string\n    void SetOpenDataSets(const std::vector<string> &paths, const std::vector<string> &names);\n\n    //! method identifies the current session file\n    //! \\retval session file path\n    string GetCurrentImagePath() const;\n\n    //! method sets the current session path\n    //! \\param[in] path string\n    void SetCurrentImagePath(string path);\n\n    //! method identifies the current session file\n    //! \\retval session file path\n    string GetCurrentImageSavePath() const;\n\n    //! method sets the current session path\n    //! \\param[in] path string\n    void SetCurrentImageSavePath(string path);\n\n    //! method identifies the current session file\n    //! \\retval session file path\n    string GetCurrentTFPath();\n\n    //! method sets the current session path\n    //! \\param[in] path string\n    void SetCurrentTFPath(string path);\n\n    //! method identifies the current session file\n    //! \\retval session file path\n    string GetCurrentPythonPath() const;\n\n    //! method sets the current session path\n    //! \\param[in] path string\n    void SetCurrentPythonPath(string path);\n\n    //! method identifies the current session file\n    //! \\retval session file path\n    string GetCurrentFlowPath() const;\n\n    //! method sets the current session path\n    //! \\param[in] path string\n    void SetCurrentFlowPath(string path);\n\n    MouseModeParams *GetMouseModeParams() const;\n\n    //! method sets and gets the active data set name in Statistics\n    //!\n    std::string GetStatsDatasetName() const;\n    void        SetStatsDatasetName(std::string &name);\n\n    //! method sets and gets the active data set name in Plot utility\n    //!\n    std::string GetPlotDatasetName() const;\n    void        SetPlotDatasetName(std::string &name);\n\n    string ActiveTab() const;\n    void   SetActiveTab(const string &t);\n\n    int  GetFlowDimensionality() const;\n    void SetFlowDimensionality(int nDims);\n\n    void SetProjectionString(string proj4String) { SetValueString(m_proj4StringTag, \"Set Proj4 projection string\", proj4String); }\n\n    string GetProjectionString() const\n    {\n        string defaultv;\n        return (GetValueString(m_proj4StringTag, defaultv));\n    }\n\n    class DataSetParam : public ParamsBase {\n    public:\n        DataSetParam(VAPoR::ParamsBase::StateSave *ssave) : ParamsBase(ssave, DataSetParam::GetClassType()) {}\n\n        DataSetParam(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node) : ParamsBase(ssave, node) {}\n\n        virtual ~DataSetParam(){};\n\n        void SetPaths(const std::vector<string> &paths) { SetValueStringVec(m_dataSetPathsTag, \"Data set paths\", paths); }\n\n        std::vector<string> GetPaths() const { return (GetValueStringVec(m_dataSetPathsTag)); };\n\n        void SetRelativePaths(const std::vector<string> &paths) { SetValueStringVec(m_dataSetRelativePathsTag, \"Data set relative paths\", paths); }\n        std::vector<string> GetRelativePaths() const { return (GetValueStringVec(m_dataSetRelativePathsTag)); };\n        bool HasRelativePaths() const { return !GetRelativePaths().empty(); };\n\n        void SetFormat(string format) { SetValueString(m_dataSetFormatTag, \"Data set format\", format); }\n\n        string GetFormat() const { return (GetValueString(m_dataSetFormatTag, \"vdc\")); }\n\n        static string GetClassType() { return (\"DataSetParam\"); }\n\n    private:\n        static const string m_dataSetPathsTag;\n        static const string m_dataSetRelativePathsTag;\n        static const string m_dataSetFormatTag;\n    };\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"GUIStateParams\"); }\n\n    void                     AddBookmark(BookmarkParams *bookmark);\n    BookmarkParams *         CreateBookmark();\n    void                     SetBookmarks(const vector<BookmarkParams *> &all);\n    void                     DeleteBookmark(int i);\n    void                     ClearBookmarks();\n    vector<BookmarkParams *> GetBookmarks() const;\n    int                      GetNumBookmarks() const;\n    BookmarkParams *         GetBookmark(int i) const;\n\nprivate:\n    class ActiveRenderer : public ParamsBase {\n    public:\n        ActiveRenderer(VAPoR::ParamsBase::StateSave *ssave) : ParamsBase(ssave, ActiveRenderer::GetClassType()) {}\n\n        ActiveRenderer(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node) : ParamsBase(ssave, node) {}\n\n        virtual ~ActiveRenderer(){};\n\n        void SetActiveRenderer(string vizWin, string renderType, string renderInst);\n\n        void GetActiveRenderer(string vizWin, string &renderType, string &renderInst) const;\n\n        static string GetClassType() { return (\"ActiveRenderer\"); }\n    };\n\n    ActiveRenderer *m_activeRenderer;\n\npublic:\n    static const string m_activeVisualizer;\n    static const string m_pathParamsTag;\n    static const string m_sessionFileTag;\n    static const string m_imagePathTag;\n    static const string m_imageSavePathTag;\n    static const string m_pythonPathTag;\n    static const string m_flowPathTag;\n    static const string m_tfPathTag;\n    static const string m_statsDatasetNameTag;\n    static const string m_plotDatasetNameTag;\n    static const string m_proj4StringTag;\n    static const string m_openDataSetsTag;\n    static const string _flowDimensionalityTag;\n    static const string BookmarksTag;\n    static const string MovingDomainTrackCameraTag;\n    static const string MovingDomainTrackRenderRegionsTag;\n    static const string ImportDataTypeTag;\n    static const string SessionNewTag;\n\nprivate:\n    MouseModeParams *m_mouseModeParams;\n\n    VAPoR::ParamsContainer *m_openDataSets;\n    VAPoR::ParamsContainer *_bookmarks;\n\n    void _init();\n};\n\n#endif    // GUISTATEPARAMS_H\n"
  },
  {
    "path": "include/vapor/GeoImage.h",
    "content": "\n#ifndef _GeoImage_h_\n#define _GeoImage_h_\n\n#ifdef WIN32\n    #include <geotiff/xtiffio.h>\n#else\n    #include <xtiffio.h>\n#endif\n\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\n\n//! \\class GeoImage\n//! \\brief An abstract class for managing geo-referenced images\n//! \\author John Clyne\n//!\n//\nclass RENDER_API GeoImage : public Wasp::MyBase {\npublic:\n    GeoImage();\n\n    //! \\param[in] pixelsize Size, in bits, of returned pixel channel\n    //! \\param[i] nbands Number of channel in a returned image\n    //\n    GeoImage(int pixelsize, int nbands);\n\n    virtual ~GeoImage();\n\n    //! Initialize the class\n    //!\n    //! \\param[in] path Path to file or directory containing image\n    //! database\n    //!\n    //! \\param[in] times Times coordinate variable. If image database contains\n    //! time-varying images the time stamps of the images will be compared\n    //! against \\p times and the best match will be returned\n    //!\n    //! \\retval status return -1 on failure\n    //\n    virtual int Initialize(string path, std::vector<double> times) = 0;\n\n    //! Fetch a non-georeferenced image\n    //!\n    //! Return an image without any geo-referencing information.\n    //!\n    //! \\param[in] ts time step of image\n    //! \\param[out] width Width in pixels of returned image\n    //! \\param[out] height Height in pixels of returned image\n    //!\n    //! \\retval image Upon success at 2D texture with n channels\n    //! (See GeoImage::GeoImage()) is returned.  Memory for the returned image\n    //! is managed by the class, and should not be freed.\n    //!\n    virtual unsigned char *GetImage(size_t ts, size_t &width, size_t &height) = 0;\n\n    //! Fetch a georeferenced image\n    //!\n    //! \\param[in] ts time step\n    //! \\param[in] pcsExtentsReq A four-element array containing the\n    //! extents (llx, lly, urx, ury) of the\n    //! requested region in Projected Coordinates.\n    //!\n    //! \\param[in] proj4StringReq The Proj4 string that maps lat-long coordinates\n    //! into the PCS coordinates used in \\p pcsExtentsReq.\n    //!\n    //! \\param[in] maxWidthReq The requested maximum width in pixels of the\n    //! returned image\n    //! \\param[in] maxHeightReq The requested maximum height in pixels of the\n    //! returned image\n    //!\n    //! \\param[out] pcsExtentsImg A four-element array containing the\n    //! extents (llx, lly, urx, ury) of the\n    //! returned image map in Projected Coordinates of the *image*.\n    //!\n    //! \\param[out] geoCornersImg An eight-element array containing the\n    //! corner points (llx, lly, ulx, uly, urx, ury, lrx, lry) of the\n    //! returned image map in Geographic coordinates\n    //!\n    //! \\param[out] width The actual width in pixels of the\n    //! returned image\n    //! \\param[out] height The actual  height in pixels of the\n    //! returned image\n    //!\n    //! \\retval image Upon success at 2D texture with n channels\n    //! (See GeoImage::GeoImage()) is returned.  Memory for the returned image\n    //! is managed by the class, and should not be freed.\n    //\n    virtual unsigned char *GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, double pcsExtentsImg[4], double geoCornersImg[8],\n                                    string &proj4StringImg, size_t &width, size_t &height) = 0;\n\nprotected:\n    int _pixelsize;\n    int _nbands;\n\n    // Support routines for reading tiff images\n    //\n    int  TiffOpen(string path);\n    void TiffClose();\n\n    int TiffGetImageDimensions(int dirnum, size_t &width, size_t &height) const;\n\n    int TiffReadImage(int dirnum, unsigned char *texture) const;\n\n    TIFF *TiffGetHandle() const { return (_tif); }\n\n    int CornerExtents(const double srccoords[4], double dstcoords[4], string proj4src) const;\n\nprivate:\n    TIFF * _tif;\n    string _path;\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/GeoImageGeoTiff.h",
    "content": "\n#ifndef _GeoImageGeoTiff_h_\n#define _GeoImageGeoTiff_h_\n\n#ifdef WIN32\n    #include <geotiff/xtiffio.h>\n    #include <geotiff/geotiff.h>\n#else\n    #include <xtiffio.h>\n    #include <geotiff.h>\n#endif\n#include <vapor/MyBase.h>\n#include <vapor/UDUnitsClass.h>\n#include \"GeoImage.h\"\n\nnamespace VAPoR {\n\n//! \\class GeoImageGeoTiff\n//! \\brief A class for managing GeoTiff images\n//! \\author John Clyne\n//!\n//\nclass RENDER_API GeoImageGeoTiff : public GeoImage {\npublic:\n    GeoImageGeoTiff();\n    virtual ~GeoImageGeoTiff();\n\n    int Initialize(string path, vector<double> times);\n\n    unsigned char *GetImage(size_t ts, size_t &width, size_t &height);\n\n    unsigned char *GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, double pcsExtentsImg[4], double geoCornersImg[8],\n                            string &proj4StringImg, size_t &width, size_t &height);\n\nprivate:\n    string              _proj4String;\n    std::vector<double> _tiffTimes;\n    std::vector<double> _times;\n    unsigned char *     _texture;        // storage for texture image\n    size_t              _textureSize;    // Texture size. No smart buffers :-(\n\n    string _getProjectionFromGTIF(GTIF *gtifHandle) const;\n\n    void _initTimeVector(TIFF *tif, const vector<double> &times);\n\n    bool _getTiffTime(TIFF *tif, UDUnits *udunits, double &tifftime) const;\n\n    int _getBestDirNum(size_t ts) const;\n\n    int _getGTIFInfo(TIFF *tif, size_t width, size_t height, double pcsExtents[4], double geoCorners[8], string &proj4String) const;\n\n    bool _extractSubtexture(unsigned char *texture, size_t width, size_t height, const double pcsExtentsReq[4], string proj4StringReq, const double pcsExtentsImg[4], const double geoCornersImg[8],\n                            string proj4StringImg, string &subProj4StringImg, size_t &subWidth, size_t &subHeight, double subPCSExtentsImg[4], double subGeoCornersImg[8]) const;\n};\n\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/GeoImageTMS.h",
    "content": "\n#ifndef _GeoImageTMS_h_\n#define _GeoImageTMS_h_\n\n#ifdef WIN32\n    #include <geotiff/xtiffio.h>\n    #include <geotiff/geotiff.h>\n#else\n    #include <xtiffio.h>\n    #include <geotiff.h>\n#endif\n#include <sstream>\n#include <fstream>\n#include <sys/stat.h>\n#include <vapor/MyBase.h>\n#include <vapor/UDUnitsClass.h>\n#include \"GeoTileMercator.h\"\n#include \"GeoImage.h\"\n\nnamespace VAPoR {\n\n//! \\class GeoImageTMS\n//! \\brief A class for managing OSGeo Tile Map Service Specification images\n//! \\author John Clyne\n//!\n//\nclass RENDER_API GeoImageTMS : public GeoImage {\npublic:\n    GeoImageTMS();\n    virtual ~GeoImageTMS();\n\n    int Initialize(string path, vector<double> times);\n\n    void SetLOD(int lod);\n\n    unsigned char *GetImage(size_t ts, size_t &width, size_t &height);\n\n    unsigned char *GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, double pcsExtentsImg[4], double geoCornersImg[8],\n                            string &proj4StringImg, size_t &width, size_t &height);\n\nprivate:\n    string _dir;           // path to TMS directory\n    int    _maxLOD;        // Maximum LOD available in TMS\n    int    _currentLOD;    // Current LOD in TMS\n\n    unsigned char *_texture;    // storage for texture image\n    size_t         _textureSize;\n\n    unsigned char *_tileBuf;    // storage for a single tile\n    size_t         _tileBufSize;\n\n    GeoTileMercator *_geotile;\n\n    string _defaultProj4String;    // proj4 string for global mercator\n\n    int _tileSize(string dir, size_t tileX, size_t tileY, int lod, size_t &w, size_t &h);\n\n    int _tileRead(string dir, size_t tileX, size_t tileY, int lod, unsigned char *tile);\n\n    int _getBestLOD(const double myGeoExtentsData[4], int maxWidthReq, int maxHeightReq) const;\n\n    int _getMap(const size_t pixelSW[2], const size_t pixelNE[2], int lod, unsigned char *texture);\n};\n\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/GeoTIFWriter.h",
    "content": "#pragma once\n\n#include \"vapor/TIFWriter.h\"\n#ifdef WIN32\n    #include <geotiff/geotiffio.h>\n#else\n    #include <geotiffio.h>\n#endif\n\nnamespace VAPoR {\n\n//! \\class GeoTIFWriter\n//! \\ingroup Public_Render\n//! \\brief Writes a TIF image with GeoTIF metadata\n//! \\author Stanislaw Jaroszynski\n//!\nclass RENDER_API GeoTIFWriter : public TIFWriter {\n    GTIF *gtif;\n    bool  _hasTiePoint;\n    bool  _hasPixelScale;\n    bool  _geoTiffWasConfigured;\n\npublic:\n    GeoTIFWriter(const std::string &path);\n    ~GeoTIFWriter();\n\n    int  Write(const unsigned char *buffer, const unsigned int width, const unsigned int height);\n    int  ConfigureFromProj4(const std::string proj4String);\n    void SetTiePoint(double worldX, double worldY, double rasterX = 0, double rasterY = 0);\n    void SetPixelScale(double x, double y);\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/GeoTile.h",
    "content": "#ifndef GeoTile_h_\n#define GeoTile_h_\n\n#include <string>\n#include <map>\n#ifdef _WINDOWS\n    #pragma warning(disable : 4251)\n#endif\n//\n//! \\class GeoTile\n//!\n//! \\brief An abstract class for managing geo-referenced world maps,\n//! decomposed into tiles, and supporting level-of-detail refinement.\n//!\n//! This representation is based on Microsoft's Virtual Earth Tile System\n//! (Bing Maps), described here\n//! \\sa http://msdn.microsoft.com/en-us/library/bb259689\n//!\n//! The image tiles are also compatible with the tiling system used by\n//! Google Maps and the open source Tile Map Service, differing only\n//! in how the tiles are indexed. Microsoft (and this class) use\n//! \"quadkeys\", whereas, Google and TMS employ different indexing/naming\n//! conventions for tiles. The encoding of quadkeys in this implementation\n//! differs from Microsoft's in one respect: a quadkey == \"\" (empty string)\n//! is a valid key, coresponding to level-of-detail zero, a single tile\n//! covering the entire globe. I.e. the coarsest lod permitted by Microsoft is\n//! level one, and coresponds to a four-tile decomposition of the global\n//! map projection. A single tile, level-zero, map is permitted by this class.\n//!\n//! The above world map tiling systems all employ a Mercator projection.\n//! No projection is specified by this base class. The projection type\n//! is left to derived classes.\n//!\n//! \\note Much of this code is based on the sample representation provided\n//! by Microsoft.\n//!\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//!\n#include <vapor/common.h>\n#ifdef WINDOWS\n    #pragma warning(disable : 4251)\n#endif\nnamespace VAPoR {\nclass RENDER_API GeoTile {\npublic:\n    //! Create a GeoTile object\n    //!\n    //! \\param[in] tile_width The width of a tile in pixels\n    //! \\param[in] tile_height The height of a tile in pixels\n    //! \\param[in] pixelsize The size of a pixel in bytes\n    //! \\param[in] min_lon The minimum valid longitude for the map projection\n    //! \\param[in] min_lat The minimum valid lattitude for the map projection\n    //! \\param[in] max_lon The maximum valid longitude for the map projection\n    //! \\param[in] max_lat The maximum valid lattitude for the map projection\n    //!\n    GeoTile(size_t tile_width, size_t tile_height, size_t pixelsize, double min_lon, double min_lat, double max_lon, double max_lat);\n    virtual ~GeoTile();\n\n    //! Insert an image tile into the class object\n    //!\n    //! This method is used to add geo-referenced image tiles to the class.\n    //!\n    //! \\param[in] quadkey A string encoding the location (index) and level\n    //! of detail of \\p image\n    //! \\param[in] image A pointer to the image tile to be copied into\n    //! the object class. The size of the image tile must be \\p tile_width *\n    //! \\p tile_height * \\p pixelsize\n    //!\n    //! \\sa GeoTile()\n    //\n    int Insert(std::string quadkey, const unsigned char *image);\n\n    //! Converts a point from latitude/longitude WGS-84 coordinates (in degrees)\n    //! into pixel XY coordinates at a specified level of detail.\n    //!\n    //! \\param[in] lon Longitude of the point, in degrees.\n    //! \\param[in] lat Latitude of the point, in degrees.\n    //! \\param[in] lod Level of detail, from 0 (lowest detail)\n    //! to 23 (highest detail).\n    //! \\param[out] pixelX Output parameter receiving the X coordinate in pixels.\n    //! \\param[out] pixelY Output parameter receiving the Y coordinate in pixels.\n    //!\n    //! \\sa PixelXYToLatLong()\n    //\n    virtual void LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const = 0;\n\n    //! Converts a pixel from pixel XY coordinates at a specified level of detail\n    //! into latitude/longitude WGS-84 coordinates (in degrees).\n    //!\n    //! \\param [in] pixelX X coordinate of the point, in pixels.\n    //! \\param [in] pixelY Y coordinates of the point, in pixels.\n    //! \\param [in] lod Level of detail, from 0 (lowest detail)\n    //! to 23 (highest detail).\n    //! \\param [out] lat Output parameter receiving the latitude in degrees.\n    //! \\param [out] lon Output parameter receiving the longitude in degrees\n    //!\n    //! \\sa LatLongToPixelXY()\n    //!\n    virtual void PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const = 0;\n\n    //! Converts pixel XY coordinates into tile XY coordinates of the tile\n    //! containing the specified pixel.\n    //!\n    //! Given a map coordinate in pixels, this method returns the index of\n    //! of the tile containing the pixel, as well as the pixel's location\n    //! within the tile coordinate system.\n    //!\n    //! \\param [in] pixelX Pixel X coordinate.\n    //! \\param [in] pixelY Pixel Y coordinate.\n    //! \\param [in] tileX Output parameter receiving the tile's X coordinate.\n    //! \\param [in] tileY Output parameter receiving the tile's Y coordinate.\n    //! \\param [in] tilePixelX Output parameter receiving the pixel's X\n    //! in the tile's local coordinate system.\n    //! \\param [in] tilePixelY Output parameter receiving the pixel's Y\n    //! in the tile's local coordinate system.\n    //!\n    void PixelXYToTileXY(size_t pixelX, size_t pixelY, size_t &tileX, size_t &tileY, size_t &tilePixelX, size_t &tilePixelY) const;\n\n    //! Converts tile XY coordinates into pixel XY coordinates of the\n    //! upper-left pixel of the specified tile.\n    //!\n    //! \\param [in] tileX Tile X coordinate.\n    //! \\param [in] tileY Tile Y coordinate.\n    //! \\param [out] pixelX Output parameter receiving the pixel X coordinate.\n    //! \\param [out] pixelY Output parameter receiving the pixel Y coordinate.\n    //!\n    void TileXYToPixelXY(size_t tileX, size_t tileY, size_t &pixelX, size_t &pixelY) const;\n\n    //! Return a pointer to the image tile associated with a quadkey\n    //!\n    //! This method returns a pointer to the image tile associated with\n    //! the Quad Key \\p quadkey. If no image tile has been added to the\n    //! class for \\p quadkey, a null pointer is returned.\n    //!\n    //! \\param[in] quadkey A Quad Key\n    //! \\retval tile If the tile associated with \\p quadkey exists, a pointer\n    //! to it is returned. If the tile does not exist (or if \\p quadkey is\n    //! not a valid key), the NULL pointer is returned\n    //!\n    //! \\sa Insert()\n    //\n    const unsigned char *GetTile(std::string quadkey) const;\n\n    //! Return a pointer to an image tile\n    //!\n    //! This method returns a pointer to the image tile associated with\n    //! a tile index and level of detail.\n    //! If no image tile has been added to the\n    //! class for combination of tile index and lod, a null pointer is returned.\n    //!\n    //! \\param[in] tileX X coordinate of tile\n    //! \\param[in] tileY X coordinate of tile\n    //! \\param[in] lod level of detail of tile\n    //! \\retval tile If the tile associated with \\p tileX, \\p tileY, and\n    //! \\p lod, a pointer\n    //! to it is returned. If the tile does not exist (or if \\p quadkey is\n    //! not a valid key), the NULL pointer is returned\n    //!\n    //! \\sa Insert()\n    //\n    const unsigned char *GetTile(size_t tileX, size_t tileY, int lod) const\n    {\n        std::string quadkey = TileXYToQuadKey(tileX, tileY, lod);\n        return (GetTile(quadkey));\n    }\n\n    //! This method contructs a continuous (non-tiled) map from the\n    //! tiles contained within the class.\n    //!\n    //! Given a rectangular boundary described to two points (the north-west and\n    //! south-east corner) in pixel coordinates, and a level of detail, this\n    //! method constructs and returns a continuous map.\n    //!\n    //! \\param[in] pixelX0 X coordinate of north-west corner in pixel coordinates\n    //! \\param[in] pixelY0 Y coordinate of north-west corner in pixel coordinates\n    //! \\param[in] pixelX0 X coordinate of south-east corner in pixel coordinates\n    //! \\param[in] pixelY0 Y coordinate of south-east corner in pixel coordinates\n    //! \\param[in] lod Level of detail\n    //! \\param[out] map_image The constructed map is copied to the location\n    //! pointed to by \\p map_image. The memory referenced by \\p map_image\n    //! must of sufficient size to accommodate the map.\n    //!\n    //! \\retval status A zero is returned on success. If the coordinates\n    //! are invalid, or if all of the tiles needed are not present, a negative\n    //! value is returned.\n    //!\n    //! \\sa MapSize(), Insert(), LatLongToPixelXY().\n    //\n    int GetMap(size_t pixelX0, size_t pixelY0, size_t pixelX1, size_t pixelY1, int lod, unsigned char *map_image) const;\n\n    //! Converts tile XY coordinates into a QuadKey at a specified level of detail.\n    //!\n    //! \\param[in] tileX Tile X coordinate.\n    //! \\param[in] tileY Tile Y coordinate.\n    //! \\param[in] lod Level of detail, from 0 (lowest detail)\n    //! to 23 (highest detail).\n    //!\n    //! \\retval quadkey A string containing the QuadKey.\n    //\n    static std::string TileXYToQuadKey(size_t tileX, size_t tileY, int lod);\n\n    //! Converts a QuadKey into tile XY coordinates.\n    //!\n    //! \\param[in] quadKey QuadKey of the tile.\n    //! \\param[out] tileX Output parameter receiving the tile X coordinate.\n    //! \\param[out] tileY Output parameter receiving the tile Y coordinate.\n    //! \\param[out] lod Output parameter receiving the level of detail.\n    //!\n    //! \\retval status A zero is returned on success, otherwise a negative\n    //! value is returned if the supplied inputs are invalid\n    //!\n    static int QuadKeyToTileXY(std::string quadKey, size_t &tileX, size_t &tileY, int &lod);\n\n    //! Compute the size of the global map in pixels at a specified lod\n    //!\n    //! This method calculates the width and height, in pixels, of the global\n    //! map at a specified level of detail\n    //!\n    //! \\param[in] lod The level of detail\n    //! \\param[out] nx Width of the map in pixels\n    //! \\param[out] ny Height of the map in pixels\n    //\n    void MapSize(int lod, size_t &nx, size_t &ny) const;\n\n    //! Compute the size of a map in pixels at a specified lod and coordinates\n    //!\n    //! Given a rectangular boundary described by two points (the north-west and\n    //! south-east corner) in pixel coordinates, and a level of detail, this\n    //! method computes the size of the map (width and height) in pixels.\n    //!\n    //! \\param[in] pixelX0 X coordinate of north-west corner in pixel coordinates\n    //! \\param[in] pixelY0 Y coordinate of north-west corner in pixel coordinates\n    //! \\param[in] pixelX0 X coordinate of south-east corner in pixel coordinates\n    //! \\param[in] pixelY0 Y coordinate of south-east corner in pixel coordinates\n    //! \\param[in] lod The level of detail\n    //! \\param[out] nx Width of the map in pixels\n    //! \\param[out] ny Height of the map in pixels\n    //\n    int MapSize(size_t pixelX0, size_t pixelY0, size_t pixelX1, size_t pixelY1, int lod, size_t &nx, size_t &ny) const;\n\n    void GetLatLonExtents(double &minlon, double &minlat, double &maxlon, double &maxlat) const\n    {\n        minlon = _MinLongitude;\n        minlat = _MinLatitude;\n        maxlon = _MaxLongitude;\n        maxlat = _MaxLatitude;\n    }\n\n    void GetTileSize(size_t &w, size_t &h) const\n    {\n        w = _tile_width;\n        h = _tile_height;\n    }\n\n    //! Map a rectanular region described by lat-lon coordinates to pixel coordinates\n    //!\n    //!\n    //! \\param[in] geoSW A two-element array containing the longitude, and latitude coordinate, respectively,\n    //! of the south-west corner of the region\n    //! \\param[in] geoNE A two-element array containing the longitude, and latitude coordinate, respectively,\n    //! of the north-east corner of the region\n    //! \\param[in] lod The level of detail\n    //! \\param[out] pixelSW Returns a two-element array containing the X, and Y pixel coordinates, respectively,\n    //! of the south-west corner of the region\n    //! \\param[out] pixelNE Returns a two-element array containing the X, and Y pixel coordinates, respectively,\n    //! of the north-east corner of the region\n    //\n    void LatLongRectToPixelRect(const double geoSW[2], const double geoNE[2], int lod, size_t pixelSW[2], size_t pixelNE[2]) const;\n\nprivate:\n    size_t                                 _pixel_size;\n    std::map<std::string, unsigned char *> _tiles;\n\n    void _CopyTileToMap(const unsigned char *tile, size_t tilePixelX0, size_t tilePixelY0, size_t tilePixelX1, size_t tilePixelY1, unsigned char *map, size_t pixelX0, size_t pixelX1, size_t nx,\n                        size_t ny) const;\n\nprotected:\n    size_t _tile_width;\n    size_t _tile_height;\n\n    double _MinLatitude;\n    double _MaxLatitude;\n    double _MinLongitude;\n    double _MaxLongitude;\n\n    double _Clip(double n, double minValue, double maxValue) const;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/GeoTileEquirectangular.h",
    "content": "#ifndef GeoTileEquirectangular_h_\n#define GeoTileEquirectangular_h_\n#ifdef _WINDOWS\n    #pragma warning(disable : 4251)\n#endif\n#include \"GeoTile.h\"\n#include <vapor/common.h>\nnamespace VAPoR {\n//! \\class GeoTileEquirectangular\n//!\n//! This class derives the GetTile base class to provide a tiled world\n//! mapping system using the Equirectangular projection.\n//!\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n\nclass RENDER_API GeoTileEquirectangular : public GeoTile {\npublic:\n    //! GeoTileEquirectangular class constructor\n    //!\n    //! \\param[in] tile_height Height of an image tile in pixels. The tile\n    //! width must be twice the tile height\n    //! \\param[in] pixelsize The size of a pixel in bytes\n    //!\n    //!\n    GeoTileEquirectangular(size_t tile_width, size_t tile_height, size_t pixelsize) : GeoTile(tile_width, tile_height, pixelsize, -180.0, -90.0, 180.0, 90.0) {}\n\n    //! copydoc GeoTile::LatLongToPixelXY()\n    //\n    virtual void LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const;\n\n    //! copydoc GeoTile::PixelXYToLatLon()\n    //\n    virtual void PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/GeoTileMercator.h",
    "content": "#ifndef GeoTileMercator_h_\n#define GeoTileMercator_h_\n#ifdef _WINDOWS\n    #pragma warning(disable : 4251)\n#endif\n#include \"GeoTile.h\"\n#include <vapor/common.h>\n//! \\class GeoTileMercator\n//!\n//! This class derives the GetTile base class to provide a tiled world\n//! mapping system using the Web \"Pseudo-Mercator\" projection.\n//!\n//! The following GDAL commands wered used to transform the NASA blue\n//! marble image into a suitable Mercator\n//!\n//! gdal_translate -of GTiff -a_srs EPSG:4326 -gcp 0 0 -180 90\n//! -gcp 4096 0 180 90 -gcp 4096 2048 180 -90 BBM.4096.png bluemarble1.tif\n//!\n//! gdalwarp -t_srs EPSG:4326 bluemarble1 bluemarble2.tif\n//!\n//! gdalwarp -s_srs EPSG:4326 -t_srs EPSG:3857 -r bilinear\n//! -ts 4096 4096 -te -20037508.34 -20037508.34 20037508.34 20037508.34\n//! bluemarble1.tif bluemarble3.tif\n//!\n//! \\sa https://www.mapbox.com/tilemill/docs/guides/reprojecting-geotiff/\n//!\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n\nnamespace VAPoR {\nclass RENDER_API GeoTileMercator : public GeoTile {\npublic:\n    //! GeoTileMercator class constructor\n    //!\n    //! \\param[in] tile_height Height of an image tile in pixels. The tile\n    //! width must the same as the tile height\n    //! \\param[in] pixelsize The size of a pixel in bytes\n    //!\n    //!\n    GeoTileMercator(size_t tile_width, size_t tile_height, size_t pixelsize) : GeoTile(tile_width, tile_height, pixelsize, -180.0, -85.05112878, 180.0, 85.05112878) {}\n\n    GeoTileMercator(size_t tile_width, size_t tile_height, size_t pixelsize, double min_lon, double min_lat, double max_lon, double max_lat)\n    : GeoTile(tile_width, tile_height, pixelsize, min_lon, min_lat, max_lon, max_lat)\n    {\n    }\n\n    //! copydoc GeoTile::LatLongToPixelXY()\n    //\n    virtual void LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const;\n\n    //! copydoc GeoTile::PixelXYToLatLon()\n    //\n    virtual void PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/GeoUtil.h",
    "content": "\n//      $Id$\n//\n\n#ifndef _GeoUtil_h_\n#define _GeoUtil_h_\n\n#include <vector>\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\n\n//\n//! \\class GeoUtil\n//! \\brief Misc. utilities for operating on geographic coordinates\n//!\n//!\n//! \\author John Clyne\n//!\nclass VDF_API GeoUtil : public Wasp::MyBase {\npublic:\n    //! Shift a container of longitude values so that all\n    //! values are in the range [-bound .. bound]\n    //\n    static void ShiftLon(vector<float>::iterator first, vector<float>::iterator last, double bound = 360.0);\n    static void ShiftLon(vector<double>::iterator first, vector<double>::iterator last, double bound = 360.0);\n    static void ShiftLon(float *first, float *last, double bound = 360.0);\n\n    //! Unwrap any wrapped longitued values\n    //!\n    //! Iteratively adds 360.0 to each value in a container that is less than\n    //! the first value until the new value is greater than the first.\n    //\n    static void UnwrapLongitude(vector<float>::iterator first, vector<float>::iterator last);\n    static void UnwrapLongitude(vector<double>::iterator first, vector<double>::iterator last);\n    static void UnwrapLongitude(float *first, float *last);\n\n    //! Extract boundary points from a 2D grid\n    //!\n    //! This method walks a 2D array, \\p a, in counter-clockwise order, visiting\n    //! each boundary grid point exactly once, copying the value\n    //! to the array \\p bdry. A total of 2*nx + 2*ny - 4 grid points are\n    //! copied.\n    //!\n    //! \\param[in] a An 2D array dimensioned \\p nx by \\p ny\n    //! \\param[in] nx\tdimension of fastest moving coordinate\n    //! \\param[in] ny\tdimension of slowest moving coordinate\n    //! \\param[output] bdry Output array containing the boundary values\n    //! of \\p a. The number of elements copied to \\p bdry is\n    //! 2 * \\p nx + 2 * \\p ny - 4.\n    //\n    static void ExtractBoundary(const float *a, int nx, int ny, float *bdry);\n    static void ExtractBoundary(const double *a, int nx, int ny, double *bdry);\n\nprivate:\n};\n};    // namespace VAPoR\n\n#endif    //\t_GeoUtil_h_\n"
  },
  {
    "path": "include/vapor/GetAppPath.h",
    "content": "//\n// $Id$\n//\n\n#ifndef INCLUDE_DEPRECATED_GET_APP_PATH\n    #error GetAppPath.h is deprecated. Please use ResourcePath.h\n#endif\n\n#ifndef _GetAppPath_h_\n    #define _GetAppPath_h_\n    #include <vapor/MyBase.h>\n\nnamespace Wasp {\n\nCOMMON_API std::string GetAppPath(const string &app, const string &name, const vector<string> &paths,\n    #ifdef _WINDOWS\n                                  // Windows default is backwards slash for separator\n                                  bool forwardSeparator = false\n    #else\n                                  bool forwardSeparator = true\n    #endif\n);\n\n};    // namespace Wasp\n\n#endif\n"
  },
  {
    "path": "include/vapor/Grid.h",
    "content": "#ifndef _Grid_\n#define _Grid_\n\n#include <algorithm>\n#include <iostream>\n#include <ostream>\n#include <vector>\n#include <cassert>\n#include <array>\n#include <string>\n#include <limits>\n#include \"vapor/VAssert.h\"\n#include <memory>\n#include <vapor/common.h>\n\n#ifdef WIN32\n    #pragma warning(disable : 4661 4251)    // needed for template class\n#endif\n\nnamespace VAPoR {\n\n//! Type for specifying floating point coordinates\nusing CoordType = std::array<double, 3>;\n\n//! Type for specifying integer indices\nusing DimsType = std::array<size_t, 3>;\n\n//! \\class Grid\n//! \\brief Abstract base class for a 2D or 3D structured or unstructured\n//!  grid.\n//! \\author John Clyne\n//!\n//! This abstract base class defines a 2D or 3D structured or unstructured\n//! grid.\n//!\n//! The grid samples a scalar function at each grid point.  Each\n//! grid point can be addressed by a 3-element array defined as\n//! type \\p DimsType.\n//! The fastest varying dimension is\n//! given by indices[0], etc.\n//!\n//! Because grid samples are repesented internally as arrays, when accessing\n//! multiple grid points better performance is achieved by using\n//! unit stride.\n//!\n//! \\param indices A \\b DimsType i in the range 0..max,\n//! where max is one minus the value of the corresponding element\n//! returned by GetDimensions().\n//!\n//! \\param coords A \\b CoordType\n//! containig the coordinates of a point in user-defined\n//! coordinates. Elements with indices greater than GetGeometryDim()-1 are\n//! ignored.\n//!\n//\nclass VDF_API Grid {\npublic:\n    //!\n    //! Construct a structured or unstructured grid sampling a 3D or\n    //! 2D scalar function\n    //!\n    //! \\param[in] dims Dimensions of arrays containing grid data.\n    //!\n    //! \\param[in] bs A \\b DimsType with, specifying the\n    //! dimensions of\n    //! each block storing the sampled scalar function.\n    //!\n    //! \\param[in] blks An array of blocks containing the sampled function.\n    //! The dimensions of each block\n    //! is given by \\p bs. The number of blocks is given by the product\n    //! of the terms:\n    //!\n    //! \\code (((dims[i]-1) / bs[i]) + 1) \\endcode\n    //!\n    //! over i = 0..dims.size()-1\n    //!\n    //! A shallow copy of the blocks is made by the constructor. Memory\n    //! referenced by the elements of \\p blks should remain valid\n    //! until the class instance is destroyed.\n    //!\n    //! \\param[in] topology_dimension Topological dimension of\n    //! grid: 1, 2 or 3, for 1D, 2D or 3D, respectively. Grids with 2D\n    //! topology are composed of 2D polygons, while\n    //! grids with 3D topology are composed of 3D polyhedron\n    //!\n    Grid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<float *> &blks, size_t topology_dimension);\n    Grid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, size_t topology_dimension);\n\n    Grid();\n    virtual ~Grid() = default;\n\n    //! Return the dimensions of grid connectivity array\n    //!\n    //! \\param[out] dims The value of \\p dims parameter provided to\n    //! the constructor. If the parameter has less than 3 values, then\n    //! number 1 will be filled.\n    //!\n    //! \\sa GetGeometryDim(), GetTopologyDim()\n    //!\n    const DimsType &GetDimensions() const { return _dims; }\n\n    //! Return the useful number of dimensions of grid connectivity array\n    //!\n    //! \\param[out] dims The number of non-unit components of \\p dims parameter provided to\n    //! the constructor.\n    //!\n    size_t GetNumDimensions() const { return GetNumDimensions(_dims); }\n\n    //! Return the number of non-unit dimensions\n    //!\n    //! Return the number of non-unit dimensions in \\p dims\n    //!\n    //! \\param[in] dims\n    //!\n    static size_t GetNumDimensions(DimsType dims);\n\n    //! Return the dimensions of the specified coordinate variable\n    //!\n    //! \\param[in] dim An integer between 0 and the return value\n    //! of GetGeometryDim() - 1, indicating which\n    //! coordinate dimensions are to be returned.\n    //!\n    //! if \\p dim is greater than or equal to GetGeometryDim() - 1\n    //! a vector of length one with its single component equal to\n    //! one is returned.\n    //!\n    virtual DimsType GetCoordDimensions(size_t dim) const = 0;\n\n    virtual std::string GetType() const = 0;\n\n    //! Get geometric dimension of cells\n    //!\n    //! Returns the geometric dimension of the cells in the mesh. I.e.\n    //! the number of spatial coordinates for each grid point.\n    //! Valid values are 0..3. The geometric dimension must be equal to\n    //! or greater than the topology dimension.\n    //!\n    //! \\sa GetTopologyDim()\n    //\n    virtual size_t GetGeometryDim() const = 0;\n\n    virtual const DimsType &GetNodeDimensions() const = 0;\n    virtual const size_t    GetNumNodeDimensions() const = 0;\n    virtual const DimsType &GetCellDimensions() const = 0;\n    virtual const size_t    GetNumCellDimensions() const = 0;\n\n    //! Return the ijk dimensions of grid in blocks\n    //!\n    //! Returns the number of blocks defined along each axis of the grid\n    //!\n    //! \\param[out] dims A two or three element array containing the grid\n    //! dimension in blocks\n    //!\n    //! \\sa GetBlockSize();\n    //\n    const std::vector<size_t> GetDimensionInBlks() const { return (_bdimsDeprecated); }\n\n    //! Return the internal blocking factor\n    //!\n    //! This method returns the internal blocking factor passed\n    //! to the constructor.\n    //\n    const std::vector<size_t> &GetBlockSize() const { return (_bsDeprecated); }\n\n    //! Return the internal data structure containing a copy of the blocks\n    //! passed in by the constructor\n    //!\n    const std::vector<float *> &GetBlks() const { return (_blks); };\n\n    //! Get the data value at the indicated grid point\n    //!\n    //! This method provides read access to the scalar data value\n    //! defined at the grid point indicated by \\p indices. The range\n    //! of valid indices is between zero and \\a dim - 1, where \\a dim\n    //! is the dimesion of the grid returned by GetDimensions()\n    //!\n    //! If any of the \\p indecies are outside of the\n    //! valid range the results are undefined\n    //!\n    //! \\param[in] indices of grid point along fastest varying dimension.\n    //!\n    virtual float GetValueAtIndex(const DimsType &indices) const;\n\n    //! \\deprecated\n    //\n    virtual float GetValueAtIndex(const std::vector<size_t> &indices) const\n    {\n        DimsType a = {0, 0, 0};\n        CopyToArr3(indices, a);\n        return (GetValueAtIndex(a));\n    }\n\n    //! Set the data value at the indicated grid point\n    //!\n    //! This method sets the data value of the grid point indexed by\n    //! \\p indices to \\p value.\n    //!\n    virtual void SetValue(const DimsType &indices, float value);\n\n    //! \\deprecated\n    //\n    virtual void SetValue(const size_t indices[3], float value)\n    {\n        DimsType i3 = {0, 0, 0};\n        CopyToArr3(indices, GetNodeDimensions().size(), i3);\n        SetValue(i3, value);\n    }\n\n    //! This method provides an alternate interface to Grid::GetValueAtIndex()\n    //! If the dimensionality of the grid as determined by GetDimensions() is\n    //! less than three subsequent parameters are ignored. Parameters\n    //! that are outside of range are clamped to boundaries.\n    //!\n    //! \\param[in] i Index into first fastest varying dimension\n    //! \\param[in] j Index into second fastest varying dimension\n    //! \\param[in] k Index into third fastest varying dimension\n    //\n    virtual float AccessIJK(size_t i, size_t j = 0, size_t k = 0) const;\n\n    void SetValueIJK(size_t i, size_t j, size_t k, float v);\n    void SetValueIJK(size_t i, size_t j, float v) { SetValueIJK(i, j, 0, v); }\n    void SetValueIJK(size_t i, float v) { SetValueIJK(i, 0, 0, v); }\n\n    //! Get the reconstructed value of the sampled scalar function\n    //!\n    //! This method reconstructs the scalar field at an arbitrary point\n    //! in space. If the point's coordinates are outside of the grid's\n    //! coordinate extents as returned by GetUserExtents(), and the grid\n    //! is not periodic along the out-of-bounds axis, the value\n    //! returned will be the \\a missing_value.\n    //!\n    //! If the value of any of the grid point samples used in the reconstruction\n    //! is the \\a missing_value then the result returned is the \\a missing_value.\n    //!\n    //! The reconstruction method used is determined by interpolation\n    //! order returned by GetInterpolationOrder()\n    //!\n    //! \\param[in] coords A vector of size matching the topology dimension\n    //! of the mesh whose contents specify the coordinates of a point in space.\n    //!\n    //! \\sa GetInterpolationOrder(), HasPeriodic(), GetMissingValue()\n    //! \\sa GetUserExtents()\n    //!\n    virtual float GetValue(const CoordType &coords) const;\n\n    //! \\deprecated\n    //\n    virtual float GetValue(const std::vector<double> &coords) const\n    {\n        CoordType c3 = {0.0, 0.0, 0.0};\n        CopyToArr3(coords, c3);\n        return (GetValue(c3));\n    };\n\n    //! \\deprecated\n    //\n    virtual float GetValue(const double coords[]) const\n    {\n        CoordType c3 = {0.0, 0.0, 0.0};\n        CopyToArr3(coords, GetGeometryDim(), c3);\n        return (GetValue(c3));\n    }\n\n    virtual float GetValue(double x, double y) const\n    {\n        double coords[] = {x, y, 0.0};\n        return (GetValue(coords));\n    }\n    virtual float GetValue(double x, double y, double z) const\n    {\n        double coords[] = {x, y, z};\n        return (GetValue(coords));\n    }\n\n    //! Return the extents of the user coordinate system\n    //!\n    //! This pure virtual method returns min and max extents of\n    //! the user coordinate\n    //! system defined on the grid. The extents of the returned box\n    //! are guaranteed to contain all points in the grid.\n    //!\n    //! \\param[out] minu A two or three element array containing the minimum\n    //! user coordinates.\n    //! \\param[out] maxu A two or three element array containing the maximum\n    //! user coordinates.\n    //!\n    //! \\sa GetDimensions(), Grid()\n    //!\n    virtual void GetUserExtents(CoordType &minu, CoordType &maxu) const;\n\n    //! \\deprecated\n    //\n    virtual void GetUserExtents(double minu[3], double maxu[3]) const\n    {\n        CoordType minu3 = {0.0, 0.0, 0.0};\n        CoordType maxu3 = {0.0, 0.0, 0.0};\n        GetUserExtents(minu3, maxu3);\n        CopyFromArr3(minu3, minu);\n        CopyFromArr3(maxu3, maxu);\n    }\n\n    //! \\deprecated\n    //\n    virtual void GetUserExtents(std::vector<double> &minu, std::vector<double> &maxu) const\n    {\n        CoordType minu3 = {0.0, 0.0, 0.0};\n        CoordType maxu3 = {0.0, 0.0, 0.0};\n        GetUserExtents(minu3, maxu3);\n        CopyFromArr3(minu3, minu);\n        CopyFromArr3(maxu3, maxu);\n\n        // Much of the use of this method assumes that the size of the minu,maxu\n        // vectors can be used to determine the number of coordinates. So we\n        // maintain this property for now.\n        //\n        minu.resize(GetGeometryDim());\n        maxu.resize(GetGeometryDim());\n    }\n\n    //! Return the extents of the axis-aligned bounding box enclosign a region\n    //!\n    //! This pure virtual method returns min and max extents, in user coordinates,\n    //! of the smallest axis-aligned box enclosing the region defined\n    //! by the grid indices, \\p min and \\p max. Every grid point in\n    //! the range \\p min to \\p max will be contained in, or reside on, the\n    //! box (rectangle) whose extents are given by \\p minu and \\p maxu.\n    //!\n    //! \\note The results are undefined if any index of \\p min is\n    //! greater than the coresponding coordinate of \\p max, or if \\p max\n    //! is outside of the valid dimension range (See GetDimension()).\n    //!\n    //! The size of \\p min and \\p max must match the grid's dimension\n    //! as returned by GetDimension()\n    //!\n    //! \\param[in] min An array containing the minimum\n    //! grid indices (offsets).\n    //! \\param[in] max An array containing the maximum\n    //! grid indices (offsets).\n    //! \\param[out] minu A two-to-three element array containing the minimum\n    //! user coordinates.\n    //! \\param[out] maxu A two-to-three element array containing the maximum\n    //! user coordinates.\n    //!\n    //! \\sa GetDimensions(), Grid()\n    //!\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const = 0;\n\n    virtual void GetBoundingBox(const std::vector<size_t> &min, const std::vector<size_t> &max, std::vector<double> &minu, std::vector<double> &maxu) const\n    {\n        VAssert(min.size() == max.size());\n        DimsType  min3 = {0, 0, 0};\n        DimsType  max3 = {0, 0, 0};\n        CoordType minu3 = {0.0, 0.0, 0.0};\n        CoordType maxu3 = {0.0, 0.0, 0.0};\n\n        CopyToArr3(min, min3);\n        CopyToArr3(max, max3);\n        GetBoundingBox(min3, max3, minu3, maxu3);\n        CopyFromArr3(minu3, minu);\n        CopyFromArr3(maxu3, maxu);\n    }\n\n    //!\n    //! Get bounding indices of grid containing a region\n    //!\n    //! Calculates the starting and ending grid indices of the\n    //! smallest grid\n    //! completely containing the rectangular region defined by the user\n    //! coordinates \\p minu and \\p maxu\n    //! If rectangluar region defined by \\p minu and \\p maxu can\n    //! not be contained the\n    //! minimum and maximum indices are returned in\n    //! \\p min and \\p max, respectively\n    //!\n    //! \\param[in] minu User coordinates of minimum coorner\n    //! \\param[in] maxu User coordinates of maximum coorner\n    //! \\param[out] min Integer coordinates of minimum coorner\n    //! \\param[out] max Integer coordinates of maximum coorner\n    //!\n    virtual bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const = 0;\n\n    //! Return the value of the \\a missing_value parameter\n    //!\n    //! The missing value is a special value intended to indicate that the\n    //! value of the sampled or reconstructed function is unknown at a\n    //! particular point.\n    //!\n    virtual float GetMissingValue() const;\n\n    //! Set the missing value indicator\n    //!\n    //! This method sets the value of the missing value indicator. The\n    //! method does not alter the value of any grid point locations, nor\n    //! does it alter the missing data flag set with the constructor.\n    //!\n    //! \\sa HasMissingData(), GetMissingValue()\n    //!\n    void SetMissingValue(float missing_value) { _missingValue = missing_value; };\n\n    //! Set missing data flag\n    //!\n    //! Set this flag if missing values may exist in the data. This missing\n    //! values are denoted by the value GetMissingValue(). Subsequent processing\n    //! of grid data will be compared against the value of GetMissingValue()\n    //! if this flag is set.\n    //\n    void SetHasMissingValues(bool flag) { _hasMissing = flag; }\n\n    //! Return missing data flag\n    //!\n    //! This method returns true if the missing data flag is set.\n    //! This does not\n    //! imply that grid points exist with missing data, only that the\n    //! the grid points should be compared against the value of\n    //! GetMissingValue() whenever operations are performed on them.\n    //\n    bool HasMissingData() const { return (_hasMissing); };\n\n    //! Return true if mesh primitives have counter clockwise winding\n    //! order.\n    //\n    virtual bool HasInvertedCoordinateSystemHandiness() const { return (true); }\n\n    //! Return the interpolation order to be used during function reconstruction\n    //!\n    //! This method returns the order of the interpolation method that will\n    //! be used when reconstructing the sampled scalar function\n    //!\n    //! \\sa SetInterpolationOrder()\n    //!\n    virtual int GetInterpolationOrder() const { return _interpolationOrder; };\n\n    //! Set the interpolation order to be used during function reconstruction\n    //!\n    //! This method sets the order of the interpolation method that will\n    //! be used when reconstructing the sampled scalar function. Valid values\n    //! of \\p order are 0 and 1, corresponding to nearest-neighbor and linear\n    //! interpolation, respectively. If \\p order is invalid it will be silently\n    //! set to 1. The default interpolation order is 1\n    //!\n    //! \\param[in] order interpolation order\n    //! \\sa GetInterpolationOrder()\n    //!\n    virtual void SetInterpolationOrder(int order);\n\n    //! Compute the dimensions of a rectangular region bounded\n    //! by \\p min and \\p max coordinates\n    //\n    static DimsType Dims(const DimsType &min, const DimsType &max);\n\n    //! Return the user coordinates of a grid point\n    //!\n    //! This method returns the user coordinates of the grid point\n    //! specified by \\p indices\n    //!\n    //! Results are undefined if \\p indices is out of range.\n    //!\n    //! \\param[in] index Logical index into coordinate array. The dimensionality\n    //! and range of component values are given by GetNodeDimensions(). The\n    //! starting value for each component of \\p index is zero. \\p index must contain\n    //! GetNodeDimensions().size() elements.\n    //!\n    //! \\param[out] coord User coordinates of grid point with indices\n    //! given by \\p indices. \\p coord must have space for the number of elements\n    //! returned by GetGeometryDim().\n    //!\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const = 0;\n\n    virtual void GetUserCoordinates(const size_t indices[], double coords[]) const\n    {\n        DimsType  indices3 = {0, 0, 0};\n        CoordType coords3 = {0.0, 0.0, 0.0};\n        CopyToArr3(indices, GetNodeDimensions().size(), indices3);\n        GetUserCoordinates(indices3, coords3);\n        CopyFromArr3(coords3, coords);\n    }\n\n    virtual void GetUserCoordinates(const std::vector<size_t> &indices, std::vector<double> &coords) const\n    {\n        DimsType  indices3 = {0, 0, 0};\n        CoordType coords3 = {0.0, 0.0, 0.0};\n        CopyToArr3(indices, indices3);\n        GetUserCoordinates(indices3, coords3);\n        CopyFromArr3(coords3, coords);\n    }\n\n    virtual void GetUserCoordinates(size_t i, double &x, double &y, double &z) const;\n    virtual void GetUserCoordinates(size_t i, size_t j, double &x, double &y, double &z) const;\n    virtual void GetUserCoordinates(size_t i, size_t j, size_t k, double &x, double &y, double &z) const;\n\n    //! Return the indices of the cell containing the\n    //! specified user coordinates\n    //!\n    //! This method returns the cell ID (index) of the cell containing\n    //! the specified user coordinates. If any\n    //! of the input coordinates correspond to periodic dimensions the\n    //! the coordinate(s) are first re-mapped to lie inside the grid\n    //! extents as returned by GetUserExtents()\n    //!\n    //! If the specified coordinates lie outside of the grid (are not\n    //! contained by any cell) the method returns false, otherwise true is\n    //! returned.\n    //!\n    //! \\retval status true on success, false if the point is not contained\n    //! by any cell.\n    //!\n    virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const = 0;\n\n    //! \\deprecated\n    //\n    virtual bool GetIndicesCell(const double coords[3], size_t indices[3]) const\n    {\n        CoordType c3 = {0.0, 0.0, 0.0};\n        DimsType  i3 = {0, 0, 0};\n        CopyToArr3(coords, GetGeometryDim(), c3);\n        bool status = GetIndicesCell(c3, i3);\n        CopyFromArr3(i3, indices);\n        return (status);\n    }\n\n    //! \\deprecated\n    //\n    virtual bool GetIndicesCell(const std::vector<double> &coords, std::vector<size_t> &indices) const\n    {\n        CoordType c3 = {0.0, 0.0, 0.0};\n        DimsType  i3 = {0, 0, 0};\n        CopyToArr3(coords, c3);\n        bool status = GetIndicesCell(c3, i3);\n        CopyFromArr3(i3, indices);\n        return (status);\n    }\n\n    //! Return the min and max data value\n    //!\n    //! This method returns the values of grid points with min and max values,\n    //! respectively.\n    //!\n    //! For dataless grids the missing value is returned.\n    //!\n    //! \\param[out] range[2] A two-element array containing the mininum and\n    //! maximum values, in that order\n    //!\n    virtual void GetRange(float range[2]) const;\n\n    virtual void GetRange(const DimsType &min, const DimsType &max, float range[2]) const;\n\n    //! \\deprecated\n    //\n    virtual void GetRange(std::vector<size_t> min, std::vector<size_t> max, float range[2]) const\n    {\n        DimsType min3 = {0, 0, 0};\n        DimsType max3 = {0, 0, 0};\n        CopyToArr3(min, min3);\n        CopyToArr3(max, max3);\n        GetRange(min3, max3, range);\n    }\n\n    //! Return true if the specified point lies inside the grid\n    //!\n    //! This method can be used to determine if a point expressed in\n    //! user coordinates reside inside or outside the grid\n    //!\n    //! \\param[in] coords User coordinates of point in space\n    //!\n    //! \\retval bool True if point is inside the grid\n    //!\n    virtual bool InsideGrid(const CoordType &coords) const = 0;\n\n    //! \\deprecated\n    //\n    virtual bool InsideGrid(const double coords[3]) const\n    {\n        CoordType c3 = {0.0, 0.0, 0.0};\n        CopyToArr3(coords, GetGeometryDim(), c3);\n        return (InsideGrid(c3));\n    }\n\n    //! \\deprecated\n    //\n    virtual bool InsideGrid(const std::vector<double> &coords) const\n    {\n        CoordType c3 = {0.0, 0.0, 0.0};\n        CopyToArr3(coords, c3);\n        return (InsideGrid(c3));\n    }\n\n    //! Get the indices of the nodes that define a cell\n    //!\n    //! This method returns a vector of index vectors. Each index vector\n    //! contains the indices for a node that defines the given cell ID\n    //! \\p indices.\n    //!\n    //! For 2D cells the node IDs are returned in counter-clockwise order.\n    //! For 3D cells the ordering is dependent on the shape of the node. TBD.\n    //!\n    //! \\param[in] cindices An array of size Grid::GetDimensions.size() specifying\n    //! the index of the cell to query.\n    //! \\param[out] nodes An array of size\n    //! Grid::GetMaxVertexPerCell() x Grid::GetDimensions.size() that will contain\n    //! the concatenated list of node indices on return.\n    //! \\param[out] n The number of node indices returned in \\p nodes, an integer\n    //! in the range (0..Grid::GetMaxVertexPerCell()).\n    //!\n    //!\n    virtual bool GetCellNodes(const DimsType &cindices, std::vector<DimsType> &nodes) const = 0;\n\n    //! \\deprecated\n    //\n    virtual bool GetCellNodes(const size_t cindices[], std::vector<DimsType> &nodes) const\n    {\n        DimsType i3 = {0, 0, 0};\n        CopyToArr3(cindices, GetCellDimensions().size(), i3);\n        return (GetCellNodes(i3, nodes));\n    }\n\n    //! Get the IDs (indices) of all of the cells that border a cell\n    //!\n    //! This method returns a vector of index vectors. Each index vector\n    //! contains the indices of a cell that borders the cell given by\n    //! \\p indices. If a\n    //! cell edge is a boundary edge, having no neighbors, the associated\n    //! index vector for that border will be empty.\n    //! The cell IDs are returned in counter-clockwise order\n    //!\n    //! \\param[in] cindices An ordered vector of multi-dimensional cell\n    //! indices.\n    //! \\param[out] cells A vector of index vectors. Each index vector\n    //! has size given by GetDimensions.size()\n    //!\n    virtual bool GetCellNeighbors(const DimsType &cindices, std::vector<DimsType> &cells) const = 0;\n\n    //! Get the IDs (indices) of all of the cells that share a node\n    //!\n    //! This method returns a vector of index vectors. Each index vector\n    //! contains the indices of a cell that share the node given by\n    //! \\p indices.\n    //! The cell IDs are returned in counter-clockwise order\n    //!\n    //! \\param[out] nodes A vector of index vectors . Each index vector\n    //! has size given by GetDimensions.size()\n    //!\n    virtual bool GetNodeCells(const DimsType &indices, std::vector<DimsType> &cells) const = 0;\n\n    //! Return the maximum number of vertices per cell face\n    //!\n    virtual size_t GetMaxVertexPerFace() const = 0;\n\n    //! Return the maximum number of vertices per cell\n    //!\n    virtual size_t GetMaxVertexPerCell() const = 0;\n\n    //! Clamp periodic coordinates and ensure valid coordinate vector dimension\n    //!\n    //! This method ensures that periodic coordinates are within the bounding\n    //! box of the grid and that the coordinate vector dimension does not\n    //! exceed the number of allowable coordinates as returned by\n    //! GetGeometryDim().\n    //!\n    //! \\param[in] coords A coordinate vector\n    //! \\param[out] cCoords The clamped coordintes \\p coords\n    //! \\sa GetGeometryDim()\n    //\n    virtual void ClampCoord(const CoordType &coords, CoordType &cCoords) const = 0;\n\n    //! \\deprecated\n    //\n    virtual void ClampCoord(const double coords[3], double cCoords[3]) const\n    {\n        CoordType c3 = {coords[0], coords[1], coords[2]};\n        CoordType cC3;\n        ClampCoord(c3, cC3);\n        cCoords[0] = cC3[0];\n        cCoords[1] = cC3[1];\n        cCoords[2] = cC3[2];\n    }\n\n    //! Clamp grid array indices\n    //!\n    //! This method ensures that grid indices are not out of bounds, clamping\n    //! any elements of \\p indices that exceeds or equals the corresponding element of\n    //! GetNodeDimensions() to that value minus 1.\n    //!\n    //! \\param[in] indices An array index vector\n    //! \\param[out] cindices An array index vector, clamped as described above\n    //!\n    //! \\sa GetNodeDimensions()\n    //\n    virtual void ClampIndex(const DimsType &indices, DimsType &cIndices) const { ClampIndex(GetNodeDimensions(), indices, cIndices); }\n\n    //! Clamp grid cell indices\n    //!\n    //! Same as ClampIndex() accept that indices are clamped to GetCellDimensions()\n    //!\n    //! \\sa ClampIndex()\n    //\n    virtual void ClampCellIndex(const DimsType &indices, DimsType &cIndices) const { ClampIndex(GetCellDimensions(), indices, cIndices); }\n\n    //! Set periodic boundaries\n    //!\n    //! This method changes the periodicity of boundaries set\n    //! by the class constructor\n    //!\n    //! \\param[in] periodic A boolean vector of size given by\n    //! GetGeometryDim() indicating\n    //! which coordinate axes are periodic.\n    //\n    virtual void SetPeriodic(const std::vector<bool> &periodic)\n    {\n        _periodic.clear();\n        int i = 0;\n        for (; i < periodic.size() && i < GetGeometryDim(); i++) { _periodic.push_back(periodic[i]); }\n        for (; i < GetGeometryDim(); i++) { _periodic.push_back(false); }\n    }\n\n    //! Check for periodic boundaries\n    //!\n    //\n    virtual const std::vector<bool> &GetPeriodic() const { return (_periodic); }\n\n    //! Get topological dimension of the mesh\n    //!\n    //! Return the number of topological dimensions for the mesh cells. Valid\n    //! values are in the range 0..3, with, for example, 0 corresponding\n    //! to points; 1 to lines; 2 to triangles, quadrilaterals, etc.; and\n    //! 3 to hexahedron, tetrahedron, etc.\n    //!\n    //! \\sa GetGeometryDim()\n    //\n    virtual size_t GetTopologyDim() const { return (_topologyDimension); }\n\n    //! Get the linear offset to the node IDs\n    //!\n    //! Return the smallest node ID. The default is zero\n    //\n    virtual long GetNodeOffset() const { return (_nodeIDOffset); }\n    virtual void SetNodeOffset(long offset) { _nodeIDOffset = offset; }\n\n    //! Get the linear offset to the cell IDs\n    //!\n    //! Return the smallest Cell ID. The default is zero\n    //\n    virtual long GetCellOffset() const { return (_cellIDOffset); }\n    virtual void SetCellOffset(long offset) { _cellIDOffset = offset; }\n\n    //! Return the absolute minimum grid coordinate\n    //!\n    //! This method returns the absolute minimum grid coordinate. If\n    //! the Grid contains a subregion extracted from a larger mesh this\n    //! absolute minimum grid coordinate gives the offset of the first\n    //! gridpoint in this grid relative to the larger mesh.\n    //!\n    //! \\note The value of returned is not used within the Grid class\n    //! and any value can be stored here using SetMinAbs().\n    //!\n    virtual DimsType GetMinAbs() const { return (_minAbs); }\n\n    //! Set the absolute minimum grid coordinate\n    //!\n    //! \\param[in] minAbs Must have same dimensionality as constructors \\p dims\n    //! parameter. Otherwise may contain any value, but is intended to contain\n    //! the offset to the first grid point in the mesh. The default is the\n    //! zero vector\n    //\n    virtual void SetMinAbs(const DimsType &minAbs) { _minAbs = minAbs; }\n\n    //! Test whether a point is contained in a bounding rectangle\n    //!\n    //! This static method checks to see if a 2D point \\p pt is contained\n    //! in the smallest rectangle that bounds the list of 2D points (vertices)\n    //! given by \\p verts. If \\p pt is inside or on the boundary of the bounding\n    //! rectangle true is returned, otherwise false\n    //!\n    //! \\param[in] pt A two-element array of point coordinates\n    //! \\param[in] verts An array of dimensions \\p n * 2 containing\n    //! a list of \\p points.\n    //! \\param[in] n The number of 2D points in \\p verts\n    //!\n    //! \\retval status Returns true if \\pt is inside or on the bounding rectangle\n    //! of \\p verts. False otherwise.\n    //\n    static bool PointInsideBoundingRectangle(const double pt[], const double verts[], int n)\n    {\n        VAssert(n > 2);\n\n        double left = verts[0];\n        double right = verts[0];\n        double top = verts[1];\n        double bottom = verts[1];\n\n        for (int i = 1; i < n; i++) {\n            if (verts[i * 2 + 0] < left) left = verts[i * 2 + 0];\n            if (verts[i * 2 + 0] > right) right = verts[i * 2 + 0];\n            if (verts[i * 2 + 1] < top) top = verts[i * 2 + 1];\n            if (verts[i * 2 + 1] > bottom) bottom = verts[i * 2 + 1];\n        }\n\n        return ((left <= pt[0]) && (right >= pt[0]) && (top <= pt[1]) && (bottom >= pt[1]));\n    }\n\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const Grid &g);\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Iterators\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    //! Inside a box functor\n    //!\n    //! operator() returns true if point pt is on or inside the axis-aligned\n    //! box defined by min and max\n    //\n    class InsideBox {\n    public:\n        InsideBox(const CoordType &min, const CoordType &max) : _min(min), _max(max) {}\n        InsideBox() {}\n\n        bool operator()(const CoordType &pt) const\n        {\n            if (_min == _max) return (true);\n            for (int i = 0; i < _min.size() && i < pt.size(); i++) {\n                if (pt[i] < _min[i] || pt[i] > _max[i]) return (false);\n            }\n            return (true);\n        }\n        bool operator()(const double pt[]) const\n        {\n            if (_min == _max) return (true);\n            for (int i = 0; i < _min.size(); i++) {\n                if (pt[i] < _min[i] || pt[i] > _max[i]) return (false);\n            }\n            return (true);\n        }\n\n        bool Enabled() const { return (_min != _max); }\n\n    private:\n        CoordType _min;\n        CoordType _max;\n    };\n\n    //\n    // Define polymorphic iterator that can be used with any\n    // class derived from this class\n    //\n    //\n\n    // Interface for iterator specializations\n    //\n    template<typename T> class AbstractIterator {\n    public:\n        virtual ~AbstractIterator() {}\n        virtual void                              next() = 0;\n        virtual void                              next(const long &offset) = 0;\n        virtual T &                               deref() const = 0;\n        virtual const void *                      address() const = 0;\n        virtual bool                              equal(const void *other) const = 0;\n        virtual std::unique_ptr<AbstractIterator> clone() const = 0;\n    };\n\n    // Overloaded operators that will act on spealizations of\n    // AbstractIterator\n    //\n    template<typename T> class PolyIterator {\n    public:\n        PolyIterator(std::unique_ptr<AbstractIterator<T>> it) : _impl(std::move(it)) {}\n\n        PolyIterator(PolyIterator const &rhs) : _impl(rhs._impl->clone()) {}\n\n        PolyIterator &operator=(PolyIterator const &rhs)\n        {\n            _impl = rhs._impl->clone();\n            return *this;\n        }\n\n        // PolyIterator has a unique_ptr member so we must provide\n        // std::move constructors\n        //\n        PolyIterator(PolyIterator &&rhs) { _impl = std::move(rhs._impl); }\n\n        PolyIterator &operator=(PolyIterator &&rhs)\n        {\n            if (this != &rhs) { _impl = std::move(rhs._impl); }\n            return (*this);\n        }\n\n        PolyIterator() : _impl(nullptr) {}\n\n        PolyIterator &operator++()\n        {    // ++prefix\n            _impl->next();\n            return *this;\n        };\n\n        PolyIterator operator++(int)\n        {    // postfix++\n            PolyIterator temp(*this);\n            ++(*this);\n            return (temp);\n        };\n\n        PolyIterator &operator+=(const long &offset)\n        {\n            _impl->next(offset);\n            return (*this);\n        };\n\n        PolyIterator operator+(const long &offset) const\n        {\n            PolyIterator temp(*this);\n            temp += offset;\n            return (temp);\n        }\n\n        const T &operator*() const { return _impl->deref(); }\n\n        bool operator==(const PolyIterator &rhs) const { return (_impl->equal(rhs._impl->address())); }\n\n        bool operator!=(const PolyIterator &rhs) const { return (!(*this == rhs)); }\n\n    private:\n        std::unique_ptr<AbstractIterator<T>> _impl;\n    };\n\n    //! Coordinate iterator. Iterates over grid node/cell coordinates\n    //!\n    //! The ConstCoordItr can be dererenced to return a grid node or\n    //! cell's coordinates. The determination, node or cell, is determined\n    //! by the location of the sampled data within the grid (node, face,\n    //! cell, etc)\n    //!\n    //! N.B. Current only works with node coordinates\n    //!\n    //\n    typedef const CoordType                        ConstCoordType;\n    typedef Grid::PolyIterator<ConstCoordType>     ConstCoordItr;\n    typedef Grid::AbstractIterator<ConstCoordType> ConstCoordItrAbstract;\n\n    //! Return constant grid coordinate iterator\n    //\n    virtual ConstCoordItr ConstCoordBegin() const = 0;\n    virtual ConstCoordItr ConstCoordEnd() const = 0;\n\n    //! Node index iterator. Iterates over grid node indices\n    //!\n    //! The ConstNodeIterator is dereferenced to give the index of\n    //! a node within the grid\n    //!\n    typedef const DimsType                         ConstIndexType;\n    typedef Grid::PolyIterator<ConstIndexType>     ConstNodeIterator;\n    typedef Grid::AbstractIterator<ConstIndexType> ConstNodeIteratorAbstract;\n\n    //! Cell index iterator. Iterates over grid cell indices\n    //\n    typedef Grid::PolyIterator<ConstIndexType>     ConstCellIterator;\n    typedef Grid::AbstractIterator<ConstIndexType> ConstCellIteratorAbstract;\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Iterators\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    //\n    // Node index iterator. Iterates over node indices\n    //\n    class ConstNodeIteratorSG : public Grid::ConstNodeIteratorAbstract {\n    public:\n        ConstNodeIteratorSG(const Grid *g, bool begin);\n        ConstNodeIteratorSG(const ConstNodeIteratorSG &rhs);\n        ConstNodeIteratorSG();\n\n        virtual ~ConstNodeIteratorSG() {}\n\n        virtual void            next();\n        virtual void            next(const long &offset);\n        virtual ConstIndexType &deref() const { return (_index); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const\n        {\n            const ConstNodeIteratorSG *itrptr = static_cast<const ConstNodeIteratorSG *>(rhs);\n            return (_index == itrptr->_index);\n        }\n\n        virtual std::unique_ptr<ConstNodeIteratorAbstract> clone() const { return std::unique_ptr<ConstNodeIteratorAbstract>(new ConstNodeIteratorSG(*this)); };\n\n    protected:\n        DimsType _dims;\n        DimsType _index;\n        DimsType _lastIndex;\n    };\n\n    class ConstNodeIteratorBoxSG : public ConstNodeIteratorSG {\n    public:\n        ConstNodeIteratorBoxSG(const Grid *g, const CoordType &minu, const CoordType &maxu);\n        ConstNodeIteratorBoxSG(const ConstNodeIteratorBoxSG &rhs);\n        ConstNodeIteratorBoxSG();\n\n        virtual ~ConstNodeIteratorBoxSG() {}\n\n        virtual void next();\n        virtual void next(const long &offset);\n\n        virtual std::unique_ptr<ConstNodeIteratorAbstract> clone() const { return std::unique_ptr<ConstNodeIteratorAbstract>(new ConstNodeIteratorBoxSG(*this)); };\n\n    private:\n        InsideBox     _pred;\n        ConstCoordItr _coordItr;\n    };\n\n    //! Return constant grid node coordinate iterator\n    //!\n    //! If \\p minu and \\p maxu are specified the iterator is constrained to\n    //! operation within the axis-aligned box defined by \\p minu and \\p maxu.\n    //!\n    //! \\param[in] minu Minimum box coordinate.\n    //! \\param[in] maxu Maximum box coordinate.\n    //!\n    virtual ConstNodeIterator ConstNodeBegin() const { return ConstNodeIterator(std::unique_ptr<ConstNodeIteratorAbstract>(new ConstNodeIteratorSG(this, true))); }\n\n    virtual ConstNodeIterator ConstNodeBegin(const CoordType &minu, const CoordType &maxu) const\n    {\n        return ConstNodeIterator(std::unique_ptr<ConstNodeIteratorAbstract>(new ConstNodeIteratorBoxSG(this, minu, maxu)));\n    }\n\n    virtual ConstNodeIterator ConstNodeBegin(const std::vector<double> &minu, const std::vector<double> &maxu) const\n    {\n        CoordType minuCT, maxuCT;\n        CopyToArr3(minu, minuCT);\n        CopyToArr3(maxu, maxuCT);\n        return ConstNodeBegin(minuCT, maxuCT);\n    }\n\n    virtual ConstNodeIterator ConstNodeEnd() const { return ConstNodeIterator(std::unique_ptr<ConstNodeIteratorAbstract>(new ConstNodeIteratorSG(this, false))); }\n\n    //\n    // Cell index iterator. Iterates over cell indices\n    //\n    class ConstCellIteratorSG : public Grid::ConstCellIteratorAbstract {\n    public:\n        ConstCellIteratorSG(const Grid *g, bool begin);\n        ConstCellIteratorSG(const ConstCellIteratorSG &rhs);\n        ConstCellIteratorSG();\n\n        virtual ~ConstCellIteratorSG() {}\n\n        virtual void            next();\n        virtual void            next(const long &offset);\n        virtual ConstIndexType &deref() const { return (_index); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const\n        {\n            const ConstCellIteratorSG *itrptr = static_cast<const ConstCellIteratorSG *>(rhs);\n\n            return (_index == itrptr->_index);\n        }\n\n        virtual std::unique_ptr<ConstCellIteratorAbstract> clone() const { return std::unique_ptr<ConstCellIteratorAbstract>(new ConstCellIteratorSG(*this)); };\n\n    protected:\n        DimsType _dims;\n        DimsType _index;\n        DimsType _lastIndex;\n    };\n\n    class ConstCellIteratorBoxSG : public ConstCellIteratorSG {\n    public:\n        ConstCellIteratorBoxSG(const Grid *g, const CoordType &minu, const CoordType &maxu);\n        ConstCellIteratorBoxSG(const ConstCellIteratorBoxSG &rhs);\n        ConstCellIteratorBoxSG();\n\n        virtual ~ConstCellIteratorBoxSG() {}\n\n        virtual void next();\n        virtual void next(const long &offset);\n\n        virtual std::unique_ptr<ConstCellIteratorAbstract> clone() const { return std::unique_ptr<ConstCellIteratorAbstract>(new ConstCellIteratorBoxSG(*this)); };\n\n    private:\n        InsideBox _pred;\n        const Grid *_g;\n        bool        _cellInsideBox(const size_t cindices[]) const;\n    };\n\n    //! Return constant grid cell coordinate iterator\n    //!\n    //! If \\p minu and \\p maxu are specified the iterator is constrained to\n    //! operation within the axis-aligned box defined by \\p minu and \\p maxu.\n    //!\n    //! \\param[in] minu Minimum box coordinate.\n    //! \\param[in] maxu Maximum box coordinate.\n    //!\n    virtual ConstCellIterator ConstCellBegin() const { return ConstCellIterator(std::unique_ptr<ConstCellIteratorAbstract>(new ConstCellIteratorSG(this, true))); }\n\n    virtual ConstCellIterator ConstCellBegin(const CoordType &minu, const CoordType &maxu) const\n    {\n        return ConstCellIterator(std::unique_ptr<ConstCellIteratorAbstract>(new ConstCellIteratorBoxSG(this, minu, maxu)));\n    }\n\n    virtual ConstCellIterator ConstCellBegin(const std::vector<double> &minu, const std::vector<double> &maxu) const\n    {\n        CoordType minuCT, maxuCT;\n        CopyToArr3(minu, minuCT);\n        CopyToArr3(maxu, maxuCT);\n        return ConstCellBegin(minuCT, maxuCT);\n    }\n\n    virtual ConstCellIterator ConstCellEnd() const { return ConstCellIterator(std::unique_ptr<ConstCellIteratorAbstract>(new ConstCellIteratorSG(this, false))); }\n\n    //! A forward iterator for accessing the data elements of the\n    //! structured grid.\n    //!\n    //! This class provides a C++ STL style Forward Iterator for\n    //! accessing grid elements passed to the constructor. All Forward\n    //! Iterator expressions are supported. In addition, the following\n    //! Random Access Iterator expressions are supported:\n    //!\n    //! \\li \\c a + n\n    //! \\li \\c n + a\n    //!\n    //! where \\i a are objects of type ForwardIterator, and \\i n is an int.\n    //!\n    //! N.B. this class does NOT need to be a template. It's a historical\n    //! implementation.\n    //\n    template<class T> class VDF_API ForwardIterator {\n    public:\n        ForwardIterator(T *rg, bool begin = true, const CoordType &minu = {0.0, 0.0, 0.0}, const CoordType &maxu = {0.0, 0.0, 0.0});\n        ForwardIterator();\n        ForwardIterator(const ForwardIterator<T> &) = default;\n        ForwardIterator(ForwardIterator<T> &&rhs);\n        ~ForwardIterator() {}\n\n        float &operator*() { return (*_itr); }\n\n        ForwardIterator<T> &operator++();    // ++prefix\n\n        ForwardIterator<T> operator++(int);    // postfix++\n\n        ForwardIterator<T> &operator+=(const long int &offset);\n        ForwardIterator<T>  operator+(const long int &offset) const;\n\n        ForwardIterator<T> &operator=(ForwardIterator<T> rhs);\n        ForwardIterator<T> &operator=(ForwardIterator<T> &rhs) = delete;\n\n        bool operator==(const ForwardIterator<T> &rhs) const { return (_index == rhs._index); }\n        bool operator!=(const ForwardIterator<T> &rhs) { return (_index != rhs._index); }\n\n        const ConstCoordItr &GetCoordItr() { return (_coordItr); }\n\n        friend void swap(Grid::ForwardIterator<T> &a, Grid::ForwardIterator<T> &b)\n        {\n            std::swap(a._blks, b._blks);\n            std::swap(a._dims3d, b._dims3d);\n            std::swap(a._bdims3d, b._bdims3d);\n            std::swap(a._bs3d, b._bs3d);\n            std::swap(a._blocksize, b._blocksize);\n            std::swap(a._coordItr, b._coordItr);\n            std::swap(a._index, b._index);\n            std::swap(a._lastIndex, b._lastIndex);\n            std::swap(a._xb, b._xb);\n            std::swap(a._itr, b._itr);\n            std::swap(a._pred, b._pred);\n        }\n\n    private:\n        std::vector<float *> _blks;\n        DimsType             _dims3d;\n        DimsType             _bdims3d;\n        DimsType             _bs3d;\n        size_t               _blocksize;\n        ConstCoordItr        _coordItr;\n        DimsType             _index;        // current index into grid\n        DimsType             _lastIndex;    // Last valid index\n        size_t               _xb;           // x index within a block\n        float *              _itr;\n        InsideBox            _pred;\n    };\n\n    typedef Grid::ForwardIterator<Grid>       Iterator;\n    typedef Grid::ForwardIterator<Grid const> ConstIterator;\n\n    //! Construct a begin iterator that will iterate through elements\n    //! inside or on the box defined by \\p minu and \\p maxu\n    //\n    Iterator begin(const CoordType &minu, const CoordType &maxu) { return (Iterator(this, true, minu, maxu)); }\n\n    Iterator begin(const std::vector<double> &minu, const std::vector<double> &maxu)\n    {\n        CoordType minuCT, maxuCT;\n        CopyToArr3(minu, minuCT);\n        CopyToArr3(maxu, maxuCT);\n        return begin(minuCT, maxuCT);\n    }\n\n    Iterator begin() { return (Iterator(this, true)); }\n\n    Iterator end() { return (Iterator(this, false)); }\n\n    ConstIterator cbegin(const CoordType &minu, const CoordType &maxu) const { return (ConstIterator(this, true, minu, maxu)); }\n\n    ConstIterator cbegin(const std::vector<double> &minu, const std::vector<double> &maxu)\n    {\n        CoordType minuCT, maxuCT;\n        CopyToArr3(minu, minuCT);\n        CopyToArr3(maxu, maxuCT);\n        return cbegin(minuCT, maxuCT);\n    }\n    ConstIterator cbegin() const { return (ConstIterator(this, true)); }\n\n    ConstIterator cend() const { return (ConstIterator(this, false)); }\n\n    template<typename T> static void CopyToArr3(const std::vector<T> &src, std::array<T, 3> &dst)\n    {\n        for (int i = 0; i < src.size() && i < dst.size(); i++) { dst[i] = src[i]; }\n    }\n\n    template<typename T> static void CopyToArr3(const T *src, size_t n, std::array<T, 3> &dst)\n    {\n        for (int i = 0; i < n && i < dst.size(); i++) { dst[i] = src[i]; }\n    }\n    template<typename T> static void CopyFromArr3(const std::array<T, 3> &src, std::vector<T> &dst)\n    {\n        dst.resize(src.size());\n        for (int i = 0; i < src.size() && i < dst.size(); i++) { dst[i] = src[i]; }\n    }\n    template<typename T> static void CopyFromArr3(const std::array<T, 3> &src, T *dst)\n    {\n        for (int i = 0; i < src.size(); i++) { dst[i] = src[i]; }\n    }\n\nprotected:\n    virtual float GetValueNearestNeighbor(const CoordType &coords) const = 0;\n\n    virtual float GetValueLinear(const CoordType &coords) const = 0;\n\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const = 0;\n\n    virtual float *GetValuePtrAtIndex(const std::vector<float *> &blks, const DimsType &indices) const;\n\n    // Deprecated\n    virtual void ClampIndex(const std::vector<size_t> &dims, const DimsType indices, DimsType &cIndices) const\n    {\n        cIndices = {0, 0, 0};\n\n        for (int i = 0; i < dims.size(); i++) {\n            cIndices[i] = indices[i];\n            if (cIndices[i] >= dims[i]) { cIndices[i] = dims[i] - 1; }\n        }\n    }\n\n    virtual void ClampIndex(const DimsType &dims, const DimsType indices, DimsType &cIndices) const\n    {\n        cIndices = {0, 0, 0};\n\n        for (int i = 0; i < dims.size(); i++) {\n            cIndices[i] = indices[i];\n            if (cIndices[i] >= dims[i]) {\n                assert(dims[i] > 0);\n                cIndices[i] = dims[i] - 1;\n            }\n        }\n    }\n\n    float BilinearInterpolate(size_t i, size_t j, size_t k, const double xwgt, const double ywgt) const;\n\n    float TrilinearInterpolate(size_t i, size_t j, size_t k, const double xwgt, const double ywgt, const double zwgt) const;\n\nprivate:\n    DimsType             _dims;                   // dimensions of grid arrays\n    DimsType             _bs = {{1, 1, 1}};       // dimensions of each block\n    DimsType             _bdims = {{1, 1, 1}};    // dimensions (specified in blocks) of ROI\n    std::vector<size_t>  _bsDeprecated;           // legacy API\n    std::vector<size_t>  _bdimsDeprecated;        // legacy API\n    std::vector<float *> _blks;\n    std::vector<bool>    _periodic;    // periodicity of boundaries\n    DimsType             _minAbs;      // Offset to start of grid\n    size_t               _topologyDimension = 0;\n    float                _missingValue = std::numeric_limits<float>::infinity();\n    bool                 _hasMissing = false;\n    int                  _interpolationOrder = 1;    // Order of interpolation\n    long                 _nodeIDOffset = 0;\n    long                 _cellIDOffset = 0;\n    mutable CoordType    _minuCache = {{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()}};\n    mutable CoordType    _maxuCache = {{std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()}};\n\n    void _grid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, size_t topology_dimension);\n};\n\ntemplate void Grid::CopyToArr3<size_t>(const std::vector<size_t> &src, std::array<size_t, 3> &dst);\n\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/GridHelper.h",
    "content": "#include <vector>\n#include <unordered_map>\n#include <list>\n#include <cstddef>\n#include <stdexcept>\n#include <vapor/DC.h>\n#include <vapor/MyBase.h>\n#include <vapor/CurvilinearGrid.h>\n#include <vapor/LayeredGrid.h>\n#include <vapor/RegularGrid.h>\n#include <vapor/StretchedGrid.h>\n#include <vapor/UnstructuredGrid2D.h>\n#include <vapor/UnstructuredGridLayered.h>\n\n#ifndef GRIDMGR_H\n    #define GRIDMGR_H\n\nnamespace VAPoR {\n\nclass UnstructuredGrid3D;\n\nclass VDF_API GridHelper : public Wasp::MyBase {\npublic:\n    GridHelper(size_t max_size = 10) : _qtrCache(max_size) {}\n\n    ~GridHelper();\n\n    string GetGridType(const DC::Mesh &m, const std::vector<DC::CoordVar> &cvarsinfo, const std::vector<vector<string>> &cdimnames) const;\n\n    bool IsUnstructured(std::string gridType) const;\n    bool IsStructured(std::string gridType) const;\n\n    //\tvar: variable info\n    //  roi_dims: spatial dimensions of ROI\n    //\tdims: spatial dimensions of full variable domain in voxels\n    //\tblkvec: data blocks, and coordinate blocks\n    //\tbsvec: data block dimensions, and coordinate block dimensions\n    //  bminvec: ROI offsets in blocks, full domain, data and coordinates\n    //  bmaxvec: ROI offsets in blocks, full domain, data and coordinates\n    //\n    StructuredGrid *MakeGridStructured(string gridType, size_t ts, int level, int lod, const DC::DataVar &var, const std::vector<DC::CoordVar> &cvarsinfo, const DimsType &roi_dims,\n                                       const DimsType &dims, const std::vector<float *> &blkvec, const std::vector<DimsType> &bsvec, const std::vector<DimsType> &bminvec,\n                                       const std::vector<DimsType> &bmaxvec);\n\n    UnstructuredGrid *MakeGridUnstructured(string gridType, size_t ts, int level, int lod, const DC::DataVar &var, const std::vector<DC::CoordVar> &cvarsinfo, const DimsType &roi_dims,\n                                           const DimsType &dims, const std::vector<float *> &blkvec, const std::vector<DimsType> &bsvec, const std::vector<DimsType> &bminvec,\n                                           const std::vector<DimsType> &bmaxvec, const std::vector<int *> &conn_blkvec, const std::vector<DimsType> &conn_bsvec,\n                                           const std::vector<DimsType> &conn_bminvec, const std::vector<DimsType> &conn_bmaxvec, const DimsType &vertexDims, const DimsType &faceDims,\n                                           const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset);\n\nprivate:\n    template<typename key_t, typename value_t> class lru_cache {\n    public:\n        typedef typename std::pair<key_t, value_t>             key_value_pair_t;\n        typedef typename std::list<key_value_pair_t>::iterator list_iterator_t;\n\n        lru_cache() : _max_size(10) {}\n\n        lru_cache(size_t max_size) : _max_size(max_size) {}\n\n        value_t put(const key_t &key, value_t value)\n        {\n            value_t rvalue = NULL;\n            auto    it = _cache_items_map.find(key);\n            _cache_items_list.push_front(key_value_pair_t(key, value));\n            if (it != _cache_items_map.end()) {\n                rvalue = it->second->second;\n                _cache_items_list.erase(it->second);\n                _cache_items_map.erase(it);\n            }\n            _cache_items_map[key] = _cache_items_list.begin();\n\n            if (_cache_items_map.size() > _max_size) {\n                auto last = _cache_items_list.end();\n                last--;\n                rvalue = last->second;\n                _cache_items_map.erase(last->first);\n                _cache_items_list.pop_back();\n            }\n            return (rvalue);\n        }\n\n        value_t get(const key_t &key)\n        {\n            auto it = _cache_items_map.find(key);\n            if (it == _cache_items_map.end()) return (NULL);\n\n            _cache_items_list.splice(_cache_items_list.begin(), _cache_items_list, it->second);\n            return it->second->second;\n        }\n\n        value_t remove_lru()\n        {\n            if (!_cache_items_map.size()) return (NULL);\n\n            auto last = _cache_items_list.end();\n            last--;\n            value_t rvalue = last->second;\n            last->second = nullptr;    // necessary for delete?\n            _cache_items_map.erase(last->first);\n            _cache_items_list.pop_back();\n            return (rvalue);\n        }\n\n        bool exists(const key_t &key) const;\n\n        size_t size() const { return _cache_items_map.size(); }\n\n    private:\n        std::list<key_value_pair_t>                _cache_items_list;\n        std::unordered_map<key_t, list_iterator_t> _cache_items_map;\n        size_t                                     _max_size;\n    };\n\n    lru_cache<string, std::shared_ptr<const QuadTreeRectangleP>> _qtrCache;\n\n    RegularGrid *_make_grid_regular(const DimsType &dims, const std::vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax\n\n    ) const;\n\n    StretchedGrid *_make_grid_stretched(const DimsType &dims, const std::vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const;\n\n    LayeredGrid *_make_grid_layered(const DimsType &dims, const std::vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const;\n\n    CurvilinearGrid *_make_grid_curvilinear(size_t ts, int level, int lod, const std::vector<DC::CoordVar> &cvarsinfo, const DimsType &dims, const std::vector<float *> &blkvec, const DimsType &bs,\n                                            const DimsType &bmin, const DimsType &bmax);\n\n    UnstructuredGrid2D *_make_grid_unstructured2d(size_t ts, int level, int lod, const DC::DataVar &var, const std::vector<DC::CoordVar> &cvarsinfo, const DimsType &dims,\n                                                  const std::vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const std::vector<int *> &conn_blkvec,\n                                                  const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims,\n                                                  const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset);\n\n    UnstructuredGridLayered *_make_grid_unstructured_layered(size_t ts, int level, int lod, const DC::DataVar &var, const vector<DC::CoordVar> &cvarsinfo, const DimsType &dims,\n                                                             const vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector<int *> &conn_blkvec,\n                                                             const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims,\n                                                             const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset,\n                                                             long faceOffset);\n\n    UnstructuredGrid3D *_make_grid_unstructured_3d(size_t ts, int level, int lod, const DC::DataVar &var, const vector<DC::CoordVar> &cvarsinfo, const DimsType &dims, const vector<float *> &blkvec,\n                                                   const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector<int *> &conn_blkvec, const DimsType &conn_bs, const DimsType &conn_bmin,\n                                                   const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location,\n                                                   size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset, long faceOffset);\n\n    void _makeGridHelper(const DC::DataVar &var, const DimsType &roi_dims, const DimsType &dims, Grid *g) const;\n\n    string _getQuadTreeRectangleKey(size_t ts, int level, int lod, const vector<DC::CoordVar> &cvarsinfo, const DimsType &bmin, const DimsType &bmax) const;\n};\n\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/HelloParams.h",
    "content": "\n#ifndef HELLOPARAMS_H\n#define HELLOPARAMS_H\n\n#include <vapor/RenderParams.h>\n\nnamespace VAPoR {\n\n//! \\class HelloParams\n//! \\brief Class that supports drawing a line connecting two points.\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date June 2015\nclass PARAMS_API HelloParams : public RenderParams {\npublic:\n    HelloParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n\n    HelloParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~HelloParams();\n\n    //! Determine line thickness in voxels\n    //! \\retval double line thickness\n    double GetLineThickness() { return (GetValueDouble(m_lineThicknessTag, 1.0)); }\n\n    //! Set the line thickness\n    //! \\param[in] double thickness\n    //! \\retval int 0 if success\n    void SetLineThickness(double val) { SetValueDouble(m_lineThicknessTag, \"Set line thickness\", val); }\n\n    //! Obtain the first endpoint in user coordinates.\n    const vector<double> GetPoint1()\n    {\n        vector<double> defaultv(3, 0.0);\n        return GetValueDoubleVec(m_point1Tag, defaultv);\n    }\n\n    //! Obtain the second endpoint in user coordinates.\n    const vector<double> GetPoint2()\n    {\n        vector<double> defaultv(3, 1.0);\n        return GetValueDoubleVec(m_point2Tag, defaultv);\n    }\n\n    //! Set the first endpoint\n    void SetPoint1(vector<double> pt) { SetValueDoubleVec(m_point1Tag, \"Set First Endpoint\", pt); }\n\n    //! Set the second endpoint\n    void SetPoint2(vector<double> pt) { SetValueDoubleVec(m_point2Tag, \"Set Second Endpoint\", pt); }\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"HelloParams\"); }\n\n    virtual size_t GetRenderDim() const override { return (0); }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override { return GetColorMapVariableName(); }\n\nprivate:\n    static const string m_lineThicknessTag;\n    static const string m_point1Tag;\n    static const string m_point2Tag;\n\n    void _init();\n\n};        // End of Class HelloParams\n};        // namespace VAPoR\n#endif    // HELLOPARAMS_H\n"
  },
  {
    "path": "include/vapor/HelloRenderer.h",
    "content": "//-- HelloRenderer.h ----------------------------------------------------------\n//\n//                   Copyright (C)  2011\n//     University Corporation for Atmospheric Research\n//                   All Rights Reserved\n//\n//----------------------------------------------------------------------------\n//\n//      File:           HelloRenderer.h\n//\n//      Author:         Alan Norton\n//\n//\n//      Description:  Definition of HelloRenderer class\n//\n//\n//\n//----------------------------------------------------------------------------\n\n#ifndef HELLORENDERER_H\n#define HELLORENDERER_H\n\n#include <vapor/Grid.h>\n#include <vapor/Renderer.h>\n#include <vapor/HelloParams.h>\n\nnamespace VAPoR {\n\n//! \\class HelloRenderer\n//! \\brief Class that draws a line as specified by HelloParams\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date June 2015\n\nclass RENDER_API HelloRenderer : public Renderer {\npublic:\n    HelloRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    ~HelloRenderer();\n\n    // Get static string identifier for this Render class\n    //\n    static string GetClassType() { return (\"Hello\"); }\n\nprotected:\n    //! \\copydoc Renderer::_initializeGL()\n    virtual int _initializeGL();\n\n    //! \\copydoc Renderer::_paintGL()\n    virtual int _paintGL(bool fast);\n\nprivate:\n    void _clearCache() {}\n};\n};    // namespace VAPoR\n\n#endif    // HELLORENDERER_H\n"
  },
  {
    "path": "include/vapor/Histo.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tHisto.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tNovember 2004\n//\n//\tDescription:  Definition of Histo class:\n//\t\tit contains a histogram derived from volume data.\n//\t\tUsed by TFEditor to draw histogram behind transfer function opacity\n//\n#ifndef HISTO_H\n#define HISTO_H\n#include <string>\n#include <vector>\n#include <climits>\n#include <vapor/MyBase.h>\n#include <vapor/StructuredGrid.h>\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nclass RENDER_API Histo {\npublic:\n    Histo(int numberBins, float mnData, float mxData, string var, int ts);\n    Histo(int numberBins);\n    Histo();\n    ~Histo();\n    void  reset(int newNumBins = -1);\n    void  reset(int newNumBins, float mnData, float mxData);\n    void  addToBin(float val);\n    void  setBins(const vector<long> &bins);\n    int   getMaxBinSize();\n    int   getMaxBinSizeBetweenIndices(const int start, const int end) const;\n    int   getNumBins() const;\n    int   getBinSize(int index) const;\n    int   getBinSize(int index, int stride) const;\n    float getNormalizedBinSize(int bin) const;\n    float getNormalizedBinSizeForValue(float v) const;\n    float getNormalizedBinSizeForNormalizedValue(float v) const;\n    int   getBinIndexForValue(float v);\n    float getMinMapData() { return _minMapData; }\n    float getMaxMapData() { return _maxMapData; }\n    float getRange() { return _range; }\n\n    int    getTimestepOfUpdate() { return _timestepOfUpdate; }\n    string getVarnameOfUpdate() { return _varnameOfUpdate; }\n\n    int  Populate(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp);\n    bool NeedsUpdate(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp);\n    int  PopulateIfNeeded(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp);\n    \n    static vector<float> GetDataSamples(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp);\n\nprivate:\n    unsigned int *_binArray = nullptr;\n    unsigned int *_below = nullptr;\n    unsigned int *_above = nullptr;\n    int           _nBinsBelow = 0, _nBinsAbove = 0;\n    long          _numSamplesBelow, _numSamplesAbove;\n    int           _numBins = 0;\n    float         _minMapData, _maxMapData, _range;\n    float         _minData, _maxData;\n    long          _maxBinSize = -1;\n\n    int                 _refLevel = INT_MIN, _lod = INT_MIN;\n    std::vector<double> _minExts, _maxExts;\n    bool                _populated = false;\n\n    int    _timestepOfUpdate;\n    string _varnameOfUpdate;\n    bool   autoSetProperties = false;\n\n    static vector<float> getDataSamplesIterating(const VAPoR::Grid *grid, const int stride);\n    static vector<float> getDataSamplesSampling(const VAPoR::Grid *grid, const vector<double> &minExts, const vector<double> &maxExts);\n    \n    void populateIteratingHistogram(const VAPoR::Grid *grid, const int stride);\n    void populateSamplingHistogram(const VAPoR::Grid *grid, const vector<double> &minExts, const vector<double> &maxExts);\n    static int  calculateStride(const std::string &varName, VAPoR::DataMgr *dm, const VAPoR::RenderParams *rp);\n    static bool shouldUseSampling(const std::string &varName, VAPoR::DataMgr *dm, const VAPoR::RenderParams *rp);\n    void setProperties(float mnData, float mxData, string var, int ts);\n    void calculateMaxBinSize();\n    void _getDataRange(const std::string &varName, VAPoR::DataMgr *d, VAPoR::RenderParams *r, float *min, float *max) const;\n};\n\n#endif    // HISTO_H\n"
  },
  {
    "path": "include/vapor/IResourceManager.h",
    "content": "#pragma once\n\n#include <string>\n#include <map>\n#include \"vapor/VAssert.h\"\n#include \"vapor/MyBase.h\"\n\n#ifdef WIN32\n    #ifdef RENDER_EXPORTS\n        #define IRESOURCEMANAGER_IMPLEMENT\n    #endif\n#else\n    #define IRESOURCEMANAGER_IMPLEMENT\n#endif\n\nnamespace VAPoR {\n\ntemplate<typename K, typename T> class RENDER_API IResourceManager : public Wasp::MyBase {\nprotected:\n    std::map<K, T *> _map;\n\n    T *GetResource(const K &key);\n\npublic:\n    virtual ~IResourceManager();\n    bool        HasResource(const K &key) const;\n    bool        HasResource(const T *resource) const;\n    virtual int LoadResourceByKey(const K &key) = 0;\n    bool        AddResource(const K &key, T *resource);\n    void        DeleteResource(const K &key);\n};\n\n#ifdef IRESOURCEMANAGER_IMPLEMENT\ntemplate<typename K, typename T> IResourceManager<K, T>::~IResourceManager()\n{\n    for (auto it = _map.begin(); it != _map.end(); ++it) delete it->second;\n}\n\ntemplate<typename K, typename T> T *IResourceManager<K, T>::GetResource(const K &key)\n{\n    auto it = _map.find(key);\n    if (it == _map.end()) {\n        if (LoadResourceByKey(key) < 0) {\n            SetErrMsg(\"Resource does not exist and unable to load by name\");\n            return nullptr;\n        }\n        it = _map.find(key);\n    }\n    return it->second;\n}\n\ntemplate<typename K, typename T> bool IResourceManager<K, T>::HasResource(const K &key) const { return _map.find(key) != _map.end(); }\n\ntemplate<typename K, typename T> bool IResourceManager<K, T>::HasResource(const T *resource) const\n{\n    for (auto it = _map.begin(); it != _map.end(); ++it)\n        if (it->second == resource) return true;\n    return false;\n}\n\ntemplate<typename K, typename T> bool IResourceManager<K, T>::AddResource(const K &key, T *resource)\n{\n    if (HasResource(key) || HasResource(resource)) {\n        VAssert(!\"Resource already exists\");\n        return false;\n    }\n    _map.insert(std::pair<K, T *>(key, resource));\n    return true;\n}\n\ntemplate<typename K, typename T> void IResourceManager<K, T>::DeleteResource(const K &key)\n{\n    VAssert(HasResource(key));\n    delete _map[key];\n    _map.erase(key);\n}\n#endif\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/ImageParams.h",
    "content": "#ifndef IMAGEPARAMS_H\n#define IMAGEPARAMS_H\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n#include <vapor/TMSUtils.h>\n\nnamespace VAPoR {\n\nclass PARAMS_API ImageParams : public RenderParams {\npublic:\n    ImageParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave);\n    ImageParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *xmlNode);\n\n    virtual ~ImageParams();\n\n    virtual int Initialize() override;\n\n    static std::string GetClassType() { return (\"ImageParams\"); }\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return (2); }\n\n    //! Set file path for the image to be read and displayed.\n    //! \\param[in] string - Path to image file\n    void SetImagePath(std::string file)\n    {\n        BeginGroup(\"Set image path\");\n        SetValueString(_fileNameTag, \"Set image file path\", file);\n        if (Wasp::TMSUtils::IsTMSFile(file)) {\n            int numTMSLODs = Wasp::TMSUtils::GetNumTMSLODs(file);\n            _setNumTMSLODs(numTMSLODs);\n        }\n        EndGroup();\n    }\n\n    //! Set image file path\n    //! \\retval string - Path to image file\n    std::string GetImagePath() const;\n\n    //! Inquire whether the currently selected image is georeferenced\n    //! Valid values: 0 = do not use georeference information, 1 = use georeference information\n    //! \\retval bool - State indicating whether current image is georeferenced\n    bool GetIsGeoRef() const { return (GetValueLong(_isGeoRefTag, (long)true)); }\n\n    //! If the raster image contained in the path returned by GetImagePath() has georeference information (e.g. the file is a GeoTIFF) this boolean determines whether or not the georeference information is honored\n    //! Valid values: 0 = do not use georeference information, 1 = use georeference information\n    //! \\param[in] bool - State indicating whether current image is georeferenced\n    void SetIsGeoRef(bool val) { SetValueLong(_isGeoRefTag, \"Geo-reference the image\", (long)val); }\n\n    //! Get whether transparency is being ignored regarding the currently selected image\n    //! Valid values: 0 = transparency is being honored, 1 = transparency is being ignored\n    //! \\retval bool - State whether transparency is being ignored\n    bool GetIgnoreTransparency() const { return (0 != GetValueLong(_ignoreTransparencyTag, (long)false)); }\n\n    //! Set whether transparency is being ignored regarding the currently selected image\n    //! Valid values: 0 = transparency is being honored, 1 = transparency is being ignored\n    //! \\param[in] bool - State whether transparency is being ignored\n    void SetIgnoreTransparency(bool val) { SetValueLong(_ignoreTransparencyTag, \"if transparence is ignored\", (long)val); }\n\n    //\n    // Get and set opacity value\n    //\n    /*\n  double GetOpacity() const\n  {\n    return GetValueDouble( _opacityTag, 1.0 );\n  }\n  void  SetOpacity( double val )\n  {\n    SetValueDouble( _opacityTag, \"set opacity value\", val );\n  }\n  */\n\n    //\n    // Get and set orientation\n    //\n    int  GetOrientation() const { return GetValueLong(_orientationTag, 2); }\n    void SetOrientation(int val) { SetValueLong(_orientationTag, \"set orientation value\", val); }\n\n    //! Get the TMS level of detail\n    //! \\retval int Currently selected TMS level of detail.  Value of -1 means we are computing a default value.\n    int GetTMSLOD() const\n    {\n        int value = ((int)GetValueLong(_TMSLODTag, -1));\n        return value;\n    }\n\n    //! Set the current TMS level of detail\n    //! \\param[in] val int val, the TMS level of detail to be applied.  Value of 0 means we are computing a default value.\n    void SetTMSLOD(int val) { SetValueLong(_TMSLODTag, \"TMS level of detail\", (long)val); }\n\n    //! Get the number of available levels of detail in the currently selected file.\n    //! \\retval int The currently available levels of detail in the current file.\n    int GetNumTMSLODs() const\n    {\n        int value = ((int)GetValueLong(_numTMSLODTag, 4));\n        return value;\n    }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override { return \"\"; }\n\npublic:\n    static const std::string _fileNameTag;\n    static const std::string _isGeoRefTag;\n    static const std::string _ignoreTransparencyTag;\n    static const std::string _opacityTag;\n    static const std::string _TMSLODTag;\n    static const std::string _numTMSLODTag;\n    static const std::string _orientationTag;    // If it's X-Y (orientation = 2)\n                                                 // If it's X-Z (orientation = 1)\n                                                 // If it's Y-Z (orientation = 0)\n\nprivate:\n    bool _initialized = false;\n\n    //! Set the number of TMS levels of detail for the currently selected image\n    //! \\param[in] val int val, the number of TMS levels of detail available in the current file.\n    void _setNumTMSLODs(int val) { SetValueLong(_numTMSLODTag, \"Number of TMS levels of detail\", (long)val); }\n};\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/ImageRenderer.h",
    "content": "#ifndef IMAGERENDERER_H\n#define IMAGERENDERER_H\n\n#include <vapor/TwoDRenderer.h>\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/GeoImage.h>\n#include <vapor/Grid.h>\n#include <vapor/utils.h>\n\nnamespace VAPoR {\n\nclass RENDER_API ImageRenderer : public TwoDRenderer {\npublic:\n    ImageRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    virtual ~ImageRenderer();\n\n    static std::string GetClassType() { return (\"Image\"); }\n\nprotected:\n    int GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh);\n\n    const GLvoid *GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned);\n\nprivate:\n    GeoImage *     _geoImage;\n    unsigned char *_twoDTex;\n    string         _cacheImgFileName;\n    vector<double> _cacheTimes;\n    vector<double> _pcsExtentsData;\n    double         _pcsExtentsImg[4];\n    string         _proj4StringImg;\n    GLsizei        _texWidth;\n    GLsizei        _texHeight;\n    const int      _maxResamplingResolution;\n    size_t         _cacheTimestep;\n    int            _cacheRefLevel;\n    int            _cacheLod;\n    int            _cacheTMSLOD;\n    vector<double> _cacheBoxExtents;\n    size_t         _cacheTimestepTex;\n    string         _cacheHgtVar;\n    int            _cacheGeoreferenced;\n    vector<double> _cacheBoxExtentsTex;\n    SmartBuf       _sb_verts;\n    SmartBuf       _sb_normals;\n    SmartBuf       _sb_indices;\n    GLsizei        _vertsWidth;\n    GLsizei        _vertsHeight;\n    GLsizei        _nindices;\n    GLsizei        _nverts;\n\n    unsigned char *_getTexture(DataMgr *dataMgr);\n\n    bool _gridStateDirty() const;\n\n    void _gridStateClear();\n\n    void _gridStateSet();\n\n    bool _imageStateDirty(const vector<double> &times) const;\n\n    void _imageStateSet(const vector<double> &times);\n\n    void _imageStateClear();\n\n    bool _texStateDirty(DataMgr *dataMgr) const;\n\n    void _texStateSet(DataMgr *dataMgr);\n\n    void _texStateClear();\n\n    int _reinit(string path, vector<double> times);\n\n    unsigned char *_getImage(GeoImage *geoimage, size_t ts, string proj4StringData, vector<double> pcsExtentsDataVec, double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg,\n                             GLsizei &width, GLsizei &height) const;\n\n    int _getMeshDisplacedGeo(DataMgr *dataMgr, Grid *hgtGrid, GLsizei width, GLsizei height, double defaultZ);\n\n    // Compute _verts  for displayed, non-georeferenced image\n    //\n    int _getMeshDisplacedNoGeo(DataMgr *dataMgr, Grid *hgtGrid, GLsizei width, GLsizei height, const vector<double> &minExt, const vector<double> &maxExt, double defaultZ);\n\n    int _getMeshDisplaced(DataMgr *dataMgr, GLsizei width, GLsizei height, const vector<double> &minBox, const vector<double> &maxBox, double defaultZ);\n\n    int _getMeshPlane(const vector<double> &minBox, const vector<double> &maxBox, double defaultZ);\n\n    // Get the selected horizontal ROI in PCS data coordinates\n    //\n    vector<double> _getPCSExtentsData() const;\n\n    // Transform verts from absolute to local coordinates\n    //\n    void _transformToLocal(size_t width, size_t height, const vector<double> &scaleFac) const;\n\n    void _clearCache() { _cacheHgtVar.clear(); }\n};\n};    // namespace VAPoR\n\n#endif    // TWODRENDERER_H\n"
  },
  {
    "path": "include/vapor/ImageWriter.h",
    "content": "#pragma once\n\n#include <vapor/MyBase.h>\n#include <string>\n\nnamespace VAPoR {\n\nclass ImageWriterFactory;\n\n//! \\class ImageWriter\n//! \\ingroup Public_Render\n//! \\brief Interface for image writers\n//! \\author Stanislaw Jaroszynski\n//!\nclass RENDER_API ImageWriter : public Wasp::MyBase {\npublic:\n    enum class Format { RGB };\n\n    // virtual static std::vector<std::string> GetFileExtensions();\n    virtual int Write(const unsigned char *buffer, const unsigned int width, const unsigned int height) = 0;\n    virtual ~ImageWriter(){};\n\n    static ImageWriter *CreateImageWriterForFile(const std::string &path);\n    static void         RegisterFactory(ImageWriterFactory *factory);\n\nprotected:\n    Format      format;\n    std::string path;\n    bool        opened;\n\n    ImageWriter(const std::string &path);\n\nprivate:\n    static std::vector<ImageWriterFactory *> factories;\n};\n\nclass ImageWriterFactory {\npublic:\n    const std::vector<std::string> Extensions;\n    virtual ImageWriter *          Create(const std::string &path) = 0;\n\nprotected:\n    ImageWriterFactory(std::vector<std::string> extensions) : Extensions(extensions) {}\n};\n\n#define REGISTER_IMAGEWRITER(name)                                                                              \\\n    class name##Factory : public ImageWriterFactory {                                                           \\\n    public:                                                                                                     \\\n        name##Factory() : ImageWriterFactory(name::GetFileExtensions()) { ImageWriter::RegisterFactory(this); } \\\n        virtual ImageWriter *Create(const std::string &path) { return new name(path); }                         \\\n    };                                                                                                          \\\n    static name##Factory registration_##name##Factory;\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/ImpExp.h",
    "content": "//\n//      $Id$\n//\n\n#ifndef _ImpExp_h_\n#define _ImpExp_h_\n\n#include <stack>\n#include <expat.h>\n#include <vapor/MyBase.h>\n#include <vapor/common.h>\n#include <vapor/XmlNode.h>\n#include <vapor/ExpatParseMgr.h>\n#ifdef WIN32\n    #pragma warning(disable : 4251)\n#endif\nnamespace VAPoR {\n\n//\n//! \\class ImpExp\n//! \\brief A class for managing data set metadata\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! The ImpExp class is used to import/export state to/from a VAPoR session\n//!\nclass VDF_API ImpExp : public Wasp::MyBase, public ParsedXml {\npublic:\n    //! Create an Import Export object\n    //!\n    //\n    ImpExp();\n\n    virtual ~ImpExp();\n\n    //! Export a volume subregion description for use by another application\n    //!\n    //! This method exports data set state information to facilitate sharing\n    //! with another application. In particular, the path name of the VDF file,\n    //! a volume time step, a named volume variable, and volumetric region\n    //! of interest are exported. The exported information may be retreive\n    //! via the Import() method\n    //!\n    //! \\note The region bounds are specified relative to the finest\n    //! resolution volume\n    //!\n    //! \\note Presently the medium of exchange is an XML file, the path to\n    //! which is internally hardwired and based on the user's uid.\n    //! Thus it is not possible for applications running under different uid's\n    //! to share data. Furthermore, there exists only one XML file per uid\n    //! on a system. This will undoubtedly change in the future.\n    //!\n    //! \\param[in] path Path to the metadata file\n    //! \\param[in] ts Time step of exported volume\n    //! \\param[in] varname Variable name of exported volume\n    //! \\param[in] min Minimum region extents in voxel coordinates relative\n    //! to the \\b finest resolution\n    //! \\param[in] max Maximum region extents in voxel coordinates relative\n    //! to the \\b finest resolution\n    //! \\param[in] timeseg Time segment range\n    //! \\retval status Returns a non-negative integer on success\n    //! \\sa Import()\n    //\n    int Export(const string &path, size_t ts, const string &varname, const size_t min[3], const size_t max[3], const size_t timeseg[2]);\n\n    //! Import a volume subregion description for use by another application\n    //!\n    //! This method imports data set state information to facilitate sharing\n    //! with another application. In particular, the path name of the VDF file,\n    //! a volume time step, a named volume variable, and volumetric region\n    //! of interest are imported. The imported information is assumed to\n    //! have been generated via the the most recent call to the Export() method.\n    //!\n    //! \\param[out] path Path to the metadata file\n    //! \\param[out] ts Time step of exported volume\n    //! \\param[out] varname Variable name of exported volume\n    //! \\param[out] min Minimum region extents in voxel coordinates relative\n    //! to the \\b finest resolution\n    //! \\param[out] max Maximum region extents in voxel coordinates relative\n    //! to the \\b finest resolution\n    //! \\param[out] timeseg Time segment range\n    //! \\retval status Returns a non-negative integer on success\n    //! \\sa Export()\n    //\n    int           Import(string *path, size_t *ts, string *varname, size_t min[3], size_t max[3], size_t timeseg[2]);\n    static string GetPath();\n\nprivate:\n    int      _objInitialized;    // has the obj successfully been initialized?\n    XmlNode *_rootnode;          // root node of the xml tree\n\n    static const string _rootTag;\n    static const string _pathNameTag;\n    static const string _timeStepTag;\n    static const string _varNameTag;\n    static const string _regionTag;\n    static const string _timeSegmentTag;\n\n    bool elementStartHandler(ExpatParseMgr *, int depth, std::string &tag, const char **attr);\n    bool elementEndHandler(ExpatParseMgr *, int depth, std::string &);\n\n    // XML Expat element handler helpers. A different handler is defined\n    // for each possible state (depth of XML tree) from 0 to 1\n    //\n    void _startElementHandler0(ExpatParseMgr *, const string &tag, const char **attrs);\n    void _startElementHandler1(ExpatParseMgr *, const string &tag, const char **attrs);\n    void _endElementHandler0(ExpatParseMgr *, const string &tag);\n    void _endElementHandler1(ExpatParseMgr *, const string &tag);\n};\n\n};    // namespace VAPoR\n\n#endif    //\t_ImpExp_h_\n"
  },
  {
    "path": "include/vapor/JPGWriter.h",
    "content": "#pragma once\n\n#include \"vapor/ImageWriter.h\"\n#include <stdio.h>\n\nnamespace VAPoR {\nclass RENDER_API JPGWriter : public ImageWriter {\n    FILE *fp;\n\npublic:\n    static int DefaultQuality;\n    int        Quality;\n\n    JPGWriter(const std::string &path);\n    ~JPGWriter();\n\n    static std::vector<std::string> GetFileExtensions();\n    int                             Write(const unsigned char *buffer, const unsigned int width, const unsigned int height);\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/KDTreeRG.h",
    "content": "#ifndef _KDTreeRG_\n#define _KDTreeRG_\n\n#include <ostream>\n#include <vector>\n#include <vapor/Grid.h>\n\n#include \"nanoflann.hpp\"\n\nstruct kdtree;\n\nnamespace VAPoR {\n//\n//! \\class KDTreeRG\n//! \\brief This class implements a k-d space partitioning tree.\n//!\n//! This class provides an object-oriented interface to kdtree.c, which\n//! implements a k-d space partitioning tree.\n//!\n//! \\sa https://en.wikipedia.org/wiki/K-d_tree\n//\nclass VDF_API KDTreeRG {\npublic:\n    //! Construct a 2D k-d tree for a structured grid\n    //!\n    //! Creates a 2D k-d space partitioning tree for a structured grid\n    //! defined by a pair of Grid instances. The data values of  the\n    //! \\p xg and \\p yg\n    //! Grid instances provide the coordinates of all of the points\n    //! to be inserted into the k-d tree.\n    //!\n    //! \\param[in] xg A Grid instance giving the X user coordinates\n    //! for each point in the k-d tree.\n    //! \\param[in] yg A Grid instance giving the Y user coordinates\n    //! for each point in the k-d tree. The \\p xg and \\p yg Grid\n    //! instances must have identical configurations, differing only in their\n    //! data values.\n    //!\n    //! \\sa Grid()\n    //\n    KDTreeRG(const Grid &xg, const Grid &yg);\n\n    //! Construct a 3D k-d tree for a structured grid\n    //!\n    //! Creates a 3D k-d space partitioning tree for a structured grid\n    //!\n    //! \\param[in] xg A Grid instance giving the X user coordinates\n    //! for each point in the k-d tree.\n    //! \\param[in] yg A Grid instance giving the Y user coordinates\n    //! for each point in the k-d tree.\n    //! \\param[in] zg A Grid instance giving the Z user coordinates\n    //! for each point in the k-d tree. The \\p xg, \\p yg, and \\p yg Grid\n    //! instances must have identical configurations, differing only in their\n    //! data values.\n    //!\n    //! \\sa KDTreeRG(const Grid, const Grid)\n    //\n    // KDTreeRG( const Grid &xg, const Grid &yg, const Grid &zg );\n\n    virtual ~KDTreeRG();\n\n    //! Return indecies of nearest point\n    //!\n    //! This method returns the \\a ijk indeces of the grid vertex nearest, by\n    //! measure of Cartesian distance, a specified point. The returned\n    //! indeces may be used to access the \\p xg, \\p yg, and \\p zg\n    //! Grid instances passed into the constructor.\n    //!\n    //! \\param[in] coordu A 2D or 3D vector of user coordinates specifying\n    //! the location of a point in space.\n    //!\n    //! \\param[out] index The \\a ijk indecies of the grid vertex nearest\n    //! \\p coordu.\n    //\n    void Nearest(const std::vector<float> &coordu, std::vector<size_t> &index) const;\n\n    void Nearest(const std::vector<double> &coordu, std::vector<size_t> &index) const\n    {\n        std::vector<float> coordu_f;\n        for (int i = 0; i < coordu.size(); i++) coordu_f.push_back(coordu[i]);\n        this->Nearest(coordu_f, index);\n    }\n\n    //! Returns the dimesionality of the structured grids passed to the\n    //! constructor.\n    //!\n    //! This method returns a two or three element vector containing the\n    //! dimensions of the Grid class instances passed to the\n    //! constructor.\n    //!\n    //! \\retval vector\n    std::vector<size_t> GetDimensions() const { return (_dims); }\n\nprivate:\n    class PointCloud2D {\n    public:\n        // Constructor\n        PointCloud2D(const Grid &xg, const Grid &yg)\n        {\n            VAssert(xg.GetDimensions() == yg.GetDimensions());\n            VAssert(xg.GetNumDimensions() <= 2);\n\n            // number of elements\n            auto   dims = xg.GetDimensions();\n            size_t nelem = 1;\n            for (int i = 0; i < dims.size(); i++) nelem *= dims[i];\n            this->X.resize(nelem);\n            this->Y.resize(nelem);\n\n            // Store the point coordinates in the k-d tree\n            Grid::ConstIterator xitr = xg.cbegin();\n            Grid::ConstIterator yitr = yg.cbegin();\n\n            for (size_t i = 0; i < nelem; ++i, ++xitr, ++yitr) {\n                this->X[i] = *xitr;\n                this->Y[i] = *yitr;\n            }\n        }    // end of the Constructor\n\n        // Must return the number of data points\n        inline size_t kdtree_get_point_count() const\n        {\n            VAssert(X.size() == Y.size());\n            return X.size();\n        }\n\n        // Returns the dim'th component of the idx'th point in the class:\n        // Since this is inlined and the \"dim\" argument is typically an immediate value, the\n        //  \"if/else's\" are actually solved at compile time.\n        inline float kdtree_get_pt(const size_t idx, int dim) const\n        {\n            if (dim == 0)\n                return X[idx];\n            else\n                return Y[idx];\n        }\n\n        // Optional bounding-box computation: return false to default to a standard bbox computation loop.\n        //   Return true if the BBOX was already computed by the class and returned in \"bb\"\n        //   so it can be avoided to redo it again.\n        //   Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)\n        template<class BBOX> bool kdtree_get_bbox(BBOX & /* bb */) const { return false; }\n\n    private:\n        std::vector<float> X, Y;\n\n    };    // end of class PointCloud2D\n\n    typedef nanoflann::KDTreeSingleIndexAdaptor<nanoflann::L2_Simple_Adaptor<float, PointCloud2D>, PointCloud2D, 2 /* dimension */> KDTreeType;\n\n    PointCloud2D        _points;\n    KDTreeType          _kdtree;\n    std::vector<size_t> _dims;\n};    // end of class KDTreeRG.\n\n//! class KDTreeRGSubset\n//! \\brief This class implements a k-d tree for a structured grid over\n//! a reduced region-of-interest (ROI)\n//!\n//! This class provides a k-d tree for a structured grid over an ROI. The\n//! class constructor is passed a pointer to a KDTreeRG instance that\n//! defines a k-d tree over a structured grid. This class can be used\n//! to cull out points outside of an axis-aligned region of interest\n//! specified by \\p min and \\p max. The advantage of using this class\n//! over simply creating a new instance of KDTreeRG is the avoidance\n//! of the cost of rebuilding the k-d tree from scratch.\n//!\nclass VDF_API KDTreeRGSubset {\npublic:\n    KDTreeRGSubset();\n\n    //! Construct a KDTreeRGSubset instance.\n    //!\n    //! Construct a KDTreeRGSubset instance.\n    //!\n    //! \\param[in] kdtreerg A pointer to a KDTreeRG instance. The pointer\n    //! is shallow copied and the referenced contents should remain valid\n    //! until this class instance is destroyed.\n    //!\n    //! \\param[in] min A two or three element vector of \\a ijk coordinate indeces\n    //! of the first grid point defined by \\a xg, \\a yg, and \\a zg.\n    //! \\param[in] max A two or three element vector of \\a ijk coordinate indeces\n    //! of the last grid point defined by \\a xg, \\a yg, and \\a zg.\n    //!\n    //! \\note \\p kdtreerg is shallow copied and the referenced contents\n    //! should remain valid\n    //! until this class instance is destroyed.\n    //\n    KDTreeRGSubset(const KDTreeRG *kdtreerg, const std::vector<size_t> &min, const std::vector<size_t> &max);\n    ~KDTreeRGSubset() {}\n\n    //! Return indecies of nearest point\n    //!\n    //! This method returns the \\a ijk index of the grid vertex nearest, by\n    //! measure of Cartesian distance, a specified point. The returned\n    //! indecies may be used to access the \\p xg, \\p yg, and \\p zg\n    //! Grid instances passed into the constructor used to\n    //! create \\p kdtreerg.\n    //!\n    //! \\param[in] coordu A 2D or 3D vector of user coordinates specifying\n    //! the location of a point in space.\n    //!\n    //! \\param[out] index The \\a ijk indecies of the grid vertex nearest\n    //! \\p coordu.\n    //\n    void Nearest(const std::vector<float> &coordu, std::vector<size_t> &coord) const;\n\n    void Nearest(const std::vector<double> &coordu, std::vector<size_t> &index) const\n    {\n        std::vector<float> coordu_f;\n        for (int i = 0; i < coordu.size(); i++) coordu_f.push_back(coordu[i]);\n        Nearest(coordu_f, index);\n    }\n\n    std::vector<size_t> GetDimensions() const\n    {\n        std::vector<std::size_t> dims;\n        for (int i = 0; i < _min.size(); i++) { dims.push_back(_max[i] - _min[i] + 1); }\n        return (dims);\n    }\n\nprivate:\n    const KDTreeRG *    _kdtree;\n    std::vector<size_t> _min;\n    std::vector<size_t> _max;\n};\n\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/LayeredGrid.h",
    "content": "#ifndef _LayeredGrid_\n#define _LayeredGrid_\n#include <vapor/common.h>\n#include \"RegularGrid.h\"\n#include \"StretchedGrid.h\"\n\nnamespace VAPoR {\n\n//! \\class LayeredGrid\n//!\n//! \\brief This class implements a 2D or 3D layered grid.\n//!\n//! This class implements a 3D layered grid: a generalization\n//! of a stretched grid where the spacing of grid points along the K dimension\n//! varies at each grid point. The spacing along the remaining I and J\n//! dimensions is invariant between grid points. I.e.\n//! z coordinate is given by some\n//! function f(i,j,k):\n//!\n//! z = f(i,j,k)\n//!\n//! where f() is monotonically increasing (or decreasing) with k.\n//! The remaining x and y coordinates are givey by (i*dx, j*dy)\n//! for some real dx and dy .\n//!\n//\nclass VDF_API LayeredGrid : public StructuredGrid {\npublic:\n    //!\n    //! Construct a layered grid sampling a 3D or 2D scalar function\n    //!\n    //! \\copydoc StructuredGrid::StructuredGrid()\n    //!\n    //!\n    //! Adds or changes parameters:\n    //!\n    //! \\param[in] xcoords  A 1D vector whose size matches that of the I\n    //! dimension of this class, and whose values specify the X user coordinates.\n    //! \\param[in] ycoords  A 1D vector whose size matches that of the J\n    //! of the last grid point.\n    //!\n    //! \\param[in] rg A RegularGrid instance with the same dimensionality and\n    //! min/max offsets as specified by \\p bs, \\p min, and \\p max. The\n    //! data values of \\p rg provide the user coordinates for the Z dinmension.\n    //!\n    LayeredGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, const std::vector<double> &xcoords, const std::vector<double> &ycoords, const RegularGrid &rg);\n    LayeredGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<float *> &blks, const std::vector<double> &xcoords, const std::vector<double> &ycoords,\n                const RegularGrid &rg);\n\n    LayeredGrid() = default;\n    virtual ~LayeredGrid() = default;\n\n    virtual size_t GetGeometryDim() const override { return (3); }\n\n    virtual DimsType GetCoordDimensions(size_t dim) const override;\n\n    static std::string GetClassType() { return (\"Layered\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    //! \\copydoc RegularGrid::GetValue()\n    //!\n    float GetValue(const CoordType &coords) const override;\n\n    //! \\copydoc Grid::GetInterpolationOrder()\n    //\n    virtual int GetInterpolationOrder() const override { return _interpolationOrder; };\n\n    //! Set the interpolation order to be used during function reconstruction\n    //!\n    //! This method sets the order of the interpolation method that will\n    //! be used when reconstructing the sampled scalar function. Valid values\n    //! of \\p order are 0,  1, and 2, corresponding to nearest-neighbor,linear,\n    //! and quadratic\n    //! interpolation, respectively. If \\p order is invalid it will be silently\n    //! set to 2. The default interpolation order is 1\n    //!\n    //! \\param[in] order interpolation order\n    //! \\sa GetInterpolationOrder()\n    //!\n    virtual void SetInterpolationOrder(int order) override;\n\n    //! \\copydoc Grid::GetBoundingBox()\n    //!\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override;\n\n    //! \\copydoc Grid::GetUserCoordinates()\n    //!\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override;\n\n    // For grandparent inheritance of\n    // Grid::GetUserCoordinates(const size_t indices[], double coords[])\n    //\n    using Grid::GetUserCoordinates;\n\n    //! \\copydoc Grid::GetIndicesCell\n    //!\n    virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override;\n\n    // For grandparent inheritance of\n    // Grid::GetIndicesCell(const double coords[3], size_t indices[3])\n    //\n    using Grid::GetIndicesCell;\n\n    //! \\copydoc Grid::InsideGrid()\n    //!\n    bool InsideGrid(const CoordType &coords) const override;\n\n    //! \\copydoc Grid::GetPeriodic()\n    //!\n    //! Only horizonal dimensions can be periodic. Layered (third) dimension\n    //! is ignored if set to periodic\n    //\n    virtual void SetPeriodic(const std::vector<bool> &periodic) override\n    {\n        VAssert(periodic.size() == 3);\n        std::vector<bool> myPeriodic = periodic;\n        myPeriodic[2] = false;\n        Grid::SetPeriodic(myPeriodic);\n    }\n\n    //! Return the internal data structure containing a copy of the coordinate\n    //! blocks passed in by the constructor\n    //!\n    const RegularGrid &GetZRG() const { return (_zrg); };\n\n    class ConstCoordItrLayered : public Grid::ConstCoordItrAbstract {\n    public:\n        ConstCoordItrLayered(const LayeredGrid *rg, bool begin);\n        ConstCoordItrLayered(const ConstCoordItrLayered &rhs);\n\n        ConstCoordItrLayered();\n        virtual ~ConstCoordItrLayered() {}\n\n        virtual void            next();\n        virtual void            next(const long &offset);\n        virtual ConstCoordType &deref() const { return (_coords); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const\n        {\n            const ConstCoordItrLayered *itrptr = static_cast<const ConstCoordItrLayered *>(rhs);\n\n            return (_zCoordItr == itrptr->_zCoordItr);\n        }\n\n        virtual std::unique_ptr<ConstCoordItrAbstract> clone() const { return std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrLayered(*this)); };\n\n    private:\n        const LayeredGrid *          _lg;\n        size_t                       _nElements2D;\n        CoordType                    _coords;\n        size_t                       _index2D;\n        ConstIterator                _zCoordItr;\n        StretchedGrid::ConstCoordItr _itr2D;\n    };\n\n    virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrLayered(this, true))); }\n    virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrLayered(this, false))); }\n\nprotected:\n    //! \\copydoc Grid::GetUserExtents()\n    //!\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override;\n\nprivate:\n    StretchedGrid       _sg2d;    // horizontal coordinates maintained in stretched grid\n    RegularGrid         _zrg;     // vertical coords are the values of a regular grid\n    std::vector<double> _xcoords;\n    std::vector<double> _ycoords;\n    CoordType           _minu = {{0.0, 0.0, 0.0}};\n    CoordType           _maxu = {{0.0, 0.0, 0.0}};\n    int                 _interpolationOrder;\n\n    void _layeredGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, const std::vector<double> &xcoords, const std::vector<double> &ycoords, const RegularGrid &rg);\n\n    virtual float GetValueNearestNeighbor(const CoordType &coords) const override;\n\n    virtual float GetValueLinear(const CoordType &coords) const override;\n\n    //!\n    //! Return the bilinear interpolation weights of a point given in user\n    //! coordinates.  These weights apply to the x (iwgt) and y (jwgt) axes.\n    //!\n    //! This function applies the bilinear interpolation method to derive\n    //! a the x and y axis weights of a point in user coordinates.\n    //!\n    //! \\param[in] x coordinate of grid point along fastest varying dimension\n    //! \\param[in] y coordinate of grid point along second fastest\n    //! varying dimension\n    //! \\param[out] a bilinearly calculated weight for the x axis\n    //! \\param[out] a bilinearly calculated weight for the y axis\n    //\n    void _getBilinearWeights(const double coords[3], double &iwgt, double &jwgt) const;\n\n    //! This function applies the bilinear interpolation method to derive\n    //! a the elevation from x and y axis weights of a point in user coordinates.\n    //!\n    //! \\param[in] i index of bottom left cell corner\n    //! \\param[in] i index of top right cell corner\n    //! \\param[in] j index of bottom left cell corner\n    //! \\param[in] j index of top right cell corner\n    //! \\param[in] k index of the level to interpolate upon\n    //! \\param[in] the i-axis weight for bilinear interpolation\n    //! \\param[in] the j-axis weight for bilinear interpolation\n    //! \\param[out] a bilinearly calculated elevation value\n\n    double _bilinearElevation(size_t i0, size_t i1, size_t j0, size_t j1, size_t k0, double iwgt, double jwgt) const;\n\n    //! double _bilinearInterpolation(double x, double y, size_t k,\n    //!\t\t\t\t\t\tdouble *iwgt, double *jwgt) const;\n    //!\n    //! Return the bilinearly interpolated value of the currently opened variable\n    //! of a point given in user coordinates.\n    //!\n    //! This function applies the bilinear interpolation method to derive\n    //! a variable value from x and y axis weights of a point in user coordinates.\n    //!\n    //! \\param[in] i index of bottom left cell corner\n    //! \\param[in] i index of top right cell corner\n    //! \\param[in] j index of bottom left cell corner\n    //! \\param[in] j index of top right cell corner\n    //! \\param[in] k index of the level to interpolate upon\n    //! \\param[in] the i-axis weight for bilinear interpolation\n    //! \\param[in] the j-axis weight for bilinear interpolation\n    //! \\param[out] a bilinearly calculated value of the currently open variable\n    double _bilinearInterpolation(size_t i0, size_t i1, size_t j0, size_t j1, size_t k0, double iwgt, double jwgt) const;\n\n    //! Return the interpolated value of a point in user\n    //! coordinates.  This only interpolates in the vertical (z) direction.\n    //!\n    //! Return the quadratically interpolated value of a point in user\n    //! coordinates.\n    //!\n    //! This function applies the quadratic interpolation method to derive\n    //! a the value of a variable in user coordinates from its neighboring\n    //! points in ijk space.  Linear interpolation is applied at the boundaries\n    //! of the domain.\n    //!\n    //! \\param[in] x coordinate of grid point along fastest varying dimension\n    //! \\param[in] y coordinate of grid point along second fastest\n    //! varying dimension\n    //! \\param[in] z coordinate of grid point along third fastest\n    //! varying dimension\n    //! \\param[out] a quadratically interpolated value of a point in user\n    //! coordinates\n    //!\n    float _getValueQuadratic(const double coords[3]) const;\n\n    //! Return the linearly interpolated value of a point in user\n    //! coordinates.  This only interpolates in the vertical (z) direction.\n    //!\n    //! \\param[in] x coordinate of grid point along fastest varying dimension\n    //! \\param[in] y coordinate of grid point along second fastest\n    //! varying dimension\n    //! \\param[in] z coordinate of grid point along third fastest\n    //! varying dimension\n    //! \\param[out] a linearly interpolated value of a point in user\n    //! coordinates.\n    //!\n    double _verticalLinearInterpolation(double x, double y, double z) const;\n\n    double _interpolateVaryingCoord(size_t i0, size_t j0, size_t k0, double x, double y) const;\n\n    bool _insideGrid(const CoordType &coords, DimsType &indices, double wgts[3]) const;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/LegacyGL.h",
    "content": "#pragma once\n\n#include <vector>\n#include <glm/fwd.hpp>\n#include <vapor/Texture.h>\n\n#ifdef GL_QUADS\n    #define LGL_QUADS GL_QUADS\n#else\n    #define LGL_QUADS 105999\n#endif\n\nnamespace VAPoR {\n\nstruct GLManager;\n\n//! \\class LegacyGL\n//! \\ingroup Public_Render\n//!\n//! \\brief Replements Legacy OpenGL API using OpenGL Core\n//!\n//! This class should not be used for any intensive rendering\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date   August, 2018\n\nclass RENDER_API LegacyGL {\n#pragma pack(push, 4)\n    struct VertexData {\n        float x, y, z;\n        float nx, ny, nz;\n        float r, g, b, a;\n        float s, t;\n    };\n#pragma pack(pop)\n\n    GLManager *             _glManager;\n    std::vector<VertexData> _vertices;\n    unsigned int            _mode;\n    bool                    _emulateQuads;\n    bool                    _firstQuadTriangle;\n    unsigned int            _VAO, _VBO;\n    float                   _nx, _ny, _nz;\n    float                   _r, _g, _b, _a;\n    float                   _s, _t;\n    bool                    _initialized, _insideBeginEndBlock;\n    bool                    _lightingEnabled, _textureEnabled;\n    float                   _lightDir[3];\n    Texture2D               _emptyTexture;\n\npublic:\n    LegacyGL(GLManager *glManager);\n    ~LegacyGL();\n    void Initialize();\n    void Begin(unsigned int mode);\n    void End();\n    void Vertex(glm::vec2);\n    void Vertex(glm::vec3);\n    void Vertex2f(float x, float y);\n    void Vertex3f(float x, float y, float z);\n    void Vertex3fv(const float *v);\n    void Vertex3dv(const double *v);\n    void Normal3f(float x, float y, float z);\n    void Normal3fv(const float *n);\n    void Color(glm::vec3);\n    void Color(glm::vec4);\n    void Color3f(float r, float g, float b);\n    void Color3fv(const float *f);\n    void Color4f(float r, float g, float b, float a);\n    void Color4fv(const float *f);\n    void TexCoord(glm::vec2);\n    void TexCoord2f(float s, float t);\n\n    void EnableLighting();\n    void DisableLighting();\n    void LightDirectionfv(const float *f);\n    void EnableTexture();\n    void DisableTexture();\n\n    // void PushAttrib(int flag);\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/LegacyVectorMath.h",
    "content": "#pragma once\n\n#ifndef INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n    #error LegacyVectorMath.h is deprecated. Please dont use unless necessary\n#endif\n\n#include <vapor/common.h>\n#include <vector>\n#include <math.h>\n#include <cstddef>\n\nnamespace VAPoR {\n\nCOMMON_API bool   powerOf2(size_t n);\nCOMMON_API size_t nextPowerOf2(size_t n);\n\nCOMMON_API void computeGradientData(int dim[3], int numChan, unsigned char *volume, unsigned char *gradient);\nCOMMON_API void makeModelviewMatrix(float *vpos, float *vdir, float *upvec, float *matrix);\nCOMMON_API void makeModelviewMatrixD(double *vpos, double *vdir, double *upvec, double *matrix);\nCOMMON_API void makeModelviewMatrixD(const std::vector<double> &vpos, const std::vector<double> &vdir, const std::vector<double> &upvec, double *matrix);\nCOMMON_API void makeTransMatrix(float *transVec, float *matrix);\nCOMMON_API void makeTransMatrix(double *transVec, double *matrix);\nCOMMON_API void makeTransMatrix(const std::vector<double> &transVec, double *matrix);\nCOMMON_API void makeScaleMatrix(const double *scaleVec, double *matrix);\nCOMMON_API void vscale(float *v, float s);\nCOMMON_API void vscale(double *v, double s);\nCOMMON_API void vscale(std::vector<double> v, double s);\nCOMMON_API void vmult(const float *v, float s, float *w);\nCOMMON_API void vmult(const double *v, double s, double *w);\nCOMMON_API void vhalf(const float *v1, const float *v2, float *half);\nCOMMON_API void vcross(const float *v1, const float *v2, float *cross);\nCOMMON_API void vcross(const double *v1, const double *v2, double *cross);\nCOMMON_API void vreflect(const float *in, const float *mirror, float *out);\nCOMMON_API void vtransform(const float *v, float *mat, float *vt);\nCOMMON_API void vtransform(const float *v, float *mat, double *vt);\nCOMMON_API void vtransform(const double *v, float *mat, double *vt);\nCOMMON_API void vtransform(const double *v, double *mat, double *vt);\nCOMMON_API void vtransform4(const float *v, float *mat, float *vt);\nCOMMON_API void vtransform3(const float *v, float *mat, float *vt);\nCOMMON_API void vtransform3(const double *v, double *mat, double *vt);\nCOMMON_API void vtransform3t(const float *v, float *mat, float *vt);\nCOMMON_API bool pointOnRight(double *pt1, double *pt2, const double *testPt);\nCOMMON_API void mcopy(float *m1, float *m2);\nCOMMON_API void mcopy(double *m1, double *m2);\nCOMMON_API void mmult(float *m1, float *m2, float *prod);\nCOMMON_API void mmult(double *m1, double *m2, double *prod);\nCOMMON_API int  minvert(const float *mat, float *result);\nCOMMON_API int  minvert(const double *mat, double *result);\n\n// Some routines to handle 3x3 rotation matrices, represented as 9 floats,\n// where the column index increments faster (like in 4x4 case\nCOMMON_API void mmult33(const double *m1, const double *m2, double *result);\n\n// Same as above, but use the transpose (i.e. inverse for rotations) on the left\nCOMMON_API void mmultt33(const double *m1Trans, const double *m2, double *result);\n\n// Determine a rotation matrix from (theta, phi, psi) (radians), that is,\n// find the rotation matrix that first rotates in (x,y) by psi, then takes the vector (0,0,1)\n// to the vector with direction (theta,phi) by rotating by phi in the (x,z) plane and then\n// rotating in the (x,y)plane by theta.\nCOMMON_API void getRotationMatrix(double theta, double phi, double psi, double *matrix);\n\n// Determine a rotation matrix about an axis:\nCOMMON_API void getAxisRotation(int axis, double rotation, double *matrix);\n\n// Determine the psi, phi, theta from a rotation matrix:\nCOMMON_API void getRotAngles(double *theta, double *phi, double *psi, const double *matrix);\nCOMMON_API int  rayBoxIntersect(const float rayStart[3], const float rayDir[3], const float boxExts[6], float results[2]);\nCOMMON_API int  rayBoxIntersect(const double rayStart[3], const double rayDir[3], const double boxExts[6], double results[2]);\n// Determine the minimum and maximum projection of box corners to ray\nCOMMON_API void rayBoxProject(std::vector<double> rayStart, std::vector<double> rayDir, const double boxExts[6], double results[2]);\n\nCOMMON_API void  qnormal(float *q);\nCOMMON_API void  qinv(const float q1[4], float q2[4]);\nCOMMON_API void  qmult(const float *q1, const float *q2, float *dest);\nCOMMON_API void  qmult(const double *q1, const double *q2, double *dest);\nCOMMON_API void  qmatrix(const float *q, float *m);\nCOMMON_API void  qmatrix(const double *q, double *m);\nCOMMON_API float ProjectToSphere(float r, float x, float y);\nCOMMON_API void  CalcRotation(float *q, float newX, float newY, float oldX, float oldY, float ballsize);\nCOMMON_API void  CalcRotation(double *q, double newX, double newY, double oldX, double oldY, double ballsize);\nCOMMON_API float ScalePoint(long pt, long origin, long size);\nCOMMON_API void  rvec2q(const float rvec[3], float radians, float q[4]);\nCOMMON_API void  rvec2q(const double rvec[3], double radians, double q[4]);\nCOMMON_API void  rotmatrix2q(float *m, float *q);\nCOMMON_API void  rotmatrix2q(double *m, double *q);\nCOMMON_API float getScale(float *rotmatrix);\nCOMMON_API void  view2Quat(float vdir[3], float upvec[3], float q[4]);\nCOMMON_API void  quat2View(float quat[4], float vdir[3], float upvec[3]);\nCOMMON_API void  qlog(float quat[4], float lquat[4]);\nCOMMON_API void  qconj(float quat[4], float conj[4]);\n\nCOMMON_API void slerp(float quat1[4], float quat2[4], float t, float result[4]);\nCOMMON_API void squad(float quat1[4], float quat2[4], float s1[4], float s2[4], float t, float result[4]);\n\nCOMMON_API void imagQuat2View(const float q[3], float vdir[3], float upvec[3]);\n\nCOMMON_API void views2ImagQuats(float vdir1[3], float upvec1[3], float vdir2[3], float upvec2[3], float q1[3], float q2[3]);\n\ninline void vset(float *a, const float x, const float y, const float z)\n{\n    a[0] = x;\n    a[1] = y;\n    a[2] = z;\n}\ninline void vset(double *a, const double x, const double y, const double z)\n{\n    a[0] = x;\n    a[1] = y;\n    a[2] = z;\n}\ninline float  vdot(const float *a, const float *b) { return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]); }\ninline float  vdot(const float *a, const double *b) { return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]); }\ninline double vdot(const double *a, const double *b) { return (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]); }\ninline float  vlength(const float *a) { return sqrt(vdot(a, a)); }\ninline double vlength(const double *a) { return sqrt(vdot(a, a)); }\ninline double vlength(const std::vector<double> a) { return sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); }\ninline float  vdist(const float *a, const float *b) { return (sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]))); }\ninline double vdist(const double *a, const double *b) { return (sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]))); }\ninline void   vnormal(float *a) { vscale(a, 1 / vlength(a)); }\ninline void   vnormal(double *a) { vscale(a, 1 / vlength(a)); }\ninline void   vnormal(std::vector<double> a) { vscale(a, 1. / vlength(a)); }\ninline void   vcopy(const float *a, float *b)\n{\n    b[0] = a[0];\n    b[1] = a[1];\n    b[2] = a[2];\n}\ninline void vcopy(const double *a, double *b)\n{\n    b[0] = a[0];\n    b[1] = a[1];\n    b[2] = a[2];\n}\ninline void vsub(const double *a, const float *b, float *c)\n{\n    c[0] = a[0] - b[0];\n    c[1] = a[1] - b[1];\n    c[2] = a[2] - b[2];\n}\ninline void vsub(const float *a, const float *b, float *c)\n{\n    c[0] = a[0] - b[0];\n    c[1] = a[1] - b[1];\n    c[2] = a[2] - b[2];\n}\ninline void vsub(const double *a, const double *b, double *c)\n{\n    c[0] = a[0] - b[0];\n    c[1] = a[1] - b[1];\n    c[2] = a[2] - b[2];\n}\ninline void vsub(const double *a, const std::vector<double> b, double *c)\n{\n    c[0] = a[0] - b[0];\n    c[1] = a[1] - b[1];\n    c[2] = a[2] - b[2];\n}\ninline void vsub(const std::vector<double> &a, const std::vector<double> &b, double *c)\n{\n    c[0] = a[0] - b[0];\n    c[1] = a[1] - b[1];\n    c[2] = a[2] - b[2];\n}\ninline void vadd(const float *a, const float *b, float *c)\n{\n    c[0] = a[0] + b[0];\n    c[1] = a[1] + b[1];\n    c[2] = a[2] + b[2];\n}\ninline void vadd(const double *a, const double *b, double *c)\n{\n    c[0] = a[0] + b[0];\n    c[1] = a[1] + b[1];\n    c[2] = a[2] + b[2];\n}\ninline void vzero(float *a) { a[0] = a[1] = a[2] = 0.f; }\ninline void vzero(double *a) { a[0] = a[1] = a[2] = 0.; }\ninline void qset(float *a, float x, float y, float z, float w)\n{\n    a[0] = x;\n    a[1] = y;\n    a[2] = z;\n    a[3] = w;\n}\ninline void qcopy(const float *a, float *b)\n{\n    b[0] = a[0];\n    b[1] = a[1];\n    b[2] = a[2];\n    b[3] = a[3];\n}\ninline void qcopy(const double *a, double *b)\n{\n    b[0] = a[0];\n    b[1] = a[1];\n    b[2] = a[2];\n    b[3] = a[3];\n}\ninline void qzero(float *a)\n{\n    a[0] = a[1] = a[2] = 0;\n    a[3] = 1;\n}\ninline void qzero(double *a)\n{\n    a[0] = a[1] = a[2] = 0.;\n    a[3] = 1.;\n}\ninline void  qadd(const float *a, const float *b, float *c) { vadd(a, b, c), c[3] = a[3] + b[3]; }\ninline float qlength(const float q[4]) { return sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]); }\n\n// Forward declarations for utility functions.\n// These should really go in glutil!\n\nint    matrix4x4_inverse(const float *in, float *out);\nvoid   matrix4x4_vec3_mult(const float m[16], const float a[4], float b[4]);\nvoid   adjoint(const float *in, float *out);\ndouble det4x4(const float m[16]);\ndouble det2x2(double a, double b, double c, double d);\ndouble det3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3);\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/MapperFunction.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tMapperFunction.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tAugust 2005\n//\n//\tDescription:\tDefines the MapperFunction class\n//\t\tThis is the mathematical definition of a function\n//\t\tthat can be used to map data to either colors or opacities\n//\t\tSubclasses can either implement color or transparency\n//\t\tmapping (or both), and/or identify one or more isovalues.\n\n#ifndef MAPPERFUNCTION_H\n#define MAPPERFUNCTION_H\n\n#include <vapor/OpacityMap.h>\n#include <vapor/ColorMap.h>\n#include <vapor/TFInterpolator.h>\n#include <vapor/ParamsBase.h>\n\nnamespace VAPoR {\n\nclass XmlNode;\nclass ParamNode;\n\n//! \\class MapperFunction\n//! \\brief Parent class for TransferFunction and IsoControl,\n//! supports positioning histogram over color/opacity maps as well as\n//! a set of isovalues (as with Contours)\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date January 2016\nclass PARAMS_API MapperFunction : public ParamsBase {\npublic:\n    MapperFunction(ParamsBase::StateSave *ssave);\n\n    MapperFunction(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    MapperFunction(const MapperFunction &rhs);\n\n    MapperFunction &operator=(const MapperFunction &rhs);\n\n    virtual ~MapperFunction();\n\n    //! Save this transfer function to a file\n    //! \\param[in] path Path of output file\n    //\n    int SaveToFile(string path);\n\n    //! Load a transfer function from a file,\n    //! \\param[in] path Path of input file\n    //\n    int LoadFromFile(string path);\n\n    int LoadColormapFromFile(string path);\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"MapperFunctionParams\"); }\n\n    //! Determine the opacity value at a particular data value\n    //! \\param[in] point float data value\n    float getOpacityValueData(float point) const;\n\n    //! Determine the color value (in HSV) at a data point\n    //! \\param[in] point Data value\n    //! \\param[out] h Hue\n    //! \\param[out] sat Saturation\n    //! \\param[out] val Value\n    void hsvValue(float point, float *h, float *sat, float *val) const;\n\n    //! Determine the color value (in RGB) at a data point\n    //! \\param[in] point Data value\n    //! \\param[out] rgb r,g,b floats\n    void rgbValue(float point, float rgb[3]) const\n    {\n        float hsv[3];\n        hsvValue(point, hsv, hsv + 1, hsv + 2);\n        hsvToRgb(hsv, rgb);\n    }\n\n    //! Determine the color (in RGB)  and opacity at a data point\n    //! \\param[in] point Data value\n    //! \\param[out] rgb r,g,b, afloats\n    void rgbaValue(float point, float rgba[4]) const\n    {\n        float hsv[3];\n        hsvValue(point, hsv, hsv + 1, hsv + 2);\n        hsvToRgb(hsv, rgba);\n        rgba[3] = getOpacityValueData(point);\n    }\n\n    //! Make the opacity map completely opaque (opacity 1)\n    void setOpaque();\n\n    //! Determine if the map is totally opaque (opacity 1)\n    //! \\return true if opaque.\n    bool isOpaque() const;\n\n    //! Build a color/opacity lookup table.\n    //! Caller must supply an array to be filled in.\n    //! Each entry isa 4-tuple: r,g,b,opacity.\n    //! \\param[out] clut lookup table of size _numEntries*4\n    void makeLut(float *clut) const;\n\n    void makeLut(std::vector<float> &clut) const;\n    std::vector<float> makeLut() const;\n\n    //! Obtain minimum mapping (histo) value\n    //! \\return Minimum mapping value\n    float getMinMapValue() const { return (getMinMaxMapValue()[0]); };\n\n    //! Obtain maximum mapping (histo) value\n    //! \\return Maximum mapping value\n    float getMaxMapValue() const { return (getMinMaxMapValue()[1]); };\n\n    //! Set both minimum and maximum mapping (histo) values\n    //! \\param[in] val1 minimum value\n    //! \\param[in] val2 maximum value\n    void setMinMaxMapValue(float val1, float val2);\n\n    void setMinMapValue(float val) { setMinMaxMapValue(val, getMaxMapValue()); }\n\n    void setMaxMapValue(float val) { setMinMaxMapValue(getMinMapValue(), val); }\n\n    //! Obtain min and max mapping (histo) values\n    //! \\return minimum and maximum as a 2-vector of doubles\n    vector<double> getMinMaxMapValue() const;\n\n    //! Returns size 2 vector of the users custom slider range. Used by TFMappingRangeSelector\n    vector<double> GetCustomMappingSliderRange() const;\n    bool           IsUsingCustomMappingSliderRange() const;\n\n    //! Set the size 2 vector of the users custom slider range. Used by TFMappingRangeSelector\n    void SetCustomMappingSliderRange(const vector<double> &range);\n    void SetUsingCustomMappingSliderRange(bool b);\n\n    //! Create an opacity map for this transfer function\n    //! \\param[in] type of opacity map\n    virtual OpacityMap *createOpacityMap(OpacityMap::Type type = OpacityMap::CONTROL_POINT);\n\n    //! Delete an opacity map from this transfer function\n    //! \\param[in] omap Pointer to map to delete\n    //\n    void DeleteOpacityMap(const OpacityMap *omap);\n\n    //! Obtain the opacity map associated with an index.\n    //! specified index identifies which of the opacity maps is requested.\n    //! \\param[in] index Opacity map index of desired map.\n    virtual OpacityMap *GetOpacityMap(int index) const;\n\n    //! Determine how many opacity maps are available\n    //! \\return number of opacity maps\n    int getNumOpacityMaps() const { return (m_opacityMaps->Size()); };\n\n    //! Specify an opacity scale factor applied to all opacity maps\n    //! \\param[in] val opacity scale factor\n    void setOpacityScale(double val) { SetValueDouble(_opacityScaleTag, \"Set Opacity Scale\", val); }\n\n    //! Identify the current opacity scale factor\n    //! \\return current opacity scale factor\n    double getOpacityScale() const { return GetValueDouble(_opacityScaleTag, 1.0); }\n\n    //! Opacity composition types\n    enum CompositionType { ADDITION = 0, MULTIPLICATION = 1 };\n\n    //! Specify the type of opacity composition (ADDITION or MULTIPLICATION)\n    //! \\param[in] t CompositionType\n    void setOpacityComposition(CompositionType t) { SetValueLong(_opacityCompositionTag, \"Set Opacity Composition Type\", (long)t); }\n\n    //! Obtain the type of opacity composition (ADDITION or MULTIPLICATION)\n    //! \\return CompositionType\n    CompositionType getOpacityComposition() const { return (CompositionType)GetValueLong(_opacityCompositionTag, ADDITION); }\n\n    //! Utility method converts HSV to RGB\n    //! \\param[in] hsv (HSV as float[3] array)\n    //! \\param[out] rgb (RGB as float[3] array)\n    static void hsvToRgb(float *hsv, float *rgb);\n\n    //! Utility method converts RGB to HSV\n    //! \\param[in] rgb (RGB as float[3] array)\n    //! \\param[out] hsv (HSV as float[3] array)\n    static void rgbToHsv(float *rgb, float *hsv);\n    static vector<float> rgbToHsv(vector<float> rgb);\n\n    //! Obtain the number of entries in the color/opacity map\n    //! \\return number of entries\n    int getNumEntries() const { return _numEntries; }\n\n    //! Map and quantize a real value to the corresponding table index\n    //! i.e., quantize to current Mapper function domain\n    //! \\param[in] point value to be quantized\n    //! \\return quantized value in [0,_numEntries-1]\n    int mapFloatToIndex(float point) const\n    {\n        int indx = mapPosition(point, getMinMapValue(), getMaxMapValue(), _numEntries - 1);\n        if (indx < 0) indx = 0;\n        if (indx > _numEntries - 1) indx = _numEntries - 1;\n        return indx;\n    }\n\n    //! Determine float value associated with index\n    //! \\param[in] indx index (between 0 and _numEntries)\n    //! \\return corresponding float value\n    float mapIndexToFloat(int indx) const { return (float)(getMinMapValue() + ((float)indx) * (float)(getMaxMapValue() - getMinMapValue()) / (float)(_numEntries - 1)); }\n\n    //! Obtain the color interpolation type\n    //! \\return TFInterpolator::type color interpolation type\n    TFInterpolator::type getColorInterpType()\n    {\n        ColorMap *cmap = GetColorMap();\n        if (cmap) return cmap->GetInterpType();\n        return TFInterpolator::diverging;\n    }\n\n    //! Specify the color interpolation type\n    //! \\param[in] t color interpolation type\n    void setColorInterpType(TFInterpolator::type t)\n    {\n        ColorMap *cmap = GetColorMap();\n        if (cmap) cmap->SetInterpType(t);\n    }\n\n    void setUseWhitespace(int state)\n    {\n        ColorMap *cmap = GetColorMap();\n        if (cmap) cmap->SetUseWhitespace(state);\n    }\n\n    int getUseWhitespace() const\n    {\n        ColorMap *cmap = GetColorMap();\n        return cmap->GetUseWhitespace();\n    }\n\n    //! Method to get the Color Map from the Mapper Function\n    //! \\return ColorMap pointer to the Color Map\n    virtual ColorMap *GetColorMap() const { return (m_colorMap); }\n\n    //! Method to get the state of the automatic histogram\n    //! update setting.\n    //! \\return The state of the autoUpdateHisto checkbox\n    //\n    bool GetAutoUpdateHisto() { return ((bool)GetValueLong(_autoUpdateHistoTag, (int)false)); }\n\n    //! Method to set the state of the automatic histogram\n    //! update setting.\n    //! \\param[in] State of the autoUpdateHisto setting\n    //\n    void SetAutoUpdateHisto(bool val) { SetValueLong(_autoUpdateHistoTag, \"enable/disable auto update of histogram\", val); }\n\n    //! Method to get the state of whether the current mapper function\n    //! applies color through a primary variable or secondary variable.\n    //! For example, Barbs may have a \"Color Mapped Variable\" that colors\n    //! the barbs according to a \"Secondary variable\", independent of\n    //! the vector variables that define the Barbs.  Isosurfaces can have\n    //! Secondary Variable colorings too.\n    //!\n    bool GetSecondaryVarMapper() { return ((bool)GetValueLong(_autoUpdateHistoTag, (int)false)); }\n\n    //! Method to set the state of whether the current mapper function\n    //! applies color through a ColorMappedVariable, or a renderer's primary\n    //! variable.\n    //! \\param[in] State of the Secondary Variable color setting\n    //\n    void SetSecondaryVarMapper(bool val) { SetValueLong(_secondaryVarMapperTag, \"Apply color through a secondary color\", val); }\n\npublic:\n    //\n    // XML tags\n    //\n    static const string _dataBoundsTag;\n    static const string _opacityCompositionTag;\n    static const string _opacityScaleTag;\n    static const string _opacityMapsTag;\n    static const string _opacityMapTag;\n    static const string _autoUpdateHistoTag;\n    static const string _secondaryVarMapperTag;\n    static const string CustomMappingSliderRangeTag;\n    static const string IsUsingCustomMappingSliderRangeTag;\n\nprivate:\n    //\n    // Size of lookup table.  Always 1<<8 currently!\n    //\n    const int _numEntries;\n\n    ParamsContainer *m_opacityMaps;\n    ColorMap *       m_colorMap;\n\n    //!\n    //! Map a point to the specified range, and quantize it.\n    //! \\param[in] x point value\n    //! \\param[in] minvalue minimum value\n    //! \\param[in] maxValue maximum value\n    //!\n    static int mapPosition(float x, float minValue, float maxValue, int hSize);\n\n    // Construct name for new parent of opac map node, unique for this instance;\n    string getNewOpacMapTag(int *tagIndex);\n\n    // Construct a map tag for a specific index\n    string getOpacMapTag(int index) const;\n\n    // Extract the index from the opacity map tag\n    int getOpacMapNum(string tag);\n\n    string _make_omap_name(int index) const;\n};\n\n#ifdef VAPOR3_0_0_ALPHA\n\n//! \\class MFContainer\n//! \\brief A simple container class for managing a collection\n//! of MapperFunctions, typically each associated with a different\n//! variable.\n//!\n//! \\author John Clyne\n//! \\date February 2016\nclass PARAMS_API MFContainer : public MyBase {\npublic:\n    MFContainer();\n\n    //! Construct an empty container.\n    //!\n    //! \\param[in] p A pointer to the RenderParams that will\n    //! store the subsequent collection.\n    //! \\param[in] tag Name to give the collection\n    //!\n    //! \\sa ParamsBase::SetParamsBase()\n    //\n    MFContainer(RenderParams *p, string tag);\n\n    ~MFContainer();\n\n    //! Insert a MapperFunction in the collection\n    //!\n    //! This method inserts the MapperFunction \\p mf into the\n    //! collection and gives it the name specified by \\p name\n    //\n    void Insert(string name, MapperFunction *mf);\n\n    //! Return the named MapperFunction\n    //!\n    //! This method returns the MapperFunction named by \\p name, if it\n    //! exists. Otherwise it returns NULL. No error is generated\n    //!\n    MapperFunction *GetMF(string name) const;\n\n    //! Remove all elements from list\n    //\n    void Clear();\n\n    //! Erase the named MapperFunction\n    //\n    void Erase(string name);\n\n    //! Return a list of names of all of the MapperFunctions\n    //\n    vector<string> GetNames() const;\n\nprivate:\n    RenderParams *_params;\n    string        _tag;\n};\n#endif\n\n};        // namespace VAPoR\n#endif    // MAPPERFUNCTION_H\n"
  },
  {
    "path": "include/vapor/MatWaveBase.h",
    "content": "#ifndef _MatWaveBase_h_\n#define _MatWaveBase_h_\n\n#include <string>\n#include \"WaveFiltBase.h\"\n\nusing namespace std;\n\nnamespace VAPoR {\n\n//\n//! \\class MatWaveBase\n//! \\brief A base class for a Matlab-like wavelet bank\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! The MatWaveBase class is a base class for building Matlab-inspired\n//! wavelet filter banks. In many cases the methods provided behave\n//! similarly - in some cases indentically - to the Matlab Wavelet Toolbox\n//! version 4 command of the same name.\n//!\nclass WASP_API MatWaveBase : public Wasp::MyBase {\npublic:\n    //! \\enum dwtmode_t\n    //! Enumerated boundary extension modes\n    //!\n    enum dwtmode_t { INVALID = -1, ZPD, SYMH, SYMW, ASYMH, ASYMW, SP0, SP1, PPD, PER };\n\n    //! Create a wavelet filter bank\n    //!\n    //! \\param[in] wname Name of wavelet.\n    //! \\param[in] mode The boundary extension mode.\n    //!\n    //! \\sa dwtmode()\n    //!\n    MatWaveBase(const string &wname, const string &mode);\n    MatWaveBase(const string &wname);\n    virtual ~MatWaveBase();\n\n    //! Set the discrete wavelet extension transform mode\n    //!\n    //! \\param[in] mode Valid values for mode are: \"zpd\", \"symh\", \"symw\",\n    //! \"asymh\", \"asymw\", \"sp0\", \"sp1\",\n    //! \"spd\", \"ppd\", and \"per\".\n    //!\n    //! \\retval status a non-negative int is returned on success\n    //!\n    int dwtmode(const string &mode);\n\n    //! Set the discrete wavelet extension transform mode\n    //!\n    //! \\param[in] mode\n    //!\n    //! \\retval status a non-negative int is returned on success\n    //! \\sa dwtmode_t\n    //!\n    int dwtmode(dwtmode_t mode);\n\n    //! Get the current discrete wavelet extension transform mode\n    //!\n    //! \\param[out] mode Current mode\n    //!\n    //! \\retval status a non-negative int is returned on success\n    //!\n    const string dwtmode() const;\n\n    //! Get the current discrete wavelet extension transform mode\n    //!\n    //! \\retval mode\n    //!\n    dwtmode_t dwtmodeenum() const { return (_mode); };\n\n    //!\n    //! Set the current wavelet\n    //!\n    //! Change the current wavelet to the one specified by \\p wname.\n    //! \\param[in] wname Name of wavelet.\n    //!\n    //! \\retval status a non-negative int is returned on success\n    //!\n    int wavelet(const string &wname);\n\n    //! Get the current discrete wavelet name\n    //!\n    //! \\retval name\n    //!\n    string wavelet_name() const { return (_wname); };\n\n    //! Get the current discrete wavelet\n    //!\n    //! \\retval wavelet\n    //!\n    const WaveFiltBase *wavelet() const { return (_wf); };\n\n    //! Returns length of approximation coefficients generated in a\n    //! decompostition pass\n    //!\n    //! This method returns the number of approximation coefficients\n    //! generated by one decomposition pass through the filter bank for a signal\n    //! of length, \\p sigInLen.\n    //!\n    //! \\param[in] sigInLen Length of input signal (number of samples)\n    //! \\retval length On success returns the number of coefficients. A\n    //! negative int is returned on failure.\n    //!\n    //! \\sa MatWaveDwt::dwt()\n    //\n    size_t approxlength(size_t sigInLen) const;\n\n    //! Returns length of detail coefficients generated in a\n    //! decompostition pass\n    //!\n    //! This method returns the number of detail coefficients\n    //! generated by one decomposition pass through the filter bank for a signal\n    //! of length, \\p sigInLen.\n    //!\n    //! \\param[in] sigInLen Length of input signal (number of samples)\n    //! \\retval length Returns the number of coefficients.\n    //!\n    //! \\sa MatWaveDwt::dwt()\n    //\n    size_t detaillength(size_t sigInLen) const;\n\n    //! Returns length of coefficients generated in a decompostition pass\n    //!\n    //! This method returns the number of coefficients (approximation plus detail)\n    //! generated by one decomposition pass through the filter bank for a signal\n    //! of length, \\p sigInLen.\n    //!\n    //! \\param[in] sigInLen Length of input signal (number of samples)\n    //! \\retval length Returns the number of coefficients.\n    //!\n    //! \\sa MatWaveDwt::dwt()\n    //\n    size_t coefflength(size_t sigInLen) const { return (approxlength(sigInLen) + detaillength(sigInLen)); };\n\n    size_t coefflength2(size_t sigInX, size_t sigInY) const { return (coefflength(sigInX) * coefflength(sigInY)); };\n\n    size_t coefflength3(size_t sigInX, size_t sigInY, size_t sigInZ) const { return (coefflength(sigInX) * coefflength(sigInY) * coefflength(sigInZ)); };\n\n    //! Returns maximum wavelet decompostion level\n    //!\n    //! This method returns the maximum level decomposition of a signal\n    //! of length, \\p s. This is the\n    //! maximum number of times that a single level decomposition can\n    //! be applied to a signal\n    //!\n    //! \\param[in] Length of input signal\n    //! \\retval length Returns the maximum number of\n    //! decompositions.\n    //!\n    //! \\sa MatWaveDwt::dwt(), MatWaveWavedec::wavedec()\n    //\n    size_t wmaxlev(size_t s) const;\n\n    //! Set or get the abort-on-invalid-float flag\n    //!\n    //! When set, the presence of input data containing invalid floats - floats\n    //! for which the math.h isfinite() function does not return true - results\n    //! in the abnormal termination of the method. If the flag is not\n    //! set invalid floats are set to zero. By default the flag is not set.\n    //!\n    //! \\retval flag A reference to the abot-on-invalid-float flag\n    //\n    bool &InvalidFloatAbortOnOff() { return (_InvalidFloatAbort); };\n\nprotected:\nprivate:\n    bool          _InvalidFloatAbort;\n    dwtmode_t     _mode;\n    WaveFiltBase *_wf;\n    string        _wname;\n\n    WaveFiltBase *_create_wf(const string &wname) const;\n\n    void _wave_len_validate(size_t sigInLen, int waveLength, size_t *lev, size_t *val) const;\n\n    dwtmode_t _dwtmodestr2enum(const string &mode) const;\n    string    _dwtmodeenum2str(dwtmode_t mode) const;\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/MatWaveDwt.h",
    "content": "\n#ifndef _MatWaveDwt_h_\n#define _MatWaveDwt_h_\n\n#include <vapor/utils.h>\n#include <vapor/MatWaveBase.h>\n\nnamespace VAPoR {\n\n//\n//! \\class MatWaveDwt\n//! \\brief Implements a single level wavelet filter\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! The MatWaveDwt class provides single-level wavelet filters similar\n//! to those provided by the Matlab dwt and idwt functions. 1D, 2D, and 3D\n//! transforms are provided. The API for dwt and idwt more closely\n//! matches the MatLab wavedec and waverec functions than the MatLab\n//! functions of the same name.\n//!\nclass WASP_API MatWaveDwt : public MatWaveBase {\npublic:\n    //! Create a wavelet filter bank\n    //!\n    //! \\param[in] wname The name of the wavelet to apply.\n    //! \\param[in] mode The boundary extension mode.\n    //!\n    //! \\sa dwtmode()\n    //!\n    MatWaveDwt(const string &wname, const string &mode);\n    MatWaveDwt(const string &wname);\n    virtual ~MatWaveDwt();\n\n    //! Single-level discrete 1D wavelet transform\n    //!\n    //! This method performs a single-level, one-dimensional wavelet\n    //! decomposition with respect to the current wavelet\n    //! and boundary extension mode.\n    //!\n    //! \\param[in] sigIn The discrete signal\n    //! \\param[in] sigInLength The length of \\p sigIn\n    //! \\param[out] C The wavelet decompostion vector. The length of \\p C,\n    //! must be equal to\n    //! the value returned by MatWaveWavedec::coefflength().\n    //! \\param[out] cA The wavelet decompostion vector approximation coefficients\n    //! \\param[out] cD The wavelet decompostion vector detail coefficients\n    //! \\param[out] L[3] The book keeping vector.  The length of \\p L, must\n    //! be equal to 3. \\p L[0] provides the length of the approximation\n    //! coefficients, \\p L[1] provides the length of the detail coefficients,\n    //! and \\p L[2] is equal to \\p sigInLength.\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa MatWaveBase::coefflength(), idwt()\n    //\n    int dwt(const double *sigIn, size_t sigInLength, double *C, size_t L[3]);\n    int dwt(const float *sigIn, size_t sigInLength, float *C, size_t L[3]);\n    int dwt(const double *sigIn, size_t sigInLength, double *cA, double *cD, size_t L[3]);\n    int dwt(const float *sigIn, size_t sigInLength, float *cA, float *cD, size_t L[3]);\n\n    int dwt(const long *sigIn, size_t sigInLength, long *C, size_t L[3]);\n    int dwt(const int *sigIn, size_t sigInLength, int *C, size_t L[3]);\n    int dwt(const long *sigIn, size_t sigInLength, long *cA, long *cD, size_t L[3]);\n    int dwt(const int *sigIn, size_t sigInLength, int *cA, int *cD, size_t L[3]);\n\n    //! Single-level inverse discrete 1D wavelet transform\n    //!\n    //! This method performs a single-level, one-dimensional wavelet\n    //! reconstruction with respect to the current wavelet and\n    //! boundary extension mode.\n    //!\n    //! \\param[in] C The Wavelet decomposition vector, dimensioned according\n    //! to \\p L.\n    //! \\param[in] cA The wavelet decompostion vector approximation coefficients\n    //! \\param[in] cD The wavelet decompostion vector detail coefficients\n    //! \\param[in] L[3] The Wavelet decomposition book keeping vector.\n    //! \\param[out] sigOut Single-level reconstruction approximation based\n    //! on the approximation and detail coefficients (\\p C). The length of\n    //! \\p sigOut is must be \\p L[2].\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa MatWaveBase::coefflength(), dwt()\n    //\n    int idwt(const double *C, const size_t L[3], double *sigOut);\n    int idwt(const float *C, const size_t L[3], float *sigOut);\n    int idwt(const double *cA, const double *cD, const size_t L[3], double *sigOut);\n    int idwt(const float *cA, const float *cD, const size_t L[3], float *sigOut);\n    int idwt(const long *C, const size_t L[3], long *sigOut);\n    int idwt(const int *C, const size_t L[3], int *sigOut);\n    int idwt(const long *cA, const long *cD, const size_t L[3], long *sigOut);\n    int idwt(const int *cA, const int *cD, const size_t L[3], int *sigOut);\n\n    //! Single-level discrete 2D wavelet transform\n    //!\n    //! This method performs a single-level, two-dimensional wavelet\n    //! decomposition with respect to the current wavelet and\n    //! boundary extension mode.\n    //!\n    //! \\param[in] sigIn The discrete signal\n    //! \\param[in] sigInX The length of the X dimension of \\p sigIn\n    //! \\param[in] sigInY The length of the Y dimension of \\p sigIn\n    //! \\param[out] C The wavelet decompostion vector. The length of \\p C,\n    //! must be equal to\n    //! the value returned by MatWaveWavedec::coefflength2().\n    //! \\param[out] cA The wavelet decompostion vector approximation coefficients\n    //! \\param[out] cDh The wavelet decompostion vector horizontal\n    //! detail coefficients\n    //! \\param[out] cDv The wavelet decompostion vector vertical\n    //! detail coefficients\n    //! \\param[out] cDv The wavelet decompostion vector diagonal\n    //! detail coefficients\n    //! \\param[out] L[10] The book keeping vector.  The length of \\p L, must\n    //! be equal to 6 + 4. \\p L[0] and \\L[1]  provide the dimensions of\n    //! the approximation\n    //! coefficients, \\p L[2] and \\p L[3] provides the dimension of the\n    //! horizontal detail coefficients, \\p L[4] and \\p L[5] the horizontal\n    //! coefficients, \\p L[6] and \\p L[7] the diagonal detail coefficients,\n    //! and \\p L[8] \\p L[9] are equal to \\p sigInX and \\p sigInY, respectively.\n    //!\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa MatWaveBase::coefflength(), idwt()\n    //\n    int dwt2d(const double *sigIn, size_t sigInX, size_t sigInY, double *C, size_t L[10]);\n    int dwt2d(const float *sigIn, size_t sigInX, size_t sigInY, float *C, size_t L[10]);\n    int dwt2d(const double *sigIn, size_t sigInX, size_t sigInY, double *cA, double *cDh, double *cDv, double *cDd, size_t L[10]);\n    int dwt2d(const float *sigIn, size_t sigInX, size_t sigInY, float *cA, float *cDh, float *cDv, float *cDd, size_t L[10]);\n\n    int dwt2d(const long *sigIn, size_t sigInX, size_t sigInY, long *C, size_t L[10]);\n    int dwt2d(const int *sigIn, size_t sigInX, size_t sigInY, int *C, size_t L[10]);\n    int dwt2d(const long *sigIn, size_t sigInX, size_t sigInY, long *cA, long *cDh, long *cDv, long *cDd, size_t L[10]);\n    int dwt2d(const int *sigIn, size_t sigInX, size_t sigInY, int *cA, int *cDh, int *cDv, int *cDd, size_t L[10]);\n\n    //! Single-level inverse discrete 2D wavelet transform\n    //!\n    //! This method performs a single-level, two-dimensional wavelet\n    //! reconstruction with respect to the current wavelet and boundary\n    //! extension mode.\n    //!\n    //! \\param[in] C The Wavelet decomposition vector, dimensioned according\n    //! to \\p L.\n    //! \\param[in] cA The wavelet decompostion vector approximation coefficients\n    //! \\param[in] cDh The wavelet decompostion vector horizontal\n    //! detail coefficients\n    //! \\param[in] cDv The wavelet decompostion vector vertical\n    //! detail coefficients\n    //! \\param[in] cDv The wavelet decompostion vector diagonal\n    //! detail coefficients\n    //! \\param[in] L[10] The Wavelet decomposition book keeping vector.\n    //! \\param[out] sigOut Single-level reconstruction approximation based\n    //! on the approximation and detail coefficients (\\p C). The length of\n    //! \\p sigOut is must be \\p L[8] * \\p L[9].\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa MatWaveBase::coefflength(), dwt()\n    //\n    int idwt2d(const double *C, const size_t L[10], double *sigOut);\n    int idwt2d(const float *C, const size_t L[10], float *sigOut);\n    int idwt2d(const double *cA, const double *cDh, const double *cDv, const double *cDd, const size_t L[10], double *sigOut);\n    int idwt2d(const float *cA, const float *cDh, const float *cDv, const float *cDd, const size_t L[10], float *sigOut);\n\n    int idwt2d(const long *C, const size_t L[10], long *sigOut);\n    int idwt2d(const int *C, const size_t L[10], int *sigOut);\n    int idwt2d(const long *cA, const long *cDh, const long *cDv, const long *cDd, const size_t L[10], long *sigOut);\n    int idwt2d(const int *cA, const int *cDh, const int *cDv, const int *cDd, const size_t L[10], int *sigOut);\n\n    //! Single-level discrete 3D wavelet transform\n    //!\n    //! C is partitioned in the order: LLL, LLH, LHL, LHH, HLL,\n    //! HLH, HHL, HHH\n    //!\n    int dwt3d(const double *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, double *C, size_t L[27]);\n    int dwt3d(const float *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, float *C, size_t L[27]);\n\n    int dwt3d(const long *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, long *C, size_t L[27]);\n    int dwt3d(const int *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int *C, size_t L[27]);\n\n    //! Single-level inverse discrete 3D wavelet transform\n    //\n    int idwt3d(const double *C, const size_t L[27], double *sigOut);\n    int idwt3d(const float *C, const size_t L[27], float *sigOut);\n    int idwt3d(const double *cLLL, const double *cLLH, const double *cLHL, const double *cLHH, const double *cHLL, const double *cHLH, const double *cHHL, const double *cHHH, const size_t L[27],\n               double *sigOut);\n    int idwt3d(const float *cLLL, const float *cLLH, const float *cLHL, const float *cLHH, const float *cHLL, const float *cHLH, const float *cHHL, const float *cHHH, const size_t L[27],\n               float *sigOut);\n\n    int idwt3d(const long *C, const size_t L[27], long *sigOut);\n    int idwt3d(const int *C, const size_t L[27], int *sigOut);\n    int idwt3d(const long *cLLL, const long *cLLH, const long *cLHL, const long *cLHH, const long *cHLL, const long *cHLH, const long *cHHL, const long *cHHH, const size_t L[27], long *sigOut);\n    int idwt3d(const int *cLLL, const int *cLLH, const int *cLHL, const int *cLHH, const int *cHLL, const int *cHLH, const int *cHHL, const int *cHHH, const size_t L[27], int *sigOut);\n\nprivate:\n    // 1D buffers\n    Wasp::SmartBuf _dwt1dSmartBuf;\n\n    // 2D buffers\n    Wasp::SmartBuf _dwt2dSmartBuf;\n\n    // 3D buffers\n    Wasp::SmartBuf _dwt3dSmartBuf1;\n    Wasp::SmartBuf _dwt3dSmartBuf2;\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/MatWaveWavedec.h",
    "content": "\n#ifndef _MatWaveWavedec_h_\n#define _MatWaveWavedec_h_\n\n#include \"MatWaveDwt.h\"\n\nnamespace VAPoR {\n\n//\n//! \\class MatWaveWavedec\n//! \\brief Implements a multi-level wavelet filter\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! The MatWaveWavedec class provides multi-level wavelet filters similar\n//! to those provided by the Matlab wavedec and waverec functions.\n//! 1D, 2D, and 3D\n//! transforms are provided.\n//!\nclass WASP_API MatWaveWavedec : public MatWaveDwt {\npublic:\n    //! Create a wavelet filter bank\n    //!\n    //! \\param[in] wname The name of the wavelet to apply.\n    //! \\param[in] mode The boundary extension mode.\n    //!\n    //! \\note To ensure that the number of coefficients in a decomposition\n    //! is equal to the number of samples in the decomposed signal, \\p mode\n    //! must be set to 'per'; or a symmetric wavelet must be used and \\p mode\n    //! set to 'symw' if the filter length is odd, or set to 'symh' if\n    //! the filter length is even. The one exception to this is the Haar\n    //! wavelet for which the number of coefficients is the same as the\n    //! signal length regardless of the boundary handling mode.\n    //!\n    //! \\sa dwtmode()\n    //!\n    MatWaveWavedec(const string &wname, const string &mode);\n    MatWaveWavedec(const string &wname);\n    virtual ~MatWaveWavedec();\n\n    //! Multi-level discrete 1D wavelet decomposition\n    //!\n    //! This method performs a multi-level, one-dimensional wavelet\n    //! decomposition with respect to the current wavelet.\n    //! The number of decompositions to apply is specified by the\n    //! parameter \\p n, where \\p n is in the range (0..max). \\b max is the\n    //! value returned by wmaxlev(). The format of the returned\n    //! decomposition vector, \\p C, and the bookkeeping vector, \\p L, are\n    //! as described by the Matlab documentation for the \\b wavedec function.\n    //!\n    //! \\param[in] sigIn The discrete signal\n    //! \\param[in] sigInLength The length of \\p sigIn\n    //! \\param[in] n The transformation level\n    //! \\param[out] C The wavelet decompostion vector.  The length of \\p C\n    //! must be equal to\n    //! the value returned by MatWaveWavedec::coefflength().\n    //! \\param[out] L The booking vector.  The length of \\p L must be equal to\n    //! \\p n + 2.\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa MatWaveWavedec::coefflength(), waverec(), wmaxlev()\n    //\n    int wavedec(const double *sigIn, size_t sigInLength, int n, double *C, size_t *L);\n    int wavedec(const float *sigIn, size_t sigInLength, int n, float *C, size_t *L);\n    int wavedec(const long *sigIn, size_t sigInLength, int n, long *C, size_t *L);\n    int wavedec(const int *sigIn, size_t sigInLength, int n, int *C, size_t *L);\n\n    //! Multi-level discrete 1D wavelet reconstruction\n    //!\n    //! This method performs a multi-level, one-dimensional wavelet\n    //! reconstruction with respect to the current wavelet.\n    //! The number of reconstructions to apply is \\p n.\n    //!\n    //! \\param[in] C The Wavelet decomposition vector\n    //! \\param[in] L The Wavelet decomposition bookkeping vector. The length\n    //! of \\p L must be equal to \\p n + 2.\n    //! \\param[in] n The transformation level\n    //! \\param[out] sigOut The reconstructed signal.  The length of\n    //! \\p sigOut is given by MatWaveWavedec::approxlength().\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa wavedec()\n    //\n    int waverec(const double *C, const size_t *L, int n, double *sigOut);\n    int waverec(const float *C, const size_t *L, int n, float *sigOut);\n    int waverec(const long *C, const size_t *L, int n, long *sigOut);\n    int waverec(const int *C, const size_t *L, int n, int *sigOut);\n\n    //! Multi-level discrete 2D wavelet decomposition\n    //!\n    //! This method performs a multi-level, two-dimensional wavelet\n    //! decomposition with respect to the current wavelet.\n    //! The number of decompositions to apply is specified by the\n    //! parameter \\p n, where \\p n is in the range (0..max). \\b max is the\n    //! value returned by wmaxlev() for the smallest input dimension (\\p sigInX\n    //! and \\p sigOutY). The format of the returned\n    //! decomposition vector, \\p C, and the bookkeeping vector, \\p L, are\n    //! as described by the Matlab documentation for the \\b wavedec2 function.\n    //!\n    //! \\param[in] sigIn The discrete signal\n    //! \\param[in] sigInX The length of the X dimension of \\p sigIn\n    //! \\param[in] sigInY The length of the Y dimension of \\p sigIn\n    //! \\param[in] n The transformation level\n    //! \\param[out] C The wavelet decompostion vector.  The length of \\p C must\n    //! be equal to the value returned by MatWaveWavedec::coefflength2().\n    //! \\param[out] L The booking vector.  The length of \\p L must be equal to\n    //! (\\p n * 6) + 4.\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa MatWaveWavedec::coefflength2(), waverec2(), wmaxlev()\n    //\n    int wavedec2(const double *sigIn, size_t sigInX, size_t sigInY, int n, double *C, size_t *L);\n    int wavedec2(const float *sigIn, size_t sigInX, size_t sigInY, int n, float *C, size_t *L);\n    int wavedec2(const long *sigIn, size_t sigInX, size_t sigInY, int n, long *C, size_t *L);\n    int wavedec2(const int *sigIn, size_t sigInX, size_t sigInY, int n, int *C, size_t *L);\n\n    //! Multi-level discrete 2D wavelet reconstruction\n    //!\n    //! This method performs a multi-level, two-dimensional wavelet\n    //! reconstruction with respect to the current wavelet.\n    //! The number of reconstructions to apply is \\p n.\n    //!\n    //! \\param[in] C The Wavelet decomposition vector\n    //! \\param[in] L The Wavelet decomposition bookkeping vector. The length\n    //! of \\p L must be equal to \\p n * 6 + 4.\n    //! \\param[in] n The transformation level\n    //! \\param[out] sigOut The reconstructed signal.  The dimensions of\n    //! \\p sigOut are given by MatWaveWavedec::approxlength2().\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa wavedec2()\n    //\n    int waverec2(const double *C, const size_t *L, int n, double *sigOut);\n    int waverec2(const float *C, const size_t *L, int n, float *sigOut);\n    int waverec2(const long *C, const size_t *L, int n, long *sigOut);\n    int waverec2(const int *C, const size_t *L, int n, int *sigOut);\n\n    //! Multi-level discrete 3D wavelet decomposition\n    //!\n    //! This method performs a multi-level, three-dimensional wavelet\n    //! decomposition with respect to the current wavelet.\n    //! The number of decompositions to apply is specified by the\n    //! parameter \\p n, where \\p n is in the range (0..max). \\b max is the\n    //! value returned by wmaxlev() for the smallest input dimension (\\p sigInX\n    //! \\p sigOutY, and \\p sigOutZ). The format of the returned\n    //! decomposition vector, \\p C, and the bookkeeping vector, \\p L, follows\n    //! the pattern of the 1D and 2D transforms\n    //!\n    //! \\param[in] sigIn The discrete signal\n    //! \\param[in] sigInX The length of the X dimension of \\p sigIn\n    //! \\param[in] sigInY The length of the Y dimension of \\p sigIn\n    //! \\param[in] sigInZ The length of the Z dimension of \\p sigIn\n    //! \\param[in] n The transformation level\n    //! \\param[out] C The wavelet decompostion vector.  The length of \\p C must\n    //! be equal to\n    //! the value returned by MatWaveWavedec::coefflength3().\n    //! \\param[out] L The booking vector.  The length of \\p L which must\n    //! be equal to\n    //! (\\p n * 21) + 6.\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa MatWaveWavedec::coefflength3(), waverec3(), wmaxlev()\n    //\n    int wavedec3(const double *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, double *C, size_t *L);\n    int wavedec3(const float *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, float *C, size_t *L);\n    int wavedec3(const long *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, long *C, size_t *L);\n    int wavedec3(const int *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, int *C, size_t *L);\n\n    //! Multi-level discrete 3D wavelet reconstruction\n    //!\n    //! This method performs a multi-level, three-dimensional wavelet\n    //! reconstruction with respect to the current wavelet.\n    //! The number of reconstructions to apply is \\p n.\n    //!\n    //! \\param[in] C The Wavelet decomposition vector\n    //! \\param[in] L The Wavelet decomposition bookkeping vector. The length\n    //! of \\p L must be equal to (\\p n * 21) + 6.\n    //! \\param[in] n The transformation level\n    //! \\param[out] sigOut The reconstructed signal.  The dimensions of\n    //! \\p sigOut are given by MatWaveWavedec::approxlength3().\n    //!\n    //! \\retval status A negative number indicates failure.\n    //!\n    //! \\sa wavedec3()\n    //\n    int waverec3(const double *C, const size_t *L, int n, double *sigOut);\n    int waverec3(const float *C, const size_t *L, int n, float *sigOut);\n    int waverec3(const long *C, const size_t *L, int n, long *sigOut);\n    int waverec3(const int *C, const size_t *L, int n, int *sigOut);\n\n    int appcoef(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut);\n    int appcoef(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut);\n    int appcoef2(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut);\n    int appcoef2(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut);\n    int appcoef3(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut);\n    int appcoef3(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut);\n    int appcoef(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut);\n    int appcoef(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut);\n    int appcoef2(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut);\n    int appcoef2(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut);\n    int appcoef3(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut);\n    int appcoef3(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut);\n\n    //\n    //! Returns length of coefficient vector generated in a\n    //! multi-level 1D decompostition pass\n    //!\n    //! This method returns the number of coefficients (approximation plus detail)\n    //! generated by a multi-level, one-dimensional\n    //!  decomposition pass through the filter\n    //! bank for a signal\n    //! of length, \\p sigInLen, using the current wavelet.\n    //!\n    //! \\param[in] sigInLen Length of input signal (number of samples)\n    //! \\param[in] L The Wavelet decomposition bookkeping vector. The length\n    //! of \\p L must be equal to (\\p n + 2).\n    //! \\param[in] n The transformation level\n    //! \\retval length returns the number of coefficients.\n    //!\n    //! \\sa MatWaveDwt::wavdec()\n    //\n    size_t coefflength(size_t sigInLen, int n) const;\n    size_t coefflength(const size_t *L, int n) const;\n\n    //\n    //! Returns the number of approximation coefficients in a\n    //! reconstruction.\n    //!\n    //! This method returns the number of coefficients in the reconstruction\n    //! of a signal of length \\p sigInLen at level \\p n. If \\p n == 0, the\n    //! return value equals \\p sigInLen\n    //!\n    //! \\param[in] sigInLen Length of input signal (number of samples)\n    //! \\param[in] n The transformation level\n    //! \\retval length returns the number of coefficients\n    //\n    size_t approxlength(size_t sigInLen, int n) const;\n\n    //\n    //! Returns the number of approximation coefficients in a\n    //! reconstruction.\n    //!\n    //! This method returns the number of coefficients in the reconstruction\n    //! of a signal whose decompostion is described by the book keeping\n    //! vector, \\p L. The total number of transformation levels in \\p L\n    //! is given by \\p n. The approximation level is given by \\p l.\n    //! If \\p l == 0, the number of coefficients equals the length of\n    //! the orginal signal.\n    //!\n    //! \\param[in] L The Wavelet decomposition bookkeping vector. The length\n    //! of \\p L must be equal to (\\p n + 2).\n    //! \\param[in] n The transformation level\n    //! \\param[in] l The approximation level sought. \\p l must be in the\n    //! range (0..\\p n ).\n    //! \\param[out] len The returned number of approximation coefficients\n    //\n    void approxlength(const size_t *L, int n, int l, size_t *len) const;\n\n    //\n    //! Returns length of coefficient vector generated in a\n    //! multi-level 2D decompostition pass\n    //!\n    //! This method returns the number of coefficients (approximation plus detail)\n    //! generated by a multi-level, two-dimensional\n    //!  decomposition pass through the filter\n    //! bank for a signal\n    //! of length, \\p sigInLen, using the current wavelet.\n    //!\n    //! \\param[in] sigInX Length X dimension of input signal (number of samples)\n    //! \\param[in] sigInY Length Y dimension of input signal (number of samples)\n    //! \\param[in] L The booking vector.  The length of \\p L must be equal to\n    //! (\\p n * 6) + 4.\n    //! \\param[in] n The transformation level\n    //! \\retval length returns the number of coefficients.\n    //!\n    //! \\sa MatWaveDwt::wavdec2()\n    //\n    size_t coefflength2(size_t sigInX, size_t sigInY, int n) const;\n    size_t coefflength2(const size_t *L, int n) const;\n\n    //\n    //! Returns the number of approximation coefficients in a\n    //! reconstruction.\n    //!\n    //! This method returns the number of coefficients in the reconstruction\n    //! of a 2D signal whose decompostion is described by the book keeping\n    //! vector, \\p L. The total number of transformation levels in \\p L\n    //! is given by \\p n. The approximation level is given by \\p l.\n    //! If \\p l == 0, the number of coefficients equals the length of\n    //! the orginal signal.\n    //!\n    //! \\param[in] L The Wavelet decomposition bookkeping vector. The length\n    //! of \\p L must be equal to (\\p n * 6) + 4.\n    //! \\param[in] n The transformation level\n    //! \\param[in] l The approximation level sought. \\p l must be in the\n    //! range (0..\\p n ).\n    //! \\param[out] lenx The returned X dimension of approximation coefficients\n    //! \\param[out] leny The returned Y dimension of approximation coefficients\n    //\n    void approxlength2(const size_t *L, int n, int l, size_t *lenx, size_t *leny) const;\n\n    //\n    //! Returns length of coefficient vector generated in a\n    //! multi-level 3D decompostition pass\n    //!\n    //! This method returns the number of coefficients (approximation plus detail)\n    //! generated by a multi-level, three-dimensional\n    //!  decomposition pass through the filter\n    //! bank for a signal\n    //! of length, \\p sigInLen, using the current wavelet.\n    //!\n    //! \\param[in] sigInX Length X dimension of input signal (number of samples)\n    //! \\param[in] sigInY Length Y dimension of input signal (number of samples)\n    //! \\param[in] sigInZ Length Z dimension of input signal (number of samples)\n    //! \\param[in] L The booking vector.  The length of \\p L must be equal to\n    //! (\\p n * 21) + 6.\n    //! \\param[in] n The transformation level\n    //! \\retval length returns the number of coefficients.\n    //!\n    //! \\sa MatWaveDwt::wavdec3()\n    size_t coefflength3(size_t sigInX, size_t sigInY, size_t sigInZ, int n) const;\n    size_t coefflength3(const size_t *L, int n) const;\n\n    //! Returns the number of approximation coefficients in a\n    //! reconstruction.\n    //!\n    //! This method returns the number of coefficients in the reconstruction\n    //! of a 3D signal whose decompostion is described by the book keeping\n    //! vector, \\p L. The total number of transformation levels in \\p L\n    //! is given by \\p n. The approximation level is given by \\p l.\n    //! If \\p l == 0, the number of coefficients equals the length of\n    //! the orginal signal.\n    //!\n    //! \\param[in] L The Wavelet decomposition bookkeping vector. The length\n    //! of \\p L must be equal to (\\p n * 6) + 4.\n    //! \\param[in] n The transformation level\n    //! \\param[in] l The approximation level sought. \\p l must be in the\n    //! range (0..\\p n ).\n    //! \\param[out] lenx The returned X dimension of approximation coefficients\n    //! \\param[out] leny The returned Y dimension of approximation coefficients\n    //! \\param[out] lenz The returned Z dimension of approximation coefficients\n    //\n    void approxlength3(const size_t *L, int n, int l, size_t *lenx, size_t *leny, size_t *lenz) const;\n\n    //\n    //! Computes the book keeping vector, L, for a 1D wavelet decomposition\n    //!\n    //!\n    //! \\param[in] sigInLength The length of the input signal\n    //! \\param[in] n The transformation level\n    //! \\param[out] L The booking vector.  The length of \\p L must be equal to\n    //! \\p n + 2.\n    //\n    void computeL(size_t sigInLen, int n, size_t *L) const;\n\n    //\n    //! Computes the book keeping vector, L, for a 2D wavelet decomposition\n    //!\n    //!\n    //! \\param[in] sigInX The length of the X dimension of input signal\n    //! \\param[in] sigInY The length of the Y dimension of input signal\n    //! \\param[in] n The transformation level\n    //! \\param[out] L The booking vector.  The length of \\p L must be equal to\n    //! (\\p n * 6) + 4.\n    //\n    void computeL2(size_t sigInX, size_t sigInY, int n, size_t *L) const;\n\n    //\n    //! Computes the book keeping vector, L, for a 3D wavelet decomposition\n    //!\n    //!\n    //! \\param[in] sigInX The length of the X dimension of input signal\n    //! \\param[in] sigInY The length of the Y dimension of input signal\n    //! \\param[in] sigInZ The length of the Z dimension of input signal\n    //! \\param[in] n The transformation level\n    //! \\param[out] L The booking vector.  The length of \\p L must be equal to\n    //! (\\p n * 21) + 6.\n    //\n    void computeL3(size_t sigInX, size_t sigInY, size_t sigInZ, int n, size_t *L) const;\n\nprivate:\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/MatrixManager.h",
    "content": "#pragma once\n\n#include <map>\n#include <string>\n#include <stack>\n#include <glm/fwd.hpp>\n#include <glm/mat4x4.hpp>\n#include <glm/gtc/type_ptr.hpp>\n\nusing std::map;\nusing std::stack;\nusing std::string;\n\nnamespace VAPoR {\n\n//! \\class MatrixManager\n//! \\ingroup Public_Render\n//!\n//! \\brief Replaces the OpenGL matrix stack.\n//!\n//! Most functions are one to one replacements and have the same\n//! effects as their OpenGL or GLUT equivalents.\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date   August, 2018\n\nclass RENDER_API MatrixManager {\npublic:\n    enum class Mode { ModelView, Projection };\n\n    MatrixManager();\n\n    glm::mat4 GetCurrentMatrix() const;\n    glm::mat4 GetProjectionMatrix() const;\n    glm::mat4 GetModelViewMatrix() const;\n    glm::mat4 GetModelViewProjectionMatrix() const;\n    void      SetCurrentMatrix(const glm::mat4 m);\n\n    void MatrixModeProjection();\n    void MatrixModeModelView();\n    void PushMatrix();\n    void PopMatrix();\n\n    void LoadMatrixd(const double *m);\n    void GetDoublev(Mode mode, double *m) const;\n\n    void LoadIdentity();\n    void Translate(float x, float y, float z);\n    void Scale(float x, float y, float z);\n    void Rotate(float angle, float x, float y, float z);\n    void Perspective(float fovy, float aspect, float zNear, float zFar);\n    void Ortho(float left, float right, float bottom, float top);\n    void Ortho(float left, float right, float bottom, float top, float zNear, float zFar);\n\n    glm::vec2 ProjectToScreen(float x, float y, float z) const;\n    glm::vec2 ProjectToScreen(const glm::vec3 &v) const;\n\n    float GetProjectionAspectRatio() const;\n\n#ifdef LEGACY_GL_DEBUG\n    int         GetGLMatrixMode();\n    const char *GetGLMatrixModeStr();\n    int         GetGLModelViewStackDepth();\n    int         GetGLProjectionStackDepth();\n    int         GetGLCurrentStackDepth();\n    const char *GetMatrixModeStr();\n#endif\n\n    float Near, Far, FOV, Aspect;\n\nprivate:\n    stack<glm::mat4>  _modelviewStack;\n    stack<glm::mat4>  _projectionStack;\n    stack<glm::mat4> *_currentStack;\n    Mode              _mode;\n    float             _projectionAspectRatio = 0;\n\n    glm::mat4 &      top();\n    const glm::mat4 &top() const;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/ModelParams.h",
    "content": "#pragma once\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\nclass PARAMS_API ModelParams : public RenderParams {\npublic:\n    //! Path to a 3D model file or Vapor vms scene file.\n    //! 3D models can be in formats supported by the ASSIMP library.\n    //! A description of the Vapor vms scene format can be found at\n    //! https://ncar.github.io/VaporDocumentationWebsite/vaporApplicationReference/modelRenderer.html\n    //! Applies to data of type: string\n    static const std::string FileTag;\n\n    ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n    ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType);\n    ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n    virtual ~ModelParams();\n\n    static string GetClassType() { return (\"ModelParams\"); }\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return (0); }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override { return \"\"; }\n\nprivate:\n    void _init();\n};\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/ModelRenderer.h",
    "content": "//************************************************************************\n//                                                                       *\n//                          Copyright (C)  2018                          *\n//            University Corporation for Atmospheric Research            *\n//                          All Rights Reserved                          *\n//                                                                       *\n//************************************************************************/\n//\n//  File:   ModelRenderer.cpp\n//\n//  Author: Stas Jaroszynski\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:   March 2018\n//\n//  Description:\n//          Definition of ModelRenderer\n//\n#pragma once\n\n#include <vapor/glutil.h>\n\n#include <vapor/Renderer.h>\n#include <vapor/ModelParams.h>\n\n#include <glm/glm.hpp>\n\n#include <assimp/Importer.hpp>\n#include <assimp/scene.h>\n\n#include <memory>\n#include <string>\n\nnamespace VAPoR {\n\nclass DataMgr;\n\n//! \\class ModelRenderer\n//! \\brief Class that draws the contours (contours) as specified by IsolineParams\n//! \\author Stas Jaroszynski\n//! \\version 1.0\n//! \\date March 2018\nclass RENDER_API ModelRenderer : public Renderer {\npublic:\n    ModelRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    static string GetClassType() { return (\"Model\"); }\n\n    //! \\copydoc Renderer::_initializeGL()\n    virtual int _initializeGL();\n    //! \\copydoc Renderer::_paintGL()\n    virtual int  _paintGL(bool fast);\n    virtual void _clearCache() {}\n\nprivate:\n    class Model {\n        Assimp::Importer _importer;\n        const aiScene *  _scene;\n        glm::vec3        _min, _max;\n\n        void      renderNode(GLManager *gl, const aiNode *nd) const;\n        void      calculateBounds(const aiNode *nd, glm::mat4 transform = glm::mat4(1.0f));\n        glm::mat4 getMatrix(const aiNode *nd) const;\n\n    public:\n        void      Render(GLManager *gl) const;\n        void      DrawBoundingBox(GLManager *gl) const;\n        int       Load(const std::string &path);\n        glm::vec3 BoundsMin() const { return _min; }\n        glm::vec3 BoundsMax() const { return _max; }\n        glm::vec3 Center() const { return (_min + _max) / 2.f; }\n    };\n\n    class Scene {\n        struct ModelInstance {\n            std::string name;\n            std::string file;\n            glm::vec3   translate = glm::vec3(0.f);\n            glm::vec3   rotate = glm::vec3(0.f);\n            glm::vec3   scale = glm::vec3(1.f);\n            glm::vec3   origin = glm::vec3(0.f);\n        };\n\n        std::vector<ModelInstance>                _instances;\n        std::map<int, std::vector<ModelInstance>> _keyframes;\n        std::map<std::string, Model *>            _models;\n\n    public:\n        ~Scene();\n        int       Load(const std::string &path);\n        void      Render(GLManager *gl, const int ts = 0);\n        glm::vec3 Center() const;\n\n    private:\n        std::vector<ModelInstance> getInstances(const int ts) const;\n        int                        createSceneFromModelFile(const std::string &path);\n        int                        loadSceneFile(const std::string &path);\n        int                        handleInstanceNode(XmlNode *node, ModelInstance *instance);\n        int                        handleTimeNode(XmlNode *node);\n        int                        handleVectorNode(XmlNode *node, glm::vec3 *v);\n        int                        handleFloatAttribute(XmlNode *node, const std::string &name, float *f);\n        int                        parseIntString(const std::string &str, int *i) const;\n        ModelInstance              getInitInstance(const std::string &name) const;\n        bool                       doesInstanceExist(const std::string &name) const;\n        bool                       isModelCached(const std::string &file) const;\n    };\n\n    Scene       _scene;\n    std::string _cachedFile;\n\n    void _renderNode(const aiNode *node);\n};\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/MouseModeParams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  1024\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tMouseModeParams.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tApril 2014\n//\n//\tDescription:\tDefines the MouseModeParams class.\n//\t\tThis Params class is global.  Specifies the current MouseMode.\n//\n#ifndef MOUSEMODEPARAMS_H\n#define MOUSEMODEPARAMS_H\n\n#include <vector>\n#include <map>\n\n#include <vapor/ParamsBase.h>\n\n//! \\class MouseModeParams\n//! \\ingroup Public_Params\n//! \\brief A class for describing mouse modes in use in VAPOR\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    April 2014\n//!\nclass PARAMS_API MouseModeParams : public VAPoR::ParamsBase {\npublic:\n    struct MouseMode {\n        string             name;\n        const char *const *icon;\n    };\n\n    //! Create a MouseModeParams object from scratch\n    //\n    MouseModeParams(VAPoR::ParamsBase::StateSave *ssave);\n\n    //! Create a MouseModeParams object from an existing XmlNode tree\n    //\n    MouseModeParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node);\n\n    virtual ~MouseModeParams();\n\n    //! method identifies pixmap icon for each mode\n    const char *const *GetIcon(string name) const\n    {\n        auto itr = _modes.cbegin();\n        for (; itr != _modes.cend(); ++itr)\n            if (itr->name == name) break;\n        VAssert(itr != _modes.end());\n        return itr->icon;\n    }\n\n    //! method indicates the current mouse mode\n    //! \\retval current mouse mode\n    //\n    string GetCurrentMouseMode() const { return GetValueString(_currentMouseModeTag, GetNavigateModeName()); }\n\n    //! method sets the current mouse mode\n    //!\n    //! \\param[in] name  current mouse mode\n    //\n    void SetCurrentMouseMode(string name);\n\n    //! method indicates how many mouse modes are available.\n    int GetNumMouseModes() { return _modes.size(); }\n\n    //! Return a vector of all registered mouse mode names\n    //\n    vector<string> GetAllMouseModes()\n    {\n        vector<string> v;\n        for (auto itr = _modes.cbegin(); itr != _modes.cend(); ++itr) { v.push_back(itr->name); }\n        return (v);\n    }\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"MouseModeParamsTag\"); }\n\n    static string GetNavigateModeName() { return (\"Navigate\"); }\n\n    static string GetRegionModeName() { return (\"Region\"); }\n\nprivate:\n    static const string _currentMouseModeTag;\n\n    vector<MouseMode> _modes;\n\n    void _init();\n    void _setUpDefault();\n};\n\n#endif    // MOUSEMODEPARAMS_H\n"
  },
  {
    "path": "include/vapor/MyBase.h",
    "content": "//\n//      $Id$\n//\n//************************************************************************\n//\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t*\n//     University Corporation for Atmospheric Research\t\t*\n//\t\t     All Rights Reserved\t\t\t*\n//\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tWed Sep 29 15:40:23 MDT 2004\n//\n//\tDescription:\tA collection of general purpose utilities - things that\n//\t\t\t\t\tprobably should be in the STL but aren't.\n//\n\n#ifndef _MyBase_h_\n#define _MyBase_h_\n\n#include <cmath>\n#include <cstdarg>\n#include <string>\n#include <cstring>\n#include <vector>\n#include <vapor/common.h>\n\n#ifdef NEW_DEBUG\n    #include <new>\nvoid *operator new(size_t sz);\nvoid *operator new[](size_t sz);\n#endif\n\n#ifdef WIN32\n    // Silence an annoying and unnecessary compiler warning\n    #pragma warning(disable : 4251)\n#endif\nusing namespace std;\n\nnamespace Wasp {\n\n//! \\class MyBase\n//! \\brief Wasp base class\n//! \\author John Clyne\n//! \\version 0.1\n//! \\date    Mon Dec 13 17:15:12 MST 2004\n\n//! A collection of general purpose utilities - things that\n//!                  probably should be in the STL but aren't.\n//!\n\n// default values used for variables outside valid grid\nconst float ABOVE_GRID = 0.f;\nconst float BELOW_GRID = 0.f;\n\n//\n// The MyBase base class provides a simple error reporting mechanism\n// that can be used by derrived classes. N.B. the error messages/codes\n// are stored in static class members.\n//\nclass COMMON_API MyBase {\npublic:\n    typedef void (*ErrMsgCB_T)(const char *msg, int err_code);\n    typedef void (*DiagMsgCB_T)(const char *msg);\n\n    MyBase();\n    const string &getClassName() const { return (_className); };\n\n    //! Record a formatted error message.\n    //\n    //! Formats and records an error message. Subsequent calls will overwrite\n    //! the stored error message. The method will also set the error\n    //! code to 1.\n    //! \\param[in] format A 'C' style sprintf format string.\n    //! \\param[in] args... Arguments to format\n    //! \\sa GetErrMsg(), GetErrCode()\n    //\n    static void SetErrMsg(const char *format, ...);\n\n    //! Record a formatted error message and an error code.\n    //\n    //! Formats and records an error message. Subsequent calls will overwrite\n    //! the stored error message. The method will also set the error\n    //! code to \\b err_code.\n    //! \\param[in] errcode A application-defined error code\n    //! \\param[in] format A 'C' style sprintf format string.\n    //! \\param[in] arg... Arguments to format\n    //! \\sa GetErrMsg(), GetErrCode()\n    //\n    static void SetErrMsg(int errcode, const char *format, ...);\n\n    //! Retrieve the current error message\n    //!\n    //! Retrieves the last error message set with SetErrMsg().\n    //! It is the\n    //! caller's responsibility to copy the message returned to user space.\n    //! \\sa SetErrMsg(), SetErrCode()\n    //! \\retval msg A pointer to null-terminated string.\n    //\n    static const char *GetErrMsg() { return (ErrMsg); }\n\n    //! Record an error code\n    //\n    //! Sets the error code to the indicated value.\n    //! \\param[in] err_code The error code\n    //! \\sa GetErrMsg(), GetErrCode(), SetErrMsg()\n    //\n    static void SetErrCode(int err_code) { ErrCode = err_code; }\n\n    //! Retrieve the current error code\n    //\n    //! Retrieves the last error code set either explicity with SetErrCode()\n    //! or indirectly with a call to SetErrMsg().\n    //! \\sa SetErrMsg(), SetErrCode()\n    //! \\retval code An erroor code\n    //\n    static int GetErrCode() { return (ErrCode); }\n\n    //! Set a callback function for error messages\n    //!\n    //! Set the callback function to be called whenever SetErrMsg()\n    //! is called. The callback function, \\p cb, will be called and passed\n    //! the formatted error message and the error code as an argument. The\n    //! default callback function is NULL, i.e. no function is called\n    //!\n    //! \\param[in] cb A callback function or NULL\n    //\n    static void SetErrMsgCB(ErrMsgCB_T cb) { ErrMsgCB = cb; };\n\n    //! Get the callback function for error messages\n    //!\n    //! Get the callback function to be called whenever SetErrMsg()\n    //! is called. This method returns the address of the callback function\n    //! set with the most recent call to SetErrMsgCB(). If no callback function\n    //! is defined, NULL is returned.\n    //!\n    //! \\sa SetErrMsgCB\n    //\n    static ErrMsgCB_T GetErrMsgCB() { return (ErrMsgCB); };\n\n    //! Set the file pointer to whence error messages are written\n    //!\n    //! This method permits the specification of a file pointer to which\n    //! all messages logged with SetErrMsg() will be written. The default\n    //! file pointer is NULL. I.e. by default error messages logged by\n    //! SetErrMsg() are not written.\n    //! \\param[in] fp A file pointer opened for writing or NULL\n    //! \\sa SetErrMsg()\n    //\n    static void SetErrMsgFilePtr(FILE *fp) { ErrMsgFilePtr = fp; };\n\n    //! Get the file pointer to whence error messages are written\n    //!\n    //! This method returns the error message file pointer most recently\n    //! set with SetErrMsgFilePtr().\n    //!\n    //! \\sa SetErrMsgFilePtr()\n    //\n    static const FILE *SetErrMsgFilePtr() { return (ErrMsgFilePtr); };\n\n    //! Record a formatted diagnostic message.\n    //\n    //! Formats and records a diagnostic message. Subsequent calls will overwrite\n    //! the stored error message. This method differs from SetErrMsg() only\n    //! in that no associated error code is set - the message is considered\n    //! diagnostic only, not an error.\n    //! \\param[in] format A 'C' style sprintf format string.\n    //! \\param[in] arg... Arguments to format\n    //! \\sa GetDiagMsg()\n    //\n    static void SetDiagMsg(const char *format, ...);\n\n    //! Retrieve the current diagnostic message\n    //!\n    //! Retrieves the last error message set with \\b SetDiagMsg(). It is the\n    //! caller's responsibility to copy the message returned to user space.\n    //! \\sa SetDiagMsg()\n    //! \\retval msg A pointer to null-terminated string.\n    //\n    static const char *GetDiagMsg() { return (DiagMsg); }\n\n    //! Set a callback function for diagnostic messages\n    //!\n    //! Set the callback function to be called whenever SetDiagMsg()\n    //! is called. The callback function, \\p cb, will be called and passed\n    //! the formatted error message as an argument. The\n    //! default callback function is NULL, i.e. no function is called\n    //!\n    //! \\param[in] cb A callback function or NULL\n    //\n    static void SetDiagMsgCB(DiagMsgCB_T cb) { DiagMsgCB = cb; };\n\n    //! Get the callback function for error messages\n    //!\n    //! Get the callback function to be called whenever SetDiagMsg()\n    //! is called. This method returns the address of the callback function\n    //! set with the most recent call to SetDiagMsgCB(). If no callback function\n    //! is defined, NULL is returned.\n    //!\n    //! \\sa SetDiagMsgCB\n    //\n    static DiagMsgCB_T GetDiagMsgCB() { return (DiagMsgCB); };\n\n    //! Set the file pointer to whence diagnostic messages are written\n    //!\n    //! This method permits the specification of a file pointer to which\n    //! all messages logged with SetDiagMsg() will be written. The default\n    //! file pointer is NULL. I.e. by default error messages logged by\n    //! SetDiagMsg() are not written.\n    //! \\param[in] fp A file pointer opened for writing or NULL\n    //! \\sa SetDiagMsg()\n    //\n    static void SetDiagMsgFilePtr(FILE *fp) { DiagMsgFilePtr = fp; };\n\n    //! Get the file pointer to whence diagnostic messages are written\n    //!\n    //! This method returns the error message file pointer most recently\n    //! set with SetDiagMsgFilePtr().\n    //!\n    //! \\sa SetDiagMsgFilePtr()\n    //\n\n    //!\n    //! Enable or disable error message reporting.\n    //!\n    //! When disabled calls to SetErrMsg() report no error messages\n    //! either through the error message callback or the error message\n    //! FILE pointer.\n    //!\n    //! \\param[in] enable Boolean flag to enable or disable error reporting\n    //!\n    static bool EnableErrMsg(bool enable)\n    {\n        bool prev = Enabled;\n        Enabled = enable;\n        return (prev);\n    };\n\n    static bool GetEnableErrMsg() { return Enabled; }\n\n    // N.B. the error codes/messages are stored in static class members!!!\n    static char *     ErrMsg;\n    static int        ErrCode;\n    static int        ErrMsgSize;\n    static FILE *     ErrMsgFilePtr;\n    static ErrMsgCB_T ErrMsgCB;\n\n    static char *      DiagMsg;\n    static int         DiagMsgSize;\n    static FILE *      DiagMsgFilePtr;\n    static DiagMsgCB_T DiagMsgCB;\n    static bool        Enabled;\n\nprotected:\n    void SetClassName(const string &name) { _className = name; };\n\nprivate:\n    static void _SetErrMsg(char **msg, int *sz, const char *format, va_list args);\n    string      _className;    // name of class\n};\n\nCOMMON_API inline int IsOdd(int x) { return (x % 2); };\n\n//! Return true if power of two\n//\n//! Returns a non-zero value if the input parameter is a power of two\n//! \\param[in] x An integer\n//! \\retval status\nCOMMON_API int IsPowerOfTwo(unsigned int x);\n\nCOMMON_API inline int Min(int a, int b) { return (a < b ? a : b); };\nCOMMON_API inline int Max(int a, int b) { return (a > b ? a : b); };\n\nCOMMON_API inline size_t Min(size_t a, size_t b) { return (a < b ? a : b); };\nCOMMON_API inline size_t Max(size_t a, size_t b) { return (a > b ? a : b); };\n\nCOMMON_API inline float Min(float a, float b) { return (a < b ? a : b); };\nCOMMON_API inline float Max(float a, float b) { return (a > b ? a : b); };\n\nCOMMON_API inline double Min(double a, double b) { return (a < b ? a : b); };\nCOMMON_API inline double Max(double a, double b) { return (a > b ? a : b); };\n\nCOMMON_API inline double LogBaseN(double x, double n) { return (log(x) / log(n)); };\n\n// Find integer log, base 2:\nCOMMON_API int ILog2(int n);\n\n//! Case-insensitive string comparison\n//\n//! Performs a case-insensitive comparison of two C++ strings. Behaviour\n//! is otherwise identical to the C++ std::string.compare() method.\n//\nCOMMON_API int StrCmpNoCase(const string &s, const string &t);\n\n//! Remove white space from a string\n//\n//! Performs in-place removal of all white space from a string.\n//! \\param[in,out] s The string.\nCOMMON_API void StrRmWhiteSpace(string &s);\n\n//! Parse a string, returning a vector of words\n//\n//! Parses a string containing a white-space delimited collection\n//! of words. The words are in order of occurence and returned\n//! as a vector of strings with all white space removed.\n//!\n//! \\param[in] s The input string.\n//! \\param[out] v The output vector.\n//\nCOMMON_API void StrToWordVec(const string &s, vector<string> &v);\n\nCOMMON_API std::vector<std::string> &SplitString(const std::string &s, char delim, std::vector<std::string> &elems);\nCOMMON_API std::vector<size_t> &SplitString(const std::string &s, char delim, std::vector<size_t> &elems);\nCOMMON_API std::vector<int> &SplitString(const std::string &s, char delim, std::vector<int> &elems);\nCOMMON_API std::vector<float> &SplitString(const std::string &s, char delim, std::vector<float> &elems);\nCOMMON_API std::vector<double> &SplitString(const std::string &s, char delim, std::vector<double> &elems);\n\n//! Retrieve a sequence of bits\n//!\n//! Extract \\p n bits from \\p targ starting at position\n//! \\p pos counting from the left. E.g. GetBits64(I,4,3) will\n//! extract bits at bit position 4,3,2, right adjusted\n//!\n//! \\retval returns the extracted bits\n//! \\sa GetBits64()\n//\nCOMMON_API unsigned long long GetBits64(unsigned long long targ, int pos, int n);\n\n//! Set a sequence of bits\n//!\n//! Set \\p n bits in \\p targ starting at position\n//! \\p pos counting from the left. The bits are obtained from\n//! \\p src\n//!\n//! \\retval returns \\targ with the indicated bits set\n//! \\sa GetBits64()\n//\nCOMMON_API unsigned long long SetBits64(unsigned long long targ, int pos, int n, unsigned long long src);\n\n// ran1 function declaration (from numerical recipes in C)\nCOMMON_API double ran1(long *);\n};    // namespace Wasp\n\n//\n// Handle OS differences in 64-bit IO operators\n//\n\n// 64-bit fseek\n//\n\n#ifdef FSEEK64\n    #undef FSEEK64\n#endif\n\n#if defined(WIN32)\n      // Note: win32 won't seek beyond 32 bits\n    #define FSEEK64 fseek\n#endif\n\n#if defined(Linux) || defined(AIX)\n    #define FSEEK64 fseeko64\n#endif\n\n#if defined(Darwin)\n    #define FSEEK64 fseeko\n#endif\n\n#ifndef FSEEK64\n    #define FSEEK64 fseek64\n#endif\n\n// 64-bit fopen\n//\n\n#ifdef FOPEN64\n    #undef FOPEN64\n#endif\n\n#if defined(WIN32) || defined(Darwin)\n    #define FOPEN64 fopen\n#endif\n\n#ifndef FOPEN64\n    #define FOPEN64 fopen64\n#endif\n\n// 64-bit stat\n//\n\n#ifdef STAT64\n    #undef STAT64\n#endif\n\n#ifdef STAT64_T\n    #undef STAT64_T\n#endif\n\n#if defined(WIN32)\n    #define STAT64_T _stat\n    #define STAT64   _stat\n#endif\n\n#if defined(Darwin)\n    #define STAT64_T stat\n    #define STAT64   stat\n#endif\n\n#if defined(__CYGWIN__)\n    #define STAT64_T stat\n    #define STAT64   stat\n#endif\n\n#ifndef STAT64\n    #define STAT64_T stat64\n    #define STAT64   stat64\n#endif\n\n#ifndef TIME64_T\n    #ifdef WIN32\n        #define TIME64_T __int64\n    #else\n        #define TIME64_T int64_t\n    #endif\n#endif\n\n#endif    // MYBASE_H\n"
  },
  {
    "path": "include/vapor/MyPython.h",
    "content": "//\n//      $Id$\n//\n\n#ifndef _MYPYTHON_h_\n#define _MYPYTHON_h_\n\n#include <vapor/MyBase.h>\n\n#if __clang__\n    #pragma clang diagnostic push\n    #pragma clang diagnostic ignored \"-Wdeprecated-register\"\n#else\n    #undef _POSIX_C_SOURCE\n    #undef _XOPEN_SOURCE\n#endif\n\n#ifdef WIN32\n    #ifdef _DEBUG\n        #undef _DEBUG\n        #include <Python.h>\n        #define _DEBUG\n    #else\n        #include <Python.h>\n    #endif\n#else\n    #include <Python.h>\n#endif\n\n#if __clang__\n    #pragma clang diagnostic pop\n#endif\n\nnamespace Wasp {\n\n//\n//! \\class MYPYTHON\n//! \\brief A singleton class for initializing Python\n//! \\author John Clyne\n//!\n//! This singleton class should be used to initialize the Python\n//! interpreter via Py_Initialize();\n//!\n//! Quoated from the Python 2.7.11 API documentation:\n//!\n//! Bugs and caveats: The destruction of modules and objects in modules\n//! is done in random order; this may cause destructors (__del__() methods)\n//! to fail when they depend on other objects (even functions) or modules.\n//! Dynamically loaded extension modules loaded by Python are not\n//! unloaded. Small amounts of memory allocated by the Python interpreter\n//! may not be freed (if you find a leak, please report it). Memory tied\n//! up in circular references between objects is not freed. Some memory\n//! allocated by extension modules may not be freed. <b> Some extensions may\n//! not work properly if their initialization routine is called more\n//! than once; this can happen if an application calls Py_Initialize()\n//! and Py_Finalize() more than once. </b>\n//!\n//! Usage: MyPython::Instance()->Initialize();\n//\nclass RENDER_API MyPython : public Wasp::MyBase {\npublic:\n    static bool IsRunningFromPython;\n    \n    static MyPython *Instance();\n\n    //! Initialize the Python interpreter\n    //!\n    //! Checks value of VAPOR_PYHONHOME environment variable. If set,\n    //! passes it's value to Py_SetPythonHome(). Otherwise uses GetAppsPath()\n    //! to find the location of Python .so's and calls Py_SetPythonHome()\n    //! with path returned by GetAppsPath(). Finally calls Py_Initialize()\n    //\n    int Initialize();\n\n    //! Return python errors as a string\n    //!\n    //! This method can be used to return errors generated by scripts launched\n    //! by the python C API. For example, if a script run by PyRun_SimpleString\n    //! fails and raises an exception this method will return the error string\n    //! generated\n    //\n    string PyErr();\n\n    //! Return stdout message as a string\n    //\n    string PyOut();\n\n    //! Create a python function object from a script\n    //!\n    //! This method create a python function, named by \\p funcName,\n    //! from the Python script \\p script. The script \\p script must\n    //! contain a python function definition for a function named by\n    //! \\p funcName. The function will be defined in the module\n    //! named by \\p moduleName. This module must already exist in\n    //! the python environment.\n    //!\n    //! \\param[in] moduleName Name of module in which to define\n    //! the function.\n    //!\n    //! \\param[in] name of function defined in the script \\p script\n    //!\n    //! \\param[in] script A string containing a valid python script\n    //!\n    //! \\retval pFunc A new PyObject reference to the defined function,\n    //! or NULL if any Python API calls fail\n    //\n    static PyObject *CreatePyFunc(string moduleName, string funcName, string script);\n\nprivate:\n    static MyPython *  m_instance;\n    static bool        m_isInitialized;\n    static std::string m_pyHome;\n    \n    int pyImport(string lib);\n    int rerouteSTDIO();\n\n    MyPython() {}                        // Don't implement\n    MyPython(MyPython const &);          // Don't Implement\n    void operator=(MyPython const &);    // Don't implement\n};\n};    // namespace Wasp\n\n#endif\n"
  },
  {
    "path": "include/vapor/NavigationUtils.h",
    "content": "#pragma once\n\n#include <vapor/ControlExecutive.h>\n#include <vapor/TrackBall.h>\n\nusing VAPoR::ControlExec;\nclass GUIStateParams;\nclass AnimationParams;\nnamespace VAPoR {\nclass ViewpointParams;\n}\n\n//! \\class NavigationUtils\n//! \\brief This class is just migrated legacy code to de-spaghetti other legacy code.\n//! (It is not written by me)\n\nclass RENDER_API NavigationUtils : public Wasp::MyBase {\npublic:\n    static void SetHomeViewpoint(ControlExec *ce);\n    static void UseHomeViewpoint(ControlExec *ce);\n    static void ViewAll(ControlExec *ce);\n    //! Align the view direction to one of the axes.\n    //! axis is 2,3,4 for +X,Y,Z,  and 5,6,7 for -X,-Y,-Z\n    static void AlignView(ControlExec *ce, int axis);\n\n    static void SetAllCameras(ControlExec *ce, const double position[3], const double direction[3], const double up[3], const double origin[3]);\n    static void SetAllCameras(ControlExec *ce, const double position[3], const double direction[3], const double up[3]);\n    static void SetAllCameras(ControlExec *ce, const vector<double> &position, const vector<double> &direction, const vector<double> &up, const vector<double> &origin);\n    static void SetAllCameras(ControlExec *ce, const vector<double> &position, const vector<double> &direction, const vector<double> &up);\n    static void SetAllCameras(ControlExec *ce, const double matrix[16], const double origin[3]);\n    static void SetAllCameras(ControlExec *ce, const vector<double> &matrix, const vector<double> &origin);\n    \n    static void SetAllCameras(ControlExec *ce, const Trackball &trackball);\n    static void ConfigureTrackball(ControlExec *ce, Trackball &trackball);\n\n    static void LookAt(ControlExec *ce, const vector<double> &position, const vector<double> &target, const vector<double> &up);\n    \n    static void SetTimestep(ControlExec *ce, size_t ts);\n    \n    static void GetCameraProperties(ControlExec *ce, vector<double> *position, vector<double> *direction, vector<double> *up, vector<double> *target);\n    static vector<double> GetCameraPosition(ControlExec *ce);\n    static vector<double> GetCameraDirection(ControlExec *ce);\n    static vector<double> GetCameraUp(ControlExec *ce);\n    static vector<double> GetCameraTarget(ControlExec *ce);\n    \n    static void SetCameraPosition(ControlExec *ce, const vector<double> &v);\n    static void SetCameraDirection(ControlExec *ce, const vector<double> &v);\n    static void SetCameraUp(ControlExec *ce, const vector<double> &v);\n    static void SetCameraTarget(ControlExec *ce, const vector<double> &v);\n\n    static long                    GetCurrentTimeStep(ControlExec *ce);\n    static VAPoR::ViewpointParams *GetActiveViewpointParams(ControlExec *ce);\n    static GUIStateParams *        GetGUIStateParams(ControlExec *ce);\n    static AnimationParams *       GetAnimationParams(ControlExec *ce);\n\nprivate:\n    static void propagateTimestep(ControlExec *ce, size_t ts);\n    static void handleMovingDomainAdjustments(ControlExec *ce, size_t ts_from, size_t ts_to);\n    static std::tuple<glm::vec3, glm::vec3> getDomainExtentsAtTimestep(ControlExec *ce, const std::string &dataset, size_t ts);\n    static glm::vec3 getDomainMovementBetweenTimesteps(ControlExec *ce, std::string dataset, size_t from, size_t to);\n    static std::tuple<glm::vec3, glm::vec3> getRendererExtents(const VAPoR::RenderParams *rp);\n    static void setRendererExtents(const VAPoR::RenderParams *rp, const glm::vec3 &minExts, const glm::vec3 &maxExts);\n    static void movingDomainTrackCamera(ControlExec *ce, size_t from, size_t to);\n    static void movingDomainTrackRenderRegions(ControlExec *ce, size_t from, size_t to);\n    static void movingDomainTrackParticleRenderRegions(ControlExec *ce, size_t from, size_t to);\n};\n"
  },
  {
    "path": "include/vapor/NetCDFCFCollection.h",
    "content": "//\n// $Id$\n//\n\n#ifndef _NetCDFCFCollection_h_\n#define _NetCDFCFCollection_h_\n\n#include <vector>\n#include <map>\n#include <algorithm>\n\n#include <sstream>\n#include <vapor/MyBase.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/NetCDFCollection.h>\n\nunion ut_unit;\nstruct ut_system;\n\nnamespace VAPoR {\n\n//\n//! \\class NetCDFCFCollection\n//! \\brief Wrapper for a collection of netCDF files\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class provides access to CF-1 compliant collection of netCDF\n//! files. This work is based on the \"NetCDF Climate and Forecast\n//! (CF) Metadata Conventions\", version 1.6, 5, December 2011.\n//\n\nclass VDF_API NetCDFCFCollection : public NetCDFCollection {\npublic:\n    NetCDFCFCollection();\n    virtual ~NetCDFCFCollection();\n\n    virtual int Initialize(const std::vector<string> &files);\n\n    //! Return boolean indicating whether variable is a CF \"coordinate\" variable\n    //!\n    //! This method returns true if the variable named by \\p var is a\n    //! \"coordinate\" variable as defined by the CF specification. I.e.\n    //! the variable has a single spatial dimension whose name matches\n    //! \\p var name; the variable can be identified as a vertical, lat, lon,\n    //! or time coordinate variable; or the variable is listed by some\n    //! other variable's \"coordinate\" metadata attribute.\n    //!\n    //!\n    //! \\retval true if \\p var is a coordinate variable, false otherwise\n    //!\n    //! \\sa IsAuxCoordVarCF()\n    //\n    virtual bool IsCoordVarCF(string var) const { return (std::find(_coordinateVars.begin(), _coordinateVars.end(), var) != _coordinateVars.end()); }\n\n    //! Return boolean indicating whether the named variable is a CF auxiliary\n    //! coordinate variable\n    //!\n    //! This method returns true if the variable named by \\p var is a\n    //! \"auxiliary coordinate variable\"\n    //!\n    //! CF1.X Definition of <em> auxiliary coordinate variable </em>:\n    //!\n    //! Any netCDF variable that contains coordinate data, but is not\n    //! a coordinate variable (in the sense of that term defined by the\n    //! NUG and used by this standard - see below). Unlike coordinate\n    //! variables, there is no relationship between the name of an auxiliary\n    //! coordinate variable and the name(s) of its dimension(s).\n    //!\n    //! \\retval true if \\p var is an auxliary coordinate variable, false otherwise\n    //\n    virtual bool IsAuxCoordVarCF(string var) const { return (std::find(_auxCoordinateVars.begin(), _auxCoordinateVars.end(), var) != _auxCoordinateVars.end()); }\n\n\n    //! Return boolean indicating whether the named variable is a\n    //! NetCDF CF \"coordinate\" variable or a \"auxilliary\" coordinate\n    //! variable.\n    //!\n    //! \\sa IsAuxCoordVarCF(), IsCoordVarCF()\n    //\n    virtual bool IsCoordinateVar(string varName) const { return (IsCoordVarCF(varName) || IsAuxCoordVarCF(varName)); }\n\n\n\n    //! Return boolean indicating whether the named variable represents\n    //! latitude.\n    //!\n    //! This method returns true if the variable named by \\p var is a\n    //! latitude coordinate variable. See section 4.1 of the CF spec.\n    //!\n    //! \\retval true if \\p var is latitude coordinate variable, false otherwise\n    //\n    virtual bool IsLatCoordVar(string var) const { return (std::find(_latCoordVars.begin(), _latCoordVars.end(), var) != _latCoordVars.end()); }\n\n    //! Return boolean indicating whether the named variable represents\n    //! longitude.\n    //!\n    //! This method returns true if the variable named by \\p var is a\n    //! longitude coordinate variable. See section 4.2 of the CF spec.\n    //!\n    //! \\retval true if \\p var is longitude coordinate variable, false otherwise\n    //\n    virtual bool IsLonCoordVar(string var) const { return (std::find(_lonCoordVars.begin(), _lonCoordVars.end(), var) != _lonCoordVars.end()); }\n\n    //! Return boolean indicating whether the named variable represents\n    //! time.\n    //!\n    //! This method returns true if the variable named by \\p var is a\n    //! time coordinate variable. See section 4.4 of the CF spec.\n    //!\n    //! \\retval true if \\p var is a time coordinate variable, false otherwise\n    //\n    virtual bool IsTimeCoordVar(string var) const { return (std::find(_timeCoordVars.begin(), _timeCoordVars.end(), var) != _timeCoordVars.end()); }\n\n    //! Return boolean indicating whether the named variable represents\n    //! a vertical coordinate.\n    //!\n    //! This method returns true if the variable named by \\p var is a\n    //! dimesional or dimensionless vertical coordinate variable.\n    //! See section 4.3 of the CF spec.\n    //!\n    //! \\retval true if \\p var is a time coordinate variable, false otherwise\n    //\n    virtual bool IsVertCoordVar(string var) const { return (std::find(_vertCoordVars.begin(), _vertCoordVars.end(), var) != _vertCoordVars.end()); }\n\n    //! Return boolean indicating whether the named variable represents\n    //! a vertical pressure coordinate.\n    //!\n    //! This method returns true if the variable named by \\p var is a\n    //! vertical coordinate variable with units of pressure.\n    //! See section 4.3 of the CF spec.\n    //!\n    //! \\retval true if \\p var is a vertical pressure coordinate variable,\n    //! false otherwise\n    //\n    virtual bool IsVertCoordVarPressure(string var) const;\n\n    //! Return boolean indicating whether the named variable represents\n    //! a vertical length coordinate.\n    //!\n    //! This method returns true if the variable named by \\p var is a\n    //! vertical coordinate variable with units of length (e.g. meters)\n    //! See section 4.3 of the CF spec.\n    //!\n    //! \\retval true if \\p var is a vertical length coordinate variable,\n    //! false otherwise\n    //\n    virtual bool IsVertCoordVarLength(string var) const;\n\n    //! Return true if the increasing direction of the named vertical coordinate\n    //! variable is up\n    //!\n    //! CF 1.x description of vertical coordinate direction:\n    //!\n    //! The direction of positive (i.e., the direction in which the coordinate\n    //! values are increasing), whether up or down, cannot in all cases be\n    //! inferred from the units. The direction of positive is useful for\n    //! applications displaying the data. For this reason the attribute\n    //! positive as defined in the COARDS standard is required if the\n    //! vertical axis units are not a valid unit of pressure (a determination\n    //! which can be made using the udunits routine, utScan) -- otherwise\n    //! its inclusion is optional. The positive attribute may have the value\n    //! up or down (case insensitive).\n    //!\n    virtual bool IsVertCoordVarUp(string var) const;\n\n    //! Return a vector of all latitude coordinate variables\n    //!\n    virtual std::vector<string> GetLatCoordVars() const { return (_latCoordVars); };\n\n    //! Return a vector of all longitude coordinate variables\n    //!\n    virtual std::vector<string> GetLonCoordVars() const { return (_lonCoordVars); };\n\n    //! Return a vector of all time coordinate variables\n    //!\n    virtual std::vector<string> GetTimeCoordVars() const { return (_timeCoordVars); };\n\n    //! Return a vector of all vertical coordinate variables\n    //!\n    virtual std::vector<string> GetVertCoordVars() const { return (_vertCoordVars); };\n\n    //! Return a list of data variables with a given rank\n    //!\n    //! Returns a list of data variables having a dimension rank\n    //! of \\p ndim. If \\p spatial is true only the data variable's spatial\n    //! dimension rank is examined.\n    //! Thus if \\p spatial is true, and the named variable is explicitly\n    //! time varying, the\n    //! time-varying dimension is not counted. For example, if a variable\n    //! named 'v' is defined with 4 dimensions in the netCDF file, and the\n    //! slowest varying dimension name matches a named dimension\n    //! specified in Initialize()\n    //! by \\p time_dimnames, then the variable 'v' would be returned by a\n    //! query with ndim==3 and spatial==true.\n    //!\n    //! Names of variables that are coordinate or auxiliary coordinate\n    //! variables are not returned, nor are variables that are missing\n    //! coordinate variables.\n    //!\n    //! \\param[in] ndim Rank of spatial dimensions\n    //! \\param[in] spatial Only compare spatial dimensions against \\p ndim\n    //!\n    //! \\sa NetCDFCollection::GetVariableNames()\n    //\n    virtual std::vector<string> GetDataVariableNames(int ndim, bool spatial) const;\n\n    //!\n    //! Return ordered list of coordinate or auxliary coordinate\n    //! variables for the named variable.\n    //!\n    //! This method returns in \\p cvars an ordered list of all of the\n    //! spatio-temporal coordinate or auxliary coordinate variables\n    //! associated with the variable named by \\p var. See Chapter 5 of\n    //! the CF 1.X spec. for more detail, summarized here:\n    //!\n    //! CF1.X Chap. 5 excerpt :\n    //!\n    //! \"The use of coordinate variables is required whenever they are\n    //! applicable. That is, auxiliary coordinate variables may not be\n    //! used as the only way to identify latitude and longitude coordinates\n    //! that could be identified using coordinate variables. This is both\n    //! to enhance conformance to COARDS and to facilitate the use of\n    //! generic applications that recognize the NUG convention for coordinate\n    //! variables. An application that is trying to find the latitude\n    //! coordinate of a variable should always look first to see if any\n    //! of the variable's dimensions correspond to a latitude coordinate\n    //! variable. If the latitude coordinate is not found this way, then\n    //! the auxiliary coordinate variables listed by the coordinates\n    //! attribute should be checked. Note that it is permissible, but\n    //! optional, to list coordinate variables as well as auxiliary\n    //! coordinate variables in the coordinates attribute.\"\n    //!\n    //! \\param[in] varname A variable name\n    //! \\param[out] cvars A ordered vector of coordinate variable names\n    //!\n    //! \\retval status a negative int is returned if the number of\n    //! elements in \\p cvars does not match the number of spatio-temporal\n    //! dimensions of the variable named by \\p var\n    //\n    virtual int GetVarCoordVarNames(string var, std::vector<string> &cvars) const;\n\n    //! Return the value of the 'units' attribute for the named variable\n    //!\n    //! This method fetches the value of the 'units' attribute, if present,\n    //! for the variable named by \\p var. If a units attribute is not\n    //! present then \\p units will contain an empty string.\n    //!\n    //! \\param[in] varname A variable name\n    //! \\param[out] units The value of the variable's 'units' attribute. If the\n    //! 'units' attribute is not present the parameter will contain the\n    //! empty string.\n    //!\n    //! \\retval status a non-negative int is returned on success\n    //!\n    virtual int GetVarUnits(string var, string &units) const;\n\n    //! Return a pointer to the internal UDUnits object used to perform\n    //! unit conversion.\n    //!\n    const UDUnits *GetUDUnits() const { return (_udunit); };\n\n    //! Convert an array of floating point values from one unit to another\n    //!\n    //! This method uses the UDUnits class to convert an array of floating\n    //! point values from one unit measure to another as supported by\n    //! Unidata's udunits2 library.\n    //! See <A HREF=\"http://www.unidata.ucar.edu/software/udunits/udunits-2/udunits2.html\">\n    //!\n    //! \\param[in] from A string containing the unit to convert\n    //! from (e.g. \"meters\")\n    //! \\param[in] to A string containing the unit to convert\n    //! to (e.g. \"feet\")\n    //! \\param[in] src An array of input values to be converted\n    //! \\param[out] dst An output buffer large enough to contained\n    //! the converted data\n    //! \\param[in] n The number of elements in \\p src\n    //!\n    //! \\retval status a non-negative int is returned on success\n    //!\n    virtual int Convert(const string from, const string to, const double *src, double *dst, size_t n) const;\n    virtual int Convert(const string from, const string to, const float *src, float *dst, size_t n) const;\n\n    //! Return the missing value, if any, for a variable\n    //!\n    //! This method returns the value of the missing data value marker,\n    //! if defined, for the variable named by \\p varname.\n    //!\n    //! Missing data values are indicated using the \\c _FillValue, or\n    //! \\c missing_value attributes as defined in section 2.5.1 of the CF 1.6\n    //! spec.\n    //!\n    //! \\param[in] varname The variable name\n    //! \\param[out] mv The missing value for the variabled name by \\p varname\n    //!\n    //! \\retval bool The boolean true is returned if a missing value is defined.\n    //! If no missing variable is defined the return value is false and the\n    //! value of \\p mv is not defined.\n    //!\n    virtual bool GetMissingValue(string varname, double &mv) const;\n\n    //! \\copydoc NetCDFCollection::OpenRead()\n    //!\n    virtual int OpenRead(size_t ts, string varname);\n\n    //! Return true if the named variable is a dimensionless vertical\n    //! coordinate variable.\n    //!\n    //! This method returns true if the variable named by \\p cvar is both\n    //! a vertical coordinate variable and it is dimensionless. See\n    //! section 4.3.2 of the CF 1.6 spec.\n    //!\n    virtual bool IsVertDimensionless(string cvar) const;\n\n    //! Get a map projection as a proj4 string\n    //!\n    //! If a variable has a map projection generate a proj4\n    //! transformation string for converting from geographic to\n    //! Cartographic coordinates. Returns false if no proj4 string\n    //! could be generated: either no map projection exists, or one\n    //! exists but is not supported.\n    //\n    bool GetMapProjectionProj4(string varname, string &proj4string) const;\n\n    void FormatTimeStr(double time, string &str) const;\n\n    friend std::ostream &operator<<(std::ostream &o, const NetCDFCFCollection &ncdfc);\n\nprivate:\n    std::vector<std::string>       _coordinateVars;\n    std::vector<std::string>       _auxCoordinateVars;\n    std::vector<std::string>       _lonCoordVars;\n    std::vector<std::string>       _latCoordVars;\n    std::vector<std::string>       _vertCoordVars;\n    std::vector<std::string>       _timeCoordVars;\n\n    UDUnits *_udunit;\n\n    //\n    // Map a variable name to it's missing value (if any)\n    //\n    std::map<string, double> _missingValueMap;\n\n    std::vector<std::string> _GetCoordAttrs(const NetCDFSimple::Variable &varinfo) const;\n\n    int _Initialize(const std::vector<string> &files);\n\n    //! CF1.X Definition of <em> coordinate variable </em>:\n    //!\n    //! \"We use this term precisely as it is defined in section 2.3.1 of the NUG.\n    //! It is a one- dimensional variable with the same name as its\n    //! dimension [e.g., time(time)], and it is defined as a numeric data\n    //! type with values that are ordered monotonically. Missing values are\n    //! not allowed in coordinate variables.\"\n    //\n    bool _IsCoordinateVar(const NetCDFSimple::Variable &varinfo) const;\n\n    //!\n    //! CF1.X Determination of a longitude coordinate variable:\n    //!\n    //! \"We recommend the determination that a coordinate is a longitude\n    //! type should be done via a string match between the given unit and\n    //! one of the acceptable forms of degrees_east.\n    //!\n    //! Optionally, the longitude type may be indicated additionally by\n    //! providing the standard_name attribute with the value longitude,\n    //! and/or the axis attribute with the value X.\n    //!\n    //! Coordinates of longitude with respect to a rotated pole should be\n    //! given units of degrees, not degrees_east or equivalents, because\n    //! applications which use the units to identify axes would have no\n    //! means of distinguishing such an axis from real longitude, and might\n    //! draw incorrect coastlines, for instance.\"\n\n    bool _IsLonCoordVar(const NetCDFSimple::Variable &varinfo) const;\n\n    //! CF1.X Determination of a latitude coordinate variable:\n    //!\n    //! Hence, determination that a coordinate is a latitude type should\n    //! be done via a string match between the given unit and one of the\n    //! acceptable forms of degrees_north.\n    //!\n    //! Optionally, the latitude type may be indicated additionally by\n    //! providing the standard_name attribute with the value latitude,\n    //! and/or the axis attribute with the value Y\n    //!\n    bool _IsLatCoordVar(const NetCDFSimple::Variable &varinfo) const;\n\n    //! CF1.X Determination of vertical coordinate variable\n    //!\n    //! A vertical coordinate will be identifiable by:\n    //!\n    //! units of pressure; or\n    //!\n    //! the presence of the positive attribute with a value of up or down\n    //! (case insensitive).\n    //!\n    //! Optionally, the vertical type may be indicated additionally by\n    //! providing the standard_name attribute with an appropriate value,\n    //! and/or the axis attribute with the value Z.\n    //!\n    bool _IsVertCoordVar(const NetCDFSimple::Variable &varinfo) const;\n\n    //! CF1.X Determination of time coordinate variable\n    //!\n    //! A time coordinate is identifiable from its units string alone. The\n    //! Udunits routines utScan() and utIsTime() can be used to make this\n    //! determination.\n    //!\n    //! Optionally, the time coordinate may be indicated additionally by\n    //! providing the standard_name attribute with an appropriate value,\n    //! and/or the axis attribute with the value T.\n    //!\n    bool _IsTimeCoordVar(const NetCDFSimple::Variable &varinfo) const;\n\n    bool _GetMissingValue(string varname, string attname, double &mv) const;\n    void _GetMissingValueMap(map<string, double> &missingValueMap) const;\n\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/NetCDFCollection.h",
    "content": "//\n// $Id: NetCDFCollection.h,v 1.7 2013/05/16 21:39:38 clynejp Exp $\n//\n\n#ifndef _NetCDFCollection_h_\n#define _NetCDFCollection_h_\n\n#include <vector>\n#include <map>\n\n#include <sstream>\n#include <netcdf.h>\n#include <vapor/MyBase.h>\n#include <vapor/NetCDFSimple.h>\n\nnamespace VAPoR {\n\n\n//\n//! \\class NetCDFCollection\n//! \\brief Wrapper for a collection of netCDF files\n//! \\author John Clyne\n//! \\version $Revision: 1.7 $\n//! \\date    $Date: 2013/05/16 21:39:38 $\n//!\n//! This class treats a collection of netCDF files as a single,\n//! time-varying data set, providing a unified interface for accessing\n//! named 0D, 1D, 2D, and 3D spatial variables at a specified timestep,\n//! independent of which netCDF file contains the data.\n//!\n//! The netCDF variables may be \"explicitly\" time-varying: the slowest\n//! varying dimension may correspond to time, while the remaining dimensions\n//! correspond to space. Or the variables may be implicitly time-varying,\n//! possessing no explicit time dimension, in which case the time index\n//! of a variable is determined by file ordering. For example, if the\n//! variable \"v\" is found in the files \"a.nc\" and \"b.nc\" and nowhere else,\n//! and \"a.nc\" preceeds \"b.nc\" in the list of files provided to the class\n//! constructor, then a.nc is assumed to contain \"v\" at time step 0,\n//! and \"b.nc\" contains \"v\" at time step 1.\n//!\n//! \\note The specification of dimensions and coordinates in this class\n//! follows the netCDF API convention of ordering from slowest\n//! varying dimension to fastest varying dimension. For example, if\n//! 'dims' is a vector of dimensions, then dims[0] is the slowest varying\n//! dimension, dim[1] is the next slowest, and so on. This ordering is the\n//! opposite of the ordering used by most of the VAPoR API.\n//!\n//! Several file organizations are supported and discussed below. To\n//! ease discussion we introduce the terminology:\n//!\n//! define TD : Time Dimension <br>\n//! define TCV : Time Coordinate Variable <br>\n//! define TVV : an explicitly Time Varying Variable (it has a time\n//! dimension) <br>\n//! define ITVV : an Implicit Time Varying Variable (has no\n//!\ttime dimension, but has multiple occurences => order determines\n//!\ttime) <br>\n//! define CV: Constant Variable (has no TD, occurs only once). CV variables\n//! are define for all time steps\n//!\n//! Four file organizations are supported as described below:\n//!\n//! <b>case 1:</b> No TD specified (therefore no TCV):\n//!\t+ All variables are ITVV\n//!\t+ synthesize TCV by order of appearance of variables (file order only)\n//!\t+ ITVV time derived by order of appearance (file order only).\n//!\t+ only one time step per variable per file\n//!\n//! <b>case 2:</b> TD specified, but no TCV:\n//!\t+ All variables are TVV or CV\n//!\t+ synthesize TCV by order of appearance (file order, then TD).\n//!\t+ multiple time steps per variable per file\n//!\t+ variables with TD are TVV\n//!\t+ variables with no TD are CV (available for all time)\n//!\t+ A CV that occurs multiple times overwrites prior occurence\n//!\t(there can be no ITVV variables).\n//!\n//! <b>case 3a</b>: TD & TCV specified, TCV appears in only file:\n//!\t+ All variables are TVV or CV\n//!\t+ TVVs indexed to time in TCV by order of appearance (file order, TD\n//!\twithin file)\n//!\t+ A CV that occurs multiple times overwrites prior occurence\n//!\t+ Require TCV to appear in first file\n//!\n//! <b>case 3b</b>: TD & TCV specified, TCV appears in every file with TVV:\n//!\t+ Only have TVV and CV variables\n//!\t+ TVVs indexed to time by TD offset within a file\n//!\t+ A CV that occurs multiple times overwrites prior occurence\n//!\t+ Order of file specification is irrelevant (except for multiple\n//!\toccurences of CVs of same name)\n//!\n\nclass VDF_API NetCDFCollection : public Wasp::MyBase {\npublic:\n    NetCDFCollection();\n    virtual ~NetCDFCollection();\n\n    //! Initialze a new collection\n    //!\n    //! Variables contained in the netCDF files may be explicitly time-varying\n    //! (i.e. have a time dimension defined), or their time step may\n    //! be determined implicitly by which file they are contained in.\n    //!\n    //! The time ordering of time-varying variables is determined by:\n    //!\n    //! 1. A 1D time coordinate variable, if it exists\n    //! 2. A time dimension, if it exists\n    //! 3. The ordering of the files in \\p files in which the variable occurs\n    //!\n    //! \\param[in] files A list of file containing time-varying 1D, 2D, and\n    //! 3D variables. In the absense of an explicit  time dimension, or time\n    //! coordinate variable, the ordering of the files determines the\n    //! the time steps of the variables contained therein.\n    //!\n    //! \\param[in] time_dimnames A list of netCDF time dimensions. A variable\n    //! whose slowest varying dimension name matches a name in \\p time_dimnames\n    //! is an explict time-varying variable with a time dimension.\n    //!\n    //! \\param[in] time_coordvar The name of a coordinate variable containing\n    //! time data. If a 1D variable with a name given by \\p time_coordvar exists,\n    //! this variable will be used to determine the time associated with each\n    //! time step of a variable.\n    //!\n    virtual int Initialize(const std::vector<string> &files, const std::vector<string> &time_dimnames, const std::vector<string> &time_coordvar);\n    \n    //! Return a boolean indicating whether a variable exists in the\n    //! data collection.\n    //!\n    //! This method returns true if the variable named by \\p varname is\n    //! contained in the data collection. The variable may be present\n    //! inside of a netCDF file, or may be a variable derived the the\n    //! NetCDFCFCollection class. In the latter case all native variables\n    //! used to construct \\p varname must also be present.\n    //!\n    //! \\param[in] varname A netCDF variable name\n    //!\n    //! \\retval bool Returns true if \\p varname is contained any one of the\n    //! netCDF files used to instantiate the class, or if \\p varname is a\n    //! derived variable.\n    //!\n    //! \\sa GetTimes(), GetVariables()\n    //\n    virtual bool VariableExists(string varname) const;\n\n    //! Return a boolean indicating whether a variable is defined for a\n    //! particular time step.\n    //!\n    //! This method returns true if the variable named by \\p varname is\n    //! contained in the data collection and defined for time step \\p ts.\n    //! The variable may be present\n    //! inside of a netCDF file, or may be a variable derived the the\n    //! NetCDFCFCollection class. In the latter case all native variables\n    //! used to construct \\p varname must also be present.\n    //!\n    //! \\param[in] ts A valid data set time step in the range from zero to\n    //! GetNumTimeSteps() - 1.\n    //! \\param[in] varname A netCDF variable name\n    //!\n    //! \\retval bool Returns true if \\p varname is contained any one of the\n    //! netCDF files used to instantiate the class, or if \\p varname is a\n    //! derived variable.\n    //!\n    //! \\sa GetTimes(), GetNumTimeSteps(), GetVariables()\n    //\n    virtual bool VariableExists(size_t ts, string varname) const;\n\n    //! Return a list of variables with a given rank\n    //!\n    //! Returns a list of variables having a dimension rank\n    //! of \\p ndim. If \\p spatial is true only the variable's spatial\n    //! dimension rank is examined.\n    //! Thus if \\p spatial is true, and the named variable is explicitly\n    //! time varying, the\n    //! time-varying dimension is not counted. For example, if a variable\n    //! named 'v' is defined with 4 dimensions in the netCDF file, and the\n    //! slowest varying dimension name matches a named dimension\n    //! specified in Initialize()\n    //! by \\p time_dimnames, then the variable 'v' would be returned by a\n    //! query with ndim==3 and spatial==true.\n    //!\n    //! \\param[in] ndim Rank of dimensions\n    //! \\param[in] spatial Only compare spatial dimensions against \\p ndim\n    //\n    virtual std::vector<string> GetVariableNames(int ndim, bool spatial) const;\n\n    //! Return a variable's spatial dimensions\n    //!\n    //! Returns the ordered list of spatial dimensions of the named variable.\n    //! \\note The order follows the netCDF convention (slowest varying\n    //! dimension is the first vector element returned), not the VDC\n    //! convention.\n    //!\n    //! \\param[in] varname Name of variable\n    //! \\retval dims An ordered vector containing the variables spatial\n    //! dimensions. If \\p varname is not defined a zero length vector is\n    //! returned\n    //!\n    virtual std::vector<size_t> GetSpatialDims(string varname) const;\n\n    //! Return a variable's spatial dimension names\n    //!\n    //! Returns the ordered list of spatial dimension names of the named variable.\n    //! \\note The order follows the netCDF convention (slowest varying\n    //! dimension is the first vector element returned), not the VDC\n    //! convention.\n    //!\n    //! \\param[in] varname Name of variable\n    //! \\retval dimnames An ordered vector containing the variable's spatial\n    //! dimension names. If \\p varname is not defined an empty list is returned.\n    //!\n    virtual std::vector<string> GetSpatialDimNames(string varname) const;\n\n    //! Return a variable's time dimension\n    //!\n    //! Returns time  dimension of the named variable.\n    //!\n    //! \\param[in] varname Name of variable\n    //! \\retval dim Number of time steps (time dimension)\n    //! If \\p varname is invalid or \\p varname is not\n    //! time varying 0 is returned.\n    //!\n    virtual size_t GetTimeDim(string varname) const;\n\n    //! Return a variable's time dimension name\n    //!\n    //! Returns the time dimension name of the named variable.\n    //!\n    //! \\param[in] varname Name of variable\n    //! \\retval name A string containing the variable's time\n    //! dimension name. If \\p varname is invalid or \\p varname is not\n    //! time varying the empty string is returned.\n    //!\n    virtual string GetTimeDimName(string varname) const;\n\n    //! Return a variable's temporal and spatial dimensions\n    //!\n    //! Returns the ordered list of temporal and spatial dimensions of the\n    //! named variable.\n    //! \\note The order follows the netCDF convention (slowest varying\n    //! dimension is the first vector element returned), not the VDC\n    //! convention.\n    //!\n    //! \\param[in] varname Name of variable\n    //! \\retval dims An ordered vector containing the variables temporal and\n    //! spatial\n    //! dimensions. If \\p varname is not defined a zero length vector is\n    //! returned\n    //!\n    virtual std::vector<size_t> GetDims(string varname) const;\n\n    //! Return a variable's temporal and spatial dimension names\n    //!\n    //! Returns the ordered list of temporal and spatial dimension names of\n    //! the named variable.\n    //! \\note The order follows the netCDF convention (slowest varying\n    //! dimension is the first vector element returned), not the VDC\n    //! convention.\n    //!\n    //! \\param[in] varname Name of variable\n    //! \\retval dimnames An ordered vector containing the variable's temporal and\n    //! spatial\n    //! dimension names. If \\p varname is not defined an empty list is returned.\n    //!\n    virtual std::vector<string> GetDimNames(string varname) const;\n\n    //! Return true if variable is time varying\n    //!\n    //! Returns true if the variable named by \\p varname has a\n    //! time varying coordinate\n    //!\n    //! \\param[in] varname Name of variable\n    //\n    virtual bool IsTimeVarying(string varname) const;\n\n    //! Return the netCDF external data type a variable\n    //!\n    //! Returns the nc_type of the named variable\n    //!\n    //! \\param[in] varname The name of the variable to query.\n    //!\n    //! \\retval If a variable named by \\p name does not exist, a\n    //! negative value is returned.\n    //!\n    int GetXType(string varname) const;\n\n    //! Return a list of available attribute's names\n    //!\n    //! Returns a vector of all attribute names for the\n    //! variable, \\p varname. If \\p varname is the empty string the names\n    //! of all of the global attributes are returned. If \\p varname is\n    //! not defined an empty vector is returned.\n    //!\n    //! \\param[in] varname The name of the variable to query,\n    //! or the empty string if the names of global attributes are desired.\n    //! \\retval attnames A vector of returned attribute names\n    //!\n    //\n    std::vector<string> GetAttNames(string varname) const;\n\n    //! Return the netCDF external data type for an attribute\n    //!\n    //! Returns the nc_type of the named variable attribute.\n    //!\n    //! \\param[in] varname The name of the variable to query,\n    //! or the empty string if the names of global attributes are desired.\n    //! \\param[in] name Name of the attribute.\n    //!\n    //! \\retval If an attribute named by \\p name does not exist, a\n    //! negative value is returned.\n    //!\n    int GetAttType(string varname, string attname) const;\n\n    //! Return attribute values for attribute of type float\n    //!\n    //! Return the values of the named attribute converted to type float.\n    //!\n    //! \\note Attributes of type int are cast to float\n    //!\n    //! \\note All attributes with floating point representation of\n    //! any precision are returned by this method. Attributes that\n    //! do not have floating point internal representations can not\n    //! be returned.\n    //!\n    //! \\param[in] attname Name of the attribute\n    //! \\param[out] values A vector of attribute values\n    //\n    void GetAtt(string varname, string attname, std::vector<double> &values) const;\n    void GetAtt(string varname, string attname, std::vector<long> &values) const;\n    void GetAtt(string varname, string attname, string &values) const;\n\n    //! Return the names of all the dimensions.\n    //!\n    //! Returns a list of all dimension names defined by all netCDF\n    //! files in the entire collection. The ordering of the returned list\n    //! coresponds to the ordering of the list of dimenension lengths\n    //! returned by GetDims(). I.e. the length of the dimension with\n    //! name GetDimNames()[i] is GetDims[i].\n    //!\n    //! \\retval dimnames A vector containing all\n    //! dimension names.\n    //!\n    //! \\sa GetDims()\n    //\n    virtual std::vector<string> GetDimNames() const { return (_dimNames); };\n\n    //! Return the lengths of all the dimensions.\n    //!\n    //! Returns a list of all dimension lengths defined by all netCDF\n    //! files in the entire collection. The ordering of the returned list\n    //! coresponds to the ordering of the list of dimenension names\n    //! returned by GetDimNames(). I.e. the length of the dimension with\n    //! name GetDimNames()[i] is GetDims[i].\n    //!\n    //! \\retval dimlens A vector containing all\n    //! dimension lengths.\n    //!\n    //! \\sa GetDimNames()\n    //\n    virtual std::vector<size_t> GetDims() const { return (_dimLens); };\n\n    virtual std::vector<bool> GetDimsAreTimeVarying() const { return _dimIsTimeVarying; }\n\n    long GetDimLengthAtTime(string name, long ts);\n\n    //! Return the number of time steps in the data collection all variables\n    //!\n    //! Return the number of time steps present. The number of time steps\n    //! returned is the number of unique times present, and\n    //!\n    //! \\note Not all variables in a collection need have the same number\n    //! of time steps\n    //!\n    //! \\param[in] varname Name of variable\n    //!\n    //! \\retval value The number of time steps\n    //!\n    //\n    virtual size_t GetNumTimeSteps() const { return (_times.size()); }\n\n    //! Return the number of time available for the named variable\n    //!\n    //! Return the number of time steps present for the variable\n    //! named by \\p varname.\n    //! \\note Not all variables in a collection need have the same number\n    //! of time steps\n    //!\n    //! \\param[in] varname Name of variable\n    //!\n    //! \\retval value The number of time steps. If \\p varname is either\n    //! not defined, or is defined but not time varying, 0 is returned.\n    //!\n    //\n    virtual size_t GetNumTimeSteps(string varname) const { return (NetCDFCollection::GetTimeDim(varname)); }\n\n    //! Return the user time associated with a time step\n    //!\n    //! This method returns the time, in user-defined coordinates,\n    //! associated with the time step, \\p ts.\n    //! If no time coordinate variable was specified the user time is\n    //! equivalent to the time step, \\p ts.\n    //!\n    //! \\param[in] ts A valid data set time step in the range from zero to\n    //! GetNumTimeSteps() - 1.\n    //!\n    //! \\param[out] time The user time\n    //!\n    //! \\retval retval A negative int is returned on failure.\n    //!\n    //\n    virtual int GetTime(size_t ts, double &time) const;\n\n    //! Return all the user times associated with a variable\n    //!\n    //! This method returns the times, in user-defined coordinates,\n    //! associated with the the variable, \\p varname.\n    //!\n    //! \\param[in] varname Name of variable\n    //! \\param[times] time A vector of user times ordered by time step\n    //!\n    //! \\retval retval A negative int is returned on failure.\n    //!\n    //\n    virtual int GetTimes(string varname, std::vector<double> &times) const;\n\n    //! Return all the user times for this collection\n    //!\n    //! This method returns the times, in user-defined coordinates,\n    //! for this data collection.\n    //!\n    //!\n    //! \\retval retval times A vector of user times.\n    //!\n    //! \\sa Initialize()\n    //\n    virtual std::vector<double> GetTimes() const { return (_times); };\n\n    //! Return the path to the netCDF file containing a variable\n    //!\n    //! This method returns the path to the netCDF file containing the\n    //! variable \\p varname, at the time step \\p ts.\n    //!\n    //! \\param[in] ts time step of variable\n    //! \\param[in] varname Name of variable\n    //! \\param[out] file The netCDF file path\n    //! \\param[out] local_ts local time index of variable within \\p file\n    //!\n    //! \\retval retval A negative int is returned on failure.\n    //!\n    //\n    virtual int GetFile(size_t ts, string varname, string &file, size_t &local_ts) const;\n\n    //! Return the NetCDFSimple::Variable for the named variable\n    //!\n    //! This method copies the contents of the NetCDFSimple::Variable\n    //! class for the named variable into \\p varinfo\n    //!\n    //! \\param[in] varname Name of variable\n    //!\n    //! \\retval retval A negative int is returned on failure.\n    //!\n    virtual int GetVariableInfo(string varname, NetCDFSimple::Variable &varinfo) const;\n\n    //! Return the missing value, if any, for a variable\n    //!\n    //! This method returns the value of the missing data value marker,\n    //! if defined, for the variable named by \\p varname.\n    //!\n    //! \\param[in] varname The variable name\n    //! \\param[out] mv The missing value for the variabled name by \\p varname\n    //!\n    //! \\retval bool The boolean true is returned if a missing value is defined.\n    //! If no missing variable is defined the return value is false and the\n    //! value of \\p mv is not defined.\n    //!\n    virtual bool GetMissingValue(string varname, double &mv) const;\n\n    //! Open the named variable for reading\n    //!\n    //! This method prepares a netCDF variable, indicated by a\n    //! variable name and time step pair, for subsequent read operations by\n    //! methods of this class.  A small, non-negative integer for  use  in\n    //! subsequent  read operations is returned.\n    //! The file descriptor returned by a\n    //! successful call will be the lowest-numbered file  descriptor  not\n    //! currently open for the process, starting with zero.\n    //!\n    //! \\param[in] ts Time step of the variable to read\n    //! \\param[in] varname Name of the variable to read\n    //!\n    //! \\retval status Returns a non-negative file descriptor on success\n    //!\n    //! \\sa Read(), ReadSlice()\n    //!\n    virtual int OpenRead(size_t ts, string varname);\n\n    //! Read data from the currently opened variable\n    //!\n    //! Read the hyperslice defined by \\p start and \\p count from\n    //! the currently opened variable into the buffer pointed to by \\p data.\n    //!\n    //! This method is identical in functionality to the netCDF function,\n    //! nc_get_var_float, with the following exception:\n    //!\n    //!\n    //! If the currently\n    //! opened variable is explicitly time-varying (has a time-varying\n    //! dimension), only the spatial dimensions should be provied\n    //! by \\p start and \\p count. I.e. if the variable contains n dimensions\n    //! in the netCDF file, only the n-1 fastest-varying (spatial) dimensions\n    //! should be specified.\n    //!\n    //! \\param[in] start Start vector with one element for each dimension\n    //! \\param[in] count Count vector with one element for each dimension\n    //! \\param[in] fd A currently opened file descriptor returned by OpenRead().\n    //! \\retval retval A negative int is returned on failure.\n    //!\n    //! \\sa NetCDFSimple::Read(),\n    //! SetMissingValueAttName(), SetMissingValueAttName()\n    //!\n    virtual int Read(size_t start[], size_t count[], double *data, int fd = 0);\n    virtual int Read(size_t start[], size_t count[], float *data, int fd = 0);\n    virtual int Read(size_t start[], size_t count[], int *data, int fd = 0);\n    virtual int Read(size_t start[], size_t count[], char *data, int fd = 0);\n    virtual int Read(std::vector<size_t> start, std::vector<size_t> count, double *data, int fd = 0);\n    virtual int Read(std::vector<size_t> start, std::vector<size_t> count, float *data, int fd = 0);\n    virtual int Read(std::vector<size_t> start, std::vector<size_t> count, int *data, int fd = 0);\n\n    virtual int Read(double *data, int fd = 0);\n    virtual int Read(float *data, int fd = 0);\n    virtual int Read(char *data, int fd = 0);\n    virtual int Read(int *data, int fd = 0);\n\n    //! Read a 2D slice from a 2D or 3D variable\n    //!\n    //! The method will read 2D slices from a 2D or 3D variable until all\n    //! slices have been processed.\n    //! For 3D data each call to ReadSlice() will return\n    //! a subsequent slice until all slices have been processed. The total\n    //! number of slices is the value of the slowest varying dimension.\n    //!\n    //! \\param[in] fd A currently opened file descriptor returned by OpenRead().\n    //! \\param[out] data The possibly resampled 2D data slice. It is the\n    //! caller's responsibility to ensure that \\p data points to sufficient\n    //! space.\n    //!\n    //! \\retval status Returns 1 if successful, 0 if there are no more\n    //! slices to read, and a negative integer on error.\n    //!\n    //! \\sa OpenRead(), Read(),\n    //! SetMissingValueAttName(), SetMissingValueAttName()\n    //\n    virtual int ReadSlice(float *data, int fd = 0);\n\n    //! Set the variable slice position indicator\n    //!\n    //! This method changes the position of the slice indicator\n    //! for an open variable. Subsequent reads with ReadSlice()\n    //! will position the slice offset based on\n    //! \\p offset. If \\p whence is 0 then \\p offset is added to\n    //! the first variable slice. If \\p whence is one then \\p offset\n    //! is added to the current slice position. If \\p whence is 2\n    //! then \\p offset is added to the last slice. If the resulting slice\n    //! position, after adding \\p offset, lies outside of the variable the\n    //! offset will be mapped to the closest valid value (i.e. the first or\n    //! last slice).\n    //!\n    //! \\param[in] offset integer slice offset\n    //! \\param[in] whence one of 0, 1, 2\n    //! \\param[in] fd A currently opened file descriptor returned by OpenRead().\n    //! \\retval A negative int is returned if \\p fd is not valid (an open\n    //! file descriptor) or if \\p whence is not one of 0, 1, or 2.\n    //\n    virtual int SeekSlice(int offset, int whence, int fd = 0);\n\n    //! Close the currently opened variable\n    //!\n    //! \\param[in] fd A currently opened file descriptor returned by OpenRead().\n    //! \\sa OpenRead()\n    //\n    virtual int Close(int fd = 0);\n\n    //! Identify missing value variable attribute name\n    //!\n    //! This method informs the class instance of the name of a netCDF\n    //! variable attribute, if one exists, that contains the missing value\n    //! for the variable.\n    //!\n    //! \\param attname Name of netCDF variable attribute specifying the\n    //! missing value\n    //\n    virtual void SetMissingValueAttName(string attname) { _missingValAttName = attname; }\n\n    //! Return a list of variables that are not available for access\n    //!\n    //! This method returns a list of variables that were detected in the\n    //! collection of netCDF files but are not accessible from the\n    //! NetCDFCollection class.\n    //!\n    virtual std::vector<string> GetFailedVars() const { return (_failedVars); };\n\n    friend std::ostream &operator<<(std::ostream &o, const NetCDFCollection &ncdfc);\n\n    class TimeVaryingVar {\n    public:\n        TimeVaryingVar();\n        int Insert(const NetCDFSimple *netcdf, const NetCDFSimple::Variable &variable, string file, const std::vector<string> &time_dimnames, const std::map<string, std::vector<double>> &timesmap,\n                   int file_org);\n        std::vector<size_t> GetSpatialDims() const { return (_spatial_dims); };\n        std::vector<string> GetSpatialDimNames() const { return (_spatial_dim_names); };\n        string              GetName() const { return (_name); };\n\n        size_t              GetNumTimeSteps() const { return (_time_varying ? _tvmaps.size() : 1); };\n        string              GetTimeDimName() const { return (_time_name); };\n        int                 GetTime(size_t ts, double &time) const;\n        std::vector<double> GetTimes() const;\n        int                 GetTimeStep(double time, size_t &ts) const;\n        size_t              GetLocalTimeStep(size_t ts) const;\n        int                 GetFile(size_t ts, string &file) const;\n        void                GetVariableInfo(NetCDFSimple::Variable &variable) const { variable = _variable; }\n        bool                GetTimeVarying() const { return (_time_varying); };\n        bool                GetMissingValue(string attname, double &mv) const;\n        void                Sort();\n\n        friend std::ostream &operator<<(std::ostream &o, const TimeVaryingVar &var);\n\n        typedef struct {\n            int    _fileidx;     // Index into _files\n            double _time;        // user time for this time step\n            size_t _local_ts;    // time step offset within file\n        } tvmap_t;\n\n    private:\n        NetCDFSimple::Variable _variable;\n        std::vector<string>    _files;\n        std::vector<tvmap_t>   _tvmaps;\n        std::vector<size_t>    _spatial_dims;    // **spatial** dimensions\n        std::vector<string>    _spatial_dim_names;\n        string                 _time_name;       // name of time dimension\n        string                 _name;            // variable name\n        bool                   _time_varying;    // true if variable's slowest varying dimension\n                                                 // is a time dimension.\n    };\n\nprotected:\n    bool _GetVariableInfo(string varname, NetCDFSimple::Variable &variable) const;\n\nprivate:\n    std::map<string, TimeVaryingVar> _variableList;\n    std::map<string, NetCDFSimple *> _ncdfmap;\n    std::vector<string>              _dimNames;    // Names of all dimensions\n    std::vector<size_t>              _dimLens;     // Names of all dimensions\n    std::vector<bool>                _dimIsTimeVarying;\n    string                           _missingValAttName;\n    std::map<string, vector<double>> _timesMap;      // map variable to time\n    std::vector<double>              _times;         // all valid time coordinates\n    std::vector<string>              _failedVars;    // Varibles that could not be added\n\n    //\n    // file handle for an open variable\n    //\n    class fileHandle {\n    public:\n        fileHandle();\n        NetCDFSimple * _ncdfptr;\n        int            _fd;    // NetCDFSimple open file descriptor\n        size_t         _local_ts;\n        int            _slice;\n        bool           _first_slice;\n        unsigned char *_slicebuf;\n        size_t         _slicebufsz;\n        unsigned char *_linebuf;\n        size_t         _linebufsz;\n        TimeVaryingVar _tvvars;\n        bool           _has_missing;\n        double         _missing_value;\n    };\n    //\n    // Open file data\n    //\n    std::map<int, NetCDFCollection::fileHandle> _ovr_table;\n\n    void ReInitialize();\n\n    int _InitializeTimesMap(const std::vector<string> &files, const std::vector<string> &time_dimnames, const std::vector<string> &time_coordvars, std::map<string, std::vector<double>> &timesMap,\n                            std::map<string, size_t> &timeDimLens, std::vector<double> &times, int &file_org) const;\n\n    int _InitializeTimesMapCase1(const std::vector<string> &files, std::map<string, std::vector<double>> &timesMap, std::map<string, size_t> &timeDimLens) const;\n\n    int _InitializeTimesMapCase2(const std::vector<string> &files, const std::vector<string> &time_dimnames, std::map<string, std::vector<double>> &timesMap,\n                                 std::map<string, size_t> &timeDimLens) const;\n\n    int _InitializeTimesMapCase3(const std::vector<string> &files, const std::vector<string> &time_dimnames, const std::vector<string> &time_coordvars, std::map<string, std::vector<double>> &timesMap,\n                                 map<string, size_t> &timeDimLens) const;\n\n    int _GetTimesMap(NetCDFSimple *netcdf, const std::vector<string> &time_coordvars, const std::vector<string> &time_dimnames, std::map<string, std::vector<double>> &timesmap) const;\n\n    double *_Get1DVar(NetCDFSimple *netcdf, const NetCDFSimple::Variable &variable) const;\n\n    int _get_var_index(const vector<NetCDFSimple::Variable> variables, string varname) const;\n\n    template<typename T> int _read_template(T *data, int fd);\n    template<typename T> int _read_template(size_t start[], size_t count[], T *data, int fd);\n    template<typename T> int _read_slice_template(T *data, int fd);\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/NetCDFCpp.h",
    "content": "#include <vector>\n#include <map>\n#include <iostream>\n#include <netcdf.h>\n#include <vapor/utils.h>\n#include <vapor/MyBase.h>\n\n#ifndef _NetCDFCpp_H_\n    #define _NetCDFCpp_H_\n\nnamespace VAPoR {\n\n//! \\class NetCDFCpp\n//! \\ingroup Public_VDC\n//! \\brief Defines simple C++ wrapper for NetCDF\n//!\n//! This class provdies a simple object-oriented wrapper for the NetCDF\n//! API C language binding. In most cases the member functions provided\n//! by this class are identical or near identical to the NetCDF API\n//! functions of the same name. Only when significant differences\n//! exist  between\n//! the NetCDF native functions and the member functions provided\n//! herein is anything other than brief documention provided.\n//!\n//! The ordering of dimension and coordinate parameters specified\n//! as arrays or STL vectors follows that of\n//! NetCDF: The first element is the slowest varying dimension, the\n//! second element is the next slowest, and so on. \\note This ordering\n//! is the opposite of that used by the VAPoR::VDC class.\n//!\n//! One particular difference of note: the various identifiers used\n//! by NetCDF (e.g. variable id, dimesion id, etc) are not exposed by\n//! the NetCDFCpp class methods. These objects are instead referred to by\n//! their ascii string names. Moreover, as the file access methods\n//! Open() and Create() do not return a NetCDF file identifier, only a single\n//! NetCDF file may be opened at a time (multiple NetCDF files may be\n//! opened, if needed, by instantiating multiple NetCDFCpp objects).\n//!\n//! Unless otherwise noted the return value of any member function that\n//! returns an integer may be interpreted as status. A negative value\n//! indicates an error. Upon error an error message will\n//! be logged via Wasp::MyBase::SetErrMsg().\n//\nclass WASP_API NetCDFCpp : public Wasp::MyBase {\npublic:\n    NetCDFCpp();\n    virtual ~NetCDFCpp();\n\n    //! Create a new NetCDF file\n    //!\n    //! Create an new NetCDF file named by 'path'. Any currently opened\n    //! NetCDF files\n    //! are closed prior to attempting to create the named file\n    //\n    virtual int Create(string path, int cmode, size_t initialsz, size_t &bufrsizehintp);\n\n    //! Open an existing NetCDF file\n    //!\n    //! Open an existing named file. Any currently opened NetCDF files\n    //! are closed prior to attempting to open the named file\n    //\n    virtual int Open(string path, int mode);\n\n    //! Define a dimension\n    virtual int DefDim(string name, size_t len) const;\n\n    //! Define a variable\n    virtual int DefVar(string name, int xtype, vector<string> dimnames);\n\n    //! Learn the dimension names associated with a variable\n    virtual int InqVarDims(string name, vector<string> &dimnames, vector<size_t> &dims) const;\n\n    //! Learn the dimension names and lengths defined in a file\n    //\n    virtual int InqDims(vector<string> &dimnames, vector<size_t> &dims) const;\n\n    //! Learn the length of a named dimension\n    virtual int InqDimlen(string name, size_t &len) const;\n\n    //! Learn the names of all the global or variable attributes\n    //\n    int InqAttnames(string varname, std::vector<string> &attnames) const;\n\n    //! Copy global or variable attribute\n    //!\n    //! This method copies an attribute from one open netCDF dataset to another.\n    //! It can also be used to copy an attribute from one variable to another\n    //! within the same netCDF.\n    //!\n    //! \\param[in] varname_in Name of source variable, empty if global\n    //! \\param[in] attname Name of attribute to copy\n    //! \\param[in] ncdf_out Destination NetCDF object\n    //! \\param[in] varname_out Name of destination variable, empty if global\n    //!\n    int CopyAtt(string varname_in, string attname, NetCDFCpp &ncdf_out, string varname_out) const;\n\n    //\n    // PutAtt - Integer\n    //\n\n    //! Write an integer attribute\n    virtual int PutAtt(string varname, string attname, int value) const;\n    virtual int PutAtt(string varname, string attname, vector<int> values) const;\n    virtual int PutAtt(string varname, string attname, const int values[], size_t n) const;\n\n    //\n    // GetAtt - Integer\n    //\n\n    //! Read an integer attribute\n    virtual int GetAtt(string varname, string attname, int &value) const;\n    virtual int GetAtt(string varname, string attname, vector<int> &values) const;\n    virtual int GetAtt(string varname, string attname, int values[], size_t n) const;\n\n    //\n    // PutAtt - size_t\n    //\n    virtual int PutAtt(string varname, string attname, size_t value) const;\n    virtual int PutAtt(string varname, string attname, vector<size_t> values) const;\n    virtual int PutAtt(string varname, string attname, const size_t values[], size_t n) const;\n\n    //\n    // GetAtt - size_t\n    //\n    virtual int GetAtt(string varname, string attname, size_t &value) const;\n    virtual int GetAtt(string varname, string attname, vector<size_t> &values) const;\n    virtual int GetAtt(string varname, string attname, size_t values[], size_t n) const;\n\n    //\n    // PutAtt - Float\n    //\n    virtual int PutAtt(string varname, string attname, float value) const;\n    virtual int PutAtt(string varname, string attname, vector<float> values) const;\n    virtual int PutAtt(string varname, string attname, const float values[], size_t n) const;\n\n    //\n    // GetAtt - Float\n    //\n    virtual int GetAtt(string varname, string attname, float &value) const;\n    virtual int GetAtt(string varname, string attname, vector<float> &values) const;\n    virtual int GetAtt(string varname, string attname, float values[], size_t n) const;\n\n    //\n    // PutAtt - Double\n    //\n    virtual int PutAtt(string varname, string attname, double value) const;\n    virtual int PutAtt(string varname, string attname, vector<double> values) const;\n    virtual int PutAtt(string varname, string attname, const double values[], size_t n) const;\n\n    //\n    // GetAtt - Double\n    //\n    virtual int GetAtt(string varname, string attname, double &value) const;\n    virtual int GetAtt(string varname, string attname, vector<double> &values) const;\n    virtual int GetAtt(string varname, string attname, double values[], size_t n) const;\n\n    //\n    // PutAtt - String\n    //\n    virtual int PutAtt(string varname, string attname, string value) const;\n    virtual int PutAtt(string varname, string attname, vector<string> values) const;\n    virtual int PutAtt(string varname, string attname, const char values[], size_t n) const;\n\n    //\n    // GetAtt - String\n    //\n    virtual int GetAtt(string varname, string attname, string &value) const;\n    virtual int GetAtt(string varname, string attname, char values[], size_t n) const;\n\n    //! Return a text attribute as a vector of strings\n    //!\n    //! This method attempts to return the value of the named\n    //! text attribute as a vector of words. The value of the\n    //! attribute named by \\p attname is tokenized (parsed) using\n    //! white space as a delimeter. The extracted tokens are returned\n    //! in the order of occurence in the vector \\p values.\n    //\n    virtual int GetAtt(string varname, string attname, vector<string> &values) const;\n\n    //! Find the NetCDF ID of a variable\n    virtual int InqVarid(string varname, int &varid) const;\n\n    //! Return information about a NetCDF attribute\n    virtual int InqAtt(string varname, string attname, nc_type &xtype, size_t &len) const;\n\n    //! Find a variable's external representation type\n    //\n    virtual int InqVartype(string varname, nc_type &xtype) const;\n\n    //! Set the fill value\n    virtual int SetFill(int fillmode, int &old_modep);\n\n    //! End the metadata definition section\n    virtual int EndDef() const;\n\n    //! Put open netcdf dataset into define mode\n    virtual int ReDef() const;\n\n    //! Close the currently opened file\n    virtual int Close();\n\n    //! Write an array of values to a variable\n    virtual int PutVara(string varname, vector<size_t> start, vector<size_t> count, const void *data);\n    virtual int PutVara(string varname, vector<size_t> start, vector<size_t> count, const float *data);\n    virtual int PutVara(string varname, vector<size_t> start, vector<size_t> count, const double *data);\n    virtual int PutVara(string varname, vector<size_t> start, vector<size_t> count, const int *data);\n    virtual int PutVara(string varname, vector<size_t> start, vector<size_t> count, const long *data);\n    virtual int PutVara(string varname, vector<size_t> start, vector<size_t> count, const unsigned char *data);\n\n    //! Write an entire variable with one function call\n    virtual int PutVar(string varname, const void *data);\n    virtual int PutVar(string varname, const float *data);\n    virtual int PutVar(string varname, const double *data);\n    virtual int PutVar(string varname, const int *data);\n    virtual int PutVar(string varname, const long *data);\n    virtual int PutVar(string varname, const unsigned char *data);\n\n    //! Read an array of values from a variable\n    virtual int GetVara(string varname, vector<size_t> start, vector<size_t> count, void *data) const;\n    virtual int GetVara(string varname, vector<size_t> start, vector<size_t> count, float *data) const;\n    virtual int GetVara(string varname, vector<size_t> start, vector<size_t> count, double *data) const;\n    virtual int GetVara(string varname, vector<size_t> start, vector<size_t> count, int *data) const;\n    virtual int GetVara(string varname, vector<size_t> start, vector<size_t> count, long *data) const;\n    virtual int GetVara(string varname, vector<size_t> start, vector<size_t> count, unsigned char *data) const;\n\n    //! Read an entire variable with one function call\n    virtual int GetVar(string varname, void *data) const;\n    virtual int GetVar(string varname, float *data) const;\n    virtual int GetVar(string varname, double *data) const;\n    virtual int GetVar(string varname, int *data) const;\n    virtual int GetVar(string varname, long *data) const;\n    virtual int GetVar(string varname, unsigned char *data) const;\n\n    //! Copy a variable from one file to another\n    //\n    virtual int CopyVar(string varname, NetCDFCpp &ncdf_out) const;\n\n    //! Return the size in bytes of a NetCDF external data type\n    //!\n    static size_t SizeOf(int nctype);\n\n    //! Return true if file exists and is a valid NetCDF file\n    //!\n    //! Returns true if both the file specified by \\p path exists, and\n    //! it can be opened with nc_open().\n    //!\n    virtual bool ValidFile(string path);\n\n    //! Returns true if the named dimension is defined\n    //!\n    //! \\param[in] dimname A NetCDF dimension name\n    //\n    virtual bool InqDimDefined(string dimname);\n\n    //! Returns true if the named attribute is defined\n    //!\n    //! \\param[in] dimname A NetCDF dimension name\n    //\n    virtual bool InqAttDefined(string varname, string attname);\n\n    //! Learn the names of the user defined variables present\n    //!\n    //! \\param[out] varnames A vector containing the names of all of the\n    //! variables defined in the presently opened NetCDF file.\n    //\n    virtual int InqVarnames(vector<string> &varnames) const;\n\n    //! Return netCDF ID associated with this object\n    //!\n    int GetNCID() const { return (_ncid); }\n\nprivate:\n    int    _ncid;\n    string _path;\n\n    int _PutVara(string varname, vector<size_t> start, vector<size_t> count, const void *data, string func);\n    int _PutVar(string varname, const void *data, string func);\n\n    int _GetVara(string varname, vector<size_t> start, vector<size_t> count, void *data, string func) const;\n    int _GetVar(string varname, void *data, string func) const;\n};\n\n}    // namespace VAPoR\n\n#endif    //\t_NetCDFCpp_H_\n"
  },
  {
    "path": "include/vapor/NetCDFSimple.h",
    "content": "//\n// $Id$\n//\n\n#ifndef _NetCDFSimple_h_\n#define _NetCDFSimple_h_\n\n#include <vector>\n#include <map>\n\n#include <sstream>\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\n\n//\n//! \\class NetCDFSimple\n//! \\brief NetCDFSimple API interface\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class presents a simplified interface for reading netCDF\n//! data files.\n//!\n//! The specification of dimensions and coordinates in this class\n//! follows the netCDF API convention of ordering from slowest\n//! varying dimension to fastest varying dimension. For example, if\n//! 'dims' is a vector of dimensions, then dims[0] is the slowest varying\n//! dimension, dim[1] is the next slowest, and so on. This ordering is the\n//! opposite of the ordering used by most of the VAPoR API.\n//\nclass VDF_API NetCDFSimple : public Wasp::MyBase {\npublic:\n    NetCDFSimple();\n    virtual ~NetCDFSimple();\n\n    //! \\class Variable\n    //! \\brief NetCDFSimple API interface\n    //!\n    //! A NetCDFSimple data variable\n    //\n    class Variable {\n    public:\n        Variable();\n\n        //! Constructor for NetCDFSimple::Variable class\n        //!\n        //! \\param[in] varname\tName of the netCDF variable\n        //! \\param[in] dimnames A vector dimension names, ordered from\n        //! slowest-varying to fastest.\n        //! \\param[in] type The netCDF external data type for the variable\n        Variable(string varname, std::vector<string> dimnames, int type);\n\n        //! Return the variable's name\n        //\n        string GetName() const { return (_name); };\n\n        //! Return variable's attribute names\n        //!\n        //! This method returns a vector containing the names of all of the\n        //! attributes associated with this variable\n        //\n        std::vector<string> GetAttNames() const;\n\n        //! Return variable's dimension names\n        //!\n        //! Returns an ordered list of the variable's netCDF dimension names.\n        //!\n        std::vector<string> GetDimNames() const { return (_dimnames); };\n        void                SetDimNames(const std::vector<string> dimnames) { _dimnames = dimnames; }\n\n        //! Return the netCDF external data type for an attribute\n        //!\n        //! Returns the nc_type of the named variable attribute.\n        //! \\param[in] name Name of the attribute\n        //!\n        //! \\retval If an attribute named by \\p name does not exist, a\n        //! negative value is returned.\n        //\n        int GetAttType(string name) const;\n\n        //! Return the netCDF external data type for the variable\n        //!\n        int GetXType() const { return (_type); };\n\n        //! Return attribute values for attribute of type float\n        //!\n        //! Return the values of the named attribute converted to type float.\n        //!\n        //!\t\\note Attributes of type int are cast to float\n        //!\n        //! \\note All attributes with floating point representation of\n        //! any precision are returned by this method. Attributes that\n        //! do not have floating point internal representations can not\n        //! be returned\n        //!\n        //! \\param[in] name Name of the attribute\n        //! \\param[out] values A vector of attribute values\n        //\n        void GetAtt(string name, std::vector<double> &values) const;\n        void GetAtt(string name, std::vector<long> &values) const;\n        void GetAtt(string name, string &values) const;\n\n        //! Set an attribute\n        //!\n        //! Set the floating point attribute, \\p name, to the values\n        //! given by \\p values\n        //\n        void SetAtt(string name, const std::vector<double> &values) { _flt_atts.push_back(make_pair(name, values)); }\n        void SetAtt(string name, const std::vector<long> &values) { _int_atts.push_back(make_pair(name, values)); }\n        void SetAtt(string name, const string &values) { _str_atts.push_back(make_pair(name, values)); }\n\n        VDF_API friend std::ostream &operator<<(std::ostream &o, const Variable &var);\n        VDF_API friend bool          operator==(const Variable &v1, const Variable &v2)\n        {\n            return ((v1._name == v2._name) && (v1._dimnames == v2._dimnames) && (v1._flt_atts == v2._flt_atts) && (v1._int_atts == v2._int_atts) && (v1._str_atts == v2._str_atts)\n                    && (v1._type == v2._type));\n        }\n\n    private:\n        string                                              _name;        // variable name\n        std::vector<string>                                 _dimnames;    // order list of dimension names\n        std::vector<std::pair<string, std::vector<double>>> _flt_atts;\n        std::vector<std::pair<string, std::vector<long>>>   _int_atts;\n        std::vector<std::pair<string, string>>              _str_atts;\n        int                                                 _type;    // netCDF variable type\n    };\n\n    //! Initialize the class instance for a netCDF file\n    //!\n    //! This method initializes (or reinitializes) a class instance with\n    //! the name of a netCDF file\n    //!\n    //! \\param[in] path Path to the netCDF file\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    virtual int Initialize(string path);\n\n    //! Open the named variable for reading\n    //!\n    //! This method prepares a netCDF variable\n    //! for subsequent read operations by\n    //! methods of this class. A small, non-negative integer for  use  in\n    //! subsequent  read operations is returned.\n    //! The file descriptor returned by a\n    //! successful call will be the lowest-numbered file  descriptor  not\n    //! currently open for the process, starting with zero.\n    //!\n    //! \\param[in] variable A variable object returned by GetVariables()\n    //!\n    //! \\retval status Returns a non-negative file descriptor on success\n    //!\n    //! \\sa Read(), GetVariables()\n    //!\n    virtual int OpenRead(const NetCDFSimple::Variable &variable);\n\n    //! Read an array of values from a variable\n    //!\n    //! The method allows the readying of a hyperslab of data from the\n    //! currently opened variable.\n    //!\n    //! \\param[in] start Start vector with one element for each dimension to\n    //! specify a hyperslab\n    //! \\param[in] count Count vector with one element for each dimension to\n    //! specify a Hyperslab\n    //! \\param[in] fd A currently opened file descriptor returned by OpenRead().\n    //! \\param[out] data A pointer to an area of memory containing sufficent\n    //! space to contain the copied hyperslab.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa OpenRead()\n    //! \\sa NetCDF documentation for nc_get_vara\n    //!\n    int Read(const size_t start[], const size_t count[], double *data, int fd = 0) const;\n    int Read(const size_t start[], const size_t count[], float *data, int fd = 0) const;\n    int Read(const size_t start[], const size_t count[], int *data, int fd = 0) const;\n    int Read(const size_t start[], const size_t count[], char *data, int fd = 0) const;\n\n    //! Close the currently opened variable\n    //!\n    //! \\param[in] fd A currently opened file descriptor returned by OpenRead().\n    //! \\retval status Returns a non-negative value on success\n    //\n    virtual int Close(int fd = 0);\n\n    //! Return a vector of the Variables contained in the file\n    //!\n    //! This method returns a vector of Variable objects containing\n    //! the metadata for each variable in the netCDF file\n    //!\n    //! \\sa Initialize(), NetCDFSimple::Variable\n    //!\n    const std::vector<NetCDFSimple::Variable> &GetVariables() const { return (_variables); };\n\n    //! Return all dimensions and dimension names defined in the file\n    //!\n    //! This method returns in \\p names a vector of all dimension names,\n    //! and in \\p dims a vector of all dimension lengths. Thus, for example,\n    //! the lenght of the dimension named by names[i] is given by dims[i]\n    //!\n    //! \\params[out] names Vector of dimension names\n    //! \\params[out] dims Vector of dimension lengths\n    //!\n    //! \\sa Initialize()\n    //!\n    void GetDimensions(std::vector<string> &names, std::vector<size_t> &dims) const;\n\n    //! Return the name of the netCDF dimension with a given dimension id\n    //!\n    //! Returns the name of dimension for the netCDF dimension id specified by\n    //! \\p id\n    //!\n    //! \\param[in] id a valid netCDF dimension ID for the current file\n    //! \\retval name Name of the dimension associated with the identifier \\p id.\n    //! if \\p id is invalid an empty string is returned.\n    //!\n    //! \\sa Initialize()\n    //\n    string DimName(int id) const;\n\n    //! Return the dimension length of the named dimension\n    //!\n    //! Returns the dimension length of the dimension  named by\n    //! \\p name. If \\p name is not recognized as a dimension name\n    //! zero is returned.\n    //!\n    //! \\param[in] name a valid netCDF dimension name for the current file\n    //! \\retval length Length of the dimension named \\p name, or 0\n    //! if \\p name is unknown.\n    //!\n    //! \\sa Initialize()\n    //\n    size_t DimLen(string name) const;\n\n    //! Return the netCDF dimension id for a named dimension\n    //!\n    //! Returns the netCDF dimension id for the named dimension specified by\n    //! \\p name\n    //!\n    //! \\param[in] name a valid netCDF dimension name for the current file\n    //! \\retval id netCDF identifier for the dimension \\p name.\n    //! if \\p name is invalid a negative int is returned.\n    //!\n    //! \\sa Initialize()\n    //\n    int DimId(string name) const;\n\n    //! Return global attribute names\n    //!\n    //! This method returns a vector of all the global netCDF attributes\n    //! defined in the file\n    //!\n    //! \\retval vector A list of global attribute names\n    //!\n    //! \\sa Initialize()\n    //\n    std::vector<string> GetAttNames() const;\n\n    //! Return the netCDF external data type for an attribute\n    //!\n    //! Returns the nc_type of the named global attribute.\n    //! \\param[in] name Name of the attribute\n    //!\n    //! \\retval If an attribute named by \\p name does not exist, a\n    //! negative value is returned.\n    //\n    int GetAttType(string name) const;\n\n    //! Return global attribute values for attribute of type float\n    //!\n    //! Return the values of the named global attribute converted to type float.\n    //!\n    //!\t\\note Attributes of type int are cast to float\n    //!\n    //! \\note All attributes with floating point representation of\n    //! any precision are returned by this method. Attributes that\n    //! do not have floating point internal representations can not\n    //! be returned\n    //!\n    //! \\param[in] name Name of the attribute\n    //! \\param[out] values A vector of attribute values\n    //\n    void GetAtt(string name, std::vector<double> &values) const;\n    void GetAtt(string name, std::vector<long> &values) const;\n    void GetAtt(string name, string &values) const;\n\n    //! Determine if a NetCDF nc_type is an int\n    //!\n    //! This static method returns true if \\p type is one of the NetCDF's\n    //! \\b nc_type: \\b NC_BYTE, \\b NC_SHORT, \\b NC_INT, \\b NC_LONG,\n    //! \\b NC_UBYTE, \\b NC_USHORT,\n    //! \\b NC_UINT, \\b NC_INT64, or \\b NC_UINT64. For all other values\n    //! of \\p type\n    //! \\b false is returned.\n    //!\n    //! \\param[in] type A NetCDF external data type\n    //! \\retval bool True if \\p type represents an integer data type\n    //!\n    static bool IsNCTypeInt(int type);\n\n    //! Determine if a NetCDF nc_type is a float\n    //!\n    //! This static method returns true if \\p type is one of the NetCDF's\n    //! \\b nc_type: \\b NC_FLOAT, or \\b NC_DOUBLE. For all other values\n    //! of \\p type\n    //! \\b false is returned.\n    //!\n    //! \\param[in] type A NetCDF external data type\n    //! \\retval bool True if \\p type represents an floating point data type\n    //!\n    static bool IsNCTypeFloat(int type);\n\n    //! Determine if a NetCDF nc_type is an char\n    //!\n    //! This static method returns true if \\p type is one of the NetCDF's\n    //! \\b nc_type: \\b NC_CHAR. For all other values\n    //! of \\p type\n    //! \\b false is returned.\n    //!\n    //! \\param[in] type A NetCDF external data type\n    //! \\retval bool True if \\p type represents an char data type\n    //!\n    static bool IsNCTypeText(int type);\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const NetCDFSimple &nc);\n\nprotected:\n    int                                                 _ncid;\n    std::map<int, int>                                  _ovr_table;    // open variable map: fd -> varid\n    string                                              _path;\n    std::vector<string>                                 _dimnames;\n    std::vector<size_t>                                 _dims;\n    std::vector<string>                                 _unlimited_dimnames;\n    std::vector<std::pair<string, std::vector<double>>> _flt_atts;\n    std::vector<std::pair<string, std::vector<long>>>   _int_atts;\n    std::vector<std::pair<string, string>>              _str_atts;\n    std::vector<NetCDFSimple::Variable>                 _variables;\n\n    int _GetAtts(int ncid, int varid, std::vector<std::pair<string, std::vector<double>>> &flt_atts, std::vector<std::pair<string, std::vector<long>>> &int_atts,\n                 std::vector<std::pair<string, string>> &str_atts);\n};\n\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/NonCopyableMixin.h",
    "content": "#pragma once\n\nnamespace VAPoR {\n\n//! \\class NonCopyableMixin\n//! \\ingroup Public_Common\n//! \\brief Mixin class that prevents copying\n//! \\author Stas Jaroszynski\n//! \\version 1.0\n//! \\date May 2019\n//!\n//! If a class inherits from this class, attempting to copy it will throw\n//! a compiler error.\n//!\n//! This class is used as follows:\n//!\n//! class NonCopyableObject : private NonCopyableMixin\n\nclass NonCopyableMixin {\nprotected:\n    NonCopyableMixin() {}\n    ~NonCopyableMixin() {}\n\nprivate:\n    NonCopyableMixin(const NonCopyableMixin &) = delete;\n    NonCopyableMixin &operator=(const NonCopyableMixin &) = delete;\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/OSPRay.h",
    "content": "#pragma once\n#ifdef BUILD_OSPRAY\n    #include <ospray/ospray_util.h>\n#endif\n#include <string>\n#include <glm/glm.hpp>\n#include <vapor/common.h>\n\n//! \\brief OSPRay integration interface and utility functions\n//! \\author Stanislaw Jaroszynski\n\nnamespace VOSP {\nRENDER_API int Initialize(int *argc, char **argv);\nRENDER_API int Shutdown();\nRENDER_API std::string Version();\nRENDER_API bool        IsVersionAtLeast(int major, int minor);\n\n#ifdef BUILD_OSPRAY\nOSPData NewCopiedData(const void *data, OSPDataType type, uint64_t numItems1, uint64_t numItems2 = 1, uint64_t numItems3 = 1);\n// void LoadTransferFunction(VAPoR::MapperFunction *vtf, OSPTransferFunction otf);\nOSPTexture OSPDepthFromGLPerspective(float fovy, float aspect, float zNear, float zFar, glm::vec3 cameraDir, glm::vec3 cameraUp, const float *glDepthBuffer, int width, int height);\n\nnamespace Test {\nOSPGeometricModel LoadTriangle(glm::vec3 scale = glm::vec3(1.f), const std::string &rendererType = \"scivis\");\n}\n#endif\n}    // namespace VOSP\n"
  },
  {
    "path": "include/vapor/OpacityMap.h",
    "content": "//--OpacityMap.h ---------------------------------------------------------\n//\n// Copyright (C) 2006 Kenny Gruchalla.  All rights reserved.\n//\n// Various types of mappings from opacity to data value.\n//\n//----------------------------------------------------------------------------\n\n#ifndef OpacityMap_H\n#define OpacityMap_H\n\n#include <iostream>\n#include <vapor/ParamsBase.h>\n#include <vapor/TFInterpolator.h>\n\n#ifdef WIN32\n    #include <vapor/glutil.h>\n#endif\n\nnamespace VAPoR {\n\nclass PARAMS_API OpacityMap : public ParamsBase {\npublic:\n    enum Type { CONTROL_POINT, GAUSSIAN, INVERTED_GAUSSIAN, SINE };\n\n    //! Create a OpacityMap object from scratch\n    //\n    OpacityMap(ParamsBase::StateSave *ssave);\n\n    //! Create a OpacityMap object from an existing XmlNode tree\n    //\n    OpacityMap(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~OpacityMap();\n    void clear();\n\n    float opacityDataAtNorm(float nv) const;\n    float opacityData(float value) const;\n    bool  inDataBounds(float value) const;\n\n    void SetType(OpacityMap::Type type);\n\n    OpacityMap::Type GetType() const { return (OpacityMap::Type)GetValueLong(_typeTag, CONTROL_POINT); }\n\n    void           SetDataBounds(const vector<double> &bounds);\n    vector<double> GetDataBounds() const;\n\n    double minValue() const;\n    double maxValue() const;\n\n    void setMinValue(double val);\n    void setMaxValue(double val);\n\n    bool   IsEnabled() { return (GetValueLong(_enabledTag, 0) != 0 ? true : false); }\n    void   SetEnabled(bool enabled);\n    double GetMean() const { return GetValueDouble(_meanTag, 0.5); }\n    void   SetMean(double mean);\n    double GetSSQ() const { return GetValueDouble(_ssqTag, 0.1); }\n    void   SetSSQ(double ssq);\n    double GetFreq() const { return GetValueDouble(_freqTag, 5.0); }\n    void   SetFreq(double freq);\n    double GetPhase() const { return GetValueDouble(_phaseTag, 2 * M_PI); }\n    void   SetPhase(double phase);\n\n    int numControlPoints() const { return (int)GetControlPoints().size() / 2; }\n\n    void addNormControlPoint(float normv, float opacity);    // Normalized Coords\n    void addControlPoint(float value, float opacity);        // Data Coordinates\n    void deleteControlPoint(int index);\n    void moveControlPoint(int index, float dx, float dy);    // Data Coordinates\n\n    float controlPointOpacity(int index) const;\n    void  controlPointOpacity(int index, float opacity);\n\n    float controlPointValueNormalized(int index) const;\n    float controlPointValue(int index) const;    // Data Coordinates\n    void  controlPointValueNormalized(int index, float nv);\n    void  controlPointValue(int index, float value);    // Data Coordinates\n\n    void setOpaque();\n    bool isOpaque() const;\n\n    void SetInterpType(TFInterpolator::type t);\n\n    TFInterpolator::type GetInterpType() const { return (TFInterpolator::type)GetValueLong(_interpTypeTag, TFInterpolator::linear); }\n\n    vector<double> GetControlPoints() const;\n    void           SetControlPoints(const vector<double> &opacityControlPoints);\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"OpacityMapParams\"); }\n\nprivate:\n    int leftControlIndex(float val) const;\n\n    double normSSq(double ssq);\n    double denormSSq(double ssq);\n\n    double normSineFreq(double freq);\n    double denormSineFreq(double freq);\n\n    double normSinePhase(double phase);\n    double denormSinePhase(double phase);\n\n    const double _minSSq;\n    const double _maxSSq;\n    const double _minFreq;\n    const double _maxFreq;\n    const double _minPhase;\n    const double _maxPhase;\n\n    static const string _relMinTag;\n    static const string _relMaxTag;\n    static const string _enabledTag;\n    static const string _meanTag;\n    static const string _ssqTag;\n    static const string _freqTag;\n    static const string _phaseTag;\n    static const string _typeTag;\n    static const string _controlPointsTag;\n    static const string _interpTypeTag;\n    static const string _opacityMapIndexTag;\n    static const string _dataBoundsTag;\n};\n};    // namespace VAPoR\n\n#endif    // OpacityMap_H\n"
  },
  {
    "path": "include/vapor/OpenMPSupport.h",
    "content": "#ifndef OPENMPSUPPORT_H\n#define OPENMPSUPPORT_H\n\n#ifdef USE_OMP\n    #include <omp.h>\n#else\n\n#define omp_get_num_threads() (1)\n#define omp_set_num_threads(x) (void(x))\n#define omp_get_thread_num() (0)\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/vapor/OptionParser.h",
    "content": "//\n//      $Id$\n//\n//************************************************************************\n//\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t*\n//     University Corporation for Atmospheric Research\t\t*\n//\t\t     All Rights Reserved\t\t\t*\n//\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tWed Oct  6 10:49:44 MDT 2004\n//\n//\tDescription:\tA class for parsing command line options.  This\n//\t\t\t\t\tclass  manages a resource data base of valid command line\n//\t\t\t\t\toptions. Valid options may be merged into the data base\n//\t\t\t\t\tat any time and later extracted with their\n//\t\t\t\t\tcoresponding values as determined by the command line.\n//\n//\n\n#ifndef _OptionParser_h_\n#define _OptionParser_h_\n\n#include <string>\n#include <cmath>\n#include <vector>\n#include <vapor/MyBase.h>\n#include <vapor/common.h>\n\n#ifdef WIN32\n    // Silence an annoying and unnecessary compiler warning\n    #pragma warning(disable : 4251)\n#endif\nusing namespace std;\n\nnamespace Wasp {\n\n//\n//\nclass COMMON_API OptionParser : public MyBase {\npublic:\n    //! An option description record (odr)\n    //\n    //! A structure for descriping an option\n    //! \\param option The name of the option\n    //! \\param arg_count Number of arguments expected by the option\n    //! \\param value Option's default value\n    //! \\param help A C string containing a help message for the option\n    //\n    typedef struct _OptDescRec {\n        const char *option;\n        int         arg_count;\n        const char *value;\n        const char *help;\n    } OptDescRec_T;\n\n    //\n    //  structure for returning the value of an option\n    //\n    typedef struct _DPOption {\n        const char *option_name;    // the options name\n\n        //\n        // option type converter\n        //\n        int (*type_conv)(const char *from, void *to);\n\n        void *offset;    // offset of return address\n        int   size;      // size of option in bytes\n    } Option_T;\n\n    typedef struct _EnvOpt {\n        const char *option;     // option name\n        const char *env_var;    // coresponding enviroment var\n    } EnvOpt_T;\n\n    typedef int Boolean_T;\n    typedef struct Dimension2D_ {\n        int nx, ny;\n    } Dimension2D_T;\n\n    typedef struct Dimension3D_ {\n        int nx, ny, nz;\n    } Dimension3D_T;\n\n    // Converter type for CvtToIntRange()\n    //\n    typedef struct IntRange_ {\n        int min, max;\n    } IntRange_T;\n\n    OptionParser();\n    ~OptionParser();\n\n    //! Append a list of option descriptions\n    //\n    //! Append a list of option descriptions. The input option\n    //! descriptor records are appended to the current list of option\n    //! description records.\n    //! \\param[in] odr A null-terminated option descriptor record.\n    //! \\sa ParseOptions(), RemoveOptions()\n    //\n    int AppendOptions(const OptDescRec_T *odr);\n\n    //! Parse a command line argument vector\n    //\n    //! Destrutively parse a command line argument vector against\n    //! the option descriptor records (odr) supplied by previous invocations\n    //! of \\b AppendOptions(). Command line arguments that match option\n    //! names in the odr and the input option table are\n    //! \\param[in,out] argc A pointer to a count of the number of elements\n    //! in \\b argv\n    //! \\param[in,out] argv A null-terminated vector of command line arguments\n    //! \\param[in,out] opts A null-terminated option table\n    //! \\sa ParseOptions(), RemoveOptions()\n    int  ParseOptions(int *argc, char **argv, Option_T *opts);\n    int  ParseOptions(const EnvOpt_T *envv, Option_T *opts);\n    void RemoveOptions(std::vector<string> options);\n    void PrintOptionHelp(FILE *fp, int linelimit = 80, bool docopyright = true);\n\n    typedef struct _OptRec {\n        const char *option;           // name of option without preceeding '-'\n        const char *value;            // current val for the argument\n        const char *default_value;    // default val for the argument\n        const char *help;             // help string for option\n        int         arg_count;        // num args expected by option\n    } _OptRec_T;\n\nprivate:\n    vector<struct _OptRec *> _optTbl;\n\n    _OptRec_T *_get_option(const char *name);\n    int        _parse_options(const Option_T *opts);\n\n    friend bool opt_cmp(OptionParser::_OptRec_T *a, OptionParser::_OptRec_T *b);\n};\n\nCOMMON_API int CvtToInt(const char *from, void *to);\n\nCOMMON_API int CvtToFloat(const char *from, void *to);\n\nCOMMON_API int CvtToDouble(const char *from, void *to);\n\nCOMMON_API int CvtToChar(const char *from, void *to);\n\nCOMMON_API int CvtToBoolean(const char *from, void *to);\n\nCOMMON_API int CvtToString(const char *from, void *to);\n\nCOMMON_API int CvtToCPPStr(const char *from, void *to);\n\nCOMMON_API int CvtToDimension2D(const char *from, void *to);\n\nCOMMON_API int CvtToDimension3D(const char *from, void *to);\n\n// convert a colon delimited ascii string to vector of C++\n// STL strings: (vector <string> *)\n//\nCOMMON_API int CvtToStrVec(const char *from, void *to);\n\n// convert a colon delimited ascii string to vector of C++\n// STL ints: (vector <int> *)\n//\nCOMMON_API int CvtToIntVec(const char *from, void *to);\n\n// convert a colon delimited ascii string to vector of C++\n// STL size_t: (vector <size_t> *)\n//\nCOMMON_API int CvtToSize_tVec(const char *from, void *to);\n\n// convert a colon delimited ascii string to vector of C++\n// STL ints: (vector <float> *)\n//\nCOMMON_API int CvtToFloatVec(const char *from, void *to);\n\nCOMMON_API int CvtToDoubleVec(const char *from, void *to);\n\n// Convert a colon-delimited pair of integers to a IntRange_T type\n//\nCOMMON_API int CvtToIntRange(const char *from, void *to);\n\n};    // namespace Wasp\n\n#endif\n"
  },
  {
    "path": "include/vapor/PNGWriter.h",
    "content": "#pragma once\n\n#include \"vapor/ImageWriter.h\"\n\nnamespace VAPoR {\nclass RENDER_API PNGWriter : public ImageWriter {\nprotected:\npublic:\n    PNGWriter(const string &path);\n    ~PNGWriter(){};\n\n    static std::vector<std::string> GetFileExtensions();\n    int                             Write(const unsigned char *buffer, const unsigned int width, const unsigned int height);\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/PVTime.h",
    "content": "//\n//      $Id$\n//\n//************************************************************************\n//\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t*\n//     University Corporation for Atmospheric Research\t\t*\n//\t\t     All Rights Reserved\t\t\t*\n//\t\t\t\t\t\t\t\t*\n//************************************************************************/\n\n#ifndef _PVTime_h_\n#define _PVTime_h_\n\n#include <cmath>\n#include <string>\n#include <ctime>\n#ifndef WIN32\n    #include <stdint.h>\n#endif\n#include <vapor/common.h>\n\n#ifndef TIME64_T\n    #ifdef WIN32\n        #define TIME64_T __int64\n    #else\n        #define TIME64_T int64_t\n    #endif\n#endif\n\nusing namespace std;\n\nnamespace Wasp {\n\nCOMMON_API TIME64_T   MkTime64(struct tm *t);\nCOMMON_API struct tm *LocalTime64_r(const TIME64_T *t, struct tm *p);\nCOMMON_API struct tm *GmTime64_r(const TIME64_T *t, struct tm *p);\n\n};    // namespace Wasp\n\n#endif    // _PVTime_h_\n"
  },
  {
    "path": "include/vapor/ParamsBase.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2008\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tParamsBase.h\n//\n//\tAuthor:\t\tJohn Clyne, modified by Alan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tMarch 2008\n//\n//\tDescription:\n//\t\tDefines the ParamsBase class\n//\t\tThis is an abstract class for classes that rely on\n//\t\taccessing an XML node for get/set\n//\n\n#ifndef ParamsBase_H\n#define ParamsBase_H\n\n#include \"vapor/VAssert.h\"\n#include <functional>\n#include <vapor/MyBase.h>\n#include <vapor/XmlNode.h>\n\n#define PARAMS_IMPL_TAG(class, tag) const std::string class::tag = #tag;\n\nnamespace VAPoR {\n\n//\n//! \\class ParamsBase\n//! \\brief Nodes with state in Xml tree representation\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This is pure abstract base class that may be derived for\n//! to maintain parameter state information in a manner that\n//! supports session save/restore and undo/redo operations. All\n//! session state is maintained in an XML tree that may be\n//! written to a file and subsequently used to reinitialize ParamsBase\n//! class objects.\n//!\n//!\nclass PARAMS_API ParamsBase : public Wasp::MyBase {\npublic:\n    //! \\class StateSave\n    //! \\brief State capture class\n    //!\n    //! A class for capturing state changes. A pointer to an\n    //! instance of this class is passed to the ParamsBase constructor.\n    //! Any changes to the ParamsBase are recorded to StateSave by\n    //! calling StateSave::Save() with the effected node and\n    //! a description of the change. It is expected that users of ParamsBase\n    //! will re-implement StateSave to suit their own needs\n    //\n    class StateSave {\n    public:\n        //! Capture current state\n        //!\n        //! If the value of GetSaveState() is true this method is called prior\n        //! to making any changes to the internal state\n        //!\n        virtual void Reinit(const XmlNode *rootNode) {}\n        virtual void Save(const XmlNode *node, string description) {}\n        virtual void BeginGroup(string description) {}\n        virtual void EndGroup() {}\n        virtual void IntermediateChange() {}\n        virtual void SetEnabled(bool onOff) {}\n        virtual bool GetEnabled() const { return (false); }\n        virtual void SetUndoEnabled(bool b) {}\n        virtual bool GetUndoEnabled() const { return false; }\n    };\n\n    // NO DEFAULT CONSTRUCTOR\n    //\n    // ParamsBase();\n\n    //! Create a ParamsBase object from scratch\n    //!\n    //! \\param[in] ssave StateSave class object that will be used to record\n    //! state changes made to this class.\n    //!\n    //! \\param[in] classname The string identifier associated with a\n    //! derived class that will be used to create new instances of that\n    //! class via the ParamsFactory factory object.\n    //!\n    ParamsBase(StateSave *ssave, const string &classname);\n\n    //! Create a ParamsBase object from an existing XmlNode tree\n    //!\n    //! This method will construct a ParamsBase object using an\n    //! existing XML tree. Hence it should NOT do any initialization\n    //! that changes parameter values.\n    //\n    ParamsBase(StateSave *ssave, XmlNode *node);\n\n    //! Copy constructor.\n    ParamsBase(const ParamsBase &rhs);\n\n    ParamsBase &operator=(const ParamsBase &rhs);\n\n    //! Explicit delete the two flavors of move constructor,\n    //! so they ain't called accidentally.\n    ParamsBase(ParamsBase &&) = delete;\n    ParamsBase &operator=(ParamsBase &) = delete;\n\n    //! Equivalence operator\n    //\n    bool operator==(const ParamsBase &rhs) const { return (_ssave == rhs._ssave && *_node == *(rhs._node)); }\n\n    bool operator!=(const ParamsBase &rhs) const { return (!(*this == rhs)); };\n\n    //! Destroy object\n    //!\n    //! Destroys all resources except possibly the XmlNode and\n    //! its children associated\n    //! with this object. If this objects node is a root node (i.e. has\n    //! no parent) the node is freed. Otherwise it is not.\n    //!\n    virtual ~ParamsBase();\n\n    //! Set parent\n    //!\n    //! This method sets the parent of the ParamsBase class to\n    //! \\p parent, modifying both this class instance and the parent\n    //!\n    //! \\param[in] parent A pointer to a parent ParamsBase class . If\n    //! NULL the class will become parentless\n    //\n    void SetParent(ParamsBase *parent);\n\n    XmlNode *GetNode() const { return _node; }\n\n    void BeginGroup(const string &description) { _ssave->BeginGroup(description); }\n    void EndGroup() { _ssave->EndGroup(); }\n    void IntermediateChange() { _ssave->IntermediateChange(); }\n\n    virtual vector<long> GetValueLongVec(const string tag) const;\n\n    virtual vector<long> GetValueLongVec(const string tag, const vector<long> &defaultVal) const;\n\n    virtual long GetValueLong(const string tag, long defaultVal) const;\n\n    virtual vector<double> GetValueDoubleVec(const string tag) const;\n\n    virtual vector<double> GetValueDoubleVec(const string tag, const vector<double> &defaultVal) const;\n\n    virtual double GetValueDouble(const string tag, double defaultVal) const;\n\n    virtual vector<string> GetValueStringVec(const string tag) const;\n\n    virtual vector<string> GetValueStringVec(const string tag, const vector<string> &defaultVal) const;\n\n    virtual string GetValueString(const string tag, string defaultVal) const;\n\n    virtual void SetValueLongVec(const string &tag, string description, const vector<long> &values);\n\n    virtual void SetValueLong(const string &tag, string description, long value);\n\n    virtual void SetValueDoubleVec(const string &tag, string description, const vector<double> &values);\n\n    virtual void SetValueDouble(const string &tag, string description, double value);\n\n    virtual void SetValueStringVec(const string &tag, string description, const vector<string> &values);\n\n    virtual void SetValueString(const string &tag, string description, const string &value);\n\n    //!\n    //! Method for obtaining the name and/or tag associated with the instance\n    //!\n    string GetName() const\n    {\n        VAssert(_node);\n        return (_node->Tag());\n    }\n\nprotected:\n    ParamsBase(StateSave *ssave);\n\n    //! Delete the named branch.\n    //!\n    //! This method deletes the named child, and all decendents, of the current\n    //! destroying it's contents in the process. The\n    //! named node must be a child of the current node. If the named node\n    //! does not exist the result is a no-op.\n    //!\n    //! \\param[in] name The name of the branch\n    //\n    void Remove(const string &name);\n\n    //! Return the attributes associated with the current branch\n    //!\n    //! \\retval map attribute mapping\n    //\n    const map<string, string> &GetAttributes();\n\n    //! Remove (undefine) all parameters\n    //!\n    //! This method deletes any and all paramters contained in the base\n    //! class as well as deleting any tree branches.\n    //\n    void Clear();\n\nprotected:\n    StateSave *_ssave;\n    XmlNode *  _node;\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// ParamsSeparator Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nclass PARAMS_API ParamsSeparator : public ParamsBase {\npublic:\n    ParamsSeparator(StateSave *ssave, const string &name);\n\n    ParamsSeparator(StateSave *ssave, XmlNode *node);\n\n    ParamsSeparator(ParamsSeparator *parent, const string &name);\n\n    virtual ~ParamsSeparator() {}\n\n    bool HasChild(const string &name) { return (GetNode()->HasChild(name)); }\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// ParamsFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nclass PARAMS_API ParamsFactory {\npublic:\n    static ParamsFactory *Instance()\n    {\n        static ParamsFactory instance;\n        return &instance;\n    }\n\n    void RegisterFactoryFunction(string name, function<ParamsBase *(ParamsBase::StateSave *, XmlNode *)> classFactoryFunction)\n    {\n        // register the class factory function\n        m_factoryFunctionRegistry[name] = classFactoryFunction;\n    }\n\n    ParamsBase *(CreateInstance(string classType, ParamsBase::StateSave *, XmlNode *));\n\n    vector<string> GetFactoryNames() const;\n\nprivate:\n    map<string, function<ParamsBase *(ParamsBase::StateSave *, XmlNode *)>> m_factoryFunctionRegistry;\n\n    ParamsFactory() {}\n    ParamsFactory(const ParamsFactory &) {}\n    ParamsFactory &operator=(const ParamsFactory &) { return *this; }\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// ParamsRegistrar Class\n//\n// Register ParamsBase derived class with:\n//\n//\tstatic ParamsRegistrar<ParamsClass> registrar(\"myclassname\");\n//\n// where 'ParamsClass' is a class derived from 'ParamsBase', and\n// \"myclassname\" is the name of the class\n//\n/////////////////////////////////////////////////////////////////////////\n\ntemplate<class T> class ParamsRegistrar {\npublic:\n    ParamsRegistrar(string classType)\n    {\n        // register the class factory function\n        //\n        ParamsFactory::Instance()->RegisterFactoryFunction(classType, [](ParamsBase::StateSave *ssave, XmlNode *node) -> ParamsBase * {\n            if (node)\n                return new T(ssave, node);\n            else\n                return new T(ssave);\n        });\n    }\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// ParamsContainer Class\n//\n/////////////////////////////////////////////////////////////////////////\n\n//\n// The ParamsContainer class constructs an XML tree as depicted below,\n// where 'Container Name' is the root of XML tree, and is the name\n// passed into the constructor as 'myname'; 'Class Name' is the name of\n// the derived ParamsBase class used to construct new instances of\n// the derived class; and 'ele name x' is the unique name of the element\n// contained in the container.\n//\n/*\n            |----------------|\n            | Container Name |\n            |----------------|\n                    |\n                   \\|/\n            |----------------|\n            |   Class Name   |\n            |----------------|\n                    |         \\\n                   \\|/         \\\n            |----------------|  \\ |----------------|\n            |   ele name 1   |....|   ele name n   |\n            |----------------|    |----------------|\n*/\nclass PARAMS_API ParamsContainer : public Wasp::MyBase {\npublic:\n    ParamsContainer(ParamsBase::StateSave *ssave, const string &myname);\n\n    ParamsContainer(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    //! Copy constructor.\n    ParamsContainer(const ParamsContainer &rhs);\n\n    ParamsContainer &operator=(const ParamsContainer &rhs);\n\n    //! Destroy object\n    //!\n    //! Destroys all resources except possibly the XmlNode associated\n    //! with this object. If this object's node is a root node (i.e. has\n    //! no parent) the node is freed. Otherwise it is not\n    //!\n    virtual ~ParamsContainer();\n\n    //! Set parent\n    //!\n    //! This method sets the parent of the ParamsBase class to\n    //! \\p parent, modifying both this class instance and the parent\n    //!\n    //! \\param[in] parent A pointer to a parent ParamsBase class . If\n    //! NULL the class will become parentless\n    //\n    void SetParent(ParamsBase *parent) { GetNode()->SetParent(parent->GetNode()); }\n\n    ParamsBase *Insert(ParamsBase *pb, string name);\n\n    ParamsBase *Create(string classType, string name);\n\n    void Remove(string name);\n\n    void Remove(const ParamsBase *pb) { Remove(GetParamsName(pb)); }\n\n    ParamsBase *GetParams(string name) const;\n\n    string GetParamsName(const ParamsBase *pb) const;\n\n    vector<string> GetNames() const;\n\n    size_t Size() const { return (_elements.size()); }\n\n    XmlNode *GetNode() const { return _separator->GetNode(); }\n\nprivate:\n    ParamsBase::StateSave *_ssave;\n    // XmlNode *_node;\n    ParamsSeparator *         _separator;\n    map<string, ParamsBase *> _elements;\n};\n\n};    // End namespace VAPoR\n\n#endif    // ParamsBase_H\n"
  },
  {
    "path": "include/vapor/ParamsMgr.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tParamsMgr.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tFebruary 2016\n//\n//\tDescription:\tDefines the ParamsMgr  class.\n//\t\tThis provides an API for manipulating the Params Objects that are used in VAPOR applications\n//\n#ifndef PARAMSMGR_H\n#define PARAMSMGR_H\n\n#include \"vapor/VAssert.h\"\n#include <map>\n#include <deque>\n#include <stack>\n#include <utility>\n#include <functional>\n\n#include <vapor/DataMgr.h>\n#include <vapor/ParamsBase.h>\n#include <vapor/RenderParams.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/regionparams.h>\n#include <vapor/AnnotationParams.h>\n#include <vapor/DatasetsParams.h>\n\nnamespace VAPoR {\n\n//!\n//!\n\n//! \\class ParamsMgr\n//! \\ingroup Public_Params\n//! \\brief A singleton class for managing Params instances\n//!\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    February 2016\n//!\n\n//!\nclass PARAMS_API ParamsMgr : public MyBase {\npublic:\n    //! ParamsMgr constructor\n    //!\n    //! \\param[in] appParamsNames A vector of unique ParamsBase class\n    //! names previously\n    //! registered with ParamsRegistrar(). The ParamsMgr will construct\n    //! these application-defined classes as needed.\n    //! If any of the class names in \\p appParamsNames were not\n    //! previously registered via ParamsRegistrar() they will be ignored.\n    //!\n    //! \\param[in] appRenderParamsNames A vector of unique RenderParams class\n    //! names previously\n    //! registered with RenParamsRegistrar(). The ParamsMgr will construct\n    //! these application-defined render params classes as needed.\n    //! If any of the class names in \\p appRenderParamsNames were not\n    //! previously registered via RenParamsRegistrar() they will be ignored.\n    //!\n    //! \\sa ParamsRegistrar()\n    //\n    ParamsMgr(std::vector<string> appParamNames = std::vector<string>(), std::vector<string> appRenderParamNames = std::vector<string>());\n\n    //! Destroy object\n    //!\n    virtual ~ParamsMgr();\n\n    //! Load the default state\n    //!\n    //! This method resets the entire parameter state to the default values.\n    //\n    virtual void LoadState();\n\n    //! Load the parameter state from an XmlNode tree\n    //!\n    //! This method resets the entire parameter state to the state specified\n    //! by the XmlNode tree whose root is \\p node. Any unrecognized nodes\n    //! in \\p node will be ignored.\n    //\n    virtual void LoadState(const XmlNode *node);\n\n    //! Load the parameter state from a file\n    //!\n    //! This method resets the entire parameter state to the state specified\n    //! by the file named by \\p stateFile. Any unrecognized nodes\n    //! in \\p stateFile will be ignored.\n    //\n    virtual int LoadState(string stateFile);\n\n    //! Add a DataMgr to the ParamsMgr class\n    //!\n    //! This method associates a data set name \\p dataSetName with a\n    //! DataMgr \\p dataMgr. Methods on this class that take a data set\n    //! name as an argument can not be invoked until the data set name is\n    //! bound to a DataMgr instance.\n    //!\n    void AddDataMgr(string dataSetName, DataMgr *dataMgr);\n\n    //! Remove a previously created Window instance\n    //!\n    //! \\param [in] winName Window name  to remove\n    //\n    void RemoveVisualizer(string winName);\n\n    //! Remove a DataMgr instance previously.\n    //!\n    //! This method removes the association of a DataMgr instance with\n    //! the data set name \\p dataSetName, previously made by AddDataMgr()\n    //!\n    void RemoveDataMgr(string dataSetName);\n\n    //! Return list of all DataMgr names\n    //!\n    //! Return a list of all DataMgr names bound with AddDataMgr()\n    //\n    vector<string> GetDataMgrNames() const;\n\n    //! Create a new ViewpointParams instances\n    //!\n    //! This method will create a new ViewpointParams instance\n    //!\n    //! \\param [in] winName Window name to associate the new RenderParams\n    //! object with.\n    //!\n    //! \\retval ptr Returns the name of the newly created object.\n    //!\n    //! \\sa RenParamsRegistrar, RenParamsFactory\n    //! GetRenderParams()\n    //\n    string CreateVisualizerParamsInstance(string winName = \"__AUTO__\");\n\n    //! Remove a previously created ViewpointParams instance\n    //!\n    //! \\param [in] winName Window name  to remove\n    //\n    void RemoveVisualizerParamsInstance(string winName);\n\n    //! Create a new rendering params instances\n    //!\n    //! This method will create a new instance of an object derived\n    //! from the RenderParams class. The object will be created with\n    //! the RenParamsFactory and its type must have been\n    //! registered with RenParamsRegistrar. The new RenderParams\n    //! instance will be associated with the window named by \\p winName.\n    //!\n    //! \\param [in] winName Window name to associate the new RenderParams\n    //! object with.\n    //! \\param [in] classType Class name used to register the derived RenderParams\n    //! object with.\n    //! \\param [in] instName Name to associate with the new object.\n    //!\n    //! \\retval ptr Returns a pointer to the newly created object on success,\n    //! and NULL on failure. This method will fail if the data set\n    //! \\p dataSetName was not previously bound with AddDataMgr()\n    //! exist, or if \\p classType does not refer to a valid RenderParams\n    //! derived class.\n    //!\n    //! \\sa RenParamsRegistrar, RenParamsFactory, AddDataMgr(),\n    //! GetRenderParams(), AddDataMgr()\n    //! \\sa RemoveRenderParamsInstance()\n    //\n    RenderParams *CreateRenderParamsInstance(string winName, string dataSetName, string classType, string instName);\n\n    //! Create a render params instance from an existing one\n    //!\n    //! Copies the RenderParams instance \\p rp into the hierarchy and\n    //! associates it with the visualizer \\p winName and gives it the name\n    //! \\p instName. If a RenderParams instance is already associated with\n    //! \\p winName and \\p instName the existing RenderParams instance is\n    //! destroyed.\n    //!\n    //! \\param[in] winName Window name to associate the new RenderParams\n    //! object with.\n    //! \\param[in] instName Name to associate with the new object.\n    //! \\param[in] rp Pointer to a valid RenderParams instance to insert\n    //!\n    //! \\retval pointer Pointer to the newly created RenderParams instance\n    //\n    RenderParams *CreateRenderParamsInstance(string winName, string dataSetName, string instName, const RenderParams *rp);\n\n    //! Remove a previously created RenderParams instance\n    //!\n    //! This method removes from the session state a previously created\n    //! RenderParams instance. If the identified RenderParams instance\n    //! does not exist this method is a no-op.\n    //!\n    //! \\params [in] winName Window name that the RenderParams instance is\n    //! associated with.\n    //! \\param [in] classType Class name used to register the derived RenderParams\n    //! object with.\n    //! \\param [in] instName Name associated with the object to destroy.\n    //!\n    //! \\sa RenParamsRegistrar, RenParamsFactory\n    //! GetRenderParams()\n    //! \\sa CreateRenderParamsInstance()\n    //\n    void RemoveRenderParamsInstance(string winName, string dataSetName, string classType, string instName);\n\n    //! Return a previously created RenderParams instance\n    //!\n    //! This method returns from the session state a previously created\n    //! RenderParams instance. If the identified RenderParams instance\n    //! does not exist this A NULL is returned, but no error is generated.\n    //!\n    //! \\params [in] winName Window name that the RenderParams instance is\n    //! associated with.\n    //! \\param [in] classType Class name used to register the derived RenderParams\n    //! object with.\n    //! \\param [in] instName Name associated with the object to destroy.\n    //!\n    //! \\sa RenParamsRegistrar, RenParamsFactory, AddDataMgr(),\n    //! GetRenderParams()\n    //! \\sa CreateRenderParamsInstance()\n    //!\n    //! \\retval ptr If the identified RenderParams instance exists in the\n    //! session state it is returned, otherwise NULL is returned. The latter\n    //! case does not generate an error\n    //\n    RenderParams *GetRenderParams(string winName, string dataSetName, string classType, string instName) const;\n\n    void GetRenderParams(string winName, string dataSetName, vector<RenderParams *> &rParams) const;\n\n    void GetRenderParams(string winName, vector<RenderParams *> &rParams) const;\n\n    void GetRenderParams(vector<RenderParams *> &rParams) const;\n\n    //! Return all render param instance names\n    //!\n    //! Return all of the RenderParam instance names associated with\n    //! the visualizer (window) named \\p winName, the data set named\n    //! \\p dataSetName, and the Params class type \\p classType\n    //!\n    //! The returned names are guaranteed to be unique.\n    //!\n    void GetRenderParamNames(string winName, string dataSetName, string classType, vector<string> &instNames) const;\n\n    void GetRenderParamNames(string winName, string dataSetName, vector<string> &instNames) const;\n\n    void GetRenderParamNames(string winName, vector<string> &instNames) const;\n\n    void GetRenderParamNames(vector<string> &instNames) const;\n    vector<string> GetRenderParamNames() const;\n\n    vector<string> GetRenderParamNamesForDataset(string datasetName) const;\n\n    //! Lookup window, data set, and class name from a render instance name\n    //!\n    //! This method returns the window name \\p winName, data set name\n    //! \\p dataSetName, and render params type \\p className that are associated\n    //! with the render instance name \\p instName.\n    //!\n    //! \\retval status True on success, false if \\p instName is not a previously\n    //! defined render instance name\n    //!\n    //! \\sa CreateRenderParamsInstance\n    //\n    bool RenderParamsLookup(string instName, string &winName, string &dataSetName, string &className) const;\n    bool RenderParamsLookup(RenderParams* inst, string &instName, string &winName, string &dataSetName, string &className) const;\n\n    //! Returns all defined window (aka visualizer names).\n    //!\n    //! This method will return all defined window names in the session state\n    //!\n    //! \\retval names A vector of window names, possibly an empty vector if\n    //! none exist.\n    //!\n    //! \\sa CreateRenderParamsInstance()\n    //\n    vector<string> GetVisualizerNames() const;\n\n    //! Returns renderer types (aka class names) defined for window \\p winName\n    //!\n    //! This method returns a list of all RenderParams types associated\n    //! with the window \\p winName in the session state\n    //!\n    //! \\sa CreateRenderParamsInstance()\n    //! \\sa RenParamsRegistrar, RenParamsFactory\n    //\n    vector<string> GetRenderParamsClassNames(string winName) const;\n\n    //! Returns renderer types (aka class names) defined for window \\p winName\n    //! associated with a data set named by \\p dataSetName.\n    //! This method returns a list of all RenderParams types associated\n    //! with the window \\p winName in the session state\n    //!\n    //! \\sa CreateRenderParamsInstance()\n    //! \\sa RenParamsRegistrar, RenParamsFactory\n    //\n    vector<string> GetRenderParamsClassNames(string winName, string dataSetName) const;\n\n    //! Returns available renderer types (aka class names)\n    //!\n    //! This method returns a list of all registered RenderParams types\n    //! (class names)\n    //!\n    //! \\sa CreateRenderParamsInstance()\n    //! \\sa RenParamsRegistrar, RenParamsFactory\n    //\n    static vector<string> GetRenderParamsClassNamesAvail() { return (RenParamsFactory::Instance()->GetFactoryNames()); }\n\n    //! Returns renderer instance names defined on window \\p winName for\n    //! renderer type \\p classname\n    //!\n    //! This method returns the instance names of all RenderParams of\n    //! type \\p classType that are associated with the window \\p winName\n    //! in the current session state.\n    //!\n    //! \\sa CreateRenderParamsInstance()\n    //! \\sa RenParamsRegistrar, RenParamsFactory\n    //\n    vector<string> GetRenderParamInstances(string winName, string dataSetName, string classType) const;\n\n    vector<string> GetRenderParamInstances(string winName, string classType) const;\n\n    //! Obtain the ViewpointParams that are applicable in a particular Visualizer\n    //! window.\n    //!\n    //! Return the ViewpointParams instance associated with the\n    //! window named by \\p winName in the current session state\n    //!\n    //! \\retval ptr ViewpointParams instance that is applicable.\n    //\n    ViewpointParams *GetViewpointParams(string winName) const;\n\n    //! Obtain the RegionParams that are applicable in a particular Visualizer\n    //! window.\n    //!\n    //! Return the RegionParams instance associated with the\n    //! window named by \\p winName in the current session state\n    //!\n    //! \\retval ptr RegionParams instance that is applicable.\n    //\n    RegionParams *GetRegionParams(string winName) const { return ((RegionParams *)_otherParams->GetParams(RegionParams::GetClassType())); };\n\n    //! Obtain the AnnotationParams that are applicable in a particular Visualizer\n    //! window.\n    //!\n    //! Return the AnnotationParams instance associated with the\n    //! window named by \\p winName in the current session state\n    //!\n    //! \\retval ptr AnnotationParams instance that is applicable.\n    //\n    AnnotationParams *GetAnnotationParams(string winName) const { return ((AnnotationParams *)_otherParams->GetParams(AnnotationParams::GetClassType())); };\n\n    //! Obtain the DatasetsParams that are applicable in a particular Visualizer\n    //! window.\n    //!\n    //! \\retval ptr DatasetsParams instance that is applicable.\n    //\n    DatasetsParams *GetDatasetsParams() const { return ((DatasetsParams *)_otherParams->GetParams(DatasetsParams::GetClassType())); };\n\n    //! Optain any paramers registered by the application\n    //!\n    //! This method returns params that have been registered on the\n    //! ParamsMgr via the constructor\n    //!\n    //! \\retval params Pointer to requested params on success, or NULL\n    //! on failure. Fails if \\p classType was not registred with\n    //! the constructor or ParamsRegistrar\n    //!\n    //! \\sa ParamsMgr()\n    //\n    ParamsBase *GetParams(string classType) const { return (_otherParams->GetParams(classType)); }\n\n    // template <std::derived_from<ParamsBase> T> T* GetParams() const\n    template <class T> T* GetParams() const\n    {\n        return (T*)GetParams(T::GetClassType());\n    }\n\n    //! Optain any render paramers registered by the application\n    //!\n    //! This method returns params that have been registered on the\n    //! ParamsMgr via RegisterAppParams() for the data set named\n    //! by \\p dataSetName;\n    //!\n    //! \\param[in] dataSetName\n    //! \\param[in] classType\n    //!\n    //! \\retval params Pointer to requested params on success, or NULL\n    //! on failure. Fails if \\p classType was not registred with\n    //! the constructor or RenParamsRegistrar\n    //!\n    //!\n    //! \\sa ParamsMgr()\n    //\n    RenderParams *GetAppRenderParams(string dataSetName, string classType)\n    {\n        std::map<string, RenParamsContainer *>::const_iterator itr;\n        itr = _otherRenParams.find(dataSetName);\n        return (itr != _otherRenParams.cend() ? itr->second->GetParams(classType) : NULL);\n    }\n\n    //! Optain any render paramers registered by the application for a given data set\n    //!\n    //! This method returns params that have been registered on the\n    //! ParamsMgr via RegisterAppParams() for the data set named\n    //! by \\p dataSetName;\n    //!\n    //! \\param[in] dataSetName\n    //! \\param[out] appRenderParams a vector of application render params associated with \\p dataSetName\n    //!\n    //! \\sa ParamsMgr()\n    //\n    void GetAppRenderParams(string dataSetName, vector<RenderParams *> &appRenderParams) const;\n\n    //! Save current state to a file\n    //!\n    //! Save the current state of the parameter database to an XML file\n    //!\n    //! \\param[in] path Path to file\n    //\n    int SaveToFile(string path) const;\n\n    // const DataMgr *GetDataMgr() const {return (_dataMgr);}\n\n    //! Begin state save group\n    //!\n    //! Changes in state can be undone (redone) one at a time using\n    //! Undo() and Redo(), or can be grouped to together into a collection.\n    //! This method announces the start of such a collection group. The group\n    //! will be completed when EndSaveStateGroup() is called.\n    //! When a subsequent call\n    //! to Undo() or Redo() is made all of the state changes made within the\n    //! group are undone (redone) at once. Groups may be nested, in\n    //! which case the outermost group prevails.\n    //!\n    //! \\param[in] description A descriptive name for the group\n    //!\n    //! \\sa EndSaveStateGroup()\n    //!\n    void BeginSaveStateGroup(string description) { _ssave.BeginGroup(description); }\n\n    //! End state save group\n    //! \\sa BeginSaveStateGroup()\n    //\n    void EndSaveStateGroup() { _ssave.EndGroup(); };\n\n    //! Call callbacks registered for intermediate changes. These are changes inside of Save State Groups that\n    //! the rendering should still be updated to show.\n    void IntermediateChange() { _ssave.IntermediateChange(); }\n\n    void SetSaveStateEnabled(bool enabled) { _ssave.SetEnabled(enabled); }\n\n    bool GetSaveStateEnabled() const { return (_ssave.GetEnabled()); }\n\n    void PushSaveStateEnabled(bool enabled) { _saveStateEnabledStack.push(GetSaveStateEnabled()); SetSaveStateEnabled(enabled); }\n    void PopSaveStateEnabled() { SetSaveStateEnabled(_saveStateEnabledStack.top()); _saveStateEnabledStack.pop(); }\n\n    //! Enable/Disable adding params changes to the undo list.\n    //! When enabled, behaves as normal.\n    //! When disabled, params are saved as normal, however the undo list is not updated.\n    //! An example use case is to store a computed value in the params database.\n    void SetSaveStateUndoEnabled(bool enabled) { _ssave.SetUndoEnabled(enabled); }\n\n    //! Get whether updating the undo list is enabled.\n    bool GetSaveStateUndoEnabled() const { return (_ssave.GetUndoEnabled()); }\n\n    //! Restore state to previously saved state\n    //!\n    //! \\retval status Returns true on success, false if the state is unchanged\n    //! \\sa BeginSaveStateGroup()\n    //\n    bool Undo();\n\n    //! Restore state to state that existed prior to the last Undo()\n    //!\n    //! \\retval status Returns true on success, false if the state is unchanged\n    //! \\sa BeginSaveStateGroup()\n    //\n    bool Redo();\n\n    void UndoRedoClear();\n\n    void ManuallyAddCurrentStateToUndoStack(const string &note=\"\");\n\n    //! Return description string for event at top of undo stack\n    //\n    string GetTopUndoDesc() const;\n\n    //! Return description string for event at top of redo stack\n    //\n    string GetTopRedoDesc() const;\n\n    string GetStateChangeReasonDescription() const { return _ssave.GetStateChangeReasonDescription(); }\n\n    //! Return number states saved that can be undone with Undo()\n    //!\n    size_t UndoSize() const { return (_ssave.UndoSize()); }\n\n    size_t RedoSize() const { return (_ssave.RedoSize()); }\n\n    //! Register a boolean flag to capture state changes\n    //!\n    //! This method registers the address of boolean flag whose value\n    //! will be set whenever the parameter state changes. It is the user's\n    //! responsbility to clear (set to false) the flag. Note, for changes\n    //! grouped tegoer with BeginSaveStateGroup() the flag will not be set\n    //! until after EndSaveStateGroup() is called, and in the case of\n    //! nested groups, not until the last EndSaveStateGroup() invocation.\n    //\n    void RegisterStateChangeFlag(bool *flag) { _ssave.RegisterStateChangeFlag(flag); }\n\n    //! Register a state change callback\n    //!\n    //! This method is similar to RegisterStateChangeFlag(). However, instead of\n    //! setting a boolean flag, the function specified by \\p callback\n    //! will be invoked on state changes\n    //\n    void RegisterStateChangeCB(std::function<void()> callback) { _ssave.RegisterStateChangeCB(callback); }\n\n    //! Intermediate changes are changes inside of Save State Groups that\n    //! the rendering should still be updated to show.\n    void RegisterIntermediateStateChangeCB(std::function<void()> callback) { _ssave.RegisterIntermediateStateChangeCB(callback); }\n\n    //! Reinit state saving\n    //!\n    //!\n    void RebaseStateSave() { _ssave.Rebase(); }\n\n    const XmlNode *GetXMLRoot() const { return (_rootSeparator->GetNode()); }\n\n    //! Return true if any state changes made since last call\n    //!\n    //! This method returns a boolean indicating whether any changes\n    //! have been made to the parameter state since the last time\n    //! the method was called. The first time StateChanged() is called\n    //! it will return true;\n    //\n    bool StateChanged()\n    {\n        if (*(_rootSeparator->GetNode()) == _prevState) return (false);\n\n        _prevState = *(_rootSeparator->GetNode());\n        return (true);\n    }\n\n    void TriggerManualStateChangeEvent(const string &reason=\"\", const bool overrideEnabled=false)\n    {\n        _ssave.TriggerManualStateChangeEvent(reason, overrideEnabled);\n    }\n\nprivate:\n    class PMgrStateSave : public ParamsBase::StateSave {\n    public:\n        PMgrStateSave(int stackSize = 100);\n        ~PMgrStateSave();\n\n        void Reinit(const XmlNode *rootNode)\n        {\n            _rootNode = rootNode;\n            // Memory leak as this is called before initializing containers in ParamsMgr::_init\n            // emitStateChange();\n        }\n\n        void Rebase()\n        {\n            if (_state0) delete _state0;\n            _state0 = _rootNode ? new XmlNode(*_rootNode) : NULL;\n        }\n        void Save(const XmlNode *node, string description);\n        void BeginGroup(string descripion);\n        void EndGroup();\n        void TriggerManualStateChangeEvent(const string & reason=\"\", const bool overrideEnabled=false);\n        void IntermediateChange();\n\n        void SetEnabled(bool onOff)\n        {\n            if (!_groups.empty()) return;    // Can't change inside group\n            _enabled = onOff;\n        }\n\n        bool GetEnabled() const { return (_enabled); }\n\n        void SetUndoEnabled(bool b);\n        bool GetUndoEnabled() const { return _addToUndoEnabled; }\n\n        const XmlNode *GetTopUndo(string &description) const;\n        const XmlNode *GetTopRedo(string &description) const;\n        const XmlNode *GetBase() const { return (_state0); }\n        string GetStateChangeReasonDescription() const {return _stateChangeReasonDescription; }\n\n        bool Undo();\n        bool Redo();\n        void Clear();\n        void ManuallyAddCurrentStateToUndoStack(const string &note=\"\");\n\n        size_t UndoSize() const { return (_undoStack.size()); }\n\n        size_t RedoSize() const { return (_redoStack.size()); }\n\n        void RegisterStateChangeFlag(bool *flag) { _stateChangeFlags.push_back(flag); }\n        void RegisterStateChangeCB(std::function<void()> callback) { _stateChangeCBs.push_back(callback); }\n        void RegisterIntermediateStateChangeCB(std::function<void()> callback) { _intermediateStateChangeCBs.push_back(callback); }\n\n    private:\n        bool           _enabled;\n        bool           _addToUndoEnabled = true;\n        int            _stackSize;\n        const XmlNode *_rootNode;\n        const XmlNode *_state0;\n\n        std::stack<string>                       _groups;\n        std::deque<std::pair<string, XmlNode *>> _undoStack;\n        std::deque<std::pair<string, XmlNode *>> _redoStack;\n\n        std::vector<bool *>                _stateChangeFlags;\n        std::vector<std::function<void()>> _stateChangeCBs;\n        std::vector<std::function<void()>> _intermediateStateChangeCBs;\n        std::string                        _stateChangeReasonDescription;\n\n        void cleanStack(int maxN, std::deque<std::pair<string, XmlNode *>> &s);\n        void emitStateChange(const string &reason);\n        void emitIntermediateStateChange(const string &reason = \"Intermediate change\");\n    };\n\n    map<string, DataMgr *> _dataMgrMap;\n    ParamsSeparator *      _rootSeparator;\n    XmlNode                _prevState;\n    std::vector<string>    _appParamNames;\n    std::vector<string>    _appRenderParamNames;\n\n    // Map of RenParamsContainers referenced by Window Name, then by\n    // data set name, and finally Renderer Name.\n    //\n    map<string, map<string, map<string, RenParamsContainer *>>> _renderParamsMap;\n\n    // Map of ViewpointParams referenced by Window Name\n    //\n    map<string, ViewpointParams *> _viewpointParamsMap;\n\n    ParamsContainer *                      _otherParams;\n    std::map<string, RenParamsContainer *> _otherRenParams;\n\n    PMgrStateSave _ssave;\n    std::stack<bool> _saveStateEnabledStack;\n\n    static const string _rootTag;\n    static const string _globalTag;\n    static const string _renderersTag;\n    static const string _appRenderersTag;\n    static const string _windowsTag;\n\n    void _init(std::vector<string> appParamNames, XmlNode *node);\n    void _createAppRenParams(string dataSetName);\n    void _destroy();\n\n    const map<string, map<string, RenParamsContainer *>> *getWinMap3(const map<string, map<string, map<string, RenParamsContainer *>>> &m3, string key) const;\n\n    const map<string, RenParamsContainer *> *getWinMap3(const map<string, map<string, map<string, RenParamsContainer *>>> &m3, string key1, string key2) const;\n\n    const map<string, RenParamsContainer *> *getWinMap2(const map<string, map<string, RenParamsContainer *>> &m2, string key) const;\n\n    RenParamsContainer *get_ren_container(string winName, string dataSetName, string renderName) const;\n\n    map<string, map<string, RenParamsContainer *>> *getWinMap3(map<string, map<string, map<string, RenParamsContainer *>>> &m3, string key) const;\n\n    map<string, RenParamsContainer *> *getWinMap3(map<string, map<string, map<string, RenParamsContainer *>>> &m3, string key1, string key2) const;\n\n    map<string, RenParamsContainer *> *getWinMap2(map<string, map<string, RenParamsContainer *>> &m2, string key) const;\n\n    void delete_ren_container(string winName, string dataSetName, string renderName);\n\n    void delete_ren_containers(string winName, string dataSetName);\n    void delete_ren_containers(string winName);\n    void delete_ren_containers();\n    void delete_datasets(string dataSetName);\n\n    RenParamsContainer *make_ren_container(string winName, string dataSetName, string renderName);\n\n    ViewpointParams *get_vp_params(string winName) const;\n\n    void delete_vp_params(string winName);\n\n    ViewpointParams *make_vp_params(string winName);\n\n    void addDataMgrNew();\n    void addDataMgrMerge(string dataSetName);\n\n    bool undoRedoHelper();\n\n    RenParamsContainer *createRenderParamsHelper(string winName, string dataSetName, string className, string instName);\n};\n\n};        // End namespace VAPoR\n#endif    // PARAMSMGR_H\n"
  },
  {
    "path": "include/vapor/Particle.h",
    "content": "/*\n * Defines a particle used in flow integration.\n */\n\n#ifndef PARTICLE_H\n#define PARTICLE_H\n\n#include \"vapor/common.h\"\n#include <glm/glm.hpp>\n#include <forward_list>\n\nnamespace flow {\nenum FLOW_ERROR_CODE    // these enum values are available in the flow namespace.\n{\n    FIELD_ALL_ZERO = 4,\n    MISSING_VAL = 3,\n    NO_ADVECT_HAPPENED = 2,\n    ADVECT_HAPPENED = 1,\n    SUCCESS = 0,\n    OUT_OF_FIELD = -1,\n    NO_FIELD_YET = -2,\n    NO_SEED_PARTICLE_YET = -3,\n    FILE_ERROR = -4,\n    TIME_ERROR = -5,\n    GRID_ERROR = -6,\n    SIZE_MISMATCH = -7,\n    PARAMS_ERROR = -8\n};\n\n// Particle is not expected to serve as a base class.\nclass FLOW_API Particle final {\npublic:\n    glm::vec3 location = {0.0f, 0.0f, 0.0f};\n    float     value = 0.0f;\n    double    time = 0.0;\n\n    // Constructors.\n    // This class complies with rule of zero.\n    Particle() = default;\n    Particle(const glm::vec3 &loc, double t, float val = 0.0f);\n    Particle(float x, float y, float z, double t, float val = 0.0f);\n\n    //\n    // The \"property\" field allows the user to keep one or more arbitrary values that\n    // are associated with this particle. It's up to the user to keep a record on\n    // what these values at each index stand for.\n    //\n    void AttachProperty(float v);\n    void ClearProperty();\n    // Remove the property at a certain index.\n    // If the index is out of bound, then nothing is performed\n    void RemoveProperty(size_t i);\n\n    auto GetPropertyList() const -> const std::forward_list<float> &;\n\n    // A particle could be set to be at a special state.\n    void SetSpecial(bool isSpecial);\n    bool IsSpecial() const;\n\nprivate:\n    std::forward_list<float> _properties;\n    // Note on the choice of using a forward_list:\n    // Forward_list takes 8 bytes, whereas a vector or list take 24 bytes!\n    // Fun fact: the end() iterator of a forward_list is the nullptr.\n};\n\n};    // namespace flow\n\n#endif\n"
  },
  {
    "path": "include/vapor/ParticleParams.h",
    "content": "#pragma once\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\nclass PARAMS_API ParticleParams : public RenderParams {\npublic:\n    ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n    ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType);\n    ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n    virtual ~ParticleParams();\n\n    static string GetClassType() { return (\"ParticleParams\"); }\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return (3); }\n    virtual string GetActualColorMapVariableName() const override { return GetVariableName(); }\n\nprivate:\n    void _init();\n\npublic:\n    //! Show direction/velocity of particles.\n    //! The field variables must be set to the particles velocity vector components\n    //! (this is likely done automatically if using DCP).\n    static const std::string ShowDirectionTag;\n\n    //! Scale the length of particles velocity vector\n    static const std::string DirectionScaleTag;\n\n    //! Load every nth particle. Useful for improving performance\n    static const std::string StrideTag;\n\n    //! Scale the rendered particle size\n    static const std::string RenderRadiusScalarTag;\n    static const std::string RenderRadiusVariableTag;\n    static const std::string RenderRadiusVariableStrengthTag;\n\n    static const std::string RenderRadiusBaseTag;\n    static const std::string RecalculateRadiusBaseRequestTag;\n    static const std::string RenderLegacyTag;\n\n    static const std::string LightingEnabledTag;\n\n    //! Specifies the Phong Ambient lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model).\n    //! Typical values: 0.0 to 1.0.\n    static const std::string PhongAmbientTag;\n\n    //! Specifies the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model).\n    //! Typical values: 0.0 to 1.0.\n    static const std::string PhongDiffuseTag;\n\n    //! Specifies the Phong Specular lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model).\n    //! Typical values: 0.0 to 1.0.\n    static const std::string PhongSpecularTag;\n\n    //! Specifies the Phong Shininess lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model).\n    //! Typical values: 0.0 to 100.0.\n    static const std::string PhongShininessTag;\n};\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/ParticleRenderer.h",
    "content": "//************************************************************************\n//                                                                       *\n//                          Copyright (C)  2018                          *\n//            University Corporation for Atmospheric Research            *\n//                          All Rights Reserved                          *\n//                                                                       *\n//************************************************************************/\n//\n//  File:   ParticleRenderer.cpp\n//\n//  Author: Stas Jaroszynski\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:   March 2018\n//\n//  Description:\n//          Definition of ParticleRenderer\n//\n#ifndef ParticleRENDERER_H\n#define ParticleRENDERER_H\n\n#include <glm/glm.hpp>\n#include <vapor/glutil.h>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/Renderer.h>\n#include <vapor/ParticleParams.h>\n#include <vapor/ShaderProgram.h>\n#include <vapor/Texture.h>\n\nnamespace VAPoR {\n\nclass DataMgr;\n\n//! \\class ParticleRenderer\n//! \\brief Class that draws the Particles (Particles) as specified by IsolineParams\n//! \\author Stas Jaroszynski, Scott Pearse\n//! \\version 1.0\n//! \\date March 2018\nclass RENDER_API ParticleRenderer : public Renderer {\npublic:\n    ParticleRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    virtual ~ParticleRenderer();\n\n    static string GetClassType() { return (\"Particle\"); }\n\n    //! \\copydoc Renderer::_initializeGL()\n    virtual int _initializeGL();\n    //! \\copydoc Renderer::_paintGL()\n    virtual int _paintGL(bool fast);\n\nprivate:\n    struct {\n        size_t              ts;\n        int                 rLevel;\n        int                 cLevel;\n        std::vector<float>  tf_lut;\n        std::vector<double> tf_minMax;\n        VAPoR::CoordType    boxMin, boxMax;\n        float               radius;\n        bool                direction;\n        size_t              stride;\n        string              varName;\n        string              radiusVarName;\n        std::vector<std::string> fieldVars;\n    } _cacheParams;\n\n    struct Vertex {\n        glm::vec3  point;\n        float      value;\n    };\n\n    size_t _particlesCount = 0;\n\n    unsigned int _VAO = 0;\n    unsigned int _VBO = 0;\n\n    GLuint              _colorMapTexId = 0;\n    GLuint              _vertexArrayId = 0;\n    GLuint              _vertexBufferId = 0;\n    const GLint         _colorMapTexOffset;\n    float               _colorMapRange[3];\n    std::vector<float>  _colorMap;\n\n    void _clearCache() {}\n\n    bool _particleBaseSizeIsDirty() const;\n    bool _particleCacheIsDirty() const;\n    bool _colormapCacheIsDirty() const;\n    void _resetParticleCache();\n    void _resetColormapCache();\n    int  _generateParticlesLegacy(Grid*& grid, std::vector<Grid*>& vecGrids);\n    int  _getGrids(Grid*& grid, std::vector<Grid*>& vecGrids) const;\n    template<typename T> void UploadDataBuffer(vector<T> buffer);\n    void _generateTextureData(const Grid* grid, const std::vector<Grid*>& vecGrids);\n    void _computeBaseRadius();\n    void _renderParticlesLegacy(const Grid* grid, const std::vector<Grid*>& vecGrids) const;\n    int  _renderParticlesHelper();\n    void _prepareColormap();\n    glm::vec3 _getScales();\n};\n\n};    // namespace VAPoR\n\n#endif    // ParticleRENDERER_H\n"
  },
  {
    "path": "include/vapor/Progress.h",
    "content": "#pragma once\n#include <string>\n#include <functional>\n#include <vapor/common.h>\n\nnamespace VAPoR {\n\n//! \\class Progress\n//! Used for displaying the progress of actions to the user. The actual method\n//! for displaying the progress can vary based on the callback.\n//!\n//! The situations where this should be used is top-level calculations\n//! that may take longer than a second. This should not be used (although\n//! it will not break) for non-top level calculations, i.e. in the DC library\n//! as typically loading data will be part of a higher-level calculation.\n//!\n//! The primary use case would be a renderer that has to precompute data, e.g.\n//! the Flow renderer computing particle advection.\n\nclass COMMON_API Progress {\npublic:\n    typedef std::function<void(const std::string &name, long nTotal, bool cancellable)> Start_t;\n    typedef std::function<void(long nDone, bool *cancelled)>                            Update_t;\n    typedef std::function<void()>                                                       Finish_t;\n\n    //! Signifies the beginning of a computation called \"name\" with \"total\" elements\n    //! Can be called multiple times to signifiy a series of computations but must\n    //! always end with a Finish\n    static void Start(const std::string &name, long total, bool cancelable = false);\n    //! Same as start but the progress is unknown. Update(0) still needs to be called periodically\n    static void StartIndefinite(const std::string &name, bool cancelable = false);\n    //! Update the progress status.\n    static void Update(long completed);\n    //! If Start was called with cancelled=true, the user will have the option to cancel\n    //! the computation.\n    static inline bool Cancelled() { return _cancelled; }\n    //! Signify the computation was cancelled.\n    static void Finish();\n    //! This class does not handle actually displaying progress information to\n    //! the user. The interface (e.g. vaporgui) must set callbacks to accomplish this.\n    static void SetHandlers(Start_t start, Update_t update, Finish_t finish);\n\n#ifndef NDEBUG\n    //! For testing purposes only.\n    static void Sleep(double s);\n#endif\n\nprivate:\n    static bool _cancelled;\n    static long _total;\n\n    static Start_t  _start;\n    static Update_t _update;\n    static Finish_t _finish;\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/Proj4API.h",
    "content": "#ifndef _Proj4API_h_\n#define _Proj4API_h_\n\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\n\n//\n//! \\class Proj4API\n//! \\brief Wrapper for proj4 C API\n//!\n//! \\author John Clyne\n//!\n//! This class provides a convience wrapper for the proj4 Cartographic\n//! Projections Library http://trac.osgeo.org/proj/\n//!\nclass VDF_API Proj4API : public Wasp::MyBase {\npublic:\n    Proj4API();\n    ~Proj4API();\n\n    //! Initialize the class\n    //!\n    //! Initializes the class with source and destination proj4\n    //! transformation strings.\n    //!\n    //! \\param[in] srcdef The source proj4 transformation definition. If\n    //! empty, the string \"+proj=latlong\" is used.\n    //! \\param[in] dstdef The destintation proj4 transformation definition. If\n    //! empty, the string \"+proj=latlong\" is used.\n    //!\n    //! \\retval status Retruns a negative int on failure\n    //!\n    //! \\sa pj_init_plus()\n    //\n    int Initialize(string srcdef, string dstdef);\n\n    //! Transform coordinates\n    //!\n    //! Transforms coordinates based on defintions of the source\n    //! and destination proj4 transformation definitions passed to\n    //! Initialize(). Transformations are performed between\n    //! Geographic coordinates (latitude and longitude) and Cartographic\n    //! coordinates (Cartesian) as specified by the transformation\n    //! definitions. Cartographic coordinates are referred to as the\n    //! Projection Coordinate System (PCS). Default units for the PCS\n    //! are meters on the ground. Geographic coordinates are always\n    //! in degrees.\n    //!\n    //!\n    //! \\note As with the proj4 C library the transformations are\n    //! performed in place, modifiying the input values\n    //!\n    //! \\param[in,out] x array of longitudes or PCS X values\n    //! \\param[in,out] y array of latitudes or PCS Y values\n    //! \\param[in] n num elements in x, y, and z\n    //! \\param[in] offset Offset between adjacent values in the input and\n    //! output arrays.\n    //!\n    //! \\retval status Retruns a negative int on failure\n    //!\n    //! \\sa Initialize(), pj_transform()\n    //!\n    int Transform(double *x, double *y, size_t n, int offset = 1) const;\n    int Transform(double *x, double *y, double *z, size_t n, int offset = 1) const;\n    int Transform(float *x, float *y, size_t n, int offset = 1) const;\n    int Transform(float *x, float *y, float *z, size_t n, int offset = 1) const;\n\n    //! Return true of source projection definition is lat-long\n    //!\n    //! This method returns true iff the source projection definition\n    //! is geographic (i.e. +proj=latlong). If true, subsequent transforms\n    //! expect input values to be in geographic coordinates (i.e. degrees)\n    //! False is returned otherwise\n    //!\n    //! \\sa Initialize(), pj_is_latlong()\n    //\n    bool IsLatLonSrc() const;\n\n    //! Return true of destination projection definition is lat-long\n    //!\n    //! This method returns true iff the destination projection definition\n    //! is geographic (i.e. +proj=latlong). If true, subsequent transforms\n    //! will return output values in geographic coordinates (i.e. degrees)\n    //! False is returned otherwise\n    //!\n    //! \\sa Initialize(), pj_is_latlong()\n    //\n    bool IsLatLonDst() const;\n\n    bool IsGeocentSrc() const;\n    bool IsGeocentDst() const;\n\n    //! Return the current source projection definition string\n    string GetSrcStr() const;\n\n    //! Return the current destination projection definition string\n    string GetDstStr() const;\n\n    int Transform(string srcdef, string dstdef, double *x, double *y, double *z, size_t n, int offset) const;\n    int Transform(string srcdef, string dstdef, float *x, float *y, float *z, size_t n, int offset) const;\n\n    //! Return the error string generated by the proj4 C API for the\n    //! most recent error\n    //!\n    //! \\sa pj_strerrno()\n\n    string ProjErr() const;\n\n    //! Clamp the input values to bounds permitted by the source\n    //! projection. If the source projection is not recognized the\n    //! method is a no-op\n    //\n    void Clamp(double *x, double *y, size_t n, int offset) const;\n\n    //! Return true if the destination projection is cylindrical\n    //!\n    //! Returns true if the destination projection string is either\n    //! cylindrical \"eqc\", or mercator \"merc\"\n    //\n    bool IsCylindrical() const;\n\nprivate:\n    void *_pjSrc;\n    void *_pjDst;\n\n    int _Initialize(string srcdef, string dstdef, void **pjSrc, void **pjDst) const;\n\n    int _Transform(void *pjSrc, void *pjDst, double *x, double *y, double *z, size_t n, int offset) const;\n\n    int _Transform(void *pjSrc, void *pjDst, float *x, float *y, float *z, size_t n, int offset) const;\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/Proj4StringParser.h",
    "content": "#pragma once\n\n#include <string>\n#include <map>\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\nclass RENDER_API Proj4StringParser : Wasp::MyBase {\n    std::string                        _string;\n    std::map<std::string, std::string> _tokens;\n\n    static std::pair<std::string, std::string> Proj4ParameterToKeyValuePair(std::string proj);\n    static std::map<std::string, std::string>  Proj4StringToParameterMap(std::string proj);\n\npublic:\n    Proj4StringParser(const std::string &projString);\n\n    bool        HasKey(const std::string &key) const;\n    std::string GetString(const std::string &key, const std::string &defaultValue = \"\") const;\n    double      GetDouble(const std::string &key, const double defaultValue = 0.0) const;\n\n    static int Proj4EllipseStringToGeoTIFEnum(const std::string &proj);\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/PyEngine.h",
    "content": "#include <vector>\n#include <vapor/MyPython.h>\n#include <vapor/DataMgr.h>\n#include <vapor/DC.h>\n\n#pragma once\n\nnamespace VAPoR {\n\n//! \\class PyEngine\n//! \\brief A class for managing derived variables computed with Python\n//! \\author John Clyne\n//!\n//! This class provides a means to manage derived variables on the DataMgr\n//! calculated using Python. It allows the user of this class to define\n//! derived variables that execute Python scripts and installs the derived\n//! variable on the DataMgr class. The Python script may operate on\n//! input variables managed by the DataMgr\n//\nclass RENDER_API PyEngine : public Wasp::MyBase {\npublic:\n    //! Constructor for PyEngine class\n    //!\n    //! \\param[in] dataMgr A pointer to a DataMgr instance upon which derived\n    //! variables created by this class will be managed.\n    //\n    PyEngine(DataMgr *dataMgr)\n    {\n        VAssert(dataMgr != NULL);\n        _dataMgr = dataMgr;\n    }\n\n    ~PyEngine();\n\n    //! Initialize the class\n    //!\n    //! This static initializer must be called to initialize the Python C API\n    //! at least once prior to using\n    //! other PyEngine class methods.\n    //!\n    //! \\retval status A negative int is returned on failure and an error\n    //! message will be logged with MyBase::SetErrMsg()\n    //\n    static int Initialize();\n\n    //! Add new derived variable(s) to the DataMgr\n    //!\n    //! This method adds one or more derived variables to the DataMgr specified\n    //! by the constructor. Each derived variable is calculated by executing\n    //! the same Python script specified by \\p script. I.e. a single Python\n    //! script may compute multiple variables.\n    //!\n    //! \\param[in] name A string identifier for the collection of derived variables\n    //! computed by \\p script. If a script named \\p name already exists it is\n    //! removed with RemoveFunction() and replaced with the new definition.\n    //!\n    //! \\param[in] script A Python (NumPy) script that will be invoked each time\n    //! one of the variables listed in \\p outputs is accessed. The scope of\n    //! the script will contain NumPy Array (numpy.array) variables named\n    //! in \\p inputs.\n    //!\n    //! \\param[in] inputs A list of input DataMgr variable names. The named\n    //! DataMgr variables will be made available in the scope of the Python\n    //! script as NumPy Arrays.\n    //!\n    //! \\param[in] outputs A list of derived DataMgr variable names. The named\n    //! variables are expected to be computed by \\p script as NumPy Arrays\n    //! and will appear as DataMgr derived variables.\n    //!\n    //! \\param[in] outMeshes A list of output mesh names, one for each output\n    //! variable listed in \\p outputs. The output mesh names must be known\n    //! to the DataMgr. Each output variable created by \\p script is expected\n    //! to be sampled by the named mesh. See DataMgr::GetMesh()\n    //!\n    //! \\retval status A negative integer is returned on failure and an error\n    //! message is reported with MyBase::SetErrMsg(). AddFunction() will fail\n    //! if any of the output variables named in \\p outputs already exist\n    //! in the DataMgr as returned by DataMgr::GetDataVarNames(), or if any of\n    //! the output mesh names in \\p outMeshes are not known to the\n    //! DataMgr (see DataMgr::GetMeshNames())\n    //!\n    //! \\note The Python script \\p script is executed when one of the output\n    //! variables is read. Depending on the region requested only a subset\n    //! of the DataMgr variable may be provided to \\p script as a NumPy\n    //! array. Currently this occurs if all of the input variables named\n    //! by \\p inputs and the requested output variable are sampled on the\n    //! same mesh.\n    //\n    int AddFunction(string name, string script, const vector<string> &inputs, const vector<string> &outputs, const vector<string> &outMeshes, bool coordFlag = false);\n\n    //! Remove a previously defined function\n    //!\n    //! This method removes the function previously created by AddFunction()\n    //! and named by \\p name. All of the associated derived variables are\n    //! removed from the DataMgr. The method is a no-op if \\p name is not\n    //! an active function.\n    //\n    void RemoveFunction(string name);\n\n    //! Return a list of all active function names\n    //!\n    //! This method returns a vector of names for all active (not previously\n    //! removed) functions created with AddFunction()\n    //!\n    //! \\sa AddFunction();\n    //!\n    std::vector<string> GetFunctionNames() const;\n\n    //! Return the script for a named function\n    //!\n    //! This method returns as a string the NumPy script associated with the\n    //! function named by \\p name.\n    //!\n    //! \\retval script Returns the Python script bound to \\p name. Any empty\n    //! string is returned if \\p name is not defined.\n    //!\n    //! \\sa AddFunction(), RemoveFunction()\n    //\n    string GetFunctionScript(string name) const;\n\n    bool GetFunctionScript(string name, string &script, std::vector<string> &inputVarNames, std::vector<string> &outputVarNames, std::vector<string> &outputMeshNames, bool &coordFlag) const;\n\n    //! Return stdout as a string\n    //!\n    //! This method returns as a string any content written to stdout\n    //! by the most recent invocation of the named script \\p name\n    //\n    string GetFunctionStdout(string name) const;\n\n    //! Execute a NumPy script\n    //!\n    //! This static method executes the NumPy script \\p script and copies the\n    //! outputs of the Python NumPy Arrays named by \\p outputVarNames\n    //! into the regions of memory provided by \\p outputVarArrays. The contents\n    //! of the memory referenced by \\p inputVarArrays are made available to\n    //! \\p script as inputs in the form of NumPy Arrays.\n    //!\n    //! \\param[in] script A Python (NumPy) script that is expected to operate on\n    //! the NumPy Arrays listed in \\p inputVarNames and store outputs in the\n    //! NumPy arrays listed in \\p outputVarNames\n    //!\n    //! \\param[in] inputVarNames A list of NumPy Array names that will be made\n    //! available in the scope of the executed Python script, \\p script.\n    //!\n    //! \\param[in] inputVarDims A list of dimensions for each of the possibly\n    //! multi-dimensional NumPy arrays named by \\p inputVarNames\n    //!\n    //! \\param[in] inputVarArrays A list of regions of memory for each\n    //! input NumPy Array that will be copied in the Python environment prior\n    //! to executing \\p script. The size of the region copy is given by the\n    //! dimensions in \\p inputVarDims\n    //!\n    //! \\param[in] outputVarNames A list of NumPy Array names that are\n    //! expected to be created within the scope of the Python script  \\p script\n    //! The required dimesions of each array is given by \\p outputVarDims\n    //!\n    //! \\param[in] outputVarDims A list of dimensions for each of the possibly\n    //! multi-dimensional NumPy arrays named by \\p outputVarNames.\n    //!\n    //! \\param[in] outputVarArrays A list of regions of memory for each\n    //! output NumPy Array that will be copied out of the Python environment after\n    //! executing \\p script. The size of the region copied is given by the\n    //! dimensions in \\p outputVarDims\n    //!\n    static int Calculate(const string &script, vector<string> inputVarNames, vector<DimsType> inputVarDims, vector<float *> inputVarArrays, vector<string> outputVarNames,\n                         vector<DimsType> outputVarDims, vector<float *> outputVarArrays);\n\nprivate:\n    class RENDER_API DerivedPythonVar : public DerivedDataVar {\n    public:\n        DerivedPythonVar(string varName, string units, DC::XType type, string mesh, string time_coord_var, bool hasMissing, std::vector<string> inNames, string script, DataMgr *dataMgr,\n                         bool coordFlag);\n\n        ~DerivedPythonVar() {}\n\n        int Initialize();\n\n        bool GetBaseVarInfo(DC::BaseVar &var) const;\n\n        std::vector<string> GetInputs() const { return (_inNames); }\n\n        int GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const;\n\n        virtual size_t GetNumRefLevels() const;\n\n        virtual std::vector<size_t> GetCRatios() const { return (_varInfo.GetCRatios()); }\n\n        int OpenVariableRead(size_t ts, int level = 0, int lod = 0);\n\n        int CloseVariable(int fd);\n\n        int ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n\n        bool VariableExists(size_t ts, int reflevel, int lod) const;\n\n        bool GetDataVarInfo(DC::DataVar &cvar) const;\n\n        //! Return stdout from most recent execution of script\n        //!\n        string GetScriptStdout() const { return (_stdoutString); }\n\n    private:\n        DC::DataVar         _varInfo;\n        std::vector<string> _inNames;\n        string              _script;\n        DataMgr *           _dataMgr;\n        bool                _coordFlag;\n        DC::FileTable       _fileTable;\n        DimsType            _dims;\n        bool                _meshMatchFlag;\n        string              _stdoutString;\n\n        int _readRegionAll(int fd, const DimsType &min, const DimsType &max, float *region);\n\n        int _readRegionSubset(int fd, const DimsType &min, const DimsType &max, float *region);\n    };\n\n    class func_c {\n    public:\n        func_c() {}\n        func_c(const string &name, const string &script, const std::vector<string> &inputVarNames, const std::vector<string> &outputVarNames, const std::vector<string> &outputMeshNames,\n               const std::vector<DerivedPythonVar *> &derivedVars, bool coordFlag)\n        : _name(name), _script(script), _inputVarNames(inputVarNames), _outputVarNames(outputVarNames), _outputMeshNames(outputMeshNames), _derivedVars(derivedVars), _coordFlag(coordFlag)\n        {\n        }\n\n        string                          _name;\n        string                          _script;\n        std::vector<string>             _inputVarNames;\n        std::vector<string>             _outputVarNames;\n        std::vector<string>             _outputMeshNames;\n        std::vector<DerivedPythonVar *> _derivedVars;\n        bool                            _coordFlag;\n    };\n\n    std::map<string, func_c> _functions;\n    std::map<string, string> _functionsStdio;\n    DataMgr *                _dataMgr;\n    static bool              _isInitialized;\n\n    PyEngine() : _dataMgr(NULL) {}\n\n    static void _cleanupDict(PyObject *mainDict, vector<string> keynames);\n\n    static int _c2python(PyObject *dict, vector<string> inputVarNames, vector<DimsType> inputVarDims, vector<float *> inputVarArrays);\n\n    static int _python2c(PyObject *dict, vector<string> outputVarNames, vector<DimsType> outputVarDims, vector<float *> outputVarArrays);\n\n    bool _validOutputVar(string name) const;\n    int  _checkOutVars(const vector<string> &outputVarNames) const;\n    bool _validOutputMesh(string name) const;\n    int  _checkOutMeshes(const vector<string> &outputMeshNames) const;\n\n    string _getTimeCoordVarName(const vector<string> &varNames) const;\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/PythonDataMgr.h",
    "content": "#include <vapor/DataMgr.h>\n\n#pragma once\n\nnamespace VAPoR {\n\nclass DCRAM;\n\n//! \\class PythonDataMgr\n//! \\brief DataMgr for data loaded from python scripts\n//! \\author Stas Jaroszynski\n\nclass VDF_API PythonDataMgr : public DataMgr {\npublic:\n    PythonDataMgr(string format, size_t mem_size, int nthreads = 0);\n    virtual ~PythonDataMgr();\n    \n    void AddRegularData(string name, const float *buf, vector<int> dims);\n    DCRAM *GetDC() const;\n    void ClearCache(string varname);\n};\n\n}\n"
  },
  {
    "path": "include/vapor/QuadTreeRectangle.hpp",
    "content": "#pragma once\n\n#include <vector>\n#include <cassert>\n#include <limits>\n#include <cmath>\n#include <iostream>\n#include <cstdint>\n#include <vapor/VAssert.h>\n\nnamespace VAPoR {\n\n// Maximum aspect ratio of a rectangle before it is split\n//\nconst float maxAspectRatio = 2.0;\n\n//\n//! \\class QuadTreeRectangle\n//! \\brief This class implements a 2D quad tree space partitioning tree\n//! that operates on rectangular regions.\n//!\n//\ntemplate<typename T, typename S> class QuadTreeRectangle {\npublic:\n    class rectangle_t {\n    public:\n        rectangle_t() : _left(0.0f), _top(0.0f), _right(0.0f), _bottom(0.0f) {}\n        rectangle_t(T x1, T y1, T x2, T y2) : _left(x1), _top(y1), _right(x2), _bottom(y2) {}\n\n        // return true iff other intersects us\n        //\n        bool intersects(rectangle_t const &other) const\n        {\n            if (_left > other._right || _top > other._bottom) return (false);\n\n            if (_right < other._left || _bottom < other._top) return (false);\n            return (true);\n        }\n\n        // return true iff other is completely contained inside or on boundary\n        //\n        bool contains(rectangle_t const &other) const { return ((_left <= other._left) && (_right >= other._right) && (_top <= other._top) && (_bottom >= other._bottom)); }\n\n        // return true iff point(x,y) is completely contained inside or on boundary\n        //\n        bool contains(T x, T y) const { return ((_left <= x) && (_right >= x) && (_top <= y) && (_bottom >= y)); }\n\n        bool touches(rectangle_t const &other) const { return ((_left == other._right) || (_right == other._left) || (_top == other._bottom) || (_bottom == other._top)); }\n\n        T width() const { return (_right - _left); }\n        T height() const { return (_bottom - _top); }\n\n        // return the sub-rectangle for the specified quadrant\n        //\n        rectangle_t quadrant(uint32_t n)\n        {\n            T const center_x((_left + _right) / 2);\n            T const center_y((_top + _bottom) / 2);\n            switch (n & 0x03) {\n            case 0: return rectangle_t(_left, _top, center_x, center_y);\n            case 1: return rectangle_t(center_x, _top, _right, center_y);\n            case 2: return rectangle_t(_left, center_y, center_x, _bottom);\n            case 3: return rectangle_t(center_x, center_y, _right, _bottom);\n            }\n            VAssert(0);\n            return *this;    // Can't happen since we mask n\n        }\n\n        // Horizontal aspect ratio\n        //\n        float hAspectRatio() const {\n            if (_bottom == _top) return (std::numeric_limits<float>::quiet_NaN());\n            return (std::fabs((_right - _left) / (_bottom - _top)));\n        }\n\n        friend std::ostream &operator<<(std::ostream &os, const rectangle_t &rec)\n        {\n            os << \"left-top, right-bottom : \"\n               << \"(\" << rec._left << \", \" << rec._top << \") \"\n               << \"(\" << rec._right << \", \" << rec._bottom << \")\" << std::endl;\n            return (os);\n        }\n\n        T _left, _top, _right, _bottom;\n    };\n\n    //! Construct a QuadTreeRectangle instance for a defined 2D region\n    //!\n    //! This contstructor initiates a 2D quad tree with specified min\n    //! and max bounds. Subsequent insertions into the tree will only\n    //! succeed for regions that intersect the tree bounds\n    //!\n    //! \\param[in] left Minimum X coordinate bound.\n    //! \\param[in] top Minimum Y coordinate bound.\n    //! \\param[in] right Maximum X coordinate bound. Must be greater than\n    //! or equal to \\p left.\n    //! \\param[in] bottom Maximum Y coordinate bound. Must be greater than\n    //! or equal to \\p top.\n    //! \\param[in] max_depth The maximum permitted depth of the tree. The\n    //! tree will not be refined beyond \\p max_depth levels.\n    //! \\param[in] reserve_size A hint indicating the antcipated number of\n    //! nodes in the tree. Accurate estimates will increase performance\n    //! of tree insertions\n    //\n    QuadTreeRectangle(T left, T top, T right, T bottom, size_t max_depth = 12, size_t reserve_size = 1000)\n    {\n        VAssert(left <= right);\n        VAssert(top <= bottom);\n        _nodes.reserve(reserve_size);\n        _nodes.push_back(node_t(left, top, right, bottom));\n        _rootidx = 0;\n        _maxDepth = max_depth;\n    }\n\n    //! Construct a QuadTreeRectangle instance for a unit 2D region\n    //!\n    //! Default contructor definining a quad tree covering the region\n    //! (.0, .0) to (1. ,1.)\n    //!\n    QuadTreeRectangle(size_t max_depth = 12, size_t reserve_size = 1000)\n    {\n        _nodes.reserve(reserve_size);\n        _nodes.push_back(node_t(0.0, 0.0, 1.0, 1.0));\n        _rootidx = 0;\n        _maxDepth = max_depth;\n    }\n\n    QuadTreeRectangle(const QuadTreeRectangle &rhs)\n    {\n        _nodes.resize(rhs._nodes.size());\n        for (size_t i = 0; i < rhs._nodes.size(); i++) { _nodes[i] = node_t((rhs._nodes[i])); }\n        _rootidx = rhs._rootidx;\n        _maxDepth = rhs._maxDepth;\n    }\n\n    QuadTreeRectangle &operator=(const QuadTreeRectangle &rhs)\n    {\n        if (*this == rhs) return *this;\n\n        _nodes.resize(rhs._nodes.size());\n        for (size_t i = 0; i < rhs._nodes.size(); i++) { _nodes[i] = node_t((rhs._nodes[i])); }\n        _rootidx = rhs._rootidx;\n        _maxDepth = rhs._maxDepth;\n        return *this;\n    }\n\n    //! Insert an element into the tree\n    //!\n    //! This method inserts a payload, \\p payload, into the tree contained\n    //! in the rectangular region defined by \\p left, \\p top, \\p right,\n    //! \\p bottom. If the region to be inserted does not intersect\n    //! the tree bound defined by the contructor method fails and returns\n    //! false. Otherwise, the tree is subdivided as necessary and the defined\n    //! region along with its payload are inserted. The refinement algorithm\n    //! for subdividing the tree operates as follows: The tree nodes that\n    //! intersect the region are subdivided until both the width and height\n    //! of the region to be inserted are larger than the respective\n    //! width and height of the node intersecting the region, or the\n    //! maximum depth of the tree is reached.\n    //!\n    //! \\retval status Return true on success, or false if region to be inserted\n    //! does not overlap the region managed by the tree.\n    //\n    bool Insert(const rectangle_t &rectangle, const S &payload)\n    {\n        if (!_nodes[_rootidx].intersects(rectangle)) return (false);\n\n        float ar = rectangle.hAspectRatio();\n        if (!(std::isfinite(ar)) || ar == 0.0) return (false);\n\n        if (ar <= maxAspectRatio && ar >= (1.0 / maxAspectRatio)) {\n            return (node_t::insert(_nodes, _rootidx, rectangle, payload, _maxDepth));\n        } else if (ar >= maxAspectRatio) {\n            // Horizontal split\n            //\n            bool   status = true;\n            size_t n = (size_t)ar;\n            float  split_width = (rectangle._right - rectangle._left) / (float)n;\n            float  splitLeft = rectangle._left;\n            for (int i = 0; i < n; i++) {\n                float splitRight = splitLeft + split_width;\n                if (i == (n - 1)) splitRight = rectangle._right;\n\n                status &= node_t::insert(_nodes, _rootidx, rectangle_t(splitLeft, rectangle._top, splitRight, rectangle._bottom), payload, _maxDepth);\n                splitLeft = splitRight;\n            }\n            return (status);\n        } else {\n            // Vertical split\n            //\n            bool   status = true;\n            size_t n = (size_t)(1.0 / ar);\n            float  split_width = (rectangle._bottom - rectangle._top) / (float)n;\n            float  splitTop = rectangle._top;\n            for (int i = 0; i < n; i++) {\n                float splitBottom = splitTop + split_width;\n                if (i == (n - 1)) splitBottom = rectangle._bottom;\n\n                status &= node_t::insert(_nodes, _rootidx, rectangle_t(rectangle._left, splitTop, rectangle._right, splitBottom), payload, _maxDepth);\n                splitTop = splitBottom;\n            }\n            return (status);\n        }\n    }\n\n    bool Insert(T left, T top, T right, T bottom, S payload) { return (Insert(rectangle_t(left, top, right, bottom), payload)); }\n\n    //! Return a list of payloads that intersect a specified point\n    //!\n    //! This method searches the tree for all nodes whose associated regions\n    //! intersect the point (\\p x, \\p y), and returns any payload found\n    //! at those nodes.\n    //!\n    //! \\p param[in] x X coordinate of point\n    //! \\p param[in] y Y coordinate of point\n    //! \\p payloads[out] A vector of payloads whose regions intersect\n    //! \\p x and \\p y.\n    //!\n    void GetPayloadContained(T x, T y, std::vector<S> &payloads) const\n    {\n        payloads.clear();\n\n        node_t::get_payload_contains(_nodes, _rootidx, x, y, payloads);\n    }\n\n    //! Return informational statistics about the current tree\n    //!\n    //! This method returns stats about the tree\n    //!\n    //! \\param[out] payload_histo Returns a histogram in the form of a vector\n    //! that gives a count of the number of payloads. For example,\n    //! the ith element of \\p payload_histo provides the count of nodes\n    //! that contain i number of payloads.\n    //!\n    //! \\param[out] level_histo Returns a histogram in the form of a vector\n    //! that gives a count of cells at each level in the tree.\n    //\n    void GetStats(std::vector<size_t> &payload_histo, std::vector<size_t> &level_histo) const\n    {\n        payload_histo.clear();\n        level_histo.clear();\n\n        for (size_t i = 0; i < _nodes.size(); i++) {\n            size_t b = _nodes[i].get_payloads().size();\n            if (b >= payload_histo.size()) { payload_histo.resize(b + 1, 0); }\n            payload_histo[b] += 1;\n\n            b = _nodes[i].get_level();\n            if (b >= level_histo.size()) { level_histo.resize(b + 1, 0); }\n            level_histo[b] += 1;\n        }\n    }\n\n    friend std::ostream &operator<<(std::ostream &os, const QuadTreeRectangle &q)\n    {\n        os << \"Num nodes : \" << q._nodes.size() << std::endl;\n        const node_t &root = q._nodes[q._rootidx];\n        root.print(q._nodes, q._rootidx, os);\n        return (os);\n    }\n\nprivate:\n    class node_t {\n    public:\n        node_t(int level = 0) : _level(level), _is_leaf(true), _child0(0), _rectangle(0.0, 0.0, 1.0, 1.0) {}\n\n        node_t(T left, T top, T right, T bottom, int level = 0) : _level(level), _is_leaf(true), _child0(0), _rectangle(left, top, right, bottom) {}\n\n        node_t(const rectangle_t &rec, int level = 0) : _level(level), _is_leaf(true), _child0(0), _rectangle(rec) {}\n\n        rectangle_t &      bounds() { return (_rectangle); }\n        rectangle_t const &bounds() const { return (_rectangle); }\n\n        bool intersects(rectangle_t const &other) const { return (_rectangle.intersects(other)); }\n        bool contains(rectangle_t const &other) const { return (_rectangle.contains(other)); }\n        bool contains(T x, T y) const { return (_rectangle.contains(x, y)); }\n        bool touches(rectangle_t const &other) const { return (_rectangle.touches(other)); }\n\n        static void subdivide(std::vector<node_t> &nodes, size_t nidx)\n        {\n            node_t &node = nodes[nidx];\n\n            if (!node._is_leaf) return;\n\n            node._is_leaf = false;\n            node._child0 = nodes.size();\n\n            node_t n0(node._rectangle.quadrant(0), node._level + 1);\n            node_t n1(node._rectangle.quadrant(1), node._level + 1);\n            node_t n2(node._rectangle.quadrant(2), node._level + 1);\n            node_t n3(node._rectangle.quadrant(3), node._level + 1);\n\n            nodes.push_back(n0);\n            nodes.push_back(n1);\n            nodes.push_back(n2);\n            nodes.push_back(n3);\n        }\n\n        static size_t quadrant(const std::vector<node_t> &nodes, size_t nidx, uint32_t n)\n        {\n            const node_t &node = nodes[nidx];\n            switch (n & 0x03) {\n            case 0: return node._child0 + 0;\n            case 1: return node._child0 + 1;\n            case 2: return node._child0 + 2;\n            case 3: return node._child0 + 3;\n            }\n            VAssert(0);\n            return node._child0 + 0;\n        }\n        static size_t quadrant(std::vector<node_t> &nodes, size_t nidx, uint32_t n)\n        {\n            const node_t &node = nodes[nidx];\n            VAssert(node._child0 < nodes.size());\n            switch (n & 0x03) {\n            case 0: return node._child0 + 0;\n            case 1: return node._child0 + 1;\n            case 2: return node._child0 + 2;\n            case 3: return node._child0 + 3;\n            }\n            VAssert(0);\n            return node._child0 + 0;\n        }\n\n        static bool insert(std::vector<node_t> &nodes, size_t nidx, const rectangle_t &rec, S payload, size_t maxDepth)\n        {\n            if (!nodes[nidx]._rectangle.intersects(rec)) return (false);\n\n            // if rec is larger than a quadrant (half the width and height of this\n            // node) there is no point in refining. I.e. stop descending the\n            // tree and store the payload here.\n            //\n            if (nodes[nidx]._rectangle.width() <= rec.width() || nodes[nidx]._rectangle.height() <= rec.height() || nodes[nidx]._level >= maxDepth) {\n                nodes[nidx]._payloads.push_back(payload);\n                return (true);\n            }\n\n            // This is a no-op if node has already been subdivided\n            //\n            subdivide(nodes, nidx);\n\n            // Recursively insert in each child node that intersects rec\n            //\n            for (int q = 0; q < 4; q++) {\n                size_t child = node_t::quadrant(nodes, nidx, q);\n                if (nodes[child].intersects(rec)) {\n                    bool ok = node_t::insert(nodes, child, rec, payload, maxDepth);\n                    VAssert(ok);\n                }\n            }\n\n            return (true);\n        }\n\n        static void get_payload_contains(const std::vector<node_t> &nodes, size_t nidx, T x, T y, std::vector<S> &payloads)\n        {\n            const node_t &node = nodes[nidx];\n\n            if (!node._rectangle.contains(x, y)) return;\n\n            if (node._payloads.size()) { payloads.insert(payloads.end(), node._payloads.begin(), node._payloads.end()); }\n            if (node._is_leaf) return;\n\n            for (int q = 0; q < 4; q++) {\n                size_t child = node_t::quadrant(nodes, nidx, q);\n                if (nodes[child]._rectangle.contains(x, y)) { node_t::get_payload_contains(nodes, child, x, y, payloads); }\n            }\n        }\n\n        static void print(const std::vector<node_t> &nodes, size_t nidx, std::ostream &os)\n        {\n            const node_t &node = nodes[nidx];\n            for (int i = 0; i < node._level; i++) os << \" \";\n            os << node._rectangle;\n\n            for (int i = 0; i < node._level; i++) os << \" \";\n            os << \"payload : \";\n            for (int i = 0; i < node._payloads.size(); i++) { os << node._payloads[i] << \" \"; }\n            os << std::endl;\n            if (!node._is_leaf) {\n                for (int q = 0; q < 4; q++) {\n                    size_t childidx = quadrant(nodes, nidx, q);\n                    node_t::print(nodes, childidx, os);\n                }\n            }\n        }\n        const std::vector<S> &get_payloads() const { return (_payloads); }\n        size_t                get_level() const { return (_level); }\n\n    private:\n        int            _level;\n        bool           _is_leaf;\n        size_t         _child0;\n        rectangle_t    _rectangle;\n        std::vector<S> _payloads;\n    };\n\n    std::vector<node_t> _nodes;\n    size_t              _rootidx;\n    size_t              _maxDepth;\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/QuadTreeRectangleP.h",
    "content": "#pragma once\n\n#include <vector>\n#include <iostream>\n#pragma once\n\n#include <cstdint>\n#include <vapor/VAssert.h>\n#include <vapor/Grid.h>\n#include <vapor/QuadTreeRectangle.hpp>\n\nusing UInt32_tArr2 = std::array<uint32_t, 2>;\nusing pType = UInt32_tArr2;\n\nnamespace VAPoR {\n\n//\n//! \\class QuadTreeRectangleP\n//! \\brief This class wraps QuadTreeRectangleP with parallel\n//! tree construction\n//!\n//\nclass QuadTreeRectangleP {\npublic:\n    //! \\copydoc QuadTreeRectangle::QuadTreeRectangle()\n    //\n    QuadTreeRectangleP(float left, float top, float right, float bottom, size_t max_depth = 12, size_t reserve_size = 1000);\n\n    //! \\copydoc QuadTreeRectangle::QuadTreeRectangle()\n    //\n    QuadTreeRectangleP(size_t max_depth = 12, size_t reserve_size = 1000);\n\n    //! \\copydoc QuadTreeRectangle::QuadTreeRectangle()\n    //\n    QuadTreeRectangleP(const QuadTreeRectangleP &rhs);\n\n    //! \\copydoc QuadTreeRectangle::QuadTreeRectangle()\n    //\n    QuadTreeRectangleP &operator=(const QuadTreeRectangleP &rhs);\n\n    ~QuadTreeRectangleP();\n\n    //! \\copydoc QuadTreeRectangle::Insert()\n    //\n    bool Insert(float left, float top, float right, float bottom, DimsType payload);\n\n    //! Parallel tree creation\n    //!\n    //! Inserts multiple rectangles into the quad tree in parallel\n    //!\n    //! \\sa QuadTreeRectangle::Insert()\n    //\n    bool Insert(std::vector<class QuadTreeRectangle<float, pType>::rectangle_t> rectangles, std::vector<pType> payloads);\n\n    //! Constructs a quadtree from the cells contained in a Grid class\n    //!\n    //! This method iterates over all of the cells found in \\p grid and\n    //! constructs a Quadtree. The construction is performed in parallel.\n    //! The topological dimesion of \\p grid must be two.\n    //!\n    //! \\param[in] grid The grid from which to construct the tree\n    //! \\param[in] ncells If non-zero specifies the number of cells to\n    //! insert via iterating over the cells contained in the grid. If zero,\n    //! all of the cells are inserted.\n    //!\n    bool Insert(const Grid *grid, size_t ncells = 0);\n\n    //! \\copydoc QuadTreeRectangle::GetPayloadContained()\n    //\n    void GetPayloadContained(float x, float y, std::vector<DimsType> &payloads) const;\n\n    //! \\copydoc QuadTreeRectangle::GetStats()\n    //\n    void GetStats(std::vector<size_t> &payload_histo, std::vector<size_t> &level_histo) const;\n\n    friend std::ostream &operator<<(std::ostream &os, const QuadTreeRectangleP &q)\n    {\n        for (int i = 0; i < q._qtrs.size(); i++) {\n            os << \"Bin \" << i << std::endl;\n            os << q._qtrs[i] << std::endl;\n        }\n        return (os);\n    }\n\nprivate:\n    float                                          _left;\n    float                                          _right;\n    std::vector<QuadTreeRectangle<float, pType> *> _qtrs;\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/RayCaster.h",
    "content": "#ifndef RAYCASTER_H\n#define RAYCASTER_H\n\n#include <vapor/glutil.h>\n#ifndef WIN32\n    #include <sys/time.h>\n#endif\n\n#include <vapor/Renderer.h>\n#include \"vapor/RayCasterParams.h\"\n#include \"vapor/GLManager.h\"\n\n#include <glm/glm.hpp>\n\nnamespace VAPoR {\n\nclass RENDER_API RayCaster : public Renderer {\npublic:\n    RayCaster(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string paramsType, std::string classType, std::string &instName, DataMgr *dataMgr);\n\n    virtual ~RayCaster();\n\nprotected:\n    // C++ stuff\n    // pure virtual functions from Renderer\n    int  _initializeGL();\n    int  _paintGL(bool fast);\n    void _clearCache(){};\n\n    // Makes RayCaster an abstract class that cannot be instantiated,\n    //   and it's up to the subclasses to decide which shader to load.\n    //   It returns 0 upon success, and non-zero upon errors.\n    virtual int _load3rdPassShaders() = 0;\n\n    enum CastingMode { FixedStep = 1, CellTraversal = 2 };\n\n    class UserCoordinates {\n        // Note: class UserCoordinates lives completely inside of class RayCaster,\n        //   and is solely used by class RayCaster. Thus for simplicity, it has all\n        //   of its member variables and methods public.\n    public:\n        //              Y\n        //              |   Z (coming out the screen)\n        //              |  /\n        //              | /\n        //              |/\n        //            0 --------X\n        float *        frontFace, *backFace;    // user coordinates, size == bx * by * 3\n        float *        rightFace, *leftFace;    // user coordinates, size == by * bz * 3\n        float *        topFace, *bottomFace;    // user coordinates, size == bx * bz * 3\n        float *        dataField;               // data field of this volume\n        unsigned char *missingValueMask;        // 0 == is missing value; non-zero == not missing value\n        float *        vertCoords;              // vertex coordinates in user coordinates\n        float *        secondVarData;           // values of a second variable\n        unsigned char *secondVarMask;           // 0 == is missing value; non-zero == not missing value\n\n        size_t dims[3];    // num. of samples along each axis.\n\n        /* Also keep the current meta data */\n        size_t      myCurrentTimeStep;\n        std::string myVariableName;\n        std::string my2ndVarName;\n        int         myRefinementLevel, myCompressionLevel;\n        float       myGridMin[3], myGridMax[3];    // Keeps the min and max of the current grid.\n                                                   // !!NOT!! the value retrieved from params.\n\n        // A few flags to indicate if certain data is out of date\n        bool dataFieldUpToDate;\n        bool vertCoordsUpToDate;\n        bool secondVarUpToDate;\n\n        /* Member functions */\n        UserCoordinates();\n        ~UserCoordinates();\n\n        //\n        // It returns 0 upon success, and non-zero upon errors.\n        //\n        int GetCurrentGrid(const RayCasterParams *params, DataMgr *dataMgr, StructuredGrid **gridpp) const;\n\n        void CheckUpToDateStatus(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr, bool use2ndVar);\n        //\n        // Update meta data, as well as pointers: 6 faces + dataField + missingValueMask\n        //   It returns 0 upon success, and non-zero upon errors:\n        //\n        int UpdateFaceAndData(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr);\n        //\n        // Update pointers: xyCoords and zCoords\n        // |-- Note: meta data is updated in UpdateFaceAndData(), but *NOT* here, so\n        // |         UpdateFaceAndData() needs to be called priori to UpdateVertCoords().\n        // |-- It returns 0 upon success, and non-zero upon errors:\n        //\n        int UpdateVertCoords(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr);\n\n        int Update2ndVariable(const RayCasterParams *params, DataMgr *dataMgr);\n\n        void FillCoordsXYPlane(const StructuredGrid *grid,        // Input\n                               size_t                planeIdx,    // Input: which plane to retrieve\n                               float *               coords);                    // Output buffer allocated by caller\n        void FillCoordsYZPlane(const StructuredGrid *grid,        // Input\n                               size_t                planeIdx,    // Input\n                               float *               coords);                    // Output\n        void FillCoordsXZPlane(const StructuredGrid *grid,        // Input\n                               size_t                planeIdx,    // Input\n                               float *               coords);                    // Output\n        void IterateAGrid(const StructuredGrid *grid,\n                          size_t                numOfVert,    // Length of buffers.\n                          float *               dataBuf,      // Need to be already allocated.\n                          unsigned char *       maskBuf);            // Need to be already allocated.\n\n    };    // end of class UserCoordinates\n\n    UserCoordinates    _userCoordinates;\n    std::vector<float> _colorMap;\n    float              _colorMapRange[3];      // min, max, and diff values.\n    glm::mat4          _currentMV;             // model view matrix in use\n    GLint              _currentViewport[4];    // current viewport in use\n    bool               _isIntel;\n\n    // OpenGL stuff\n    // textures\n    GLuint      _backFaceTextureId;\n    GLuint      _frontFaceTextureId;\n    GLuint      _volumeTextureId;\n    GLuint      _missingValueTextureId;\n    GLuint      _colorMapTextureId;\n    GLuint      _vertCoordsTextureId;\n    GLuint      _depthTextureId;\n    GLuint      _2ndVarDataTexId;\n    GLuint      _2ndVarMaskTexId;\n    const GLint _backFaceTexOffset;\n    const GLint _frontFaceTexOffset;\n    const GLint _volumeTexOffset;\n    const GLint _colorMapTexOffset;\n    const GLint _missingValueTexOffset;\n    const GLint _vertCoordsTexOffset;\n    const GLint _depthTexOffset;\n    const GLint _2ndVarDataTexOffset;\n    const GLint _2ndVarMaskTexOffset;\n\n    // buffers and vertex arrays\n    GLuint _frameBufferId;\n    GLuint _vertexArrayId;\n    GLuint _vertexBufferId;    // Keeps user coordinates of 6 faces.\n    GLuint _indexBufferId;     // Auxiliary indices for efficiently drawing triangle strips.\n    GLuint _vertexAttribId;    // Attribute of vertices: (i, j k) logical indices.\n\n    // shaders\n    ShaderProgram *_1stPassShader;\n    ShaderProgram *_2ndPassShader;\n    ShaderProgram *_3rdPassShader;\n    ShaderProgram *_3rdPassMode1Shader;\n    ShaderProgram *_3rdPassMode2Shader;\n\n    //\n    // Render the volume surface using triangle strips\n    //   This is a subroutine used by _drawVolumeFaces().\n    //\n    void _renderTriangleStrips(int whichPass, int castingMode) const;\n\n    void _drawVolumeFaces(int whichPass, int whichCastingMode, const std::vector<size_t> &cameraCellIdx, const glm::mat4 &inversedMV = glm::mat4(0.0f), bool fast = false) const;\n\n    void _load3rdPassUniforms(int castingMode, bool fast, bool insideVolume) const;\n\n    virtual void _3rdPassSpecialHandling(bool fast, int castingMode) const;\n    virtual void _colormapSpecialHandling();    // Cannot be const due to other subroutines.\n    virtual bool _use2ndVariable(const RayCasterParams *params) const;\n    virtual void _update2ndVarTextures();\n\n    //\n    // Initialization for 1) framebuffers and 2) textures\n    //   It returns 0 upon success, and non-zero upon errors.\n    //\n    int _initializeFramebufferTextures();\n\n    int _selectDefaultCastingMethod() const;\n\n    void _updateViewportWhenNecessary(const GLint *viewport);\n    void _updateColormap(RayCasterParams *params);\n    void _updateDataTextures();\n    int  _updateVertCoordsTexture(const glm::mat4 &MV);\n    void _configure3DTextureNearestInterpolation() const;\n    void _configure3DTextureLinearInterpolation() const;\n    void _configure2DTextureLinearInterpolation() const;\n    void _sleepAWhile() const;\n\n#ifndef WIN32\n    double _getElapsedSeconds(const struct timeval *begin, const struct timeval *end) const;\n#endif\n\n};    // End of class RayCaster\n\n};    // End of namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/RayCasterParams.h",
    "content": "#ifndef RAYCASTERPARAMS_H\n#define RAYCASTERPARAMS_H\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\nclass PARAMS_API RayCasterParams : public RenderParams {\npublic:\n    RayCasterParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, std::string classType);\n    RayCasterParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *xmlNode);\n\n    virtual ~RayCasterParams();\n\n    //\n    //! Obtain current MapperFunction for the primary variable.\n    //\n    MapperFunction *GetMapperFunc();\n\n    bool                GetLighting() const;\n    void                SetLighting(bool);\n    std::vector<double> GetLightingCoeffs() const;\n    void                SetLightingCoeffs(const std::vector<double> &coeffs);\n    //\n    // Different ray casting methods: 1 == fixed step casting\n    //                                2 == prism intersection casting\n    //\n    long GetCastingMode() const;\n    void SetCastingMode(long);\n    long GetSampleRateMultiplier() const;    // ComboBox index is held here. Need to translate\n    void SetSampleRateMultiplier(long);      //   to real multipliers in RayCaster.cpp\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return (3); }\n\nprotected:\n    static const std::string _lightingTag;\n    static const std::string _lightingCoeffsTag;\n    static const std::string _castingModeTag;\n    static const std::string _sampleMultiplierTag;\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/RegularGrid.h",
    "content": "#ifndef _RegularGrid_\n#define _RegularGrid_\n\n#include <ostream>\n#include <vector>\n#include <vapor/common.h>\n#include <vapor/StructuredGrid.h>\n\nnamespace VAPoR {\n\n//! \\class RegularGrid\n//! \\brief This class implements a 2D or 3D regular grid.\n//!\n//! This class implements a 2D or 3D regular grid: a tessellation\n//! of Euculidean space by rectangles (2D) or parallelpipeds (3D). Each\n//! grid point can be addressed by an index(i,j,k), where \\a i, \\p a\n//! and \\a k range from 0 to \\a dim - 1, where \\a dim is the dimension of the\n//! \\a I, \\a J, or \\a K axis, respectively. Moreover, each grid point\n//! has a coordinate in a user-defined coordinate system given by\n//! (\\a i * \\a dx, \\a j * \\a dy, \\a k * \\a dz) for some real\n//! numbers \\a dx, \\a dy, and \\a dz representing the grid spacing.\n//!\n//\n\nclass VDF_API RegularGrid : public StructuredGrid {\npublic:\n    //! \\copydoc StructuredGrid::StructuredGrid(\n    //!\tconst std::vector<size_t>&, const std::vector<bool>&,\n    //!\tconst std::vector<float*>&\n    //!\t)\n    //!\n    //! Construct a regular grid sampling a 3D or 2D scalar function.\n    //!\n    //! Adds new parameters:\n    //!\n    //! \\param[in] minu A vector provding the user coordinates of the first\n    //! point in the grid.\n    //! \\param[in] maxu A vector provding the user coordinates of the last\n    //! point in the grid. All elements of \\p maxu must be greater than or\n    //! equal to corresponding elements in \\p minu.\n    //!\n    //\n    RegularGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, const CoordType &minu, const CoordType &maxu);\n    RegularGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<float *> &blks, const std::vector<double> &minu, const std::vector<double> &maxu);\n\n    RegularGrid() = default;\n    virtual ~RegularGrid() = default;\n\n    virtual size_t GetGeometryDim() const override { return (_geometryDim); }\n\n    virtual DimsType GetCoordDimensions(size_t dim) const override;\n\n    static std::string GetClassType() { return (\"Regular\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    //! \\copydoc Grid::GetBoundingBox()\n    //\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override;\n\n    //! \\copydoc Grid::GetUserCoordinates()\n    //\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override;\n\n    // For grandparent inheritance of\n    // Grid::GetUserCoordinates(const size_t indices[], double coords[])\n    //\n    using Grid::GetUserCoordinates;\n\n    //! \\copydoc Grid::GetIndicesCell\n    //!\n    virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override;\n\n    //! \\copydoc Grid::InsideGrid()\n    //\n    virtual bool InsideGrid(const CoordType &coords) const override;\n\n    class ConstCoordItrRG : public Grid::ConstCoordItrAbstract {\n    public:\n        ConstCoordItrRG(const RegularGrid *rg, bool begin);\n        ConstCoordItrRG(const ConstCoordItrRG &rhs);\n\n        ConstCoordItrRG();\n        virtual ~ConstCoordItrRG() {}\n\n        virtual void            next();\n        virtual void            next(const long &offset);\n        virtual ConstCoordType &deref() const { return (_coords); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const\n        {\n            const ConstCoordItrRG *itrptr = static_cast<const ConstCoordItrRG *>(rhs);\n\n            return (_index == itrptr->_index);\n        }\n\n        virtual std::unique_ptr<ConstCoordItrAbstract> clone() const { return std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrRG(*this)); };\n\n    private:\n        DimsType  _index;\n        DimsType  _dims;\n        CoordType _minu;\n        CoordType _delta;\n        CoordType _coords;\n    };\n\n    virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrRG(this, true))); }\n    virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrRG(this, false))); }\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const RegularGrid &rg);\n\nprotected:\n    virtual float GetValueNearestNeighbor(const CoordType &coords) const override;\n\n    virtual float GetValueLinear(const CoordType &coords) const override;\n\n    //! \\copydoc Grid::GetUserExtents()\n    //\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override;\n\nprivate:\n    void _regularGrid(const CoordType &minu, const CoordType &maxu);\n\n    CoordType _minu = {{0.0, 0.0, 0.0}};\n    CoordType _maxu = {{0.0, 0.0, 0.0}};\n    size_t    _geometryDim;\n    CoordType _delta;    // increment between grid points in user coords\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/RenderParams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tRenderParams.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJuly 2014\n//\n//\tDescription:\tDefines the RendererParams class.\n//\t\tThis is an abstract class for all the tabbed panel render params classes.\n//\t\tSupports functionality common to all the tabbed panel render params.\n\n//\n#ifndef RENDERPARAMS_H\n#define RENDERPARAMS_H\n\n#include <map>\n#include <vapor/common.h>\n#include <vapor/ParamsBase.h>\n#include <vapor/MapperFunction.h>\n#include <vapor/Box.h>\n#include <vapor/ColorbarPbase.h>\n#include <vapor/Transform.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\n//! \\class RenderParams\n//! \\ingroup Public_Params\n//! \\brief A Params subclass for managing parameters used by Renderers\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    February 2014\n//!\nclass PARAMS_API RenderParams : public ParamsBase {\npublic:\n    //! Standard RenderParams constructor.\n    //! \\param[in] name  std::string name, can be the tag\n    RenderParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, const string &classname, int maxdim = 3);\n\n    RenderParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node, int maxdim = 3);\n\n    RenderParams(const RenderParams &rhs);\n\n    RenderParams &operator=(const RenderParams &rhs);\n\n    virtual ~RenderParams();\n\n    //! Initialize the class.\n    //!\n    //! Must be called immediately after the constructor:\n    //!\n    //!  RenderParams(DataMgr *, ParamsBase::StateSave *, const string &, int maxdim);\n    //!\n    //! The results of\n    //! calling any other methods before calling Initialize() are\n    //! undefined.\n    //!\n    //! Subsequent calls to Initialize() after the first call are a no-op.\n    //!\n    //! \\retval returns integer >= 0 on success, otherwise failure\n    //\n    virtual int Initialize();\n    \n    int ResetUserExtentsToDataExents(string var=\"\");\n\n    //! Determine if this params has been enabled for rendering\n    //!\n    //! Default is false.\n    //!\n    //! \\retval bool true if enabled\n    virtual bool IsEnabled() const { return ((bool)GetValueLong(_EnabledTag, (int)false)); }\n\n    //! Enable or disable this params for rendering\n    //!\n    //! This should be executed between start and end capture\n    //! which provides the appropriate undo/redo support\n    //! Accordingly this will not make an entry in the undo/redo queue.\n    //!\n    //! Default is false.\n    //!\n    //! \\param[in] bool true to enable, false to disable.\n    virtual void SetEnabled(bool val);\n\n    //! Specify primary variable name; e.g. used in color mapping or rendering.\n    //! The default is the empty string, which indicates no variable.\n    //! \\param[in] string varName. If \"0\" \\p varName will be quietly\n    //! set to the empty string, \"\".\n    virtual void SetVariableName(string varName);\n\n    //! Get the primary variable name, e.g. used in color mapping or rendering.\n    //! The default is the empty string, which indicates a no variable.\n    //! \\retval string variable name\n    string GetVariableName() const;\n\n    //! Specify auxiliary variable name; e.g. \"Position along Flow\"\n    //! The default is a vector of length containing the empty string.\n    //! \\param[in] string varNames. If any element is \"0\" the element\n    //! will be quietly\n    //! set to the empty string, \"\".\n    virtual void SetAuxVariableNames(vector<string> varName);\n\n    //! Get the auxiliary variable names, e.g. \"position along flow\"\n    //!\n    //! The default is a vector of length containing the empty string.\n    //!\n    //! \\retval vector<string> variable name\n    vector<string> GetAuxVariableNames() const;\n\n    //! Determine if auxiliary variable name is used\n    //! \\retval bool true if using auxiliary variable\n    bool UseAuxVariable() const\n    {\n        vector<string> names = GetAuxVariableNames();\n        for (int i = 0; i < names.size(); i++) {\n            if (GetVariableName() == names[i]) return true;\n        }\n        return false;\n    }\n\n    //! Get the primary variable, or the first valid field variable\n    //!\n    //! Return the first non-empty variable found, first searching\n    //! the name returned by GetVariableName(), and the ordered list\n    //! of variables returned by GetFieldVariableNames(). The empty\n    //! string is returned if no non-empty variable names exist.\n    //!\n    //! \\retval string variable name\n    //\n    string GetFirstVariableName() const;\n\n    //! Specify field variable names; e.g. used in flow integration\n    //! can be 0 or 3 strings\n    //! \\param[in] string varNames. If any element is \"0\" the element\n    //! will be quietly\n    //! set to the empty string, \"\".\n    //\n    virtual void SetFieldVariableNames(vector<string> varNames);\n\n    //! Set the X field variable name, e.g. used in flow integration.\n    //! \\param[in] std::string varName for X field\n    //\n    void SetXFieldVariableName(std::string varName);\n\n    //! Set the Y field variable name, e.g. used in flow integration.\n    //! \\param[in] std::string varName for Y field\n    //\n    void SetYFieldVariableName(std::string varName);\n\n    //! Set the Z field variable name, e.g. used in flow integration.\n    //! \\param[in] std::string varName for Z field\n    //\n    void SetZFieldVariableName(std::string varName);\n\n    //! Get the field variable names, e.g. used in flow integration.\n    //! \\retval vector<string> variable names. A vector of length 3\n    //! containing variable names. The default is 3 empty variable names.\n    vector<string> GetFieldVariableNames() const;\n\n    //! Get the X field variable name, e.g. used in flow integration.\n    //! \\retval std::string X field variable name.\n    //\n    std::string GetXFieldVariableName() const;\n\n    //! Get the Y field variable name, e.g. used in flow integration.\n    //! \\retval std::string Y field variable name.\n    //\n    std::string GetYFieldVariableName() const;\n\n    //! Get the Z field variable name, e.g. used in flow integration.\n    //! \\retval std::string Z field variable name.\n    //\n    std::string GetZFieldVariableName() const;\n\n    //! Get the distribution variable names, e.g. used in flow integration.\n    //! \\retval vector<string> variable names\n    vector<string> GetDistribVariableNames() const { return (GetValueStringVec(_distribVariableNamesTag)); }\n\n    //! Virtual method sets current number of refinements of this Params.\n    //! \\param[in] int refinements\n    //!\n    virtual void SetRefinementLevel(int numrefinements);\n\n    //! Virtual method indicates current number of refinements of this Params.\n    //! \\retval integer number of refinements\n    //!\n    virtual int GetRefinementLevel() const;\n\n    //! virtual method indicates current Compression level.\n    //! \\retval integer compression level, 0 is most compressed\n    //!\n    virtual int GetCompressionLevel() const;\n\n    //! Virtual method sets current Compression level.\n    //! \\param[in] val  compression level, 0 is most compressed\n    //!\n    virtual void SetCompressionLevel(int val);\n\n    //! Specify a stretch factor used in displaying histograms in\n    //! mapper functions.\n    //! Can be ignored if there is no mapper function in the params.\n    //! Default value is 1.0.\n    //!\n    //! \\param[in] factor positive multiplier that applies to the\n    //! histogram height.\n    void SetHistoStretch(float factor);\n\n    //! Obtain the stretch factor used in displaying histograms in mapper\n    //! functions.\n    //!\n    //! Default value is 1.0.\n    //! \\return multiplier that applies to the histogram height.\n    float GetHistoStretch() const;\n\n    //! Obtain ColorbarPBase (used to specify Color Bar properties) from RenderParams.\n    virtual ColorbarPbase *GetColorbarPbase() const { return _Colorbar; }\n\n    //! Set the ColorbarPbase that specifies properties of the Color bar.\n    //! \\sa GetColorbarPbase\n    //! By default the ColorbarPbase is a child of the root node of this RenderParams.\n    //! \\param[in] pb ColorbarPbase to set.\n    //! \\return 0 if successful.\n    virtual void SetColorbarPbase(ColorbarPbase *pb);\n\n    //! Obtain current MapperFunction\n    //!\n    //! Get a MapperFunction for the variable \\p varname.\n    //! If one does not exist it is created.\n    //\n    virtual MapperFunction *GetMapperFunc(string varname);\n\n    //! Remove the mapper function for the named variable.\n    //\n    virtual void RemoveMapperFunc(string varname);\n\n    //! Set current MapperFunction\n    //!\n    //! \\param[in] varname Name of variable associated with mapping\n    //! \\param[in] tf\n    //\n    virtual void SetMapperFunc(string varname, MapperFunction *tf);\n\n    //! Virtual method to return the Box associated with a Params class.\n    //! By default returns NULL.\n    //! All params classes that use a box to define data extents should reimplement this method.\n    //! Needed to support manipulators.\n    //! \\retval Box* returns pointer to the Box associated with this Params.\n    //\n    virtual Box *GetBox() const { return (_Box); }\n\n    //! Specify the 2D cursor coordinates when associated with this RenderParams\n    //! \\param[in] coords\n    void SetCursorCoords(const float coords[2]);\n\n    //! Obtain the 2D cursor coordinates if associated with this RenderParams\n    //! \\return 2D cursor coordinates\n    void GetCursorCoords(float coords[2]) const;\n\n    //! Specify the variable being used for height\n    //! Overrides method on RenderParams\n    //! \\param[in] string varName. If any \\p varName is \"0\" it\n    //! will be quietly\n    //! set to the empty string, \"\".\n    //! \\retval int 0 if successful;\n    virtual void SetHeightVariableName(string varname);\n\n    //! Determine variable name being used for terrain height (above or below sea level)\n    //! \\retval const string& variable name\n    virtual string GetHeightVariableName() const;\n\n    //! Indicate if a single (constant) color is being used\n    //! \\return true if constant single color is used\n    bool UseSingleColor() const;\n\n    //! Specify the variable being used for color mapping\n    //! \\param[in] string varName. If any \\p varName is \"0\" it\n    //! will be quietly\n    //! set to the empty string, \"\".\n    //\n    virtual void SetColorMapVariableName(string varname);\n\n    //! Get the color mapping variable name if any\n    //! \\retval string variable name\n    //!\n    virtual string GetColorMapVariableName() const;\n\n    //! Due to legacy code, the \"ColorMapVariableName\" is not  the name of the variable by which\n    //! the renderer is colormapping, but rather the variable it should use if it is not already using its\n    //! primary variable or a constant color. This function should return the name of the variable that\n    //! is currently being used for colormapping.\n    virtual string GetActualColorMapVariableName() const = 0;\n\n    //! Turn on or off the use of single constant color (versus color map)\n    //! \\param[in] val true will enable constant color\n    void SetUseSingleColor(bool val);\n\n    //! Specify a constant color\n    //!\n    //! Specify a constant color is in rgb values between 0 and 1.\n    //! The constant color is used to color objects when UseSingleColor()\n    //! returns true.\n    //!\n    //! \\param[in] const float rgb[3]\n    //!\n    //! \\sa GetConstantColor()\n    //\n    void SetConstantColor(const float rgb[3]);\n    void SetConstantColor(vector<float> rgb);\n\n    //! Get the constant color (in r,g,b)\n    //!\n    //! \\param[out] rgb A 3-element array use values are in the range 0.0..1.0\n    //!\n    //! \\sa SetConstantColor(), GetConstantOpacity(), UseSingleColor()\n    //\n    void GetConstantColor(float rgb[3]) const;\n\n    vector<float> GetConstantColor() const\n    {\n        float rgb[3];\n        GetConstantColor(rgb);\n        vector<float> v = {rgb[0], rgb[1], rgb[2]};\n        return (v);\n    }\n\n    //! Specify a constant opacity.  Color is n the between 0 and 1.\n    //!\n    //! \\param[in] const float rgb[3]\n    //! \\retval 0 if successful\n    //!\n    void SetConstantOpacity(float o);\n\n    //! Get the constant opacity\n    //!\n    //! \\retval opacity\n    //!\n    //! \\sa SetConstantColor(), GetConstantOpacity()\n    //\n    float GetConstantOpacity() const;\n\n    //! Get the current data timestep\n    //! \\retval ts current time step\n    //\n    size_t GetCurrentTimestep() const { return (size_t)GetValueLong(_currentTimestepTag, 0); }\n\n    //! Set the current data timestep being used\n    //! \\param[in] ts current time step\n    //\n    void SetCurrentTimestep(size_t ts) { SetValueLong(_currentTimestepTag, \"Set timestep\", (long)ts); }\n\n    //! Access the transform used by the renderer\n    //\n    virtual Transform *GetTransform() const { return _transform; }\n\n    void initializeBypassFlags();\n\n    //! Set reasonable default variables\n    //! \\param[in] The dimension of the variables being set\n    //! \\param[in] Indicates whether we're using color mapped variables\n    virtual void SetDefaultVariables(int dim, bool secondaryColormapVariable);\n\n    //! Return the renderer's current dimension\n    //!\n    //! For renderers that are only capable of operating on variables of a fixed\n    //! dimensionality (e.g. 2D or 3D) this function will return a constant value:\n    //! the number of dimensions. For renderers that can operate on a variable of\n    //! varying dimension this method returns the current dimensionality. The\n    //! returned value will be between 0 and 3. A value of zero will be\n    //! returned if the current dimensionality cannot be determined.\n    //!\n    //!\n    virtual size_t GetRenderDim() const = 0;\n\n    //! This should be overriden by params for renderes that support iso values to return true.\n    virtual bool           HasIsoValues() const { return false; }\n    virtual vector<double> GetIsoValues(const string &variable)\n    {\n        VAssert(0);\n        return {};\n    }\n    virtual void SetIsoValues(const string &variable, const vector<double> &values) { VAssert(0); }\n\n    vector<double> GetIsoValues() { return GetIsoValues(GetVariableName()); }\n    void           SetIsoValues(const vector<double> &values) { SetIsoValues(GetVariableName(), values); }\n\n    //! Return whether a renderer can be oriented - IE, can this renderer be rotated about an origin point?\n    virtual bool GetOrientable() const;\n\n    //! Return the renderer's 3 axis rotation for creating ArbitrarilyOrientedRegularGrids.\n    //! \\retval vector<double> - Slice's rotation on X, Y, and Z axes\n    //! Valid values - -90.0 to 90.0 for each axis component\n    vector<double> GetSlicePlaneRotation() const;\n\n    //! Return the renderer's 3 axis origin for creating ArbitrarilyOrientedRegularGrids.\n    //! \\retval vector<double> - Slice's origin on X, Y, and Z axes, specified in the data's coordinate system\n    //! Valid values - A point within the data domain\n    vector<double> GetSlicePlaneOrigin() const;\n\n    //! Return the renderer's 3 axis normal for creating ArbitrarilyOrientedRegularGrids.\n    //! \\retval vector<double> - Slice's rotation on X, Y, and Z axes, specified in the data's coordinate system\n    //! Valid values - -1.0 to 1.0 for each axis component\n    vector<double> GetSlicePlaneNormal() const;\n\n    //! Return the renderer's origin value on the X axis for creating ArbitrarilyOrientedRegularGrids.\n    //! \\retval double - Slice's origin on the X axis\n    //! Valid values - A point within the data domain's X axis coordinates\n    double GetXSlicePlaneOrigin() const;\n\n    //! Return the renderer's origin value on the Y axis for creating ArbitrarilyOrientedRegularGrids.\n    //! \\retval double - Slice's origin on the Y axis\n    //! Valid values - A point within the data domain's Y axis coordinates\n    double GetYSlicePlaneOrigin() const;\n\n    //! Return the renderer's origin value on the Z axis for creating ArbitrarilyOrientedRegularGrids.\n    //! \\retval double - Slice's origin on the Z axis, specified in the data's coordinate system\n    //! Valid values - A point within the data domain's Z axis coordinates\n    double GetZSlicePlaneOrigin() const;\n\n    //! Set the renderer's origin value on the X axis for creating ArbitrarilyOrientedRegularGrids.\n    //! \\param[in] double - Value to use for the plane origin on the X axis.\n    //! Valid values - A point within the data domain's X axis coordinates\n    void SetXSlicePlaneOrigin(double xOrigin);\n\n    //! Set the renderer's origin value on the Y axis for creating ArbitrarilyOrientedRegularGrids.\n    //! \\param[in] double - Value to use for the plane origin on the Y axis.\n    //! Valid values - A point within the data domain's Y axis coordinates\n    void SetYSlicePlaneOrigin(double yOrigin);\n\n    //! Set the renderer's origin value on the Z axis for creating ArbitrarilyOrientedRegularGrids.\n    //! \\param[in] double - Value to use for the plane origin on the Z axis.\n    //! Valid values - A point within the data domain's Z axis coordinates\n    void SetZSlicePlaneOrigin(double zOrigin);\n\n    //! Set the values for a quad that encloses an arbitrary user-defined plane\n    //! \\param[in] A std::vector<CoordType> of size 4, containing the locations of four vertices.\n    void SetSlicePlaneQuad(const std::vector<CoordType> &quad) { _slicePlaneQuad = quad; }\n\n    //! Return the values for a quad that encloses an arbitrary user-defined plane\n    //! \\retval A std::vector<CoordType> of size 4, containing the locations of four vertices.\n    std::vector<CoordType> GetSlicePlaneQuad() const { return _slicePlaneQuad; }\n\n    //! Sets whether the renderer is drawn without depth testing (drawn on top of other renderers)\n    void SetDrawInFront(bool);\n\n    //! Return whether the renderer is drawn without depth testing (drawn on top of other renderers)\n    bool GetDrawInFront() const;\n\nprotected:\n    DataMgr *_dataMgr;\n    int      _maxDim;\n\n    bool InitBoxFromVariable(size_t ts, string varName);\n\n    virtual bool GetUseSingleColorDefault() const { return false; }\n\nprivate:\n    void                   _init();\n    void                   _calculateStride(string varName);\n    int                    _stride;\n    ParamsContainer *      _TFs;\n    Box *                  _Box;\n    ColorbarPbase *        _Colorbar;\n    Transform *            _transform;\n    bool                   _classInitialized;    //\n    std::vector<CoordType> _slicePlaneQuad;\n\n    static const string _EnabledTag;\n    static const string _histoScaleTag;\n    static const string _editBoundsTag;\n    static const string _histoBoundsTag;\n    static const string _cursorCoordsTag;\n    static const string _terrainMapTag;\n    static const string _auxVariableNamesTag;\n    static const string _distribVariableNamesTag;\n    static const string _transferFunctionsTag;\n    static const string _stretchFactorsTag;\n    static const string _currentTimestepTag;\n\n    string _findVarStartingWithLetter(std::vector<string> searchVars, char letter);\n    string _findVarEndingWithLetter(std::vector<string> searchVars, char letter);\n\npublic:\n    static const string _variableNameTag;\n    static const string _colorMapVariableNameTag;\n    static const string _heightVariableNameTag;\n    static const string _useSingleColorTag;\n    static const string _constantColorTag;\n    static const string _CompressionLevelTag;\n    static const string _RefinementLevelTag;\n    //    static const string _fieldVariableNamesTag;\n    static const string _xFieldVariableNameTag;\n    static const string _yFieldVariableNameTag;\n    static const string _zFieldVariableNameTag;\n    static const string _constantOpacityTag;\n    static const string CustomHistogramDataTag;\n    static const string CustomHistogramRangeTag;\n    static const string LightingEnabledTag;\n    static const string UserNameTag;\n    static const string DrawInFrontTag;\n\n    //! If a renderer supports rotation about a point of origin (IE - Slice and Contour),\n    //! this tag identifies the parameter for the origin's\n    //! location on the X axis.\n    //! \\details This tag only applies when 3D data are sliced for contouring or pseudo-coloring slices\n    //! Applies to data of type: double\n    //! Valid values: A point within the data domain's X axis coordinates\n    static const string XSlicePlaneOriginTag;\n\n    //! If a renderer supports rotation about a point of origin (IE - Slice and Contour),\n    //! this tag identifies the parameter for the origin's\n    //! location on the Y axis.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Valid values: A point within the data domain's Y axis coordinates\n    static const string YSlicePlaneOriginTag;\n\n    //! If a renderer supports rotation about a point of origin (IE - Slice and Contour),\n    //! this tag identifies the parameter for the origin's\n    //! location on the Z axis.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Valid values: A point within the data domain's Z axis coordinates\n    static const string ZSlicePlaneOriginTag;\n\n    //! If a renderer supports rotation about a point of origin (IE - Slice and Contour),\n    //! this tag identifies the parameter for the rotation\n    //! about the X axis.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Valid values: -90.0 to 90.0\n    static const string XSlicePlaneRotationTag;\n\n    //! If a renderer supports rotation about a point of origin (IE - Slice and Contour),\n    //! this tag identifies the parameter for the rotation\n    //! about the Y axis.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Valid values: -90.0 to 90.0\n    static const string YSlicePlaneRotationTag;\n\n    //! If a renderer supports rotation about a point of origin (IE - Slice and Contour),\n    //! this tag identifies the parameter for the rotation\n    //! about the Z axis.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Valid values: -90.0 to 90.0\n    static const string ZSlicePlaneRotationTag;\n\n    //! If a renderer samples data points through a plane (IE - Slice and Contour),\n    //! this tag identifies the parameter for how many samples\n    //! to take along that vector.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: long\n    //! Valid values: 0 to LONG_MAX\n    static const string SampleRateTag;\n\n    //! If a renderer can be offset from a point of origin  (IE - Slice and Contour),\n    //! this tag identifies the parameter for offsetting the renderer from that point.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Valid values: DBL_MIN to DBL_MAX\n    static const string SliceOffsetTag;\n\n    //! If a renderer can be oriented orthogonally to a normal vector (IE - Slice and Contour),\n    //! this tag identifies the normal's X component.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Typical values: -1.0 to 1.0\n    //! Valid values: DBL_MIN to DBL_MAX\n    static const string SlicePlaneNormalXTag;\n\n    //! If a renderer can be oriented orthogonally to a normal vector (IE - Slice and Contour),\n    //! this tag identifies the normal's Y component.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Typical values: -1.0 to 1.0\n    //! Valid values: DBL_MIN to DBL_MAX\n    static const string SlicePlaneNormalYTag;\n\n    //! If a renderer can be oriented orthogonally to a normal vector (IE - Slice and Contour),\n    //! this tag identifies the normal's Z component.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: double\n    //! Typical values: -1.0 to 1.0\n    //! Valid values: DBL_MIN to DBL_MAX\n    static const string SlicePlaneNormalZTag;\n\n    //! If a renderer can be oriented according to 1) a set of rotationis on the XYZ axes, or\n    //! 2) according to the orthoganality of a specified normal (IE - Slice and Contour), \n    //! this tag determines which method is being used to orient the the renderer.\n    //! \\copydetails RenderParams::XSlicePlaneOriginTag()\n    //! Applies to data of type: long\n    //! Valid values: 0 = SlicePlaneOrientationMode::Rotation, 1 = SlicePlaneOrientationMode::Normal\n    static const string SlicePlaneOrientationModeTag;\n\n    enum class SlicePlaneOrientationMode {\n        Rotation = 0,\n        Normal = 1,\n    };\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RenParamsFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nclass PARAMS_API RenParamsFactory {\npublic:\n    static RenParamsFactory *Instance()\n    {\n        static RenParamsFactory instance;\n        return &instance;\n    }\n\n    void RegisterFactoryFunction(string name, function<RenderParams *(DataMgr *, ParamsBase::StateSave *, XmlNode *)> classFactoryFunction)\n    {\n        // register the class factory function\n        _factoryFunctionRegistry[name] = classFactoryFunction;\n    }\n\n    RenderParams *(CreateInstance(string classType, DataMgr *, ParamsBase::StateSave *, XmlNode *));\n\n    vector<string> GetFactoryNames() const;\n\nprivate:\n    map<string, function<RenderParams *(DataMgr *, ParamsBase::StateSave *, XmlNode *)>> _factoryFunctionRegistry;\n\n    RenParamsFactory() {}\n    RenParamsFactory(const RenParamsFactory &) {}\n    RenParamsFactory &operator=(const RenParamsFactory &) { return *this; }\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RenParamsRegistrar Class\n//\n// Register RenParamsBase derived class with:\n//\n//\tstatic RenParamsRegistrar<RenParamsClass> registrar(\"myclassname\");\n//\n// where 'RenParamsClass' is a class derived from 'RenderParams', and\n// \"myclassname\" is the name of the class\n//\n/////////////////////////////////////////////////////////////////////////\n\ntemplate<class T> class RenParamsRegistrar {\npublic:\n    RenParamsRegistrar(string classType)\n    {\n        // register the class factory function\n        //\n        RenParamsFactory::Instance()->RegisterFactoryFunction(classType, [](DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) -> RenderParams * {\n            if (node)\n                return new T(dataMgr, ssave, node);\n            else\n                return new T(dataMgr, ssave);\n        });\n    }\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RenParamsContainer Class\n//\n/////////////////////////////////////////////////////////////////////////\n\n//\n// The RenParamsContainer class constructs an XML tree as depicted below,\n// where 'Container Name' is the root of XML tree, and is the name\n// passed into the constructor as 'myname'; 'Class Name' is the name of\n// the derived RenParamBase class used to construct new instances of\n// the derived class; and 'ele name x' is the unique name of the element\n// contained in the container.\n//\n/*\n            |----------------|\n            | Container Name |\n            |----------------|\n                    |\n                   \\|/\n            |----------------|\n            |   Class Name   |\n            |----------------|\n                    |         \\\n                   \\|/         \\\n            |----------------|  \\ |----------------|\n            |   ele name 1   |....|   ele name n   |\n            |----------------|    |----------------|\n*/\nclass PARAMS_API RenParamsContainer : public Wasp::MyBase {\npublic:\n    RenParamsContainer(DataMgr *dataMgr, ParamsBase::StateSave *ssave, const string &myname);\n\n    RenParamsContainer(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n\n    //! Copy constructor.\n    RenParamsContainer(const RenParamsContainer &rhs);\n\n    RenParamsContainer &operator=(const RenParamsContainer &rhs);\n\n    ~RenParamsContainer();\n\n    RenderParams *Insert(const RenderParams *rp, string name);\n\n    RenderParams *Create(string classType, string name);\n\n    void Remove(string name);\n\n    RenderParams *GetParams(string name) const;\n\n    vector<string> GetNames() const;\n\n    size_t Size() const { return (_elements.size()); }\n\n    XmlNode *GetNode() const { return _separator->GetNode(); }\n\n    ParamsSeparator *GetSeparator() const { return _separator; }\n\n    string const GetName() const { return (_separator->GetName()); }\n\nprivate:\n    DataMgr *                   _dataMgr;\n    ParamsBase::StateSave *     _ssave;\n    ParamsSeparator *           _separator;\n    map<string, RenderParams *> _elements;\n};\n\n};        // End namespace VAPoR\n#endif    // RENDERPARAMS_H\n"
  },
  {
    "path": "include/vapor/Renderer.h",
    "content": "\n//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\tFile:\t\tRenderer.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tSeptember 2004\n//\n//\tDescription:\tDefines the Renderer class.\n//\t\tA pure virtual class that is implemented for each renderer.\n//\t\tMethods are called by the visualizer class as needed.\n//\n\n#ifndef RENDERER_H\n#define RENDERER_H\n\n#include <vapor/MyBase.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/RenderParams.h>\n\nnamespace VAPoR {\n\nclass ShaderProgram;\nstruct GLManager;\nclass MatrixManager;\n\n//! \\class RendererBase\n//! \\ingroup Public_Render\n//! \\brief A base class for Renderer classes\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date July 2015\n//!\n//! RendererBase is a base class of Renderer, for special rendering\n//! tasks that are not associated with RenderParams instances.\n//! For example the VizFeatureRenderer has a special role during\n//! Visualizer OpenGL rendering. RendererBase instances perform rendering\n//! in a VAPOR Visualizer but are not associated with RenderParams instances.\n//!\nclass RENDER_API RendererBase : public MyBase {\npublic:\n    RendererBase(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr);\n    virtual ~RendererBase();\n    //! Pure virtual method\n    //! Any OpenGL initialization is performed in initializeGL\n    //! It will be called from an OpenGL rendering context.\n    //! Sets _initialized to true if successful.\n    virtual int initializeGL(GLManager *glManager);\n\n    //! Obtain the Visualizer associated with this Renderer\n    string GetVisualizer() { return _winName; }\n\n    //! Identify the name of the current renderer\n    //! \\return name of renderer\n    string GetMyName() const { return (_instName); };\n    string GetInstanceName() const { return GetMyName(); }\n\n    //! Identify the type of the current renderer\n    //! \\return type of renderer\n    string GetMyType() const { return (_classType); };\n\n    //! Identify the params belonging to the current renderer\n    //! \\return params for renderer\n    string GetMyParamsType() const { return (_paramsType); };\n\n    //! Identifiy the dataset associated with the current renderer\n    //! \\return dataset name\n    string GetMyDatasetName() const { return (_dataSetName); };\n\n    //! Return boolean indicating whether initializeGL has been\n    //! successfully called\n    //!\n    bool IsGLInitialized() const { return (_glInitialized); }\n\nprotected:\n    const ParamsMgr *_paramsMgr;\n    string           _winName;\n    string           _dataSetName;\n    string           _paramsType;\n    string           _classType;\n    string           _instName;\n    DataMgr *        _dataMgr;\n\n    GLManager *_glManager;\n\n    //! Pure virtual method\n    //! Any OpenGL initialization is performed in initializeGL\n    //! It will be called from an OpenGL rendering context.\n    virtual int _initializeGL() = 0;\n\npublic:\n    //! Renderers need to be deleted during the draw loop\n    //! to ensure the correct OpenGL context is bound\n    void FlagForDeletion();\n    bool IsFlaggedForDeletion() const;\n    DataMgr *GetDataMgr() const { return _dataMgr; }\n\n    RendererBase() {}\n\nprivate:\n    bool _glInitialized;\n    bool _flaggedForDeletion;\n};\n\n//! \\class Renderer\n//! \\ingroup Public_Render\n//! \\brief A class that performs rendering in a Visualizer\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date July 2015\n//!\n//! Renderer class is a pure virtual class that supports\n//! OpenGL rendering in the VAPOR visualizer window, using a RenderParams instance to describe the rendering.\n//! All Renderer classes must derive from this class.\nclass RENDER_API Renderer : public RendererBase {\npublic:\n    //! Constructor should be invoked by any derived renderers.\n    //! It is invoked when the user enables a renderer.\n    //! Provides any needed setup of renderer state, but not of OpenGL state.\n    //\n    Renderer(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr);\n\n    virtual ~Renderer();\n\n    //! Get default z value at the base of the domain.  Useful\n    //! for applying a height value to 2D renderers.\n    //! \\param[in] dataMgr Current (valid) dataMgr\n    //! \\retval default height value for current dataset\n    double GetDefaultZ(DataMgr *dataMgr, size_t ts) const;\n\n    //! All OpenGL rendering is performed in the paintGL method.\n    //! This invokes _paintGL on the renderer subclass\n    //! \\param[in] dataMgr Current (valid) dataMgr\n    //! \\retval int zero if successful.\n    virtual int paintGL(bool fast);\n\n    //! Clear render cache\n    //!\n    //! Called whenever renderer should clear any cached data\n    //\n    void ClearCache() { _clearCache(); };\n\n#ifdef VAPOR3_0_0_ALPHA\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Call setBypass to indicate that the renderer will not work until the state of the params is changed\n    //! This will result in the renderer not being invoked for the specified timestep\n    //! \\param[in] int timestep The timestep when the renderer fails\n    void setBypass(int timestep)\n    {\n        if (_currentRenderParams) _currentRenderParams->setBypass(timestep);\n    }\n\n    //! Partial bypass is currently only used by DVR and Isosurface renderers.\n    //! Indicates a renderer that should be bypassed at\n    //! full resolution but not necessarily at interactive resolution.\n    //! \\param[in] timestep Time step that should be bypassed\n    void setPartialBypass(int timestep)\n    {\n        if (_currentRenderParams) _currentRenderParams->setPartialBypass(timestep);\n    }\n\n    //! SetAllBypass is set to indicate all (or no) timesteps should be bypassed\n    //! Should be set true when render failure is independent of timestep\n    //! Should be set false when state changes and rendering should be reattempted.\n    //! \\param[in] val indicates whether it is being turned on or off.\n    void setAllBypass(bool val)\n    {\n        if (_currentRenderParams) _currentRenderParams->setAllBypass(val);\n    }\n\n    //! doBypass indicates the state of the bypass flag.\n    //! \\param[in] timestep indicates the timestep being checked\n    //! \\retval bool indicates that the rendering at the timestep should be bypassed.\n    bool doBypass(int timestep) { return (_currentRenderParams && _currentRenderParams->doBypass(timestep)); }\n\n    //! doAlwaysBypass is used in the presence of partial bypass.\n    //! Indicates that the rendering should be bypassed at any resolution\n    //! \\param[in] int timestep Time step\n    //! \\retval bool value of flag\n    bool doAlwaysBypass(int timestep) { return (_currentRenderParams && _currentRenderParams->doAlwaysBypass(timestep)); }\n\n    //! General method to force a renderer to re-obtain its data.\n    //! Default does nothing\n    //! Must be re-implemented if\n    //! there is state or a cache that is retained between renderings.\n    virtual void setAllDataDirty() { return; }\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Set the current ControlExec\n    //! \\param[in] ds Current DataStatus instance\n    static void SetControlExec(ControlExec *ce) { _controlExec = ce; }\n\n    //! @name Internal\n    //! Internal methods not intended for general use\n    //!\n    ///@{\n\n    //! Static method invoked during Undo and Redo of Renderer enable or disable.\n    //! This function must be passed in Command::CaptureStart for enable and disable rendering.\n    //! It causes the Undo and Redo operations on enable/disable renderer to actually create\n    //! or destroy the renderer.\n    //! \\sa UndoRedoHelpCB_T\n    //! \\param[in] isUndo indicates whether an Undo or Redo is being performed\n    //! \\param[in] instance indicates the RenderParams instance that is enabled or disabled\n    //! \\param[in] beforeP is a copy of the InstanceParams at the start of the Command\n    //! \\param[in] afterP is a copy of the InstanceParams at the end of the Command\n    //! \\param[in] auxPrev is a copy of auxiliary InstanceParams at the start of the Command, not currently used\n    //! \\param[in] afterP is a copy of auxiliary InstanceParams at the end of the Command, not currently used\n    static void UndoRedo(bool isUndo, int instance, Params *beforeP, Params *afterP, Params *auxPrev = 0, Params *auxNext = 0);\n\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Construct transform of form (x,y)-> (a[0]x+b[0],a[1]y+b[1],const)\n    //! Mapping [-1,1]X[-1,1] into local 3D volume coordinates.\n    //! This is used to map plane coordinates (for various 2D renderers) into User coordinates\n    //! \\param[in] orientation is 0 1 or 2 for z, y, or x-axis orientation.\n    //! \\param[out] a is linear term of mapping\n    //! \\param[out] b is constant term of mapping\n    //! \\param[out] constVal is the coordinate along the axis orthogonal to the image of the mapping\n    //! \\param[out] mappedDims gives the three axes of the mapped image\n    void buildLocal2DTransform(int dataOrientation, float a[2], float b[2], float *constVal, int mappedDims[3]);\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n\n    //! Obtain the extents of a region that contains a rotated (3D) box associated with a renderer.\n    //! \\param[out] regMin Minimum coordinates of containing region.\n    //! \\param[out] regMix Maximum coordinates of containing region.\n    void getLocalContainingRegion(float regMin[3], float regMax[3]);\n#endif\n\n    //! Render the colorbar for this renderer (if it has one)\n    void renderColorbar();\n\n    ///@}\n\n    //! Obtain the current RenderParams instance\n    //! \\retval RenderParams* current render params\n    RenderParams *GetActiveParams() const { return (_paramsMgr->GetRenderParams(_winName, _dataSetName, _paramsType, _instName)); }\n\n    ViewpointParams *GetViewpointParams() const { return _paramsMgr->GetViewpointParams(_winName); }\n\n    AnnotationParams *GetAnnotationParams() const { return _paramsMgr->GetAnnotationParams(_winName); }\n\n    Transform *GetDatasetTransform() const { return GetViewpointParams()->GetTransform(_dataSetName); }\n\n    void ApplyTransform(MatrixManager *mm) const;\n    static void ApplyTransform(MatrixManager *mm, const Transform *dataset, const Transform *renderer);\n\n    static void ApplyDatasetTransform(GLManager *gl, const Transform *dataset);\n\nprotected:\n    Renderer() {}\n\n    virtual std::string _getColorbarVariableName() const;\n\n    //! All OpenGL rendering is performed in the pure virtual paintGL method.\n    virtual int _paintGL(bool fast) = 0;\n\n    //! Enable specified clipping planes during the GL rendering. This\n    //! method clips the scene to the bounding box. See\n    //!! RenderParams::GetBox()\n    //! May be invoked during _paintGL() by classes derived from this class.\n    //! Clipping planes are specified in User coordinates.\n    //!\n    //! \\param[in] haloFrac Fraction of bounding box that should be used to\n    //! extend the min and max clippig planes. For example, if a min extent\n    //! is zero, and a max extent is 1.0, and haloFrac is 0.1 then the\n    //! min clipping plane will be set to -0.1 and the max to 1.1\n    //!\n    //! \\sa DisableClippingPlanes\n    void EnableClipToBox(ShaderProgram *shader, float haloFrac = 0.0) const;\n\n    //! Disable clipping planes.\n    //! If clipping is enabled this  method should be called prior to\n    //! returning from _paintGL()\n    //\n    void DisableClippingPlanes();\n\n    //! Get clipping planes in the model/user coordinates.\n    //! There are six planes in total that get stored in \"planes\"\n    //! It is the caller's responsibility to allocate memory for 24 floats.\n    void GetClippingPlanes(float planes[24]) const;\n\n    //! return true if all of the specified variables exist in the DataMgr\n    //! at the specified timestep, refinement level, and lod. If \\p zeroOK\n    //! is true variables named \"0\" or \"\" evaluate to true.\n    //\n    virtual bool VariableExists(size_t ts, std::vector<string> &varnames, int level, int lod, bool zeroOK) const;\n\n    virtual void _clearCache() = 0;\n\n    static const int _imgHgt;\n    static const int _imgWid;\n    unsigned char *  _colorbarTexture;\n    string           _fontName;\n\nprivate:\n    size_t _timestep;\n\n#ifdef VAPOR3_0_0_ALPHA\n    static ControlExec *_controlExec;\n#endif\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RendererFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nclass RENDER_API RendererFactory {\npublic:\n    static RendererFactory *Instance();\n\n    void RegisterFactoryFunction(string myName, string myParamsName, function<Renderer *(const ParamsMgr *, string, string, string, string, DataMgr *)> classFactoryFunction);\n\n    Renderer *(CreateInstance(const ParamsMgr *pm, string winName, string dataSetName, string classType, string instName, DataMgr *dataMgr));\n\n    string              GetRenderClassFromParamsClass(string paramsClass) const;\n    string              GetParamsClassFromRenderClass(string renderClass) const;\n    std::vector<string> GetFactoryNames() const;\n\nprivate:\n    map<string, function<Renderer *(const ParamsMgr *, string, string, string, string, DataMgr *)>> _factoryFunctionRegistry;\n    map<string, string>                                                                             _factoryMapRegistry;\n\n    RendererFactory();\n    RendererFactory(const RendererFactory &);\n    RendererFactory &operator=(const RendererFactory &);\n};\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RendererRegistrar Class\n//\n// Register RendererBase derived class with:\n//\n//\tstatic RendererRegistrar<RendererClass>\n//\t\tregistrar(\"myclassname\", \"myparamsclassname\");\n//\n// where 'RendererClass' is a class derived from 'Renderer', and\n// \"myclassname\" is the name of the class\n//\n/////////////////////////////////////////////////////////////////////////\n\ntemplate<class T> class RENDER_API RendererRegistrar {\npublic:\n    RendererRegistrar(string classType, string paramsClassType)\n    {\n        // register the class factory function\n        //\n        RendererFactory::Instance()->RegisterFactoryFunction(classType, paramsClassType,\n                                                             [](const ParamsMgr *pm, string winName, string dataSetName, string classType, string instName, DataMgr *dataMgr) -> Renderer * {\n                                                                 return new T(pm, winName, dataSetName, instName, dataMgr);\n                                                             });\n    }\n};\n\n};    // namespace VAPoR\n\n#endif    // RENDERER_H\n"
  },
  {
    "path": "include/vapor/ResourcePath.h",
    "content": "#pragma once\n\n#include \"vapor/MyBase.h\"\n#include <string>\n\nnamespace Wasp {\nCOMMON_API std::string GetResourcePath(const std::string &name);\nCOMMON_API std::string GetSharePath(const std::string &name);\n\n//! Returns full python installation path\n//! e.g. /home/lib/python2.7\nCOMMON_API std::string GetPythonPath();\n\n//! Returns python version\n//! e.g. 3.6\nCOMMON_API std::string GetPythonVersion();\n\n//! Returns python home\n//! e.g. if python if installed in /home/lib/python2.7\n//! this will return /home on Linux/Mac but it will return\n//! /home/lib/python2.7 on Windows\nCOMMON_API std::string GetPythonDir();\n\n//! Register an additional function which returns a path for a given resource.\n//! This function will be given precidence over the default resource search paths.\nCOMMON_API void RegisterResourceFinder(std::string (*cb)(const std::string &));\n};    // namespace Wasp\n"
  },
  {
    "path": "include/vapor/STLUtils.h",
    "content": "#pragma once\n\n#include <vapor/MyBase.h>\n#include <string>\n#include <vector>\n#include <map>\n#include <algorithm>\n#include <functional>\n#include <iterator>\n\nnamespace STLUtils {\n\ntemplate<typename T> bool Contains(const std::vector<T> &toSearch, const T &object) { return std::find(toSearch.cbegin(), toSearch.cend(), object) != toSearch.cend(); }\n\ntemplate<typename T> void AppendTo(std::vector<T> &a, const std::vector<T> &b) { a.insert(a.end(), b.begin(), b.end()); }\n\ntemplate<typename T> std::vector<T> Slice(const std::vector<T> &a, int from, int to = -1) { return std::vector<T>(a.begin() + from, to < 0 ? a.end() : a.begin() + to); }\ntemplate<typename T, typename K> const std::vector<T> MapKeys(const std::map<T, K> m) {\n    // const auto keys = std::views::keys(m);\n    // return vector<T>(keys.begin(), keys.end());\n    vector<T> keys;\n    keys.reserve(m.size());\n    for (const auto &it : m)\n        keys.push_back(it.first);\n    return keys;\n}\n\ntemplate<typename T> vector<T> Filter(const std::vector<T> &v, std::function<bool(const T&)> f) {\n    vector<T> v2;\n    std::copy_if(v.begin(), v.end(), std::back_inserter(v2), f);\n    return v2;\n}\n\ntemplate<typename T> bool BeginsWith(const T &str, const T &match) {\n    return str.size() >= match.size() && equal(match.begin(), match.end(), str.begin());\n}\nCOMMON_API bool BeginsWith(const std::string &str, const std::string &match);\nCOMMON_API bool Contains(const std::string &toSearch, const std::string &query);\nCOMMON_API bool ContainsIgnoreCase(const std::string &toSearch, const std::string &query);\nCOMMON_API bool EndsWith(const std::string &str, const std::string &match);\nCOMMON_API std::string ToLower(std::string str);\nCOMMON_API std::vector<std::string> Split(std::string str, const std::string &delimeter);\nCOMMON_API std::string Join(const std::vector<std::string> &parts, const std::string &delimeter);\nCOMMON_API std::string ReplaceAll(std::string source, const std::string &oldSegment, const std::string &newSegment);\nCOMMON_API std::string GetCurrentDateTimestamp();\n\ntemplate<typename T>\nvector<T> SyncToRemove(const vector<T> &truth, const vector<T> &cache)\n{\n    vector<T> toRemove;\n    for (const auto &x : cache)\n        if (!STLUtils::Contains(truth, x))\n            toRemove.push_back(x);\n    return toRemove;\n}\n\ntemplate<typename T>\nvector<T> SyncToAdd(const vector<T> &truth, const vector<T> &cache)\n{\n    vector<T> toAdd;\n    for (const auto &x : truth)\n        if (!STLUtils::Contains(cache, x))\n            toAdd.push_back(x);\n    return toAdd;\n}\n\n}    // namespace STLUtils\n"
  },
  {
    "path": "include/vapor/SetHDF5PluginPath.h",
    "content": "#pragma once\n\n#include <stdlib.h>\n#include \"vapor/MyBase.h\"\n#include \"vapor/ResourcePath.h\"\n\nnamespace VAPoR {\nvoid SetHDF5PluginPath() {\n    char *existing = getenv(\"HDF5_PLUGIN_PATH\");\n    if (existing) {\n        printf(\"Using custom HDF5_PLUGIN_PATH: '%s'\\n\", existing);\n        return;\n    }\n\n    int rc=0;\n    std::string plugins = \"HDF5_PLUGIN_PATH=\" + Wasp::GetSharePath(\"plugins\");\n    #ifdef WIN32\n        rc=_putenv(plugins.c_str());\n    #else\n        rc = setenv(\"HDF5_PLUGIN_PATH\", Wasp::GetSharePath(\"plugins\").c_str(), 1);\n    #endif\n\n    if (rc != 0) Wasp::MyBase::SetErrMsg(\"Unable to set environtment variable s\", plugins.c_str());\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/SettingsParams.h",
    "content": "//************************************************************************\n//         *\n//       Copyright (C)  2015    *\n//     University Corporation for Atmospheric Research   *\n//       All Rights Reserved    *\n//         *\n//************************************************************************/\n//\n// File:  SettingsParams.h\n//\n// Authors:\n//   Scott Pearse\n//   Alan Norton\n//   National Center for Atmospheric Research\n//   PO 3000, Boulder, Colorado\n//\n// Date:  February 2018\n//\n// Description: Defines the SettingsParams class.\n//  This class supports parameters associted with the\n//  Settings panel, describing the settings settings of the app.\n//\n#ifndef SETTINGSPARAMS_H\n#define SETTINGSPARAMS_H\n\n#include <vector>\n#include <vapor/ParamsBase.h>\n\n//! \\class SettingsParams\n//! \\ingroup Public_Params\n//! \\brief A class for describing settings at settings.\n//! \\authors Scott Pearse, Alan Norton\n//! \\version 3.0\n//! \\date    February 2018\n\n//! The SettingsParams class controls various features set when the application starts.\n//! There is only a global SettingsParams, that\n//! is used throughout the application\n//!\nclass PARAMS_API SettingsParams : public VAPoR::ParamsBase {\npublic:\n    SettingsParams(VAPoR::ParamsBase::StateSave *ssave, bool loadFromFile = true);\n    SettingsParams(VAPoR::ParamsBase::StateSave *ssave, VAPoR::XmlNode *node);\n    SettingsParams(const SettingsParams &rhs);\n    SettingsParams &operator=(const SettingsParams &rhs);\n\n    void Init();\n\n    ~SettingsParams();\n\n    int  GetNumThreads() const;\n    void SetNumThreads(int num);\n\n    long GetCacheMB() const;\n    void SetCacheMB(long val);\n\n    long GetTextureSize() const;\n    void SetTextureSize(long val);\n    void SetTexSizeEnable(bool val);\n    bool GetTexSizeEnable() const;\n\n    bool GetAutoStretchEnabled() const;\n    void SetAutoStretchEnabled(bool val);\n\n    int  GetJpegQuality() const;\n    void SetJpegQuality(int quality);\n\n    bool GetSessionAutoSaveEnabled() const;\n    void SetSessionAutoSaveEnabled(bool enabled);\n\n    int  GetChangesPerAutoSave() const;\n    void SetChangesPerAutoSave(int changes);\n\n    string GetAutoSaveSessionFile() const;\n    void   SetAutoSaveSessionFile(string file);\n    void   SetDefaultAutoSaveFile(string file);\n\n    string GetSessionDir() const;\n    void   SetSessionDir(string name);\n    string GetDefaultSessionDir() const;\n    void   SetDefaultSessionDir(string dir);\n\n    string GetMetadataDir() const;\n    void   SetMetadataDir(string dir);\n    string GetDefaultMetadataDir() const;\n    void   SetDefaultMetadataDir(string dir);\n\n    string GetTFDir() const;\n    void   SetTFDir(string dir);\n    string GetDefaultTFDir() const;\n    void   SetDefaultTFDir(string dir);\n\n    string GetFlowDir() const;\n    void   SetFlowDir(string dir);\n    string GetDefaultFlowDir() const;\n    void   SetDefaultFlowDir(string dir);\n\n    string GetPythonDir() const;\n    void   SetPythonDir(string dir);\n    string GetDefaultPythonDir() const;\n    void   SetDefaultPythonDir(string dir);\n\n    int  GetFontSize() const;\n    void SetFontSize(int size);\n\n    string GetFontFile() const;\n    void   SetFontFile(string file);\n\n    bool GetDontShowIntelDriverWarning() const;\n    void SetDontShowIntelDriverWarning(bool b);\n\n    string GetCurrentPrefsPath() const;\n    void   SetCurrentPrefsPath(string pth);\n\n    void              Reinit();\n    const std::string getShortName() { return _shortName; }\n\n    void SetFidelityDefault3D(long lodDef, long refDef);\n    void SetFidelityDefault2D(long lodDef, long refDef);\n\n    static string GetClassType() { return (_classType); }\n\n    int SaveSettings() const;\n\n    static const string _sessionAutoSaveEnabledTag;\n\n    std::string GetSettingsPath() const;\n\n    void SetAutoCheckForUpdates(bool b);\n    bool GetAutoCheckForUpdates() const;\n    void SetAutoCheckForNotices(bool b);\n    bool GetAutoCheckForNotices() const;\n    void SetCasperCheckForVGL(bool b);\n    bool GetCasperCheckForVGL() const;\n\n    static const string UseAllCoresTag;\n    static const string AutoCheckForUpdatesTag;\n    static const string AutoCheckForNoticesTag;\n    static const string CasperVGLCheck;\n\n    bool LoadFromSettingsFile();\n    void FindDefaultSettingsPath();\n\nprivate:\n    static const string _classType;\n    static const string _shortName;\n    static const string _numThreadsTag;\n    static const string _cacheMBTag;\n    static const string _texSizeTag;\n    static const string _texSizeEnableTag;\n    static const string _currentPrefsPathTag;\n    static const string _sessionDirTag;\n    static const string _defaultSessionDirTag;\n    static const string _metadataDirTag;\n    static const string _defaultMetadataDirTag;\n    static const string _tfDirTag;\n    static const string _defaultTfDirTag;\n    static const string _flowDirTag;\n    static const string _defaultFlowDirTag;\n    static const string _pythonDirTag;\n    static const string _defaultPythonDirTag;\n    static const string _fidelityDefault2DTag;\n    static const string _fidelityDefault3DTag;\n    static const string _autoStretchTag;\n    static const string _jpegQualityTag;\n    static const string _changesPerAutoSaveTag;\n    static const string _autoSaveFileLocationTag;\n    static const string _defaultAutoSaveFileTag;\n    static const string _fontFileTag;\n    static const string _fontSizeTag;\n    static const string _dontShowIntelDriverWarningTag;\n    static const string _settingsNeedsWriteTag;\n\n    void _swapTildeWithHome(std::string &file) const;\n\n    string _settingsPath;\n};\n\n#endif    // SETTINGS_H\n"
  },
  {
    "path": "include/vapor/Shader.h",
    "content": "#pragma once\n\n#include <vapor/MyBase.h>\n#include <string>\n\nnamespace VAPoR {\n\n//! \\class Shader\n//! \\ingroup Public_Render\n//!\n//! \\brief Provides a C++ interface to the OpenGL shader construct\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date    August, 2018\n\nclass RENDER_API Shader : public Wasp::MyBase {\n    unsigned int _id;\n    int          _successStatus;\n    bool         _compiled;\n    unsigned int _type;\n    std::string  _name;\n\npublic:\n    //! Allocate a new C++ shader and specify the type. An OpenGL shader\n    //! is not allocated until it is compiled\n    //!\n    //! \\param[in] type OpenGL shader type enum\n    //!\n    Shader(unsigned int type);\n    ~Shader();\n\n    //! \\param[in] source GLSL source code\n    //!\n    //! \\retval 1 is returned on success\n    //! \\retval -1 is returned on failure\n    //!\n    int CompileFromSource(const std::string &source);\n\n    //! Calls glGetShaderInfoLog\n    std::string GetLog() const;\n\n    unsigned int GetID() const;\n    unsigned int GetType() const;\n    bool         WasCompilationSuccessful() const;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/ShaderManager.h",
    "content": "#pragma once\n\n#include \"vapor/IResourceManager.h\"\n#include \"vapor/ShaderProgram.h\"\n#include <string>\n#include <vector>\n\nnamespace VAPoR {\n\n//! \\class ShaderManager\n//! \\ingroup Public_Render\n//!\n//! \\brief Resource management class for shaders\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date    August, 2018\n\nclass RENDER_API ShaderManager : public IResourceManager<std::string, ShaderProgram> {\n    std::map<std::string, std::map<string, long>> _dependencyModifiedTimes;\n\n    std::vector<std::string>        _getSourceFilePaths(const std::string &name) const;\n    bool                            _wasFileModified(const std::string &path) const;\n    static std::string              _getNameFromKey(const std::string &key);\n    static std::vector<std::string> _getDefinesFromKey(const std::string &key);\n\npublic:\n    ShaderProgram *    GetShader(const std::string &name);\n    SmartShaderProgram GetSmartShader(const std::string &name);\n    int                LoadResourceByKey(const std::string &key);\n\n    //! \\param[in] path to GLSL source code file\n    //!\n    //! \\retval Shader* is returned on success\n    //! \\retval nullptr is returned on failure\n    //!\n    static Shader *CompileNewShaderFromFile(const std::string &path, const std::vector<std::string> &defines = {});\n\n    //! Returns an OpenGL shader type enum based on the file extension.\n    //! Valid extensions are .vert, .frag, and .geom\n    //!\n    //! \\param[in] path to GLSL source code file\n    //!\n    static unsigned int GetShaderTypeFromPath(const std::string &path);\n\n    //! Implements the following preprocessor directives:\n    //! - #pragma auto_version\n    //!   This sets the GLSL version to the highest available\n    //!\n    //! - #include FileName.glsl\n    //!   c-style include without quotes. Path is relative to shader base path\n    //!   This will also update line numbers with the #line directive\n    //!\n    //! - #define X\n    //!   Each item in the defines list is added to the GLSL code after the #version directive\n    //!\n    //! \\param[in] path to GLSL source code file\n    //! \\param[in] defines list of definitions to be added to source\n    //!\n    static std::string              PreProcessShader(const std::string &path, const std::vector<std::string> &defines = {});\n    static std::vector<std::string> GetShaderDependencies(const std::string &path);\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/ShaderProgram.h",
    "content": "#pragma once\n\n#include <vector>\n#include <string>\n#include <map>\n#include <glm/fwd.hpp>\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\n\n//! \\class ShaderProgram\n//! \\ingroup Public_Render\n//!\n//! \\brief Provides a C++ interface to the OpenGL shader program construct\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date August, 2018\n//!\n//! Automatically manages sampler uniforms and the active gl texture.\n//! This allows samplers to be set simply like uniforms.\n\nclass Shader;\nclass Texture;\n\nclass RENDER_API ShaderProgram : public Wasp::MyBase {\n    unsigned int               _id;\n    std::vector<Shader *>      _shaders;\n    bool                       _linked;\n    int                        _successStatus;\n    std::map<std::string, int> _samplerLocations;\n\npublic:\n    enum class Policy { Strict, Relaxed };\n    static Policy UniformNotFoundPolicy;\n\n    ShaderProgram();\n    ~ShaderProgram();\n\n    //! \\retval 1 is returned on success\n    //! \\retval -1 is returned on failure\n    //!\n    int         Link();\n    void        Bind();\n    bool        IsBound() const;\n    static void UnBind();\n    static int  GetBoundProgramID();\n\n    void AddShader(Shader *s);\n\n    //! \\param[in] type OpenGL shader type enum\n    //! \\param[in] source GLSL source code\n    //!\n    //! \\retval 1 is returned on success\n    //! \\retval -1 is returned on failure\n    //!\n    int AddShaderFromSource(unsigned int type, const char *source);\n\n    unsigned int GetID() const;\n    unsigned int WasLinkingSuccessful() const;\n\n    int  GetAttributeLocation(const std::string &name) const;\n    int  GetUniformLocation(const std::string &name) const;\n    bool HasUniform(const std::string &name) const;\n    void ComputeSamplerLocations();\n\n    template<typename T> bool SetUniform(const std::string &name, const T &value) const;\n    void                      SetUniform(int location, const int &value) const;\n    void                      SetUniform(int location, const float &value) const;\n    void                      SetUniform(int location, const glm::vec2 &value) const;\n    void                      SetUniform(int location, const glm::vec3 &value) const;\n    void                      SetUniform(int location, const glm::vec4 &value) const;\n    void                      SetUniform(int location, const glm::mat4 &value) const;\n    void                      SetUniform(int location, const glm::ivec2 &value) const;\n    void                      SetUniform(int location, const glm::ivec3 &value) const;\n    void                      SetUniform(int location, const std::vector<float> &value) const;\n\n    template<typename T> void SetUniformArray(const std::string &name, int count, const T *values) const;\n    void                      SetUniformArray(int location, int count, const int *values) const;\n    void                      SetUniformArray(int location, int count, const float *values) const;\n    void                      SetUniformArray(int location, int count, const glm::vec3 *values) const;\n    void                      SetUniformArray(int location, int count, const glm::vec4 *values) const;\n\n    //! This function behaves just like setting a uniform\n    //!\n    //! \\param[in] name uniform name\n    //! \\param[in] value an instance of VAPoR::Texture\n    //!\n    //! \\retval false if uniform name is not found\n    //!\n    template<typename T> bool SetSampler(const std::string &name, const T &texture) const;\n\n    std::string        GetLog() const;\n    void               PrintUniforms() const;\n    static const char *GLTypeToString(const unsigned int type);\n    static bool        IsGLTypeSampler(const unsigned int type);\n};\n\n//! \\class SmartShaderProgram\n//! \\ingroup Public_Render\n//!\n//! \\brief Provides a C++ interface to the OpenGL shader program construct\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date August, 2018\n//!\n//! This class causes shaders to automatically bind when requested from the ShaderManager.\n//! Once the object becomes out of scope, the shader is unbound.\n//! Since this class is intended to be used as an object, not a pointer, IsValid replaces\n//! the usual NULL check\n\nclass SmartShaderProgram {\n    ShaderProgram *_program;\n\npublic:\n    SmartShaderProgram(ShaderProgram *program);\n    ~SmartShaderProgram();\n    ShaderProgram *operator->() { return _program; }\n    bool           IsValid() const;\n    friend class ShaderManager;\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/SignificanceMap.h",
    "content": "//\n// $Id: SignificanceMap.h,v 1.5 2012/02/28 18:15:58 ypolius Exp $\n//\n\n#ifndef _SignificanceMap_h_\n#define _SignificanceMap_h_\n\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <vapor/MyBase.h>\n#include <algorithm>\n\n// using namespace std;\n\n//#include \"MyBase.h\"\n\n#ifndef BITSPERBYTE\n    #define BITSPERBYTE 8\n#endif\n\nnamespace VAPoR {\n\n//\n//! \\class SignificanceMap\n//! \\brief Implements a significance map\n//! \\author John Clyne\n//! \\version $Revision: 1.5 $\n//! \\date    $Date: 2012/02/28 18:15:58 $\n//!\n//! This class implements a quick and dirty significance map - a mapping\n//! indicating which entries in an array are valid and which are not.\n//!\n\nclass WASP_API SignificanceMap : public Wasp::MyBase {\npublic:\n    SignificanceMap();\n\n    //!\n    //! Significance map constructors for 1D, 2D, 3D, and 4D maps\n    //!\n    //! \\param[in] nx Dimension of X axis (fastest varying)\n    //! \\param[in] ny Dimension of Y axis (second fastest varying)\n    //! \\param[in] nz Dimension of Z axis (third fastest varying)\n    //! \\param[in] nt Dimension of Z axis (fourth fastest varying)\n    //! \\param[in] dims A vector specifying the number of dimensions and their\n    //! lengths.\n    //!\n    SignificanceMap(size_t nx, size_t ny = 1, size_t nz = 1, size_t nt = 1);\n    SignificanceMap(std::vector<size_t> dims);\n\n    //\n    //! Significance map constructors for 1D, 2D, 3D, and 4D maps, using\n    //! a previously created map. I.e. a map returned from GetMap()\n    //!\n    //! \\param[in] map An encoded significance map returned by GetMap()\n    //! \\param[in] nx Dimension of X axis (fastest varying)\n    //! \\param[in] ny Dimension of Y axis (second fastest varying)\n    //! \\param[in] nz Dimension of Z axis (third fastest varying)\n    //! \\param[in] nt Dimension of Z axis (fourth fastest varying)\n    //! \\param[in] dims A vector specifying the number of dimensions and their\n    //! lengths.\n    //\n    SignificanceMap(const unsigned char *map, size_t nx, size_t ny = 1, size_t nz = 1, size_t nt = 1);\n    SignificanceMap(const unsigned char *map, std::vector<size_t> dims);\n\n    //! Significance map copy constructor\n    //!\n    SignificanceMap(const SignificanceMap &);\n\n    ~SignificanceMap();\n\n    //! Set the shape (dimension) of a significance map\n    //!\n    //! This method changes the shape (dimension) of a significance map\n    //!\n    //! \\param[in] nx Dimension of X axis (fastest varying)\n    //! \\param[in] ny Dimension of Y axis (second fastest varying)\n    //! \\param[in] nz Dimension of Z axis (third fastest varying)\n    //! \\param[in] nt Dimension of Z axis (fourth fastest varying)\n    //! \\param[in] dims A vector specifying the number of dimensions and their\n    //! lengths.\n    int Reshape(std::vector<size_t> dims);\n    int Reshape(size_t nx, size_t ny = 1, size_t nz = 1, size_t nt = 1);\n\n    //! Return the shape of a significance map\n    //!\n    void GetShape(std::vector<size_t> &dims) const { dims = _dimsVec; };\n\n    //! Mark a map entry as significant.\n    //!\n    //! This method marks a particular coordinate as significant.\n    //! The coordinate parameters, \\p x, \\p y, \\p z, and \\p t, must lie within the\n    //! range [0..n-1], where n-1 is the value passed as the coordinates\n    //! dimension to the constructor. No attempt is to prevent duplicate\n    //! entries. If a coordinate is not specified its default value is zero.\n    //!\n    //! \\param[in] x X coordinate\n    //! \\param[in] y Y coordinate\n    //! \\param[in] z Z coordinate\n    //! \\param[in] t T coordinate\n    //! \\param[in] idx coordinate specified as an offset from a linear array\n    //!\n    //! \\retval status a negative value is returned on failure\n    //!\n    int Set(size_t idx);\n    int SetXYZT(size_t x, size_t y = 0, size_t z = 0, size_t t = 0);\n\n    //! Return true if the indicated entry is significant. Test() returns\n    //! false if the entry is out of range or in range, but not set\n    //!\n    //! \\param[in] x X coordinate\n    //! \\param[in] y Y coordinate\n    //! \\param[in] z Z coordinate\n    //! \\param[in] t T coordinate\n    //! \\param[in] idx coordinate specified as an offset from a linear array\n    //!\n    bool inline Test(size_t idx) const;\n    bool inline TestXYZT(size_t x, size_t y = 0, size_t z = 0, size_t t = 0) const;\n\n    //! Mark the indicated entry as insignificant\n    //!\n    //! This method clears the indicated entry (marks it as insignificant)\n    //!\n    //! \\retval status a negative value is returned on failure\n    //!\n    int Clear(size_t idx);\n    int ClearXYZT(size_t x, size_t y = 0, size_t z = 0, size_t t = 0);\n\n    //! Clear entire map\n    //!\n    void Clear();\n\n    //! Return the number of significant entries in the map\n    //!\n    size_t GetNumSignificant() const { return (_sigMapVec.size()); };\n\n    //! Return coordinates for an ordered entry in the map\n    //!\n    //! Return the coordinates of the ith significant entry in the\n    //! significant map. Note, the mapping between an entry number and\n    //! it's coordinates returned by this function are no longer valid after\n    //! the map is modified (set, cleared, or sorted). If the coordinate pointers,\n    //! x,y,z,t are null, no value is returned for that coordinate.\n    //!\n    //! Valid values for 'i' are in the range [0..GetNumSignificant()-1]\n    //! \\retval status a negative value is returned on failure\n    //!\n    //\n    int GetCoordinatesXYZT(size_t i, size_t *x, size_t *y = NULL, size_t *z = NULL, size_t *t = NULL) const;\n    int GetCoordinates(size_t i, size_t *idx) const;\n\n    //! Restart counters for GetNextEntry()\n    //!\n    //! This method is used to restore internal counters used by the\n    //! GetNextEntry() method\n    //!\n    //! \\sa GetMextEntry()\n    //\n    void GetNextEntryRestart();\n\n    //\n    //! Return the coordinates for the next signficant entry in the\n    //! significance map. This method may be called iteratively until\n    //! all map entries are turned. The GetNextEntryRestart() method may be used\n    //! to reset the current entry to the first one in the map. A zero\n    //! value is returned if the entry list is exhausted. The coordinates\n    //! are returned in the order that they were set with Set() or SetXYZT().\n    //!\n    //! \\note For sequential processing of map entries it is preferable to\n    //! use this method over the indexed GetEntry() method.\n    //!\n    //! \\retval status a negative value is returned on failure\n    //!\n    //\n    int GetNextEntry(size_t *idx);\n    int GetNextEntryXYZT(size_t *x, size_t *y, size_t *z, size_t *t);\n\n    //! Return size in bytes of an encoded signficance map of given size\n    //!\n    //! This static member method returns the size in bytes of an encoded\n    //! signficance map that would be returned by GetMap() for a\n    //! SignificanceMap of given dimension, \\p dims, and number of\n    //! entries, \\p num_entries.\n    //\n    static size_t GetMapSize(vector<size_t> dims, size_t num_entries);\n\n    //! Return size in bytes of an encoded signficance map of given size\n    //!\n    //! This method returns the size in bytes of an encoded\n    //! signficance map that would be returned by GetMap() after\n    //! the given number of entries, \\p num_entries, were stored.\n    //! This method can be used to determine the amount of space\n    //! required to store an encoded signficance map after\n    //! \\p num_entries entries have been stored in it. In general,\n    //! this is not the same value for the current significance map.\n    //!\n    //! \\param num_entries[in] Number of entries in the signficance map\n    //!\n    //! \\sa GetMap()\n    //\n    size_t GetMapSize(size_t num_entries) const;\n\n    //! Return size in bytes of current encoded signficance map\n    //!\n    //! This method returns the size in bytes of the encoded,\n    //! current signficance map that would be returned by GetMap().\n    //!\n    //! \\sa GetMap()\n    //\n    size_t GetMapSize() const { return (GetMapSize(GetNumSignificant())); };\n\n    //! Return the compressed representation of the significance map. The data\n    //! returned are only suitable passing as an argument to the constructor.\n    //!\n    //! \\param map[out] Encoded significance map data\n    //! \\param maplen[out] Length of \\p map in bytes\n    //\n    void GetMap(const unsigned char **map, size_t *maplen);\n\n    //! Return the compressed representation of the significance map. The data\n    //! returned are only suitable passing as an argument to the constructor.\n    //!\n    //! \\param map[out] Encoded significance map data. Caller is\n    //! responsible for allocating memory. The array \\p map must be of\n    //! size GetMapSize().\n    //\n    void GetMap(unsigned char *map);\n\n    //\n    //! Reinitialize the significance map with the map, \\p map , returned from a\n    //! previous call to GetMap.\n    //!\n    //! \\param[in] map An encoded significance map returned by GetMap()\n    //!\n    //! \\sa GetMap()\n    //!\n    //! \\retval status a negative value is returned on failure\n    //!\n    //\n    int SetMap(const unsigned char *map);\n\n    //! Append a SignificanceMap\n    //!\n    //! This method appends the coordinates in the map, \\p smap, to\n    //! this map, creating a new signficance map containing the entries\n    //! from both this signficance map and \\p smap. The ordering of the new map\n    //! is as if the GetNextEntry() method of \\p smap was called\n    //! iteratively, storing the the returned coordinate with Set().\n    //!\n    //! The dimensions of \\p smap must match those of this map or error\n    //! condition is returned.\n    //!\n    //! \\param[in] smap An encoded significance map returned by GetMap()\n    //!\n    //! \\retval status a negative value is returned on failure\n    //!\n    //\n    int Append(const SignificanceMap &smap);\n\n    //! Invert the signficance map\n    //!\n    //! This method inverts the signficance map, making insignficant\n    //! coordinates (those not found in the significance map) into significant\n    //! coordinates. The ordering of the newly created map will be from\n    //! smallest to largest coordinate.\n    //!\n    //! \\sa GetNextEntry()\n    //\n    void Invert();\n\n    //! Sort map entries\n    //!\n    //! This method sorts the entries of the significance maps so that\n    //! they are stored from smallest to largest. Once sorted, map entries\n    //! returned by GetNextEntry() are guaranteed to be returned from\n    //! smallest to largest\n    //!\n    //! \\sa GetNextEntry()\n    //\n    void Sort();\n\n    SignificanceMap &operator=(const SignificanceMap &map);\n\n    friend std::ostream &operator<<(std::ostream &o, const SignificanceMap &sigmap);\n\nprivate:\n    static const int HEADER_SIZE = 64;\n    static const int VDF_VERSION = 2;\n    size_t           _nx;\n    size_t           _ny;\n    size_t           _nz;\n    size_t           _nt;    // dimensions of map (when # dims < 5)\n\n    bool _sorted;    // true if the map is sorted in ascending order\n\n    std::vector<size_t> _dimsVec;       // Map dimensions\n    size_t              _sigMapSize;    // product of dimensions (max coordinate index)\n    std::vector<size_t> _sigMapVec;     // The signficance map\n\n    int            _bits_per_idx;        // # bits needed to encode a coordinate\n    unsigned char *_sigMapEncode;        // compactly encoded version of _sigMapVec\n    size_t         _sigMapEncodeSize;    // size of _sigMapEncode in bytes\n\n    size_t _idxentry;    // Counter for sequential access to sig. map\n\n    int _SignificanceMap(std::vector<size_t> dims);\n    int _SignificanceMap(const unsigned char *map, std::vector<size_t> dims);\n\n    static size_t _GetBitsPerIdx(vector<size_t> dims);\n};\n\nbool inline SignificanceMap::Test(size_t idx) const\n{\n    if (idx > _sigMapSize) return (0);    // Invalid coordinate\n\n    if (_sorted) { return (binary_search(_sigMapVec.begin(), _sigMapVec.end(), idx)); }\n\n    for (size_t i = 0; i < _sigMapVec.size(); i++) {\n        if (_sigMapVec[i] == idx) return (1);\n    }\n    return (0);\n}\n\nbool inline SignificanceMap::TestXYZT(size_t x, size_t y, size_t z, size_t t) const\n{\n    size_t idx = (t * _nz * _ny * _nx) + (z * _ny * _nx) + (y * _nx) + x;\n\n    return (this->Test(idx));\n}\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/SliceParams.h",
    "content": "\n#ifndef SLICEPARAMS_H\n#define SLICEPARAMS_H\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\n//! \\class SliceParams\n//! \\brief Class that supports drawing Barbs based on 2D or 3D vector field\n//! \\version 3.0\nclass PARAMS_API SliceParams : public RenderParams {\npublic:\n    SliceParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n\n    SliceParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~SliceParams();\n\n    virtual int Initialize() override;\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"SliceParams\"); }\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return (3); }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override\n    {\n        if (UseSingleColor())\n            return \"\";\n        else\n            return GetVariableName();\n    }\n\n    void                SetCachedValues(std::vector<double> values);\n    std::vector<double> GetCachedValues() const;\n    bool                GetOrientable() const override;\n\nprivate:\n    bool _initialized = false;\n\n    void                _init();\n    std::vector<double> _cachedValues;\n\n};    // End of Class SliceParams\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/SliceRenderer.h",
    "content": "#ifndef SLICERENDERER_H\n#define SLICERENDERER_H\n\n#include <vapor/glutil.h>\n\n#include <glm/glm.hpp>\n#include <vapor/DataMgr.h>\n#include <vapor/utils.h>\n#include <vapor/Renderer.h>\n\n//#define DEBUG 1\n\nnamespace VAPoR {\n\n\nclass RENDER_API SliceRenderer : public Renderer {\npublic:\n    SliceRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    static string GetClassType() { return (\"Slice\"); }\n\n    virtual ~SliceRenderer();\n\nprotected:\n    virtual int _initializeGL();\n    virtual int _paintGL(bool fast);\n\nprivate:\n    struct {\n        string              varName;\n        string              heightVarName;\n        size_t              ts;\n        int                 refinementLevel;\n        int                 compressionLevel;\n        int                 textureSampleRate;\n        int                 orientation;\n        double              xRotation;\n        double              yRotation;\n        double              zRotation;\n        double              xOrigin;\n        double              yOrigin;\n        double              zOrigin;\n        std::vector<float>  tf_lut;\n        std::vector<double> tf_minMax;\n        VAPoR::CoordType    boxMin, boxMax;\n        VAPoR::CoordType    domainMin, domainMax;\n        std::vector<double> sampleLocation;\n        std::vector<double> sliceRotation;\n        std::vector<double> sliceNormal;\n        double              sliceOffset;\n        int                 sliceOrientationMode;\n    } _cacheParams;\n\n    void _initVAO();\n    void _initTexCoordVBO();\n    void _initVertexVBO();\n\n    bool _isColormapCacheDirty() const;\n    bool _isDataCacheDirty() const;\n    bool _isBoxCacheDirty() const;\n    void _getExtents(VAPoR::CoordType &min, VAPoR::CoordType &max) const;\n    void _resetColormapCache();\n    void _resetCache();\n    void _createDataTexture(std::unique_ptr<float> &dataValues);\n    int  _regenerateSlice();\n    int  _getGrid3D(Grid *&grid) const;\n#ifdef DEBUG\n    void _drawDebugPolygons();\n#endif\n\n    void _configureShader();\n    void _resetState();\n    void _initializeState();\n\n    bool   _initialized;\n    size_t _textureSideSize;\n\n    GLuint _colorMapTextureID;\n    GLuint _dataValueTextureID;\n\n    std::vector<double> _windingOrder;\n    std::vector<double> _rectangle3D;\n\n    GLuint _VAO;\n    GLuint _vertexVBO;\n    GLuint _texCoordVBO;\n\n    int _colorMapSize;\n\n    void _clearCache() { _cacheParams.varName.clear(); }\n};\n\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/SphericalGrid.h",
    "content": "#ifndef _SphericalGrid_\n#define _SphericalGrid_\n#include <vector>\n#include <vapor/common.h>\n#include \"RegularGrid.h\"\n#ifdef _WINDOWS\n    #pragma warning(disable : 4251 4100)\n#endif\n\nnamespace VAPoR {\n\n//! \\class SphericalGrid\n//!\n//! \\brief This class implements a 2D or 3D spherical grid.\n//!\n//! This class implements a 2D or 3D spherical grid: a generalization\n//! of a regular grid where the spacing of grid points along a single dimension\n//! may vary at each grid point. The spacing along the remaining one (2D case)\n//! or two (3D case) dimensions is invariant between grid points. For example,\n//! if K is the spherical dimension than the z coordinate is given by some\n//! function f(i,j,k):\n//!\n//! z = f(i,j,k)\n//!\n//! while the remaining x and y coordinates are givey by (i*dx, j*dy)\n//! for some real dx and dy .\n//!\n//\nclass VDF_API SphericalGrid : public RegularGrid {\npublic:\n    //!\n    //! Construct a spherical grid sampling a 3D or 2D scalar function\n    //!\n    //! \\param[in] bs A three-element vector specifying the dimensions of\n    //! each block storing the sampled scalar function.\n    //! \\param[in] min A three-element vector specifying the ijk index\n    //! of the first point in the grid. The first grid point need not coincide\n    //! with\n    //! block boundaries. I.e. the indecies need not be (0,0,0)\n    //! \\param[in] max A three-element vector specifying the ijk index\n    //! of the last point in the grid\n    //! \\param[in] extents A six-element vector specifying the user coordinates\n    //! of the first (first three elements) and last (last three elements) of\n    //! the grid points indicated by \\p min and \\p max, respectively.\n    //! The units are degrees, not radians.\n    //! \\param[in] permutation A three-element array indicating the ordering\n    //! of the Longitude, Latitude, and radial dimensions. The array must\n    //! contain some permutation of the set (0,1,2). The permuation (0,1,2)\n    //! indicates that longitude is the fastest varying dimesion, then latitude\n    //! then radius. The permutation (2,1,0) indicates that radius is fastest,\n    //! then latitude, and so on.\n    //! \\param[in] periodic A three-element boolean vector indicating\n    //! which i,j,k indecies, respectively, are periodic.\n    //! \\param[in] blks An array of blocks containing the sampled function.\n    //! The dimensions of each block\n    //! is given by \\p bs. The number of blocks is given by the product\n    //! of the terms:\n    //!\n    //! \\code (max[i]/bs[i] - min[i]/bs[i] + 1) \\endcode\n    //!\n    //! over i = 0..2.\n    //!\n    //! \\param[in] coords An array of blocks with dimension and number the\n    //! same as \\p blks specifying the varying dimension grid point coordinates.\n    //! \\param[in] varying_dim An enumerant indicating which axis is the\n    //! varying dimension: 0 for I, 1 for J, 2 for K\n    //!\n    SphericalGrid(const size_t bs[3], const size_t min[3], const size_t max[3], const double extents[6], const size_t permutation[3], const bool periodic[3], float **blks);\n\n    //!\n    //! Construct a spherical grid sampling a 3D or 2D scalar function\n    //! that contains missing values.\n    //!\n    //! This constructor adds a parameter, \\p missing_value, that specifies\n    //! the value of missing values in the sampled function. When\n    //! reconstructing the function at arbitrary coordinates special\n    //! consideration is given to grid points with missing values that\n    //! are used in the reconstruction.\n    //!\n    //! \\sa GetValue()\n    //!\n    SphericalGrid(const size_t bs[3], const size_t min[3], const size_t max[3], const double extents[6], const size_t permutation[3], const bool periodic[3], float **blks, float missing_value);\n\n    //! \\copydoc RegularGrid::GetValue()\n    //!\n    float GetValue(double x, double y, double z) const;\n\n    //! \\copydoc RegularGrid::GetUserExtents()\n    //!\n    //! Return extents in Cartesian coordinates\n    //\n    virtual void GetUserExtents(double extents[6]) const\n    {\n        for (int i = 0; i < 6; i++) extents[i] = _extentsC[i];\n    };\n\n    //! \\copydoc RegularGrid::GetVBoundingBox()\n    //!\n    virtual void GetBoundingBox(const size_t min[3], const size_t max[3], double extents[6]) const;\n\n    //! \\copydoc RegularGrid::GetUserCoordinates()\n    //!\n    int GetUserCoordinates(size_t i, size_t j, size_t k, double *x, double *y, double *z) const;\n\n    //! \\copydoc RegularGrid::GetIJKIndex()\n    //!\n    void GetIJKIndex(double x, double y, double z, size_t *i, size_t *j, size_t *k) const;\n\n    //! \\copydoc RegularGrid::GetIJKIndexFloor()\n    //!\n    void GetIJKIndexFloor(double x, double y, double z, size_t *i, size_t *j, size_t *k) const;\n\n    //! Return true if the specified point lies inside the grid\n    //!\n    //! This method can be used to determine if a point expressed in\n    //! user coordinates reside inside or outside the grid\n    //!\n    //! \\param[in] x coordinate along fastest varying dimension\n    //! \\param[in] y coordinate along second fastest varying dimension\n    //! \\param[in] z coordinate along third fastest varying dimension\n    //!\n    //! \\retval bool True if point is inside the grid\n    //!\n    bool InsideGrid(double x, double y, double z) const;\n\n    // phi is in range -180 to 180, theta is in range -180/2 to 180/2\n    //\n    static inline void CartToSph(double x, double y, double z, double *phi, double *theta, double *r);\n\n    static inline void SphToCart(double phi, double theta, double r, double *x, double *y, double *z);\n\nprivate:\n    double            _extentsC[6];    // extents in Cartesian coordinates, ordered x,y,z\n    std::vector<long> _permutation;    // permutation vector for coordinate ordering\n\n    void _GetUserExtents(double extents[6]) const;\n\n    void _permute(const std::vector<long> &permutation, double result[3], double x, double y, double z) const;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/StretchedGrid.h",
    "content": "#ifndef _StretchedGrid_\n#define _StretchedGrid_\n#include <vapor/common.h>\n#include <vapor/Grid.h>\n#include <vapor/StructuredGrid.h>\n\nnamespace VAPoR {\n//! \\class StretchedGrid\n//!\n//! \\brief This class implements a 2D or 3D stretched grid.\n//!\n//! This class implements a 2D or 3D stretched grid: a\n//! specialization of StructuredGrid class where cells are\n//! quadrilaterals (2D), or cuboids (3D). Hence, stretched grids are\n//! topologically, but the location of each grid point is expressed\n//! by functions:\n//!\n//! \\code\n//! x = X(i)\n//! y = Y(j)\n//! z = Z(k)\n//! \\endcode\n//!\n//!\n//\nclass VDF_API StretchedGrid : public StructuredGrid {\npublic:\n    //! \\copydoc StructuredGrid::StructuredGrid()\n    //!\n    //! Construct a regular grid sampling a 3D or 2D scalar function.\n    //!\n    //! This constructor instantiates a stretched grid  where the x,y,z\n    //! user coordinates are expressed as follows:\n    //!\n    //! \\code\n    //! x = X(i)\n    //! y = Y(j)\n    //! z = Z(k)\n    //! \\endcode\n    //!\n    //! The X, Y, and Z user coordinates are specified with \\p xcoords, \\p xcoords,\n    //! and \\p zcoords (if 3D), respectively.\n    //!\n    //! Adds new parameters:\n    //!\n    //! \\param[in] xcoords  A 1D vector whose size matches that of the I\n    //! dimension of this class, and whose values specify the X user coordinates.\n    //! \\param[in] ycoords  A 1D vector whose size matches that of the J\n    //! dimension of this class, and whose values specify the Y user coordinates.\n    //! \\param[in] zcoords  A 1D vector whose size matches that of the K\n    //! dimension of this class, and whose values specify the Z user coordinates.\n    //!\n    //! \\sa RegularGrid()\n    //\n    StretchedGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, const std::vector<double> &xcoords, const std::vector<double> &ycoords,\n                  const std::vector<double> &zcoords);\n    StretchedGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<float *> &blks, const std::vector<double> &xcoords, const std::vector<double> &ycoords,\n                  const std::vector<double> &zcoords);\n\n    StretchedGrid() = default;\n    virtual ~StretchedGrid() = default;\n\n    virtual size_t GetGeometryDim() const override;\n\n    virtual DimsType GetCoordDimensions(size_t dim) const override;\n\n    static std::string GetClassType() { return (\"Stretched\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    // \\copydoc GetGrid::GetBoundingBox()\n    //\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override;\n\n    // \\copydoc GetGrid::GetUserCoordinates()\n    //\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override;\n\n    //! \\copydoc Grid::GetIndicesCell\n    //!\n    //! Returns resampling weights if point is found\n    //\n    virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices, double wgts[3]) const;\n\n    //! \\copydoc Grid::GetIndicesCell\n    //!\n    virtual bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override\n    {\n        double dummy[3];\n        return (GetIndicesCell(coords, indices, dummy));\n    };\n\n    // \\copydoc GetGrid::InsideGrid()\n    //\n    virtual bool InsideGrid(const CoordType &coords) const override;\n\n    //! Returns reference to vector containing X user coordinates\n    //!\n    //! Returns reference to vector passed to constructor\n    //! containing X user coordinates\n    //!\n    const std::vector<double> &GetXCoords() const { return (_xcoords); };\n\n    //! Returns reference to vector containing Y user coordinates\n    //!\n    //! Returns reference to vector passed to constructor\n    //! containing Y user coordinates\n    //!\n    const std::vector<double> &GetYCoords() const { return (_ycoords); };\n\n    //! Returns reference to vector containing Z user coordinates\n    //!\n    //! Returns reference to vector passed to constructor\n    //! containing Z user coordinates\n    //!\n    const std::vector<double> &GetZCoords() const { return (_zcoords); };\n\n    class ConstCoordItrSG : public Grid::ConstCoordItrAbstract {\n    public:\n        ConstCoordItrSG(const StretchedGrid *cg, bool begin);\n        ConstCoordItrSG(const ConstCoordItrSG &rhs);\n\n        ConstCoordItrSG();\n        virtual ~ConstCoordItrSG() {}\n\n        virtual void            next();\n        virtual void            next(const long &offset);\n        virtual ConstCoordType &deref() const { return (_coords); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const\n        {\n            const ConstCoordItrSG *itrptr = static_cast<const ConstCoordItrSG *>(rhs);\n\n            return (_index == itrptr->_index);\n        }\n\n        virtual std::unique_ptr<ConstCoordItrAbstract> clone() const { return std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrSG(*this)); };\n\n    private:\n        const StretchedGrid *_sg;\n        DimsType             _index;\n        CoordType            _coords;\n    };\n\n    virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrSG(this, true))); }\n    virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrSG(this, false))); }\n\nprotected:\n    virtual float GetValueNearestNeighbor(const CoordType &coords) const override;\n\n    virtual float GetValueLinear(const CoordType &coords) const override;\n\n    void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override;\n\nprivate:\n    std::vector<double> _xcoords;\n    std::vector<double> _ycoords;\n    std::vector<double> _zcoords;\n    CoordType           _minu = {{0.0, 0.0, 0.0}};\n    CoordType           _maxu = {{0.0, 0.0, 0.0}};\n\n    void _stretchedGrid(const std::vector<double> &xcoords, const std::vector<double> &ycoords, const std::vector<double> &zcoords);\n\n    bool _insideGrid(double x, double y, double z, size_t &i, size_t &j, size_t &k, double &xwgt, double &ywgt, double &zwgt) const;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/StructuredGrid.h",
    "content": "#ifndef _StructuredGrid_\n#define _StructuredGrid_\n\n#include <ostream>\n#include <vector>\n#include <memory>\n#include <vapor/common.h>\n#include <vapor/Grid.h>\n\n#ifdef WIN32\n    #pragma warning(disable : 4661 4251)    // needed for template class\n#endif\n\nnamespace VAPoR {\n\n//! \\class StructuredGrid\n//! \\brief Abstract base class for a 2D or 3D structured grid.\n//! \\author John Clyne\n//!\n//! This abstract base class defines a 2D or 3D structured\n//! grid: a tessellation\n//! of Euculidean space by quadrilaterals (2D) or hexahdrons (3D). Each\n//! grid point can be addressed by an index(i,j,k), where \\a i, \\p j\n//! and \\a k range from 0 to \\a dim - 1, where \\a dim is the dimension of the\n//! \\a I, \\a J, or \\a K axis, respectively. Moreover, each grid point\n//! has a coordinate in a user-defined coordinate system.\n//!\n//! The structured grid samples a scalar function at each grid point. The\n//! scalar function samples are stored as an array decomposed into\n//! equal-sized blocks.\n//!\n//! Because grid samples are repesented internally as arrays, when accessing\n//! multiple grid points better performance is achieved by using\n//! unit stride. The \\a I axis varies fastest (has unit stride),\n//! followed by \\a J, then \\a K. Best performance is achieved\n//! when using the class iterator: Grid::Iterator.\n//!\n//! For methods that allow the specification of grid indecies or coordinates\n//! as a single parameter tuple (e.g. vector <double> coordinate) the\n//! first element\n//! of the tuple corresponds to the \\a I axis, etc.\n//!\n//! \\note Throughout this class grid vertex offsets are specified as\n//! \\a i, \\a j, \\a k, where \\a i, \\a j, \\a k are integers. User coordinates\n//! are real values denoted \\a x, \\a y, \\a z, and are given by functions\n//! \\a X(i,j,k), \\a Y(i,j,k), \\a Z(i,j,k).\n//\nclass VDF_API StructuredGrid : public Grid {\npublic:\n    //! Construct a structured grid sampling a 3D or 2D scalar function\n    //!\n    //! \\copydoc Grid()\n    //!\n    //! The sampled function is represented as a 2D or 3D array, decomposed\n    //! into smaller blocks (tiles in 2D). The dimensions of the array are not\n    //! constrained to coincide with block (tile) boundaries.\n    //!\n    //! The length of parameter vectors \\p bs, and \\p dim\n    //! must all be either 3 (3D structured grid) or 2 (2D structured grid)\n    //!\n    //! If \\p blks is empty a dataless StructuredGrid object is returned.\n    //! Data can not be retrieved from a dataless StructuredGrid. However,\n    //! coordinate access methods may still be invoked.\n    //!\n    StructuredGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<float *> &blks);\n    StructuredGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks);\n\n\n    StructuredGrid() = default;\n    virtual ~StructuredGrid() = default;\n\n    static std::string GetClassType() { return (\"Structured\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    const DimsType &GetNodeDimensions() const override;\n    const size_t   GetNumNodeDimensions() const override;\n\n    const DimsType &GetCellDimensions() const override { return (_cellDims); };\n    const size_t    GetNumCellDimensions() const override { return GetNumNodeDimensions(); }\n\n    //! \\copydoc Grid::GetCellNodes()\n    //!\n    virtual bool GetCellNodes(const DimsType &cindices, std::vector<DimsType> &nodes) const override;\n    // For grandparent inheritance of\n    // Grid::GetUserCoordinates(const size_t indices[], double coords[])\n    //\n    using Grid::GetCellNodes;\n\n    //! \\copydoc Grid::GetCellNeighbors()\n    //!\n    virtual bool GetCellNeighbors(const DimsType &cindices, std::vector<DimsType> &cells) const override;\n\n    //! \\copydoc Grid::GetNodeCells()\n    //!\n    virtual bool GetNodeCells(const DimsType &cindices, std::vector<DimsType> &cells) const override;\n\n    virtual bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override;\n\n    size_t GetMaxVertexPerFace() const override { return (4); };\n\n    size_t GetMaxVertexPerCell() const override { return ((GetTopologyDim() == 3) ? 8 : 4); };\n\n    virtual void ClampCoord(const CoordType &coords, CoordType &cCoords) const override;\n\n    //! \\deprecated\n    //\n    virtual void ClampCoord(const double coords[3], double cCoords[3]) const override { Grid::ClampCoord(coords, cCoords); }\n\n    //! \\copydoc Grid::HasInvertedCoordinateSystemHandiness()\n    //!\n    virtual bool HasInvertedCoordinateSystemHandiness() const override;\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const StructuredGrid &sg);\n\nprotected:\nprivate:\n    DimsType _cellDims;\n    void     _structuredGrid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks);\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/TFInterpolator.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2004\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tTFInterpolator.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tNovember 2004\n//\n//\tDescription:\tDefines the TFInterpolator class:\n//\t\tA class to interpolate transfer function values\n//\t\tCurrently only supports linear interpolation\n//\n#ifndef TFINTERPOLATOR_H\n#define TFINTERPOLATOR_H\n#include <iostream>\n#include <cmath>\n\n#include <vapor/common.h>\n\nnamespace VAPoR {\nclass PARAMS_API TFInterpolator {\npublic:\n    ~TFInterpolator();\n\n    // Default is linear\n    enum type {\n        linear,    // linearHSV\n        discrete,\n        logarithm,\n        exponential,\n        diverging,\n        linearRGB,\n        linearLAB,\n        linearLCH\n    };\n    // Determine the interpolated value at intermediate value 0<=r<=1\n    // where the value at left and right endpoint is known\n    // This method is just a stand-in until we get more sophistication\n    //\n    static float interpolate(type, float leftVal, float rightVal, float r);\n\n    // Linear interpolation for circular (hue) fcn.  values in [0,1).\n    // If it's closer to go around 1, then do so\n    //\n    static float interpCirc(type t, float leftVal, float rightVal, float r);\n\n    //! Generate the complete diverging color map using the Moreland\n    //! technique from RGB1 to RGB2, placing \"white\" in the middle.\n    //! The number of points given by the \"numColors\" variable\n    //! controls the resolution of the color map.\n    //!\n    //! \\param[in] RGB1 Start point color for diverging color map.\n    //! \\param[in] RGB2 End point color for diverging color map.\n    //! \\param[in] Number of colors to generate in the new color map.\n    //! \\retval Return status, 1 = success\n    static float *genDivergentMap(float rgb1[3], float rgb2[3], int numColors);\n\n    // private:\n\n    //! Interpolation algorithm to generate a single interpolated\n    //! color in a diverging color map.\n    //!\n    //! \\param[in] RGB1 Start point color for diverging color map\n    //! \\param[in] RGB2 End point color for diverging color map.\n    //! \\param[in] The output interpolated RGB value in the divergent map\n    //! \\param[in] The interpolation weight of the current color in the color map\n    //! \\param[in] Set whether we insert white space between two saturated color control points\n    //! \\retval Return status, 1 = success\n    static int divergentInterpolation(float rgb1[3], float rgb2[3], float output[3], float interp, bool corrective = false);\n\n    //! Interpolation algorithm that applies a corrective white space\n    //! between two saturated color control points\n    //!\n    //! \\param[in] RGB1 Start point color for diverging color map\n    //! \\param[in] RGB2 End point color for diverging color map.\n    //! \\param[in] The output interpolated RGB value in the divergent map\n    //! \\param[in] The interpolation weight of the current color in the color map\n    //! \\param[in] Set whether we insert white space between two saturated color control points\n    static void correctiveDivergentInterpolation(float rgb1[3], float rgb2[3], float output[3], float interp);\n\n    //! A function to provide an adjusted hue when interpolating\n    //! to an unsaturated color in Msh space\n    //! \\param[in] Input M value to adjust hue to\n    //! \\param[in] Input s value to adjust hue to\n    //! \\param[in] Input h value to adjust hue to\n    //! \\param[in] Second input M value to adjust hue to\n    //! \\param[out] Adjusted hue value\n    static float adjustHue(float m1, float s1, float h1, float m2);\n\n    //! Conversion of Msh to RGB\n    //! \\param[in] A 3-tuple color in Msg space\n    //! \\param[in] The resultant 3-tuple color in rgb space\n    //! \\retval Return status, 1 = success\n    static int msh2srgb(float msh[3], float rgb[3]);\n\n    //! Conversion of Msh to Lab\n    //! \\param[in] A 3-tuple color in Msh space\n    //! \\param[in] The resultant 3-tuple color in Lab space\n    //! \\retval Return status, 1 = success\n    static int msh2lab(float msh[3], float lab[3]);\n\n    //! Conversion of Lab to RGB\n    //! \\param[in] A 3-tuple color in Lab space\n    //! \\param[in] The resultant 3-tuple color in rgb space\n    //! \\retval Return status, 1 = success\n    static int lab2srgb(float lab[3], float rgb[3]);\n\n    //! Conversion from RGB to Msh\n    //! \\param[in] A 3-tuple color in rgb space\n    //! \\param[in] The resultant 3-tuple color in Msh space\n    //! \\retval Return status, 1 = success\n    static int srgb2msh(float rgb[3], float msh[3]);\n\n    //! Conversion from RGB to Lab\n    //! \\param[in] A 3-tuple color in rgb space\n    //! \\param[in] The resultant 3-tuple color in Lab space\n    //! \\retval Return status, 1 = success\n    static int srgb2lab(float rgb[3], float lab[3]);\n\n    //! Conversion from Lab to Msh\n    //! \\param[in] A 3-tuple color in rgb space\n    //! \\param[in] The resultant 3-tuple color in Msh space\n    //! \\retval Return status, 1 = success\n    static int lab2msh(float lab[3], float msh[3]);\n\n    //! Conversion from Lab to Msh\n    //! \\param[in] A 3-tuple color in rgb space\n    //! \\param[in] The resultant 3-tuple color in xyz space\n    //! \\retval Return status, 1 = success\n    static int srgb2xyz(float rgb[3], float xyz[3]);\n\n    //! Conversion from xyz to rgb\n    //! \\param[in] A 3-tuple color in xyz space\n    //! \\param[in] The resultant 3-tuple color in rgb space\n    //! \\retval Return status, 1 = success\n    static int xyz2srgb(float xyz[3], float rgb[3]);\n\n    //! Convert an RGB tuple to sRGB\n    //! \\param[in] A 3-tuple color in rgb space\n    //! \\param[in] The resultant 3-tuple color in sRGB space\n    //! \\retval Return status, 1 = success\n    static int rgb2srgb(float rgb[3], float srgb[3]);\n\n    //! Convert an sRGB tuple to RGB\n    //! \\param[in] A 3-tuple color in sRGB space\n    //! \\param[in] The resultant 3-tuple color in RGB space\n    //! \\retval Return status, 1 = success\n    static int srgb2rgb(float srgb[3], float rgb[3]);\n\n    static int rgb2hsv(float rgb[3], float hsv[3]);\n    static int hsv2rgb(float hsv[3], float rgb[3]);\n\n    static float  Xn;\n    static float  Yn;\n    static float  Zn;\n    static float  XYZtransferMatrix[9];\n    static float  XYZinverseMatrix[9];\n    static float *colorMap;\n};\n\n};    // namespace VAPoR\n\n#endif    // TFINTERPOLATOR_H\n"
  },
  {
    "path": "include/vapor/TIFWriter.h",
    "content": "#pragma once\n\n#include \"vapor/ImageWriter.h\"\n#ifdef WIN32\n    #include <tiff/tiffio.h>\n#else\n    #include <xtiffio.h>\n#endif\n\nnamespace VAPoR {\n//! \\class TIFWriter\n//! \\ingroup Public_Render\n//! \\brief Writes TIF image files\n//! \\author Stanislaw Jaroszynski\nclass RENDER_API TIFWriter : public ImageWriter {\nprotected:\n    TIFF *tif;\n\n    int ConfigureWithFormat(Format f);\n\npublic:\n    static std::vector<std::string> GetFileExtensions();\n\n    TIFWriter(const std::string &path);\n    virtual ~TIFWriter();\n\n    virtual int Write(const unsigned char *buffer, const unsigned int width, const unsigned int height);\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/TMSUtils.h",
    "content": "#pragma once\n\n#include <vapor/common.h>\n#include <string>\n#include <vector>\n\nnamespace Wasp {\nnamespace TMSUtils {\n\nCOMMON_API bool IsTMSFile(std::string path);\nCOMMON_API std::string TilePath(std::string file, size_t tileX, size_t tileY, int lod);\nCOMMON_API int         GetNumTMSLODs(std::string file);\n\n}    // namespace TMSUtils\n}    // namespace Wasp\n"
  },
  {
    "path": "include/vapor/TextLabel.h",
    "content": "#pragma once\n\n#include <string>\n#include <glm/glm.hpp>\n\nnamespace VAPoR {\n\nstruct GLManager;\nclass Font;\n\n//! \\class TextLabel\n//! \\ingroup Public_Render\n//!\n//! \\brief Utitlity wrapper for Font class\n//!\n//! Creates a 2D label for a point in 2D or 3D space\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date   August, 2018\n\nclass TextLabel {\n    GLManager *_glManager;\n\npublic:\n    enum Alignment { Left, Center, Right, Top, Bottom };\n\n    std::string  FontName;\n    unsigned int FontSize;\n    glm::vec4    BackgroundColor;\n    glm::vec4    ForegroundColor;\n    Alignment    HorizontalAlignment;\n    Alignment    VerticalAlignment;\n    float        Padding;\n\n    TextLabel(GLManager *glManager, const std::string &fontName, unsigned int fontSize);\n\n    //! Draws a floating text label if a 3D perspective is used or simply text\n    //! if using a pixel coordinate space matrix. Formatting is determined by the\n    //! public variables.\n    //!\n    //! \\param[in] position will be transformed according to the current ModelViewProjection matrix\n    //! \\param[in] text will be drawn\n    //!\n    void DrawText(const glm::vec3 &position, const std::string &text);\n    void DrawText(const glm::vec2 &position, const std::string &text);\n\n    Font *GetFont() const;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/Texture.h",
    "content": "#pragma once\n\n#include <vapor/NonCopyableMixin.h>\n\nnamespace VAPoR {\n\nclass Framebuffer;\n\n//! \\class Texture\n//! \\ingroup Public_Render\n//! \\brief Wrapper class for an OpenGL texture\n//! \\author Stas Jaroszynski\n//! \\version 1.0\n//! \\date May 2019\n//!\n//! This class is intended to be used as a member object for a renderer.\n//! Any use of this class (including the destructor and except the constructor)\n//! must occur inside the correct OpenGL context.\n//!\n\nclass Texture : private NonCopyableMixin {\nprotected:\n    unsigned int       _id = 0;\n    unsigned int       _width = 0;\n    unsigned int       _height = 0;\n    unsigned int       _depth = 0;\n    const unsigned int _type;\n    const unsigned int _nDims;\n\npublic:\n    ~Texture();\n    int  Generate();\n    int  Generate(int filter);\n    void Delete();\n    bool Initialized() const;\n    void Bind() const;\n    void UnBind() const;\n    int  TexImage(int internalFormat, int width, int height, int depth, unsigned int format, unsigned int type, const void *data, int level = 0);\n\n    static unsigned int GetDimsCount(unsigned int glTextureEnum);\n\nprotected:\n    Texture(unsigned int type);\n\n    friend class Framebuffer;\n};\n\nclass Texture1D : public Texture {\npublic:\n    Texture1D();\n};\nclass Texture2D : public Texture {\npublic:\n    Texture2D();\n    void CopyDepthBuffer();\n};\nclass Texture3D : public Texture {\npublic:\n    Texture3D();\n};\nclass Texture2DArray : public Texture {\npublic:\n    Texture2DArray();\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/TrackBall.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tTrackBall.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJuly 2004\n//\n//\tDescription:\tDefines the Trackball class:\n//\t\tThis was implemented from Ken Purcell's TrackBall\n//\t\tmethods.  Additional methods provided to set the TrackBall\n//\t\tbased on a viewing frame\n//\n/* Copyright (C) 1992  AHPCRC, Univeristy of Minnesota\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program in a file named 'Copying'; if not, write to\n * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139.\n */\n\n/* Author:\n *\tKen Chin-Purcell (ken@ahpcrc.umn.edu)\n *\tArmy High Performance Computing Research Center (AHPCRC)\n *\tUniveristy of Minnesota\n *\n */\n\n#ifndef TRACKBALL_H\n#define TRACKBALL_H\n\n#include <vector>\n#include <vapor/common.h>\n\n/* These vector and quaternion macros complement similar\n * routines.\n */\n\n/* The Trackball package gives that nice 3D rotation interface.\n * A TrackBall class is needed for each rotated scene.\n */\nclass RENDER_API Trackball {\npublic:\n    Trackball();\n    Trackball(float scale[3]);\n    void TrackballSetMatrix();\n    void TrackballFlip(int axis);\n    void TrackballSpin();\n    void TrackballStopSpinning();\n    int  TrackballSpinning();\n    void TrackballSetPosition(double newx, double newy);\n    void TrackballRotate(double newx, double newy);\n    void TrackballPan(double newx, double newy);\n    void TrackballZoom(double newx, double newy);\n    void TrackballCopyTo(Trackball *dst);\n\n    void TrackballReset();\n\n    void GetCenter(double center[3]) const\n    {\n        for (int i = 0; i < 3; i++) center[i] = _center[i];\n    }\n\n    bool ReconstructCamera(double position[3], double upVec[3], double viewDir[3]) const;\n\n    // Note:  button is 1,2,3 for left, middle, right\n    void MouseOnTrackball(int eventType, int thisButton, int xcrd, int ycrd, int width, int height);\n\n    // Initialize the trackball, provide viewer position, direction, upvector,\n    // and the center of rotation (all in trackball coordinate space)\n    //\n    bool setFromFrame(const std::vector<double> &posvec, const std::vector<double> &dirvec, const std::vector<double> &upvec, const std::vector<double> &centerRot, bool perspective);\n\n    bool setFromFrame(const double posvec[3], const double dirvec[3], const double upvec[3], const double centerRot[3], bool perspective)\n    {\n        std::vector<double> pos, dir, up, center;\n        for (int i = 0; i < 3; i++) {\n            pos.push_back(posvec[i]);\n            dir.push_back(dirvec[i]);\n            up.push_back(upvec[i]);\n            center.push_back(centerRot[i]);\n        }\n        return setFromFrame(pos, dir, up, center, perspective);\n    }\n\n    void SetScale(const double scale[3])\n    {\n        _scale[0] = scale[0];\n        _scale[1] = scale[1];\n        _scale[2] = scale[2];\n    }\n\n    double GetOrthoSize() const;\n\n    const double *GetModelViewMatrix() const { return (_modelViewMatrix); }\n\nprivate:\n    void setCenter(const std::vector<double> &newCenter)\n    {\n        _center[0] = newCenter[0];\n        _center[1] = newCenter[1];\n        _center[2] = newCenter[2];\n    }\n\n    double _qrot[4];\n    double _qinc[4];\n    double _trans[3];\n    double _scale[3];\n    double _center[3];\n    double _ballsize;\n    double _lastx, _lasty;\n    bool   _perspective;\n    double _modelViewMatrix[16];\n};\n\n#endif    // TRACKBALL_H\n"
  },
  {
    "path": "include/vapor/Transform.h",
    "content": "#ifndef TRANSFORM_H\n#define TRANSFORM_H\n/*\n * This class describes a viewpoint\n */\n#include <vapor/ParamsBase.h>\n\nnamespace VAPoR {\n\n//! \\class Transform\n//! \\ingroup Public_Params\n//! \\brief class that indicates location and direction of view\n//! \\author Scott Pearse\n//! \\version 3.0\n//! \\date October 2017\n\n//! \\par\n//! This class contains all the parameters associated with dataset transforms,\n//! including the scaling, rotation, and translation of that dataset.\n//! ddshould be accessed through the TransformParams class.\n\nclass PARAMS_API Transform : public ParamsBase {\npublic:\n    enum Flags { VIEWPOINT = (1u << 0), RENDERER = (1u << 1) };\n\n    Transform(ParamsBase::StateSave *ssave);\n\n    Transform(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~Transform();\n\n    vector<double> GetRotations() const\n    {\n        vector<double> defaultv(3, 0.0);\n        vector<double> rotation = GetValueDoubleVec(_rotationTag, defaultv);\n        return rotation;\n    }\n\n    void SetRotations(const vector<double> rotation) { SetValueDoubleVec(_rotationTag, \"Set rotation transform\", rotation); }\n\n    vector<double> GetTranslations() const\n    {\n        vector<double> defaultv(3, 0.0);\n        vector<double> translation = GetValueDoubleVec(_translationTag, defaultv);\n        return translation;\n    }\n\n    void SetTranslations(const vector<double> translation) { SetValueDoubleVec(_translationTag, \"Set translation transform\", translation); }\n\n    vector<double> GetScales() const\n    {\n        vector<double> defaultv(3, 1.0);\n        vector<double> scale = GetValueDoubleVec(_scaleTag, defaultv);\n        return scale;\n    }\n\n    void SetScales(const vector<double> scale);\n\n    vector<double> GetOrigin() const;\n    void           SetOrigin(const vector<double> origin);\n\n    bool IsOriginInitialized() const;\n    void SetOriginInitialized(bool value);\n\n    static string GetClassType() { return (\"Transform\"); }\n\nprivate:\n    static const string _translationTag;\n    static const string _rotationTag;\n    static const string _scaleTag;\n    static const string _originTag;\n    static const string _originInitializedTag;\n};\n};    // namespace VAPoR\n\n#endif    // TRANSFORM_H\n"
  },
  {
    "path": "include/vapor/TwoDDataParams.h",
    "content": "\n#ifndef TWODDATAPARAMS_H\n#define TWODDATAPARAMS_H\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\n//! \\class TwoDDataParams\n//! \\brief Class that supports drawing Barbs based on 2D or 3D vector field\n//! \\author Alan Norton\n//! \\version 3.0\nclass PARAMS_API TwoDDataParams : public RenderParams {\npublic:\n    TwoDDataParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n\n    TwoDDataParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~TwoDDataParams();\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! \\copydoc Params::Validate()\n    virtual void Validate(int type);\n#endif\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"TwoDDataParams\"); }\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return (2); }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override { return GetVariableName(); }\n\nprivate:\n    void _init();\n#ifdef VAPOR3_0_0_ALPHA\n    void _validateTF(int type, DataMgr *dataMgr);\n#endif\n\n};    // End of Class TwoDDataParams\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/TwoDDataRenderer.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2008\t\t\t\t\t\t\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t\t\t\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tTwoDDataRender.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tMarch 2009\n//\n//\tDescription:\tDefinition of the TwoDDataRenderer class\n//\n#ifndef TWODDATARENDERER_H\n#define TWODDATARENDERER_H\n\n#include <vapor/glutil.h>\n#include <vapor/TwoDRenderer.h>\n#include <vapor/DataMgr.h>\n#include <vapor/GeoImage.h>\n#include <vapor/Grid.h>\n#include <vapor/utils.h>\n#include <vapor/TwoDDataParams.h>\n\nnamespace VAPoR {\n\nclass RENDER_API TwoDDataRenderer : public TwoDRenderer {\npublic:\n    TwoDDataRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    virtual ~TwoDDataRenderer();\n\n    // Get static string identifier for this render class\n    //\n    static string GetClassType() { return (\"TwoDData\"); }\n\nprotected:\n    int _initializeGL();\n\n    int _paintGL(bool fast);\n\n    int GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh);\n\n    const GLvoid *GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned);\n\nprivate:\n    class _grid_state_c {\n    public:\n        _grid_state_c() = default;\n        _grid_state_c(size_t numRefLevels, int refLevel, int lod, string hgtVar, string meshName, size_t ts, vector<double> minExts, vector<double> maxExts)\n        : _numRefLevels(numRefLevels), _refLevel(refLevel), _lod(lod), _hgtVar(hgtVar), _meshName(meshName), _ts(ts), _minExts(minExts), _maxExts(maxExts)\n        {\n        }\n\n        void clear()\n        {\n            _numRefLevels = 0;\n            _refLevel = _lod = -1;\n            _hgtVar = _meshName = \"\";\n            _ts = 0;\n            _minExts.clear();\n            _maxExts.clear();\n        }\n\n        bool operator==(const _grid_state_c &rhs) const\n        {\n            return (_numRefLevels == rhs._numRefLevels && _refLevel == rhs._refLevel && _lod == rhs._lod && _hgtVar == rhs._hgtVar && _meshName == rhs._meshName && _ts == rhs._ts\n                    && _minExts == rhs._minExts && _maxExts == rhs._maxExts);\n        }\n        bool operator!=(const _grid_state_c &rhs) const { return (!(*this == rhs)); }\n\n    private:\n        size_t         _numRefLevels;\n        int            _refLevel;\n        int            _lod;\n        string         _hgtVar;\n        string         _meshName;\n        size_t         _ts;\n        vector<double> _minExts;\n        vector<double> _maxExts;\n    };\n\n    class _tex_state_c {\n    public:\n        _tex_state_c() = default;\n        _tex_state_c(int refLevel, int lod, string varname, size_t ts, vector<double> minExts, vector<double> maxExts)\n        : _refLevel(refLevel), _lod(lod), _varname(varname), _ts(ts), _minExts(minExts), _maxExts(maxExts)\n        {\n        }\n\n        void clear()\n        {\n            _refLevel = _lod = -1;\n            _varname = \"\";\n            _ts = 0;\n            _minExts.clear();\n            _maxExts.clear();\n        }\n\n        bool operator==(const _tex_state_c &rhs) const\n        {\n            return (_refLevel == rhs._refLevel && _lod == rhs._lod && _varname == rhs._varname && _ts == rhs._ts && _minExts == rhs._minExts && _maxExts == rhs._maxExts);\n        }\n        bool operator!=(const _tex_state_c &rhs) const { return (!(*this == rhs)); }\n\n    private:\n        int            _refLevel;\n        int            _lod;\n        string         _varname;\n        size_t         _ts;\n        vector<double> _minExts;\n        vector<double> _maxExts;\n    };\n\n    _grid_state_c _grid_state;\n    _tex_state_c  _tex_state;\n\n    GLsizei  _texWidth;\n    GLsizei  _texHeight;\n    size_t   _texelSize;\n    SmartBuf _sb_verts;\n    SmartBuf _sb_normals;\n    SmartBuf _sb_indices;\n    SmartBuf _sb_texture;\n    GLsizei  _vertsWidth;\n    GLsizei  _vertsHeight;\n    GLsizei  _nindices;\n    GLsizei  _nverts;\n\n    GLuint   _cMapTexID;\n    GLfloat *_colormap;\n    size_t   _colormapsize;\n\n    bool _gridStateDirty() const;\n\n    void _gridStateClear();\n\n    void _gridStateSet();\n\n    bool _texStateDirty(DataMgr *dataMgr) const;\n\n    void _texStateSet(DataMgr *dataMgr);\n\n    void _texStateClear();\n\n    int _getMeshStructured(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ);\n\n    int _getMeshUnStructured(DataMgr *dataMgr, const Grid *g, double defaultZ);\n\n    int _getMeshUnStructuredHelper(DataMgr *dataMgr, const Grid *g, double defaultZ);\n\n    int _getMeshStructuredDisplaced(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ);\n\n    int _getMeshStructuredPlane(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ);\n\n    const GLvoid *_getTexture(DataMgr *dataMgr);\n\n    int _getOrientation(DataMgr *dataMgr, string varname);\n\n    void _clearCache() { _tex_state.clear(); }\n};\n};    // namespace VAPoR\n\n#endif    // TWODDATARENDERER_H\n"
  },
  {
    "path": "include/vapor/TwoDRenderer.h",
    "content": "//---------------- ----------------------------------------------------------\n//\n//                   Copyright (C)  2016\n//     University Corporation for Atmospheric Research\n//                   All Rights Reserved\n//\n//----------------------------------------------------------------------------\n\n#ifndef TWODRENDERER_H\n#define TWODRENDERER_H\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <vapor/DataMgr.h>\n#include <vapor/utils.h>\n#include <vapor/Renderer.h>\n\nnamespace VAPoR {\n\n//! \\class TwoDRenderer\n//! \\brief\n//! \\author John Clyne\n//! \\version 3.0\n//! \\date March 2016\n\nclass RENDER_API TwoDRenderer : public Renderer {\npublic:\n    //! Constructor, must invoke Renderer constructor\n    //! \\param[in] Visualizer* pointer to the visualizer where this will draw\n    //! \\param[in] RenderParams* pointer to the ArrowParams describing\n    //! this renderer\n    TwoDRenderer(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr);\n\n    //! Destructor\n    //\n    virtual ~TwoDRenderer();\n\nprotected:\n    // Protected pure virual methods\n    //\n\n    // Return a 2D structured or unstructured mesh\n    //\n    // verts : contains a packed representation of the x,y,z coordinates\n    // of each grid point. Thus size is height * width * sizeof(float) * 3\n    //\n    // normals : contains surface normal at each vertex. Need not be unit length\n    // Same packing as verts\n    //\n    // nverts : number of vertices and number of normals in verts, and\n    // normals, respectively. A single vertex or normal consists of three\n    // components. Thus if nverts == 1 then verts and normals each contain\n    // one three-component element.\n    //\n    // width : For structured grids contains number of grid points along\n    // fastest varying dimension. For unstructured grids contains *total*\n    // number of grid points\n    //\n    // height : For structured grids contains number of grid points along\n    // second fastest varying dimension. For unstructured grids should be set to\n    // one.\n    //\n    // indices : indexes into verts and normals to generate either triangles\n    // (unstructured mesh) or triangle strips (structured mesh).\n    // Compatible with index argument to GLDrawElements\n    //\n    // nindices : num elements in indices\n    //\n    // structuredMesh : bool, true if structured mesh, false if unstructured\n    //\n    virtual int GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh) = 0;\n\n    // Return data values for mesh returned with GetMesh(). The returned\n    // array may or may not be coincident with the mesh nodes. In the latter\n    // case the array returned is a uniformally 2D sampling of the data\n    // values on the mesh.\n    //\n    // width : For grid aligned data (gridAligned == true) contains number of\n    // data values along\n    // fastest varying dimension. For non-aligned data (gridAligned == false)\n    // contains *total* number of elements\n    //\n    // height : For grid aligned data (gridAligned == true) contains number of\n    // data values along\n    // second fastest varying dimension. For non-aligned data\n    // (gridAligned == false) should be set to one.\n    //\n    // type : Type of data returned by GetTexture(). If gridAligned\n    // is true, type must be GL_FLOAT\n    //\n    // texelSize: Size, in bytes, of a single element returned by GetTexture.\n    //\n    // gridAligned : bool. If true data are coincident with mesh returned by\n    // GetMesh()\n    //\n    virtual const GLvoid *GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned) = 0;\n\n    virtual void _clearCache() = 0;\n\n    //! \\copydoc Renderer::_initializeGL()\n    virtual int _initializeGL();\n\n    //! \\copydoc Renderer::_paintGL()\n    virtual int _paintGL(bool fast);\n\n    //! Compute 2D surface normals at each vertex.\n    //!\n    //! This protected method can be used by derived classes to calculate\n    //! unitized normals from a set of vertices by calculating the gradient\n    //! at each vertex.  The normal vectors are determined by looking\n    //! at z-coords of adjacent vertices in both\n    //! x and y.  Suppose that dzx is the change in z associated with\n    //! an x-change of dz, and that dzy is the change in z associated with\n    //! a y-change of dy.  Let the normal\n    //! vector be (a,b,c).  Then a/c is equal to dzx/dx, and b/c is\n    //! equal to dzy/dy.  So (a,b,c) is proportional to (dzx*dy, dzy*dx, 1)\n    //!\n    //! \\param[in] verts A pointer to a 2D array of surface vertices, dimensioned\n    //! \\p w by \\p h by 3. Vertices are store as inteleaved\n    //! triplets: vx0, vy0, vz0, vx1, vy1, vz1, ... vxn, vyn, vzn, where\n    //! \\b n = \\p w * \\p h - 1\n    //!\n    //! \\param[in] w Width (length of fastest varying dimension)\n    //! of \\p verts in grid points\n    //! \\param[in] h Height (length of second fastest varying dimension)\n    //! of \\p verts in grid points\n    //!\n    //! \\param[out] normals A pointer to a 2D array of the same size as \\p verts\n    //! that will contain the computed, unitized surface normals, stored\n    //! in interleaved form.\n    //\n    void ComputeNormals(const GLfloat *verts, GLsizei w, GLsizei h, GLfloat *normals);\n\nprivate:\n    GLuint        _textureID;\n    const GLvoid *_texture;\n    GLfloat *     _texCoords;\n    GLsizei       _texWidth;\n    GLsizei       _texHeight;\n    GLint         _texInternalFormat;\n    GLenum        _texFormat;\n    GLenum        _texType;\n    size_t        _texelSize;\n    bool          _gridAligned;\n    bool          _structuredMesh;\n    GLfloat *     _verts;\n    GLfloat *     _normals;\n    GLuint *      _indices;\n    GLsizei       _meshWidth;\n    GLsizei       _meshHeight;\n    GLsizei       _nindices;\n    GLsizei       _nverts;\n    SmartBuf      _sb_texCoords;\n\n    GLuint _VAO, _VBO, _dataVBO, _EBO;\n\n    void _openGLInit();\n    void _openGLRestore();\n    void _renderMesh();\n    void _renderMeshUnAligned();\n    void _renderMeshAligned();\n    void _computeTexCoords(GLfloat *tcoords, size_t w, size_t h) const;\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/UDUnitsClass.h",
    "content": "//\n// $Id$\n//\n\n#ifndef _UDUnitsClass_h_\n#define _UDUnitsClass_h_\n\n#include <string>\n#include <vector>\n#include <map>\n#include <algorithm>\n#include <vapor/common.h>\n\nunion ut_unit;\nstruct ut_system;\n\nnamespace VAPoR {\n\n//! \\class UDUnits\n//!\n//! Provides a C++ wrapper for Unidata's Udunits-2 package:\n//! http://www.unidata.ucar.edu/software/udunits/udunits-2/udunits2.html\n//!\n//! Error handling: most methods in this class return an integer status\n//! flag, with a negative value indicating error. Error messages for the\n//! most recent error can be retrieved with GetErrMsg().\n//!\nclass VDF_API UDUnits {\npublic:\n    UDUnits();\n    ~UDUnits();\n\n    static std::string GetDatabasePath();\n\n    //! Initialize the Udunits-2 data base. Must be called after the\n    //! constructor, prior to any other class methods\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    int Initialize();\n\n    //! Return true if the string provided by \\p unitstr is recognized\n    //! by Udunits-2 as a unit of pressure\n    //!\n    bool IsPressureUnit(std::string unitstr) const;\n\n    //! Return true if the string provided by \\p unitstr is recognized\n    //! by Udunits-2 as a unit of time\n    //!\n    bool IsTimeUnit(std::string unitstr) const;\n\n    //! Return true if the string provided by \\p unitstr is recognized\n    //! by Udunits-2 as a unit of Latitude\n    //!\n    bool IsLatUnit(std::string unitstr) const;\n\n    //! Return true if the string provided by \\p unitstr is recognized\n    //! by Udunits-2 as a unit of Longitude\n    //!\n    bool IsLonUnit(std::string unitstr) const;\n\n    //! Return true if the string provided by \\p unitstr is recognized\n    //! by Udunits-2 as a unit of Longitude or Latitude\n    //!\n    bool IsLatOrLonUnit(std::string unitstr) const;\n\n    //! Return true if the string provided by \\p unitstr is recognized\n    //! by Udunits-2 as a unit of length\n    //!\n    bool IsLengthUnit(std::string unitstr) const;\n\n    //! Return true if the unit identified by the string contained in \\p unitstr\n    //! can be converted into the unit identified by \\p unit. Otherwise false\n    //! is returned\n    //!\n    bool AreUnitsConvertible(const ut_unit *unit, std::string unitstr) const;\n\n    //! Returns true if the string contained in \\p unitstr is recognized\n    //! as a valid unit by the Udunits-2 data base\n    //!\n    bool ValidUnit(std::string unitstr) const;\n\n    //! Convert one unit to another\n    //!\n    //! This method performs conversion between different units, when\n    //! possible (see AreUnitsConvertible()).  For example, converting\n    //! meters to feet. The string \\p from specifies the unit to convert\n    //! from, and the string \\p to specifies the unit to convert to.\n    //!\n    //! \\param[in] from A string specifying the source unit\n    //! \\param[in] to A string specifying the destination unit\n    //! \\param[in] src An array of source unit values\n    //! \\param[out] dst An array large enough to store the converted\n    //! unit values.\n    //! \\param[in] n The number of elements in \\p from\n    //!\n    //! \\retval boolean A boolean status is returned indicating whether\n    //! the conversion took place. Conversion will fail if the units are\n    //! not convertible. No error message is generated.\n    //!\n    //! \\sa AreUnitsConvertible\n    //!\n    bool Convert(const std::string from, const std::string to, const float *src, float *dst, size_t n) const;\n\n    bool Convert(const std::string from, const std::string to, const double *src, double *dst, size_t n) const;\n\n    //! Decode time specified in seconds to year, month, day, hour, minute\n    //! and second.\n    //!\n    //! This method uses Udunits-2 ut_decode_time() function to perform\n    //! time conversion\n    //!\n    void DecodeTime(double seconds, int *year, int *month, int *day, int *hour, int *minute, int *second) const;\n\n    //! Encode time specified to years, month, day, hour, minute\n    //! and seconds to seconds\n    //!\n    //! This method uses Udunits-2 ut_encode_time() function to perform\n    //! time conversion\n    //!\n    double EncodeTime(int year, int month, int day, int hour, int minute, int second) const;\n\n    //! Get the most recent error message\n    //!\n    //! This method returns a string containing the most recently occurring\n    //! error message, if any.\n    //!\n    std::string GetErrMsg() const;\n\nprivate:\n    std::map<int, std::string> _statmsg;\n    int                        _status;\n    ut_unit *                  _pressureUnit;\n    ut_unit *                  _timeUnit;\n    ut_unit *                  _latUnit;\n    ut_unit *                  _lonUnit;\n    ut_unit *                  _lengthUnit;\n    ut_system *                _unitSystem;\n};\n};    // namespace VAPoR\n#endif\n"
  },
  {
    "path": "include/vapor/UnstructuredGrid.h",
    "content": "#ifndef _UnstructuredGrid_\n#define _UnstructuredGrid_\n\n#include <ostream>\n#include <vector>\n#include <memory>\n#include <vapor/common.h>\n#include <vapor/Grid.h>\n\n#ifdef WIN32\n    #pragma warning(disable : 4661 4251)    // needed for template class\n#endif\n\nnamespace VAPoR {\n\n//! \\class UnstructuredGrid\n//! \\brief Abstract base class for a 2D or 3D unstructured grid.\n//! \\author John Clyne\n//!\n//! This abstract base class defines a 2D or 3D unstructured\n//! grid.\n//!\n//! The unstructured grid samples a scalar function at each grid point. The\n//! scalar function samples are stored as an array decomposed into\n//! equal-sized blocks.\n//!\n//! Because grid samples are repesented internally as arrays, when accessing\n//! multiple grid points better performance is achieved by using\n//! unit stride. The \\a I axis varies fastest (has unit stride),\n//! followed by \\a J, then \\a K. Best performance is achieved\n//! when using the class iterator: UnstructuredGrid::Iterator.\n//!\n//! For methods that allow the specification of grid indecies or coordinates\n//! as a single parameter tuple (e.g. vector <double> coordinate) the\n//! first element\n//! of the tuple corresponds to the \\a I axis, etc.\n//!\n//! \\note Throughout this class grid vertex offsets are specified as\n//! \\a i, \\a j, \\a k, where \\a i, \\a j, \\a k are integers. User coordinates\n//! are real values denoted \\a x, \\a y, \\a z, and are given by functions\n//! \\a X(i,j,k), \\a Y(i,j,k), \\a Z(i,j,k).\n//\nclass VDF_API UnstructuredGrid : public Grid {\npublic:\n    enum Location { NODE, CELL, EDGE };\n\n    //!\n    //! Construct a unstructured grid sampling a 3D or 2D scalar function\n    //!\n    //! \\param[in] vertexDims Dimensions of grid nodes (vertices).\n    //! The product of the\n    //! elements of \\p vertexDims gives the total number of nodes in the mesh.\n    //! If the rank of \\p vertexDims is greater than one the mesh is assumed to\n    //! be structured along the slower varying dimensions (e.g. a layered mesh)\n    //!\n    //! \\param[in] faceDims Dimensions of grid cells. The product of the\n    //! elements of \\p cells gives the total number of cells in the mesh.\n    //! If the rank of \\p cells is greater than one the mesh is assumed to\n    //! be structured along the slower varying dimensions (e.g. a layered mesh).\n    //! Moreover, the slowest varying dimensions must be one less than the\n    //! corresponding dimension of \\p vertexDims.\n    //!\n    //! \\param[in] edgeDims Dimensions of grid edges. The product of the\n    //! elements of \\p edges gives the total number of edges in the mesh.\n    //! If the rank of \\p edges is greater than one the mesh is assumed to\n    //! be structured along the slower varying dimensions (e.g. a layered mesh).\n    //! Moreover, the slowest varying dimensions must be one less than the\n    //! corresponding dimension of \\p vertexDims.\n    //!\n    //! \\param[in] blks Grid data values. The location of the data values\n    //! (node, cell, edge) is determined by \\p location. If the dimensions\n    //! (\\p vertexDims, etc) are multi-dimensional the size of \\p blks must\n    //! match the size of the slowest varying dimension. Each element of\n    //! \\p blks must point to an area of memory of size \\b n elements, where\n    //! \\b n is the first element of \\p vertexDims, \\p faceDims, or \\p edgeDims\n    //! as indicated by \\p location.\n    //!\n    //! \\param[in] vertexOnFace An array with dimensions:\n    //!\n    //! \\p faceDims[0] * maxVertexPerFace\n    //! that provides for each cell the 1D node IDs of each corner node.\n    //! If the number of corner nodes is less than \\p maxVertexPerFace\n    //! the missing node indices will be equal to GetMissingID();\n    //! The ordering of the nodes is counter-clockwise.\n    //!\n    //! \\param[in] faceOnVertex An array with dimensions:\n    //!\n    //! \\p vertexDims[0] * maxFacePerVertex\n    //! that provides for each vertex the 1D node IDs of each face\n    //! sharing that vertex.\n    //! If the number of faces is less than \\p maxFacePerVertex\n    //! the missing face indices will be equal to GetMissingID();\n    //! The ordering of the faces is counter-clockwise.\n    //!\n    //! \\param[in] faceOnFace An array with dimensions:\n    //!\n    //! \\p faceDims[0] * maxVertexPerFace\n    //! that provides for each cell the 1D cell IDs of border cell\n    //! If the number of corner nodes is less than \\p maxVertexPerFace\n    //! the missing node indices will be equal to GetMissingID(). If an\n    //! edge is on the mesh boundary the index will be set to the value\n    //! GetBoundaryIndex().\n    //! The ordering of the neighboring faces is counter-clockwise.\n    //!\n    //! \\param[in] location The location of grid data: at the nodes, edge-centered,\n    //! or cell-centered\n    //!\n    //! \\param[in] maxVertexPerFace The maxium number of nodes that a face\n    //! may have.\n    //!\n    //! \\param[in] nodeOffset The offset from zero for the first element\n    //! in \\p vertexOnFace\n    //!\n    //! \\param[in] cellOffset The offset from zero for the first element\n    //! in \\p faceOnVertex or \\p faceOnFace\n    //\n    UnstructuredGrid(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, size_t topology_dimension,\n                     const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                     Location location,    // node,face, edge\n                     size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset\n\n    );\n    UnstructuredGrid(const std::vector<size_t> &vertexDims, const std::vector<size_t> &faceDims, const std::vector<size_t> &edgeDims, const std::vector<size_t> &bs, const std::vector<float *> &blks,\n                     size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                     Location location,    // node,face, edge\n                     size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset\n\n    );\n\n    UnstructuredGrid() = default;\n    virtual ~UnstructuredGrid() = default;\n\n    static std::string GetClassType() { return (\"Unstructured\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    bool GetCellNodes(const DimsType &cindices, std::vector<DimsType> &nodes) const override;\n\n    //! \\copydoc Grid::GetCellNeighbors()\n    //!\n    virtual bool GetCellNeighbors(const DimsType &cindices, std::vector<DimsType> &cells) const override;\n\n    //! \\copydoc Grid::GetNodeCells()\n    //!\n    virtual bool GetNodeCells(const DimsType &indices, std::vector<DimsType> &cells) const override;\n\n    size_t GetMaxVertexPerFace() const override { return (_maxVertexPerFace); };\n\n    size_t GetMaxVertexPerCell() const override { return ((GetTopologyDim() == 3) ? 2 * GetMaxVertexPerFace() : GetMaxVertexPerFace()); };\n\n    //! Return the grid node dimmensions\n    //!\n    const VAPoR::DimsType &GetNodeDimensions() const override;\n    const size_t          GetNumNodeDimensions() const override;\n\n    //! Return the grid cell dimmensions\n    //!\n    const DimsType &GetCellDimensions() const override { return (_faceDims); }\n\n    virtual const size_t GetNumCellDimensions() const override { return (_nDims); }\n\n    //! Return the grid edge dimmensions\n    //!\n    const DimsType &GetEdgeDimensions() const { return (_edgeDims); }\n\n    //! Get missing element ID\n    //!\n    //! Return the value used to indicate termination of a list of element IDs\n    //!\n    size_t GetMissingID() const { return (_missingID); }\n    void   SetMissingID(size_t v) { _missingID = v; }\n\n    //! Get boundary element ID\n    //!\n    //! Return the value used to indicate termination of a list of element IDs\n    //!\n    size_t GetBoundaryID() const { return (_boundaryID); }\n    void   SetBoundaryID(size_t v) { _boundaryID = v; }\n\n    virtual void ClampCoord(const CoordType &coords, CoordType &cCoords) const override { cCoords = coords; }\n\n    //! \\deprecated\n    //\n    virtual void ClampCoord(const double coords[3], double cCoords[3]) const override { Grid::ClampCoord(coords, cCoords); }\n\n    // A no-op for unstructured grids. Needs to be set in the constuctor :-(\n    //\n    virtual void SetNodeOffset(long offset) override {}\n    virtual void SetCellOffset(long offset) override {}\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Iterators\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGrid &sg);\n\nprotected:\n    const int *_vertexOnFace;\n    const int *_faceOnVertex;\n    const int *_faceOnFace;\n    size_t     _maxVertexPerFace;\n    size_t     _maxFacePerVertex;\n    Location   _location;\n\nprivate:\n    DimsType            _vertexDims;\n    DimsType            _faceDims;\n    DimsType            _edgeDims;\n    size_t              _nDims;\n    int                 _missingID;\n    int                 _boundaryID;\n\n    void _unstructuredGrid(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, size_t topology_dimension,\n                           const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                           Location location,    // node,face, edge\n                           size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset\n\n    );\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/UnstructuredGrid2D.h",
    "content": "#ifndef _UnstructuredGrid2D_\n#define _UnstructuredGrid2D_\n\n#include <ostream>\n#include <vector>\n#include <memory>\n#include <vapor/common.h>\n#include <vapor/UnstructuredGrid.h>\n#include <vapor/UnstructuredGridCoordless.h>\n#include <vapor/QuadTreeRectangleP.h>\n\n#ifdef WIN32\n    #pragma warning(disable : 4661 4251)    // needed for template class\n#endif\n\nnamespace VAPoR {\n\n//! \\class UnstructuredGrid2D\n//! \\brief class for a 2D unstructured grid.\n//! \\author John Clyne\n//!\n//\nclass VDF_API UnstructuredGrid2D : public UnstructuredGrid {\npublic:\n    //! Construct a unstructured grid sampling 2D scalar function\n    //!\n    //\n    UnstructuredGrid2D(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, const int *vertexOnFace,\n                       const int *faceOnVertex, const int *faceOnFace,\n                       Location location,    // node,face, edge\n                       size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                       const UnstructuredGridCoordless &zug, std::shared_ptr<const QuadTreeRectangleP> qtr);\n\n    UnstructuredGrid2D(const std::vector<size_t> &vertexDims, const std::vector<size_t> &faceDims, const std::vector<size_t> &edgeDims, const std::vector<size_t> &bs, const std::vector<float *> &blks,\n                       const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                       Location location,    // node,face, edge\n                       size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                       const UnstructuredGridCoordless &zug, std::shared_ptr<const QuadTreeRectangleP> qtr);\n\n    UnstructuredGrid2D() = default;\n    virtual ~UnstructuredGrid2D()\n    {\n        if (_qtr) _qtr = nullptr;\n    }\n\n    std::shared_ptr<const QuadTreeRectangleP> GetQuadTreeRectangle() const { return (_qtr); }\n\n    virtual DimsType GetCoordDimensions(size_t dim) const override;\n\n    virtual size_t GetGeometryDim() const override;\n\n    static std::string GetClassType() { return (\"Unstructured2D\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override;\n\n    bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override;\n\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override;\n\n    bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override\n    {\n        std::vector<double>              lambda;\n        std::vector<std::vector<size_t>> nodes;\n        return (GetIndicesCell(coords, indices, nodes, lambda));\n    }\n    // For grandparent inheritance of\n    // Grid::GetIndicesCell(const double coords[3], size_t indices[3])\n    //\n    using Grid::GetIndicesCell;\n\n    //! \\copydoc Grid::GetIndicesCell()\n    //!\n    //! \\param[out] nodes Indices of vertices of the cell identified by \\p indices\n    //! \\param[out] lambda Interpolation weights that may be applied to values\n    //! at nodes identified by \\p nodes\n    //!\n    bool GetIndicesCell(const CoordType &coords, DimsType &indices, std::vector<std::vector<size_t>> &nodes, std::vector<double> &lambda) const;\n\n    bool InsideGrid(const CoordType &coords) const override;\n\n    float GetValueNearestNeighbor(const CoordType &coords) const override;\n\n    float GetValueLinear(const CoordType &coords) const override;\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Iterators\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    class ConstCoordItrU2D : public Grid::ConstCoordItrAbstract {\n    public:\n        ConstCoordItrU2D(const UnstructuredGrid2D *ug, bool begin);\n        ConstCoordItrU2D(const ConstCoordItrU2D &rhs);\n\n        ConstCoordItrU2D();\n        virtual ~ConstCoordItrU2D() {}\n\n        virtual void            next();\n        virtual void            next(const long &offset);\n        virtual ConstCoordType &deref() const { return (_coords); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const\n        {\n            const ConstCoordItrU2D *itrptr = static_cast<const ConstCoordItrU2D *>(rhs);\n\n            return (_xCoordItr == itrptr->_xCoordItr && _yCoordItr == itrptr->_yCoordItr && _zCoordItr == itrptr->_zCoordItr);\n        }\n\n        virtual std::unique_ptr<ConstCoordItrAbstract> clone() const { return std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrU2D(*this)); };\n\n    private:\n        size_t              _ncoords;\n        ConstIterator       _xCoordItr;\n        ConstIterator       _yCoordItr;\n        ConstIterator       _zCoordItr;\n        CoordType           _coords;\n    };\n\n    virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrU2D(this, true))); }\n    virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrU2D(this, false))); }\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGrid2D &sg);\n\nprotected:\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override;\n\nprivate:\n    UnstructuredGridCoordless                 _xug;\n    UnstructuredGridCoordless                 _yug;\n    UnstructuredGridCoordless                 _zug;\n    std::shared_ptr<const QuadTreeRectangleP> _qtr;\n\n    bool _insideGrid(const CoordType &coords, size_t &face, std::vector<size_t> &nodes, double *lambda, int &nlambda) const;\n\n    bool _insideGridNodeCentered(const CoordType &coords, size_t &face, std::vector<size_t> &nodes, double *lambda, int &nlambda) const;\n\n    bool _insideGridFaceCentered(const CoordType &coords, size_t &face, std::vector<size_t> &nodes, double *lambda, int &nlambda) const;\n\n    bool _pointInsideBoundingRectangle(const double pt[], const double verts[], int n) const;\n\n    bool _insideFace(size_t face, double pt[2], std::vector<size_t> &node_indices, double *lambda, int &nlambda) const;\n\n    std::shared_ptr<QuadTreeRectangleP> _makeQuadTreeRectangle() const;\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/UnstructuredGrid3D.h",
    "content": "#pragma once\n\n#include <ostream>\n#include <vector>\n#include <memory>\n#include <vapor/common.h>\n#include <vapor/UnstructuredGrid2D.h>\n#include <vapor/QuadTreeRectangle.hpp>\n\n\n#ifdef WIN32\n    #pragma warning(disable : 4661 4251)    // needed for template class\n#endif\n\nnamespace VAPoR {\n\n//! \\class UnstructuredGrid3D\n//! \\brief class for a Layered unstructured grid.\n//!\n//\nclass VDF_API UnstructuredGrid3D : public UnstructuredGrid {\npublic:\n    //! Construct a unstructured grid sampling Layered scalar function\n    //!\n    //\n    UnstructuredGrid3D(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, const int *vertexOnFace,\n                       const int *faceOnVertex, const int *faceOnFace,\n                       Location location,    // node,face, edge\n                       size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                       const UnstructuredGridCoordless &zug);\n\n    UnstructuredGrid3D(const std::vector<size_t> &vertexDims, const std::vector<size_t> &faceDims, const std::vector<size_t> &edgeDims, const std::vector<size_t> &bs, const std::vector<float *> &blks,\n                       const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                       Location location,    // node,face, edge\n                       size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                       const UnstructuredGridCoordless &zug);\n\n    UnstructuredGrid3D() = default;\n    virtual ~UnstructuredGrid3D() = default;\n\n    virtual DimsType GetCoordDimensions(size_t dim) const override;\n\n    virtual size_t GetGeometryDim() const override;\n\n    static std::string GetClassType() { return (\"Unstructured3D\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override;\n    bool         GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override;\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override;\n    bool         GetIndicesCell(const CoordType &coords, DimsType &indices) const override;\n    bool         InsideGrid(const CoordType &coords) const override;\n    float        GetValueNearestNeighbor(const CoordType &coords) const override;\n    float        GetValueLinear(const CoordType &coords) const override;\n\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Iterators\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    class ConstCoordItrU3D : public Grid::ConstCoordItrAbstract {\n    public:\n        ConstCoordItrU3D(const UnstructuredGrid3D *ug, bool begin);\n        ConstCoordItrU3D(const ConstCoordItrU3D &rhs);\n\n\n        ConstCoordItrU3D();\n        virtual ~ConstCoordItrU3D() {}\n\n        virtual void            next() override;\n        virtual void            next(const long &offset) override;\n        virtual ConstCoordType &deref() const override { return (_coords); }\n        virtual const void *    address() const override { return this; };\n\n        virtual bool equal(const void *rhs) const override\n        {\n            const ConstCoordItrU3D *itrptr = static_cast<const ConstCoordItrU3D *>(rhs);\n\n            return (_xCoordItr == itrptr->_xCoordItr && _yCoordItr == itrptr->_yCoordItr && _zCoordItr == itrptr->_zCoordItr);\n        }\n\n        virtual std::unique_ptr<ConstCoordItrAbstract> clone() const override { return std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrU3D(*this)); };\n\n    private:\n        const UnstructuredGrid3D *_ug;\n        ConstIterator             _xCoordItr;\n        ConstIterator             _yCoordItr;\n        ConstIterator             _zCoordItr;\n        CoordType                 _coords;\n    };\n\n    virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrU3D(this, true))); }\n    virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrU3D(this, false))); }\n\n\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGrid3D &sg);\n\nprotected:\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override;\n\nprivate:\n    UnstructuredGridCoordless _xug;\n    UnstructuredGridCoordless _yug;\n    UnstructuredGridCoordless _zug;\n\n    bool _insideGrid(const CoordType &coords, DimsType &cindices, std::vector<size_t> &nodes2D, std::vector<double> &lambda, float zwgt[2]) const;\n};\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/UnstructuredGridCoordless.h",
    "content": "#ifndef _UnstructuredGridCoordless_\n#define _UnstructuredGridCoordless_\n\n#include <ostream>\n#include <vector>\n#include <memory>\n#include <vapor/common.h>\n#include <vapor/UnstructuredGrid.h>\n\n#ifdef WIN32\n    #pragma warning(disable : 4661 4251)    // needed for template class\n#endif\n\nnamespace VAPoR {\n\n//! \\class UnstructuredGridCoordless\n//! \\brief class for a 2D unstructured grid.\n//! \\author John Clyne\n//!\n//\nclass VDF_API UnstructuredGridCoordless : public UnstructuredGrid {\npublic:\n    //! Construct a unstructured grid sampling 2D scalar function\n    //!\n    //\n    UnstructuredGridCoordless(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, size_t topology_dimension,\n                              const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                              Location location,    // node,face, edge\n                              size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset)\n    : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, topology_dimension, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset)\n    {\n    }\n    UnstructuredGridCoordless(const std::vector<size_t> &vertexDims, const std::vector<size_t> &faceDims, const std::vector<size_t> &edgeDims, const std::vector<size_t> &bs,\n                              const std::vector<float *> &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                              Location location,    // node,face, edge\n                              size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset)\n    : UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, topology_dimension, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset)\n    {\n    }\n\n    UnstructuredGridCoordless() = default;\n    virtual ~UnstructuredGridCoordless() = default;\n\n    virtual DimsType GetCoordDimensions(size_t dim) const override { return (DimsType{1, 1, 1}); }\n\n    static std::string GetClassType() { return (\"UnstructuredCoordless\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override\n    {\n        minu = {0.0, 0.0, 0.0};\n        maxu = {0.0, 0.0, 0.0};\n    }\n\n    bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override { return (false); }\n\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override {}\n\n    bool GetIndicesCell(const CoordType &, DimsType &) const override { return (false); }\n\n    bool InsideGrid(const CoordType &coords) const override { return (false); }\n\n    float GetValueNearestNeighbor(const CoordType &coords) const override { return (0.0); }\n\n    float GetValueLinear(const CoordType &coords) const override { return (0.0); }\n\n    virtual size_t GetGeometryDim() const override { return (0); }\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Iterators\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    class ConstCoordItrUCoordless : public Grid::ConstCoordItrAbstract {\n    public:\n        ConstCoordItrUCoordless(const UnstructuredGridCoordless *ug, bool begin) {}\n        ConstCoordItrUCoordless(const ConstCoordItrUCoordless &rhs) {}\n\n        ConstCoordItrUCoordless();\n        virtual ~ConstCoordItrUCoordless() {}\n\n        virtual void            next() {}\n        virtual void            next(const long &offset) {}\n        virtual ConstCoordType &deref() const { return (_coords); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const { return (true); }\n\n        virtual std::unique_ptr<ConstCoordItrAbstract> clone() const { return std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrUCoordless(*this)); };\n\n    private:\n        CoordType _coords;\n    };\n\n    virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrUCoordless(this, true))); }\n    virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrUCoordless(this, false))); }\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGridCoordless &sg);\n\nprotected:\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override\n    {\n        minu = {0.0, 0.0, 0.0};\n        maxu = {0.0, 0.0, 0.0};\n    }\n\nprivate:\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/UnstructuredGridLayered.h",
    "content": "#ifndef _UnstructuredGridLayered_\n#define _UnstructuredGridLayered_\n\n#include <ostream>\n#include <vector>\n#include <memory>\n#include <vapor/common.h>\n#include <vapor/UnstructuredGrid2D.h>\n#include <vapor/QuadTreeRectangleP.h>\n\n#ifdef WIN32\n    #pragma warning(disable : 4661 4251)    // needed for template class\n#endif\n\nnamespace VAPoR {\n\n//! \\class UnstructuredGridLayered\n//! \\brief class for a Layered unstructured grid.\n//! \\author John Clyne\n//!\n//\nclass VDF_API UnstructuredGridLayered : public UnstructuredGrid {\npublic:\n    //! Construct a unstructured grid sampling Layered scalar function\n    //!\n    //\n    UnstructuredGridLayered(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, const int *vertexOnFace,\n                            const int *faceOnVertex, const int *faceOnFace,\n                            Location location,    // node,face, edge\n                            size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                            const UnstructuredGridCoordless &zug, std::shared_ptr<const QuadTreeRectangleP> qtr);\n\n    UnstructuredGridLayered(const std::vector<size_t> &vertexDims, const std::vector<size_t> &faceDims, const std::vector<size_t> &edgeDims, const std::vector<size_t> &bs,\n                            const std::vector<float *> &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                            Location location,    // node,face, edge\n                            size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                            const UnstructuredGridCoordless &zug, std::shared_ptr<const QuadTreeRectangleP> qtr);\n\n    UnstructuredGridLayered() = default;\n    virtual ~UnstructuredGridLayered() = default;\n\n    std::shared_ptr<const QuadTreeRectangleP> GetQuadTreeRectangle() const { return (_ug2d.GetQuadTreeRectangle()); }\n\n    virtual DimsType GetCoordDimensions(size_t dim) const override;\n\n    virtual size_t GetGeometryDim() const override;\n\n    static std::string GetClassType() { return (\"UnstructuredLayered\"); }\n    std::string        GetType() const override { return (GetClassType()); }\n\n    virtual void GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const override;\n\n    bool GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const override;\n\n    virtual void GetUserCoordinates(const DimsType &indices, CoordType &coords) const override;\n\n    bool GetIndicesCell(const CoordType &coords, DimsType &indices) const override;\n\n    bool InsideGrid(const CoordType &coords) const override;\n\n    float GetValueNearestNeighbor(const CoordType &coords) const override;\n\n    float GetValueLinear(const CoordType &coords) const override;\n\n    /////////////////////////////////////////////////////////////////////////////\n    //\n    // Iterators\n    //\n    /////////////////////////////////////////////////////////////////////////////\n\n    class ConstCoordItrULayered : public Grid::ConstCoordItrAbstract {\n    public:\n        ConstCoordItrULayered(const UnstructuredGridLayered *ug, bool begin);\n        ConstCoordItrULayered(const ConstCoordItrULayered &rhs);\n\n        ConstCoordItrULayered();\n        virtual ~ConstCoordItrULayered() {}\n\n        virtual void            next();\n        virtual void            next(const long &offset);\n        virtual ConstCoordType &deref() const { return (_coords); }\n        virtual const void *    address() const { return this; };\n\n        virtual bool equal(const void *rhs) const\n        {\n            const ConstCoordItrULayered *itrptr = static_cast<const ConstCoordItrULayered *>(rhs);\n\n            return (_itr2D == itrptr->_itr2D && _zCoordItr == itrptr->_zCoordItr);\n        }\n\n        virtual std::unique_ptr<ConstCoordItrAbstract> clone() const { return std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrULayered(*this)); };\n\n    private:\n        const UnstructuredGridLayered *   _ug;\n        UnstructuredGrid2D::ConstCoordItr _itr2D;\n        ConstIterator                     _zCoordItr;\n        CoordType                         _coords;\n        size_t                            _nElements2D;\n        size_t                            _index2D;\n    };\n\n    virtual ConstCoordItr ConstCoordBegin() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrULayered(this, true))); }\n    virtual ConstCoordItr ConstCoordEnd() const override { return ConstCoordItr(std::unique_ptr<ConstCoordItrAbstract>(new ConstCoordItrULayered(this, false))); }\n\n    VDF_API friend std::ostream &operator<<(std::ostream &o, const UnstructuredGridLayered &sg);\n\nprotected:\n    virtual void GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const override;\n\nprivate:\n    UnstructuredGrid2D        _ug2d;\n    UnstructuredGridCoordless _zug;\n\n    bool _insideGrid(const CoordType &coords, DimsType &cindices, std::vector<size_t> &nodes2D, std::vector<double> &lambda, float zwgt[2]) const;\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/VAssert.h",
    "content": "#pragma once\n\n#include <vapor/common.h>\n\nnamespace Wasp {\nCOMMON_API void _VAssertFailed(const char *expr, const char *path, const unsigned int line);\n}\n\n#define VAssert(expr) ((expr) ? (void)0 : Wasp::_VAssertFailed(#expr, __FILE__, __LINE__))\n"
  },
  {
    "path": "include/vapor/VDC.h",
    "content": "#include <vector>\n#include <map>\n#include <iostream>\n#include <vapor/DC.h>\n#include <vapor/MyBase.h>\n#include <vapor/UDUnitsClass.h>\n\n#ifndef _VDC_H_\n    #define _VDC_H_\n\nnamespace VAPoR {\n\n//!\n//! \\class VDC\n//! \\ingroup Public_VDC\n//!\n//! \\brief Defines API for reading, writing, and appending data to a\n//! VAPOR Data Collection (Version 3)\n//!\n//! \\author John Clyne\n//! \\date    July, 2014\n//!\n//! This abstract class efines API for reading, writing, and\n//! appending data to a\n//! VAPOR Data Collection (Version 3).  The VDC class is an abstract virtual\n//! class, providing a public API, but performing no actual storage\n//! operations. Derived implementations of the VDC base class are\n//! required to support the API.\n//!\n//! In version 3 of the VDC the metadata (.vdf) file found in VDC version 1\n//! and 2 is replaced with a\n//! \"master\" file that describes the contents of the entire VDC. The master\n//! file imposes structure on the organization of the files containing data,\n//! determining, for example, which data files contain which variables\n//! and time steps.\n//!\n//! Unlike\n//! the .vdf file, it is intended that the master file will be stored in the\n//! same scientific data\n//! file format as the data themselves (though this depends on the\n//! implementation of the derived class).\n//! Another important change in version 3\n//! is that both the master file and the accompanying data files\n//! are intended to be accessible using the native file format API. I.e.\n//! users may operate on files in the VDC using, for example, the\n//! NetCDF API, or they\n//! may use the API provided by the VDC class object. The latter is only\n//! required when reading or writing compressed variables (not all variables\n//! in a VDC version 3 must be compressed). Thus if NetCDF is chosen\n//! as the underlying format the NetCDF API may be used directly to read\n//! and write NetCDF \"attributes\" and variables (provided the variables\n//! are not compressed).\n//!\n//! Variables in a VDC may have 1, 2, or 3 spatial dimensions, and 0 or 1\n//! temporal dimensions.\n//!\n//! The VDC is structured in the spirit of the \"NetCDF Climate and Forecast\n//! (CF) Metadata Conventions\", version 1.6, 5, December 2011.\n//! It supports only a subset of the CF functionality (e.g. there is no\n//! support for \"Discrete Sampling Geometries\"). Moreover, it is\n//! more restrictive than the CF in a number of areas. Particular\n//! items of note include:\n//!\n//! \\li All dimensions defined in the VDC have a 1D coordinate variable\n//! associated with them with the same name as the dimension.\n//!\n//! \\li The API supports variables with 1 to 4 dimensions only.\n//!\n//! \\li Coordinate variables representing time must be 1D\n//!\n//! \\li All data variables have a \"coordinate\" attribute identifying\n//! the coordinate (or auxilliary coordinate) variables associated with\n//! each axis\n//!\n//! \\li To be consistent with VAPOR, when specified in vector form the\n//! ordering of dimension lengths\n//! and dimension names is from fastest varying dimension to slowest.\n//! For example, if\n//! 'dims' is a vector of dimensions, then dims[0] is the fastest varying\n//! dimension, dim[1] is the next fastest, and so on. This ordering is the\n//! opposite of the ordering used by NetCDF.\n//!\n//! This class inherits from Wasp::MyBase. Unless otherwise documented\n//! any method that returns an integer value is returning status. A negative\n//! value indicates failure. Error messages are logged via\n//! Wasp::MyBase::SetErrMsg(). Methods that return a boolean do\n//! not, unless otherwise documented, log an error message upon\n//! failure (return of false).\n//!\n//! \\param level\n//! \\parblock\n//! Grid refinement level for multiresolution variables.\n//! Compressed variables in the VDC have a multi-resolution\n//! representation: the sampling grid for multi-resolution variables\n//! is hierarchical, and the dimension lengths of adjacent levels in the\n//! hierarchy differ by a factor of two. The \\p level parameter is\n//! used to select a particular depth of the hierarchy.\n//!\n//! To provide maximum flexibility as well as compatibility with previous\n//! versions of the VDC the interpretation of \\p level is somewhat\n//! complex. Both positive and negative values may be used to specify\n//! the refinement level and have different interpretations.\n//!\n//! For positive\n//! values of \\p level, a value of \\b 0 indicates the coarsest\n//! member of the\n//! grid hierarchy. A value of \\b 1 indicates the next grid refinement\n//! after the coarsest, and so on. Using postive values the finest level\n//! in the hierarchy is given by GetNumRefLevels() - 1. Values of \\p level\n//! that are greater than GetNumRefLevels() - 1 are treated as if they\n//! were equal to GetNumRefLevels() - 1.\n//!\n//! For negative values of \\p level a value of -1 indicates the\n//! variable's native grid resolution (the finest resolution available).\n//! A value of -2 indicates the next coarsest member in the hierarchy after\n//! the finest, and so\n//! on. Using negative values the coarsest available level in the hierarchy is\n//! given by negating the value returned by GetNumRefLevels(). Values of\n//! \\p level that are less than the negation of GetNumRefLevels() are\n//! treated as if they were equal to the negation of the GetNumRefLevels()\n//! return value.\n//! \\endparblock\n//! \\param lod\n//! \\parblock\n//! The level-of-detail parameter, \\p lod, selects\n//! the approximation level for a compressed variable.\n//! The \\p lod parameter is similar to the \\p level parameter in that it\n//! provides control over accuracy of a compressed variable. However, instead\n//! of selecting the grid resolution the \\p lod parameter controls\n//! the compression factor by indexing into the \\p cratios vector (see below).\n//! As with the \\p level parameter, both positive and negative values may be\n//! used to index into \\p cratios and\n//! different interpretations.\n//!\n//! For positive\n//! values of \\p lod, a value of \\b 0 indicates the\n//! the first element of \\p cratios, a value of \\b 1 indicates\n//! the second element, and so on up to the size of the\n//! \\p cratios vector (See DC::GetCRatios()).\n//!\n//! For negative values of \\p lod a value of \\b -1 indexes the\n//! last element of \\p cratios, a value of \\b -2 indexes the\n//! second to last element, and so on.\n//! Using negative values the first element of \\p cratios - the greatest\n//! compression rate - is indexed by negating the size of the\n//! \\p cratios vector.\n//! \\endparblock\n//! \\param cratios A monotonically decreasing vector of\n//! compression ratios. Compressed variables in the VDC are stored\n//! with a fixed, finite number of compression factors. The \\p cratios\n//! vector is used to specify the available compression factors (ratios).\n//! A compression factor of 1 indicates no compression (1:1). A value\n//! of 2 indciates two to one compression (2:1), and so on. The minimum\n//! valid value of \\p cratios is \\b 1. The maximum value is determined\n//! by a number of factors and can be obtained using the CompressionInfo()\n//! method.\n//!\n//! \\param wname Name of wavelet used for transforming compressed\n//! variables between wavelet and physical space. Valid values\n//! are \"bior1.1\", \"bior1.3\", \"bior1.5\", \"bior2.2\", \"bior2.4\",\n//! \"bior2.6\", \"bior2.8\", \"bior3.1\", \"bior3.3\", \"bior3.5\", \"bior3.7\",\n//! \"bior3.9\", \"bior4.4\"\n//!\n//!\nclass VDF_API VDC : public VAPoR::DC {\npublic:\n    //! Read, Write, Append access mode\n    //!\n    enum AccessMode { R, W, A };\n\n    //! Class constuctor\n    //!\n    //!\n    VDC();\n    virtual ~VDC() {}\n\nprotected:\n    //! Initialize the VDC class\n    //!\n    //! Prepare a VDC for reading or writing/appending. This method prepares\n    //! the master VDC file indicated by \\p path for reading or writing.\n    //! The method should be called immediately after the constructor,\n    //! before any other class methods. This method\n    //! exists only because C++ constructors can not return error codes.\n    //!\n    //! \\param[in] path A single element vector that specifies the name of file\n    //! that contains, or will\n    //! contain, the VDC master file for this data collection\n    //! \\param[in] mode One of \\b R, \\b W, or \\b A, indicating whether \\p path\n    //! will be opened for reading, writing, or appending, respectively.\n    //! When \\p mode is \\b A underlying NetCDF files will be opened\n    //! opened with \\em nc_open(path, NC_WRITE)). When \\p mode is \\b W\n    //! NetCDF files will be created (opened with \\em nc_create(path)).\n    //! When \\p mode is \\b A additional time steps may be added to\n    //! an existing file.\n    //!\n    //! \\p bs is a three-element array, with the first element\n    //! specifying the length of the fastest varying spatial dimension (e.g. X) of\n    //! the storage block, the\n    //! second element specifies the length of the next fastest varying\n    //! dimension, etc. If a variable definition defines a variable with \\b n\n    //! spatial , where \\b n is less than three, only the\n    //! first \\b n elements\n    //! of \\p bs will be used. For example, if the rank of \\b bs is greater than\n    //! two a 2D variable will be stored in\n    //! blocks having dimensions \\b bs[0] x \\b bs[1]. Time dimensions are\n    //! never blocked. This parameter is ignored unless \\p mode is W.\n    //!\n    //! \\note The parameter \\p mode controls the access to the master\n    //! file indicated by \\p path and the variable data files in a somewhat\n    //! unintuitive manner.  If \\p mode is \\b R or \\b A the master file \\p path\n    //! must already exist. If \\p mode is\n    //! \\b A or \\b W the contents of the VDC master may be changed (written)\n    //! and the\n    //! VDC is put into \\b define mode until EndDefine()\n    //! is called. While in \\b define mode metadata that will be contained\n    //! in the VDC master file may be changed, but coordinate and data variables\n    //! may not be accessed (read or written). Similarly, when not in define\n    //! mode coordinate\n    //! and data variables may be accessed (read or written), but metadata\n    //! in the VDC master may not be changed. See OpenVariableRead() and\n    //! OpenVariableWrite() for discussion on how \\p mode effects reading\n    //! and writing of coordinate and data variables.\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa EndDefine();\n    //\n    virtual int initialize(const std::vector<string> &paths, const std::vector<string> &options, AccessMode mode, vector<size_t> bs);\n    virtual int initialize(const std::vector<string> &paths, const std::vector<string> &options) { return (initialize(paths, options, R, vector<size_t>())); }\n\npublic:\n    //! Sets various parameters for storage blocks for subsequent variable\n    //! definitions\n    //!\n    //! This method sets the storage parameters for subsequent variable\n    //! definitions for compressed variables.\n    //!\n    //! Variables whose spatial dimension lengths are less than the coresponding\n    //! dimension of \\p bs will be padded to block boundaries.\n    //!\n    //! \\p wname set the wavelet family name and\n    //! boundary handling mode\n    //! for subsequent compressed variable definitions.\n    //! Wider wavelets (those requiring\n    //! more filter coefficients) will typically yield higher compression rates,\n    //! but are more computationally expensive and will limit the depth of\n    //! of the grid resolution refinement hierarchy.\n    //!\n    //! Recommended values for \\p wname are \\e bior1.1, \\e bior1.3, \\e bior1.5\n    //! \\e bior3.3, \\e bior3.5, \\e bior3.7, \\e bior3.9, \\e bior2.2, \\e bior2.6,\n    //! \\e bior2.6, and \\e bior2.8. For odd length filters (e.g. bior1.3)\n    //!\n    //! Finally, \\p cratios specifies a vector of compression factors for\n    //! subsequent compressed variable definitions.\n    //!\n    //! \\note For compressed variables compression is applied to individual blocks.\n    //! Larger blocks permit deeper grid refinement hierarchies, but may\n    //! result in poor cache performance and slowed disk storage access\n    //!\n    //! \\note The wavelet and compression ratio parameters are ignored by variable\n    //! definitions for variables that are not compressed.\n    //!\n    //!\n    //! \\param[in] wname A wavelet family name. The default value is \"bior4.4\".\n    //! \\param[in] cratios A vector of compression of integer compression\n    //! factors.\n    //! The default compression ratio vector is: (1, 10, 100, 500)\n    //!\n    //! \\retval status A negative int is returned if an invalid parameter\n    //! or parameter combination is specified.\n    //!\n    //! \\sa DefineDataVar(), DefineCoordVar(), VDC()\n    //\n    int SetCompressionBlock(string wname, std::vector<size_t> cratios);\n\n    //! Retrieve current compression block settings.\n    //!\n    //! \\param[out] bs An ordered vector containing the current compression\n    //! block dimensions.\n    //! \\param[out] wname The wavelet family name.\n    //! \\param[out] cratios A vector of compression of integer compression\n    //! factors.\n    //!\n    //! \\sa SetCompressionBlock()\n    //\n    void GetCompressionBlock(std::vector<size_t> &bs, string &wname, std::vector<size_t> &cratios) const;\n\n    //! Set the boundary periodic for subsequent variable definitions\n    //!\n    //! This method specifies an ordered, three-element boolean vector\n    //! indicating the boundary periodicty for a variable's spatial\n    //! dimensions. The ordering is from fastest to slowest varying dimension.\n    //!\n    //! \\param[in] periodic A three-element array of booleans. The\n    //! default value of \\p periodic is (\\b false, \\b false, \\b false).\n    //!\n    //! \\retval status A negative int is returned on error\n    //!\n    void SetPeriodicBoundary(std::vector<bool> periodic)\n    {\n        _periodic = periodic;\n        for (int i = _periodic.size(); i < 3; i++) _periodic.push_back(false);\n    }\n\n    //! Retrieve current boundary periodic settings\n    //!\n    //! \\sa SetPeriodicBoundary()\n    //\n    std::vector<bool> GetPeriodicBoundary() const { return (_periodic); };\n\n    //! Define a dimension in the VDC\n    //!\n    //! This method specifies the name, and length of a dimension.\n    //! A variable in the VDC may have one to four dimensions (one to\n    //! three spatial, and zero or one temporal).  Dimensions may be of\n    //! any length\n    //! greater than or equal to one.\n    //!\n    //! This method must be called prior to defining any variables requring\n    //! the defined dimensions.\n    //!\n    //! There are no default dimensions defined.\n    //!\n    //! It is an error to call this method if the VDC master is not currently\n    //! in \\b define mode.\n    //!\n    //! \\param[in] dimname A string specifying the name of the dimension.\n    //! \\param[in] length The dimension length, which must be greater than zero.\n    //!\n    //! \\note When the VDC master file is initialized in\n    //! append (\\b mode = \\b A)\n    //! mode it is an error to redefine an\n    //! existing dimension. New dimensions may, however, be defined.\n    //!\n    //! \\retval status A negative int is returned on error\n    //!\n    //! \\sa DefineCoordVar(), DefineDataVar(), GetDimension()\n    //\n    int DefineDimension(string dimname, size_t length);\n\n    //! Define a dimension in the VDC and an associated coordinate variable\n    //!\n    //! This method defines a dimension and a 1D, unitless coordinate variable\n    //! with the same name.\n    //!\n    //! It is an error to call this method if the VDC master is not currently\n    //! in \\b define mode.\n    //!\n    //! \\param[in] name A string specifying the name of the dimension, and the\n    //! coordinate variable.\n    //! \\param[in] length The dimension length, which must be greater than zero.\n    //! \\param[in] axis An integer indicating the spatial or temporal\n    //! coordinate axis. Acceptable values are \\b 0 (for X or longitude),\n    //! \\b 1 (for Y or latitude), \\b 2 (for Z or vertical), and \\b 3 (for time).\n    //!\n    //! \\retval status A negative int is returned on error\n    //!\n    //! \\sa DefineCoordVar(), DefineDataVar(), GetDimension()\n    //\n    int DefineDimension(string dimname, size_t length, int axis);\n\nprotected:\n    //! \\copydoc DC:getDimension()\n    //\n    bool getDimension(string dimname, DC::Dimension &dimension) const;\n\n    //! \\copydoc DC:getDimensionNames()\n    //\n    std::vector<string> getDimensionNames() const;\n\n    //! \\copydoc DC:getMeshNames()\n    //\n    std::vector<string> getMeshNames() const;\n\n    virtual bool getMesh(string mesh_name, DC::Mesh &mesh) const;\n\n    //! \\copydoc DC::GetCoordVarInfo()\n    //\n    bool getCoordVarInfo(string varname, DC::CoordVar &cvar) const;\n\n    //! \\copydoc DC::GetDataVarInfo()\n    //\n    bool getDataVarInfo(string varname, DC::DataVar &datavar) const;\n\n    //! \\copydoc DC::GetAuxVarInfo()\n    //\n    bool getAuxVarInfo(string varname, DC::AuxVar &var) const { return (false); }\n\n    //! \\copydoc DC::GetBaseVarInfo()\n    //\n    bool getBaseVarInfo(string varname, DC::BaseVar &var) const;\n\n    virtual std::vector<string> getDataVarNames() const;\n\n    virtual std::vector<string> getAuxVarNames() const { return (vector<string>()); }\n\n    virtual std::vector<string> getCoordVarNames() const;\n\n    //! \\copydoc DC:GetNumRefLevels()\n    //\n    size_t getNumRefLevels(string varname) const;\n\n    bool getAtt(string varname, string attname, vector<double> &values) const;\n    bool getAtt(string varname, string attname, vector<long> &values) const;\n    bool getAtt(string varname, string attname, string &values) const;\n\n    std::vector<string> getAttNames(string varname) const;\n\n    XType getAttType(string varname, string attname) const;\n\n    virtual vector<size_t> getBlockSize() const { return (_bs); }\n\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const = 0;\n\n    virtual string getMapProjection(string varname) const;\n\n    virtual string getMapProjection() const;\n\n    virtual string getMapProjectionDefault() const { return (getMapProjection()); }\n\n    virtual int openVariableRead(size_t ts, string varname, int level = 0, int lod = 0) = 0;\n\n    virtual int closeVariable(int fd) = 0;\n\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) = 0;\n    virtual int readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) = 0;\n\npublic:\n    //! Define a coordinate variable\n    //!\n    //! This method provides the definition for a coordinate variable: a\n    //! variable providing spatial or temporal coordinates for a subsequently\n    //! defined data variable.\n    //!\n    //! If the variable's name, \\p varname, matches a dimension defined\n    //! with DefineDimension(), only the units and external data type\n    //! may differ from the 1D coordinate variable impliclity defined by\n    //! DefineDimension()\n    //!\n    //! \\param[in] varname The name of the coordinate variable.\n    //! \\param[in] dimnames An ordered vector specifying the variable's spatial\n    //! dimension names. The dimension names must have previously been defined\n    //! with the DefineDimension() method.\n    //! \\param[in] time_dim_name The name of the time varying dimension, if any.\n    //! \\param[in] units This parameter specifies a string describing the\n    //! units of measure for the\n    //! variable. The string is compatible with the Unidata udunits2 conversion\n    //! package. If the quantity is unitless an empty string may be specified.\n    //! \\param[in] axis An integer indicating the spatial or temporal\n    //! coordinate axis. Acceptable values are \\b 0 (for X or longitude),\n    //! \\b 1 (for Y or latitude), \\b 2 (for Z or vertical), and \\b 3 (for time).\n    //! \\param[in] type The primitive data type storage format.\n    //! Currently supported values\n    //! are \\b FLOAT. This is the type that will be used to store the\n    //! variable on disk\n    //! \\param[in] compressed A boolean indicating whether the\n    //! coordinate variable is\n    //! to be wavelet transformed.\n    //!\n    //! It is an error to call this method if the VDC master is not currently\n    //! in \\b define mode.\n    //!\n    //! \\note Temporal coordinate variables (axis=3) must have exactly one\n    //! dimension.\n    //!\n    //! \\note When in append (\\b A) mode it is an error to redefine an\n    //! existing variable.\n    //!\n    //! \\retval status A negative int is returned on error\n    //!\n    //! \\sa DefineDimension(), DefineCoordVar(), SetCompressionBlock()\n    //\n    int DefineCoordVar(string varname, std::vector<string> dimnames, string time_dim_name, string units, int axis, XType type, bool compressed);\n\n    //! Define a coordinate variable with uniform sampling\n    //!\n    //! This method provides the definition for a uniform coordinate variable.\n    //! A uniformly sampled coordinate variable is a variable\n    //! for which the coordinates along the fastest varying axis\n    //! may be given by <em> i * dx </em>, where\n    //! \\em i is an index starting from zero, and \\em dx is a real number\n    //! representing the spacing between points.\n    //!\n    //! One-dimensional coordinate variables that have uniform sampling\n    //! should be declared as such using this method rather than the\n    //! more general DefineCoordVar().\n    //!\n    //! \\param[in] varname The name of the coordinate variable.\n    //! \\param[in] dimnames An ordered vector specifying the variable's spatial\n    //! dimension names. The dimension names must have previously been defined\n    //! with the DefineDimension() method.\n    //! \\param[in] time_dim_name The name of the time varying dimension, if any.\n    //! \\param[in] units This parameter specifies a string describing the\n    //! units of measure for the\n    //! variable. The string is compatible with the udunits2 conversion\n    //! package. If the quantity is unitless an empty string may be specified.\n    //! \\param[in] axis An integer indicating the spatial or temporal\n    //! coordinate axis. Acceptable values are \\b 0 (for X or longitude),\n    //! \\b 1 (for Y or latitude), \\b 2 (for Z or vertical), and \\b 3 (for time).\n    //! \\param[in] type The primitive data type storage format.\n    //! Currently supported values\n    //! are \\b FLOAT\n    //! \\param[in] compressed A boolean indicating whether the\n    //! coordinate variable is\n    //! to be wavelet transformed.\n    //!\n    //! It is an error to call this method if the VDC master is not currently\n    //! in \\b define mode.\n    //!\n    //! \\note When in append (\\b A) mode it is an error to redefine an\n    //! existing variable.\n    //!\n    //! \\retval status A negative int is returned on error\n    //!\n    //! \\sa DefineDimension(), DefineCoordVar(), SetCompressionBlock()\n    //\n    int DefineCoordVarUniform(string varname, std::vector<string> dimname, string time_dim_name, string units, int axis, XType type, bool compressed);\n\n    //! Define a data variable\n    //!\n    //! This method defines a data variable in the VDC master file\n    //!\n    //! \\param[in] varname The name of the data variable.\n    //! \\param[in] dimnames An ordered vector specifying the variables\n    //! dimension names. The dimension names must have previously be defined\n    //! with the DefineDimension() method.\n    //! \\param[in] coordvars An ordered vector specifying the coordinate\n    //! variable names providing the coordinates for this variable. The\n    //! coordinate variables must have previously been defined\n    //! with the DefineCoordVar() method. Moreover, the dimension names\n    //! of each coordinate variable must be a subset of those in \\p dimnames.\n    //! \\param[in] units This parameter specifies a string describing the\n    //! units of measure for the\n    //! variable. The string is compatible with the udunits2 conversion\n    //! package. If the quantity is unitless an empty string may be specified.\n    //! \\param[in] type The primitive data type storage format.\n    //! Currently supported values\n    //! are \\b FLOAT\n    //! \\param[in] compressed A boolean indicating whether the coordinate\n    //! variable is to be wavelet transformed.\n    //!\n    //! It is an error to call this method if the VDC master is not currently\n    //! in \\b define mode.\n    //!\n    //! \\note When in append (\\b A) mode it is an error to redefine an\n    //! existing variable.\n    //!\n    //! \\sa DefineDimension(), DefineCoordVar(), SetCompressionBlock()\n    //!\n    int DefineDataVar(string varname, std::vector<string> dimnames, std::vector<string> coordvars, string units, XType type, bool compressed);\n\n    //!\n    //! Define a compressed or non-compressed data variable with missing data\n    //!\n    //! \\copydoc VDC::DefineDataVar(\n    //! \tstring varname, std::vector <string> dimnames,\n    //! \tstd::vector <string> coordvars,\n    //! \tstring units, XType type, bool compressed\n    //! \t);\n    //!\n    //! \\param[in] missing_value Specifies a value that should be used\n    //! for masked grid locations after a variable is reconstructed.\n    //!\n    //! \\param[in] maskvar Specifies the name of a variable\n    //! whose contents indicate the presense or absense of invalid\n    //! entries in the data variable. The contents of the mask array are treated\n    //! as booleans, true values indicating valid data. The rank of of the\n    //! variable may be less than or equal to that of \\p varname. The dimensions\n    //! of \\p maskvar must match the fastest varying dimensions of \\p varname.\n    //! The \\p maskvar variable must have been previously defined with\n    //! DefineDataVar(). If \\p maskvar is empty, the variable will\n    //! not be compressed.\n    //!\n    //! \\sa DefineDimension(), DefineCoordVar(), SetCompressionBlock()\n    //!\n    int DefineDataVar(string varname, std::vector<string> dimnames, std::vector<string> coordvars, string units, XType type, double missing_value, string maskvar);\n\n    //! Write an attribute\n    //!\n    //! This method write an attribute to the VDC. The attribute can either\n    //! be \"global\", if \\p varname is the empty string, or bound to a variable\n    //! if \\p varname indentifies a variable in the VDC.\n    //!\n    //! \\param[in] varname The name of a variable already defined in the VDC,\n    //! or the empty string if the attribute is to be global\n    //! \\param[in] attname The attributes name\n    //! \\param[in] type The primitive data type storage format.\n    //! This is the type that will be used to store the\n    //! attribute on disk\n    //! \\param[in] values A vector of floating point attribute values\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa GetAtt()\n    //\n    int PutAtt(string varname, string attname, XType type, const vector<double> &values);\n    int PutAtt(string varname, string attname, XType type, const vector<long> &values);\n    int PutAtt(string varname, string attname, XType type, const string &values);\n\n    //! Copy an attribute\n    //!\n    //! This method copies an attribute from the src DC. The attribute can either\n    //! be \"global\", if \\p varname is the empty string, or bound to a variable\n    //! if \\p varname indentifies a variable in the src DC.\n    //!\n    //! \\param[in] src The source DC from which to copy.\n    //! \\param[in] varname The name of the variable the attribute is bound to,\n    //! or the empty string if the attribute is global\n    //! \\param[in] attname The attributes name\n    //!\n    //! \\retval status A negative int is returned on failure. 0 returned on\n    //! success.\n    //!\n    //! \\sa PutAtt()\n    //\n    int CopyAtt(const DC &src, string varname, string attname);\n\n    //! Copy attributes\n    //!\n    //! This method copies attributes from the src DC. The attributes can either\n    //! be \"global\", if \\p varname is the empty string, or bound to a variable\n    //! if \\p varname indentifies a variable in the src DC. All attributes\n    //! associated with \\p varname are copied.\n    //!\n    //! \\param[in] src The source DC from which to copy.\n    //! \\param[in] varname The name of the variable the attribute is bound to,\n    //! or the empty string if the attribute is global\n    //!\n    //! \\retval status A negative int is returned on failure. 0 returned on\n    //! success.\n    //!\n    //! \\sa PutAtt()\n    //\n    int CopyAtt(const DC &src, string varname);\n\n    //! Set a map projection string for a data variable\n    //!\n    //! This method sets a properly formatted Proj4 map projection string\n    //! for the data variable indicated by \\p varname\n    //!\n    //! \\sa GetMapProjection()\n    //\n    virtual int SetMapProjection(string varname, string projstring);\n\n    //! Set the default Proj4 map projection for georeferenced variables\n    //!\n    //! This method sets the default Proj4 map projection string to be\n    //! used for georeferenced variables.  The string set by\n    //! \\p projstring is returned by VDC::GetMapProjection()\n    //!\n    virtual int SetMapProjection(string projstring);\n\n    //!\n    //! When the open mode \\b mode is \\b A or \\b W this method signals the\n    //! class object that metadata defintions have been completed and it\n    //! commits them to the master VDC file. This method also prepares\n    //! the VDC for the reading or writing of variable or coordinate data.\n    //!\n    //! Ignored if \\b mode is \\b R.\n    //!\n    //! \\retval status A negative it is returned if the master file is not\n    //! successfully written for any reason\n    //!\n    //! \\note The master file should not be accessed with the native file\n    //! format API (e.g. NetCDF) if the VDC is in define mode (e.g. until\n    //! after EndDefine() is called).\n    //!\n    //! \\sa VDC()\n    //!\n    int EndDefine();\n\n    //! Return the path name and temporal offset for a variable\n    //!\n    //! Data and coordinate variables in a VDC are in general distributed\n    //! into multiple files. For example, for large variables only a single\n    //! time step\n    //! may be stored per file.\n    //! This method returns the file path name, \\p path, of the file\n    //! containing \\p varname at time step \\p ts. Also returned is the\n    //! integer time offset of the variable within \\p path.\n    //!\n    //! \\param[in] varname Data or coordinate variable name.\n    //! \\param[in] ts Integer offset relative to a variable's temporal dimension\n    //! \\param[out] path Path to file containing variable \\p varname at\n    //! time step \\p ts.\n    //! \\param[out] file_ts Temporal offset of variable \\p varname in file\n    //! \\p path.\n    //! \\param[out] max_ts Maximum number of time steps stored in\n    //! \\p path\n    //!\n    //! \\retval status A negative int is returned if \\p varname or\n    //! \\p ts are invalid, or if the class object is in define mode.\n    //!\n    virtual int GetPath(string varname, size_t ts, string &path, size_t &file_ts, size_t &max_ts\n\n    ) const = 0;\n\n    //! Open the named variable for writing\n    //!\n    //! This method prepares a data or coordinate variable, indicated by a\n    //! variable name and time step pair, for subsequent write operations by\n    //! methods of this class.\n    //!\n    //! The behavior of this method is impacted somewhat by the setting\n    //! of the Initialize() \\b mode parameter. Coordinate or data variable\n    //! files may be\n    //! written regardless of the \\p mode setting. However, if\n    //! \\p mode is \\b W the first time a coordinate or data file is written\n    //! it will be created (opened with \\em nc_create(path), for example)\n    //! regareless of whether the file previously existed. If \\p\n    //! mode is \\b A or \\b R existing coordinate or data files will be opened\n    //! for appending (e.g. opened with \\em nc_open(path, NC_WRITE)). New\n    //! files will be created (opened with \\em nc_create(path)).\n    //!\n    //! An error occurs, indicated by a negative return value, if the\n    //! varible identified by the {varname, timestep, lod} tupple\n    //! is not defined.\n    //!\n    //! \\param[in] ts Time step of the variable to read. This is the integer\n    //! offset into the variable's temporal dimension. If the variable\n    //! does not have a temporal dimension \\p ts is ignored.\n    //! \\param[in] varname Name of the variable to read\n    //! \\param[in] lod Approximation level of the variable. A value of -1\n    //! indicates the maximum approximation level defined for the VDC.\n    //! Ignored if the variable is not compressed.\n    //! \\retval status Returns a non-negative value on success\n    //!\n    //! \\sa GetNumRefLevels(), DC::BaseVar::GetCRatios(), OpenVariableRead()\n    //\n    virtual int OpenVariableWrite(size_t ts, string varname, int lod = -1) = 0;\n\n    virtual int CloseVariableWrite(int fd) = 0;\n\n    //! Write all spatial values to the currently opened variable\n    //!\n    //! This method writes, and compresses as necessary,\n    //!  the contents of the array contained in\n    //! \\p data to the currently opened variable. The number of values\n    //! written from \\p data is given by the product of the spatial\n    //! dimensions of the open variable.\n    //!\n    //! \\param[in] data An array of data to be written\n    //! \\retval status Returns a non-negative value on success\n    //!\n    //! \\sa OpenVariableWrite()\n    //\n    virtual int Write(int fd, const float *data) = 0;\n    virtual int Write(int fd, const int *data) = 0;\n\n    //! Write a single slice of data to the currently opened variable\n    //!\n    //! Compress, and necessary, and write a single slice (2D array) of\n    //! data to the variable\n    //! indicated by the most recent call to OpenVariableWrite().\n    //! The dimensions of a slices are NX by NY,\n    //! where NX is the dimension of the array along the fastest varying\n    //! spatial dimension, specified\n    //! in grid points, and NY is the length of the second fastest varying\n    //! dimension at the currently opened refinement level. See\n    //! OpenVariableWrite().\n    //!\n    //! This method should be called exactly NZ times for each opened variable,\n    //! where NZ is the dimension of third, and slowest varying dimension.\n    //! In the case of a 2D variable, NZ is 1.\n    //!\n    //! \\param[in] slice A 2D slice of data\n    //! \\retval status Returns a non-negative value on success\n    //!\n    //! \\sa OpenVariableWrite()\n    //!\n    virtual int WriteSlice(int fd, const float *slice) = 0;\n    virtual int WriteSlice(int fd, const int *slice) = 0;\n    virtual int WriteSlice(int fd, const unsigned char *slice) = 0;\n\n    //! Write an entire variable in one call\n    //!\n    //! This method writes and entire variable (all time steps, all grid points)\n    //! into a VDC.  This is the simplest interface for writing data into\n    //! a VDC. If the variable is split across multiple files PutVar()\n    //! ensures that the data are correctly distributed.\n    //! Any variables currently opened with OpenVariableWrite() are first closed.\n    //! Thus variables need not be opened with OpenVariableWrite() prior to\n    //! calling PutVar();\n    //!\n    //! It is an error to call this method in \\b define mode\n    //!\n    //! \\param[in] varname Name of the variable to write\n    //! \\param[in] lod Approximation level of the variable. A value of -1\n    //! indicates the maximum approximation level defined for the VDC.\n    //! Ignored if the variable is not compressed.\n    //! \\param[in] data Pointer from where the data will be copied\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa GetVar()\n    //\n    virtual int PutVar(string varname, int lod, const float *data) = 0;\n    virtual int PutVar(string varname, int lod, const int *data) = 0;\n\n    //! Write a variable at single time step\n    //!\n    //! This method writes a variable hyperslab consisting of the\n    //! variable's entire spatial dimensions at the time step\n    //! indicated by \\p ts.\n    //! Any variables currently opened with OpenVariableWrite() are first closed.\n    //! Thus variables need not be opened with OpenVariableWrite() prior to\n    //! calling PutVar();\n    //!\n    //! It is an error to call this method in \\b define mode\n    //!\n    //! \\param[in] ts Time step of the variable to write. This is the integer\n    //! offset into the variable's temporal dimension. If the variable\n    //! does not have a temporal dimension \\p ts is ignored.\n    //! \\param[in] varname Name of the variable to write\n    //! \\param[in] lod Approximation level of the variable. A value of -1\n    //! indicates the maximum approximation level defined for the VDC.\n    //! Ignored if the variable is not compressed.\n    //! \\param[in] data Pointer from where the data will be copied\n    //!\n    //! \\retval status A negative int is returned on failure\n    //!\n    //! \\sa GetVar()\n    //\n    virtual int PutVar(size_t ts, string varname, int lod, const float *data) = 0;\n    virtual int PutVar(size_t ts, string varname, int lod, const int *data) = 0;\n\n    //! Copy a variable from another data collection to this data collection\n    //!\n    //! This method copies the variable named \\p varname from the data\n    //! collection specified by \\b dc to this data collection. The variable\n    //! must have previously been defined in this data collection.\n    //!\n    //! \\param[in] dc A reference to a source data collection\n    //! \\param[in] varname Name of variable to copy\n    //! \\param[in] srclod The level-of-detail used to open \\p varname\n    //! in \\p dc.\n    //! \\param[in] dstlod The level-of-detail used to open \\p varname\n    //! in this data collection.\n    //!\n    virtual int CopyVar(DC &dc, string varname, int srclod, int dstlod) = 0;\n\n    //! Copy a variable from another data collection to this data collection\n    //! at a single time step\n    //\n    virtual int CopyVar(DC &dc, size_t ts, string varname, int srclod, int dstlod) = 0;\n\n    //! This method computes and returns the depth (number of levels) in a\n    //! a multi-resolution hierarch for a given wavelet, \\p wname,\n    //! and decomposition block, \\p bs.\n    //! It also computes the maximum compression ratio, \\p cratio, possible\n    //! for the\n    //! the specified combination of block size, \\p bs, and wavelet, \\p wname.\n    //! The maximum compression ratio is \\p cratio:1.\n    //!\n    //! \\param[in] bs Dimensions of native decomposition block. The rank of\n    //! \\p bs may be less than or equal to the rank of \\p dims.\n    //! \\param[in] wname wavelet name. Empty string if no compression\n    //! is to be performed.\n    //! \\param[out] nlevels Number of levels in hierarchy\n    //! \\param[out] maxcratio Maximum compression ratio\n    //!\n    //! \\retval bool If \\p bs, \\p wname, or the combination there of is invalid\n    //! false is returned and the values of \\p nlevels and \\p maxcratio are\n    //! undefined. Upon success true is returned.\n    //!\n    virtual bool CompressionInfo(vector<size_t> bs, string wname, size_t &nlevels, size_t &maxcratio) const = 0;\n\n    //! Returns true if indicated data volume is available\n    //!\n    //! Returns true if the variable identified by the timestep, variable\n    //! name, refinement level, and level-of-detail is present in\n    //! the data set. Returns false if\n    //! the variable is not available.\n    //!\n    //! \\param[in] ts A valid time step between 0 and GetNumTimesteps()-1\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] reflevel Refinement level requested.\n    //! \\param[in] lod Compression level of detail requested.\n    //! refinement level contained in the VDC.\n    //\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const = 0;\n\n    friend std::ostream &operator<<(std::ostream &o, const VDC &vdc);\n\nprivate:\n    string              _proj4StringOption;\n    std::vector<string> _newUniformVars;\n\nprotected:\n    string              _master_path;\n    AccessMode          _mode;\n    bool                _defineMode;\n    std::vector<size_t> _bs;\n    string              _wname;\n    std::vector<size_t> _cratios;\n    vector<bool>        _periodic;\n    VAPoR::UDUnits      _udunits;\n\n    std::map<string, Dimension> _dimsMap;\n    std::map<string, Attribute> _atts;\n    std::map<string, CoordVar>  _coordVars;\n    std::map<string, DataVar>   _dataVars;\n    std::map<string, Mesh>      _meshes;\n\n    #ifndef DOXYGEN_SKIP_THIS\n\n    bool _ValidDefineDimension(string name, size_t length) const;\n\n    bool _ValidDefineCoordVar(string varname, vector<string> dimnames, string time_dim_name, string units, int axis, XType type, bool compressed) const;\n\n    bool _valid_blocking(const vector<DC::Dimension> &dimensions, const vector<size_t> &bs, const vector<string> &coordvars) const;\n\n    bool _valid_mask_var(string varname, vector<DC::Dimension> dimensions, vector<size_t> bs, bool compressed, string maskvar) const;\n\n    bool _ValidDefineDataVar(string varname, vector<string> dimnames, vector<string> coordnames, string units, XType type, bool compressed, bool has_missing, string maskvar) const;\n\n    bool _ValidCompressionBlock(vector<size_t> bs, string wname, vector<size_t> cratios) const;\n\n    bool _valid_dims(const vector<DC::Dimension> &dims0, const vector<size_t> &bs0, const vector<DC::Dimension> &dims1, const vector<size_t> &bs1) const;\n\n    virtual int _WriteMasterMeta() = 0;\n    virtual int _ReadMasterMeta() = 0;\n\n    void _DefineMesh(string meshname, vector<string> dim_names, vector<string> coord_vars);\n\n    int _DefineDataVar(string varname, std::vector<string> dimnames, std::vector<string> coordvars, string units, XType type, bool compressed, bool has_missing, double mv, string maskvar);\n\n    vector<string> _GetCoordVarDimNames(const CoordVar &var, bool &time_varying) const;\n\n    vector<string> _GetDataVarDimNames(const DataVar &var, bool &time_varying) const;\n\n    int _DefineImplicitCoordVars(vector<string> dim_names, vector<string> coord_vars_in, vector<string> &coord_vars_out);\n\n    #endif\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/VDCNetCDF.h",
    "content": "#include <vector>\n#include <map>\n#include <algorithm>\n#include <iostream>\n#include \"vapor/VDC.h\"\n#include \"vapor/WASP.h\"\n\n#ifndef _VDCNetCDF_H_\n    #define _VDCNetCDF_H_\n\nnamespace VAPoR {\n\n//! \\class VDCNetCDF\n//!\t\\ingroup Public_VDC\n//!\n//! \\brief Implements the VDC\n//! abstract class, providing storage of VDC data\n//! in NetCDF files.\n//!\n//! \\author John Clyne\n//! \\date    July, 2014\n//!\n//! Implements the VDC abstract class, providing storage of VDC data\n//! in NetCDF files. Data (variables) are stored in multiple NetCDF files.\n//! The distribution of variables to files is described by GetPath().\n//!\nclass VDF_API VDCNetCDF : public VAPoR::VDC {\npublic:\n    //! Class constructor\n    //!\n    //! \\param[in] numthreads Number of parallel execution threads\n    //! to be run during encoding and decoding of compressed data. A value\n    //! of 0, the default, indicates that the thread count should be\n    //! determined by the environment in a platform-specific manner, for\n    //! example using sysconf(_SC_NPROCESSORS_ONLN) under *nix OSes.\n    //!\n    //! \\param[in] master_theshold Variables that are either compressed, or whose\n    //! total number of elements are larger than \\p master_theshold, will\n    //! not be stored in the master file. Ignored if the file is open\n    //! for appending or reading.\n    //!\n    //! \\param[in] variable_threshold Variables not stored in the master\n    //! file and whose\n    //! total number of elements are larger than \\p variable_threshold\n    //! will be stored with one time step per file. Ignored if the file is open\n    //! for appending or reading.\n    //\n    VDCNetCDF(int numthreads = 0, size_t master_theshold = 10 * 1024 * 1024, size_t variable_threshold = 100 * 1024 * 1024);\n    virtual ~VDCNetCDF();\n\n    //! \\copydoc DC:GetHyperSliceInfo()\n    //!\n    //! Override base class to ensure hyperslices are block aligned\n    //!\n    virtual int GetHyperSliceInfo(string varname, int level, std::vector<size_t> &dims, size_t &nslice);\n\n    //! Return path to the data directory\n    //!\n    //! Return the file path to the data directory associated with the\n    //! master file named by \\p path. Data files, those NetCDF files\n    //! containing coordinate and data variables, are stored in separate\n    //! files from\n    //! the VDC master file (See VDC::Initialize()). The data files reside\n    //! under the directory returned by this command.\n    //!\n    //! \\param[in] path Path to VDC master file\n    //!\n    //! \\retval dir : Path to the data directory\n    //! \\sa Initialize(), GetPath(), DataDirExists()\n    //\n    static string GetDataDir(string path);\n\n    //! \\copydoc VDC::GetPath()\n    //!\n    //! \\par Algorithm\n    //! If the size of a variable (total number of elements) is less than\n    //! GetMasterThreshold() and the variable is not compressed it will\n    //! be stored in the file master file. Otherwise, the variable will\n    //! be stored in either the coordinate variable or data variable\n    //! directory, as appropriate. Variables stored in coordinate or\n    //! data directories are stored one variable per file. If the size\n    //! of the variable is less than GetVariableThreshold() and the\n    //! variable is time varying multiple time steps may be saved in a single\n    //! file. If the variable is compressed each compression level is stored\n    //! in a separate file.\n    //!\n    //! \\sa VDCNetCDF::VDCNetCDF(), GetMasterThreshold(), GetVariableThreshold()\n    //!\n    virtual int GetPath(string varname, size_t ts, string &path, size_t &file_ts, size_t &max_ts) const;\n\n    //! \\copydoc VDC::GetDimLensAtLevel()\n    //\n    virtual int getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, vector<size_t> &bs_at_level) const;\n\n    //! Return true if a data directory exists for the master file\n    //! named by \\p path\n    //!\n    //! \\param[in] path Path to VDC master file\n    //!\n    //! \\sa Initialize(), GetPath(), GetDataDir();\n    //\n    static bool DataDirExists(string path);\n\n    //! Initialize the VDCNetCDF class\n    //! \\copydoc VDC::Initialize()\n    //!\n    //! \\param[in] chunksizehint : NetCDF chunk size hint.  A value of\n    //! zero results in NC_SIZEHINT_DEFAULT being used.\n    //\n    virtual int Initialize(const vector<string> &paths, const vector<string> &options = {}, AccessMode mode = VDC::R, vector<size_t> bs = {64, 64, 64}, size_t chunksizehint = 0);\n    virtual int Initialize(string path, const vector<string> &options, AccessMode mode, vector<size_t> bs = {64, 64, 64}, size_t chunksizehint = 0)\n    {\n        std::vector<string> paths;\n        paths.push_back(path);\n        return (Initialize(paths, options, mode, bs, chunksizehint));\n    }\n\n    //! Return the master file size threshold\n    //!\n    //! \\sa VDCNetCDF::VDCNetCDF(), GetVariableThreshold()\n    //\n    size_t GetMasterThreshold() const { return _master_threshold; };\n\n    //! Return the variable size  threshold\n    //!\n    //! \\sa VDCNetCDF::VDCNetCDF(), GetMasterThreshold()\n    //\n    size_t GetVariableThreshold() const { return _variable_threshold; };\n\n    //! \\copydoc VDC::OpenVariableWrite()\n    //\n    int OpenVariableWrite(size_t ts, string varname, int lod = -1);\n\n    int CloseVariableWrite(int fd) { return (closeVariable(fd)); };\n\n    //! \\copydoc VDC::Write()\n    //\n    int Write(int fd, const float *region) { return (_writeTemplate(fd, region)); }\n    int Write(int fd, const int *region) { return (_writeTemplate(fd, region)); }\n\n    int WriteSlice(int fd, const float *slice) { return (_writeSliceTemplate(fd, slice)); };\n    int WriteSlice(int fd, const int *slice) { return (_writeSliceTemplate(fd, slice)); };\n    int WriteSlice(int fd, const unsigned char *slice) { return (_writeSliceTemplate(fd, slice)); }\n\n    //! \\copydoc VDC::PutVar()\n    //\n    int PutVar(string varname, int lod, const float *data) { return (_putVarTemplate(varname, lod, data)); }\n    int PutVar(string varname, int lod, const int *data) { return (_putVarTemplate(varname, lod, data)); }\n\n    //! \\copydoc VDC::PutVar()\n    //\n    int PutVar(size_t ts, string varname, int lod, const float *data) { return (_putVarTemplate(ts, varname, lod, data)); }\n    int PutVar(size_t ts, string varname, int lod, const int *data) { return (_putVarTemplate(ts, varname, lod, data)); }\n\n    int CopyVar(DC &dc, string varname, int srclod, int dstlod);\n    int CopyVar(DC &dc, size_t ts, string varname, int srclod, int dstlod);\n\n    //! \\copydoc VDC::CompressionInfo()\n    //\n    bool CompressionInfo(std::vector<size_t> bs, string wname, size_t &nlevels, size_t &maxcratio) const;\n\n    //! Enable or disable the NetCDF fill-value mode\n    //!\n    //! Enable or disable the NetCDF fill-value mode\n    //!\n    //! \\param[in] fillmode NC_FILL as 0x0 or NC_NOFILL as 0x100\n    //!\n    //! \\retval err: NC_NOERR on success\n    //\n    int SetFill(int fillmode);\n\nprotected:\n    #ifndef DOXYGEN_SKIP_THIS\n    virtual int _WriteMasterMeta();\n    virtual int _ReadMasterMeta();\n    #endif\n\n    int openVariableRead(size_t ts, string varname, int level = 0, int lod = -1);\n\n    int closeVariable(int fd);\n\n    int readRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region);\n    int readRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, double *region);\n    int readRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, int *region);\n\n    virtual bool variableExists(size_t ts, string varname, int reflevel = 0, int lod = 0) const;\n\nprivate:\n    string _version;\n    WASP * _master;    // Master NetCDF file\n\n    class VDCFileObject : public DC::FileTable::FileObject {\n    public:\n        VDCFileObject(size_t ts, string varname, int level, int lod, size_t file_ts, WASP *wasp_data, WASP *wasp_mask, string varname_mask, int level_mask, size_t file_ts_mask, double mv)\n        : FileObject(ts, varname, level, lod), _file_ts(file_ts), _wasp_data(wasp_data), _wasp_mask(wasp_mask), _varname_mask(varname_mask), _level_mask(level_mask), _file_ts_mask(file_ts_mask),\n          _mv(mv)\n        {\n        }\n\n        size_t GetFileTS() const { return (_file_ts); }\n        WASP * GetWaspData() const { return (_wasp_data); }\n        WASP * GetWaspMask() const { return (_wasp_mask); }\n        string GetVarnameMask() const { return (_varname_mask); }\n        int    GetLevelMask() const { return (_level_mask); }\n        size_t GetFileTSMask() const { return (_file_ts_mask); }\n        double GetMissingValue() const { return (_mv); }\n\n    private:\n        size_t _file_ts;\n        WASP * _wasp_data;\n        WASP * _wasp_mask;\n        string _varname_mask;\n        int    _level_mask;\n        size_t _file_ts_mask;\n        double _mv;\n    };\n\n    Wasp::SmartBuf _sb_slice_buffer;\n    Wasp::SmartBuf _mask_buffer;\n\n    size_t _chunksizehint;    // NetCDF chunk size hint for file creates\n    size_t _master_threshold;\n    size_t _variable_threshold;\n    int    _nthreads;\n\n    int _WriteMasterDimensions();\n    int _WriteMasterAttributes(string prefix, const map<string, Attribute> &atts);\n    int _WriteMasterAttributes();\n    int _WriteMasterMeshDefs();\n    int _WriteMasterBaseVarDefs(string prefix, const BaseVar &var);\n    int _WriteMasterCoordVarsDefs();\n    int _WriteMasterDataVarsDefs();\n\n    template<class T> int _writeTemplate(int fd, const T *data);\n\n    template<class T> int _writeSliceTemplate(int fd, const T *slice);\n\n    int _ReadMasterDimensions();\n    int _ReadMasterAttributes(string prefix, map<string, Attribute> &atts);\n    int _ReadMasterAttributes();\n    int _ReadMasterMeshDefs();\n    int _ReadMasterBaseVarDefs(string prefix, BaseVar &var);\n    int _ReadMasterCoordVarsDefs();\n    int _ReadMasterDataVarsDefs();\n\n    template<class T> int _ReadSlice(WASP *file, T *slice);\n\n    int _PutAtt(WASP *ncdf, string varname, string tag, const Attribute &attr);\n\n    int _WriteAttributes(WASP *wasp, string varname, const map<string, Attribute> &atts);\n    int _DefBaseVar(WASP *ncdf, const VDC::BaseVar &var, size_t max_ts);\n    int _DefDataVar(WASP *ncdf, const VDC::DataVar &var, size_t max_ts);\n    int _DefCoordVar(WASP *ncdf, const VDC::CoordVar &var, size_t max_ts);\n\n    bool _var_in_master(const VDC::BaseVar &var) const;\n\n    string _get_mask_varname(string varname, double &mv) const;\n\n    unsigned char *_read_mask_var(WASP *wasp, string varname, string varname_mask, vector<size_t> start, vector<size_t> count);\n\n    WASP *_OpenVariableRead(size_t ts, string varname, int clevel, int lod, size_t &file_ts);\n\n    int _ReadHelper(vector<size_t> &start, vector<size_t> &count) const;\n\n    template<class T> int _putVarTemplate(string varname, int lod, const T *data);\n\n    template<class T> int _putVarTemplate(size_t ts, string varname, int lod, const T *data);\n\n    int _copyVar0d(DC &dc, size_t ts, const BaseVar &varInfo);\n\n    template<class T>\n    int _copyVarHelper(DC &dc, int fdr, int fdw, vector<size_t> &buffer_dims, vector<size_t> &src_hslice_dims, vector<size_t> &dst_hslice_dims, size_t src_nslice, size_t dst_nslice, T *buffer);\n\n    template<class T> int _readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region);\n};\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/VDC_c.h",
    "content": "#ifndef _VDC_C_H_\n#define _VDC_C_H_\n\n#define VDC_AccessMode_R 1\n#define VDC_AccessMode_W 2\n#define VDC_AccessMode_A 3\n\n#define VDC_XType         int\n#define VDC_XType_INVALID -1\n#define VDC_XType_FLOAT   1\n#define VDC_XType_DOUBLE  2\n#define VDC_XType_INT32   3\n#define VDC_XType_INT64   4\n#define VDC_XType_TEXT    5\n\n#define VDCDimension_Axis_X 0\n#define VDCDimension_Axis_Y 1\n#define VDCDimension_Axis_Z 2\n#define VDCDimension_Axis_T 3\n\n#ifdef __cplusplus\n\n    #include \"vapor/VDC.h\"\ntypedef VAPoR::VDCNetCDF      VDC;\ntypedef VAPoR::VDC::Dimension VDCDimension;\ntypedef VAPoR::VDC::BaseVar   VDCBaseVar;\ntypedef VAPoR::VDC::AuxVar    VDCAuxVar;\ntypedef VAPoR::VDC::DataVar   VDCDataVar;\ntypedef VAPoR::VDC::CoordVar  VDCCoordVar;\nextern \"C\" {\n\n#else\n\ntypedef struct VDCNetCDF    VDC;\ntypedef struct VDCDimension VDCDimension;\ntypedef struct VDCBaseVar   VDCBaseVar;\ntypedef struct VDCAuxVar    VDCAuxVar;\ntypedef struct VDCDataVar   VDCDataVar;\ntypedef struct VDCCoordVar  VDCCoordVar;\n\n#endif\n\nVDCDimension *VDCDimension_new();\nvoid          VDCDimension_delete(VDCDimension *p);\nvoid          VDCDimension_GetName(const VDCDimension *p, char **name);\nsize_t        VDCDimension_GetLength(const VDCDimension *p);\nint           VDCDimension_IsTimeVarying(const VDCDimension *p);\n\nVDCBaseVar *VDCBaseVar_new();\nvoid        VDCBaseVar_delete(VDCBaseVar *p);\nvoid        VDCBaseVar_GetName(const VDCBaseVar *p, char **name);\nvoid        VDCBaseVar_GetUnits(const VDCBaseVar *p, char **units);\nint         VDCBaseVar_GetXType(const VDCBaseVar *p);\nvoid        VDCBaseVar_GetWName(const VDCBaseVar *p, char **name);\nvoid        VDCBaseVar_GetCRatios(const VDCBaseVar *p, size_t **ratios, int *count);\nvoid        VDCBaseVar_GetBS(const VDCBaseVar *p, size_t **bs, int *count);\nvoid        VDCBaseVar_GetPeriodic(const VDCBaseVar *p, long **periodic, int *count);\nvoid        VDCBaseVar_GetAttributeNames(const VDCBaseVar *p, char ***names, int *count);    // Return names instead of objects\nint         VDCBaseVar_IsCompressed(const VDCBaseVar *p);\n\nVDCAuxVar *VDCAuxVar_new();\nvoid       VDCAuxVar_delete(VDCAuxVar *p);\nvoid       VDCAuxVar_GetDimNames(const VDCAuxVar *p, char ***names, int *count);\n\nVDCDataVar *VDCDataVar_new();\nvoid        VDCDataVar_delete(VDCDataVar *p);\nvoid        VDCDataVar_GetMeshName(const VDCDataVar *p, char **name);\nvoid        VDCDataVar_GetTimeCoordVar(const VDCDataVar *p, char **name);\n// GetSamplingLocation\nvoid   VDCDataVar_GetMaskvar(const VDCDataVar *p, char **name);\nint    VDCDataVar_GetHasMissing(const VDCDataVar *p);\ndouble VDCDataVar_GetMissingValue(const VDCDataVar *p);\n\nVDCCoordVar *VDCCoordVar_new();\nvoid         VDCCoordVar_delete(VDCCoordVar *p);\nvoid         VDCCoordVar_GetDimNames(const VDCCoordVar *p, char ***names, int *count);\nvoid         VDCCoordVar_GetTimeDimName(const VDCCoordVar *p, char **name);\nint          VDCCoordVar_GetAxis(const VDCCoordVar *p);\nint          VDCCoordVar_GetUniform(const VDCCoordVar *p);\n\nVDC *VDC_new();\nvoid VDC_delete(VDC *p);\nint  VDC_InitializeDefaultBS(VDC *p, const char *path, int mode);\nint  VDC_Initialize(VDC *p, const char *path, int mode, size_t *bs, int bsCount);\n\nint  VDC_GetDimension(const VDC *p, const char *dimname, VDCDimension *dimension);\nvoid VDC_GetDimensionNames(const VDC *p, char ***names, int *count);\nint  VDC_GetCoordVarInfo(const VDC *p, const char *varname, VDCCoordVar *var);\nint  VDC_GetDataVarInfo(const VDC *p, const char *varname, VDCDataVar *var);\nint  VDC_GetBaseVarInfo(const VDC *p, const char *varname, VDCBaseVar *var);\nvoid VDC_GetDataVarNames(const VDC *p, char ***names, int *count);\nvoid VDC_GetCoordVarNames(const VDC *p, char ***names, int *count);\nint  VDC_GetNumRefLevels(const VDC *p, const char *varname);\nint  VDC_GetAtt_long(const VDC *p, const char *varname, const char *attname, long **values, int *count);\nint  VDC_GetAtt_double(const VDC *p, const char *varname, const char *attname, double **values, int *count);\nint  VDC_GetAtt_text(const VDC *p, const char *varname, const char *attname, char **text);\nint  VDC_GetAtt_Count(const VDC *p, const char *varname, const char *attname, int *count);\nvoid VDC_GetAttNames(const VDC *p, const char *varname, char ***names, int *count);\nint  VDC_GetAttType(const VDC *p, const char *varname, const char *attname);\nint  VDC_VariableExists(const VDC *p, size_t ts, const char *varname, int reflevel, int lod);\nint  VDC_IsTimeVarying(const VDC *p, const char *varname);\nint  VDC_CoordVarExists(const VDC *p, const char *varname);\n\nint VDC_GetCRatios(const VDC *p, const char *varname, size_t **ratios, int *count);\nint VDC_GetCRatiosCount(const VDC *p, const char *varname);\n\nint VDC_GetVarDimLens(const VDC *p, const char *varname, int spatial, size_t **lens, int *count);\nint VDC_GetVarDimNames(const VDC *p, const char *varname, int spatial, char ***names, int *count);\nint VDC_GetVarCoordVars(const VDC *p, const char *varname, int spatial, char ***names, int *count);\nint VDC_GetVarDimLensAtLevel(const VDC *p, const char *varname, int level, size_t **lens, int *count);\n\nint VDC_OpenVariableRead(VDC *p, size_t ts, const char *varname, int level, int lod);\nint VDC_CloseVariable(VDC *p, int fd);\nint VDC_Read(VDC *p, int fd, float *region);\nint VDC_ReadSlice(VDC *p, int fd, float *slice);\nint VDC_ReadRegion(VDC *p, int fd, const size_t *min, const size_t *max, const int dims, float *region);\nint VDC_GetVar(VDC *p, const char *varname, int level, int lod, float *data);\nint VDC_GetVarAtTimeStep(VDC *p, size_t ts, const char *varname, int level, int lod, float *data);\n\n// Write\n\nint VDC_SetCompressionBlock(VDC *p, const char *wname, const size_t *cratios, int cratiosCount);\nint VDC_DefineDimension(VDC *p, const char *dimname, size_t length);\nint VDC_DefineDimensionWithAxis(VDC *p, const char *dimname, size_t length, int axis);\nint VDC_DefineDataVar(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char **coordvars, size_t coordvarCount, const char *units, VDC_XType xtype, int compressed);\nint VDC_DefineCoordVar(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char *time_dim_name, const char *units, int axis, VDC_XType xtype, int compressed);\nint VDC_DefineCoordVarUniform(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char *time_dim_name, const char *units, int axis, VDC_XType xtype, int compressed);\nint VDC_PutAtt(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const void *values, size_t count);\nint VDC_PutAtt_double(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const double *values, size_t count);\nint VDC_PutAtt_long(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const long *values, size_t count);\nint VDC_PutAtt_text(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const char *values);\nint VDC_EndDefine(VDC *p);\nint VDC_PutVar(VDC *p, const char *varname, int lod, const float *data);\nint VDC_PutVarAtTimeStep(VDC *p, size_t ts, const char *varname, int lod, const float *data);\n\n// Utility\nconst char *VDC_GetErrMsg();\nvoid        VDC_FreeStringArray(char ***str, int *count);\nvoid        VDC_FreeString(char **str);\nvoid        VDC_FreeLongArray(long **data);\nvoid        VDC_FreeDoubleArray(double **data);\nvoid        VDC_FreeSize_tArray(size_t **data);\nvoid        VDC_ReverseSize_tArray(size_t *data, int count);\n\n#ifdef __cplusplus\n}    // extern \"C\" }\n#endif\n\n#endif\n"
  },
  {
    "path": "include/vapor/VaporField.h",
    "content": "#ifndef VAPORFIELD_H\n#define VAPORFIELD_H\n\n#include \"vapor/Field.h\"\n#include \"vapor/Particle.h\"\n#include \"vapor/DataMgr.h\"\n#include \"vapor/FlowParams.h\"\n#include \"vapor/Grid.h\"\n#include \"vapor/ptr_cache.hpp\"\n\nnamespace flow {\n\n//\n// Helper class: it is used to identify a specific grid.\n//\nclass FLOW_API GridKey {\nprivate:\n    uint32_t              _timestep = std::numeric_limits<uint32_t>::max(); // almost impossible value\n    int32_t               _refLev = -2;   // Impossible value\n    int32_t               _compLev = -2;  // Impossible value\n    std::string           _varName;\n    VAPoR::CoordType      _ext_min = {0.0, 0.0, 0.0};\n    VAPoR::CoordType      _ext_max = {0.0, 0.0, 0.0};\n\npublic:\n    void Reset(uint32_t, int32_t, int32_t, std::string, VAPoR::CoordType, VAPoR::CoordType);\n\n    bool emptyVar() const;\n\n    // == operator to be used in the cache\n    bool operator==(const GridKey &) const;\n};\n\n//\n// Helper class: it wraps a grid and a data manager pointer to ensure\n// the grid is properly destroyed.\n//\nclass FLOW_API GridWrapper final {\nprivate:\n    const VAPoR::Grid *const _gridPtr;\n    VAPoR::DataMgr *const    _mgr;    // The pointer itself cannot be changed\n\npublic:\n    GridWrapper(const VAPoR::Grid *gp, VAPoR::DataMgr *mp);\n    // Rule of five\n    GridWrapper(const GridWrapper &) = delete;\n    GridWrapper(const GridWrapper &&) = delete;\n    GridWrapper &operator=(const GridWrapper &) = delete;\n    GridWrapper &operator=(const GridWrapper &&) = delete;\n    ~GridWrapper();\n\n    // Access the real pointer\n    const VAPoR::Grid *grid() const;\n};\n\n//\n//  Note on variable names in a VaporField:\n//  If a variable name is an empty string, then this variable is still valid,\n//  but contains all zero values in it.\n//\nclass FLOW_API VaporField final : public Field {\npublic:\n    //\n    // Functions from class Field\n    //\n    virtual bool InsideVolumeVelocity(double time, glm::vec3 pos) const override;\n    virtual bool InsideVolumeScalar(double time, glm::vec3 pos) const override;\n    virtual uint32_t  GetNumberOfTimesteps() const override;\n\n    virtual int GetVelocity(double time, glm::vec3 pos,     // input\n                            glm::vec3 &vel) const override; // output\n    virtual int GetScalar(double time, glm::vec3 pos,       // input\n                          float &scalar) const override;    // output\n\n    //\n    // Functions for interaction with VAPOR components\n    //\n    void AssignDataManager(VAPoR::DataMgr *dmgr);\n    void UpdateParams(const VAPoR::FlowParams *);\n    void ReleaseLockedGrids();    // Supposed to be invoked at the end of each paintGL event.\n\n    //\n    // Find one index whose timestamp is just below a given time\n    // I.e., _timestamps[floor] <= time\n    //\n    int LocateTimestamp(double  time,            // Input\n                        size_t &floor) const;    // Output\n\n    //\n    // Returns the intersection domain of 3 velocity variables at a specific time step.\n    // It returns non-zeros upon failure.\n    //\n    int GetVelocityIntersection(size_t ts, glm::vec3 &minxyz, glm::vec3 &maxxyz) const;\n\n    //\n    // Calculate a reasonable deltaT based on the velocity speed and domain size.\n    // This is used as a one-time operation when getting ready a velocity field.\n    // It'll return 0 on success, and non-zero on error conditions.\n    //\n    int CalcDeltaTFromCurrentTimeStep(double &delT) const;\n\n    //\n    // It turns that interactions from FlowParams can be expensive.\n    // Let's implement a mechanism to cache information and interact with them less frequently.\n    // Specifically, the following two functions are used to `lock` into (and `unlock` from)\n    // the current set of params from FlowParams, so we don't need to interact with it anymore.\n    //\n    virtual auto LockParams() -> int override;\n    virtual auto UnlockParams() -> int override;\n\nprivate:\n    //\n    // Member variables\n    //\n    std::vector<double>      _timestamps;    // in ascending order\n    VAPoR::DataMgr *         _datamgr = nullptr;\n    const VAPoR::FlowParams *_params = nullptr;\n\n    using cacheType = VAPoR::ptr_cache<GridKey, GridWrapper, 6, true>;\n    mutable cacheType _recentGrids;\n    mutable std::mutex _grid_operation_mutex;\n\n    // The following variables are cache states from DataMgr and Params.\n    bool                               _params_locked = false;\n    uint32_t                           _c_currentTS = 0;          // cached timestep\n    int32_t                            _c_refLev = -2;            // cached ref levels\n    int32_t                            _c_compLev = -2;           // cached ref levels\n    float                              _c_vel_mult = 0.0f;        // cached velocity multiplier\n    VAPoR::CoordType                   _c_ext_min;                // cached extents\n    VAPoR::CoordType                   _c_ext_max;                // cached extents\n\n    //\n    // Member functions\n    //\n    // Are the following member pointers correctly set?\n    //   1) _datamgr, 2) _params\n    bool _isReady() const;\n\n    // _getAGrid will use _params to retrieve/generate grids.\n    // In the case of failing to generate a requested grid, nullptr will be returned.\n    // This failure will also be recorded to MyBase.\n    // Note: If a variable name is empty, we then return a ConstantField.\n    const VAPoR::Grid *_getAGrid(uint32_t timestep, const std::string &varName) const;\n};\n};    // namespace flow\n\n#endif\n"
  },
  {
    "path": "include/vapor/Version.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t*\n//     University Corporation for Atmospheric Research\t\t*\n//\t\t     All Rights Reserved\t\t\t*\n//\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tTue Jul 11 11:59:53 MDT 2006\n//\n//\tDescription:\tVersion information.\n//\n\n//! \\class Version\n//! \\brief Return version information\n//! \\author John Clyne\n//! \\date    Tue Jul 11 11:59:43 MDT 2006\n//! A collection of general purpose utilities - things that\n//!                  probably should be in the STL but aren't.\n//!\n\n#ifndef _Version_h_\n#define _Version_h_\n\n#include <string>\n#include <cstdlib>\n#include <vapor/MyBase.h>\n#include <vapor/common.h>\n#include <vapor/CMakeConfig.h>\n\nusing namespace std;\n\nnamespace Wasp {\n\n//\nclass COMMON_API Version : public MyBase {\npublic:\n    //! Return the major version number\n    //\n    static int GetMajor() { return (_majorVersion); }\n\n    //! Return the minor version number\n    //\n    static int GetMinor() { return (_minorVersion); }\n\n    //! Return the sub minor version number\n    //\n    static int GetMinorMinor() { return (_minorMinorVersion); }\n\n    //! Return the sub minor version number\n    //\n    static string GetRC() { return (VERSION_RC); }\n\n    static string GetBuildType() { return (BUILD_TYPE); }\n\n    //! Return the canonical version number as a formatted string\n    //!\n    //! Return the canonical version number as a formatted string of\n    //! the form: X.Y.Z, where \\p X is the major version number, \\p Y\n    //! is the minor version number, and \\p Z is the sub minor version number.\n    //\n    static const string &GetVersionString();\n\n    //! Return the full version as a formatted string\n    //!\n    //! Return the version as a formatted string of\n    //! the form: MAJOR.MINOR.MICRO.RC.COMMIT\n    //\n    static const string &GetFullVersionString();\n\n    //! Return the git hash of the current build\n    //\n    static const string GetBuildHash();\n\n    //! Return a string containing the date  associated with the version number\n    //!\n    //! This method returns the value of the RCS \\p Date keyword. In general,\n    //! this should corespond to the date that the version number was last\n    //! advanced.\n    //\n    static const string &GetDateString()\n    {\n        _dateString.assign(VERSION_DATE);\n        return (_dateString);\n    }\n\n    //! Parse a version string into it's component major, minor,\n    //! and minorminor numbers\n    //\n    static void Parse(std::string ver, int &major, int &minor, int &minorminor, string &rc);\n\n    static int Compare(int major, int minor, int minorminor);\n    static int Compare(std::string ver1, std::string ver2);\n\nprivate:\n    static const int _majorVersion;\n    static const int _minorVersion;\n    static const int _minorMinorVersion;\n    static string    _formatString;\n    static string    _dateString;\n};\n}    // namespace Wasp\n\n#endif\n"
  },
  {
    "path": "include/vapor/Viewpoint.h",
    "content": "#ifndef VIEWPOINT_H\n#define VIEWPOINT_H\n/*\n * This class describes a viewpoint\n */\n#include <vapor/ParamsBase.h>\n\nnamespace VAPoR {\n\n//! \\class Viewpoint\n//! \\ingroup Public_Params\n//! \\brief class that indicates location and direction of view\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date February 2014\n\n//! \\par\n//! This class contains all the parameters associated with viewpoint, including\n//! camera position, direction, and rotation center.  Most of its methods\n//! should be accessed through the ViewpointParams class.\n\nclass PARAMS_API Viewpoint : public ParamsBase {\npublic:\n    Viewpoint(ParamsBase::StateSave *ssave);\n\n    Viewpoint(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~Viewpoint();\n\n    //! Return the current 4x4 model-view matrix\n    //\n    void GetModelViewMatrix(double m[16]) const;\n    void SetModelViewMatrix(const double m[16]);\n\n    void GetProjectionMatrix(double m[16]) const;\n    void SetProjectionMatrix(const double m[16]);\n\n    bool ReconstructCamera(const double m[16], double position[3], double upVec[3], double viewDir[3]) const;\n\n    void SetRotationCenter(const std::vector<double> &v)\n    {\n        VAssert(v.size() == 3);\n        SetValueDoubleVec(_rotationCenterTag, \"Camera rotation center\", v);\n    }\n\n    std::vector<double> GetRotationCenter() const\n    {\n        vector<double> defaultv(3, 0.0);\n        return (GetValueDoubleVec(_rotationCenterTag, defaultv));\n    }\n\n    static string GetClassType() { return (\"Viewpoint\"); }\n\nprivate:\n    // ParamsContainer *_VPs;\n\n    static const string _modelViewMatrixTag;\n    static const string _projectionMatrixTag;\n    static const string _rotationCenterTag;\n\n    static double _defaultModelViewMatrix[16];\n    static double _defaultProjectionMatrix[16];\n\n    void _init();\n};\n};    // namespace VAPoR\n\n#endif    // VIEWPOINT_H\n"
  },
  {
    "path": "include/vapor/ViewpointParams.h",
    "content": "//************************************************************************\n//         *\n//       Copyright (C)  2004    *\n//     University Corporation for Atmospheric Research   *\n//       All Rights Reserved    *\n//         *\n//************************************************************************/\n//\n// File:  ViewpointParams.h\n//\n// Author:  Alan Norton\n//   National Center for Atmospheric Research\n//   PO 3000, Boulder, Colorado\n//\n// Date:  August 2004\n//\n// Description: Defines the ViewpointParams class\n//  This class contains the parameters associated with viewpoint and lights\n//\n#ifndef VIEWPOINTPARAMS_H\n#define VIEWPOINTPARAMS_H\n\n#include <vapor/ParamsBase.h>\n#include <vapor/Viewpoint.h>\n#include <vapor/Transform.h>\n\n#include <memory>\n#include <fstream>\n\nnamespace VAPoR {\n\n//! \\class ViewpointParams\n//! \\ingroup Public_Params\n//! \\brief A class for describing the viewpoint and lights in a 3D VAPOR scene\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    February 2014\n\n//! This class describes the state of viewpoints and\n//! and the properties of light sources.  If the ViewpointParams is shared (i.e. not local), all windows can\n//! use the same viewpoint and lights.  Local viewpoints are\n//! just applicable in one visualizer.\nclass PARAMS_API ViewpointParams : public ParamsBase {\npublic:\n    ViewpointParams(ParamsBase::StateSave *ssave);\n\n    ViewpointParams(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    ViewpointParams(const ViewpointParams &rhs);\n\n    ViewpointParams &operator=(const ViewpointParams &rhs);\n\n    virtual ~ViewpointParams();\n\n    //! Rescale viewing parameters, e.g. when the scene stretch factors change\n    //! \\param[in] vector<double> scaleFac scale factors to be applied, relative to previous scaling.\n    void rescale(vector<double> scaleFac);\n\n    //! This method tells how many lights are specified and whether\n    //! lighting is on or not (i.e. if there are more than 0 lights).\n    //! Note that only the first (light 0) is used in DVR and Isosurface rendering.\n    //! \\retval int number of lights (0,1,2)\n    int getNumLights() const\n    {\n        size_t n = (size_t)GetValueLong(_numLightsTag, _defaultNumLights);\n        if (n > 2) n = 2;\n        return (n);\n    }\n\n    //! Obtain the current specular exponent.\n    //! This value should be used in setting the material properties\n    //! of all geometry being rendered.\n    //! \\retval float Specular exponent\n    double getExponent() const { return (GetValueDouble(_specularExpTag, _defaultSpecularExp)); }\n\n    //! Set the number of directional light sources\n    //! \\param[in] int number of lights (0,1,2)\n    //! \\retval 0 on success\n    void setNumLights(size_t nlights)\n    {\n        if (nlights > 2) nlights = 2;\n        SetValueLong(_numLightsTag, \"Set number of lights\", nlights);\n    }\n\n    //! get one component of a light direction vector\n    //! \\param[in] int lightNum identifies which light source\n    //! \\param[in] int dir coordinate of direction vector (0..3)\n    //! \\retval double requested component of light direction vector\n    //\n    double getLightDirection(int lightNum, int dir) const;\n\n    //! Set one component of a light direction vector\n    //! \\param[in] int lightNum identifies which light source\n    //! \\param[in] int dir coordinate of direction vector (0..3)\n    //! \\param[in] double value to be set\n    //! \\retval int 0 on success\n    void setLightDirection(int lightNum, int dir, double val);\n\n    //! Optain the diffuse lighting coefficient of a light source\n    //! \\param[in] int light number (0..2)\n    //! \\retval double diffuse coefficient\n    double getDiffuseCoeff(int lightNum) const;\n\n    //! Optain the specular lighting coefficient of a light source\n    //! \\param[in] int light number (0..2)\n    //! \\retval double specular coefficient\n    double getSpecularCoeff(int lightNum) const;\n\n    //! Optain the ambient lighting coefficient of the lights\n    //! \\retval double ambient coefficient\n    double getAmbientCoeff() const { return GetValueDouble(_ambientCoeffTag, _defaultAmbientCoeff); }\n\n    //! Set the diffuse lighting coefficient of a light source\n    //! \\param[in] int light number (0..2)\n    //! \\param[in] double diffuse coefficent\n    //! \\retval int 0 if successful\n    void setDiffuseCoeff(int lightNum, double val);\n\n    //! Set the specular lighting coefficient of a light source\n    //! \\param[in] int light number (0..2)\n    //! \\param[in] double specular coefficent\n    //! \\retval int 0 if successful\n    void setSpecularCoeff(int lightNum, double val);\n\n    //! Set the specular lighting exponent of all light sources\n    //! \\param[in] double specular exponent\n    //! \\retval int 0 if successful\n    void setExponent(double val) { SetValueDouble(_specularExpTag, \"Set specular lighting\", val); }\n\n    //! Set the ambient lighting coefficient\n    //! \\param[in] double ambient coefficient\n    //! \\retval int 0 if successful\n    void setAmbientCoeff(double val) { SetValueDouble(_ambientCoeffTag, \"Set ambient lighting\", val); }\n\n    //! Set the current viewpoint to another viewpoint\n    //! \\param[in] Viewpoint* viewpoint to be set\n    //! \\retval int 0 if successful\n    //! \\sa Viewpoint\n    void SetCurrentViewpoint(Viewpoint *newVP);\n\n    //! Set widow width and height\n    //!\n    //! \\param[in] width width of window in pixels\n    //! \\param[in] height height of window in pixels\n    //!\n    void SetWindowSize(size_t width, size_t height);\n\n    //! Get widow width and height\n    //!\n    //! \\param[out] width width of window in pixels\n    //! \\param[out] height height of window in pixels\n    //!\n    void GetWindowSize(size_t &width, size_t &height) const;\n\n    void   SetFOV(float v);\n    double GetFOV() const;\n    void   SetOrthoProjectionSize(float f);\n    double GetOrthoProjectionSize() const;\n\n    enum ProjectionType { Perspective, Orthographic, MapOrthographic };\n    void           SetProjectionType(ProjectionType type);\n    ProjectionType GetProjectionType() const;\n\n    //! Method to get stretch factors\n    vector<double> GetStretchFactors() const;\n\n    //! method to set stretch factors\n    //! \\param[in] factors 3-vector of stretch factors\n    void SetStretchFactors(vector<double> factors);\n\n    //! Obtain the current viewpoint\n    //! \\sa Viewpoint\n    //! \\retval Viewpoint* current viewpoint.\n    virtual Viewpoint *getCurrentViewpoint() const\n    {\n        Viewpoint *v = (Viewpoint *)m_VPs->GetParams(_currentViewTag);\n        VAssert(v != NULL);\n        return (v);\n    }\n\n    //! Return the current 4x4 model-view matrix\n    //\n    void                GetModelViewMatrix(double m[16]) const { getCurrentViewpoint()->GetModelViewMatrix(m); }\n    std::vector<double> GetModelViewMatrix() const\n    {\n        double m[16];\n        getCurrentViewpoint()->GetModelViewMatrix(m);\n        vector<double> vec(m, m + sizeof(m) / sizeof(m[0]));\n        return (vec);\n    }\n    void SetModelViewMatrix(const double matrix[16]) { getCurrentViewpoint()->SetModelViewMatrix(matrix); }\n    void SetModelViewMatrix(const std::vector<double> mvec)\n    {\n        VAssert(mvec.size() == 16);\n        double m[16];\n        for (int i = 0; i < mvec.size(); i++) m[i] = mvec[i];\n        getCurrentViewpoint()->SetModelViewMatrix(m);\n    }\n\n    void GetProjectionMatrix(double m[16]) const { getCurrentViewpoint()->GetProjectionMatrix(m); }\n    void SetProjectionMatrix(const double m[16]) { getCurrentViewpoint()->SetProjectionMatrix(m); }\n\n    bool ReconstructCamera(const double m[16], double position[3], double upVec[3], double viewDir[3]) const { return (getCurrentViewpoint()->ReconstructCamera(m, position, upVec, viewDir)); }\n\n    std::vector<double> GetRotationCenter() const { return (getCurrentViewpoint()->GetRotationCenter()); }\n\n    void GetRotationCenter(double c[3]) const\n    {\n        vector<double> val = GetRotationCenter();\n        VAssert(val.size() == 3);\n        for (int i = 0; i < val.size(); i++) c[i] = val[i];\n    }\n\n    void SetRotationCenter(vector<double> c) { getCurrentViewpoint()->SetRotationCenter(c); }\n    void SetRotationCenter(const double c[3])\n    {\n        std::vector<double> vec = {c[0], c[1], c[2]};\n        SetRotationCenter(vec);\n    }\n\n    //! Access the transform for a data set\n    //!\n    //! Access the transform for data set \\p dataSetName\n    //!\n    //! \\retval Returns a new transform if one does not exist\n    //\n    virtual Transform *GetTransform(string dataSetName);\n\n    //! Return list of transform names.\n    //!\n    //! Return the list of transform names added with AddDatasetTransform()\n    //\n    vector<string> GetTransformNames() const { return (_transforms->GetNames()); }\n\n    //! Set the current camera position, direction, up vector, and origin from a given xml file\n    //! \\retval integer indicating success (0) or failure (-1)\n    int SetCameraFromFile(const std::string &path);\n    \n    //! Save the current camera position, direction, up vector, and origin to an xml file\n    //! \\retval integer indicating success (0) or failure (-1)\n    int SaveCameraToFile(const std::string &path);\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Determine the current diameter of the visible scene.\n    //! Calculated as 2*Dist*tan(theta*.5) where theta is the camera angle,\n    //! Dist is the distance from the camera to the rotation center.\n    double GetCurrentViewDiameter(vector<double> stretchFactors) const;\n#endif\n\n#ifndef DOXYGEN_SKIP_THIS\n\n    static const double *getDefaultLightDirection(int lightNum) { return _defaultLightDirection[lightNum]; }\n    static double        getDefaultAmbientCoeff() { return _defaultAmbientCoeff; }\n    static double        getDefaultSpecularExp() { return _defaultSpecularExp; }\n    static int           getDefaultNumLights() { return _defaultNumLights; }\n    static const double *getDefaultDiffuseCoeff() { return _defaultDiffuseCoeff; }\n    static const double *getDefaultSpecularCoeff() { return _defaultSpecularCoeff; }\n    static void          setDefaultLightDirection(int lightNum, double val[3])\n    {\n        for (int i = 0; i < 3; i++) _defaultLightDirection[lightNum][i] = val[i];\n    }\n    static void setDefaultSpecularCoeff(double val[3])\n    {\n        for (int i = 0; i < 3; i++) _defaultSpecularCoeff[i] = val[i];\n    }\n    static void setDefaultDiffuseCoeff(double val[3])\n    {\n        for (int i = 0; i < 3; i++) _defaultDiffuseCoeff[i] = val[i];\n    }\n    static void setDefaultAmbientCoeff(double val) { _defaultAmbientCoeff = val; }\n    static void setDefaultSpecularExp(double val) { _defaultSpecularExp = val; }\n    static void setDefaultNumLights(int val) { _defaultNumLights = val; }\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"ViewpointParams\"); }\n\n    static const string UseCustomFramebufferTag;\n    static const string CustomFramebufferWidthTag;\n    static const string CustomFramebufferHeightTag;\n\nprivate:\n    ParamsContainer *m_VPs = nullptr;\n    ParamsContainer *_transforms = nullptr;\n\n    static const string _viewPointsTag;\n    static const string _transformsTag;\n    static const string _currentViewTag;\n    static const string _lightDirectionsTag;\n    static const string _diffuseCoeffTag;\n    static const string _specularCoeffTag;\n    static const string _specularExpTag;\n    static const string _ambientCoeffTag;\n    static const string _numLightsTag;\n    static const string m_windowSizeTag;\n    static const string m_stretchFactorsTag;\n    static const string m_fieldOfView;\n    static const string _orthoProjectionSizeTag;\n    static const string _projectionTypeTag;\n\n    // defaults:\n    static double _defaultLightDirection[3][4];\n    static double _defaultDiffuseCoeff[3];\n    static double _defaultSpecularCoeff[3];\n    static double _defaultAmbientCoeff;\n    static double _defaultSpecularExp;\n    static int    _defaultNumLights;\n\n    void _init();\n\n#endif    // DOXYGEN_SKIP_THIS\n};\n};        // namespace VAPoR\n#endif    // VIEWPOINTPARAMS_H\n"
  },
  {
    "path": "include/vapor/Visualizer.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tVisualizer.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tSeptember 2013\n//\n//\tDescription:  Definition of Visualizer class:\n//\tA Visualizer object is associated with each visualization window.  It contains\n//  information required for rendering, performs\n//\tnavigation and resize, and defers drawing to the viz window's list of\n//\tregistered renderers.\n\n#pragma once\n\n#include <map>\n#include <vapor/DataStatus.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/Renderer.h>\n#include <vapor/AnnotationRenderer.h>\n#include <vapor/Framebuffer.h>\n\nnamespace VAPoR {\n\n//! \\class Visualizer\n//! \\ingroup Public_Render\n//! \\brief A class for performing OpenGL rendering in VAPOR GUI Window\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    October 2013\n//!\n//!\n//! The Visualizer class performs OpenGL rendering for the main VAPOR visualizers.  The\n//! Visualizer class is not a GL Window itself, however it will issue the OpenGL calls to\n//! perform rendering in a context that is already current.\n\nclass RENDER_API Visualizer : public MyBase {\npublic:\n    Visualizer(const ParamsMgr *pm, const DataStatus *dataStatus, string winName);\n    ~Visualizer();\n\n    //! Method that returns the ViewpointParams that is active in this window.\n    //! \\retval ViewpointParams* current active ViewpointParams\n    ViewpointParams *getActiveViewpointParams() const;\n\n    //! Method that returns the RegionParams that is active in this window.\n    //! \\retval RegionParams* current active RegionParams\n    RegionParams *getActiveRegionParams() const;\n\n    //! Method that returns the AnnotationParams that is active in this window.\n    //! \\retval AnnotationParams* current active AnnotationParams\n    AnnotationParams *getActiveAnnotationParams() const;\n\n    //! Method to initialize GL rendering.  Must be called from a GL context.\n    //! \\param[in] glManager A pointer to a GLManager\n    int InitializeGL(GLManager *glManager);\n\n    void syncWithParams();\n\n    //! Set/clear a flag indicating that the trackball has changed the viewpoint.\n    //! all the OpenGL rendering is performed in the _paintEvent method.  It must be invoked from\n    //! a current OpenGL context.\n    //! \\return zero if successful.\n    int paintEvent(bool fast);\n\n    //! Helper function for paintEvent() to hand off a renderer, call matrix operations, and call paintGL\n    //! \\return zero if successful.\n    int renderRenderer(Renderer* renderer, bool fast);\n\n    //! Issue the OpenGL resize call.  Must be called from an OpenGL context.\n    //! \\param[in] w Window width in pixels.\n    //! \\param[in] h Window height in pixels.\n    int resizeGL(int w, int h);\n\n    //! Identify the visualizer index associated with this visualizer\n    //! \\retval visualizer index;\n    string GetWindowName() const { return _winName; }\n\n    //! Determine the number of renderers in the renderer list\n    //! \\return number of renderers\n    int GetNumRenderers() const { return _renderers.size(); }\n\n    //! \\note A render params instance must have been previously created for\n    //! this renderer.\n    //\n    int CreateRenderer(string dataSetName, string renderType, string renderName);\n\n    //! Flag a renderer for destruction.\n    //!\n    //! \\param[in] hasOpenGLContext If true it is the callers job to ensure that the\n    //! OpenGL Context for the window \\p winName is active. In this case the renderer\n    //! is destroyed immediately. If false the renderer is queue'd for later destruction\n    //! when \\p winName has an active OpenGL context.\n    //\n    void DestroyRenderer(string renderType, string renderName, bool hasOpenGLContext);\n\n    //! Flag all rendereres for destruction.\n    //!\n    //! \\param[in] hasOpenGLContext If true it is the callers job to ensure that the\n    //! OpenGL Context for the window \\p winName is active. In this case the renderer\n    //! is destroyed immediately. If false the renderer is queue'd for later destruction\n    //! when \\p winName has an active OpenGL context.\n    //\n    void DestroyAllRenderers(bool hasOpenGLContext);\n\n    bool HasRenderer(string renderType, string renderName) const;\n\n    //! Move the renderer to the front of the render queue\n    //! \\param[out] Renderer instance that is moved to front\n    void MoveRendererToFront(string renderType, string renderName);\n    void MoveRenderersOfTypeToFront(const std::string &type);\n\n    //! Determine the approximate size of a pixel in terms of user coordinates,\n    //! at the center of the scene.\n    double getPixelSize() const;\n\n    //! Turn on or off the image capture enablement.  If on, the next _paintEvent will result in capture\n    //! Also saves the capture file name\n    int SetImageCaptureEnabled(bool onOff, string filename)\n    {\n        if (_animationCaptureEnabled) {\n            SetErrMsg(\"Image capture concurrent with Animation Capture\\n\");\n            return -1;\n        }\n        _imageCaptureEnabled = onOff;\n        if (onOff)\n            _captureImageFile = filename;\n        else\n            _captureImageFile = \"\";\n        return 0;\n    }\n\n    //! Turn on or off the animation capture enablement.  If on, all paintEvents will result in capture\n    //! until it is turned off\n    int SetAnimationCaptureEnabled(bool onOff, string filename)\n    {\n        if (_imageCaptureEnabled) {\n            SetErrMsg(\"Image capture concurrent with Animation Capture\\n\");\n            return -1;\n        }\n        if (_animationCaptureEnabled == onOff) {\n            SetErrMsg(\"Animation capture in incorrect state\\n\");\n            return -1;\n        }\n        _animationCaptureEnabled = onOff;\n        if (onOff)\n            _captureImageFile = filename;\n        else\n            _captureImageFile = \"\";\n        return 0;\n    }\n\n    //! Draw a text banner at x, y coordinates\n    //\n    void DrawText(string text, int x, int y, int size, float color[3], int type = 0) { _vizFeatures->AddText(text, x, y, size, color, type); }\n\n    void DrawTextNormalizedCoords(string text, float x, float y, int size, float color[3], int type = 0) { _vizFeatures->AddTextNormalizedCoords(text, x, y, size, color, type); }\n\n    void ClearText() { _vizFeatures->ClearText(); }\n\n    //! Force each renderer to empty its cache\n    //!\n    //! This method calls ClearCache on every renderer\n    //\n    void ClearRenderCache();\n    \n    void ClearRenderCache(const string &inst);\n\nprivate:\n    //! Render all the colorbars enabled in this visualizer.\n    void _renderColorbars(int timeStep);\n\n    //! Capture a single image to a file.  Filename must be *.tif or *.jpg\n    //! Must be called during _paintEvent when captureEnabled has been called.\n    //! Will turn off the captureEnabled switch.\n    //! \\param[in] filename\n    //! \\return zero if successful\n    int _captureImage(std::string path);\n\n    void _loadMatricesFromViewpointParams();\n\n    //! Definition of OpenGL Vendors\n    enum GLVendorType { UNKNOWN = 0, MESA, NVIDIA, ATI, INTEL };\n\n    //! Identify the OpenGL Vendor\n    //! \\return OpenGL vendor\n    static GLVendorType GetVendor();\n\n    //! Place the OpenGL directional lights specified in the ViewpointParams\n    int _configureLighting();\n\n    //! Obtain the image from the gl back buffer\n    //! \\param[out] data is array of rgb byte values, 3 bytes per pixel\n    //! \\return true if successful\n    bool _getPixelData(unsigned char *data) const;\n\n    void _deleteFlaggedRenderers();\n    int  _initializeNewRenderers();\n    void _clearActiveFramebuffer(float r, float g, float b) const;\n    void _applyDatasetTransformsForRenderer(Renderer *r);\n\n    int _getCurrentTimestep() const;\n\n    static void _incrementPath(string &s);\n\n    Renderer *_getRenderer(string type, string instance) const;\n\n    const ParamsMgr *   _paramsMgr;\n    const DataStatus *  _dataStatus;\n    string              _winName;\n    GLManager *         _glManager;\n    AnnotationRenderer *_vizFeatures;\n\n    bool _insideGLContext;    // This is only to make sure we don't call certain functions when they are not supposed to be called. In some situations this variable will be set to true incorrectly. In\n                              // those cases there is already some other error so it doesn't matter.\n    bool   _imageCaptureEnabled;\n    bool   _animationCaptureEnabled;\n    string _captureImageFile;\n\n    vector<Renderer *> _renderers;\n    vector<Renderer *> _renderersToDestroy;\n\n    Framebuffer  _framebuffer;\n    unsigned int _screenQuadVAO = 0;\n    unsigned int _screenQuadVBO = 0;\n};\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VisualizerGLContextManager.h",
    "content": "#pragma once\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\nclass RENDER_API VisualizerGLContextManager {\npublic:\n    virtual void Activate(const string &visualizerName) = 0;\n};\n}\n"
  },
  {
    "path": "include/vapor/VolumeAlgorithm.h",
    "content": "#pragma once\n\n#include <vapor/Grid.h>\n#include <vapor/ShaderManager.h>\n#include <vector>\n#include <map>\n#include <string>\n#include <vapor/NonCopyableMixin.h>\n\nnamespace VAPoR {\n\nstruct GLManager;\nclass VolumeAlgorithmFactory;\nclass VolumeRenderer;\nclass VolumeParams;\nclass ViewpointParams;\nclass AnnotationParams;\nclass Transform;\n\n//! \\class VolumeAlgorithm\n//! \\ingroup Public_Render\n//!\n//! \\brief Strategy pattern for volume rendering algorithms\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date Feburary, 2019\n//!\n//! Instances are created with a Factory pattern\n\nclass VolumeAlgorithm : private NonCopyableMixin {\npublic:\n    enum class Type { Any, DVR, Iso };\n\n    VolumeAlgorithm(GLManager *gl, VolumeRenderer *renderer);\n    virtual ~VolumeAlgorithm() {}\n    virtual void SaveDepthBuffer(bool fast){};\n    virtual int  Render(bool fast) = 0;\n    virtual int  LoadData(const Grid *grid) = 0;\n    virtual int  LoadSecondaryData(const Grid *grid) = 0;\n    virtual void DeleteSecondaryData() = 0;\n    virtual void GetFinalBlendingMode(int *src, int *dst) = 0;\n\n    //! On OSX, some shaders can run for a long time without problems\n    //! while others will crash if the run too long. It seems to correlate\n    //! with complexity. Chunked rendering splits the rendering into smaller\n    //! tasks so they won't crash\n    virtual bool  RequiresChunkedRendering() = 0;\n    virtual float GuestimateFastModeSpeedupFactor() const { return 1; }\n    virtual int CheckHardwareSupport(const Grid *grid) const { return 0; }\n\n    static VolumeAlgorithm *NewAlgorithm(const std::string &name, GLManager *gl, VolumeRenderer *renderer);\n\n    static void Register(VolumeAlgorithmFactory *f);\n\nprotected:\n    GLManager *_glManager;\n\n    VolumeParams *    GetParams() const;\n    ViewpointParams * GetViewpointParams() const;\n    AnnotationParams *GetAnnotationParams() const;\n    Transform *       GetDatasetTransform() const;\n    void              GetExtents(glm::vec3 *dataMin, glm::vec3 *dataMax, glm::vec3 *userMin, glm::vec3 *userMax) const;\n\nprivate:\n    static std::map<std::string, VolumeAlgorithmFactory *> factories;\n    VolumeRenderer *                                       _renderer;\n};\n\nclass VolumeAlgorithmNull : public VolumeAlgorithm {\npublic:\n    VolumeAlgorithmNull(GLManager *gl, VolumeRenderer *renderer) : VolumeAlgorithm(gl, renderer) {}\n    static std::string GetName() { return \"NULL\"; }\n    static Type        GetType() { return Type::Any; }\n    int                Render(bool fast) { return 0; }\n    int                LoadData(const Grid *grid) { return 0; }\n    int                LoadSecondaryData(const Grid *grid) { return 0; }\n    void               DeleteSecondaryData() {}\n    bool               RequiresChunkedRendering() { return false; }\n    void               GetFinalBlendingMode(int *src, int *dst) {}\n};\n\nclass VolumeAlgorithmFactory {\npublic:\n    std::string              name;\n    VolumeAlgorithm::Type    type;\n    virtual VolumeAlgorithm *Create(GLManager *gl, VolumeRenderer *renderer) = 0;\n};\n\ntemplate<class T> class VolumeAlgorithmRegistrar : public VolumeAlgorithmFactory {\npublic:\n    VolumeAlgorithmRegistrar()\n    {\n        static_assert(std::is_base_of<VolumeAlgorithm, T>::value, \"Register is not derived from VolumeAlgorithm\");\n        name = T::GetName();\n        type = T::GetType();\n        VolumeAlgorithm::Register(this);\n    }\n    VolumeAlgorithm *Create(GLManager *gl, VolumeRenderer *renderer) { return new T(gl, renderer); }\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeCellTraversal.h",
    "content": "#pragma once\n\n#include <vapor/VolumeRegular.h>\n\nnamespace VAPoR {\n\n//! \\class VolumeCellTraversal\n//! \\ingroup Public_Render\n//!\n//! \\brief Curvilinear grid rendering algorithm\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date Feburary, 2019\n//!\n//! Renders a curvilinear grid by traversing through the cells. The c++ code\n//! does the following:\n//! 1. Loads scalar data\n//! 2. Loads the coordinates\n//! 3. Generates a bounding box for every border face\n//! 4. Groups bounding boxs recursively into a tree, i.e. a bounding box at level n\n//!    would encapsulate the 4 associated bounding boxes at level n-1\n//!\n//! The glsl code does the following:\n//! 1. Find the initial border face that the ray intersects with by traversing\n//!    the tree built on the CPU\n//! 2. Loop:\n//! 3. Find the exit face of the current cell\n//! 4. Render the ray segment from the entrance to the exit\n//! 5. Set the current exit face to the new entrance face\n//! 6. Goto Loop until the ray exits the volume\n\nclass VolumeCellTraversal : public VolumeRegular {\npublic:\n    VolumeCellTraversal(GLManager *gl, VolumeRenderer *renderer);\n    ~VolumeCellTraversal();\n\n    static std::string GetName() { return \"Curvilinear\"; }\n    static Type        GetType() { return Type::DVR; }\n    virtual bool       RequiresChunkedRendering() { return true; }\n\n    virtual int            LoadData(const Grid *grid);\n    virtual ShaderProgram *GetShader() const;\n    virtual void           SetUniforms(const ShaderProgram *shader) const;\n    virtual float          GuestimateFastModeSpeedupFactor() const;\n    virtual int CheckHardwareSupport(const Grid *grid) const;\n\nprivate:\n    Texture3D      _coordTexture;\n    Texture2DArray _minTexture;\n    Texture2DArray _maxTexture;\n    Texture2D      _BBLevelDimTexture;\n\n    int  _coordDims[3];\n    int  _BBLevels;\n    bool _useHighPrecisionTriangleRoutine;\n    bool _gridHasInvertedCoordinateSystemHandiness;\n\n    bool        _needsHighPrecisionTriangleRoutine(const Grid *grid);\n    static bool _need32BitForCoordinates(const Grid *grid);\n\nprotected:\n    int                 _getHeuristicBBLevels() const;\n    virtual std::string _addDefinitionsToShader(std::string shaderName) const;\n};\n\n//! \\class VolumeCellTraversalIso\n//! \\ingroup Public_Render\n//!\n//! \\brief Curvilinear grid isosurface rendering algorithm\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date Feburary, 2019\n//!\n//! Renders isosurfaces by ray tracing. This class is the same as the curvilinear DVR\n//! except it renders an isosurface\n\nclass VolumeCellTraversalIso : public VolumeCellTraversal {\npublic:\n    VolumeCellTraversalIso(GLManager *gl, VolumeRenderer *renderer) : VolumeCellTraversal(gl, renderer) {}\n    static std::string     GetName() { return \"Iso Curvilinear\"; }\n    static Type            GetType() { return Type::Iso; }\n    virtual ShaderProgram *GetShader() const;\n    virtual void           SetUniforms(const ShaderProgram *shader) const;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeGLSL.h",
    "content": "#pragma once\n\n#include <vapor/VolumeAlgorithm.h>\n#include <vapor/Texture.h>\n#include <vapor/MapperFunction.h>\n\nnamespace VAPoR {\n\n//! \\class VolumeGLSL\n//! \\ingroup Public_Render\n//!\n//! \\brief Volume rendering algorithms using GLSL\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date July, 2020\n\nclass VolumeGLSL : public VolumeAlgorithm {\npublic:\n    VolumeGLSL(GLManager *gl, VolumeRenderer *renderer);\n    ~VolumeGLSL();\n\n    virtual void           SaveDepthBuffer(bool fast);\n    virtual int            Render(bool fast);\n    virtual int            LoadData(const Grid *grid);\n    virtual ShaderProgram *GetShader() const = 0;\n    virtual void           SetUniforms(const ShaderProgram *shader) const = 0;\n    virtual void           GetFinalBlendingMode(int *src, int *dst);\n\nprivate:\n    Texture1D       _LUTTexture;\n    Texture1D       _LUT2Texture;\n    Texture2D       _depthTexture;\n    MapperFunction *_tf = 0, *_tf2 = 0;\n    vector<double>  _minDataExtents, _maxDataExtents;\n    vector<float>   _constantColor;\n\n    void _loadTF();\n    void _loadTF(Texture1D *texture, MapperFunction *tf, MapperFunction **cacheTF);\n    void _getLUTFromTF(const MapperFunction *tf, float *LUT) const;\n\n    void      _setShaderUniforms(const ShaderProgram *shader, const bool fast) const;\n    glm::vec3 _getVolumeScales() const;\nprotected:\n    void      _getExtents(glm::vec3 *dataMin, glm::vec3 *dataMax, glm::vec3 *userMin, glm::vec3 *userMax) const;\nprivate:\n    bool      _usingColorMapData() const;\n};\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeIsoParams.h",
    "content": "#pragma once\n\n#include <vapor/VolumeParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\nclass PARAMS_API VolumeIsoParams : public VolumeParams {\npublic:\n    VolumeIsoParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n    VolumeIsoParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n    virtual ~VolumeIsoParams();\n\n    static string GetClassType() { return (\"VolumeIsoParams\"); }\n\n    virtual bool   GetDefaultLightingEnabled() const override { return true; }\n    virtual double GetDefaultPhongAmbient() const override { return 0.2; }\n    virtual string GetDefaultAlgorithmName() const override;\n\n    bool HasIsoValues() const override { return true; }\n\nprotected:\n    virtual bool GetUseSingleColorDefault() const override { return true; }\n\nprivate:\n    void _init();\n};\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeIsoRenderer.h",
    "content": "#pragma once\n\n#include <vapor/VolumeRenderer.h>\n#include <vapor/VolumeAlgorithm.h>\n#include <glm/fwd.hpp>\n\nusing std::string;\nusing std::vector;\n\nnamespace VAPoR {\n\n//! \\class VolumeIsoRenderer\n//! \\ingroup Public_Render\n//!\n//! \\brief Isosurface renderer\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date Feburary, 2019\n//!\n//! Since Vapor requires a separate class for each renderer, this\n//! class is a copy of the VolumeRenderer class but it only gives access\n//! to the isosurface rendering algorithms\n\nclass RENDER_API VolumeIsoRenderer : public VolumeRenderer {\npublic:\n    VolumeIsoRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr);\n    ~VolumeIsoRenderer();\n\n    static std::string GetClassType() { return (\"IsoSurface\"); }\n\n    virtual bool        _usingColorMapData() const;\n    virtual void        _setShaderUniforms(const ShaderProgram *shader, const bool fast) const;\n    virtual std::string _getDefaultAlgorithmForGrid(const Grid *grid) const;\n    virtual void        _getLUTFromTF(const MapperFunction *tf, float *LUT) const;\n};\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeOSPRay.h",
    "content": "#pragma once\n\n#include <vapor/VolumeAlgorithm.h>\n#include <vapor/Texture.h>\n#include <vapor/OSPRay.h>\n\nnamespace VAPoR {\n\n//! \\class VolumeOSPRay\n//! \\ingroup Public_Render\n//!\n//! \\brief OSPRay volume rendering adapter\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date July, 2020\n//!\n\n#ifdef BUILD_OSPRAY\nclass RENDER_API VolumeOSPRay : public VolumeAlgorithm {\npublic:\n    enum WindingOrder { CCW, CW, INVALID };\n\n    VolumeOSPRay(GLManager *gl, VolumeRenderer *renderer);\n    ~VolumeOSPRay();\n\n    static std::string GetName();\n    static Type        GetType() { return Type::DVR; }\n    virtual bool       RequiresChunkedRendering() { return false; }\n\n    virtual void           SaveDepthBuffer(bool fast);\n    virtual int            Render(bool fast);\n    virtual int            LoadData(const Grid *grid);\n    virtual int            LoadSecondaryData(const Grid *grid) { return 0; }\n    virtual void           DeleteSecondaryData() {}\n    virtual ShaderProgram *GetShader() const;\n    virtual void           SetUniforms(const ShaderProgram *shader) const;\n    virtual float          GuestimateFastModeSpeedupFactor() const;\n    virtual void           GetFinalBlendingMode(int *src, int *dst);\n\nprotected:\n    virtual bool _isIso() const { return false; }\n\nprivate:\n    std::vector<size_t>        _dataDimensions;\n    std::vector<float>         _depthData;\n    std::vector<unsigned char> _backplateData;\n    Texture2D                  _ospRenderTexture;\n    Texture2D                  _ospWriteDepthTexture;\n    struct {\n        glm::vec3 min, max;\n    } _clipBox = {glm::vec3(0), glm::vec3(1)};\n    float _ospSampleRateScalar;\n\n    struct {\n        bool usePT;\n    } _cache;\n\n    OSPRenderer         _ospRenderer = nullptr;\n    OSPWorld            _ospWorld = nullptr;\n    OSPCamera           _ospCamera = nullptr;\n    OSPTransferFunction _ospTF = nullptr;\n    OSPInstance         _ospInstance = nullptr;\n    OSPVolumetricModel  _ospVolumeModel = nullptr;\n    OSPLight            _ospLightAmbient = nullptr;\n    OSPLight            _ospLightDistant = nullptr;\n    OSPGeometry         _ospIso = nullptr;\n    OSPGeometricModel   _ospIsoModel = nullptr;\n\n    void _setupRenderer(bool fast);\n    void _setupCamera();\n    void _setupIso();\n    void _loadTF();\n    void _applyTransform();\n    void _copyDepth();\n    void _copyBackplate();\n\n    float     _guessSamplingRateScalar(const Grid *grid) const;\n    OSPVolume _loadVolumeRegular(const Grid *grid);\n    OSPVolume _loadVolumeStructured(const Grid *grid);\n    OSPVolume _loadVolumeUnstructured(const Grid *grid);\n    OSPVolume _loadVolumeTest(const Grid *grid);\n\n    static WindingOrder getWindingOrderRespectToZ(const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c);\n    static WindingOrder getWindingOrderTetra(const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c, const glm::vec3 &d);\n    static const char * windingOrderToString(WindingOrder o);\n    static bool         isQuadCoPlanar(const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c, const glm::vec3 &d);\n};\n#else\nclass VolumeOSPRay : public VolumeAlgorithm {\npublic:\n    VolumeOSPRay(GLManager *gl, VolumeRenderer *renderer) : VolumeAlgorithm(gl, renderer) {}\n\n    static std::string GetName() { return \"OSPRay\"; }\n};\n#endif\n\n//! \\class VolumeOSPRayIso\n//! \\ingroup Public_Render\n//!\n//! \\brief OSPRay isosurface rendering adapter\n//!\n//! \\author Stanislaw Jaroszynski\n\nclass RENDER_API VolumeOSPRayIso : public VolumeOSPRay {\npublic:\n    VolumeOSPRayIso(GLManager *gl, VolumeRenderer *renderer) : VolumeOSPRay(gl, renderer) {}\n    static std::string GetName() { return \"Iso OSPRay (experimental)\"; }\n    static Type        GetType() { return Type::Iso; }\n\nprotected:\n    bool _isIso() const { return true; }\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeParams.h",
    "content": "#pragma once\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n#include <vapor/STLUtils.h>\n\nnamespace VAPoR {\n\nclass PARAMS_API VolumeParams : public RenderParams {\npublic:\n    enum class Type { Any, DVR, Iso };\n\n    VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n    VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType);\n    VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n    virtual ~VolumeParams();\n\n    virtual string GetDefaultAlgorithmName() const;\n\n    virtual bool   GetDefaultLightingEnabled() const { return true; }\n    virtual double GetDefaultPhongAmbient() const { return 0.6; }\n    virtual double GetDefaultPhongDiffuse() const { return 0.5; }\n    virtual double GetDefaultPhongSpecular() const { return 0.1; }\n    virtual double GetDefaultPhongShininess() const { return 0.2; }\n\n    static string GetClassType() { return (\"VolumeParams\"); }\n\n    //! Get the current raycasting algorithm\n    //! \\retval string - Current raycasting algorithm (Regular, Curvilinear, or Ospray) \n    std::string GetAlgorithm() const;\n\n    //! Set the current raycasting algorithm\n    //! \\param[in] string - Raycasting algorithm (Regular, Curvilinear, or Ospray)\n    void        SetAlgorithm(std::string algorithm);\n\n    void        SetAlgorithmByUser(std::string algorithm);\n    bool        GetAlgorithmWasManuallySetByUser() const;\n    void        SetAlgorithmWasManuallySetByUser(bool v);\n    static std::vector<float> GetSamplingRateMultiples();\n\n    //! Get the sampling rate multiplier used with the current raycasting algorithm\n    //! \\retval long - Sampling rate multiplier\n    long                      GetSamplingMultiplier() const;\n    \n    //! Set the sampling rate multiplier used with the current raycasting algorithm\n    //! \\param[in] long - Sampling rate multiplier\n    void                      SetSamplingMultiplier(long d);\n\n    using RenderParams::GetIsoValues;\n    using RenderParams::SetIsoValues;\n    vector<double> GetIsoValues(const string &variable) override;\n    void           SetIsoValues(const string &variable, const vector<double> &values) override;\n\n    //! Enable or disable lighting from the position of the camera\n    //! \\param[in] bool - Enable lighting (1/true) or disable lighting (0/false)\n    void  SetLightingEnabled(bool v);\n    \n    //! Get the state for whether lighting is enabled or disabled\n    //! \\retval bool - State for enabled lighting (1/true) or disabled lighting (0/false)\n    bool  GetLightingEnabled() const;\n    \n    //! Set the Phong Ambient lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model)\n    //! \\param[in] float - Phong ambient lighting coefficient\n    void  SetPhongAmbient(float v);\n    \n    //! Get the Phong Ambient lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model)\n    //! \\param[in] float - Phong ambient lighting coefficient\n    float GetPhongAmbient() const;\n\n    //! Set the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model)\n    //! \\param[in] float - Phong diffuse lighting coefficient\n    void  SetPhongDiffuse(float v);\n    \n    //! Get the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model)\n    //! \\param[in] float - Phong diffuse lighting coefficient\n    float GetPhongDiffuse() const;\n\n    //! Set the Phong Specular lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model)\n    //! \\param[in] float - Phong specular lighting coefficient\n    void  SetPhongSpecular(float v);\n    \n    //! Get the Phong Specular lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model)\n    //! \\param[in] float - Phong specular lighting coefficient\n    float GetPhongSpecular() const;\n    \n    //! Set the Phong Shininess lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model)\n    //! \\param[in] float - Phong shininess lighting coefficient\n    void  SetPhongShininess(float v);\n    \n    //! Get the Phong Diffuse lighting coefficient (https://en.wikipedia.org/wiki/Phong_reflection_model)\n    //! \\param[in] float - Phong shininess lighting coefficient\n    float GetPhongShininess() const;\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return (3); }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override\n    {\n        if (GetAlgorithm() == OSPVolmeAlgorithmName)\n            return GetVariableName();\n        else if (GetValueLong(UseColormapVariableTag, 0))\n            return GetColorMapVariableName();\n        else\n            return GetVariableName();\n    }\n\n    static const std::vector<std::string> GetAlgorithmNames(Type type = Type::Any);\n    static void                           Register(const std::string &name, Type type = Type::Any);\n\nprivate:\n    void _init();\n\n    struct AlgorithmEntry {\n        const std::string name;\n        const Type        type;\n        bool              operator==(const VolumeParams::AlgorithmEntry &b) { return std::tie(name, type) == std::tie(b.name, b.type); }\n    };\n    static std::vector<AlgorithmEntry> _algorithms;\n\n    static const std::string _algorithmWasManuallySetByUserTag;\n    static const std::string _isoValuesTag;\n    static const std::string _enabledIsoValuesTag;\n\npublic:\n    static const std::string _algorithmTag;\n\n    //! If this is enabled, the volume opacity will be controlled by the main variable while the colormapping will be determined by the colormap variable\n    static const std::string UseColormapVariableTag;\n    static const std::string SamplingRateMultiplierTag;\n\n    //! The VolumeDensityTag applies an opacity factor to the entirety of the volume rendering\n    //! in addition to the opacity applied in the Transfer Function.\n    //! Values range between 0.0 (completely transparent) and 1.0 (completely opaque).\n    static const std::string VolumeDensityTag;\n\n    static const std::string LightingEnabledTag;\n    static const std::string PhongAmbientTag;\n    static const std::string PhongDiffuseTag;\n    static const std::string PhongSpecularTag;\n    static const std::string PhongShininessTag;\n\n    static const std::string OSPDensity;\n    static const std::string OSPSampleRateScalar;\n    static const std::string OSPAmbientLightIntensity;\n    static const std::string OSPDirectionalLightIntensity;\n\n    static const std::string OSPVolmeAlgorithmName;\n};\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeRectilinear.h",
    "content": "#pragma once\n\n#include <vapor/VolumeRegular.h>\n\nnamespace VAPoR {\n\n//! \\class VolumeRectilinear\n//! \\ingroup Public_Render\n//!\n//! \\brief Rectilinear grid rendering algorithm\n//!\n//! \\author Stanislaw Jaroszynski\n//!\n\nclass VolumeRectilinear : public VolumeRegular {\npublic:\n    VolumeRectilinear(GLManager *gl, VolumeRenderer *renderer);\n    ~VolumeRectilinear();\n\n    static std::string GetName() { return \"Rectilinear\"; }\n    static Type        GetType() { return Type::DVR; }\n    virtual bool       RequiresChunkedRendering() { return true; }\n\n    virtual int            LoadData(const Grid *grid);\n    virtual ShaderProgram *GetShader() const;\n    virtual void           SetUniforms(const ShaderProgram *shader) const;\n    virtual float          GuestimateFastModeSpeedupFactor() const;\n    virtual int CheckHardwareSupport(const Grid *grid) const;\n\nprivate:\n    Texture2DArray _minTexture;\n    Texture2DArray _maxTexture;\n    Texture2D      _BBLevelDimTexture;\n    Texture2D      _coordLUTTexture;\n\n    int  _coordDims[3];\n    int  _coordSigns[3];\n    bool _useHighPrecisionTriangleRoutine;\n    bool _gridHasInvertedCoordinateSystemHandiness;\n\nprotected:\n    virtual std::string _addDefinitionsToShader(std::string shaderName) const;\n};\n\n//! \\class VolumeRectilinearIso\n//! \\ingroup Public_Render\n//!\n//! \\brief Rectilinear grid isosurface rendering algorithm\n//!\n//! \\author Stanislaw Jaroszynski\n//!\n//! Renders isosurfaces by ray tracing. This class is the same as the rectilinear DVR\n//! except it renders an isosurface\n\nclass VolumeRectilinearIso : public VolumeRectilinear {\npublic:\n    VolumeRectilinearIso(GLManager *gl, VolumeRenderer *renderer) : VolumeRectilinear(gl, renderer) {}\n    static std::string     GetName() { return \"Iso Rectilinear\"; }\n    static Type            GetType() { return Type::Iso; }\n    virtual ShaderProgram *GetShader() const;\n    virtual void           SetUniforms(const ShaderProgram *shader) const;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeRegular.h",
    "content": "#pragma once\n\n#include <vapor/VolumeGLSL.h>\n#include <vapor/Texture.h>\n\nnamespace VAPoR {\n\n//! \\class VolumeRegular\n//! \\ingroup Public_Render\n//!\n//! \\brief Regular grid rendering algorithm\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date Feburary, 2019\n//!\n//! Renders a regular grid by ray tracing. The CPU side just loads\n//! the scalar data and missing values as well as secondary data if needed\n//!\n//! The glsl code does a standard sampled ray tracing of the volume.\n\nclass VolumeRegular : public VolumeGLSL {\npublic:\n    VolumeRegular(GLManager *gl, VolumeRenderer *renderer);\n    ~VolumeRegular();\n\n    static std::string GetName() { return \"Regular\"; }\n    static Type        GetType() { return Type::DVR; }\n    virtual bool       RequiresChunkedRendering() { return false; }\n\n    virtual int            LoadData(const Grid *grid);\n    virtual int            LoadSecondaryData(const Grid *grid);\n    virtual void           DeleteSecondaryData();\n    virtual ShaderProgram *GetShader() const;\n    virtual void           SetUniforms(const ShaderProgram *shader) const;\n    virtual float          GuestimateFastModeSpeedupFactor() const;\n    virtual int CheckHardwareSupport(const Grid *grid) const;\n\nprotected:\n    Texture3D _data;\n    Texture3D _missing;\n    bool      _hasMissingData;\n\n    std::vector<size_t> _dataDimensions;\n\n    bool      _hasSecondData;\n    Texture3D _data2;\n    Texture3D _missing2;\n    bool      _hasMissingData2;\n\n    int                 _loadDataDirect(const Grid *grid, Texture3D *dataTexture, Texture3D *missingTexture, bool *hasMissingData);\n    virtual std::string _addDefinitionsToShader(std::string shaderName) const;\n};\n\n//! \\class VolumeRegularIso\n//! \\ingroup Public_Render\n//!\n//! \\brief Regular grid isosurface rendering algorithm\n//!\n//! \\author Stanislaw Jaroszynski\n//! \\date Feburary, 2019\n//!\n//! Renders isosurfaces by ray tracing. This does the same CPU side tasks\n//! as the volume renderer but it provides different GLSL code.\n\nclass VolumeRegularIso : public VolumeRegular {\npublic:\n    VolumeRegularIso(GLManager *gl, VolumeRenderer *renderer) : VolumeRegular(gl, renderer) {}\n    static std::string     GetName() { return \"Iso Regular\"; }\n    static Type            GetType() { return Type::Iso; }\n    virtual ShaderProgram *GetShader() const;\n    virtual void           SetUniforms(const ShaderProgram *shader) const;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeRenderer.h",
    "content": "#pragma once\n\n#include <vapor/Renderer.h>\n#include <vapor/Texture.h>\n#include <vapor/Framebuffer.h>\n#include <vapor/VolumeAlgorithm.h>\n#include <glm/fwd.hpp>\n\nnamespace VAPoR {\n\nclass RENDER_API VolumeRenderer : public Renderer {\npublic:\n    VolumeRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr);\n    VolumeRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string paramsType, std::string classType, std::string &instName, DataMgr *dataMgr);\n    ~VolumeRenderer();\n\n    static std::string GetClassType() { return (\"Volume\"); }\n\nprotected:\n    int  _initializeGL();\n    int  _paintGL(bool fast);\n    void _clearCache(){};\n\n    virtual std::string _getColorbarVariableName() const;\n\n    void                _drawScreenQuad();\n    void                _drawScreenQuadChuncked();\n    void                _generateChunkedRenderMesh(const float chunks);\n    bool                _wasTooSlowForFastRender() const;\n    void                _computeNewFramebufferRatio();\n    bool                _shouldUseChunkedRender(bool fast) const;\n    virtual bool        _usingColorMapData() const;\n    void                _saveOriginalViewport();\n    void                _restoreOriginalViewport();\n    void                _initializeFramebuffer(bool fast);\n    int                 _renderFramebufferToDisplay();\n    int                 _initializeAlgorithm();\n    int                 _loadData();\n    int                 _loadSecondaryData();\n    virtual std::string _getDefaultAlgorithmForGrid(const Grid *grid) const;\n    bool                _needToSetDefaultAlgorithm() const;\n\n    unsigned int     _VAO = (int)NULL;\n    unsigned int     _VBO = (int)NULL;\n    unsigned int     _VAOChunked = (int)NULL;\n    unsigned int     _VBOChunked = (int)NULL;\n    VolumeAlgorithm *_algorithm = nullptr;\n    Framebuffer      _framebuffer;\n\n    int                 _nChunks;\n    double              _lastRenderTime;\n    bool                _lastRenderWasFast;\n    int                 _originalViewport[4];\n    int                 _originalFramebuffer;\n    int                 _framebufferSize[2];\n    float               _framebufferRatio;\n    float               _previousFramebufferRatio;\n    std::vector<double> _dataMinExt;\n    std::vector<double> _dataMaxExt;\n\n    struct Cache {\n        std::string var = \"\";\n        size_t      ts = -1;\n        int         refinement;\n        int         compression;\n\n        bool        useColorMapVar = false;\n        std::string colorMapVar = \"\";\n\n        MapperFunction *   tf = nullptr;\n        std::vector<float> constantColor;\n        MapperFunction *   tf2 = nullptr;\n\n        std::string algorithmName = \"\";\n\n        std::vector<double> minExt;\n        std::vector<double> maxExt;\n\n        int  ospMaxCells;\n        int  ospTestCellId;\n        bool ospPT;\n        bool osp_force_regular;\n        bool osp_test_volume;\n        bool osp_decompose;\n        bool osp_enable_clipping;\n\n        bool needsUpdate;\n    } _cache;\n\n    friend class VolumeAlgorithm;\n};\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeResampled.h",
    "content": "#pragma once\n\n#include <vapor/VolumeRegular.h>\n\nnamespace VAPoR {\n\nclass VolumeResampled : public VolumeRegular {\npublic:\n    VolumeResampled(GLManager *gl) : VolumeRegular(gl) {}\n\n    static std::string GetName() { return \"Resampled\"; }\n\n    virtual int LoadData(const Grid *grid);\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeTest.h",
    "content": "#pragma once\n\n#include <vapor/VolumeRegular.h>\n\nnamespace VAPoR {\n\nclass VolumeTest : public VolumeRegular {\npublic:\n    VolumeTest(GLManager *gl);\n    ~VolumeTest();\n\n    static std::string GetName() { return \"Test\"; }\n    static Type        GetType() { return Type::Any; }\n\n    virtual int            LoadData(const Grid *grid);\n    virtual ShaderProgram *GetShader() const;\n\nprivate:\n    unsigned int xyCoordTexture;\n    unsigned int zCoordTexture;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/VolumeTest2.h",
    "content": "#pragma once\n\n#include <vapor/VolumeRegular.h>\n\nnamespace VAPoR {\n\nclass VolumeTest2 : public VolumeRegular {\npublic:\n    VolumeTest2(GLManager *gl);\n    ~VolumeTest2();\n\n    static std::string GetName() { return \"Test2\"; }\n    static Type        GetType() { return Type::Any; }\n\n    virtual int            LoadData(const Grid *grid);\n    virtual ShaderProgram *GetShader() const;\n\nprivate:\n    unsigned int xyCoordTexture;\n    unsigned int zCoordTexture;\n};\n\n}    // namespace VAPoR\n"
  },
  {
    "path": "include/vapor/WASP.h",
    "content": "\n#ifndef _WASP_H_\n#define _WASP_H_\n\n#include <vector>\n#include <map>\n#include <iostream>\n#include <netcdf.h>\n#include <vapor/NetCDFCpp.h>\n#include <vapor/Compressor.h>\n#include <vapor/EasyThreads.h>\n#include <vapor/utils.h>\n\nnamespace VAPoR {\n\n//! \\class WASP\n//! \\ingroup Public_VDC\n//! \\brief Implements WASP compression conventions for NetCDF\n//!\n//! \\author John Clyne\n//! \\date    July, 2014\n//!\n//! Implements WASP compression conventions for NetCDF by extending\n//! the NetCDFCPP class.\n//!\n//! The WASP conventions establish a policy for compressing, storing,\n//! and accessing arrays of data in NetCDF. This API provides\n//! an interface for NetCDF data adhering to the WASP conventions.\n//!\n//! Fundamental concepts of the WASP compression conventions include the\n//! following:\n//!\n//! \\li \\b Blocking Compressed arrays are decomposed into fixed size blocks,\n//! and each block is compressed individually and atomically. The rank of the\n//! block may be equal-to, or less-than that of the array. In the latter\n//! case blocking (and subsequent compression) is only performed on the\n//! the \\em n fastest varying array dimensions, where \\em n is the rank of\n//! the block.\n//!\n//! \\li \\b Transformation Each block is transformed prior to compression\n//! in an effort to decorrelate (remove redundancy) from the data. The\n//! transformation process is typically lossless up to floating point\n//! round off.\n//!\n//! \\li \\b Multi-resolution Some transforms, notably wavelets, exhibit the\n//! the property of multi-resolution: arrays can be reconstructed from\n//! transformed coefficients at progressively finer resolution. Resolution\n//! levels in the WASP API are specified with a \\b level parameter, in the\n//! range 0..max, where 0 is the coarsest resolution possible for a given\n//! variable, and \\em max corresponds to the original resolution of the\n//! array. The value of \\b -1 is an alias for \\em max.\n//!\n//! \\li <b> Progressive access </b> Aka embedded encoding, is the property by\n//! which compressed data may be progressively refined during decoding by\n//! transmitting (reading) more of the encoded data. The WASP API supports\n//! progressive access, but supports a discrete form of refinement: only\n//! a small, finite set of refinement levels, indicated by a \\b lod\n//! parameter that indexes into an ordered vector of available\n//! compression  ratios.\n//!\n//! This class inherits from Wasp::MyBase. Unless otherwise documented\n//! any method that returns an integer value is returning status. A negative\n//! value indicates failure. Error messages are logged via\n//! Wasp::MyBase::SetErrMsg(). In general, methods that return\n//! boolean values will not record an error message on failure.\n//!\n//! \\param wname Name of biorthogonal wavelet to use for data\n//! transformation. If not specified (if \\p wname is the empty string)\n//! no transformation or compression are performed. However, arrays\n//! are still decomposed into blocks as per the \\p bs parameter.\n//! See VAPoR::WaveFiltBior.\n//!\n//! \\param bs An ordered list of block dimensions that specifies the\n//! block decomposition of the variable. The rank of \\p bs may be less\n//! than that of a variable's array dimensions, in which case only\n//! the \\b n fastest varying variable dimensions will be blocked, where\n//! \\b n is the rank of \\p bs.\n//!\n//! \\param cratios A monotonically decreasing vector of\n//! compression ratios. Each element of \\p cratios is in\n//! the range 1\n//! (indicating no compression) to\n//! \\b max, where \\b max is the maximum compression supported by the\n//! specified combination of block size, \\p bs, and\n//! wavelet (See InqCompressionInfo()). If the underlying NetCDF file was\n//! created with the \\b numfiles parameter greater than one then the\n//! length of \\p cratios must exactly match that of \\b numfiles.\n//!\n//! \\param lod An index into the \\p cratios vector. A value of -1\n//! may be used to index the last element of \\p cratios\n//!\n//! \\param level Array dimensions refinement level for compressed\n//! variables. A value of 0 indicates\n//! the coarsest refinement level available, a value of one indicates\n//! next coarsest, and so on. The finest resolution available is given\n//! by InqVarNumRefLevels() - 1. If \\p level is less than 0 it is interpreted\n//! do indicate the finest grid resolution.\n//\nclass WASP_API WASP : public VAPoR::NetCDFCpp {\npublic:\n    //! default constructor\n    //!\n    //! Construct a WASP object\n    //!\n    //! \\param[in] nthreads Number of parallel execution threads\n    //! to be run during encoding and decoding of compressed data. A value\n    //! of 0, the default, indicates that the thread count should be\n    //! determined by the environment in a platform-specific manner, for\n    //! example using sysconf(_SC_NPROCESSORS_ONLN) under *nix OSes.\n    //!\n    //\n    WASP(int nthreads = 0);\n    virtual ~WASP();\n\n    //! Create a new NetCDF data set with support for WASP conventions\n    //!\n    //! \\param[in] path The file base name of the new NetCDF data set\n    //! \\param[in] cmode Same as in NetCDFCpp::Create()\n    //! \\param[in] initialsz Same as in NetCDFCpp::Create()\n    //! \\param[in] bufrsizehintp Same as in NetCDFCpp::Create()\n    //! \\param[in] numfiles An integer greater than or equal to one indicating\n    //! whether compressed\n    //! variables should be stored in separate files, one compression level\n    //! (level of detail) per file. A value of one indicates that all\n    //! compression levels for\n    //! compressed variables should be stored in the single file specified by\n    //! \\p path. A value greater than one results in the creation of\n    //! \\p numfile NetCDF files, each of which will contain a separate\n    //! compression level for any compressed variables. Variables that\n    //! are not compressed will be stored in their entirety in the file\n    //! named by \\p path.\n    //!\n    //! \\sa NetCDFCpp::Create(), NetCDFCpp::GetPaths()\n    //\n    virtual int Create(string path, int cmode, size_t initialsz, size_t &bufrsizehintp, int numfiles);\n\n    //! Open an existing NetCDF file\n    //!\n    //! \\param[in] path The file base name of the new NetCDF data set\n    //! \\param[in] mode Same as in NetCDFCpp::Open()\n    //!\n    //! \\sa NetCDFCpp::Open()\n    //\n    virtual int Open(string path, int mode);\n\n    //! \\copydoc NetCDFCpp::SetFill()\n    //\n    virtual int SetFill(int fillmode, int &old_modep);\n\n    //! \\copydoc NetCDFCpp::EndDef()\n    //\n    virtual int EndDef() const;\n\n    //! Close an open NetCDF file\n    //!\n    //! This method closes any currently opened NetCDF files that were\n    //! opened with Create() or Open().\n    //!\n    virtual int Close();\n\n    //! Return the dimension lengths associated with a variable.\n    //!\n    //! Returns the dimensions of the named variable at the\n    //! multi-resolution level indicated by \\p level.  If the variable\n    //! does not support multi-resolution (is not compressed with a\n    //! multi-resolution transform) the \\p level parameter is ignored,\n    //! the variable's native dimensions will be returned, and the value\n    //! of \\p bs will not be undefined.\n    //!\n    //! \\param[in] name Name of NetCDF variable\n    //! \\param[in] level Grid (dimension) refinement level. A value of 0 indicates\n    //! the coarsest refinement level available, a value of one indicates\n    //! next coarsest, and so on. The finest resolution available is given\n    //! by InqVarNumRefLevels() - 1. If \\p level is less than 0 it is interpreted\n    //! do indicate the finest grid resolution.\n    //!\n    //! \\param[out] dims Ordered list of variable's \\p name dimension lengths\n    //! at the grid hierarchy level indicated by \\p level\n    //! \\param[out] bs Ordered list of block dimension lengths\n    //! at the grid hierarchy level indicated by \\p level\n    //!\n    //! \\sa NetCDFCpp::InqVarDims(), InqVarNumRefLevels(),\n    //! InqDimsAtLevel()\n    //\n    virtual int InqVarDimlens(string name, int level, vector<size_t> &dims, vector<size_t> &bs) const;\n\n    //! \\copydoc NetCDFCpp::NetCDFCpp()\n    //\n    virtual int InqVarDims(string name, vector<string> &dimnames, vector<size_t> &dims) const;\n\n    //! Returns compression paramaters associated with the named variable\n    //!\n    //! This method returns various compression parameters associated\n    //! with a compressed variabled named by \\p name. If the variable\n    //! \\p name is not compressed \\p wname will be empty. If the variable\n    //! is not blocked \\p bs will be either empty or all elements\n    //! set to one.\n    //!\n    //! \\param[in] name The variable name.\n    //! \\param[out] wname The name of the wavelet used to transform the variable.\n    //! \\param[out] bs An ordered list of block dimensions that specifies the\n    //! block decomposition of the variable.\n    //! \\param[out] cratios The compression ratios available.\n    //!\n    virtual int InqVarCompressionParams(string name, string &wname, vector<size_t> &bs, vector<size_t> &cratios) const;\n\n    //! Return the dimensions of a multi-resolution grid at a specified level in\n    //! the hierarchy\n    //!\n    //! This static method calculates the coarsened dimensions of a\n    //! grid at a specified level in a multiresolution wavelet hierarchy.\n    //! The dimensions of an array are determined by the combination of\n    //! the multi-resolution wavelet used, specified by \\p wname, the\n    //! refinement level, \\p level, in the multi-resolution hierarchy,\n    //! the rank and dimension of the decomposition block, specified by\n    //! \\p bs, and the dimensions of the native (original) grid, \\p dims.\n    //!\n    //! \\param[in] wname wavelet name\n    //! \\param[in] level Grid (dimension) refinement level. A value of 0 indicates\n    //! the coarsest refinement level available, a value of one indicates\n    //! next coarsest, and so on. The finest resolution available is given\n    //! by InqVarNumRefLevels() - 1. If \\p level is less than 0 it is interpreted\n    //! do indicate the finest grid resolution.\n    //! \\param[in] dims Dimensions of native grid\n    //! \\param[in] bs Dimensions of native decomposition block. The rank of\n    //! \\p bs may be less than or equal to the rank of \\p dims.\n    //! \\param[out] dims_at_level Computed grid dimensions at the specified level\n    //! \\param[out] bs_at_level Computed block dimensions at the specified level\n    //!\n    //! \\sa VarOpenRead()\n    //\n    static int InqDimsAtLevel(string wname, int level, vector<size_t> dims, vector<size_t> bs, vector<size_t> &dims_at_level, vector<size_t> &bs_at_level);\n\n    //! Return the number of levels available in a variable's multiresolution\n    //! hierarchy.\n    //!\n    //! Returns the depth of the multi-resolution hierarchy for the variable\n    //! specified by \\p name. If the variable\n    //! does not support multi-resolution (is not compressed with a\n    //! multi-resolution transform) value of 1 is returned.\n    //!\n    //! \\param[in] name The name of the variable\n    //!\n    //! \\retval depth Upon success the number of levels in hierarchy\n    //! are returned. If \\p varname does not specify a known variable\n    //! a -1 is returned.\n    //\n    virtual int InqVarNumRefLevels(string name) const;\n\n    //! Compute the number of levels in a multi-resolution hierarchy\n    //!\n    //! This static method computes and returns the depth (number of levels) in a\n    //! a multi-resolution hierarch for a given wavelet, \\p wname,\n    //! and decomposition block, \\p bs.\n    //! It also computes the maximum compression ratio, \\p cratio, possible\n    //! for the\n    //! the specified combination of block size, \\p bs, and wavelet, \\p wname.\n    //! The maximum compression ratio is \\p cratio:1.\n    //!\n    //! \\param[in] wname wavelet name\n    //! \\param[in] bs Dimensions of native decomposition block. The rank of\n    //! \\p bs may be less than or equal to the rank of \\p dims.\n    //! \\param[out] nlevels Number of levels in hierarchy\n    //! \\param[out] maxcratio Maximum compression ratio\n    //!\n    //! bool status If \\p bs, \\p wname, or the combination there of is invalid\n    //! false is returned and the values of \\p nlevels and \\p maxcratio are\n    //! undefined. Upon success true is returned.\n    //!\n    static bool InqCompressionInfo(vector<size_t> bs, string wname, size_t &nlevels, size_t &maxcratio);\n\n    //! Define a new compressed variable\n    //!\n    //! \\param[in] name Same as NetCDFCpp::DefVar()\n    //! \\param[in] xtype Same as NetCDFCpp::DefVar()\n    //! \\param[in] dimnames Same as NetCDFCpp::DefVar()\n    //! \\param[in] wname Name of biorthogonal wavelet to use for data\n    //! transformation. See VAPoR::WaveFiltBior. If empty, the variable\n    //! will be blocked according to \\p bs, but will not be compressed.\n    //! \\param[in] bs An ordered list of block dimensions that specifies the\n    //! block decomposition of the variable.\n    //! array's associated dimension. The rank of \\p bs may be equal to\n    //! or less than\n    //! that of \\p dimnames. In the latter case only the rank(bs) fastest\n    //! varying dimensions of the variable will be blocked.\n    //! The dimension(s) of \\p bs[i] need not align with (be integral factors\n    //! of) the dimension lengths\n    //! associated with \\p dimnames in which case boundary blocks will be\n    //! padded. If \\p bs is empty, or the product of its elements is one,\n    //! the variable will not be blocked or compressed. Hence, the\n    //! \\p wname and \\p cratio parameters will be ignored. The variable\n    //! will not be defined as a \\b WASP variable. See InqVarWASP().\n    //! \\param[in] cratios A monotonically decreasing vector of\n    //! compression ratios. Each element of \\p cratios is in\n    //! the range 1\n    //! (indicating no compression) to\n    //! \\b max, where \\b max is the maximum compression supported by the\n    //! specified combination of block size, \\p bs, and\n    //! wavelet (See InqCompressionInfo()). If the underlying NetCDF file was\n    //! created with \\b numfiles parameter greater than one then the\n    //! length of \\p cratios must exactly match that of \\b numfiles.\n    //!\n    //! \\sa NetCDFCpp::DefVar(), Create(), InqCompressionInfo()\n    //\n    virtual int DefVar(string name, int xtype, vector<string> dimnames, string wname, vector<size_t> bs, vector<size_t> cratios);\n\n    //! Define a compressed variable with missing data values\n    //!\n    //! The defined variable may contain missing data values. These\n    //! values will not be transformed and compressed\n    //!\n    //! \\copydoc DefVar(\n    //!\tstring name, int xtype, vector <string> dimnames,\n    //!\tstring wname, vector <size_t> bs, vector <size_t> cratios\n    //! )\n    //!\n    //! \\param[in] missing_value Value of missing value indicator.\n    //!\n    //! \\sa NetCDFCpp::DefVar()\n    //!\n    virtual int DefVar(string name, int xtype, vector<string> dimnames, string wname, vector<size_t> bs, vector<size_t> cratios, double missing_value);\n\n    //! \\copydoc NetCDFCpp::DefVar()\n    // Is this needed?\n    virtual int DefVar(string name, int xtype, vector<string> dimnames) { return (NetCDFCpp::DefVar(name, xtype, dimnames)); };\n\n    //! \\copydoc NetCDFCpp::DefDim()\n    //\n    int DefDim(string name, size_t len) const;\n\n    //! Inquire whether a named variable is compressed\n    //!\n    //! \\param[in] name The name of the variable\n    //! \\param[out] compressed A boolean return value indicating whether\n    //! variable \\p name is compressed\n    //\n    virtual int InqVarCompressed(string varname, bool &compressed) const;\n\n    //! Inquire whether a variable is a WASP variable\n    //!\n    //! This method returns true if the variable named by \\p varname\n    //! was defined by the WASP API and is either compressed, blocked, or\n    //! both.\n    //!\n    int InqVarWASP(string varname, bool &wasp) const;\n\n    //! Prepare a variable for writing\n    //!\n    //! Compressed or blocked variables must be opened prior to writing.\n    //! This method initializes the variable named by \\p name for writing\n    //! using the PutVara() method. If the variable is defined as compressed\n    //! the \\p lod parameter indicates which compression levels will be stored.\n    //! Valid values for \\p lod are in the range 0..max, where \\p max the size\n    //! of cratios - 1.\n    //!\n    //! Any currently opened variable is first closed with Close()\n    //!\n    //! \\param[in] name Name of variable\n    //! \\param[in] lod Level-of-detail to save. If not -1, all LOD's from\n    //! 0 to \\p lod will subsequently be written.\n    //!\n    //! \\note Is \\p lod needed? Since cratios can be specified on a per\n    //! variable basis perhaps this is not needed? For single file\n    //! representations it would be better to limit the lod using cratios,\n    //! which will result in a smaller file.\n    //!\n    //! \\sa PutVara(),\n    //\n    virtual int OpenVarWrite(string name, int lod);\n\n    //! Prepare a variable for reading\n    //!\n    //! Compressed or blocked variables must be opened prior to reading.\n    //! This method initializes the variable named by \\p name for reading\n    //! using the GetVara() or GetVar() methods. If the variable is\n    //! defined as compressed\n    //! the \\p lod parameter indicates which compression levels will used\n    //! during reconstruction of the variable.\n    //! Valid values for \\p lod are in the range 0..max, where \\p max the size\n    //! of \\b cratios - 1.\n    //! If the transform used to compress this variable supports\n    //! multiresolution then the \\p level parameter indicates the\n    //! grid hierarchy refinement level for which to reconstruct the data.\n    //!\n    //! Any currently opened variable is first closed with Close()\n    //!\n    //! \\param[in] name Name of variable\n    //! \\param[in] lod Level-of-detail to read.\n    //! \\param[in] level Grid refinement level\n    //!\n    //! \\sa GetVara()\n    //\n    virtual int OpenVarRead(string name, int level, int lod);\n\n    //! Close the currently opened variable\n    //!\n    //! If a variable is opened for writing this method will flush\n    //! all buffers to disk and perform cleanup. If opened for reading\n    //! only cleanup is performed. If no variables are open this method\n    //! is a no-op.\n    //\n    //!\n    virtual int CloseVar();\n\n    //! Write an array of values to the currently opened variable\n    //!\n    //! The currently opened variable may or may not be a WASP\n    //! variable (See InqVarWASP()).\n    //!\n    //! The combination of \\p start and \\p count specify the\n    //! coordinates of a hyperslab to write as described by\n    //! NetCDFCpp::PutVara(). However, for blocked data dimensions\n    //! the values of \\p start and \\p count must be block aligned\n    //! unless the hyperslab includes the array boundary, in which case\n    //! the hyperslab must be aligned to the boundary.\n    //!\n    //! \\param[in] start A vector of block-aligned integers specifying\n    //! the index in the variable where the first of the data values will\n    //! be read. See NetCDFCpp::PutVara()\n    //! \\param[in] count A vector of size_t, block-aligned integers\n    //! specifying the edge\n    //! lengths along each dimension of the block of data values to be read.\n    //! See NetCDFCpp::PutVara()\n    //! \\param[in] data Same as NetCDFCpp::PutVara()\n    //!\n    //! \\sa OpenVarWrite();\n    //\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const float *data);\n    virtual int PutVar(const float *data);\n\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const double *data);\n    virtual int PutVar(const double *data);\n\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const int *data);\n    virtual int PutVar(const int *data);\n\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const int16_t *data);\n    virtual int PutVar(const int16_t *data);\n\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const unsigned char *data);\n    virtual int PutVar(const unsigned char *data);\n\n    //! Write an array of masked values to the currently opened variable\n    //!\n    //! This version of PutVar() handles missing data values whose\n    //! presence is indicated by a boolean mask, \\p mask. Missing values\n    //! are replaced with values that perform better when compressed (e.g. the\n    //! average of the field)\n    //!\n    //! \\copydoc PutVar(\n    //!    vector <size_t> start, vector <size_t> count, const float *data\n    //! )\n    //!\n    //! \\param[in] mask a boolean array with the same shape as \\p data\n    //! indicting valid and invalid values in \\p data. Elements of \\p data\n    //! corresponding to false values in \\p mask are not preserved when\n    //! written to storage.\n    //!\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const float *data, const unsigned char *mask);\n    virtual int PutVar(const float *data, const unsigned char *mask);\n\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const double *data, const unsigned char *mask);\n    virtual int PutVar(const double *data, const unsigned char *mask);\n\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const int *data, const unsigned char *mask);\n    virtual int PutVar(const int *data, const unsigned char *mask);\n\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const int16_t *data, const unsigned char *mask);\n    virtual int PutVar(const int16_t *data, const unsigned char *mask);\n\n    virtual int PutVara(vector<size_t> start, vector<size_t> count, const unsigned char *data, const unsigned char *mask);\n    virtual int PutVar(const unsigned char *data, const unsigned char *mask);\n\n    //! Read a hyper-slab of values from the currently opened variable\n    //!\n    //! The currently opened variable may or may not be a WASP\n    //! variable (See InqVarWASP()).\n    //!\n    //! If a compressed variable is being read and the transform\n    //! supports multi-resolution the method InqVarDimlens()\n    //! should be be used to determine the dimensions of the variable\n    //! at the opened refinement level.\n    //!\n    //! \\param[in] start A vector of size_t integers specifying the index in\n    //! the variable where the first of the data values will be read.\n    //! The coordinates are specified relative to the dimensions of the\n    //! array at the currently opened refinement level.\n    //! See NetCDFCpp::InqVarDimlens()\n    //! \\param[in] count  A vector of size_t integers specifying the\n    //! edge lengths along each dimension of the hyperslab of data values to\n    //! be read.\n    //! The coordinates are specified relative to the dimensions of the\n    //! array at the currently opened refinement level.  See NetCDFCpp::PutVara()\n    //! \\param[out] data Same as NetCDFCpp::PutVara()\n    //!\n    //! \\sa InqVarDimlens(), OpenVarRead()\n    //\n    virtual int GetVara(vector<size_t> start, vector<size_t> count, float *data);\n    virtual int GetVara(vector<size_t> start, vector<size_t> count, double *data);\n    virtual int GetVara(vector<size_t> start, vector<size_t> count, int *data);\n    virtual int GetVara(vector<size_t> start, vector<size_t> count, int16_t *data);\n\n    virtual int GetVara(vector<size_t> start, vector<size_t> count, unsigned char *data);\n\n    //! Read a hyper-slab of blocked values from currently opened variable\n    //!\n    //! This method is identical to GetVara() with the exceptions\n    //! that:\n    //! \\li The vectors \\p start and \\p count must be aligned\n    //! with the underlying storage block of the variable. See\n    //! WASP::DefVar()\n    //!\n    //! \\li The hyperslab copied to \\p data will preserve its underlying\n    //! storage blocking (the data will not be contiguous)\n    //!\n    //! \\param[in] start A block-aligned vector of size_t integers specifying\n    //! the index in\n    //! the variable where the first of the data values will be read.\n    //! \\param[in] count  A block-aligned vector of size_t integers specifying the\n    //! edge lengths along each dimension of the hyperslab of data values to\n    //! be read.\n    //!\n    //! \\sa WASP::DefVar()\n    //\n    virtual int GetVaraBlock(vector<size_t> start, vector<size_t> count, float *data);\n    virtual int GetVaraBlock(vector<size_t> start, vector<size_t> count, double *data);\n    virtual int GetVaraBlock(vector<size_t> start, vector<size_t> count, int *data);\n    virtual int GetVaraBlock(vector<size_t> start, vector<size_t> count, int16_t *data);\n    virtual int GetVaraBlock(vector<size_t> start, vector<size_t> count, unsigned char *data);\n\n    //! Read an array of values from the currently opened variable\n    //!\n    //! The currently opened variable may or may not be a WASP\n    //! variable (See InqVarWASP()).\n    //!\n    //! The entire variable is read and copied into the array pointed to\n    //! by \\p data. The caller is responsible for ensuring that\n    //! adequate space is availble in \\p data.\n    //!\n    //! If a compressed variable is being read and the transform\n    //! supports multi-resolution the method InqVarDimlens()\n    //! should be be used to determine the dimensions of the variable\n    //! at the opened refinement level\n    //!\n    //! \\param[in] data Same as NetCDFCpp::PutVara()\n    //!\n    //! \\sa InqVarDimlens(), OpenVarRead()\n    //\n    virtual int GetVar(float *data);\n    virtual int GetVar(double *data);\n    virtual int GetVar(int *data);\n    virtual int GetVar(int16_t *data);\n    virtual int GetVar(unsigned char *data);\n\n    //! Copy a variable from one WASP file to another WASP file\n    //!\n    //! Copy a variable from the WASP file associated with this\n    //! object instance to the WASP file associated with \\p wasp\n    //! The variable \\p varname must be defined in both the source\n    //! and destination files, and must have matching dimensions.\n    //!\n    //! If the source and destination variables are compressed this method\n    //! attempts to copy data verbatim, avoiding decoding and encoding.\n    //\n    virtual int CopyVar(string varname, WASP &wasp);\n\n    //! Copy a variable from a NetCDF file to a WASP file\n    //!\n    //! Copy a variable from the NetCDF file associated with \\p ncdf\n    //! to the WASP file associated with this object instance.\n    //! The variable \\p varname must be defined in both the source\n    //! and destination files, and must have matching dimensions.\n    //\n    virtual int CopyVarFrom(string varname, NetCDFCpp &ncdf);\n\n    //! Copy a variable from a WASP file to a NetCDF file\n    //!\n    //! Copy a variable from the WASP file associated this object instance\n    //! to the WASP file associated with \\p ncdf.\n    //! The variable \\p varname must be defined in both the source\n    //! and destination files, and must have matching dimensions.\n    //\n    virtual int CopyVarTo(string varname, NetCDFCpp &ncdf);\n\n    //! Return the NetCDF file paths that would be created from a base\n    //! path.\n    //!\n    //!\n    //! \\param[in] path The file base name of the new NetCDF data set\n    //! \\param[in] numfiles An integer greater than or equal to one indicating\n    //! the number of files to split a variable into\n    //! \\retval vector The path names generated from \\p path\n    //!\n    //! \\sa Create()\n    //\n    static std::vector<string> GetPaths(string path, int numfiles)\n    {\n        if (numfiles > 1) {\n            return (mkmultipaths(path, numfiles));\n        } else {\n            std::vector<string> t(1, path);\n            return (t);\n        }\n    }\n\n    //! NetCDF attribute name specifying Wavelet name\n    static string AttNameWavelet() { return (\"WASP.Wavelet\"); }\n\n    //! NetCDF attribute name specifying compression block dimensions\n    static string AttNameBlockSize() { return (\"WASP.BlockSize\"); }\n\n    //! NetCDF attribute name specifying number of compression files\n    static string AttNameNumFiles() { return (\"WASP.NumFiles\"); }\n\n    //! NetCDF attribute name specifying compression ratios\n    static string AttNameCRatios() { return (\"WASP.CRatios\"); }\n\n    //! NetCDF attribute name specifying if this is a WASP file or\n    //! variable\n    static string AttNameWASP() { return (\"WASP\"); }\n\n    //! NetCDF attribute name specifying names of uncompressed dimensions\n    static string AttNameDimNames() { return (\"WASP.DimNames\"); }\n\n    //! NetCDF attribute name specifying if missing data values are present\n    static string AttNameMissingValue() { return (\"WASP.MissingValue\"); }\n\n    //! NetCDF attribute name specifying WASP version number\n    static string AttNameVersion() { return (\"WASP.Version\"); }\n\nprivate:\n    Wasp::EasyThreads * _et;\n    int                 _nthreads;\n    vector<NetCDFCpp>   _ncdfcs;\n    vector<NetCDFCpp *> _ncdfcptrs;         // pointers into _ncdfcs;\n    bool                _waspFile;          // Is this a WASP file\n    int                 _numfiles;          // Number of NetCDF files\n    int                 _currentVersion;    // Current WASP version number;\n    int                 _fileVersion;       // version number of opened file;\n    Wasp::SmartBuf      _blockbuf;          // Dynamic storage for blocks\n    Wasp::SmartBuf      _coeffbuf;          // Dynamic storage wavelet coefficients\n    Wasp::SmartBuf      _sigbuf;            // Dynamic storage encoded signficance maps\n\n    bool                 _open;                // compressed variable open for reading or writing?\n    string               _open_wname;          // wavelet name of opened variable\n    vector<size_t>       _open_bs;             // block size of opened variable\n    vector<size_t>       _open_cratios;        // compression ratios of opened variable\n    vector<size_t>       _open_udims;          // uncompressed dims of opened variable\n    vector<size_t>       _open_dims;           // compressed dims of opened variable\n    int                  _open_lod;            // level-of-detail of opened variable\n    int                  _open_level;          // grid refinement level of opened variable\n    bool                 _open_write;          // opened variable open for writing?\n    bool                 _open_waspvar;        // opened variable is a WASP variable?\n    string               _open_varname;        // name of opened variable\n    nc_type              _open_varxtype;       // external type of opened variable\n    vector<Compressor *> _open_compressors;    // Compressor for opened variable\n\n    int _GetBlockAlignedDims(vector<string> dimnames, vector<size_t> bs, vector<string> &badimnames, vector<size_t> &badims) const;\n\n    int _GetCompressedDims(vector<string> dimnames, string wname, vector<size_t> bs, vector<size_t> cratios, int xtype, vector<string> &cdimnames, vector<size_t> &cdims,\n                           vector<string> &encoded_dim_names, vector<size_t> &encoded_dims) const;\n\n    int _InqDimlen(string name, size_t &len) const;\n\n    void _get_encoding_vectors(string wname, vector<size_t> bs, vector<size_t> cratios, int xtype, vector<size_t> &ncoeffs, vector<size_t> &encoded_dims) const;\n\n    bool _validate_compression_params(string wname, vector<size_t> dims, vector<size_t> bs, vector<size_t> cratios) const;\n\n    bool _validate_put_vara_compressed(vector<size_t> start, vector<size_t> count, vector<size_t> bs, vector<size_t> udims, vector<size_t> cratios) const;\n\n    bool _validate_get_vara_compressed(vector<size_t> start, vector<size_t> count, vector<size_t> bs, vector<size_t> udims, vector<size_t> cratios, bool unblock) const;\n\n    int _get_compression_params(string name, vector<size_t> &bs, vector<size_t> &cratios, vector<size_t> &udims, vector<size_t> &dims, string &wname) const;\n\n    template<class T, class U> int _GetVara(vector<size_t> start, vector<size_t> count, bool unblock, T *data, U dummy);\n\n    template<class T> int _GetVara(vector<size_t> start, vector<size_t> count, bool unblock_flag, T *data);\n\n    static void _dims_at_level(vector<size_t> dims, vector<size_t> bs, int level, string wname, vector<size_t> &dims_level, vector<size_t> &bs_level);\n\n    static vector<string> mkmultipaths(string path, int n);\n\n    template<class T, class U> int _PutVara(vector<size_t> start, vector<size_t> count, const T *data, const unsigned char *mask, U dummy);\n\n    template<class T> int _PutVara(vector<size_t> start, vector<size_t> count, const T *data, const unsigned char *mask);\n\n    template<class T> int _CopyHyperSlice(string varname, NetCDFCpp &src_ncdf, NetCDFCpp &dst_ncdf, vector<size_t> start, vector<size_t> count, T *buf) const;\n\n    int _CopyVar(string varname, NetCDFCpp &src_ncdf, NetCDFCpp &dst_ncdf) const;\n\n    // Determine POD type\n    //\n    int _NetCDFType(float dummy) { return NC_FLOAT; }\n    int _NetCDFType(char dummy) { return NC_BYTE; }\n    int _NetCDFType(double dummy) { return NC_DOUBLE; }\n    int _NetCDFType(unsigned char dummy) { return NC_UBYTE; }\n    int _NetCDFType(int16_t dummy) { return NC_SHORT; }\n    int _NetCDFType(int dummy) { return NC_INT; }\n    int _NetCDFType(long dummy) { return NC_INT64; }\n};\n\n}    // namespace VAPoR\n\nnamespace Wasp {\n}\n\n#endif    //\t_WASP_H_\n"
  },
  {
    "path": "include/vapor/WaveCodecIO.h",
    "content": "//\n// $Id$\n//\n#ifndef _WaveCodeIO_h_\n#define _WaveCodeIO_h_\n\n#include <vapor/VDFIOBase.h>\n#include <vapor/SignificanceMap.h>\n#include <vapor/Compressor.h>\n#include <vapor/EasyThreads.h>\n#include <vapor/NCBuf.h>\n\n#ifdef PARALLEL\n    #include <mpi.h>\n#endif\n\nnamespace VAPoR {\n\n//\n//! \\class WaveCodecIO\n//! \\brief A sub-region reader for VDF files\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class provides an API for reading and writing\n//! VDC2 data. VDC2 data may be accessed with two forms of\n//! wavelet based progressive\n//! refinement, : hierarchical or level-of-detail. The former supports\n//! coarsening and refinement of the sampling grid resolution (the\n//! dimensions of the sampling grid) at varying\n//! powers-of-two, and is controled by the \\p reflevel parameter. The latter\n//! allows for arbitrary approximations by restricting  the number of\n//! wavelet basis coefficients used when reconstructing the data from\n//! their wavelet representation. The level-of-detail is controled with\n//! the \\p lod parameter.\n//\nclass VDF_API WaveCodecIO : public VDFIOBase, protected Wasp::EasyThreads {\npublic:\n    //! \\copydoc VDFIOBase::VDFIOBase(MetadataVDC &)\n    //!\n    //! \\param[in] nthreads Number of execution threads that may be used by\n    //! the class for parallel execution. If zero, the system hardware will\n    //! be queried via sysconf to determine the number of processors\n    //! available and this value will be used.\n    //\n    WaveCodecIO(const MetadataVDC &metadata, int nthreads = 0);\n\n    //! \\copydoc VDFIOBase::VDFIOBase(const string &)\n    //!\n    //! \\param[in] nthreads Number of execution threads that may be used by\n    //! the class for parallel execution. If zero, the system hardware will\n    //! be queried via sysconf to determine the number of processors\n    //! available and this value will be used.\n    //\n    WaveCodecIO(const string &metafile, int nthreads = 0);\n\n#ifdef VAPOR3_0_0_ALPHA\n    WaveCodecIO(const size_t dim[3], const size_t bs[3], int numTransforms, const vector<size_t> cratios, const string &wname, const string &filebase);\n\n    WaveCodecIO(const vector<string> &files);\n#endif\n\n    virtual ~WaveCodecIO();\n\n    //! Open the named variable for reading\n    //!\n    //! This method prepares a data volume (slice), indicated by a\n    //! variable name and time step pair, for subsequent read operations by\n    //! methods of this class.  The number of the refinement levels\n    //! parameter, \\p reflevel, indicates the resolution of the volume in\n    //! the multiresolution hierarchy. The valid range of values for\n    //! \\p reflevel is [0..max_refinement], where \\p max_refinement is the\n    //! maximum refinement level of the data set: Metadata::GetNumTransforms().\n    //! A value of zero indicates the\n    //! coarsest resolution data, a value of \\p max_refinement (or -1) indicates\n    //! the\n    //! finest resolution data.\n    //! The level-of-detail parameter, \\p lod, selects\n    //! the approximation level. Valid values for \\p lod are integers in\n    //! the range 0..GetCRatios().size()-1, or the value -1 may be used\n    //! to select the best approximation available: GetCRatios().size()-1.\n    //!\n    //! An error occurs, indicated by a negative return value, if the\n    //! volume identified by the {varname, timestep, reflevel, lod} tupple\n    //! is not available. Note the availability of a volume can be tested\n    //! with the VariableExists() method.\n    //!\n    //! \\param[in] timestep Time step of the variable to read\n    //! \\param[in] varname Name of the variable to read\n    //! \\param[in] reflevel Refinement level of the variable. A value of -1\n    //! indicates the maximum refinment level defined for the VDC\n    //! \\param[in] lod Approximation level of the variable. A value of -1\n    //! indicates the maximum approximation level defined for the VDC\n    //! \\retval status Returns a non-negative value on success\n    //!\n    //! \\sa Metadata::GetVariableNames(), Metadata::GetNumTransforms(),\n    //! GetNumTimeSteps(), GetCRatios()\n    //!\n    virtual int OpenVariableRead(size_t timestep, const char *varname, int reflevel = 0, int lod = 0);\n\n    //! Open the named variable for writing\n    //!\n    //! Prepare a VDC for writing a data volume (slice).\n    //! The data volume is identified by the specfied time step and\n    //! variable name. The number of resulting approximations for\n    //! the data volume is determined by the Metadata object used to\n    //! initialize the class. Moreover, the number of levels-of-detail actually\n    //! saved to the data collection are determined by \\p lod. If\n    //! \\p lod is maximum level of detail (or the special value -1, the default)\n    //! all of the wavelet coefficients are saved, and it is possible to\n    //! fully reconstruct the volume later without loss of information (beyond\n    //! floating point round off).\n    //!\n    //! \\param[in] timestep Time step of the variable to read\n    //! \\param[in] varname Name of the variable to read\n    //! \\param[in] lod Level of detail saved. A value of -1\n    //! indicates the maximum level of detail.\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //! \\sa Metadata::GetVariableNames(), Metadata::GetNumTransforms()\n    //!\n    virtual int OpenVariableWrite(size_t timestep, const char *varname, int reflevel = -1 /*ignored*/, int lod = -1);\n\n    //! Close the currently opened variable.\n    //!\n    //! \\sa OpenVariableWrite(), OpenVariableRead()\n    //\n    virtual int CloseVariable();\n\n    //! Read in and return a subregion from the currently opened\n    //! data volume.\n    //!\n    //! The \\p bmin and \\p bmax vectors identify the minimum and\n    //! maximum extents, in block coordinates, of the subregion of interest. The\n    //! minimum valid value of 'bmin' is (0,0,0), the maximum valid value of\n    //! \\p bmax is (nbx-1,nby-1,nbz-1), where nx, ny, and nz are the\n    //! block dimensions of the volume at the currently opened refinement\n    //! level as retuned by GetDimBlk().\n    //! The volume\n    //! returned is stored in the memory region pointed to by \\p region. It\n    //! is the caller's responsbility to ensure adequate space is available.\n    //!\n    //! \\param[in] bmin Minimum region extents in block coordinates\n    //! \\param[in] bmax Maximum region extents in block coordinates\n    //! \\param[out] region The requested volume subregion\n    //! \\param[in] unblock If true, unblock the data before copying to \\p region\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //!\n    //! \\sa OpenVariableRead(), GetBlockSize(), MapVoxToBlk()\n    //\n    virtual int BlockReadRegion(const size_t bmin[3], const size_t bmax[3], float *region, bool unblock = true);\n\n    //! Read in and return a subregion from the currently opened\n    //! data volume.\n    //!\n    //! This method is similar to BlockReadRegion() with the exception\n    //! that the region bounds are specified in voxel coordinates.\n    //! The \\p min and \\p max vectors identify the minimum and\n    //! maximum extents, in voxel coordinates, of the subregion of interest. The\n    //! minimum valid value of 'min' is (0,0,0), the maximum valid value of\n    //! \\p max is (nx-1,ny-1,nz-1), where nx, ny, and nz are the\n    //! voxel dimensions of the volume at the currently opened refinement\n    //! level as returned by GetDim().\n    //!\n    //! The volume\n    //! returned is stored in the memory region pointed to by \\p region. It\n    //! is the caller's responsbility to ensure adequate space is available.\n    //!\n    //! \\param[in] min Minimum region extents in voxel coordinates\n    //! \\param[in] max Maximum region extents in voxel coordinates\n    //! \\param[out] region The requested volume subregion\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //! \\sa OpenVariableRead(), GetDim(), MapVoxToBlk()\n    //\n    virtual int ReadRegion(const size_t min[3], const size_t max[3], float *region);\n\n    virtual int ReadRegion(float *region);\n\n    //! Read the next volume slice from the currently opened file\n    //!\n    //! Read in and return a slice (2D array) of\n    //! voxels from the currently opened data volume at the current\n    //! refinement level.\n    //! Subsequent calls will read successive slices\n    //! until the entire volume has been read.\n    //! It is the caller's responsibility to ensure that the array pointed\n    //! to by \\p slice contains enough space to accomodate\n    //! an NX by NY dimensioned slice, where NX is the dimesion of the\n    //! volume along the X axis, specified\n    //! in **voxels**, and NY is the Y axis dimension, as returned by\n    //! GetDim().\n    //!\n    //! \\note ReadSlice returns 0 if the entire volume has been read.\n    //!\n    //! \\param[out] slice The requested volume slice\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //! \\sa OpenVariableRead(), Metadata::GetDim()\n    //!\n    //\n    virtual int ReadSlice(float *slice);\n\n    //! Write a volume subregion to the currently opened progressive\n    //! access data volume.\n    //!\n    //! This method is identical to the WriteRegion() method with the exception\n    //! that the region boundaries are defined in block, not voxel, coordinates.\n    //! Secondly, unless the 'block' parameter  is set, the internal\n    //! blocking of the data will be preserved. I.e. the data are assumed\n    //! to already be blocked.\n    //!\n    //! The number of voxels contained in \\p region must be the product\n    //! over i :\n    //!\n    //! \\p (bmax[i] - \\p bmin[i] + 1) * bs[i]\n    //!\n    //! where bs[i] is the ith dimension of the block size.\n    //!\n    //! \\param[in] bmin Minimum region extents in block coordinates\n    //! \\param[in] bmax Maximum region extents in block coordinates\n    //! \\param[in] region The volume subregion to write\n    //! \\param[in] block If true, block the data before writing/transforming\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //! \\sa OpenVariableWrite() SetBoundarPadOnOff()\n    //\n    virtual int BlockWriteRegion(const float *region, const size_t bmin[3], const size_t bmax[3], bool block = true);\n\n    //! Write a volume subregion to the currently opened progressive\n    //! access data volume.\n    //!\n    //! This method is identical to the WriteRegion() method with the exception\n    //! that the region boundaries are defined in block, not voxel, coordinates.\n    //! Secondly, unless the 'block' parameter  is set, the internal\n    //! blocking of the data will be preserved. I.e. the data are assumed\n    //! to already be blocked.\n    //!\n    //! The number of voxels contained in \\p region must be the product\n    //! over i :\n    //!\n    //! \\p (max[i] - \\p min[i] + 1)\n    //!\n    //! \\param[in] min Minimum region extents in voxel coordinates\n    //! \\param[in] max Maximum region extents in voxel coordinates\n    //! \\param[in] region The volume subregion to write\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //! \\sa OpenVariableWrite(), GetBlockSize(), MapVoxToBlk()\n    //! \\sa SetBoundarPadOnOff()\n    //!\n    //! \\note Unexpected results may be obtained if this method is\n    //! invoked multiple times for adjacent regions if the region\n    //! boundaries do not coincide with block boundaries.\n    //!\n    virtual int WriteRegion(const float *region, const size_t min[3], const size_t max[3]);\n\n    virtual int WriteRegion(const float *region);\n\n    //! Write a single slice of voxels to the currently opened variable\n    //!\n    //! Transform and write a single slice (2D array) of voxels to the variable\n    //! indicated by the most recent call to OpenVariableWrite().\n    //! The dimensions of a slices is NX by NY,\n    //! where NX is the dimesion of the volume along the X axis, specified\n    //! in voxels, and NY is the Y axis dimension.\n    //!\n    //! This method should be called exactly NZ times for each opened variable,\n    //! where NZ is the dimension of the volume in voxels along the Z axis. Each\n    //! invocation should pass a successive slice of volume data.\n    //!\n    //! \\param[in] slice A slices of volume data\n    //! \\retval status Returns a non-negative value on success\n    //! \\sa OpenVariableRead()\n    //!\n    virtual int WriteSlice(const float *slice);\n\n    //! Toggle padding of data on writes\n    //!\n    //! If true, incomplete data blocks will be padded prior to transformation\n    //! and storage to disk. A block is incomplete iff it is a boundary block\n    //! (a block that contains a volume region boundary)\n    //! and the extents of the region do not coincide with block boundaries\n    //!\n    //! \\param[in] pad Boolean indicating whether padding should (true) or should\n    //! not (false) take place\n    //!\n    //! \\sa GetBoundaryMode()\n    //!\n    virtual void SetBoundaryPadOnOff(bool pad) { _pad = pad; };\n\n    //! Return the data range of the currently opened volume as a two-element array\n    //!\n    //! This method returns the minimum and maximum data values\n    //! of the currently opened variable within the valid domain\n    //! bounds. See GetValidRegion().\n    //!\n    //! \\note The range values returned are valid for the native\n    //! data only. Data approximations produced by level-of-detail or\n    //! through multi-resolution may have values outside of this range.\n    //!\n    //! \\retval[out] range  A two-element vector containing the current\n    //! minimum and maximum.\n    //!\n    //\n    const float *GetDataRange() const { return (_dataRange); }\n\n    //! Return the valid region bounds for the currently opened\n    //! variable\n    //!\n    //! This method returns the minimum and maximum valid coordinate\n    //! bounds (in voxels) of the currently opened variable. In general,\n    //! the minimum bounds are (0,0,0) and the maximum bounds are\n    //! (nx-1, ny-1, nz-1), where nx, ny, and nz are the volume dimensions\n    //! returned by GetDim(). However, partial regions (sub-volumes) may be\n    //! written to the VDC as well.\n    //!\n    //!\n    //! \\param[in] reflevel Refinement level of the variable\n    //! \\param[out] min Minimum coordinate bounds (in voxels) of volume\n    //! \\param[out] max Maximum coordinate bounds (in voxels) of volume\n    //! \\retval status A non-negative int is returned on success\n    //!\n    void GetValidRegion(size_t min[3], size_t max[3], int reflevel) const;\n\n    //! Returns true if the indicated data volume exists on disk\n    //!\n    //! Returns true if the variable identified by the timestep, variable\n    //! name, refinement level, and level-of-detail is present on disk.\n    //! Returns 0 if\n    //! the variable is not present.\n    //! \\param[in] ts A valid time step from the Metadata object used\n    //! to initialize the class\n    //! \\param[in] varname A valid variable name\n    //! \\param[in] reflevel Ignored\n    //! \\param[in] lod Compression level of detail requested. The coarsest\n    //! approximation level is 0 (zero). A value of -1 indicates the finest\n    //! refinement level contained in the VDC.\n    //\n    virtual int VariableExists(size_t ts, const char *varname, int reflevel = 0, int lod = 0) const;\n\n    //! Return the maximimum compression ratio possible\n    //!\n    //! This static methods returns the maximum possible compression ratio\n    //! possible for a given combination of blocksize, \\p ps, wavele name,\n    //! \\p wname, and wavelet boundary handling mode, \\p wmode.\n    //!\n    //! \\param[in] bs A three-element vector providing the dimensions of\n    //! a block\n    //! \\param[in] wavename The name of the wavelet\n    //! \\param[in] wmode The wavelet boundary handling mode\n    //!\n    //! \\retval ratio A value of zero is returned if the wavename or wmode\n    //! are invalid, otherwise the maximum possible data compression ratio\n    //! is returned.\n    //!\n    //! \\sa Metadata::GetCRatios()\n    //!\n    static size_t GetMaxCRatio(const size_t bs[3], string wavename, string wmode);\n\n    //! \\copydoc Metadata::GetNumTransforms()\n    //\n    virtual int GetNumTransforms() const;\n\n    //! \\copydoc Metadata::GetBlockSize(size_t, int)\n    //\n    virtual void GetBlockSize(size_t bs[3], int reflevel) const;\n#ifdef PARALLEL\n    void SetIOComm(MPI_Comm NewIOComm) { _IO_Comm = NewIOComm; };\n#endif\n    void         SetCollectiveIO(bool newCollectiveIO) { _collectiveIO = newCollectiveIO; };\n    friend void *RunBlockReadRegionThread(void *object);\n    friend void *RunBlockWriteRegionThread(void *object);\n\nprivate:\n#ifdef PARALLEL\n    MPI_Comm _IO_Comm;\n#endif\n    bool   _collectiveIO;\n    double _xformMPI;\n    double _methodTimer;\n    double _methodThreadTimer;\n    double _ioMPI;\n    //\n    // Threaded read object for parallel inverse transforms\n    // (data reconstruction)\n    //\n    class ReadWriteThreadObj {\n    public:\n        ReadWriteThreadObj(WaveCodecIO *wc, int id, float *region, const size_t bmin_p[3], const size_t bmax_p[3], const size_t bdim_p[3], const size_t dim_p[3], const size_t bs_p[3], bool reblock,\n                           bool pad);\n        void         BlockReadRegionThread();\n        void         BlockWriteRegionThread();\n        const float *GetDataRange() const { return (_dataRange); }\n\n    private:\n        WaveCodecIO * _wc;\n        int           _id;        // thread id\n        float *       _region;    // destination buffer for read\n        const size_t *_bmin_p;\n        const size_t *_bmax_p;    // block coordinates of data\n        const size_t *_bdim_p;\n        const size_t *_dim_p;\n        const size_t *_bs_p;    // dimensions of block\n        float         _dataRange[2];\n        bool          _reblock;\n        bool          _pad;\n        int           _FetchBlock(size_t bx, size_t by, size_t bz);\n        int           _WriteBlock(size_t bx, size_t by, size_t bz);\n    };\n\npublic:\n    int  _nthreads;    // num execution threads\n    int  getNumThread() { return _nthreads; }\n    void EnableBuffering(size_t count[3], size_t divisor, int rank);\n\nprivate:\n    int                             _next_block;\n    int                             _threadStatus;\n    size_t                          _NC_BUF_SIZE;    // buffering disabled by default\n    ReadWriteThreadObj **           _rw_thread_objs;\n    vector<vector<SignificanceMap>> _sigmapsThread;    // one set for each thread\n    vector<size_t>                  _sigmapsizes;      // size of each encoded sig map\n    Compressor *                    _compressor3D;     // 3D compressor\n    Compressor *                    _compressor2DXY;\n    Compressor *                    _compressor2DXZ;\n    Compressor *                    _compressor2DYZ;\n    Compressor *                    _compressor;    // compressor for currently opened variable\n    vector<Compressor *>            _compressorThread3D;\n    vector<Compressor *>            _compressorThread2DXY;\n    vector<Compressor *>            _compressorThread2DXZ;\n    vector<Compressor *>            _compressorThread2DYZ;\n    vector<Compressor *>            _compressorThread;    // current compressor threads\n    vector<NCBuf *>                 _ncbufs;\n\n    VarType_T               _vtype;             // Type (2d, or 3d) of currently opened variable\n    VarType_T               _compressorType;    // Type (2d, or 3d) of current _compressor\n    int                     _lod;               // compression level of currently opened file\n    int                     _reflevel;          // current refinement level\n    size_t                  _validRegMin[3];    // min region bounds of current file\n    size_t                  _validRegMax[3];    // max region bounds of current file\n    bool                    _writeMode;         // true if opened for writes\n    bool                    _isOpen;            // true if a file is opened\n    size_t                  _timeStep;          // currently opened time step\n    string                  _varName;           // Currently opened variable\n    vector<string>          _ncpaths;\n    vector<int>             _ncids;\n    vector<int>             _nc_sig_vars;    // ncdf ids for wave and sig vars\n    vector<int>             _nc_wave_vars;\n    float *                 _cvector;        // storage for wavelet coefficients\n    size_t                  _cvectorsize;    // amount of space allocated to _cvector\n    vector<float *>         _cvectorThread;\n    unsigned char *         _svector;        // storage for encoded signficance map\n    size_t                  _svectorsize;    // amount of space allocated to _svector\n    vector<unsigned char *> _svectorThread;\n    float *                 _block;    // storage for a block\n    vector<float *>         _blockThread;\n    float *                 _blockReg;    // more storage\n    float                   _dataRange[2];\n    vector<size_t>          _ncoeffs;      // num wave coeff. at each compression level\n    vector<size_t>          _cratios3D;    // 3D compression ratios\n    vector<size_t>          _cratios2D;    // 2D compression ratios\n    vector<size_t>          _cratios;      // compression ratios for currently opened file\n\n    float *_sliceBuffer;\n    size_t _sliceBufferSize;    // size of slice buffer in elements\n    int    _sliceCount;         // num slices written\n\n    bool _pad;    // Padding enabled?\n\n    int _OpenVarWrite(const string &basename);\n    int _OpenVarRead(const string &basename);\n    int _WaveCodecIO(int nthreads);\n    int _SetupCompressor();\n\n    void _UnpackCoord(VarType_T vtype, const size_t src[3], size_t dst[3], size_t fill) const;\n\n    void _PackCoord(VarType_T vtype, const size_t src[3], size_t dst[3], size_t fill) const;\n\n    void _FillPackedCoord(VarType_T vtype, const size_t src[3], size_t dst[3], size_t fill) const;\n};\n};    // namespace VAPoR\n\n#endif    // _WaveCodeIO_h_\n"
  },
  {
    "path": "include/vapor/WaveFiltBase.h",
    "content": "#ifndef _WaveFiltBase_h_\n#define _WaveFiltBase_h_\n\n#include <vapor/MyBase.h>\n\nnamespace VAPoR {\n\n//\n//! \\class WaveFiltBase\n//! \\brief A base class for wavelet family filters\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! The WaveFiltBase class is a base class for building classes of\n//! wavelet families that can be implemented as FIR filters. A wavelet\n//! family class contains scaling and\n//! wavelet coefficients that define a particular wavelet. All\n//! filters are normalized unless IsNormalized returns false.\n//!\nclass WASP_API WaveFiltBase {\npublic:\n    WaveFiltBase();\n    virtual ~WaveFiltBase();\n\n    //! Return the number of coefficients in both the scaling and\n    //! wavelet FIR filter.\n    //!\n    //! This method returns the number of elements in the arrays\n    //! returned by the classes filter retrieval methods\n    //!\n    //! \\retval filter length\n    //!\n    //! \\sa GetLowDecomFilCoef(), GetLowReconFilCoef(), GetHighDecomFilCoef()\n    //! GetHighReconFilCoef()\n    //!\n    int GetLength() const { return (_filterLength); };\n\n    //! Return scaling (low pass) decompostion filter coefficients\n    const double *GetLowDecomFilCoef() const { return (_lowDecomFilCoef); };\n\n    //! Return scaling (low pass) reconstruction filter coefficients\n    const double *GetLowReconFilCoef() const { return (_lowReconFilCoef); };\n\n    //! Return wavelet (high pass) decompostion filter coefficients\n    const double *GetHighDecomFilCoef() const { return (_hiDecomFilCoef); };\n\n    //! Return wavelet (high pass) decompostion filter coefficients\n    const double *GetHighReconFilCoef() const { return (_hiReconFilCoef); };\n\n    //! Returns true if the wavelet is symmetric (or antisymmetric)\n    //!\n    virtual bool issymmetric() const { return (false); };\n\n    //! Returns true if the wavelet is an integer transform\n    //!\n    virtual bool isint() const { return (false); };\n\n    //! Returns true wavelet transform is normalized\n    //!\n    virtual bool IsNormalized() const { return (true); };\n\nprotected:\n    static const int MAX_FILTER_SIZE = 32;    // space allocated to filters\n    int              _filterLength;           // length of filters\n    double *         _lowDecomFilCoef;\n    double *         _lowReconFilCoef;\n    double *         _hiDecomFilCoef;\n    double *         _hiReconFilCoef;\n\n    /*-------------------------------------------\n     * Flipping Operation\n     *-----------------------------------------*/\n    void wrev(const double *sigIn, double *sigOut, int sigLength) const;\n\n    /*-------------------------------------------\n     * Quadrature Mirror Filtering Operation\n     *-----------------------------------------*/\n    void qmf_even(const double *sigIn, double *sigOut, int sigLength) const;\n\n    /*-------------------------------------------\n     * Flipping and QMF at the same time\n     *-----------------------------------------*/\n    void qmf_wrev(const double *sigIn, double *sigOut, int sigLength) const;\n\n    /*-------------------------------------------\n     * Verbatim Copying\n     *-----------------------------------------*/\n    void verbatim_copy(const double *sigIn, double *sigOut, int sigLength) const;\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/WaveFiltBior.h",
    "content": "#include <string>\n#include \"WaveFiltBase.h\"\n\nusing namespace std;\n\n#ifndef _WaveFiltBior_h_\n    #define _WaveFiltBior_h_\n\nnamespace VAPoR {\n\n//\n//! \\class WaveFiltBior\n//! \\brief Biorthogonal spline family FIR filters\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class provides FIR filters for the Biorlet family of wavelets\n//!\nclass WASP_API WaveFiltBior : public WaveFiltBase {\npublic:\n    //! Create a set of Biorthogonal spline filters\n    //!\n    //! \\param[in] wavename The Biorlet family wavelet member. Valid values\n    //! are \"bior1.1\", \"bior1.3\", \"bior1.5\", \"bior2.2\", \"bior2.4\",\n    //! \"bior2.6\", \"bior2.8\", \"bior3.1\", \"bior3.3\", \"bior3.5\", \"bior3.7\",\n    //! \"bior3.9\", \"bior4.4\"\n    //!\n    WaveFiltBior(const string &wavename);\n    virtual ~WaveFiltBior();\n\n    //! Returns true if the wavelet is symmetric (or antisymmetric)\n    //!\n    virtual bool issymmetric() const { return (true); };\n\nprivate:\n    void _analysis_initialize(int member);\n    void _synthesis_initialize(int member);\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/WaveFiltCoif.h",
    "content": "#include <string>\n#include <vapor/WaveFiltBase.h>\n\nusing namespace std;\n\n#ifndef _WaveFiltCoif_h_\n    #define _WaveFiltCoif_h_\n\nnamespace VAPoR {\n\n//\n//! \\class WaveFiltCoif\n//! \\brief Coiflet family FIR filters\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class provides FIR filters for the Coiflet family of wavelets\n//!\nclass WASP_API WaveFiltCoif : public WaveFiltBase {\npublic:\n    //! Create a set of Coiflet filters\n    //!\n    //! \\param[in] wavename The Coiflet family wavelet member. Valid values\n    //! are \"coif1\", \"coif2\", \"coif3\", \"coif4\", and \"coif5\"\n    //!\n    WaveFiltCoif(const string &wavename);\n    virtual ~WaveFiltCoif();\n\nprivate:\n    void _analysis_initialize(int member);\n    void _synthesis_initialize(int member);\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/WaveFiltDaub.h",
    "content": "#include <string>\n#include <vapor/WaveFiltBase.h>\n\nusing namespace std;\n\n#ifndef _WaveFiltDaub_h_\n    #define _WaveFiltDaub_h_\n\nnamespace VAPoR {\n\n//\n//! \\class WaveFiltDaub\n//! \\brief Daubechies family FIR filters\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class provides FIR filters for the Daubechies family of wavelets\n//!\nclass WASP_API WaveFiltDaub : public WaveFiltBase {\npublic:\n    //! Create a set of Daubechies filters\n    //!\n    //! \\param[in] wavename The Daubechies family wavelet member. Valid values\n    //! are \"db\", \"db\", \"db\", \"db\", \"db5\", \"db6\", \"db7\", \"db8\", \"db9\", and\n    //! \"db10\"\n    //!\n    WaveFiltDaub(const string &wavename);\n    virtual ~WaveFiltDaub();\n\nprivate:\n    void _analysis_initialize(int member);\n    void _synthesis_initialize(int member);\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/WaveFiltHaar.h",
    "content": "\n#ifndef _WaveFiltHaar_h_\n#define _WaveFiltHaar_h_\n\nnamespace VAPoR {\n\n//\n//! \\class WaveFiltHaar\n//! \\brief Haar FIR filters\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class provides FIR filters for the Haar wavelet\n//!\nclass WASP_API WaveFiltHaar : public WaveFiltBase {\npublic:\n    //! Create a set of Haar wavelet filters\n    //!\n    WaveFiltHaar();\n    virtual ~WaveFiltHaar();\n\nprivate:\n    void _analysis_initialize();\n    void _synthesis_initialize();\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/WaveFiltInt.h",
    "content": "#include <string>\n#include \"WaveFiltBase.h\"\n\nusing namespace std;\n\n#ifndef _WaveFiltInt\n    #define _WaveFiltInt\n\nnamespace VAPoR {\n\n//\n//! \\class WaveFiltInt\n//! \\brief Integer Biorthogonal spline family FIR filters\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class provides FIR filters for the Biorlet family of wavelets\n//!\nclass WASP_API WaveFiltInt : public WaveFiltBase {\npublic:\n    //! Create a set of Biorthogonal spline filters\n    //!\n    //! \\param[in] wavename The Biorlet family wavelet member. Valid values\n    //! are \"bior2.2\"\n    //!\n    WaveFiltInt(const string &wavename);\n    virtual ~WaveFiltInt();\n\n    //! Returns true if the wavelet is symmetric (or antisymmetric)\n    //!\n    virtual bool issymmetric() const { return (true); };\n\n    //! Returns true if the wavelet operates only on integers and preserves\n    //! integer values.\n    //!\n    virtual bool isint() const { return (true); };\n\n    virtual bool IsNormalized() const { return (false); };\n\n    void Analysis(const long *sigIn, size_t sigInLen, long *cA, long *cD, bool oddlow, bool oddhigh) const;\n\n    void Synthesis(const long *cA, const long *cD, size_t sigInLen, long *sigOut) const;\n\nprivate:\n    string _wavename;\n\n    void _analysis_initialize();\n    void _synthesis_initialize();\n\n    void _AnalysisCDF5_3(const long *sigIn, size_t sigInLen, long *cA, long *cD) const;\n\n    void _SynthesisCDF5_3(const long *cA, const long *cD, size_t sigInLen, long *sigOut) const;\n};\n\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/WireFrameParams.h",
    "content": "\n#ifndef WIREFRAMEDATAPARAMS_H\n#define WIREFRAMEDATAPARAMS_H\n\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n\nnamespace VAPoR {\n\n//! \\class WireFrameParams\n//! \\brief Class that supports drawing Barbs based on 2D or 3D vector field\n//! \\author John Clyne\n//! \\version 3.0\nclass PARAMS_API WireFrameParams : public RenderParams {\npublic:\n    WireFrameParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave);\n\n    WireFrameParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node);\n\n    virtual ~WireFrameParams();\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"WireFrameParams\"); }\n\n    //! \\copydoc RenderParams::GetRenderDim()\n    //\n    virtual size_t GetRenderDim() const override { return (_dataMgr->GetVarTopologyDim(GetVariableName())); }\n\n    //! \\copydoc RenderParams::GetActualColorMapVariableName()\n    virtual string GetActualColorMapVariableName() const override { return GetVariableName(); }\n\nprivate:\n    void _init();\n\n};    // End of Class WireFrameParams\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/WireFrameRenderer.h",
    "content": "//---------------- ----------------------------------------------------------\n//\n//                   Copyright (C)  2018\n//     University Corporation for Atmospheric Research\n//                   All Rights Reserved\n//\n//----------------------------------------------------------------------------\n\n#ifndef WIREFRAMERENDERER_H\n#define WIREFRAMERENDERER_H\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <utility>\n#include <vapor/DataMgr.h>\n#include <vapor/utils.h>\n#include <vapor/Renderer.h>\n#include <vapor/Texture.h>\n\nnamespace VAPoR {\n\n//! \\class WireFrameRenderer\n//! \\brief\n//! \\author John Clyne\n//! \\version 3.0\n//! \\date June 2018\n\nclass RENDER_API WireFrameRenderer : public Renderer {\npublic:\n    //! Constructor, must invoke Renderer constructor\n    //! \\param[in] Visualizer* pointer to the visualizer where this will draw\n    //! \\param[in] RenderParams* pointer to the ArrowParams describing\n    //! this renderer\n    WireFrameRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr);\n\n    static string GetClassType() { return (\"WireFrame\"); }\n\n    //! Destructor\n    //\n    virtual ~WireFrameRenderer();\n\nprotected:\n    //! \\copydoc Renderer::_initializeGL()\n    virtual int _initializeGL();\n\n    //! \\copydoc Renderer::_paintGL()\n    virtual int _paintGL(bool fast);\n\nprivate:\n    GLuint       _VAO, _VBO, _EBO;\n    unsigned int _nIndices;\n    Texture1D    _lutTexture;\n    bool         _GPUOutOfMemory;\n\n    struct VertexData;\n    struct {\n        string              varName;\n        string              heightVarName;\n        size_t              ts;\n        int                 level;\n        int                 lod;\n        std::vector<double> boxMin, boxMax;\n\n    } _cacheParams;\n\n    // Helper class to keep track of which cell edges have been drawn so\n    // we can avoid duplicate draws.\n    //\n    class DrawList {\n    public:\n        // maxEntries is the maximum number of unique cell nodes.\n        // maxLinesPerVertex is the *expected* max valence (degree) of any\n        // node (vertex). If a node has more than maxLinesPerVertex edges\n        // only the first maxLinesPerVertex edges will be recorded in\n        // DrawList. Hence, queries to edges with DrawList::InList will\n        // return false once maxLinesPerVertex has been exceeded\n        //\n        DrawList(GLuint maxEntries, size_t maxLinesPerVertex)\n        : _drawList(maxEntries * maxLinesPerVertex, (std::numeric_limits<GLuint>::max)()), _maxEntries(maxEntries), _maxLinesPerVertex(maxLinesPerVertex)\n        {\n        }\n\n        bool InList(GLuint idx0, GLuint idx1)\n        {\n            VAssert(idx0 < _maxEntries);\n            VAssert(idx1 < _maxEntries);\n\n            if (idx1 < idx0) { std::swap(idx1, idx0); }\n\n            for (int i = 0; i < _maxLinesPerVertex; i++) {\n                if (_drawList[idx0 * _maxLinesPerVertex + i] == idx1) { return (true); }\n                if (_drawList[idx0 * _maxLinesPerVertex + i] == (std::numeric_limits<GLuint>::max)()) {\n                    _drawList[idx0 * _maxLinesPerVertex + i] = idx1;\n                    return (false);\n                }\n            }\n            return (false);\n        }\n\n    private:\n        vector<GLuint> _drawList;\n        const size_t   _maxEntries;\n        const size_t   _maxLinesPerVertex;\n    };\n\n    void _buildCacheVertices(const Grid *grid, const Grid *heightGrid, vector<GLuint> &nodeMap, bool *GPUOutOfMemory) const;\n\n    size_t _buildCacheConnectivity(const Grid *grid, const vector<GLuint> &nodeMap, bool *GPUOutOfMemory) const;\n\n    int  _buildCache();\n    bool _isCacheDirty() const;\n    void _saveCacheParams();\n    void _drawCell(const GLuint *cellNodeIndices, int n, bool layered, const std::vector<GLuint> &nodeMap, GLuint invalidIndex, std::vector<unsigned int> &indices, DrawList &drawList) const;\n\n    void _clearCache() { _cacheParams.varName.clear(); }\n};\n\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/XmlNode.h",
    "content": "//\n//      $Id$\n//\n\n#ifndef _XmlNode_h_\n#define _XmlNode_h_\n\n#include <iostream>\n#include <map>\n#include <vector>\n#include <string>\n#include <stack>\n#include <vapor/MyBase.h>\n#ifdef WIN32\n    #pragma warning(disable : 4251)\n#endif\n\nnamespace VAPoR {\n\n//\n//! \\class XmlNode\n//! \\brief An Xml tree\n//! \\author John Clyne\n//! \\version $Revision$\n//! \\date    $Date$\n//!\n//! This class manages an XML tree. Each node in the tree\n//! coresponds to an XML \"parent\" element. The concept\n//! of \"parent\" element is a creation of this class,\n//! and should be confused with any notions of parent\n//! in more commonly used XML jargon. A parent element\n//! is simply one possessing child XML elements\n//! Non-parent elements - those elements that do not have\n//! children elements -\n//! may be thought of as data elements. Typically\n//! non-parent elements possess XML character data. Parent\n//! elements may or may not have XML character data\n//! themselves.\n//!\n//! The XmlNode class is derived from the MyBase base\n//! class. Hence all of the methods make use of MyBase's\n//! error reporting capability.\n//! Any method with a return type of int returns a 0 on\n//! success, and and a negative int on failure, unless otherwise\n//! docummented. Similary, methods returning pointers return non-NULL on\n//! success and NULL on failure. Failure in either case triggers\n//! logging of an error message with MyBase::SetErrMsg()\n//!\nclass PARAMS_API XmlNode : public Wasp::MyBase {\npublic:\n    //! Constructor for the XmlNode class.\n    //!\n    //! Create's a new Xml node\n    //!\n    //! \\param[in] tag Name of Xml node\n    //! \\param[in] attrs A list of Xml attribute names and values for this node\n    //! \\param[in] numChildrenHint Reserve space for the indicated number of\n    //! children. Children must be created with\n    //! the NewChild() method\n    //!\n    XmlNode(const string &tag, const map<string, string> &attrs, size_t numChildrenHint = 0);\n    XmlNode(const string &tag, size_t numChildrenHint = 0);\n    XmlNode();\n\n    virtual XmlNode *Construct(const string &tag, const map<string, string> &attrs, size_t numChildrenHint = 0) { return (new XmlNode(tag, attrs, numChildrenHint)); }\n\n    //! Copy constructor for the XmlNode class.\n    //!\n    //! Create's a new XmlNode node from an existing one. The new\n    //! node will be parentless.\n    //!\n    //! \\param[in] node XmlNode instance from which to construct a copy\n    //!\n    XmlNode(const XmlNode &node);\n\n    virtual XmlNode *Clone() { return new XmlNode(*this); };\n\n    //! Destructor\n    //!\n    //! Recursively delete node and chilren, but only if this is the root\n    //! node. Otherwise this method is a no-op\n    //!\n    //! \\sa SetParent()\n    //\n    virtual ~XmlNode();\n\n    //! Set or get that node's tag (name)\n    //!\n    //! \\retval tag A reference to the node's tag\n    //\n    string &Tag() { return (_tag); }\n\n    string GetTag() const { return (_tag); }\n\n    void SetTag(string tag) { _tag = tag; }\n\n    //! Set or get that node's attributes\n    //!\n    //! \\retval attrs A reference to the node's attributes\n    //\n    map<string, string> &Attrs() { return (_attrmap); }\n\n    // These methods set or get XML character data, possibly formatting\n    // the data in the process. The paramter 'tag' identifies the XML\n    // element tag associated with the character data. The\n    // parameter, 'values', contains the character data itself. The Long and\n    // Double versions of these methods convert a between character streams\n    // and vectors of longs or doubles as appropriate.\n    //\n\n    //! Set an Xml element of type long\n    //!\n    //! This method defines and sets an Xml element. The Xml character\n    //! data to be associated with this element is the array of longs\n    //! specified by \\p values\n    //!\n    //! \\param[in] tags Sequence of names of elements as a path to the desired node\n    //! \\param[in] values Vector of longs to be converted to character data\n    //!\n    //! \\retval status Returns 0 if successful\n    //\n    virtual void SetElementLong(const vector<string> &tags, const vector<long> &values);\n    virtual void SetElementLong(const vector<string> &tags, long value)\n    {\n        vector<long> values(1, value);\n        XmlNode::SetElementLong(tags, values);\n    }\n\n    //! Set an Xml element of type long\n    //!\n    //! This method defines and sets an Xml element. The Xml character\n    //! data to be associated with this element is the array of longs\n    //! specified by \\p values\n    //!\n    //! \\param[in] tag Name of the element to define/set\n    //! \\param[in] values Vector of longs to be converted to character data\n    //!\n    //! \\retval status Returns 0 if successful\n    //\n    virtual void SetElementLong(const string &tag, const vector<long> &values);\n    virtual void SetElementLong(const string &tag, long value)\n    {\n        vector<long> values(1, value);\n        XmlNode::SetElementLong(tag, values);\n    }\n\n    //! Get an Xml element's data of type long\n    //!\n    //! Return the character data associated with the Xml elemented\n    //! named by \\p tag for this node. The data is interpreted and\n    //! returned as a vector of longs. If the element does not exist\n    //! an empty vector is returned.\n    //!\n    //! \\param[in] tag Name of element\n    //! \\retval vector Vector of longs associated with the named elemented\n    //!\n    virtual const vector<long> &GetElementLong(const string &tag) const;\n\n    //! Return true if the named element of type long exists\n    //!\n    //! \\param[in] tag Name of element\n    //! \\retval value at element\n    //!\n    virtual bool HasElementLong(const string &tag) const;\n\n    //! Set an Xml element of type double\n    //!\n    //! This method defines and sets an Xml element. The Xml character\n    //! data to be associated with this element is the array of doubles\n    //! specified by \\p values\n    //!\n    //! \\param[in] tag Name of the element to define/set\n    //! \\param[in] values Vector of doubles to be converted to character data\n    //!\n    //! \\retval status 0 if successful\n    //\n    virtual void SetElementDouble(const string &tag, const vector<double> &values);\n    virtual void SetElementDouble(const string &tag, double value)\n    {\n        vector<double> values(1, value);\n        XmlNode::SetElementDouble(tag, values);\n    }\n\n    //! Set an Xml element of type double, using a sequence of tags\n    //!\n    //! This method defines and sets an Xml element. The Xml character\n    //! data to be associated with this element is the array of doubles\n    //! specified by \\p values\n    //!\n    //! \\param[in] tags vector of tags to the specified element\n    //! \\param[in] values Vector of doubles to be converted to character data\n    //!\n    //! \\retval status 0 if successful\n    //\n    virtual void SetElementDouble(const vector<string> &tags, const vector<double> &values);\n    virtual void SetElementDouble(const vector<string> &tags, double value)\n    {\n        vector<double> values(1, value);\n        XmlNode::SetElementDouble(tags, values);\n    }\n\n    //! Get an Xml element's data of type double\n    //!\n    //! Return the character data associated with the Xml elemented\n    //! named by \\p tag for this node. The data is interpreted and\n    //! returned as a vector of doubles. If the element does not exist\n    //! an empty vector is returned.\n    //!\n    //! \\param[in] tag Name of element\n    //! \\retval vector Vector of doubles associated with the named elemented\n    //!\n    virtual const vector<double> &GetElementDouble(const string &tag) const;\n\n    //! Return true if the named element of type double exists\n    //!\n    //! \\param[in] tag Name of element\n    //! \\retval bool\n    //!\n    virtual bool HasElementDouble(const string &tag) const;\n\n    //! Set an Xml element of type string\n    //!\n    //! This method defines and sets an Xml element. The Xml character\n    //! data to be associated with this element is the string\n    //! specified by \\p values\n    //!\n    //! \\param[in] tag Name of the element to define/set\n    //! \\param[in] values string to be converted to character data\n    //!\n    //! \\retval status Returns a non-negative value on success\n    //! \\retval status Returns 0 if successful\n    //\n    virtual void SetElementString(const string &tag, const string &values);\n\n    //! Get an Xml element's data of type string\n    //!\n    //! Return the character data associated with the Xml elemented\n    //! named by \\p tag for this node. The data is interpreted and\n    //! returned as a string. If the element does not exist\n    //! an empty vector is returned.\n    //!\n    //! \\param[in] tag Name of element\n    //! \\retval string The string associated with the named element\n    //!\n    virtual const string &GetElementString(const string &tag) const;\n\n    //! Set an Xml element of type string\n    //!\n    //! This method defines and sets an Xml element. The Xml character\n    //! data to be associated with this element is the array of strings\n    //! specified by \\p values. The array of strings is first\n    //! translated to a single string of space-separated words (contiguous\n    //! characters)\n    //!\n    //! \\param[in] tag Name of the element to define/set\n    //! \\param[in] values Vector of strings to be converted to a\n    //! space-separated list of characters\n    //!\n    //! \\retval status Returns 0 if successful\n    //\n    virtual void SetElementStringVec(const string &tag, const vector<string> &values);\n    //! Set an Xml element of type string\n    //!\n    //! This method defines and sets an Xml element. The Xml character\n    //! data to be associated with this element is the array of strings\n    //! specified by \\p values. The array of strings is first\n    //! translated to a single string of space-separated words (contiguous\n    //! characters)\n    //!\n    //! \\param[in] tagpath sequence of tags leading from this to element\n    //! \\param[in] values Vector of strings to be converted to a\n    //! space-separated list of characters\n    //!\n    //! \\retval status Returns 0 if successful\n    //\n    virtual void SetElementStringVec(const vector<string> &tagpath, const vector<string> &values);\n\n    //! Get an Xml element's data of type string\n    //!\n    //! Return the character data associated with the Xml elemented\n    //! named by \\p tag for this node. The data is interpreted as\n    //! a space-separated list of words (contiguous characters). The\n    //! string vector returned is generated by treating white\n    //! space as delimeters between vector elements.\n    //! If the element does not exist\n    //! an empty vector is returned\n    //!\n    //! \\param[in] tag Name of element\n    //! \\param[out] vec Vector of strings associated with the named element\n    //!\n    virtual void GetElementStringVec(const string &tag, vector<string> &vec) const;\n\n    //! Return true if the named element of type string exists\n    //!\n    //! \\param[in] tag Name of element\n    //! \\retval bool\n    //!\n    virtual bool HasElementString(const string &tag) const;\n\n    //! Return the number of children nodes this node has\n    //!\n    //! \\retval n The number of direct children this node has\n    //!\n    //! \\sa NewChild()\n    //\n\n    //! Add an existing node as a child of the current node.\n    //!\n    //! The new child node will be cloned from \\p child and\n    //! appended to the array of child nodes.\n    //!\n    //! \\param[in] child is the XmlNode object to be added as a child\n    //! \\retval newchild Returns a pointer to the newly created child. This\n    //! is a no-fail method (NULL is never returned).\n    //\n    XmlNode *AddChild(const XmlNode *child);\n    XmlNode *AddChild(const XmlNode &child);\n\n    virtual int GetNumChildren() const { return (int)(_children.size()); };\n\n    //! Create a new child of this node\n    //!\n    //! Create a new child node, named \\p tag. The new child node will be\n    //! appended to the array of child nodes. The \\p numChildrenHint\n    //! parameter is a hint specifying how many children the new child\n    //! itself may have.\n    //!\n    //! \\param[in] tag Name to give the new child node\n    //! \\param[in] attrs A list of Xml attribute names and values for this node\n    //! \\param[in] numChildrenHint Reserve space for future children of this node\n    //! \\retval child Returns the newly created child, or NULL if the child\n    //! could not be created\n    //\n    virtual XmlNode *NewChild(const string &tag, const map<string, string> &attrs, size_t numChildrenHint = 0);\n\n    virtual XmlNode *NewChild(const string &tag, size_t numChildrenHint = 0)\n    {\n        map<string, string> attrs;\n        return (NewChild(tag, attrs, numChildrenHint));\n    }\n\n    //! Delete the indicated child node.\n    //!\n    //! Delete the indicated child node, decrementing the total number\n    //! of children by one. Return an error if the child does not\n    //! exist (i.e. if index >= GetNumChildren())\n    //!\n    //! \\param[in] index Index of the child. The first child is zero\n    //! \\retval status Returns a non-negative value on success\n    //! \\sa GetNumChildren()\n    virtual int DeleteChild(size_t index);\n    virtual int DeleteChild(const string &tag);\n\n    //!\n    //! Recursively delete all descendants of a node.\n    //!\n    //\n    virtual void DeleteAll();\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Replace the indicated child node with specified new child node\n    //!\n    //! If indicated child does not exist, return -1, otherwise\n    //! return the index of the replaced child.\n    //!\n    //! \\param[in] childNode Pointer to existing child node\n    //! \\param[in] newChild Pointer to replacement child node\n    //! \\retval status Returns non-negative child index on success\n\n    virtual int ReplaceChild(XmlNode *childNode, XmlNode *newChild);\n#endif\n\n    //! Return the indicated child node.\n    //!\n    //! Return the ith child of this node. The first child node is index=0,\n    //! the last is index=GetNumChildren()-1. Return NULL if the child\n    //! does not exist.\n    //!\n    //! \\param[in] index Index of the child. The first child is zero\n    //! \\retval child Returns the indicated child, or NULL if the child\n    //! could does not exist. No error is generated on failure.\n    //! \\sa GetNumChildren()\n    //\n    virtual XmlNode *GetChild(size_t index) const;\n\n    //! Return true if the indicated child node exists\n    //!\n    //! \\param[in] index Index of the child. The first child is zero\n    //! \\retval bool\n    //!\n    virtual bool HasChild(size_t index) const;\n\n    //! Return the indicated child node.\n    //!\n    //! Return the indicated tagged child node. Return NULL if the child\n    //! does not exist.\n    //! \\param[in] tag Name of the child node to return\n    //! \\retval child Returns the indicated child, or NULL if the child\n    //! could does not exist. No error is generated on failure.\n    //\n    virtual XmlNode *GetChild(const string &tag) const;\n\n    //! Return true if the indicated child node exists\n    //!\n    //! \\param[in] tag Name of the child node\n    //! \\retval bool\n    //!\n    virtual bool HasChild(const string &tag) const;\n\n    //! Return a pointer to a node with the indicated path if it exists\n    //!\n    //! This method returns a pointer to the node with the path indicated\n    //! by the path vector \\p path. If \\p absolute is true the search\n    //! begins from the root of the root of the tree. If \\p absolute\n    //! is false, the search begins with the children of this node.\n    //!\n    //! \\p retval The indicated node is returned on success. If the path\n    //! is not valid NULL is returned, but no error is reported\n    //!\n    virtual XmlNode *GetNode(std::vector<string> path, bool absolute) const;\n\n    //! Return a pointer to a node with the indicated path if it exists\n    //!\n    //! The path argument \\p path is parsed into a vector of strings, with\n    //! the '/' character used as a delimiter. The resulting path vector\n    //! is passed to GetNode(std::vector <string> path, bool absolute).\n    //! If the first character in \\p path is '/' then an absolute path\n    //! is assumed.\n    //!\n    //! \\sa GetNode(std::vector <string> path, bool absolute)\n    //\n    virtual XmlNode *GetNode(string path) const;\n\n    //! Return the node's parent\n    //!\n    //! This method returns a pointer to the parent node, or NULL if this\n    //! node is the root of the tree.\n    //!\n    //! \\retval node Pointer to parent node or NULL if no parent exists\n    //\n    virtual XmlNode *GetParent() const { return (_parent); }\n\n    //! Set a node's parent\n    //!\n    //! Set the parent node to \\p parent, adding this node to the\n    //! children of \\p parent, and removing it from the children of the\n    //! node's current parent. If \\p parent already has a child with the\n    //! same name as this node that child is deleted.\n    //!\n    //! \\p parent may be NULL in which case the node becomes a root node\n    //!\n    //! \\sa IsRoot();\n    //\n    void SetParent(XmlNode *parent);\n\n    //! Write the XML tree, rooted at this node, to a file in XML format\n    //\n    friend ostream &operator<<(ostream &s, const XmlNode &node);\n\n    //! Assignment operator\n    //\n    XmlNode &operator=(const XmlNode &rhs);\n\n    //! Equivalence operator\n    //\n    bool operator==(const XmlNode &rhs) const;\n    bool operator!=(const XmlNode &rhs) const { return (!(*this == rhs)); };\n\n    //! Return boolean indicating if this node is the root of the tree\n    //!\n    //! This method returns true if the node is the root if the tree. I.e.\n    //! true is returned if the node has no parent. Otherwise false is returned.\n    //\n    virtual bool IsRoot() const { return (GetParent() == NULL); }\n\n    //! Get the path from the root to this node as a vector of tags\n    //!\n    //! This method returns an ordered vector of strings containing all\n    //! of the XmlNode tags from the root to this node. The first string\n    //! in the vector is the root node tag.\n    //\n    virtual std::vector<string> GetPathVec() const;\n\n    //! Get the path from the root to this node as a delimeter separated string\n    //!\n    //! This method constructs a delimeter separated path from the string\n    //! vector returned  by GetPathVec(). The delimiter is a '/'\n    //\n    virtual string GetPath() const;\n\n    //! Get the root node of the tree\n    //!\n    //! Walks up the tree starting from this node and\n    //! returns the root node of the tree\n    //!\n    virtual XmlNode *GetRoot() const;\n\n    static const std::vector<XmlNode *> &GetAllocatedNodes() { return (_allocatedNodes); }\n\n    // Following is a substitute for exporting the \"<<\" operator in windows.\n    // I don't know how to export an operator<< !\n    static ostream &streamOut(ostream &os, const XmlNode &node);\n\n    static bool IsValidXMLElement(const string &s, int *badIdx=nullptr);\n    static string SanitizeXMLTag(string s);\n\nprivate:\n    static vector<long>   _emptyLongVec;    // empty elements\n    static vector<double> _emptyDoubleVec;\n    static vector<string> _emptyStringVec;\n    static string         _emptyString;\n\n    static std::vector<XmlNode *> _allocatedNodes;\n\n    map<string, vector<long>>   _longmap;      // node's long data\n    map<string, vector<double>> _doublemap;    // node's double data\n    map<string, string>         _stringmap;    // node's string data\n    map<string, string>         _attrmap;      // node's attributes\n\n    vector<XmlNode *> _children;    // node's children\n    string            _tag;         // node's tag name\n\n    size_t   _asciiLimit;    // length limit beyond which element data are encoded\n    XmlNode *_parent;        // Node's parent\n};\n// ostream& VAPoR::operator<< (ostream& os, const XmlNode& node);\n\nclass PARAMS_API XmlParser : public Wasp::MyBase {\npublic:\n    XmlParser();\n    ~XmlParser() {}\n\n    int LoadFromFile(XmlNode *root, string path);\n    int LoadFromFile(XmlNode *root, istream &in);\n\nprivate:\n    enum type { UNKNOWN, PARENT, LONG_DATA, DOUBLE_DATA, STRING_DATA };\n\n    XmlNode *             _root;\n    type                  _nodeType;\n    std::stack<XmlNode *> _nodeStack;\n    string                _stringData;\n\n    void _startElementHandler(string tag, map<string, string> &myattrs);\n    void _endElementHandler(string tag);\n    void _charDataHandler(string s);\n\n    bool _isParentElement(string tag, map<string, string> myattrs) const;\n    bool _isDataElement(string tag, map<string, string> myattrs, type &dtype) const;\n\n    friend void _StartElementHandler(void *userData, const char *tag, const char **attrs);\n\n    friend void _EndElementHandler(void *userData, const char *tag);\n\n    friend void _CharDataHandler(void *userData, const char *s, int len);\n};\n\n};    // namespace VAPoR\n\n#endif    //\t_XmlNode_h_\n"
  },
  {
    "path": "include/vapor/common.h",
    "content": "\n#ifdef WIN32\n    #pragma warning(disable : 4018 4244 4267 4305)\n    #ifdef COMMON_EXPORTS\n        #define COMMON_API __declspec(dllexport)\n    #else\n        #define COMMON_API __declspec(dllimport)\n    #endif\n\n    #ifdef VDF_EXPORTS\n        #define VDF_API __declspec(dllexport)\n    #else\n        #define VDF_API __declspec(dllimport)\n    #endif\n\n    #ifdef WASP_EXPORTS\n        #define WASP_API __declspec(dllexport)\n    #else\n        #define WASP_API __declspec(dllimport)\n    #endif\n\n    #ifdef FLOW_EXPORTS\n        #define FLOW_API __declspec(dllexport)\n    #else\n        #define FLOW_API __declspec(dllimport)\n    #endif\n\n    #ifdef OSGL_EXPORTS\n        #define OSGL_API __declspec(dllexport)\n    #else\n        #define OSGL_API __declspec(dllimport)\n    #endif\n\n    #ifdef PARAMS_EXPORTS\n        #define PARAMS_API __declspec(dllexport)\n    #else\n        #define PARAMS_API __declspec(dllimport)\n    #endif\n\n    #ifdef RENDER_EXPORTS\n        #define RENDER_API __declspec(dllexport)\n    #else\n        #define RENDER_API __declspec(dllimport)\n    #endif\n\n    #ifdef UDUNITS2_EXPORTS\n        #define UDUNITS2_API __declspec(dllexport)\n    #else\n        #define UDUNITS2_API __declspec(dllimport)\n    #endif\n\n    #ifdef GRIBAPI_EXPORTS\n        #define GRIBAPI_API __declspec(dllexport)\n    #else\n        #define GRIBAPI_API __declspec(dllimport)\n    #endif\n\n    #ifdef JPEG_EXPORTS\n        // Slightly different definitions for jpeg project:\n        #define JPEG_GLOBAL(type) __declspec(dllexport) type\n        #define JPEG_EXTERN(type) extern __declspec(dllexport) type\n    #else\n        #define JPEG_GLOBAL(type) __declspec(dllimport) type\n        #ifdef __cplusplus\n            #define JPEG_EXTERN(type) extern \"C\" __declspec(dllimport) type\n        #else\n            #define JPEG_EXTERN(type) extern __declspec(dllimport) type\n        #endif\n    #endif    // JPEG_EXPORTS\n\n#else    // not WIN32, everything is exported\n    #define COMMON_API\n    #define VDF_API\n    #define WASP_API\n    #define FLOW_API\n    #define OSGL_API\n    #define PARAMS_API\n    #define RENDER_API\n    #define GRIBAPI_API\n    #define JPEG_GLOBAL(type) type\n    // Assume all outside projects depending on JPEG are C++\n    #ifdef JPEG_EXPORTS\n        #define JPEG_EXTERN(type) extern type\n    #else\n        #define JPEG_EXTERN(type) extern \"C\" type\n    #endif    // ifeq JPEG_EXPORTS\n#endif        // end !Win32\n\n#ifndef M_PI\n    #define M_PI 3.1415926535897932384626433832795\n#endif\n"
  },
  {
    "path": "include/vapor/converter.h",
    "content": "/*\n * Copyright 2008, 2009 University Corporation for Atmospheric Research\n *\n * This file is part of the UDUNITS-2 package.  See the file LICENSE\n * in the top-level source-directory of the package for copying and\n * redistribution conditions.\n */\n/*\n * Public header-file for the Unidata units(3) library.\n */\n\n#ifndef CV_CONVERTER_H_INCLUDED\n#define CV_CONVERTER_H_INCLUDED\n\n#include <stddef.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include \"udunits2.h\"\ntypedef union cv_converter cv_converter;\n\n/*\n * Returns the trivial converter (i.e., y = x).\n * When finished with the converter, the client should pass the converter to\n * cv_free().\n * RETURNS:\n *\tThe trivial converter.\n */\nUDUNITS2_API cv_converter *cv_get_trivial(void);\n\n/*\n * Returns the reciprocal converter (i.e., y = 1/x).\n * When finished with the converter, the client should pass the converter to\n * cv_free().\n * RETURNS:\n *\tThe reciprocal converter.\n */\nUDUNITS2_API cv_converter *cv_get_inverse(void);\n\n/*\n * Returns a scaling converter (i.e., y = ax).\n * When finished with the converter, the client should pass the converter to\n * cv_free().\n * RETURNS:\n *\tThe scaling converter.\n */\nUDUNITS2_API cv_converter *cv_get_scale(const double slope);\n\n/*\n * Returns a converter that adds a number to values (i.e., y = x + b).\n * When finished with the converter, the client should pass the converter to\n * cv_free().\n * ARGUMENTS:\n *\tintercept\tThe number to be added.\n * RETURNS:\n *\tNULL\tNecessary memory couldn't be allocated.\n *\telse\tA converter that adds the given number to values.\n */\nUDUNITS2_API cv_converter *cv_get_offset(const double intercept);\n\n/*\n * Returns a Galilean converter (i.e., y = ax + b).\n * When finished with the converter, the client should pass the converter to\n * cv_free().\n * ARGUMENTS:\n *\tslope\t\tThe number by which to multiply values.\n *\tintercept\tThe number to be added.\n * RETURNS:\n *\tNULL\tNecessary memory couldn't be allocated.\n *\telse\tA Galilean converter corresponding to the inputs.\n */\nUDUNITS2_API cv_converter *cv_get_galilean(const double slope, const double intercept);\n\n/*\n * Returns a logarithmic converter (i.e., y = log(x) in some base).\n * When finished with the converter, the client should pass the converter to\n * cv_free().\n * ARGUMENTS:\n *\tbase\t\tThe logarithmic base (e.g., 2, M_E, 10).  Must be\n *                      greater than one.\n * RETURNS:\n *\tNULL\t\t\"base\" is not greater than one or necessary\n *\t\t\tmemory couldn't be allocated.\n *\telse\t\tA logarithmic converter corresponding to the inputs.\n */\nUDUNITS2_API cv_converter *cv_get_log(const double base);\n\n/*\n * Returns an exponential converter (i.e., y = pow(b, x) in some base \"b\").\n * When finished with the converter, the client should pass the converter to\n * cv_free().\n *\n * Arguments:\n *\tbase\t\tThe desired base.  Must be positive.\n * Returns:\n *\tNULL\t\t\"base\" is invalid or necessary memory couldn't be\n *\t\t\tallocated.\n *\telse\t\tAn exponential converter corresponding to the inputs.\n */\nUDUNITS2_API cv_converter *cv_get_pow(const double base);\n\n/*\n * Returns a converter corresponding to the sequential application of two\n * other converters.\n * ARGUMENTS:\n *\tfirst\tThe converter to be applied first.\n *\tsecond\tThe converter to be applied second.\n * RETURNS:\n *\tNULL\tEither \"first\" or \"second\" is NULL or necessary memory couldn't\n *\t\tbe allocated.\n *      else    A converter corresponding to the sequential application of the\n *              given converters.  If one of the input converters is the trivial\n *              converter, then the returned converter will be the other input\n *              converter.\n */\nUDUNITS2_API cv_converter *cv_combine(cv_converter *const first, cv_converter *const second);\n\n/*\n * Frees resources associated with a converter.\n * ARGUMENTS:\n *\tconv\tThe converter to have its resources freed or NULL.\n */\nUDUNITS2_API void cv_free(cv_converter *const conv);\n\n/*\n * Converts a float.\n * ARGUMENTS:\n *\tconverter\tThe converter.\n *\tvalue\t\tThe value to be converted.\n * RETURNS:\n *\tThe converted value.\n */\nUDUNITS2_API float cv_convert_float(const cv_converter *converter, const float value);\n\n/*\n * Converts a double.\n * ARGUMENTS:\n *\tconverter\tThe converter.\n *\tvalue\t\tThe value to be converted.\n * RETURNS:\n *\tThe converted value.\n */\nUDUNITS2_API double cv_convert_double(const cv_converter *converter, const double value);\n\n/*\n * Converts an array of floats.\n * ARGUMENTS:\n *\tconverter\tThe converter.\n *\tin\t\tThe values to be converted.\n *\tcount\t\tThe number of values to be converted.\n *\tout\t\tThe output array for the converted values.  May\n *\t\t\tbe the same array as \"in\" or overlap it.\n * RETURNS:\n *\tNULL\t\"out\" is NULL.\n *\telse\tA pointer to the output array.\n */\nUDUNITS2_API float *cv_convert_floats(const cv_converter *converter, const float *const in, const size_t count, float *out);\n\n/*\n * Converts an array of doubles.\n * ARGUMENTS:\n *\tconverter\tThe converter.\n *\tin\t\tThe values to be converted.\n *\tcount\t\tThe number of values to be converted.\n *\tout\t\tThe output array for the converted values.  May\n *\t\t\tbe the same array as \"in\" or overlap it.\n * RETURNS:\n *\tNULL\t\"out\" is NULL.\n *\telse\tA pointer to the output array.\n */\nUDUNITS2_API double *cv_convert_doubles(const cv_converter *converter, const double *const in, const size_t count, double *out);\n\n/*\n * Returns a string representation of a converter.\n * ARGUMENTS:\n *\tconv\t\tThe converter.\n *\tbuf\t\tThe buffer into which to write the expression.\n *\tmax\t\tThe size of the buffer.\n *\tvariable\tThe string to be used as the input value for the\n *\t\t\tconverter.\n * RETURNS\n *\t<0\tAn error was encountered.\n *\telse\tThe number of bytes formatted excluding the terminating null.\n */\nUDUNITS2_API int cv_get_expression(const cv_converter *const conv, char *const buf, size_t max, const char *const variable);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/vapor/debug.h",
    "content": "#ifndef DEBUG_H\n#define DEBUG_H\n\n#ifdef NDEBUG\n    #define dLog(...)\n    #define dBreak()\n    #define dBreakIf(x)\n    #define dBreakCount(x)\n    #define FTRACE(...)\n    #define PERF_TIMER_START\n    #define PERF_TIMER_STOP\n    #define PERF_TIMER_DELTA 1\n#else\n\n    #include <signal.h>\n    #include <stdio.h>\n    #include <string>\n    #include <vector>\n\n    #define DLOG_BASENAME_ONLY 1\n\n    #ifdef WIN32\n        #undef DLOG_BASENAME_ONLY\n    #endif\n\n    #if DLOG_BASENAME_ONLY\n        #include <libgen.h>\n        #define dLog_pre() fprintf(stderr, \"[%s:%i:%s] \", basename(__FILE__), __LINE__, __func__)\n    #else\n        #define dLog_pre() fprintf(stderr, \"[%s:%i:%s] \", __FILE__, __LINE__, __func__)\n    #endif\n\n    #define dLog(...)                     \\\n        {                                 \\\n            dLog_pre();                   \\\n            fprintf(stderr, __VA_ARGS__); \\\n            fprintf(stderr, \"\\n\");        \\\n        }\n    #define dBreak()            \\\n        {                       \\\n            dLog(\"Breakpoint\"); \\\n            raise(SIGTRAP);     \\\n        }\n    #define dBreakIf(x)          \\\n        {                        \\\n            if (x) { dBreak(); } \\\n        }\n    #define dBreakCount(x)                \\\n        {                                 \\\n            static int count = 0;         \\\n            if (++count == (x)) dBreak(); \\\n        }\n\n    #if WIN32\n        #define PERF_TIMER_START\n        #define PERF_TIMER_STOP\n        #define PERF_TIMER_DELTA 1\n    #else\n        #include <sys/time.h>\n        #define PERF_TIMER_START                         \\\n            struct timeval PERF_TIMER_T1, PERF_TIMER_T2; \\\n            gettimeofday(&PERF_TIMER_T1, NULL);\n        #define PERF_TIMER_STOP  gettimeofday(&PERF_TIMER_T2, NULL);\n        #define PERF_TIMER_DELTA ((PERF_TIMER_T2.tv_usec - PERF_TIMER_T1.tv_usec) / 1000000.0 + (double)(PERF_TIMER_T2.tv_sec - PERF_TIMER_T1.tv_sec))\n    #endif\n\n    #ifdef WIN32\n        #define PRINT_BACKTRACE()\n    #else\n        #include <execinfo.h>\n        #define PRINT_BACKTRACE(...)                                  \\\n            {                                                         \\\n                printf(\"------------------ %s\", __func__);            \\\n                printf(__VA_ARGS__);                                  \\\n                printf(\" ------------------\\n\");                      \\\n                void **buffer = (void **)malloc(sizeof(void *) * 32); \\\n                int    depth = backtrace(buffer, 32);                 \\\n                fflush(stdout);                                       \\\n                backtrace_symbols_fd(buffer, depth, fileno(stdout));  \\\n                free(buffer);                                         \\\n            }\n    #endif\n\nusing std::string;\nusing std::vector;\n\n    #define VDC_LIBTRACE\n    // #define VDC_LIBTRACE_RUNNABLE\n    #ifdef VDC_LIBTRACE\n\n        #define NARG(...)                                         NARG_(__VA_ARGS__, RSEQ_N())\n        #define NARG_(...)                                        ARG_N(__VA_ARGS__)\n        #define ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N\n        #define RSEQ_N()                                          9, 8, 7, 6, 5, 4, 3, 2, 1, 0\n\ninline void PRINTARG() {}\ninline void PRINTARG(int x) { printf(\"%i\", x); }\ninline void PRINTARG(long x) { printf(\"%li\", x); }\ninline void PRINTARG(size_t x) { printf(\"%li\", x); }\ninline void PRINTARG(float x) { printf(\"%g\", x); }\ninline void PRINTARG(double x) { printf(\"%g\", x); }\ninline void PRINTARG(bool x) { printf(\"%s\", x ? \"true\" : \"false\"); }\ninline void PRINTARG(const std::string x) { printf(\"\\\"%s\\\"\", x.c_str()); }\ninline void PRINTARG(const char *x) { printf(\"\\\"%s\\\"\", x); }\n        #ifdef VDC_LIBTRACE_RUNNABLE\ninline void PRINTARG(const int *i) { printf(\"(int[]){%i}\", *i); }\ninline void PRINTARG(const float *f) { printf(\"(float[]){%f}\", *f); }\ninline void PRINTARG(const double *d) { printf(\"(double[]){%d}\", *d); }\ninline void PRINTARG(const size_t *li) { printf(\"(size_t[]){%li}\", *li); }\ninline void PRINTARG(const long *li) { printf(\"(long[]){%li}\", *li); }\n        #else\ninline void PRINTARG(const int *i) { printf(\"*[%i]\", *i); }\ninline void PRINTARG(const float *f) { printf(\"*[%f]\", *f); }\ninline void PRINTARG(const double *d) { printf(\"*[%f]\", *d); }\ninline void PRINTARG(const size_t *li) { printf(\"*[%li]\", *li); }\ninline void PRINTARG(const long *li) { printf(\"*[%li]\", *li); }\n        #endif\ninline void PRINTARG(const void *x) { printf(\"%s\", x ? \"<ptr>\" : \"NULL\"); }\n// void PRINTARG(const VAPoR::VDC::AccessMode x) { printf(\"VDC::AccessMode::%s\", x==VAPoR::VDC::AccessMode::R?\"R\":x==VAPoR::VDC::AccessMode::W?\"W\":\"A\"); }\n// void PRINTARG(const VAPoR::DC::XType x)\n// {\n//     switch (x) {\n//         case VAPoR::DC::XType::INVALID: printf(\"DC::INVALID\"); break;\n//         case VAPoR::DC::XType::FLOAT:   printf(\"DC::FLOAT\"); break;\n//         case VAPoR::DC::XType::DOUBLE:  printf(\"DC::DOUBLE\"); break;\n//         case VAPoR::DC::XType::UINT8:   printf(\"DC::UINT8\"); break;\n//         case VAPoR::DC::XType::INT8:    printf(\"DC::INT8\"); break;\n//         case VAPoR::DC::XType::INT32:   printf(\"DC::INT32\"); break;\n//         case VAPoR::DC::XType::INT64:   printf(\"DC::INT64\"); break;\n//         case VAPoR::DC::XType::TEXT:    printf(\"DC::TEXT\"); break;\n//     }\n// }\ntemplate<class T> void PRINTARG(const std::vector<T> v)\n{\n        #ifdef VDC_LIBTRACE_RUNNABLE\n    if (v.size() == 1) {\n        string t(__PRETTY_FUNCTION__);\n        int    s = t.find(\"[T = \") + strlen(\"[T = \");\n        int    f = t.find(\"]\", s);\n        t = t.substr(s, f - s);\n        printf(\"vector<%s>(1, \", t.c_str());\n    } else\n        #endif\n        printf(\"{\");\n    for (int i = 0; i < v.size(); i++) {\n        PRINTARG(v[i]);\n        if (i != v.size() - 1) printf(\", \");\n    }\n        #ifdef VDC_LIBTRACE_RUNNABLE\n    if (v.size() == 1)\n        printf(\")\");\n    else\n        #endif\n        printf(\"}\");\n}\n\ninline std::string classScopeFromPrettyFunc(const std::string &pretty)\n{\n    size_t args = pretty.find(\"(\");\n    size_t colons = pretty.substr(0, args).rfind(\"::\");\n    if (colons == std::string::npos) return \"\";\n    size_t begin = pretty.substr(0, colons).rfind(\" \") + 1;\n    size_t end = colons - begin;\n\n    return pretty.substr(begin, end) + \"::\";\n}\n\n        #define _CONCAT(a, b) a##b\n        #define PRINTARGS_1(x, ...) \\\n            {                       \\\n                PRINTARG(x);        \\\n            }\n        #define PRINTARGS_2(x, ...)       \\\n            {                             \\\n                PRINTARG(x);              \\\n                printf(\", \");             \\\n                PRINTARGS_1(__VA_ARGS__); \\\n            }\n        #define PRINTARGS_3(x, ...)       \\\n            {                             \\\n                PRINTARG(x);              \\\n                printf(\", \");             \\\n                PRINTARGS_2(__VA_ARGS__); \\\n            }\n        #define PRINTARGS_4(x, ...)       \\\n            {                             \\\n                PRINTARG(x);              \\\n                printf(\", \");             \\\n                PRINTARGS_3(__VA_ARGS__); \\\n            }\n        #define PRINTARGS_5(x, ...)       \\\n            {                             \\\n                PRINTARG(x);              \\\n                printf(\", \");             \\\n                PRINTARGS_4(__VA_ARGS__); \\\n            }\n        #define PRINTARGS_6(x, ...)       \\\n            {                             \\\n                PRINTARG(x);              \\\n                printf(\", \");             \\\n                PRINTARGS_5(__VA_ARGS__); \\\n            }\n        #define PRINTARGS_7(x, ...)       \\\n            {                             \\\n                PRINTARG(x);              \\\n                printf(\", \");             \\\n                PRINTARGS_6(__VA_ARGS__); \\\n            }\n        #define PRINTARGS_8(x, ...)       \\\n            {                             \\\n                PRINTARG(x);              \\\n                printf(\", \");             \\\n                PRINTARGS_7(__VA_ARGS__); \\\n            }\n        #define PRINTARGS_9(x, ...)       \\\n            {                             \\\n                PRINTARG(x);              \\\n                printf(\", \");             \\\n                PRINTARGS_8(__VA_ARGS__); \\\n            }\n        #define _PRINTARGS(n, ...) \\\n            _CONCAT(PRINTARGS_, n) \\\n            (__VA_ARGS__)\n        #define PRINTARGS(...) _PRINTARGS(NARG(__VA_ARGS__), __VA_ARGS__)\n        #define FTRACE_PRE()   printf(\"%s%s(\", classScopeFromPrettyFunc(__PRETTY_FUNCTION__).c_str(), __func__)\n        #define FTRACE(...)             \\\n            do {                        \\\n                FTRACE_PRE();           \\\n                PRINTARGS(__VA_ARGS__); \\\n                printf(\");\\n\");         \\\n            } while (0)\n\n    #else\n        #define FTRACE(...)\n    #endif\n\n#endif\n\n#endif\n"
  },
  {
    "path": "include/vapor/direntWin32.h",
    "content": "/*\n * dirent.h - dirent API for Microsoft Visual Studio\n *\n * Copyright (C) 2006-2012 Toni Ronkko\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * ``Software''), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be included\n * in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR\n * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n *\n * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $\n */\n#ifndef DIRENTWin32_H\n#define DIRENTWin32_H\n\n/*\n * Define architecture flags so we don't need to include windows.h.\n * Avoiding windows.h makes it simpler to use windows sockets in conjunction\n * with dirent.h.\n */\n#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86)\n    #define _X86_\n#endif\n#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64)\n    #define _AMD64_\n#endif\n\n#include <stdio.h>\n#include <stdarg.h>\n#include <windef.h>\n#include <winbase.h>\n#include <wchar.h>\n#include <string.h>\n#include <stdlib.h>\n#include <malloc.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <errno.h>\n\n/* Indicates that d_type field is available in dirent structure */\n#define _DIRENT_HAVE_D_TYPE\n\n/* Indicates that d_namlen field is available in dirent structure */\n#define _DIRENT_HAVE_D_NAMLEN\n\n/* Entries missing from MSVC 6.0 */\n#if !defined(FILE_ATTRIBUTE_DEVICE)\n    #define FILE_ATTRIBUTE_DEVICE 0x40\n#endif\n\n/* File type and permission flags for stat() */\n#if !defined(S_IFMT)\n    #define S_IFMT _S_IFMT /* File type mask */\n#endif\n#if !defined(S_IFDIR)\n    #define S_IFDIR _S_IFDIR /* Directory */\n#endif\n#if !defined(S_IFCHR)\n    #define S_IFCHR _S_IFCHR /* Character device */\n#endif\n#if !defined(S_IFFIFO)\n    #define S_IFFIFO _S_IFFIFO /* Pipe */\n#endif\n#if !defined(S_IFREG)\n    #define S_IFREG _S_IFREG /* Regular file */\n#endif\n#if !defined(S_IREAD)\n    #define S_IREAD _S_IREAD /* Read permission */\n#endif\n#if !defined(S_IWRITE)\n    #define S_IWRITE _S_IWRITE /* Write permission */\n#endif\n#if !defined(S_IEXEC)\n    #define S_IEXEC _S_IEXEC /* Execute permission */\n#endif\n#if !defined(S_IFIFO)\n    #define S_IFIFO _S_IFIFO /* Pipe */\n#endif\n#if !defined(S_IFBLK)\n    #define S_IFBLK 0 /* Block device */\n#endif\n#if !defined(S_IFLNK)\n    #define S_IFLNK 0 /* Link */\n#endif\n#if !defined(S_IFSOCK)\n    #define S_IFSOCK 0 /* Socket */\n#endif\n\n#if defined(_MSC_VER)\n    #define S_IRUSR S_IREAD  /* Read user */\n    #define S_IWUSR S_IWRITE /* Write user */\n    #define S_IXUSR 0        /* Execute user */\n    #define S_IRGRP 0        /* Read group */\n    #define S_IWGRP 0        /* Write group */\n    #define S_IXGRP 0        /* Execute group */\n    #define S_IROTH 0        /* Read others */\n    #define S_IWOTH 0        /* Write others */\n    #define S_IXOTH 0        /* Execute others */\n#endif\n\n/* Maximum length of file name */\n#if !defined(PATH_MAX)\n    #define PATH_MAX MAX_PATH\n#endif\n#if !defined(FILENAME_MAX)\n    #define FILENAME_MAX MAX_PATH\n#endif\n#if !defined(NAME_MAX)\n    #define NAME_MAX FILENAME_MAX\n#endif\n\n/* File type flags for d_type */\n#define DT_UNKNOWN 0\n#define DT_REG     S_IFREG\n#define DT_DIR     S_IFDIR\n#define DT_FIFO    S_IFIFO\n#define DT_SOCK    S_IFSOCK\n#define DT_CHR     S_IFCHR\n#define DT_BLK     S_IFBLK\n#define DT_LNK     S_IFLNK\n\n/* Macros for converting between st_mode and d_type */\n#define IFTODT(mode) ((mode)&S_IFMT)\n#define DTTOIF(type) (type)\n\n/*\n * File type macros.  Note that block devices, sockets and links cannot be\n * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are\n * only defined for compatibility.  These macros should always return false\n * on Windows.\n */\n#define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO)\n#define S_ISDIR(mode)  (((mode)&S_IFMT) == S_IFDIR)\n#define S_ISREG(mode)  (((mode)&S_IFMT) == S_IFREG)\n#define S_ISLNK(mode)  (((mode)&S_IFMT) == S_IFLNK)\n#define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK)\n#define S_ISCHR(mode)  (((mode)&S_IFMT) == S_IFCHR)\n#define S_ISBLK(mode)  (((mode)&S_IFMT) == S_IFBLK)\n\n/* Return the exact length of d_namlen without zero terminator */\n#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)\n\n/* Return number of bytes needed to store d_namlen */\n#define _D_ALLOC_NAMLEN(p) (PATH_MAX)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Wide-character version */\nstruct _wdirent {\n    long           d_ino;            /* Always zero */\n    unsigned short d_reclen;         /* Structure size */\n    size_t         d_namlen;         /* Length of name without \\0 */\n    int            d_type;           /* File type */\n    wchar_t        d_name[PATH_MAX]; /* File name */\n};\ntypedef struct _wdirent _wdirent;\n\nstruct _WDIR {\n    struct _wdirent  ent;    /* Current directory entry */\n    WIN32_FIND_DATAW data;   /* Private file data */\n    int              cached; /* True if data is valid */\n    HANDLE           handle; /* Win32 search handle */\n    wchar_t *        patt;   /* Initial directory name */\n};\ntypedef struct _WDIR _WDIR;\n\nstatic _WDIR *          _wopendir(const wchar_t *dirname);\nstatic struct _wdirent *_wreaddir(_WDIR *dirp);\nstatic int              _wclosedir(_WDIR *dirp);\nstatic void             _wrewinddir(_WDIR *dirp);\n\n/* For compatibility with Symbian */\n#define wdirent    _wdirent\n#define WDIR       _WDIR\n#define wopendir   _wopendir\n#define wreaddir   _wreaddir\n#define wclosedir  _wclosedir\n#define wrewinddir _wrewinddir\n\n/* Multi-byte character versions */\nstruct dirent {\n    long           d_ino;            /* Always zero */\n    unsigned short d_reclen;         /* Structure size */\n    size_t         d_namlen;         /* Length of name without \\0 */\n    int            d_type;           /* File type */\n    char           d_name[PATH_MAX]; /* File name */\n};\ntypedef struct dirent dirent;\n\nstruct DIR {\n    struct dirent ent;\n    struct _WDIR *wdirp;\n};\ntypedef struct DIR DIR;\n\nstatic DIR *          opendir(const char *dirname);\nstatic struct dirent *readdir(DIR *dirp);\nstatic int            closedir(DIR *dirp);\nstatic void           rewinddir(DIR *dirp);\n\n/* Internal utility functions */\nstatic WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);\nstatic WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);\n\nstatic int dirent_mbstowcs_s(size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count);\n\nstatic int dirent_wcstombs_s(size_t *pReturnValue, char *mbstr, size_t sizeInBytes, const wchar_t *wcstr, size_t count);\n\nstatic void dirent_set_errno(int error);\n\n/*\n * Open directory stream DIRNAME for read and return a pointer to the\n * internal working area that is used to retrieve individual directory\n * entries.\n */\nstatic _WDIR *_wopendir(const wchar_t *dirname)\n{\n    _WDIR *dirp = NULL;\n    int    error;\n\n    /* Must have directory name */\n    if (dirname == NULL || dirname[0] == '\\0') {\n        dirent_set_errno(ENOENT);\n        return NULL;\n    }\n\n    /* Allocate new _WDIR structure */\n    dirp = (_WDIR *)malloc(sizeof(struct _WDIR));\n    if (dirp != NULL) {\n        DWORD n;\n\n        /* Reset _WDIR structure */\n        dirp->handle = INVALID_HANDLE_VALUE;\n        dirp->patt = NULL;\n        dirp->cached = 0;\n\n        /* Compute the length of full path plus zero terminator */\n        n = GetFullPathNameW(dirname, 0, NULL, NULL);\n\n        /* Allocate room for absolute directory name and search pattern */\n        dirp->patt = (wchar_t *)malloc(sizeof(wchar_t) * n + 16);\n        if (dirp->patt) {\n            /*\n             * Convert relative directory name to an absolute one.  This\n             * allows rewinddir() to function correctly even when current\n             * working directory is changed between opendir() and rewinddir().\n             */\n            n = GetFullPathNameW(dirname, n, dirp->patt, NULL);\n            if (n > 0) {\n                wchar_t *p;\n\n                /* Append search pattern \\* to the directory name */\n                p = dirp->patt + n;\n                if (dirp->patt < p) {\n                    switch (p[-1]) {\n                    case '\\\\':\n                    case '/':\n                    case ':':\n                        /* Directory ends in path separator, e.g. c:\\temp\\ */\n                        /*NOP*/;\n                        break;\n\n                    default:\n                        /* Directory name doesn't end in path separator */\n                        *p++ = '\\\\';\n                    }\n                }\n                *p++ = '*';\n                *p = '\\0';\n\n                /* Open directory stream and retrieve the first entry */\n                if (dirent_first(dirp)) {\n                    /* Directory stream opened successfully */\n                    error = 0;\n                } else {\n                    /* Cannot retrieve first entry */\n                    error = 1;\n                    dirent_set_errno(ENOENT);\n                }\n\n            } else {\n                /* Cannot retrieve full path name */\n                dirent_set_errno(ENOENT);\n                error = 1;\n            }\n\n        } else {\n            /* Cannot allocate memory for search pattern */\n            error = 1;\n        }\n\n    } else {\n        /* Cannot allocate _WDIR structure */\n        error = 1;\n    }\n\n    /* Clean up in case of error */\n    if (error && dirp) {\n        _wclosedir(dirp);\n        dirp = NULL;\n    }\n\n    return dirp;\n}\n\n/*\n * Read next directory entry.  The directory entry is returned in dirent\n * structure in the d_name field.  Individual directory entries returned by\n * this function include regular files, sub-directories, pseudo-directories\n * \".\" and \"..\" as well as volume labels, hidden files and system files.\n */\nstatic struct _wdirent *_wreaddir(_WDIR *dirp)\n{\n    WIN32_FIND_DATAW *datap;\n    struct _wdirent * entp;\n\n    /* Read next directory entry */\n    datap = dirent_next(dirp);\n    if (datap) {\n        size_t n;\n        DWORD  attr;\n\n        /* Pointer to directory entry to return */\n        entp = &dirp->ent;\n\n        /*\n         * Copy file name as wide-character string.  If the file name is too\n         * long to fit in to the destination buffer, then truncate file name\n         * to PATH_MAX characters and zero-terminate the buffer.\n         */\n        n = 0;\n        while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) {\n            entp->d_name[n] = datap->cFileName[n];\n            n++;\n        }\n        dirp->ent.d_name[n] = 0;\n\n        /* Length of file name excluding zero terminator */\n        entp->d_namlen = n;\n\n        /* File type */\n        attr = datap->dwFileAttributes;\n        if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {\n            entp->d_type = DT_CHR;\n        } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {\n            entp->d_type = DT_DIR;\n        } else {\n            entp->d_type = DT_REG;\n        }\n\n        /* Reset dummy fields */\n        entp->d_ino = 0;\n        entp->d_reclen = sizeof(struct _wdirent);\n\n    } else {\n        /* Last directory entry read */\n        entp = NULL;\n    }\n\n    return entp;\n}\n\n/*\n * Close directory stream opened by opendir() function.  This invalidates the\n * DIR structure as well as any directory entry read previously by\n * _wreaddir().\n */\nstatic int _wclosedir(_WDIR *dirp)\n{\n    int ok;\n    if (dirp) {\n        /* Release search handle */\n        if (dirp->handle != INVALID_HANDLE_VALUE) {\n            FindClose(dirp->handle);\n            dirp->handle = INVALID_HANDLE_VALUE;\n        }\n\n        /* Release search pattern */\n        if (dirp->patt) {\n            free(dirp->patt);\n            dirp->patt = NULL;\n        }\n\n        /* Release directory structure */\n        free(dirp);\n        ok = /*success*/ 0;\n\n    } else {\n        /* Invalid directory stream */\n        dirent_set_errno(EBADF);\n        ok = /*failure*/ -1;\n    }\n    return ok;\n}\n\n/*\n * Rewind directory stream such that _wreaddir() returns the very first\n * file name again.\n */\nstatic void _wrewinddir(_WDIR *dirp)\n{\n    if (dirp) {\n        /* Release existing search handle */\n        if (dirp->handle != INVALID_HANDLE_VALUE) { FindClose(dirp->handle); }\n\n        /* Open new search handle */\n        dirent_first(dirp);\n    }\n}\n\n/* Get first directory entry (internal) */\nstatic WIN32_FIND_DATAW *dirent_first(_WDIR *dirp)\n{\n    WIN32_FIND_DATAW *datap;\n\n    /* Open directory and retrieve the first entry */\n    dirp->handle = FindFirstFileW(dirp->patt, &dirp->data);\n    if (dirp->handle != INVALID_HANDLE_VALUE) {\n        /* a directory entry is now waiting in memory */\n        datap = &dirp->data;\n        dirp->cached = 1;\n\n    } else {\n        /* Failed to re-open directory: no directory entry in memory */\n        dirp->cached = 0;\n        datap = NULL;\n    }\n    return datap;\n}\n\n/* Get next directory entry (internal) */\nstatic WIN32_FIND_DATAW *dirent_next(_WDIR *dirp)\n{\n    WIN32_FIND_DATAW *p;\n\n    /* Get next directory entry */\n    if (dirp->cached != 0) {\n        /* A valid directory entry already in memory */\n        p = &dirp->data;\n        dirp->cached = 0;\n\n    } else if (dirp->handle != INVALID_HANDLE_VALUE) {\n        /* Get the next directory entry from stream */\n        if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {\n            /* Got a file */\n            p = &dirp->data;\n        } else {\n            /* The very last entry has been processed or an error occured */\n            FindClose(dirp->handle);\n            dirp->handle = INVALID_HANDLE_VALUE;\n            p = NULL;\n        }\n\n    } else {\n        /* End of directory stream reached */\n        p = NULL;\n    }\n\n    return p;\n}\n\n/*\n * Open directory stream using plain old C-string.\n */\nstatic DIR *opendir(const char *dirname)\n{\n    struct DIR *dirp;\n    int         error;\n\n    /* Must have directory name */\n    if (dirname == NULL || dirname[0] == '\\0') {\n        dirent_set_errno(ENOENT);\n        return NULL;\n    }\n\n    /* Allocate memory for DIR structure */\n    dirp = (DIR *)malloc(sizeof(struct DIR));\n    if (dirp) {\n        wchar_t wname[PATH_MAX];\n        size_t  n;\n\n        /* Convert directory name to wide-character string */\n        error = dirent_mbstowcs_s(&n, wname, PATH_MAX, dirname, PATH_MAX);\n        if (!error) {\n            /* Open directory stream using wide-character name */\n            dirp->wdirp = _wopendir(wname);\n            if (dirp->wdirp) {\n                /* Directory stream opened */\n                error = 0;\n            } else {\n                /* Failed to open directory stream */\n                error = 1;\n            }\n\n        } else {\n            /*\n             * Cannot convert file name to wide-character string.  This\n             * occurs if the string contains invalid multi-byte sequences or\n             * the output buffer is too small to contain the resulting\n             * string.\n             */\n            error = 1;\n        }\n\n    } else {\n        /* Cannot allocate DIR structure */\n        error = 1;\n    }\n\n    /* Clean up in case of error */\n    if (error && dirp) {\n        free(dirp);\n        dirp = NULL;\n    }\n\n    return dirp;\n}\n\n/*\n * Read next directory entry.\n *\n * When working with text consoles, please note that file names returned by\n * readdir() are represented in the default ANSI code page while any output to\n * console is typically formatted on another code page.  Thus, non-ASCII\n * characters in file names will not usually display correctly on console.  The\n * problem can be fixed in two ways: (1) change the character set of console\n * to 1252 using chcp utility and use Lucida Console font, or (2) use\n * _cprintf function when writing to console.  The _cprinf() will re-encode\n * ANSI strings to the console code page so many non-ASCII characters will\n * display correcly.\n */\nstatic struct dirent *readdir(DIR *dirp)\n{\n    WIN32_FIND_DATAW *datap;\n    struct dirent *   entp;\n\n    /* Read next directory entry */\n    datap = dirent_next(dirp->wdirp);\n    if (datap) {\n        size_t n;\n        int    error;\n\n        /* Attempt to convert file name to multi-byte string */\n        error = dirent_wcstombs_s(&n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);\n\n        /*\n         * If the file name cannot be represented by a multi-byte string,\n         * then attempt to use old 8+3 file name.  This allows traditional\n         * Unix-code to access some file names despite of unicode\n         * characters, although file names may seem unfamiliar to the user.\n         *\n         * Be ware that the code below cannot come up with a short file\n         * name unless the file system provides one.  At least\n         * VirtualBox shared folders fail to do this.\n         */\n        if (error && datap->cAlternateFileName[0] != '\\0') { error = dirent_wcstombs_s(&n, dirp->ent.d_name, PATH_MAX, datap->cAlternateFileName, PATH_MAX); }\n\n        if (!error) {\n            DWORD attr;\n\n            /* Initialize directory entry for return */\n            entp = &dirp->ent;\n\n            /* Length of file name excluding zero terminator */\n            entp->d_namlen = n - 1;\n\n            /* File attributes */\n            attr = datap->dwFileAttributes;\n            if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {\n                entp->d_type = DT_CHR;\n            } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {\n                entp->d_type = DT_DIR;\n            } else {\n                entp->d_type = DT_REG;\n            }\n\n            /* Reset dummy fields */\n            entp->d_ino = 0;\n            entp->d_reclen = sizeof(struct dirent);\n\n        } else {\n            /*\n             * Cannot convert file name to multi-byte string so construct\n             * an errornous directory entry and return that.  Note that\n             * we cannot return NULL as that would stop the processing\n             * of directory entries completely.\n             */\n            entp = &dirp->ent;\n            entp->d_name[0] = '?';\n            entp->d_name[1] = '\\0';\n            entp->d_namlen = 1;\n            entp->d_type = DT_UNKNOWN;\n            entp->d_ino = 0;\n            entp->d_reclen = 0;\n        }\n\n    } else {\n        /* No more directory entries */\n        entp = NULL;\n    }\n\n    return entp;\n}\n\n/*\n * Close directory stream.\n */\nstatic int closedir(DIR *dirp)\n{\n    int ok;\n    if (dirp) {\n        /* Close wide-character directory stream */\n        ok = _wclosedir(dirp->wdirp);\n        dirp->wdirp = NULL;\n\n        /* Release multi-byte character version */\n        free(dirp);\n\n    } else {\n        /* Invalid directory stream */\n        dirent_set_errno(EBADF);\n        ok = /*failure*/ -1;\n    }\n    return ok;\n}\n\n/*\n * Rewind directory stream to beginning.\n */\nstatic void rewinddir(DIR *dirp)\n{\n    /* Rewind wide-character string directory stream */\n    _wrewinddir(dirp->wdirp);\n}\n\n/* Convert multi-byte string to wide character string */\nstatic int dirent_mbstowcs_s(size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords, const char *mbstr, size_t count)\n{\n    int error;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\n    /* Microsoft Visual Studio 2005 or later */\n    error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count);\n\n#else\n\n    /* Older Visual Studio or non-Microsoft compiler */\n    size_t n;\n\n    /* Convert to wide-character string (or count characters) */\n    n = mbstowcs(wcstr, mbstr, sizeInWords);\n    if (!wcstr || n < count) {\n        /* Zero-terminate output buffer */\n        if (wcstr && sizeInWords) {\n            if (n >= sizeInWords) { n = sizeInWords - 1; }\n            wcstr[n] = 0;\n        }\n\n        /* Length of resuting multi-byte string WITH zero terminator */\n        if (pReturnValue) { *pReturnValue = n + 1; }\n\n        /* Success */\n        error = 0;\n\n    } else {\n        /* Could not convert string */\n        error = 1;\n    }\n\n#endif\n\n    return error;\n}\n\n/* Convert wide-character string to multi-byte string */\nstatic int dirent_wcstombs_s(size_t *pReturnValue, char *mbstr, size_t sizeInBytes, /* max size of mbstr */\n                             const wchar_t *wcstr, size_t count)\n{\n    int error;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\n    /* Microsoft Visual Studio 2005 or later */\n    error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count);\n\n#else\n\n    /* Older Visual Studio or non-Microsoft compiler */\n    size_t n;\n\n    /* Convert to multi-byte string (or count the number of bytes needed) */\n    n = wcstombs(mbstr, wcstr, sizeInBytes);\n    if (!mbstr || n < count) {\n        /* Zero-terminate output buffer */\n        if (mbstr && sizeInBytes) {\n            if (n >= sizeInBytes) { n = sizeInBytes - 1; }\n            mbstr[n] = '\\0';\n        }\n\n        /* Lenght of resulting multi-bytes string WITH zero-terminator */\n        if (pReturnValue) { *pReturnValue = n + 1; }\n\n        /* Success */\n        error = 0;\n\n    } else {\n        /* Cannot convert string */\n        error = 1;\n    }\n\n#endif\n\n    return error;\n}\n\n/* Set errno variable */\nstatic void dirent_set_errno(int error)\n{\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\n    /* Microsoft Visual Studio 2005 and later */\n    _set_errno(error);\n\n#else\n\n    /* Non-Microsoft compiler or older Microsoft compiler */\n    errno = error;\n\n#endif\n}\n\n#ifdef __cplusplus\n}\n#endif\n#endif /*DIRENT_H*/\n"
  },
  {
    "path": "include/vapor/errorcodes.h",
    "content": "//-- errorcodes.h ------------------------------------------------------------\n//\n//                   Copyright (C)  2004\n//     University Corporation for Atmospheric Research\n//                   All Rights Reserved\n//\n//----------------------------------------------------------------------------\n//\n//      File:           errorcodes.h\n//\n//      Author:         Kenny Gruchalla\n//                      National Center for Atmospheric Research\n//                      PO 3000, Boulder, Colorado\n//\n//      Date:           August 2006\n//\n//      Description:    VAPoR error codes used for message reporting.\n//\n//                      The high-order bits of the codes are bit masked\n//                      providing type information: diagonstic, warning, error,\n//                      and fatal.\n//\n//                      For example, if (code & VAPoR::WARNING) then 'code'\n//                      is a warning type.\n//\n//----------------------------------------------------------------------------\n\nnamespace VAPoR {\nenum errorcodes {\n    // VDF Errors: 0x1 - 0xFF:  Handled specially:\n    // The Vaporgui application will not clear\n    // error codes less than 0xfff, until the\n    // error is later detected in the application.\n    // Any errors discovered in the application\n    // must be set with an error code > 0xfff, or\n    // the error will cause methods\n    // in the VDF library to fail.\n    VAPOR_ERROR_VDF = 0x1,\n    VAPOR_ERROR_XML = 0x2,\n    // Diagnostic Codes  0x1001 - 0x1FFF\n    // Currently, diagnostic codes are not used\n    VAPOR_DIAGNOSTIC = 0x1000,\n\n    // Warning Codes     0x2001 - 0x2FFF\n    VAPOR_WARNING = 0x2000,\n    VAPOR_WARNING_GL_SHADER_LOG = 0x2001,\n    VAPOR_WARNING_FLOW = 0x2100,\n    VAPOR_WARNING_SEEDS = 0x2101,\n    VAPOR_WARNING_FLOW_DATA = 0x2102,\n    VAPOR_WARNING_FLOW_STOP = 0x2103,\n    VAPOR_WARNING_DATA_UNAVAILABLE = 0x2004,\n    VAPOR_WARNING_GL_ERROR = 0x2105,\n    VAPOR_WARNING_TWO_D = 0x2106,\n\n    // Error Codes       0x4001 - 0x4FFF\n    VAPOR_ERROR = 0x4000,\n    VAPOR_ERROR_GL_RENDERING = 0x4001,\n    VAPOR_ERROR_GL_UNKNOWN_UNIFORM = 0x4002,\n    VAPOR_ERROR_DATA_UNAVAILABLE = 0x4003,\n    VAPOR_ERROR_DATA_TOO_BIG = 0x4004,\n    VAPOR_ERROR_DRIVER_FAILURE = 0x4005,\n    VAPOR_ERROR_GL_VENDOR = 0x4006,\n    VAPOR_ERROR_DVR = 0x4007,\n    VAPOR_ERROR_IMAGE_CAPTURE = 0x4008,\n    VAPOR_ERROR_SPHERICAL = 0x4009,\n    VAPOR_ERROR_STRETCHED = 0x4010,\n    VAPOR_ERROR_PARAMS = 0x4011,\n    VAPOR_ERROR_TWO_D = 0x4012,\n    VAPOR_ERROR_GEOREFERENCE = 0x4013,\n    VAPOR_ERROR_SCRIPTING = 0x4014,\n    VAPOR_ERROR_PARSING = 0x4015,\n    VAPOR_ERROR_VDC_MERGE = 0x4016,\n    VAPOR_ERROR_GL_SHADER = 0x4017,\n\n    // Flow errors\n    VAPOR_ERROR_FLOW = 0x4100,\n    VAPOR_ERROR_SEEDS = 0x4101,\n    VAPOR_ERROR_INTEGRATION = 0x4102,\n    VAPOR_ERROR_FLOW_DATA = 0x4103,\n    VAPOR_ERROR_FLOW_SAVE = 0x4104,\n\n    // Fatal Codes       0x8001 - 0x8FFF\n    VAPOR_FATAL = 0x8000\n};\n};\n"
  },
  {
    "path": "include/vapor/glutil.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tglutil.h\n//\n//\tAdaptor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJuly 2004\n//\n//\tDescription:  Methods to facilitate use of trackball navigation,\n//\t\tadapted from Ken Purcell's code to work in QT window\n//\n// Copyright (C) 1992  AHPCRC, Univeristy of Minnesota\n//\n// This program is free software; you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation; either version 2 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program in a file named 'Copying'; if not, write to\n// the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139.\n//\n\n// Original Author:\n//\tKen Chin-Purcell (ken@ahpcrc.umn.edu)\n//\tArmy High Performance Computing Research Center (AHPCRC)\n//\tUniveristy of Minnesota\n//\n\n#ifndef _glutil_h_\n#define _glutil_h_\n\n#ifdef __APPLE__\n    #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED\n#endif\n\n#include <vapor/GLInclude.h>\n#include <cmath>\n#include <vector>\n#include <string>\n#include <vapor/common.h>\n\n/* These vector and quaternion macros complement similar\n * routines.\n */\n\n#ifdef ArchLinux\n    #define sqrtf(fval) ((float)sqrt((double)(fval)))\n    #define fabsf(fval) ((float)fabs((double)(fval)))\n    #define sinf(fval)  ((float)sin((double)(fval)))\n    #define cosf(fval)  ((float)cos((double)(fval)))\n    #define tanf(fval)  ((float)tan((double)(fval)))\n#endif\n\n//#define vset(a,x,y,z)\t(a[0] = x, a[1] = y, a[2] = z)\n//#define Verify(expr,estr)\tif (!(expr)) BailOut(estr,__FILE__,__LINE__)\n\n#define CallocType(type, i) (type *)calloc(i, sizeof(type))\n\n#define YMAXSTEREO 491\n#define YOFFSET    532\n#ifndef M_PI\n    #define M_PI 3.14159265358979323846\n#endif\n/*extern GLfloat *idmatrix;*/\n\nnamespace VAPoR {\n\n/* glutil.c */\n\nRENDER_API int __CheckGLError(const char *file, int line, const char *msg = 0);\n\n//! Check for any OpenGL errors and return their error codes\n//!\n//! This function calls glGetError() to test for any OpenGL errors.\n//! If no errors are detected the function returns \\b true. If one\n//! or more errors are detected the function returns false and stores\n//! each of the error codes in the \\p status vector\n//\nRENDER_API bool oglStatusOK(std::vector<int> &status);\n\nRENDER_API void doubleToString(const double val, std::string &result, int digits);\n//! Decode OpenGL error codes and format them as a string\n//!\n//! This function takes a vector of error codes (see oglStatusOK) and\n//! produces a formatted error string from the list of codes\n//\nRENDER_API std::string oglGetErrMsg(std::vector<int> status);\n\n//! Returns free RAM in kilobytes\n//! Returns -1 if not supported\nRENDER_API int oglGetFreeMemory();\n\n//! Test readyness of OpenGL frame buffer, GL_FRAMEBUFFER\n//!\nRENDER_API bool FrameBufferReady();\n};    // namespace VAPoR\n\n#define CheckGLError()       __CheckGLError(__FILE__, __LINE__)\n#define CheckGLErrorMsg(msg) __CheckGLError(__FILE__, __LINE__, msg)\n\n#ifndef NDEBUG\n    #ifdef Darwin\n        #define GL_LEGACY(x) \\\n            {                \\\n            }\n    #else\n        #define GL_LEGACY(x) x\n    #endif\n    #include <signal.h>\n    #define GL_ERR_BREAK() \\\n        if (CheckGLError()) ::raise(SIGINT)\n#else\n    #define GL_LEGACY(x)\n    #define GL_ERR_BREAK()\n#endif\n\n#endif    // _glutil_h_\n"
  },
  {
    "path": "include/vapor/jpegapi.h",
    "content": "#ifndef JPEGAPI_H\n#define JPEGAPI_H\n/*\n *  This header defines the external api to the jpeg library.\n */\n#include <vapor/common.h>\n\nnamespace VAPoR {\n\nRENDER_API int write_JPEG_file(FILE *file, int image_width, int image_height, unsigned char *image_buffer, int quality);\n\nRENDER_API int read_JPEG_file(const char *filename, unsigned char **imageBuffer, int *width, int *height);\n\n//(void) free_image(unsigned char* imageData);\n\n};    // namespace VAPoR\n\n#endif    // JPEGAPI_H\n"
  },
  {
    "path": "include/vapor/nanoflann.hpp",
    "content": "/***********************************************************************\n * Software License Agreement (BSD License)\n *\n * Copyright 2008-2009  Marius Muja (mariusm@cs.ubc.ca). All rights reserved.\n * Copyright 2008-2009  David G. Lowe (lowe@cs.ubc.ca). All rights reserved.\n * Copyright 2011-2016  Jose Luis Blanco (joseluisblancoc@gmail.com).\n *   All rights reserved.\n *\n * THE BSD LICENSE\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *************************************************************************/\n\n/** \\mainpage nanoflann C++ API documentation\n *  nanoflann is a C++ header-only library for building KD-Trees, mostly\n *  optimized for 2D or 3D point clouds.\n *\n *  nanoflann does not require compiling or installing, just an\n *  #include <nanoflann.hpp> in your code.\n *\n *  See:\n *   - <a href=\"modules.html\" >C++ API organized by modules</a>\n *   - <a href=\"https://github.com/jlblancoc/nanoflann\" >Online README</a>\n *   - <a href=\"http://jlblancoc.github.io/nanoflann/\" >Doxygen documentation</a>\n */\n\n#ifndef NANOFLANN_HPP_\n#define NANOFLANN_HPP_\n\n#include <vector>\n#include <cassert>\n#include <algorithm>\n#include <stdexcept>\n#include <cstdio>            // for fwrite()\n#define _USE_MATH_DEFINES    // Required by MSVC to define M_PI,etc. in <cmath>\n#include <cmath>             // for abs()\n#include <cstdlib>           // for abs()\n#include <limits>\n\n// Avoid conflicting declaration of min/max macros in windows headers\n#if !defined(NOMINMAX) && (defined(_WIN32) || defined(_WIN32_) || defined(WIN32) || defined(_WIN64))\n    #define NOMINMAX\n    #ifdef max\n        #undef max\n        #undef min\n    #endif\n#endif\n\nnamespace nanoflann {\n/** @addtogroup nanoflann_grp nanoflann C++ library for ANN\n *  @{ */\n\n/** Library version: 0xMmP (M=Major,m=minor,P=patch) */\n#define NANOFLANN_VERSION 0x123\n\n/** @addtogroup result_sets_grp Result set classes\n *  @{ */\ntemplate<typename DistanceType, typename IndexType = size_t, typename CountType = size_t> class KNNResultSet {\n    IndexType *   indices;\n    DistanceType *dists;\n    CountType     capacity;\n    CountType     count;\n\npublic:\n    inline KNNResultSet(CountType capacity_) : indices(0), dists(0), capacity(capacity_), count(0) {}\n\n    inline void init(IndexType *indices_, DistanceType *dists_)\n    {\n        indices = indices_;\n        dists = dists_;\n        count = 0;\n        if (capacity) dists[capacity - 1] = (std::numeric_limits<DistanceType>::max)();\n    }\n\n    inline CountType size() const { return count; }\n\n    inline bool full() const { return count == capacity; }\n\n    /**\n     * Called during search to add an element matching the criteria.\n     * @return true if the search should be continued, false if the results are sufficient\n     */\n    inline bool addPoint(DistanceType dist, IndexType index)\n    {\n        CountType i;\n        for (i = count; i > 0; --i) {\n#ifdef NANOFLANN_FIRST_MATCH    // If defined and two points have the same distance, the one with the lowest-index will be returned first.\n            if ((dists[i - 1] > dist) || ((dist == dists[i - 1]) && (indices[i - 1] > index))) {\n#else\n            if (dists[i - 1] > dist) {\n#endif\n                if (i < capacity) {\n                    dists[i] = dists[i - 1];\n                    indices[i] = indices[i - 1];\n                }\n            } else\n                break;\n        }\n        if (i < capacity) {\n            dists[i] = dist;\n            indices[i] = index;\n        }\n        if (count < capacity) count++;\n\n        // tell caller that the search shall continue\n        return true;\n    }\n\n    inline DistanceType worstDist() const { return dists[capacity - 1]; }\n};    // namespace nanoflann\n\n/** operator \"<\" for std::sort() */\nstruct IndexDist_Sorter {\n    /** PairType will be typically: std::pair<IndexType,DistanceType> */\n    template<typename PairType> inline bool operator()(const PairType &p1, const PairType &p2) const { return p1.second < p2.second; }\n};\n\n/**\n * A result-set class used when performing a radius based search.\n */\ntemplate<typename DistanceType, typename IndexType = size_t> class RadiusResultSet {\npublic:\n    const DistanceType radius;\n\n    std::vector<std::pair<IndexType, DistanceType>> &m_indices_dists;\n\n    inline RadiusResultSet(DistanceType radius_, std::vector<std::pair<IndexType, DistanceType>> &indices_dists) : radius(radius_), m_indices_dists(indices_dists) { init(); }\n\n    inline void init() { clear(); }\n    inline void clear() { m_indices_dists.clear(); }\n\n    inline size_t size() const { return m_indices_dists.size(); }\n\n    inline bool full() const { return true; }\n\n    /**\n     * Called during search to add an element matching the criteria.\n     * @return true if the search should be continued, false if the results are sufficient\n     */\n    inline bool addPoint(DistanceType dist, IndexType index)\n    {\n        if (dist < radius) m_indices_dists.push_back(std::make_pair(index, dist));\n        return true;\n    }\n\n    inline DistanceType worstDist() const { return radius; }\n\n    /**\n     * Find the worst result (furtherest neighbor) without copying or sorting\n     * Pre-conditions: size() > 0\n     */\n    std::pair<IndexType, DistanceType> worst_item() const\n    {\n        if (m_indices_dists.empty()) throw std::runtime_error(\"Cannot invoke RadiusResultSet::worst_item() on an empty list of results.\");\n        typedef typename std::vector<std::pair<IndexType, DistanceType>>::const_iterator DistIt;\n        DistIt                                                                           it = std::max_element(m_indices_dists.begin(), m_indices_dists.end(), IndexDist_Sorter());\n        return *it;\n    }\n};\n\n/** @} */\n\n/** @addtogroup loadsave_grp Load/save auxiliary functions\n * @{ */\ntemplate<typename T> void save_value(FILE *stream, const T &value, size_t count = 1) { fwrite(&value, sizeof(value), count, stream); }\n\ntemplate<typename T> void save_value(FILE *stream, const std::vector<T> &value)\n{\n    size_t size = value.size();\n    fwrite(&size, sizeof(size_t), 1, stream);\n    fwrite(&value[0], sizeof(T), size, stream);\n}\n\ntemplate<typename T> void load_value(FILE *stream, T &value, size_t count = 1)\n{\n    size_t read_cnt = fread(&value, sizeof(value), count, stream);\n    if (read_cnt != count) { throw std::runtime_error(\"Cannot read from file\"); }\n}\n\ntemplate<typename T> void load_value(FILE *stream, std::vector<T> &value)\n{\n    size_t size;\n    size_t read_cnt = fread(&size, sizeof(size_t), 1, stream);\n    if (read_cnt != 1) { throw std::runtime_error(\"Cannot read from file\"); }\n    value.resize(size);\n    read_cnt = fread(&value[0], sizeof(T), size, stream);\n    if (read_cnt != size) { throw std::runtime_error(\"Cannot read from file\"); }\n}\n/** @} */\n\n/** @addtogroup metric_grp Metric (distance) classes\n * @{ */\n\nstruct Metric {\n};\n\n/** Manhattan distance functor (generic version, optimized for high-dimensionality data sets).\n *  Corresponding distance traits: nanoflann::metric_L1\n * \\tparam T Type of the elements (e.g. double, float, uint8_t)\n * \\tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t)\n */\ntemplate<class T, class DataSource, typename _DistanceType = T> struct L1_Adaptor {\n    typedef T             ElementType;\n    typedef _DistanceType DistanceType;\n\n    const DataSource &data_source;\n\n    L1_Adaptor(const DataSource &_data_source) : data_source(_data_source) {}\n\n    inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size, DistanceType worst_dist = -1) const\n    {\n        DistanceType result = DistanceType();\n        const T *    last = a + size;\n        const T *    lastgroup = last - 3;\n        size_t       d = 0;\n\n        /* Process 4 items with each loop for efficiency. */\n        while (a < lastgroup) {\n            const DistanceType diff0 = std::abs(a[0] - data_source.kdtree_get_pt(b_idx, d++));\n            const DistanceType diff1 = std::abs(a[1] - data_source.kdtree_get_pt(b_idx, d++));\n            const DistanceType diff2 = std::abs(a[2] - data_source.kdtree_get_pt(b_idx, d++));\n            const DistanceType diff3 = std::abs(a[3] - data_source.kdtree_get_pt(b_idx, d++));\n            result += diff0 + diff1 + diff2 + diff3;\n            a += 4;\n            if ((worst_dist > 0) && (result > worst_dist)) { return result; }\n        }\n        /* Process last 0-3 components.  Not needed for standard vector lengths. */\n        while (a < last) { result += std::abs(*a++ - data_source.kdtree_get_pt(b_idx, d++)); }\n        return result;\n    }\n\n    template<typename U, typename V> inline DistanceType accum_dist(const U a, const V b, int) const { return std::abs(a - b); }\n};\n\n/** Squared Euclidean distance functor (generic version, optimized for high-dimensionality data sets).\n *  Corresponding distance traits: nanoflann::metric_L2\n * \\tparam T Type of the elements (e.g. double, float, uint8_t)\n * \\tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t)\n */\ntemplate<class T, class DataSource, typename _DistanceType = T> struct L2_Adaptor {\n    typedef T             ElementType;\n    typedef _DistanceType DistanceType;\n\n    const DataSource &data_source;\n\n    L2_Adaptor(const DataSource &_data_source) : data_source(_data_source) {}\n\n    inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size, DistanceType worst_dist = -1) const\n    {\n        DistanceType result = DistanceType();\n        const T *    last = a + size;\n        const T *    lastgroup = last - 3;\n        size_t       d = 0;\n\n        /* Process 4 items with each loop for efficiency. */\n        while (a < lastgroup) {\n            const DistanceType diff0 = a[0] - data_source.kdtree_get_pt(b_idx, d++);\n            const DistanceType diff1 = a[1] - data_source.kdtree_get_pt(b_idx, d++);\n            const DistanceType diff2 = a[2] - data_source.kdtree_get_pt(b_idx, d++);\n            const DistanceType diff3 = a[3] - data_source.kdtree_get_pt(b_idx, d++);\n            result += diff0 * diff0 + diff1 * diff1 + diff2 * diff2 + diff3 * diff3;\n            a += 4;\n            if ((worst_dist > 0) && (result > worst_dist)) { return result; }\n        }\n        /* Process last 0-3 components.  Not needed for standard vector lengths. */\n        while (a < last) {\n            const DistanceType diff0 = *a++ - data_source.kdtree_get_pt(b_idx, d++);\n            result += diff0 * diff0;\n        }\n        return result;\n    }\n\n    template<typename U, typename V> inline DistanceType accum_dist(const U a, const V b, int) const { return (a - b) * (a - b); }\n};\n\n/** Squared Euclidean (L2) distance functor (suitable for low-dimensionality datasets, like 2D or 3D point clouds)\n *  Corresponding distance traits: nanoflann::metric_L2_Simple\n * \\tparam T Type of the elements (e.g. double, float, uint8_t)\n * \\tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double, int64_t)\n */\ntemplate<class T, class DataSource, typename _DistanceType = T> struct L2_Simple_Adaptor {\n    typedef T             ElementType;\n    typedef _DistanceType DistanceType;\n\n    const DataSource &data_source;\n\n    L2_Simple_Adaptor(const DataSource &_data_source) : data_source(_data_source) {}\n\n    inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size) const\n    {\n        DistanceType result = DistanceType();\n        for (size_t i = 0; i < size; ++i) {\n            const DistanceType diff = a[i] - data_source.kdtree_get_pt(b_idx, i);\n            result += diff * diff;\n        }\n        return result;\n    }\n\n    template<typename U, typename V> inline DistanceType accum_dist(const U a, const V b, int) const { return (a - b) * (a - b); }\n};\n\n/** SO2 distance functor\n *  Corresponding distance traits: nanoflann::metric_SO2\n * \\tparam T Type of the elements (e.g. double, float)\n * \\tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double)\n * orientation is constrained to be in [-pi, pi]\n */\ntemplate<class T, class DataSource, typename _DistanceType = T> struct SO2_Adaptor {\n    typedef T             ElementType;\n    typedef _DistanceType DistanceType;\n\n    const DataSource &data_source;\n\n    SO2_Adaptor(const DataSource &_data_source) : data_source(_data_source) {}\n\n    inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size) const { return accum_dist(a[size - 1], data_source.kdtree_get_pt(b_idx, size - 1), size - 1); }\n\n    template<typename U, typename V> inline DistanceType accum_dist(const U a, const V b, int) const\n    {\n        DistanceType result = DistanceType();\n        result = b - a;\n        if (result > M_PI)\n            result -= 2. * M_PI;\n        else if (result < -M_PI)\n            result += 2. * M_PI;\n        return result;\n    }\n};\n\n/** SO3 distance functor (Uses L2_Simple)\n *  Corresponding distance traits: nanoflann::metric_SO3\n * \\tparam T Type of the elements (e.g. double, float)\n * \\tparam _DistanceType Type of distance variables (must be signed) (e.g. float, double)\n */\ntemplate<class T, class DataSource, typename _DistanceType = T> struct SO3_Adaptor {\n    typedef T             ElementType;\n    typedef _DistanceType DistanceType;\n\n    L2_Simple_Adaptor<T, DataSource> distance_L2_Simple;\n\n    SO3_Adaptor(const DataSource &_data_source) : distance_L2_Simple(_data_source) {}\n\n    inline DistanceType evalMetric(const T *a, const size_t b_idx, size_t size) const { return distance_L2_Simple.evalMetric(a, b_idx, size); }\n\n    template<typename U, typename V> inline DistanceType accum_dist(const U a, const V b, int idx) const { return distance_L2_Simple.accum_dist(a, b, idx); }\n};\n\n/** Metaprogramming helper traits class for the L1 (Manhattan) metric */\nstruct metric_L1 : public Metric {\n    template<class T, class DataSource> struct traits {\n        typedef L1_Adaptor<T, DataSource> distance_t;\n    };\n};\n/** Metaprogramming helper traits class for the L2 (Euclidean) metric */\nstruct metric_L2 : public Metric {\n    template<class T, class DataSource> struct traits {\n        typedef L2_Adaptor<T, DataSource> distance_t;\n    };\n};\n/** Metaprogramming helper traits class for the L2_simple (Euclidean) metric */\nstruct metric_L2_Simple : public Metric {\n    template<class T, class DataSource> struct traits {\n        typedef L2_Simple_Adaptor<T, DataSource> distance_t;\n    };\n};\n/** Metaprogramming helper traits class for the SO3_InnerProdQuat metric */\nstruct metric_SO2 : public Metric {\n    template<class T, class DataSource> struct traits {\n        typedef SO2_Adaptor<T, DataSource> distance_t;\n    };\n};\n/** Metaprogramming helper traits class for the SO3_InnerProdQuat metric */\nstruct metric_SO3 : public Metric {\n    template<class T, class DataSource> struct traits {\n        typedef SO3_Adaptor<T, DataSource> distance_t;\n    };\n};\n\n/** @} */\n\n/** @addtogroup param_grp Parameter structs\n * @{ */\n\n/**  Parameters (see README.md) */\nstruct KDTreeSingleIndexAdaptorParams {\n    KDTreeSingleIndexAdaptorParams(size_t _leaf_max_size = 10) : leaf_max_size(_leaf_max_size) {}\n\n    size_t leaf_max_size;\n};\n\n/** Search options for KDTreeSingleIndexAdaptor::findNeighbors() */\nstruct SearchParams {\n    /** Note: The first argument (checks_IGNORED_) is ignored, but kept for compatibility with the FLANN interface */\n    SearchParams(int checks_IGNORED_ = 32, float eps_ = 0, bool sorted_ = true) : checks(checks_IGNORED_), eps(eps_), sorted(sorted_) {}\n\n    int   checks;    //!< Ignored parameter (Kept for compatibility with the FLANN interface).\n    float eps;       //!< search for eps-approximate neighbours (default: 0)\n    bool  sorted;    //!< only for radius search, require neighbours sorted by distance (default: true)\n};\n/** @} */\n\n/** @addtogroup memalloc_grp Memory allocation\n * @{ */\n\n/**\n * Allocates (using C's malloc) a generic type T.\n *\n * Params:\n *     count = number of instances to allocate.\n * Returns: pointer (of type T*) to memory buffer\n */\ntemplate<typename T> inline T *allocate(size_t count = 1)\n{\n    T *mem = static_cast<T *>(::malloc(sizeof(T) * count));\n    return mem;\n}\n\n/**\n * Pooled storage allocator\n *\n * The following routines allow for the efficient allocation of storage in\n * small chunks from a specified pool.  Rather than allowing each structure\n * to be freed individually, an entire pool of storage is freed at once.\n * This method has two advantages over just using malloc() and free().  First,\n * it is far more efficient for allocating small objects, as there is\n * no overhead for remembering all the information needed to free each\n * object or consolidating fragmented memory.  Second, the decision about\n * how long to keep an object is made at the time of allocation, and there\n * is no need to track down all the objects to free them.\n *\n */\n\nconst size_t WORDSIZE = 16;\nconst size_t BLOCKSIZE = 8192;\n\nclass PooledAllocator {\n    /* We maintain memory alignment to word boundaries by requiring that all\n            allocations be in multiples of the machine wordsize.  */\n    /* Size of machine word in bytes.  Must be power of 2. */\n    /* Minimum number of bytes requested at a time from\tthe system.  Must be multiple of WORDSIZE. */\n\n    size_t remaining; /* Number of bytes left in current block of storage. */\n    void * base;      /* Pointer to base of current block of storage. */\n    void * loc;       /* Current location in block to next allocate memory. */\n\n    void internal_init()\n    {\n        remaining = 0;\n        base = NULL;\n        usedMemory = 0;\n        wastedMemory = 0;\n    }\n\npublic:\n    size_t usedMemory;\n    size_t wastedMemory;\n\n    /**\n            Default constructor. Initializes a new pool.\n         */\n    PooledAllocator() { internal_init(); }\n\n    /**\n     * Destructor. Frees all the memory allocated in this pool.\n     */\n    ~PooledAllocator() { free_all(); }\n\n    /** Frees all allocated memory chunks */\n    void free_all()\n    {\n        while (base != NULL) {\n            void *prev = *(static_cast<void **>(base)); /* Get pointer to prev block. */\n            ::free(base);\n            base = prev;\n        }\n        internal_init();\n    }\n\n    /**\n     * Returns a pointer to a piece of new memory of the given size in bytes\n     * allocated from the pool.\n     */\n    void *malloc(const size_t req_size)\n    {\n        /* Round size up to a multiple of wordsize.  The following expression\n                only works for WORDSIZE that is a power of 2, by masking last bits of\n                incremented size to zero.\n             */\n        const size_t size = (req_size + (WORDSIZE - 1)) & ~(WORDSIZE - 1);\n\n        /* Check whether a new block must be allocated.  Note that the first word\n                of a block is reserved for a pointer to the previous block.\n             */\n        if (size > remaining) {\n            wastedMemory += remaining;\n\n            /* Allocate new storage. */\n            const size_t blocksize = (size + sizeof(void *) + (WORDSIZE - 1) > BLOCKSIZE) ? size + sizeof(void *) + (WORDSIZE - 1) : BLOCKSIZE;\n\n            // use the standard C malloc to allocate memory\n            void *m = ::malloc(blocksize);\n            if (!m) {\n                fprintf(stderr, \"Failed to allocate memory.\\n\");\n                return NULL;\n            }\n\n            /* Fill first word of new block with pointer to previous block. */\n            static_cast<void **>(m)[0] = base;\n            base = m;\n\n            size_t shift = 0;\n            // int size_t = (WORDSIZE - ( (((size_t)m) + sizeof(void*)) & (WORDSIZE-1))) & (WORDSIZE-1);\n\n            remaining = blocksize - sizeof(void *) - shift;\n            loc = (static_cast<char *>(m) + sizeof(void *) + shift);\n        }\n        void *rloc = loc;\n        loc = static_cast<char *>(loc) + size;\n        remaining -= size;\n\n        usedMemory += size;\n\n        return rloc;\n    }\n\n    /**\n     * Allocates (using this pool) a generic type T.\n     *\n     * Params:\n     *     count = number of instances to allocate.\n     * Returns: pointer (of type T*) to memory buffer\n     */\n    template<typename T> T *allocate(const size_t count = 1)\n    {\n        T *mem = static_cast<T *>(this->malloc(sizeof(T) * count));\n        return mem;\n    }\n};\n/** @} */\n\n/** @addtogroup nanoflann_metaprog_grp Auxiliary metaprogramming stuff\n * @{ */\n\n// ----------------  CArray -------------------------\n/** A STL container (as wrapper) for arrays of constant size defined at compile time (class imported from the MRPT project)\n * This code is an adapted version from Boost, modifed for its integration\n *\twithin MRPT (JLBC, Dec/2009) (Renamed array -> CArray to avoid possible potential conflicts).\n * See\n *      http://www.josuttis.com/cppcode\n * for details and the latest version.\n * See\n *      http://www.boost.org/libs/array for Documentation.\n * for documentation.\n *\n * (C) Copyright Nicolai M. Josuttis 2001.\n * Permission to copy, use, modify, sell and distribute this software\n * is granted provided this copyright notice appears in all copies.\n * This software is provided \"as is\" without express or implied\n * warranty, and with no claim as to its suitability for any purpose.\n *\n * 29 Jan 2004 - minor fixes (Nico Josuttis)\n * 04 Dec 2003 - update to synch with library TR1 (Alisdair Meredith)\n * 23 Aug 2002 - fix for Non-MSVC compilers combined with MSVC libraries.\n * 05 Aug 2001 - minor update (Nico Josuttis)\n * 20 Jan 2001 - STLport fix (Beman Dawes)\n * 29 Sep 2000 - Initial Revision (Nico Josuttis)\n *\n * Jan 30, 2004\n */\ntemplate<typename T, std::size_t N> class CArray {\npublic:\n    T elems[N];    // fixed-size array of elements of type T\n\npublic:\n    // type definitions\n    typedef T              value_type;\n    typedef T *            iterator;\n    typedef const T *      const_iterator;\n    typedef T &            reference;\n    typedef const T &      const_reference;\n    typedef std::size_t    size_type;\n    typedef std::ptrdiff_t difference_type;\n\n    // iterator support\n    inline iterator       begin() { return elems; }\n    inline const_iterator begin() const { return elems; }\n    inline iterator       end() { return elems + N; }\n    inline const_iterator end() const { return elems + N; }\n\n    // reverse iterator support\n#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)\n    typedef std::reverse_iterator<iterator>       reverse_iterator;\n    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;\n#elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310)\n    // workaround for broken reverse_iterator in VC7\n    typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, iterator, reference, iterator, reference>> reverse_iterator;\n    typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, const_iterator, const_reference, iterator, reference>> const_reverse_iterator;\n#else\n    // workaround for broken reverse_iterator implementations\n    typedef std::reverse_iterator<iterator, T>       reverse_iterator;\n    typedef std::reverse_iterator<const_iterator, T> const_reverse_iterator;\n#endif\n\n    reverse_iterator       rbegin() { return reverse_iterator(end()); }\n    const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }\n    reverse_iterator       rend() { return reverse_iterator(begin()); }\n    const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }\n    // operator[]\n    inline reference       operator[](size_type i) { return elems[i]; }\n    inline const_reference operator[](size_type i) const { return elems[i]; }\n    // at() with range check\n    reference at(size_type i)\n    {\n        rangecheck(i);\n        return elems[i];\n    }\n    const_reference at(size_type i) const\n    {\n        rangecheck(i);\n        return elems[i];\n    }\n    // front() and back()\n    reference       front() { return elems[0]; }\n    const_reference front() const { return elems[0]; }\n    reference       back() { return elems[N - 1]; }\n    const_reference back() const { return elems[N - 1]; }\n    // size is constant\n    static inline size_type size() { return N; }\n    static bool             empty() { return false; }\n    static size_type        max_size() { return N; }\n    enum { static_size = N };\n    /** This method has no effects in this class, but raises an exception if the expected size does not match */\n    inline void resize(const size_t nElements)\n    {\n        if (nElements != N) throw std::logic_error(\"Try to change the size of a CArray.\");\n    }\n    // swap (note: linear complexity in N, constant for given instantiation)\n    void swap(CArray<T, N> &y) { std::swap_ranges(begin(), end(), y.begin()); }\n    // direct access to data (read-only)\n    const T *data() const { return elems; }\n    // use array as C array (direct read/write access to data)\n    T *data() { return elems; }\n    // assignment with type conversion\n    template<typename T2> CArray<T, N> &operator=(const CArray<T2, N> &rhs)\n    {\n        std::copy(rhs.begin(), rhs.end(), begin());\n        return *this;\n    }\n    // assign one value to all elements\n    inline void assign(const T &value)\n    {\n        for (size_t i = 0; i < N; i++) elems[i] = value;\n    }\n    // assign (compatible with std::vector's one) (by JLBC for MRPT)\n    void assign(const size_t n, const T &value)\n    {\n        assert(N == n);\n        for (size_t i = 0; i < N; i++) elems[i] = value;\n    }\n\nprivate:\n    // check range (may be private because it is static)\n    static void rangecheck(size_type i)\n    {\n        if (i >= size()) { throw std::out_of_range(\"CArray<>: index out of range\"); }\n    }\n};    // end of CArray\n\n/** Used to declare fixed-size arrays when DIM>0, dynamically-allocated vectors when DIM=-1.\n * Fixed size version for a generic DIM:\n */\ntemplate<int DIM, typename T> struct array_or_vector_selector {\n    typedef CArray<T, DIM> container_t;\n};\n/** Dynamic size version */\ntemplate<typename T> struct array_or_vector_selector<-1, T> {\n    typedef std::vector<T> container_t;\n};\n\n/** @} */\n\n/** kd-tree base-class\n *\n * Contains the member functions common to the classes KDTreeSingleIndexAdaptor and KDTreeSingleIndexDynamicAdaptor_.\n *\n * \\tparam Derived The name of the class which inherits this class.\n * \\tparam DatasetAdaptor The user-provided adaptor (see comments above).\n * \\tparam Distance The distance metric to use, these are all classes derived from nanoflann::Metric\n * \\tparam DIM Dimensionality of data points (e.g. 3 for 3D points)\n * \\tparam IndexType Will be typically size_t or int\n */\n\ntemplate<class Derived, typename Distance, class DatasetAdaptor, int DIM = -1, typename IndexType = size_t> class KDTreeBaseClass {\npublic:\n    /** Frees the previously-built index. Automatically called within buildIndex(). */\n    void freeIndex(Derived &obj)\n    {\n        obj.pool.free_all();\n        obj.root_node = NULL;\n        obj.m_size_at_index_build = 0;\n    }\n\n    typedef typename Distance::ElementType  ElementType;\n    typedef typename Distance::DistanceType DistanceType;\n\n    /*--------------------- Internal Data Structures --------------------------*/\n    struct Node {\n        /** Union used because a node can be either a LEAF node or a non-leaf node, so both data fields are never used simultaneously */\n        union {\n            struct leaf {\n                IndexType left, right;    //!< Indices of points in leaf node\n            } lr;\n            struct nonleaf {\n                int          divfeat;            //!< Dimension used for subdivision.\n                DistanceType divlow, divhigh;    //!< The values used for subdivision.\n            } sub;\n        } node_type;\n        Node *child1, *child2;    //!< Child nodes (both=NULL mean its a leaf node)\n    };\n\n    typedef Node *NodePtr;\n\n    struct Interval {\n        ElementType low, high;\n    };\n\n    /**\n     *  Array of indices to vectors in the dataset.\n     */\n    std::vector<IndexType> vind;\n\n    NodePtr root_node;\n\n    size_t m_leaf_max_size;\n\n    size_t m_size;                   //!< Number of current points in the dataset\n    size_t m_size_at_index_build;    //!< Number of points in the dataset when the index was built\n    int    dim;                      //!< Dimensionality of each data point\n\n    /** Define \"BoundingBox\" as a fixed-size or variable-size container depending on \"DIM\" */\n    typedef typename array_or_vector_selector<DIM, Interval>::container_t BoundingBox;\n\n    /** Define \"distance_vector_t\" as a fixed-size or variable-size container depending on \"DIM\" */\n    typedef typename array_or_vector_selector<DIM, DistanceType>::container_t distance_vector_t;\n\n    /** The KD-tree used to find neighbours */\n\n    BoundingBox root_bbox;\n\n    /**\n     * Pooled memory allocator.\n     *\n     * Using a pooled memory allocator is more efficient\n     * than allocating memory directly when there is a large\n     * number small of memory allocations.\n     */\n    PooledAllocator pool;\n\n    /** Returns number of points in dataset  */\n    size_t size(const Derived &obj) const { return obj.m_size; }\n\n    /** Returns the length of each point in the dataset */\n    size_t veclen(const Derived &obj) { return static_cast<size_t>(DIM > 0 ? DIM : obj.dim); }\n\n    /// Helper accessor to the dataset points:\n    inline ElementType dataset_get(const Derived &obj, size_t idx, int component) const { return obj.dataset.kdtree_get_pt(idx, component); }\n\n    /**\n     * Computes the inde memory usage\n     * Returns: memory used by the index\n     */\n    size_t usedMemory(Derived &obj)\n    {\n        return obj.pool.usedMemory + obj.pool.wastedMemory + obj.dataset.kdtree_get_point_count() * sizeof(IndexType);    // pool memory and vind array memory\n    }\n\n    void computeMinMax(const Derived &obj, IndexType *ind, IndexType count, int element, ElementType &min_elem, ElementType &max_elem)\n    {\n        min_elem = dataset_get(obj, ind[0], element);\n        max_elem = dataset_get(obj, ind[0], element);\n        for (IndexType i = 1; i < count; ++i) {\n            ElementType val = dataset_get(obj, ind[i], element);\n            if (val < min_elem) min_elem = val;\n            if (val > max_elem) max_elem = val;\n        }\n    }\n\n    /**\n     * Create a tree node that subdivides the list of vecs from vind[first]\n     * to vind[last].  The routine is called recursively on each sublist.\n     *\n     * @param left index of the first vector\n     * @param right index of the last vector\n     */\n    NodePtr divideTree(Derived &obj, const IndexType left, const IndexType right, BoundingBox &bbox)\n    {\n        NodePtr node = obj.pool.template allocate<Node>();    // allocate memory\n\n        /* If too few exemplars remain, then make this a leaf node. */\n        if ((right - left) <= static_cast<IndexType>(obj.m_leaf_max_size)) {\n            node->child1 = node->child2 = NULL; /* Mark as leaf node. */\n            node->node_type.lr.left = left;\n            node->node_type.lr.right = right;\n\n            // compute bounding-box of leaf points\n            for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {\n                bbox[i].low = dataset_get(obj, obj.vind[left], i);\n                bbox[i].high = dataset_get(obj, obj.vind[left], i);\n            }\n            for (IndexType k = left + 1; k < right; ++k) {\n                for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {\n                    if (bbox[i].low > dataset_get(obj, obj.vind[k], i)) bbox[i].low = dataset_get(obj, obj.vind[k], i);\n                    if (bbox[i].high < dataset_get(obj, obj.vind[k], i)) bbox[i].high = dataset_get(obj, obj.vind[k], i);\n                }\n            }\n        } else {\n            IndexType    idx;\n            int          cutfeat;\n            DistanceType cutval;\n            middleSplit_(obj, &obj.vind[0] + left, right - left, idx, cutfeat, cutval, bbox);\n\n            node->node_type.sub.divfeat = cutfeat;\n\n            BoundingBox left_bbox(bbox);\n            left_bbox[cutfeat].high = cutval;\n            node->child1 = divideTree(obj, left, left + idx, left_bbox);\n\n            BoundingBox right_bbox(bbox);\n            right_bbox[cutfeat].low = cutval;\n            node->child2 = divideTree(obj, left + idx, right, right_bbox);\n\n            node->node_type.sub.divlow = left_bbox[cutfeat].high;\n            node->node_type.sub.divhigh = right_bbox[cutfeat].low;\n\n            for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {\n                bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);\n                bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);\n            }\n        }\n\n        return node;\n    }\n\n    void middleSplit_(Derived &obj, IndexType *ind, IndexType count, IndexType &index, int &cutfeat, DistanceType &cutval, const BoundingBox &bbox)\n    {\n        const DistanceType EPS = static_cast<DistanceType>(0.00001);\n        ElementType        max_span = bbox[0].high - bbox[0].low;\n        for (int i = 1; i < (DIM > 0 ? DIM : obj.dim); ++i) {\n            ElementType span = bbox[i].high - bbox[i].low;\n            if (span > max_span) { max_span = span; }\n        }\n        ElementType max_spread = -1;\n        cutfeat = 0;\n        for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {\n            ElementType span = bbox[i].high - bbox[i].low;\n            if (span > (1 - EPS) * max_span) {\n                ElementType min_elem, max_elem;\n                computeMinMax(obj, ind, count, i, min_elem, max_elem);\n                ElementType spread = max_elem - min_elem;\n                ;\n                if (spread > max_spread) {\n                    cutfeat = i;\n                    max_spread = spread;\n                }\n            }\n        }\n        // split in the middle\n        DistanceType split_val = (bbox[cutfeat].low + bbox[cutfeat].high) / 2;\n        ElementType  min_elem, max_elem;\n        computeMinMax(obj, ind, count, cutfeat, min_elem, max_elem);\n\n        if (split_val < min_elem)\n            cutval = min_elem;\n        else if (split_val > max_elem)\n            cutval = max_elem;\n        else\n            cutval = split_val;\n\n        IndexType lim1, lim2;\n        planeSplit(obj, ind, count, cutfeat, cutval, lim1, lim2);\n\n        if (lim1 > count / 2)\n            index = lim1;\n        else if (lim2 < count / 2)\n            index = lim2;\n        else\n            index = count / 2;\n    }\n\n    /**\n     *  Subdivide the list of points by a plane perpendicular on axe corresponding\n     *  to the 'cutfeat' dimension at 'cutval' position.\n     *\n     *  On return:\n     *  dataset[ind[0..lim1-1]][cutfeat]<cutval\n     *  dataset[ind[lim1..lim2-1]][cutfeat]==cutval\n     *  dataset[ind[lim2..count]][cutfeat]>cutval\n     */\n    void planeSplit(Derived &obj, IndexType *ind, const IndexType count, int cutfeat, DistanceType &cutval, IndexType &lim1, IndexType &lim2)\n    {\n        /* Move vector indices for left subtree to front of list. */\n        IndexType left = 0;\n        IndexType right = count - 1;\n        for (;;) {\n            while (left <= right && dataset_get(obj, ind[left], cutfeat) < cutval) ++left;\n            while (right && left <= right && dataset_get(obj, ind[right], cutfeat) >= cutval) --right;\n            if (left > right || !right) break;    // \"!right\" was added to support unsigned Index types\n            std::swap(ind[left], ind[right]);\n            ++left;\n            --right;\n        }\n        /* If either list is empty, it means that all remaining features\n         * are identical. Split in the middle to maintain a balanced tree.\n         */\n        lim1 = left;\n        right = count - 1;\n        for (;;) {\n            while (left <= right && dataset_get(obj, ind[left], cutfeat) <= cutval) ++left;\n            while (right && left <= right && dataset_get(obj, ind[right], cutfeat) > cutval) --right;\n            if (left > right || !right) break;    // \"!right\" was added to support unsigned Index types\n            std::swap(ind[left], ind[right]);\n            ++left;\n            --right;\n        }\n        lim2 = left;\n    }\n\n    DistanceType computeInitialDistances(const Derived &obj, const ElementType *vec, distance_vector_t &dists) const\n    {\n        assert(vec);\n        DistanceType distsq = DistanceType();\n\n        for (int i = 0; i < (DIM > 0 ? DIM : obj.dim); ++i) {\n            if (vec[i] < obj.root_bbox[i].low) {\n                dists[i] = obj.distance.accum_dist(vec[i], obj.root_bbox[i].low, i);\n                distsq += dists[i];\n            }\n            if (vec[i] > obj.root_bbox[i].high) {\n                dists[i] = obj.distance.accum_dist(vec[i], obj.root_bbox[i].high, i);\n                distsq += dists[i];\n            }\n        }\n        return distsq;\n    }\n\n    void save_tree(Derived &obj, FILE *stream, NodePtr tree)\n    {\n        save_value(stream, *tree);\n        if (tree->child1 != NULL) { save_tree(obj, stream, tree->child1); }\n        if (tree->child2 != NULL) { save_tree(obj, stream, tree->child2); }\n    }\n\n    void load_tree(Derived &obj, FILE *stream, NodePtr &tree)\n    {\n        tree = obj.pool.template allocate<Node>();\n        load_value(stream, *tree);\n        if (tree->child1 != NULL) { load_tree(obj, stream, tree->child1); }\n        if (tree->child2 != NULL) { load_tree(obj, stream, tree->child2); }\n    }\n\n    /**  Stores the index in a binary file.\n     *   IMPORTANT NOTE: The set of data points is NOT stored in the file, so when loading the index object it must be constructed associated to the same source of data points used while building it.\n     * See the example: examples/saveload_example.cpp\n     * \\sa loadIndex  */\n    void saveIndex_(Derived &obj, FILE *stream)\n    {\n        save_value(stream, obj.m_size);\n        save_value(stream, obj.dim);\n        save_value(stream, obj.root_bbox);\n        save_value(stream, obj.m_leaf_max_size);\n        save_value(stream, obj.vind);\n        save_tree(obj, stream, obj.root_node);\n    }\n\n    /**  Loads a previous index from a binary file.\n     *   IMPORTANT NOTE: The set of data points is NOT stored in the file, so the index object must be constructed associated to the same source of data points used while building the index.\n     * See the example: examples/saveload_example.cpp\n     * \\sa loadIndex  */\n    void loadIndex_(Derived &obj, FILE *stream)\n    {\n        load_value(stream, obj.m_size);\n        load_value(stream, obj.dim);\n        load_value(stream, obj.root_bbox);\n        load_value(stream, obj.m_leaf_max_size);\n        load_value(stream, obj.vind);\n        load_tree(obj, stream, obj.root_node);\n    }\n};\n\n/** @addtogroup kdtrees_grp KD-tree classes and adaptors\n * @{ */\n\n/** kd-tree static index\n *\n * Contains the k-d trees and other information for indexing a set of points\n * for nearest-neighbor matching.\n *\n *  The class \"DatasetAdaptor\" must provide the following interface (can be non-virtual, inlined methods):\n *\n *  \\code\n *   // Must return the number of data poins\n *   inline size_t kdtree_get_point_count() const { ... }\n *\n *\n *   // Must return the dim'th component of the idx'th point in the class:\n *   inline T kdtree_get_pt(const size_t idx, int dim) const { ... }\n *\n *   // Optional bounding-box computation: return false to default to a standard bbox computation loop.\n *   //   Return true if the BBOX was already computed by the class and returned in \"bb\" so it can be avoided to redo it again.\n *   //   Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)\n *   template <class BBOX>\n *   bool kdtree_get_bbox(BBOX &bb) const\n *   {\n *      bb[0].low = ...; bb[0].high = ...;  // 0th dimension limits\n *      bb[1].low = ...; bb[1].high = ...;  // 1st dimension limits\n *      ...\n *      return true;\n *   }\n *\n *  \\endcode\n *\n * \\tparam DatasetAdaptor The user-provided adaptor (see comments above).\n * \\tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc.\n * \\tparam DIM Dimensionality of data points (e.g. 3 for 3D points)\n * \\tparam IndexType Will be typically size_t or int\n */\ntemplate<typename Distance, class DatasetAdaptor, int DIM = -1, typename IndexType = size_t>\nclass KDTreeSingleIndexAdaptor : public KDTreeBaseClass<KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, IndexType>, Distance, DatasetAdaptor, DIM, IndexType> {\npublic:\n    /** Deleted copy constructor*/\n    KDTreeSingleIndexAdaptor(const KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, IndexType> &) = delete;\n\n    /**\n     * The dataset used by this index\n     */\n    const DatasetAdaptor &dataset;    //!< The source of our data\n\n    const KDTreeSingleIndexAdaptorParams index_params;\n\n    Distance distance;\n\n    typedef typename nanoflann::KDTreeBaseClass<nanoflann::KDTreeSingleIndexAdaptor<Distance, DatasetAdaptor, DIM, IndexType>, Distance, DatasetAdaptor, DIM, IndexType> BaseClassRef;\n\n    typedef typename BaseClassRef::ElementType  ElementType;\n    typedef typename BaseClassRef::DistanceType DistanceType;\n\n    typedef typename BaseClassRef::Node Node;\n    typedef Node *                      NodePtr;\n\n    typedef typename BaseClassRef::Interval Interval;\n    /** Define \"BoundingBox\" as a fixed-size or variable-size container depending on \"DIM\" */\n    typedef typename BaseClassRef::BoundingBox BoundingBox;\n\n    /** Define \"distance_vector_t\" as a fixed-size or variable-size container depending on \"DIM\" */\n    typedef typename BaseClassRef::distance_vector_t distance_vector_t;\n\n    /**\n     * KDTree constructor\n     *\n     * Refer to docs in README.md or online in https://github.com/jlblancoc/nanoflann\n     *\n     * The KD-Tree point dimension (the length of each point in the datase, e.g. 3 for 3D points)\n     * is determined by means of:\n     *  - The \\a DIM template parameter if >0 (highest priority)\n     *  - Otherwise, the \\a dimensionality parameter of this constructor.\n     *\n     * @param inputData Dataset with the input features\n     * @param params Basically, the maximum leaf node size\n     */\n    KDTreeSingleIndexAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams &params = KDTreeSingleIndexAdaptorParams())\n    : dataset(inputData), index_params(params), distance(inputData)\n    {\n        BaseClassRef::root_node = NULL;\n        BaseClassRef::m_size = dataset.kdtree_get_point_count();\n        BaseClassRef::m_size_at_index_build = BaseClassRef::m_size;\n        BaseClassRef::dim = dimensionality;\n        if (DIM > 0) BaseClassRef::dim = DIM;\n        BaseClassRef::m_leaf_max_size = params.leaf_max_size;\n\n        // Create a permutable array of indices to the input vectors.\n        init_vind();\n    }\n\n    /**\n     * Builds the index\n     */\n    void buildIndex()\n    {\n        BaseClassRef::m_size = dataset.kdtree_get_point_count();\n        BaseClassRef::m_size_at_index_build = BaseClassRef::m_size;\n        init_vind();\n        this->freeIndex(*this);\n        BaseClassRef::m_size_at_index_build = BaseClassRef::m_size;\n        if (BaseClassRef::m_size == 0) return;\n        computeBoundingBox(BaseClassRef::root_bbox);\n        BaseClassRef::root_node = this->divideTree(*this, 0, BaseClassRef::m_size, BaseClassRef::root_bbox);    // construct the tree\n    }\n\n    /** \\name Query methods\n     * @{ */\n\n    /**\n     * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside\n     * the result object.\n     *\n     * Params:\n     *     result = the result object in which the indices of the nearest-neighbors are stored\n     *     vec = the vector for which to search the nearest neighbors\n     *\n     * \\tparam RESULTSET Should be any ResultSet<DistanceType>\n     * \\return  True if the requested neighbors could be found.\n     * \\sa knnSearch, radiusSearch\n     */\n    template<typename RESULTSET> bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParams &searchParams) const\n    {\n        assert(vec);\n        if (this->size(*this) == 0) return false;\n        if (!BaseClassRef::root_node) throw std::runtime_error(\"[nanoflann] findNeighbors() called before building the index.\");\n        float epsError = 1 + searchParams.eps;\n\n        distance_vector_t dists;                                 // fixed or variable-sized container (depending on DIM)\n        dists.assign((DIM > 0 ? DIM : BaseClassRef::dim), 0);    // Fill it with zeros.\n        DistanceType distsq = this->computeInitialDistances(*this, vec, dists);\n        searchLevel(result, vec, BaseClassRef::root_node, distsq, dists, epsError);    // \"count_leaf\" parameter removed since was neither used nor returned to the user.\n        return result.full();\n    }\n\n    /**\n     * Find the \"num_closest\" nearest neighbors to the \\a query_point[0:dim-1]. Their indices are stored inside\n     * the result object.\n     *  \\sa radiusSearch, findNeighbors\n     * \\note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface.\n     * \\return Number `N` of valid points in the result set. Only the first `N` entries in `out_indices` and `out_distances_sq` will be valid.\n     *         Return may be less than `num_closest` only if the number of elements in the tree is less than `num_closest`.\n     */\n    size_t knnSearch(const ElementType *query_point, const size_t num_closest, IndexType *out_indices, DistanceType *out_distances_sq, const int /* nChecks_IGNORED */ = 10) const\n    {\n        nanoflann::KNNResultSet<DistanceType, IndexType> resultSet(num_closest);\n        resultSet.init(out_indices, out_distances_sq);\n        this->findNeighbors(resultSet, query_point, nanoflann::SearchParams());\n        return resultSet.size();\n    }\n\n    /**\n     * Find all the neighbors to \\a query_point[0:dim-1] within a maximum radius.\n     *  The output is given as a vector of pairs, of which the first element is a point index and the second the corresponding distance.\n     *  Previous contents of \\a IndicesDists are cleared.\n     *\n     *  If searchParams.sorted==true, the output list is sorted by ascending distances.\n     *\n     *  For a better performance, it is advisable to do a .reserve() on the vector if you have any wild guess about the number of expected matches.\n     *\n     *  \\sa knnSearch, findNeighbors, radiusSearchCustomCallback\n     * \\return The number of points within the given radius (i.e. indices.size() or dists.size() )\n     */\n    size_t radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector<std::pair<IndexType, DistanceType>> &IndicesDists, const SearchParams &searchParams) const\n    {\n        RadiusResultSet<DistanceType, IndexType> resultSet(radius, IndicesDists);\n        const size_t                             nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams);\n        if (searchParams.sorted) std::sort(IndicesDists.begin(), IndicesDists.end(), IndexDist_Sorter());\n        return nFound;\n    }\n\n    /**\n     * Just like radiusSearch() but with a custom callback class for each point found in the radius of the query.\n     * See the source of RadiusResultSet<> as a start point for your own classes.\n     * \\sa radiusSearch\n     */\n    template<class SEARCH_CALLBACK> size_t radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParams &searchParams = SearchParams()) const\n    {\n        this->findNeighbors(resultSet, query_point, searchParams);\n        return resultSet.size();\n    }\n\n    /** @} */\n\npublic:\n    /** Make sure the auxiliary list \\a vind has the same size than the current dataset, and re-generate if size has changed. */\n    void init_vind()\n    {\n        // Create a permutable array of indices to the input vectors.\n        BaseClassRef::m_size = dataset.kdtree_get_point_count();\n        if (BaseClassRef::vind.size() != BaseClassRef::m_size) BaseClassRef::vind.resize(BaseClassRef::m_size);\n        for (size_t i = 0; i < BaseClassRef::m_size; i++) BaseClassRef::vind[i] = i;\n    }\n\n    void computeBoundingBox(BoundingBox &bbox)\n    {\n        bbox.resize((DIM > 0 ? DIM : BaseClassRef::dim));\n        if (dataset.kdtree_get_bbox(bbox)) {\n            // Done! It was implemented in derived class\n        } else {\n            const size_t N = dataset.kdtree_get_point_count();\n            if (!N) throw std::runtime_error(\"[nanoflann] computeBoundingBox() called but no data points found.\");\n            for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) { bbox[i].low = bbox[i].high = this->dataset_get(*this, 0, i); }\n            for (size_t k = 1; k < N; ++k) {\n                for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) {\n                    if (this->dataset_get(*this, k, i) < bbox[i].low) bbox[i].low = this->dataset_get(*this, k, i);\n                    if (this->dataset_get(*this, k, i) > bbox[i].high) bbox[i].high = this->dataset_get(*this, k, i);\n                }\n            }\n        }\n    }\n\n    /**\n     * Performs an exact search in the tree starting from a node.\n     * \\tparam RESULTSET Should be any ResultSet<DistanceType>\n     * \\return true if the search should be continued, false if the results are sufficient\n     */\n    template<class RESULTSET> bool searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindistsq, distance_vector_t &dists, const float epsError) const\n    {\n        /* If this is a leaf node, then do check and return. */\n        if ((node->child1 == NULL) && (node->child2 == NULL)) {\n            // count_leaf += (node->lr.right-node->lr.left);  // Removed since was neither used nor returned to the user.\n            DistanceType worst_dist = result_set.worstDist();\n            for (IndexType i = node->node_type.lr.left; i < node->node_type.lr.right; ++i) {\n                const IndexType index = BaseClassRef::vind[i];    // reorder... : i;\n                DistanceType    dist = distance.evalMetric(vec, index, (DIM > 0 ? DIM : BaseClassRef::dim));\n                if (dist < worst_dist) {\n                    if (!result_set.addPoint(dist, BaseClassRef::vind[i])) {\n                        // the resultset doesn't want to receive any more points, we're done searching!\n                        return false;\n                    }\n                }\n            }\n            return true;\n        }\n\n        /* Which child branch should be taken first? */\n        int          idx = node->node_type.sub.divfeat;\n        ElementType  val = vec[idx];\n        DistanceType diff1 = val - node->node_type.sub.divlow;\n        DistanceType diff2 = val - node->node_type.sub.divhigh;\n\n        NodePtr      bestChild;\n        NodePtr      otherChild;\n        DistanceType cut_dist;\n        if ((diff1 + diff2) < 0) {\n            bestChild = node->child1;\n            otherChild = node->child2;\n            cut_dist = distance.accum_dist(val, node->node_type.sub.divhigh, idx);\n        } else {\n            bestChild = node->child2;\n            otherChild = node->child1;\n            cut_dist = distance.accum_dist(val, node->node_type.sub.divlow, idx);\n        }\n\n        /* Call recursively to search next level down. */\n        if (!searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError)) {\n            // the resultset doesn't want to receive any more points, we're done searching!\n            return false;\n        }\n\n        DistanceType dst = dists[idx];\n        mindistsq = mindistsq + cut_dist - dst;\n        dists[idx] = cut_dist;\n        if (mindistsq * epsError <= result_set.worstDist()) {\n            if (!searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError)) {\n                // the resultset doesn't want to receive any more points, we're done searching!\n                return false;\n            }\n        }\n        dists[idx] = dst;\n        return true;\n    }\n\npublic:\n    /**  Stores the index in a binary file.\n     *   IMPORTANT NOTE: The set of data points is NOT stored in the file, so when loading the index object it must be constructed associated to the same source of data points used while building it.\n     * See the example: examples/saveload_example.cpp\n     * \\sa loadIndex  */\n    void saveIndex(FILE *stream) { this->saveIndex_(*this, stream); }\n\n    /**  Loads a previous index from a binary file.\n     *   IMPORTANT NOTE: The set of data points is NOT stored in the file, so the index object must be constructed associated to the same source of data points used while building the index.\n     * See the example: examples/saveload_example.cpp\n     * \\sa loadIndex  */\n    void loadIndex(FILE *stream) { this->loadIndex_(*this, stream); }\n\n};    // class KDTree\n\n/** kd-tree dynamic index\n *\n * Contains the k-d trees and other information for indexing a set of points\n * for nearest-neighbor matching.\n *\n *  The class \"DatasetAdaptor\" must provide the following interface (can be non-virtual, inlined methods):\n *\n *  \\code\n *   // Must return the number of data poins\n *   inline size_t kdtree_get_point_count() const { ... }\n *\n *   // Must return the dim'th component of the idx'th point in the class:\n *   inline T kdtree_get_pt(const size_t idx, int dim) const { ... }\n *\n *   // Optional bounding-box computation: return false to default to a standard bbox computation loop.\n *   //   Return true if the BBOX was already computed by the class and returned in \"bb\" so it can be avoided to redo it again.\n *   //   Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)\n *   template <class BBOX>\n *   bool kdtree_get_bbox(BBOX &bb) const\n *   {\n *      bb[0].low = ...; bb[0].high = ...;  // 0th dimension limits\n *      bb[1].low = ...; bb[1].high = ...;  // 1st dimension limits\n *      ...\n *      return true;\n *   }\n *\n *  \\endcode\n *\n * \\tparam DatasetAdaptor The user-provided adaptor (see comments above).\n * \\tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc.\n * \\tparam DIM Dimensionality of data points (e.g. 3 for 3D points)\n * \\tparam IndexType Will be typically size_t or int\n */\ntemplate<typename Distance, class DatasetAdaptor, int DIM = -1, typename IndexType = size_t>\nclass KDTreeSingleIndexDynamicAdaptor_ : public KDTreeBaseClass<KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM, IndexType>, Distance, DatasetAdaptor, DIM, IndexType> {\npublic:\n    /**\n     * The dataset used by this index\n     */\n    const DatasetAdaptor &dataset;    //!< The source of our data\n\n    KDTreeSingleIndexAdaptorParams index_params;\n\n    std::vector<int> &treeIndex;\n\n    Distance distance;\n\n    typedef typename nanoflann::KDTreeBaseClass<nanoflann::KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM, IndexType>, Distance, DatasetAdaptor, DIM, IndexType> BaseClassRef;\n\n    typedef typename BaseClassRef::ElementType  ElementType;\n    typedef typename BaseClassRef::DistanceType DistanceType;\n\n    typedef typename BaseClassRef::Node Node;\n    typedef Node *                      NodePtr;\n\n    typedef typename BaseClassRef::Interval Interval;\n    /** Define \"BoundingBox\" as a fixed-size or variable-size container depending on \"DIM\" */\n    typedef typename BaseClassRef::BoundingBox BoundingBox;\n\n    /** Define \"distance_vector_t\" as a fixed-size or variable-size container depending on \"DIM\" */\n    typedef typename BaseClassRef::distance_vector_t distance_vector_t;\n\n    /**\n     * KDTree constructor\n     *\n     * Refer to docs in README.md or online in https://github.com/jlblancoc/nanoflann\n     *\n     * The KD-Tree point dimension (the length of each point in the datase, e.g. 3 for 3D points)\n     * is determined by means of:\n     *  - The \\a DIM template parameter if >0 (highest priority)\n     *  - Otherwise, the \\a dimensionality parameter of this constructor.\n     *\n     * @param inputData Dataset with the input features\n     * @param params Basically, the maximum leaf node size\n     */\n    KDTreeSingleIndexDynamicAdaptor_(const int dimensionality, const DatasetAdaptor &inputData, std::vector<int> &treeIndex_,\n                                     const KDTreeSingleIndexAdaptorParams &params = KDTreeSingleIndexAdaptorParams())\n    : dataset(inputData), index_params(params), treeIndex(treeIndex_), distance(inputData)\n    {\n        BaseClassRef::root_node = NULL;\n        BaseClassRef::m_size = 0;\n        BaseClassRef::m_size_at_index_build = 0;\n        BaseClassRef::dim = dimensionality;\n        if (DIM > 0) BaseClassRef::dim = DIM;\n        BaseClassRef::m_leaf_max_size = params.leaf_max_size;\n    }\n\n    /** Assignment operator definiton */\n    KDTreeSingleIndexDynamicAdaptor_ operator=(const KDTreeSingleIndexDynamicAdaptor_ &rhs)\n    {\n        KDTreeSingleIndexDynamicAdaptor_ tmp(rhs);\n        std::swap(BaseClassRef::vind, tmp.BaseClassRef::vind);\n        std::swap(BaseClassRef::m_leaf_max_size, tmp.BaseClassRef::m_leaf_max_size);\n        std::swap(index_params, tmp.index_params);\n        std::swap(treeIndex, tmp.treeIndex);\n        std::swap(BaseClassRef::m_size, tmp.BaseClassRef::m_size);\n        std::swap(BaseClassRef::m_size_at_index_build, tmp.BaseClassRef::m_size_at_index_build);\n        std::swap(BaseClassRef::root_node, tmp.BaseClassRef::root_node);\n        std::swap(BaseClassRef::root_bbox, tmp.BaseClassRef::root_bbox);\n        std::swap(BaseClassRef::pool, tmp.BaseClassRef::pool);\n        return *this;\n    }\n\n    /**\n     * Builds the index\n     */\n    void buildIndex()\n    {\n        BaseClassRef::m_size = BaseClassRef::vind.size();\n        this->freeIndex(*this);\n        BaseClassRef::m_size_at_index_build = BaseClassRef::m_size;\n        if (BaseClassRef::m_size == 0) return;\n        computeBoundingBox(BaseClassRef::root_bbox);\n        BaseClassRef::root_node = this->divideTree(*this, 0, BaseClassRef::m_size, BaseClassRef::root_bbox);    // construct the tree\n    }\n\n    /** \\name Query methods\n     * @{ */\n\n    /**\n     * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside\n     * the result object.\n     *\n     * Params:\n     *     result = the result object in which the indices of the nearest-neighbors are stored\n     *     vec = the vector for which to search the nearest neighbors\n     *\n     * \\tparam RESULTSET Should be any ResultSet<DistanceType>\n     * \\return  True if the requested neighbors could be found.\n     * \\sa knnSearch, radiusSearch\n     */\n    template<typename RESULTSET> bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParams &searchParams) const\n    {\n        assert(vec);\n        if (this->size(*this) == 0) return false;\n        if (!BaseClassRef::root_node) return false;\n        float epsError = 1 + searchParams.eps;\n\n        distance_vector_t dists;                                 // fixed or variable-sized container (depending on DIM)\n        dists.assign((DIM > 0 ? DIM : BaseClassRef::dim), 0);    // Fill it with zeros.\n        DistanceType distsq = this->computeInitialDistances(*this, vec, dists);\n        searchLevel(result, vec, BaseClassRef::root_node, distsq, dists, epsError);    // \"count_leaf\" parameter removed since was neither used nor returned to the user.\n        return result.full();\n    }\n\n    /**\n     * Find the \"num_closest\" nearest neighbors to the \\a query_point[0:dim-1]. Their indices are stored inside\n     * the result object.\n     *  \\sa radiusSearch, findNeighbors\n     * \\note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface.\n     * \\return Number `N` of valid points in the result set. Only the first `N` entries in `out_indices` and `out_distances_sq` will be valid.\n     *         Return may be less than `num_closest` only if the number of elements in the tree is less than `num_closest`.\n     */\n    size_t knnSearch(const ElementType *query_point, const size_t num_closest, IndexType *out_indices, DistanceType *out_distances_sq, const int /* nChecks_IGNORED */ = 10) const\n    {\n        nanoflann::KNNResultSet<DistanceType, IndexType> resultSet(num_closest);\n        resultSet.init(out_indices, out_distances_sq);\n        this->findNeighbors(resultSet, query_point, nanoflann::SearchParams());\n        return resultSet.size();\n    }\n\n    /**\n     * Find all the neighbors to \\a query_point[0:dim-1] within a maximum radius.\n     *  The output is given as a vector of pairs, of which the first element is a point index and the second the corresponding distance.\n     *  Previous contents of \\a IndicesDists are cleared.\n     *\n     *  If searchParams.sorted==true, the output list is sorted by ascending distances.\n     *\n     *  For a better performance, it is advisable to do a .reserve() on the vector if you have any wild guess about the number of expected matches.\n     *\n     *  \\sa knnSearch, findNeighbors, radiusSearchCustomCallback\n     * \\return The number of points within the given radius (i.e. indices.size() or dists.size() )\n     */\n    size_t radiusSearch(const ElementType *query_point, const DistanceType &radius, std::vector<std::pair<IndexType, DistanceType>> &IndicesDists, const SearchParams &searchParams) const\n    {\n        RadiusResultSet<DistanceType, IndexType> resultSet(radius, IndicesDists);\n        const size_t                             nFound = radiusSearchCustomCallback(query_point, resultSet, searchParams);\n        if (searchParams.sorted) std::sort(IndicesDists.begin(), IndicesDists.end(), IndexDist_Sorter());\n        return nFound;\n    }\n\n    /**\n     * Just like radiusSearch() but with a custom callback class for each point found in the radius of the query.\n     * See the source of RadiusResultSet<> as a start point for your own classes.\n     * \\sa radiusSearch\n     */\n    template<class SEARCH_CALLBACK> size_t radiusSearchCustomCallback(const ElementType *query_point, SEARCH_CALLBACK &resultSet, const SearchParams &searchParams = SearchParams()) const\n    {\n        this->findNeighbors(resultSet, query_point, searchParams);\n        return resultSet.size();\n    }\n\n    /** @} */\n\npublic:\n    void computeBoundingBox(BoundingBox &bbox)\n    {\n        bbox.resize((DIM > 0 ? DIM : BaseClassRef::dim));\n        if (dataset.kdtree_get_bbox(bbox)) {\n            // Done! It was implemented in derived class\n        } else {\n            const size_t N = BaseClassRef::m_size;\n            if (!N) throw std::runtime_error(\"[nanoflann] computeBoundingBox() called but no data points found.\");\n            for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) { bbox[i].low = bbox[i].high = this->dataset_get(*this, BaseClassRef::vind[0], i); }\n            for (size_t k = 1; k < N; ++k) {\n                for (int i = 0; i < (DIM > 0 ? DIM : BaseClassRef::dim); ++i) {\n                    if (this->dataset_get(*this, BaseClassRef::vind[k], i) < bbox[i].low) bbox[i].low = this->dataset_get(*this, BaseClassRef::vind[k], i);\n                    if (this->dataset_get(*this, BaseClassRef::vind[k], i) > bbox[i].high) bbox[i].high = this->dataset_get(*this, BaseClassRef::vind[k], i);\n                }\n            }\n        }\n    }\n\n    /**\n     * Performs an exact search in the tree starting from a node.\n     * \\tparam RESULTSET Should be any ResultSet<DistanceType>\n     */\n    template<class RESULTSET> void searchLevel(RESULTSET &result_set, const ElementType *vec, const NodePtr node, DistanceType mindistsq, distance_vector_t &dists, const float epsError) const\n    {\n        /* If this is a leaf node, then do check and return. */\n        if ((node->child1 == NULL) && (node->child2 == NULL)) {\n            // count_leaf += (node->lr.right-node->lr.left);  // Removed since was neither used nor returned to the user.\n            DistanceType worst_dist = result_set.worstDist();\n            for (IndexType i = node->node_type.lr.left; i < node->node_type.lr.right; ++i) {\n                const IndexType index = BaseClassRef::vind[i];    // reorder... : i;\n                if (treeIndex[index] == -1) continue;\n                DistanceType dist = distance.evalMetric(vec, index, (DIM > 0 ? DIM : BaseClassRef::dim));\n                if (dist < worst_dist) { result_set.addPoint(dist, BaseClassRef::vind[i]); }\n            }\n            return;\n        }\n\n        /* Which child branch should be taken first? */\n        int          idx = node->node_type.sub.divfeat;\n        ElementType  val = vec[idx];\n        DistanceType diff1 = val - node->node_type.sub.divlow;\n        DistanceType diff2 = val - node->node_type.sub.divhigh;\n\n        NodePtr      bestChild;\n        NodePtr      otherChild;\n        DistanceType cut_dist;\n        if ((diff1 + diff2) < 0) {\n            bestChild = node->child1;\n            otherChild = node->child2;\n            cut_dist = distance.accum_dist(val, node->node_type.sub.divhigh, idx);\n        } else {\n            bestChild = node->child2;\n            otherChild = node->child1;\n            cut_dist = distance.accum_dist(val, node->node_type.sub.divlow, idx);\n        }\n\n        /* Call recursively to search next level down. */\n        searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError);\n\n        DistanceType dst = dists[idx];\n        mindistsq = mindistsq + cut_dist - dst;\n        dists[idx] = cut_dist;\n        if (mindistsq * epsError <= result_set.worstDist()) { searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError); }\n        dists[idx] = dst;\n    }\n\npublic:\n    /**  Stores the index in a binary file.\n     *   IMPORTANT NOTE: The set of data points is NOT stored in the file, so when loading the index object it must be constructed associated to the same source of data points used while building it.\n     * See the example: examples/saveload_example.cpp\n     * \\sa loadIndex  */\n    void saveIndex(FILE *stream) { this->saveIndex_(*this, stream); }\n\n    /**  Loads a previous index from a binary file.\n     *   IMPORTANT NOTE: The set of data points is NOT stored in the file, so the index object must be constructed associated to the same source of data points used while building the index.\n     * See the example: examples/saveload_example.cpp\n     * \\sa loadIndex  */\n    void loadIndex(FILE *stream) { this->loadIndex_(*this, stream); }\n};\n\n/** kd-tree dynaimic index\n *\n * class to create multiple static index and merge their results to behave as single dynamic index as proposed in Logarithmic Approach.\n *\n *  Example of usage:\n *  examples/dynamic_pointcloud_example.cpp\n *\n * \\tparam DatasetAdaptor The user-provided adaptor (see comments above).\n * \\tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc.\n * \\tparam DIM Dimensionality of data points (e.g. 3 for 3D points)\n * \\tparam IndexType Will be typically size_t or int\n */\ntemplate<typename Distance, class DatasetAdaptor, int DIM = -1, typename IndexType = size_t> class KDTreeSingleIndexDynamicAdaptor {\npublic:\n    typedef typename Distance::ElementType  ElementType;\n    typedef typename Distance::DistanceType DistanceType;\n\nprotected:\n    size_t m_leaf_max_size;\n    size_t treeCount;\n    size_t pointCount;\n\n    /**\n     * The dataset used by this index\n     */\n    const DatasetAdaptor &dataset;    //!< The source of our data\n\n    std::vector<int> treeIndex;    //!< treeIndex[idx] is the index of tree in which point at idx is stored. treeIndex[idx]=-1 means that point has been removed.\n\n    KDTreeSingleIndexAdaptorParams index_params;\n\n    int dim;    //!< Dimensionality of each data point\n\n    typedef KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM> index_container_t;\n    std::vector<index_container_t>                                          index;\n\npublic:\n    /** Get a const ref to the internal list of indices; the number of indices is adapted dynamically as\n     * the dataset grows in size. */\n    const std::vector<index_container_t> &getAllIndices() const { return index; }\n\nprivate:\n    /** finds position of least significant unset bit */\n    int First0Bit(IndexType num)\n    {\n        int pos = 0;\n        while (num & 1) {\n            num = num >> 1;\n            pos++;\n        }\n        return pos;\n    }\n\n    /** Creates multiple empty trees to handle dynamic support */\n    void init()\n    {\n        typedef KDTreeSingleIndexDynamicAdaptor_<Distance, DatasetAdaptor, DIM> my_kd_tree_t;\n        std::vector<my_kd_tree_t>                                               index_(treeCount, my_kd_tree_t(dim /*dim*/, dataset, treeIndex, index_params));\n        index = index_;\n    }\n\npublic:\n    Distance distance;\n\n    /**\n     * KDTree constructor\n     *\n     * Refer to docs in README.md or online in https://github.com/jlblancoc/nanoflann\n     *\n     * The KD-Tree point dimension (the length of each point in the datase, e.g. 3 for 3D points)\n     * is determined by means of:\n     *  - The \\a DIM template parameter if >0 (highest priority)\n     *  - Otherwise, the \\a dimensionality parameter of this constructor.\n     *\n     * @param inputData Dataset with the input features\n     * @param params Basically, the maximum leaf node size\n     */\n    KDTreeSingleIndexDynamicAdaptor(const int dimensionality, const DatasetAdaptor &inputData, const KDTreeSingleIndexAdaptorParams &params = KDTreeSingleIndexAdaptorParams(),\n                                    const size_t maximumPointCount = 1000000000U)\n    : dataset(inputData), index_params(params), distance(inputData)\n    {\n        treeCount = std::log2(maximumPointCount);\n        pointCount = 0U;\n        dim = dimensionality;\n        treeIndex.clear();\n        if (DIM > 0) dim = DIM;\n        m_leaf_max_size = params.leaf_max_size;\n        init();\n        int num_initial_points = dataset.kdtree_get_point_count();\n        if (num_initial_points > 0) { addPoints(0, num_initial_points - 1); }\n    }\n\n    /** Deleted copy constructor*/\n    KDTreeSingleIndexDynamicAdaptor(const KDTreeSingleIndexDynamicAdaptor<Distance, DatasetAdaptor, DIM, IndexType> &) = delete;\n\n    /** Add points to the set, Inserts all points from [start, end] */\n    void addPoints(IndexType start, IndexType end)\n    {\n        int count = end - start + 1;\n        treeIndex.resize(treeIndex.size() + count);\n        for (IndexType idx = start; idx <= end; idx++) {\n            int pos = First0Bit(pointCount);\n            index[pos].vind.clear();\n            treeIndex[pointCount] = pos;\n            for (int i = 0; i < pos; i++) {\n                for (int j = 0; j < static_cast<int>(index[i].vind.size()); j++) {\n                    index[pos].vind.push_back(index[i].vind[j]);\n                    treeIndex[index[i].vind[j]] = pos;\n                }\n                index[i].vind.clear();\n                index[i].freeIndex(index[i]);\n            }\n            index[pos].vind.push_back(idx);\n            index[pos].buildIndex();\n            pointCount++;\n        }\n    }\n\n    /** Remove a point from the set (Lazy Deletion) */\n    void removePoint(size_t idx)\n    {\n        if (idx >= pointCount) return;\n        treeIndex[idx] = -1;\n    }\n\n    /**\n     * Find set of nearest neighbors to vec[0:dim-1]. Their indices are stored inside\n     * the result object.\n     *\n     * Params:\n     *     result = the result object in which the indices of the nearest-neighbors are stored\n     *     vec = the vector for which to search the nearest neighbors\n     *\n     * \\tparam RESULTSET Should be any ResultSet<DistanceType>\n     * \\return  True if the requested neighbors could be found.\n     * \\sa knnSearch, radiusSearch\n     */\n    template<typename RESULTSET> bool findNeighbors(RESULTSET &result, const ElementType *vec, const SearchParams &searchParams) const\n    {\n        for (size_t i = 0; i < treeCount; i++) { index[i].findNeighbors(result, &vec[0], searchParams); }\n        return result.full();\n    }\n};\n\n/** An L2-metric KD-tree adaptor for working with data directly stored in an Eigen Matrix, without duplicating the data storage.\n *  Each row in the matrix represents a point in the state space.\n *\n *  Example of usage:\n * \\code\n * \tEigen::Matrix<num_t,Dynamic,Dynamic>  mat;\n * \t// Fill out \"mat\"...\n *\n * \ttypedef KDTreeEigenMatrixAdaptor< Eigen::Matrix<num_t,Dynamic,Dynamic> >  my_kd_tree_t;\n * \tconst int max_leaf = 10;\n * \tmy_kd_tree_t   mat_index(mat, max_leaf );\n * \tmat_index.index->buildIndex();\n * \tmat_index.index->...\n * \\endcode\n *\n *  \\tparam DIM If set to >0, it specifies a compile-time fixed dimensionality for the points in the data set, allowing more compiler optimizations.\n *  \\tparam Distance The distance metric to use: nanoflann::metric_L1, nanoflann::metric_L2, nanoflann::metric_L2_Simple, etc.\n */\ntemplate<class MatrixType, class Distance = nanoflann::metric_L2> struct KDTreeEigenMatrixAdaptor {\n    typedef KDTreeEigenMatrixAdaptor<MatrixType, Distance>                                       self_t;\n    typedef typename MatrixType::Scalar                                                          num_t;\n    typedef typename MatrixType::Index                                                           IndexType;\n    typedef typename Distance::template traits<num_t, self_t>::distance_t                        metric_t;\n    typedef KDTreeSingleIndexAdaptor<metric_t, self_t, MatrixType::ColsAtCompileTime, IndexType> index_t;\n\n    index_t *index;    //! The kd-tree index for the user to call its methods as usual with any other FLANN index.\n\n    /// Constructor: takes a const ref to the matrix object with the data points\n    KDTreeEigenMatrixAdaptor(const MatrixType &mat, const int leaf_max_size = 10) : m_data_matrix(mat)\n    {\n        const IndexType dims = mat.cols();\n        index = new index_t(dims, *this /* adaptor */, nanoflann::KDTreeSingleIndexAdaptorParams(leaf_max_size));\n        index->buildIndex();\n    }\n\npublic:\n    /** Deleted copy constructor */\n    KDTreeEigenMatrixAdaptor(const self_t &) = delete;\n\n    ~KDTreeEigenMatrixAdaptor() { delete index; }\n\n    const MatrixType &m_data_matrix;\n\n    /** Query for the \\a num_closest closest points to a given point (entered as query_point[0:dim-1]).\n     *  Note that this is a short-cut method for index->findNeighbors().\n     *  The user can also call index->... methods as desired.\n     * \\note nChecks_IGNORED is ignored but kept for compatibility with the original FLANN interface.\n     */\n    inline void query(const num_t *query_point, const size_t num_closest, IndexType *out_indices, num_t *out_distances_sq, const int /* nChecks_IGNORED */ = 10) const\n    {\n        nanoflann::KNNResultSet<num_t, IndexType> resultSet(num_closest);\n        resultSet.init(out_indices, out_distances_sq);\n        index->findNeighbors(resultSet, query_point, nanoflann::SearchParams());\n    }\n\n    /** @name Interface expected by KDTreeSingleIndexAdaptor\n     * @{ */\n\n    const self_t &derived() const { return *this; }\n    self_t &      derived() { return *this; }\n\n    // Must return the number of data points\n    inline size_t kdtree_get_point_count() const { return m_data_matrix.rows(); }\n\n    // Returns the dim'th component of the idx'th point in the class:\n    inline num_t kdtree_get_pt(const IndexType idx, int dim) const { return m_data_matrix.coeff(idx, IndexType(dim)); }\n\n    // Optional bounding-box computation: return false to default to a standard bbox computation loop.\n    //   Return true if the BBOX was already computed by the class and returned in \"bb\" so it can be avoided to redo it again.\n    //   Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds)\n    template<class BBOX> bool kdtree_get_bbox(BBOX & /*bb*/) const { return false; }\n\n    /** @} */\n\n};    // end of KDTreeEigenMatrixAdaptor\n      /** @} */\n\n/** @} */    // end of grouping\n}    // namespace nanoflann\n\n#endif /* NANOFLANN_HPP_ */\n"
  },
  {
    "path": "include/vapor/ptr_cache.hpp",
    "content": "//-----------------------------------------------------------------------------\n// This is an implementation of a least-recently-used (LRU) cache that keeps\n// raw pointers pointing to big structures (e.g., grids, quadtrees).\n//\n// This cache has two execution policies:\n// 1) only insertion counts as `recently used`, and\n// 2) both insertion and query count as `recently used`.\n//\n// Given this design, this cache is expected to keep the ownership of these\n// structures once they're put in the cache, and all other codes will not\n// need to manage these structures. In other words, once an object is evicted,\n// its destructor will be called.\n//\n// All structures stored in this cache are const qualified, so once a\n// structure is put in this cache, there is no more modification to this structure.\n//\n// Caveat: A cache keeps things that it is asked to keep, which in this case are pointers.\n//         This implementation guarantees that pointers and the objects that they point to\n//         are not altered while in the cache, and are properly destroyed when evicted.\n//         The cache guarantees nothing more than that.\n//-----------------------------------------------------------------------------\n\n#ifndef PTR_CACHE_H\n#define PTR_CACHE_H\n\n#include <cstddef>    // size_t\n#include <utility>    // std::pair<>\n#include <mutex>\n#include <algorithm>\n#include <array>\n\nnamespace VAPoR {\n\n//\n// Note : 1) Key must support == operator and = operator.\n//        2) BigObj must be able to be destructed by delete.\n//\ntemplate<typename Key, typename BigObj, unsigned int Size, bool Query> class ptr_cache {\npublic:\n    //\n    // Constructors and Destructor\n    //\n    ptr_cache() = default;\n    ptr_cache(const ptr_cache &) = delete;\n    ptr_cache(const ptr_cache &&) = delete;\n    ptr_cache &operator=(const ptr_cache &) = delete;\n    ptr_cache &operator=(const ptr_cache &&) = delete;\n    ~ptr_cache()\n    {\n        for (auto &p : _element_vector) {\n            if (p.second) delete p.second;\n        }\n    }\n\n    auto size() const -> size_t { return _element_vector.size(); }\n\n    //\n    // Major action function.\n    // If the key exists, it returns the pointer associated with the key.\n    // If the key does not exist, it returns a nullptr.\n    //\n    auto query(const Key &key) -> const BigObj *\n    {\n        if (Query) {\n            // Use a guard lock if queries can change ordering.\n            const std::lock_guard<std::mutex> lock_gd(_element_vector_mutex);\n            auto                              it = std::find_if(_element_vector.begin(), _element_vector.end(), [&key](element_type &e) { return e.first == key; });\n            if (it == _element_vector.end())    // This key does not exist\n                return nullptr;\n            else {    // This key does exist\n                std::rotate(_element_vector.begin(), it, it + 1);\n                return _element_vector.front().second;\n            }\n        } else {\n            // Just query, no change whatsoever.\n            auto it = std::find_if(_element_vector.begin(), _element_vector.end(), [&key](element_type &e) { return e.first == key; });\n            if (it == _element_vector.end())    // This key does not exist\n                return nullptr;\n            else    // This key does exist\n                return it->second;\n        }\n    }\n\n    void insert(const Key &key, const BigObj *ptr)\n    {\n        const std::lock_guard<std::mutex> lock_gd(_element_vector_mutex);\n\n        auto it = std::find_if(_element_vector.begin(), _element_vector.end(), [&key](element_type &e) { return e.first == key; });\n\n        if (it == _element_vector.end()) {    // This key does not exist\n            --it;                             // `it` points to the last element now.\n            it->first = key;\n        }\n        if (it->second)    // Destroy the old object held here.\n            delete it->second;\n        it->second = ptr;\n        std::rotate(_element_vector.begin(), it, it + 1);\n    }\n\nprivate:\n    using element_type = std::pair<Key, const BigObj *>;\n\n    std::mutex                     _element_vector_mutex;\n    std::array<element_type, Size> _element_vector;\n};\n}    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "include/vapor/regionparams.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tregionparams.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tSeptember 2004\n//\n//\tDescription:\tDefines the RegionParams class.\n//\t\tThis class supports parameters associted with the\n//\t\tregion panel, describing the rendering region\n//\n#ifndef REGIONPARAMS_H\n#define REGIONPARAMS_H\n\n#include <vapor/ParamsBase.h>\n#include <vapor/Box.h>\n\nnamespace VAPoR {\n\n//! \\class RegionParams\n//! \\ingroup Public_Params\n//! \\brief A class for describing a 3D axis-aligned region in user space.\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date    February 2014\n\n//! The RegionParams class controls the extents of a 3D box of data for visualization.\n//! The DVR, Isosurface and Flow renderers use only the data specified by the current RegionParams.\n//! There is a global RegionParams, that\n//! is shared by all windows whose region is set to \"global\".  There is also\n//! a local RegionParams for each window, that users can select whenever there are multiple windows.\n//! When local settings are used, they only affect one currently active visualizer.\n//! The RegionParams class also has several methods that are useful in setting up data requests from the DataMgr.\n//!\nclass PARAMS_API RegionParams : public ParamsBase {\npublic:\n    RegionParams(ParamsBase::StateSave *ssave);\n\n    RegionParams(ParamsBase::StateSave *ssave, XmlNode *node);\n\n    RegionParams(const RegionParams &rhs);\n\n    RegionParams &operator=(const RegionParams &rhs);\n\n    virtual ~RegionParams();\n\n    ///@}\n    //! Method to obtain the current Box defining the region extents\n    //! \\retval Box* current Box.\n    virtual Box *GetBox() const { return m_Box; }\n\n    //! Get the extents extent of the Box, in local coordinates\n    //! \\param[out] double[6] extents\n    //! \\param[in] int timestep indicates the current timestep, used only with time-varying extents.\n\n#ifdef VAPOR3_0_0_ALPHA\n    void getLocalRegionExtents(double exts[6], int timestep) const\n    {\n        GetBox()->GetLocalExtents(exts, timestep);\n        return;\n    }\n\n    //! Get a center coordinate of the Box, in local coordinates\n    //! \\param[in] int coord 0,1,2 for x,y,z\n    //! \\param[in] int timestep indicates the current timestep, used only with time-varying extents.\n    //! \\retval double value of center for specified coordinate.\n    double getLocalRegionCenter(int indx, int timestep) const\n    {\n        if (indx < 0 || indx > 2) indx = 0;\n        return (0.5 * (getLocalRegionMin(indx, timestep) + getLocalRegionMax(indx, timestep)));\n    }\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Provide a vector of the times, useful for time-varying extents\n    //! \\retval const vector<long> vector of times.\n    const vector<long> GetTimes() const { return GetBox()->GetTimes(); }\n\n    //! Indicate whether or not the extents vary over time\n    //! \\retval bool return true if extents are time-varying.\n    bool extentsAreVarying() { return GetBox()->GetTimes().size() > 1; }\n\n    //! Insert a specific time in the list of time-varying extents.  Return false if it's already there\n    //! \\param[in] timestep to be inserted\n    //! \\retval true if the time was not already in the list.\n    bool insertTime(int timestep);\n\n    //! Remove a time from the time-varying timesteps.  Return false if unsuccessful\n    //! \\param[in] timestep to be removed\n    //! \\retval false if the time was not already in the list.\n    bool removeTime(int timestep);\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Provide a vector of all the extents for all times\n    //! returns 6 doubles for each time step.\n    //! \\retval const vector<double> vector of extents.\n    vector<double> GetAllExtents() const { return GetBox()->GetLocalExtents(); }\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n    //! Provide the domain-defining variables\n    //! returns a vector of variable names.\n    //! Note that this is an attribute of the global Region params\n    //! \\retval vector<string> domain-defining variables\n    static const vector<string> GetDomainVariables()\n    {\n        ((RegionParams *)_paramsMgr->GetParamsInstance(_regionParamsTag, -1, -1))->GetValueStringVec(_domainVariablesTag);\n        return vec;\n    }\n    //! set the domain-defining variables\n    //! Note that this value is stored in the global Region params\n    //! \\param [in] vector<string> names of domain-defining variables\n    //! \\retval int 0 if successful\n    static int SetDomainVariables(vector<string> varnames)\n    {\n        if (varnames.size() == 0) return -1;\n        return ((RegionParams *)_paramsMgr->GetParamsInstance(_regionParamsTag, -1, -1))->SetValueStringVec(_domainVariablesTag, \"Set Domain-defining variables\", varnames);\n    }\n#endif\n\n    // Get static string identifier for this params class\n    //\n    static string GetClassType() { return (\"RegionParams\"); }\n\nprivate:\n    Box *m_Box;\n\n    static const string _domainVariablesTag;\n\n    void _init();\n    void _reconcile();\n};\n\n};        // namespace VAPoR\n#endif    // REGIONPARAMS_H\n"
  },
  {
    "path": "include/vapor/udunits2.h",
    "content": "/*\n * Copyright 2008, 2009 University Corporation for Atmospheric Research\n *\n * This file is part of the UDUNITS-2 package.  See the file LICENSE\n * in the top-level source-directory of the package for copying and\n * redistribution conditions.\n */\n#ifndef UT_UNITS2_H_INCLUDED\n#define UT_UNITS2_H_INCLUDED\n#include \"vapor/common.h\"\n#include <stdarg.h>\n#include <stddef.h>\n\n#include \"converter.h\"\n\ntypedef struct ut_system ut_system;\ntypedef union ut_unit    ut_unit;\n\ntypedef enum {\n    UT_SUCCESS = 0,     /* Success */\n    UT_BAD_ARG,         /* An argument violates the function's contract */\n    UT_EXISTS,          /* Unit, prefix, or identifier already exists */\n    UT_NO_UNIT,         /* No such unit exists */\n    UT_OS,              /* Operating-system error.  See \"errno\". */\n    UT_NOT_SAME_SYSTEM, /* The units belong to different unit-systems */\n    UT_MEANINGLESS,     /* The operation on the unit(s) is meaningless */\n    UT_NO_SECOND,       /* The unit-system doesn't have a unit named \"second\" */\n    UT_VISIT_ERROR,     /* An error occurred while visiting a unit */\n    UT_CANT_FORMAT,     /* A unit can't be formatted in the desired manner */\n    UT_SYNTAX,          /* string unit representation contains syntax error */\n    UT_UNKNOWN,         /* string unit representation contains unknown word */\n    UT_OPEN_ARG,        /* Can't open argument-specified unit database */\n    UT_OPEN_ENV,        /* Can't open environment-specified unit database */\n    UT_OPEN_DEFAULT,    /* Can't open installed, default, unit database */\n    UT_PARSE            /* Error parsing unit specification */\n} ut_status;\n\ntypedef enum { UT_ASCII = 0, UT_ISO_8859_1 = 1, UT_LATIN1 = UT_ISO_8859_1, UT_UTF8 = 2 } ut_encoding;\n\n#define UT_NAMES      4\n#define UT_DEFINITION 8\n\n/*\n * Data-structure for a visitor to a unit:\n */\ntypedef struct {\n    /*\n     * Visits a basic-unit.  A basic-unit is a base unit like \"meter\" or a non-\n     * dimensional but named unit like \"radian\".\n     *\n     * Arguments:\n     *\tunit\t\tPointer to the basic-unit.\n     *\targ\t\tClient pointer passed to ut_accept_visitor().\n     * Returns:\n     *\tUT_SUCCESS\tSuccess.\n     *\telse\t\tFailure.\n     */\n    ut_status (*visit_basic)(const ut_unit *unit, void *arg);\n\n    /*\n     * Visits a product-unit.  A product-unit is a product of zero or more\n     * basic-units, each raised to a non-zero power.\n     *\n     * Arguments:\n     *\tunit\t\tPointer to the product-unit.\n     *\tcount\t\tThe number of basic-units in the product.  May be zero.\n     *\tbasicUnits\tPointer to an array of basic-units in the product.\n     *\tpowers\t\tPointer to an array of powers to which the respective\n     *\t\t\tbasic-units are raised.\n     *\targ\t\tClient pointer passed to ut_accept_visitor().\n     * Returns:\n     *\tUT_SUCCESS\tSuccess.\n     *\telse\t\tFailure.\n     */\n    ut_status (*visit_product)(const ut_unit *unit, int count, const ut_unit *const *basicUnits, const int *powers, void *arg);\n\n    /*\n     * Visits a Galilean-unit.  A Galilean-unit has an underlying unit and a\n     * non-unity scale factor or a non-zero offset.\n     *\n     * Arguments:\n     *\tunit\t\tPointer to the Galilean-unit.\n     *\tscale\t\tThe scale factor (e.g., 1000 for a kilometer when the\n     *\t\t\tunderlying unit is a meter).\n     *\tunderlyingUnit\tPointer to the underlying unit.\n     *\toffset\t\tPointer to the underlying unit.\n     *\targ\t\tClient pointer passed to ut_accept_visitor().\n     * Returns:\n     *\tUT_SUCCESS\tSuccess.\n     *\telse\t\tFailure.\n     */\n    ut_status (*visit_galilean)(const ut_unit *unit, double scale, const ut_unit *underlyingUnit, double offset, void *arg);\n\n    /*\n     * Visits a timestamp-unit.  A timestamp-unit has an underlying unit of time\n     * and an encoded time-origin.\n     *\n     * Arguments:\n     *\tunit\t\tPointer to the timestamp-unit.\n     *\ttimeUnit\tPointer to the underlying unit of time.\n     *  origin          Encoded origin of the timestamp-unit.\n     *\targ\t\tClient pointer passed to ut_accept_visitor().\n     * Returns:\n     *\tUT_SUCCESS\tSuccess.\n     *\telse\t\tFailure.\n     */\n    ut_status (*visit_timestamp)(const ut_unit *unit, const ut_unit *timeUnit, double origin, void *arg);\n\n    /*\n     * Visits a logarithmic-unit.  A logarithmic-unit has a logarithmic base and\n     * a unit that specifies the reference level.\n     *\n     * Arguments:\n     *\tunit\t\tPointer to the logarithmic-unit.\n     *  base            The logarithmic base (e.g., 2, M_E, 10).\n     *\treference\tPointer to the unit that specifies the reference level.\n     *\targ\t\tClient pointer passed to ut_accept_visitor().\n     * Returns:\n     *\tUT_SUCCESS\tSuccess.\n     *\telse\t\tFailure.\n     */\n    ut_status (*visit_logarithmic)(const ut_unit *unit, double base, const ut_unit *reference, void *arg);\n} ut_visitor;\n\ntypedef int (*ut_error_message_handler)(const char *fmt, va_list args);\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/******************************************************************************\n * Unit System:\n ******************************************************************************/\n\n/*\n * Returns the unit-system corresponding to an XML file.  This is the usual way\n * that a client will obtain a unit-system.\n *\n * Arguments:\n *\tpath\tThe pathname of the XML file or NULL.  If NULL, then the\n *\t\tpathname specified by the environment variable UDUNITS2_XML_PATH\n *\t\tis used if set; otherwise, the compile-time pathname of the\n *\t\tinstalled, default, unit database is used.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be\n *\t\t    UT_OPEN_ARG\t\t\"path\" is non-NULL but file couldn't be\n *\t\t\t\t\topened.  See \"errno\" for reason.\n *\t\t    UT_OPEN_ENV\t\t\"path\" is NULL and environment variable\n *\t\t\t\t\tUDUNITS2_XML_PATH is set but file\n *\t\t\t\t\tcouldn't be opened.  See \"errno\" for\n *\t\t\t\t\treason.\n *\t\t    UT_OPEN_DEFAULT\t\"path\" is NULL, environment variable\n *\t\t\t\t\tUDUNITS2_XML_PATH is unset, and the\n *\t\t\t\t\tinstalled, default, unit database\n *\t\t\t\t\tcouldn't be opened.  See \"errno\" for\n *\t\t\t\t\treason.\n *\t\t    UT_PARSE\t\tCouldn't parse unit database.\n *\t\t    UT_OS\t\tOperating-system error.  See \"errno\".\n *\telse\tPointer to the unit-system defined by \"path\".\n */\nUDUNITS2_API ut_system *ut_read_xml(const char *path);\n\n/*\n * Returns a new unit-system.  On success, the unit-system will only contain\n * the dimensionless unit one.  See \"ut_get_dimensionless_unit_one()\".\n *\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be:\n *\t\t    UT_OS\tOperating-system error.  See \"errno\".\n *\telse\tPointer to a new unit system.\n */\nUDUNITS2_API ut_system *ut_new_system(void);\n\n/*\n * Frees a unit-system.  All unit-to-identifier and identifier-to-unit mappings\n * will be removed.\n *\n * Arguments:\n *\tsystem\t\tPointer to the unit-system to be freed.  Use of \"system\"\n *\t\t\tupon return results in undefined behavior.\n */\nUDUNITS2_API void ut_free_system(ut_system *system);\n\n/*\n * Returns the unit-system to which a unit belongs.\n *\n * Arguments:\n *\tunit\tPointer to the unit in question.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be\n *\t\t    UT_BAD_ARG\t\"unit\" is NULL.\n *\telse\tPointer to the unit-system to which \"unit\" belongs.\n */\nUDUNITS2_API ut_system *ut_get_system(const ut_unit *const unit);\n\n/*\n * Returns the dimensionless-unit one of a unit-system.\n *\n * Arguments:\n *\tsystem\tPointer to the unit-system for which the dimensionless-unit one\n *\t\twill be returned.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be:\n *\t\t    UT_BAD_ARG\t\"system\" is NULL.\n *\telse\tPointer to the dimensionless-unit one associated with \"system\".\n *\t\tWhile not necessary, the pointer may be passed to ut_free()\n *\t\twhen the unit is no longer needed by the client.\n */\nUDUNITS2_API ut_unit *ut_get_dimensionless_unit_one(const ut_system *const system);\n\n/*\n * Returns the unit with a given name from a unit-system.  Name comparisons\n * are case-insensitive.\n *\n * Arguments:\n *\tsystem\tPointer to the unit-system.\n *\tname\tPointer to the name of the unit to be returned.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be\n *\t\t    UT_SUCCESS\t\t\"name\" doesn't map to a unit of\n *\t\t\t\t\t\"system\".\n *\t\t    UT_BAD_ARG\t\t\"system\" or \"name\" is NULL.\n *\telse\tPointer to the unit of the unit-system with the given name.\n *\t\tThe pointer should be passed to ut_free() when the unit is\n *\t\tno longer needed.\n */\nUDUNITS2_API ut_unit *ut_get_unit_by_name(const ut_system *const system, const char *const name);\n\n/*\n * Returns the unit with a given symbol from a unit-system.  Symbol\n * comparisons are case-sensitive.\n *\n * Arguments:\n *\tsystem\t\tPointer to the unit-system.\n *\tsymbol\t\tPointer to the symbol associated with the unit to be\n *\t\t\treturned.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be\n *\t\t    UT_SUCCESS\t\t\"symbol\" doesn't map to a unit of\n *\t\t\t\t\t\"system\".\n *\t\t    UT_BAD_ARG\t\t\"system\" or \"symbol\" is NULL.\n *\telse\tPointer to the unit in the unit-system with the given symbol.\n *\t\tThe pointer should be passed to ut_free() when the unit is no\n *\t\tlonger needed.\n */\nUDUNITS2_API ut_unit *ut_get_unit_by_symbol(const ut_system *const system, const char *const symbol);\n\n/*\n * Sets the \"second\" unit of a unit-system.  This function must be called before\n * the first call to \"ut_offset_by_time()\". ut_read_xml() calls this function if the\n * resulting unit-system contains a unit named \"second\".\n *\n * Arguments:\n *\tsecond\t\tPointer to the \"second\" unit.\n * Returns:\n *\tUT_BAD_ARG\t\"second\" is NULL.\n *\tUT_EXISTS\tThe second unit of the unit-system to which \"second\"\n *\t\t\tbelongs is set to a different unit.\n *\tUT_SUCCESS\tSuccess.\n */\nUDUNITS2_API ut_status ut_set_second(const ut_unit *const second);\n\n/******************************************************************************\n * Defining Unit Prefixes:\n ******************************************************************************/\n\n/*\n * Adds a name-prefix to a unit-system.  A name-prefix is something like \"mega\"\n * or \"milli\".  Comparisons between name-prefixes are case-insensitive.\n *\n * Arguments:\n *\tsystem\t\tPointer to the unit-system.\n *\tname\t\tPointer to the name-prefix (e.g., \"mega\").  May be freed\n *\t\t\tupon return.\n *\tvalue\t\tThe value of the prefix (e.g., 1e6).\n * Returns:\n *\tUT_SUCCESS\tSuccess.\n *\tUT_BAD_ARG\t\"system\" or \"name\" is NULL, or \"value\" is 0.\n *\tUT_EXISTS\t\"name\" already maps to a different value.\n *\tUT_OS\t\tOperating-system failure.  See \"errno\".\n */\nUDUNITS2_API ut_status ut_add_name_prefix(ut_system *const system, const char *const name, const double value);\n\n/*\n * Adds a symbol-prefix to a unit-system.  A symbol-prefix is something like\n * \"M\" or \"y\".  Comparisons between symbol-prefixes are case-sensitive.\n *\n * Arguments:\n *\tsystem\t\tPointer to the unit-system.\n *\tsymbol\t\tPointer to the symbol-prefix (e.g., \"M\").  May be freed\n *\t\t\tupon return.\n *\tvalue\t\tThe value of the prefix (e.g., 1e6).\n * Returns:\n *\tUT_SUCCESS\tSuccess.\n *\tUT_BADSYSTEM\t\"system\" or \"symbol\" is NULL.\n *\tUT_BAD_ARG\t\"value\" is 0.\n *\tUT_EXISTS\t\"symbol\" already maps to a different value.\n *\tUT_OS\t\tOperating-system failure.  See \"errno\".\n */\nUDUNITS2_API ut_status ut_add_symbol_prefix(ut_system *const system, const char *const symbol, const double value);\n\n/******************************************************************************\n * Defining and Deleting Units:\n ******************************************************************************/\n\n/*\n * Adds a base-unit to a unit-system.  Clients that use ut_read_xml() should not\n * normally need to call this function.\n *\n * Arguments:\n *\tsystem\tPointer to the unit-system to which to add the new base-unit.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be\n *\t\t    UT_BAD_ARG\t\t\"system\" or \"name\" is NULL.\n *\t\t    UT_OS\t\tOperating-system error.  See \"errno\".\n *\telse\tPointer to the new base-unit.  The pointer should be passed to\n *\t\tut_free() when the unit is no longer needed by the client (the\n *\t\tunit will remain in the unit-system).\n */\nUDUNITS2_API ut_unit *ut_new_base_unit(ut_system *const system);\n\n/*\n * Adds a dimensionless-unit to a unit-system.  In the SI system of units, the\n * derived-unit radian is a dimensionless-unit.  Clients that use ut_read_xml()\n * should not normally need to call this function.\n *\n * Arguments:\n *\tsystem\tPointer to the unit-system to which to add the new\n *\t\tdimensionless-unit.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be\n *\t\t    UT_BAD_ARG\t\t\"system\" is NULL.\n *\t\t    UT_OS\t\tOperating-system error.  See \"errno\".\n *\telse\tPointer to the new dimensionless-unit.  The pointer should be\n *\t\tpassed to ut_free() when the unit is no longer needed by the\n *\t\tclient (the unit will remain in the unit-system).\n */\nUDUNITS2_API ut_unit *ut_new_dimensionless_unit(ut_system *const system);\n\n/*\n * Returns a clone of a unit.\n *\n * Arguments:\n *\tunit\tPointer to the unit to be cloned.\n * Returns:\n *\tNULL\tFailure.  ut_get_status() will be\n *\t\t    UT_OS\tOperating-system failure.  See \"errno\".\n *\t\t    UT_BAD_ARG\t\"unit\" is NULL.\n *\telse\tPointer to the clone of \"unit\".  The pointer should be\n *\t\tpassed to ut_free() when the unit is no longer needed by the\n *\t\tclient.\n */\nUDUNITS2_API ut_unit *ut_clone(const ut_unit *unit);\n\n/*\n * Frees resources associated with a unit.  This function should be invoked on\n * all units that are no longer needed by the client.  Use of the unit upon\n * return from this function will result in undefined behavior.\n *\n * Arguments:\n *\tunit\tPointer to the unit to have its resources freed or NULL.\n */\nUDUNITS2_API void ut_free(ut_unit *const unit);\n\n/******************************************************************************\n * Mapping between Units and Names:\n ******************************************************************************/\n\n/*\n * Returns the name in a given encoding to which a unit maps.\n *\n * Arguments:\n *\tunit\t\tPointer to the unit whose name should be returned.\n *\tencoding\tThe desired encoding of the name.\n * Returns:\n *\tNULL\t\tFailure.  \"ut_get_status()\" will be\n *\t\t\t    UT_BAD_ARG\t\t\"unit\" is NULL.\n *\t\t\t    UT_SUCCESS\t\t\"unit\" doesn't map to a name in\n *\t\t\t\t\t\tin the given encoding.\n *\telse\t\tPointer to the name in the given encoding to which\n *\t\t\t\"unit\" maps.\n */\nUDUNITS2_API const char *ut_get_name(const ut_unit *const unit, const ut_encoding encoding);\n\n/*\n * Adds a mapping from a name to a unit.\n *\n * Arguments:\n *\tname\t\tPointer to the name to be mapped to \"unit\".  May be\n *\t\t\tfreed upon return.\n *      encoding        The character encoding of \"name\".\n *\tunit\t\tPointer to the unit to be mapped-to by \"name\".  May be\n *\t\t\tfreed upon return.\n * Returns:\n *\tUT_BAD_ARG\t\"name\" or \"unit\" is NULL.\n *\tUT_OS\t\tOperating-system error.  See \"errno\".\n *\tUT_EXISTS\t\"name\" already maps to a different unit.\n *\tUT_SUCCESS\tSuccess.\n */\nut_status ut_map_name_to_unit(const char *const name, const ut_encoding encoding, const ut_unit *const unit);\n\n/*\n * Removes a mapping from a name to a unit.  After this function,\n * ut_get_unit_by_name(system,name) will no longer return a unit.\n *\n * Arguments:\n *\tsystem\t\tThe unit-system to which the unit belongs.\n *\tname\t\tThe name of the unit.\n *      encoding        The character encoding of \"name\".\n * Returns:\n *\tUT_SUCCESS\tSuccess.\n *\tUT_BAD_ARG\t\"system\" or \"name\" is NULL.\n */\nUDUNITS2_API ut_status ut_unmap_name_to_unit(ut_system *system, const char *const name, const ut_encoding encoding);\n\n/*\n * Adds a mapping from a unit to a name.\n *\n * Arguments:\n *\tunit\t\tPointer to the unit to be mapped to \"name\".  May be\n *\t\t\tfreed upon return.\n *\tname\t\tPointer to the name to be mapped-to by \"unit\".  May be\n *\t\t\tfreed upon return.\n *\tencoding\tThe encoding of \"name\".\n * Returns:\n *\tUT_SUCCESS\tSuccess.\n *\tUT_BAD_ARG\t\"unit\" or \"name\" is NULL, or \"name\" is not in the\n *                      specified encoding.\n *\tUT_OS\t\tOperating-system error.  See \"errno\".\n *\tUT_EXISTS\t\"unit\" already maps to a name.\n */\nUDUNITS2_API ut_status ut_map_unit_to_name(const ut_unit *const unit, const char *const name, ut_encoding encoding);\n\n/*\n * Removes a mapping from a unit to a name.\n *\n * Arguments:\n *\tunit\t\tPointer to the unit.  May be freed upon return.\n *\tencoding\tThe encoding to be removed.  No other encodings will be\n *\t\t\tremoved.\n * Returns:\n *\tUT_BAD_ARG\t\"unit\" is NULL.\n *\tUT_SUCCESS\tSuccess.\n */\nUDUNITS2_API ut_status ut_unmap_unit_to_name(const ut_unit *const unit, ut_encoding encoding);\n\n/******************************************************************************\n * Mapping between Units and Symbols:\n ******************************************************************************/\n\n/*\n * Returns the symbol in a given encoding to which a unit maps.\n *\n * Arguments:\n *\tunit\t\tPointer to the unit whose symbol should be returned.\n *\tencoding\tThe desired encoding of the symbol.\n * Returns:\n *\tNULL\t\tFailure.  \"ut_get_status()\" will be\n *\t\t\t    UT_BAD_ARG\t\t\"unit\" is NULL.\n *\t\t\t    UT_SUCCESS\t\t\"unit\" doesn't map to a symbol\n *\t\t\t\t\t\tin the given encoding.\n *\telse\t\tPointer to the symbol in the given encoding to which\n *\t\t\t\"unit\" maps.\n */\nUDUNITS2_API const char *ut_get_symbol(const ut_unit *const unit, const ut_encoding encoding);\n\n/*\n * Adds a mapping from a symbol to a unit.\n *\n * Arguments:\n *\tsymbol\t\tPointer to the symbol to be mapped to \"unit\".  May be\n *\t\t\tfreed upon return.\n *      ut_encoding     The character encoding of \"symbol\".\n *\tunit\t\tPointer to the unit to be mapped-to by \"symbol\".  May\n *\t\t\tbe freed upon return.\n * Returns:\n *\tUT_BAD_ARG\t\"symbol\" or \"unit\" is NULL.\n *\tUT_OS\t\tOperating-system error.  See \"errno\".\n *\tUT_EXISTS\t\"symbol\" already maps to a different unit.\n *\tUT_SUCCESS\tSuccess.\n */\nUDUNITS2_API ut_status ut_map_symbol_to_unit(const char *const symbol, const ut_encoding encoding, const ut_unit *const unit);\n\n/*\n * Removes a mapping from a symbol to a unit.  After this function,\n * ut_get_unit_by_symbol(system,symbol) will no longer return a unit.\n *\n * Arguments:\n *\tsystem\t\tThe unit-system to which the unit belongs.\n *\tsymbol\t\tThe symbol of the unit.\n *      encoding        The character encoding of \"symbol\".\n * Returns:\n *\tUT_SUCCESS\tSuccess.\n *\tUT_BAD_ARG\t\"system\" or \"symbol\" is NULL.\n */\nUDUNITS2_API ut_status ut_unmap_symbol_to_unit(ut_system *system, const char *const symbol, const ut_encoding encoding);\n\n/*\n * Adds a mapping from a unit to a symbol.\n *\n * Arguments:\n *\tunit\t\tPointer to the unit to be mapped to \"symbol\".  May be\n *\t\t\tfreed upon return.\n *\tsymbol\t\tPointer to the symbol to be mapped-to by \"unit\".  May\n *\t\t\tbe freed upon return.\n *\tencoding\tThe encoding of \"symbol\".\n * Returns:\n *\tUT_SUCCESS\tSuccess.\n *\tUT_BAD_ARG\t\"unit\" or \"symbol\" is NULL.\n *\tUT_OS\t\tOperating-system error.  See \"errno\".\n *\tUT_EXISTS\t\"unit\" already maps to a symbol.\n */\nUDUNITS2_API ut_status ut_map_unit_to_symbol(const ut_unit *unit, const char *const symbol, ut_encoding encoding);\n\n/*\n * Removes a mapping from a unit to a symbol.\n *\n * Arguments:\n *\tunit\t\tPointer to the unit to be unmapped to a symbol.  May be\n *\t\t\tfreed upon return.\n *\tencoding\tThe encoding to be removed.  The mappings for \"unit\" in\n *\t\t\tother encodings will not be removed.\n * Returns:\n *\tUT_SUCCESS\tSuccess.\n *\tUT_BAD_ARG\t\"unit\" is NULL.\n */\nUDUNITS2_API ut_status ut_unmap_unit_to_symbol(const ut_unit *const unit, ut_encoding encoding);\n\n/******************************************************************************\n * Getting Information about a Unit:\n ******************************************************************************/\n\n/*\n * Indicates if a given unit is dimensionless or not.  Note that logarithmic\n * units are dimensionless by definition.\n *\n * Arguments:\n *\tunit\tPointer to the unit in question.\n * Returns:\n *\t0\t\"unit\" is dimensionfull or an error occurred.  \"ut_get_status()\"\n *\t\t will be\n *\t\t    UT_BAD_ARG\t\t\"unit\" is NULL.\n *\t\t    UT_SUCCESS\t\t\"unit\" is dimensionfull.\n *\telse\t\"unit\" is dimensionless.\n */\nUDUNITS2_API int ut_is_dimensionless(const ut_unit *const unit);\n\n/*\n * Indicates if two units belong to the same unit-system.\n *\n * Arguments:\n *\tunit1\t\tPointer to a unit.\n *\tunit2\t\tPointer to another unit.\n * Returns:\n *\t0\t\tFailure or the units belong to different unit-systems.\n *\t\t\t\"ut_get_status()\" will be\n *\t    \t\t    UT_BAD_ARG\t\t\"unit1\" or \"unit2\" is NULL.\n *\t    \t\t    UT_SUCCESS\t\tThe units belong to different\n *\t\t\t\t\t\tunit-systems.\n *\telse\t\tThe units belong to the same unit-system.\n */\nUDUNITS2_API int ut_same_system(const ut_unit *const unit1, const ut_unit *const unit2);\n\n/*\n * Compares two units.  Returns a value less than, equal to, or greater than\n * zero as the first unit is considered less than, equal to, or greater than\n * the second unit, respectively.  Units from different unit-systems never\n * compare equal.\n *\n * Arguments:\n *\tunit1\t\tPointer to a unit or NULL.\n *\tunit2\t\tPointer to another unit or NULL.\n * Returns:\n *\t<0\tThe first unit is less than the second unit.\n *\t 0\tThe first and second units are equal or both units are NULL.\n *\t>0\tThe first unit is greater than the second unit.\n */\nUDUNITS2_API int ut_compare(const ut_unit *const unit1, const ut_unit *const unit2);\n\n/*\n * Indicates if numeric values in one unit are convertible to numeric values in\n * another unit via \"ut_get_converter()\".  In making this determination,\n * dimensionless units are ignored.\n *\n * Arguments:\n *\tunit1\t\tPointer to a unit.\n *\tunit2\t\tPointer to another unit.\n * Returns:\n *\t0\t\tFailure.  \"ut_get_status()\" will be\n *\t    \t\t    UT_BAD_ARG\t\t\"unit1\" or \"unit2\" is NULL.\n *\t\t\t    UT_NOT_SAME_SYSTEM\t\"unit1\" and \"unit2\" belong to\n *\t\t\t\t\t\tdifferent unit-sytems.\n *\t\t\t    UT_SUCCESS\t\tConversion between the units is\n *\t\t\t\t\t\tnot possible (e.g., \"unit1\" is\n *\t\t\t\t\t\t\"meter\" and \"unit2\" is\n *\t\t\t\t\t\t\"kilogram\").\n *\telse\tNumeric values can be converted between the units.\n */\nUDUNITS2_API int ut_are_convertible(const ut_unit *const unit1, const ut_unit *const unit2);\n\n/*\n * Returns a converter of numeric values in one unit to numeric values in\n * another unit.  The returned converter should be passed to cv_free() when it is\n * no longer needed by the client.\n *\n * NOTE:  Leap seconds are not taken into account when converting between\n * timestamp units.\n *\n * Arguments:\n *\tfrom\t\tPointer to the unit from which to convert values.\n *\tto\t\tPointer to the unit to which to convert values.\n * Returns:\n *\tNULL\t\tFailure.  \"ut_get_status()\" will be:\n *\t\t\t    UT_BAD_ARG\t\t\"from\" or \"to\" is NULL.\n *\t\t\t    UT_NOT_SAME_SYSTEM\t\"from\" and \"to\" belong to\n *\t\t\t\t\t\tdifferent unit-systems.\n *\t\t\t    UT_MEANINGLESS\tConversion between the units is\n *\t\t\t\t\t\tnot possible.  See\n *\t\t\t\t\t\t\"ut_are_convertible()\".\n *\telse\t\tPointer to the appropriate converter.  The pointer\n *\t\t\tshould be passed to cv_free() when no longer needed by\n *\t\t\tthe client.\n */\nUDUNITS2_API cv_converter *ut_get_converter(ut_unit *const from, ut_unit *const to);\n\n/******************************************************************************\n * Arithmetic Unit Manipulation:\n ******************************************************************************/\n\n/*\n * Returns a unit equivalent to another unit scaled by a numeric factor,\n * e.g.,\n *\tconst ut_unit*\tmeter = ...\n *\tconst ut_unit*\tkilometer = ut_scale(1000, meter);\n *\n * Arguments:\n *\tfactor\t\tThe numeric scale factor.\n *\tunit\t\tPointer to the unit to be scaled.\n * Returns:\n *\tNULL\t\tFailure.  \"ut_get_status()\" will be\n *\t\t\t    UT_BAD_ARG  \t\"factor\" is 0 or \"unit\" is NULL.\n *\t\t\t    UT_OS\t\tOperating-system error.  See\n *\t\t\t\t\t\t\"errno\".\n *\telse\t\tPointer to the resulting unit.  The pointer should be\n *\t\t\tpassed to ut_free() when the unit is no longer needed by\n *\t\t\tthe client.\n */\nUDUNITS2_API ut_unit *ut_scale(const double factor, const ut_unit *const unit);\n\n/*\n * Returns a unit equivalent to another unit offset by a numeric amount,\n * e.g.,\n *\tconst ut_unit*\tkelvin = ...\n *\tconst ut_unit*\tcelsius = ut_offset(kelvin, 273.15);\n *\n * Arguments:\n *\tunit\t\tPointer to the unit to be offset.\n *\toffset\t\tThe numeric offset.\n * Returns:\n *\tNULL\t\tFailure.  \"ut_get_status()\" will be\n *\t\t\t    UT_BAD_ARG\t\t\"unit\" is NULL.\n *\t\t\t    UT_OS\t\tOperating-system error.  See\n *\t\t\t\t\t\t\"errno\".\n *\telse\t\tPointer to the resulting unit.  The pointer should be\n *\t\t\tpassed to ut_free() when the unit is no longer needed by\n *\t\t\tthe client.\n */\nUDUNITS2_API ut_unit *ut_offset(const ut_unit *const unit, const double offset);\n\n/*\n * Returns a unit equivalent to another unit relative to a particular time.\n * e.g.,\n *\tconst ut_unit*\tsecond = ...\n *\tconst ut_unit*\tsecondsSinceTheEpoch =\n *              ut_offset_by_time(second, ut_encode_time(1970, 1, 1, 0, 0, 0.0));\n *\n * Arguments:\n *\tunit\tPointer to the time-unit to be made relative to a time-origin.\n *\torigin\tThe origin as returned by ut_encode_time().\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be\n *\t\t    UT_BAD_ARG\t\t\"unit\" is NULL.\n *\t\t    UT_OS\t\tOperating-system error.  See \"errno\".\n *\t\t    UT_MEANINGLESS\tCreation of a timestamp unit based on\n *\t\t\t\t\t\"unit\" is not meaningful.\n *\t\t    UT_NO_SECOND\tThe associated unit-system doesn't\n *\t\t\t\t\tcontain a \"second\" unit.  See\n *\t\t\t\t\tut_set_second().\n *\telse\tPointer to the resulting unit.  The pointer should be passed\n *\t\tto ut_free() when the unit is no longer needed by the client.\n */\nUDUNITS2_API ut_unit *ut_offset_by_time(const ut_unit *const unit, const double origin);\n\n/*\n * Returns the result of multiplying one unit by another unit.\n *\n * Arguments:\n *\tunit1\tPointer to a unit.\n *\tunit2\tPointer to another unit.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be:\n *\t\t    UT_BAD_ARG\t\t\"unit1\" or \"unit2\" is NULL.\n *\t\t    UT_NOT_SAME_SYSTEM\t\"unit1\" and \"unit2\" belong to\n *\t\t\t\t\tdifferent unit-systems.\n *\t\t    UT_OS\t\tOperating-system error. See \"errno\".\n *\telse\tPointer to the resulting unit.  The pointer should be passed\n *\t\tto ut_free() when the unit is no longer needed by the client.\n */\nUDUNITS2_API ut_unit *ut_multiply(const ut_unit *const unit1, const ut_unit *const unit2);\n\n/*\n * Returns the inverse (i.e., reciprocal) of a unit.  This convenience function\n * is equal to \"ut_raise(unit, -1)\".\n *\n * Arguments:\n *\tunit\tPointer to the unit.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be:\n *\t\t    UT_BAD_ARG\t\t\"unit\" is NULL.\n *\t\t    UT_OS\t\tOperating-system error. See \"errno\".\n *\telse\tPointer to the resulting unit.  The pointer should be passed to\n *\t\tut_free() when the unit is no longer needed by the client.\n */\nUDUNITS2_API ut_unit *ut_invert(const ut_unit *const unit);\n\n/*\n * Returns the result of dividing one unit by another unit.  This convenience\n * function is equivalent to the following sequence:\n *     {\n *         ut_unit* inverse = ut_invert(denom);\n *         ut_multiply(numer, inverse);\n *         ut_free(inverse);\n *     }\n *\n * Arguments:\n *\tnumer\tPointer to the numerator (top, dividend) unit.\n *\tdenom\tPointer to the denominator (bottom, divisor) unit.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be:\n *\t\t    UT_BAD_ARG\t\t\"numer\" or \"denom\" is NULL.\n *\t\t    UT_NOT_SAME_SYSTEM\t\"unit1\" and \"unit2\" belong to\n *\t\t\t\t\tdifferent unit-systems.\n *\t\t    UT_OS\t\tOperating-system error. See \"errno\".\n *\telse\tPointer to the resulting unit.  The pointer should be passed to\n *\t\tut_free() when the unit is no longer needed by the client.\n */\nUDUNITS2_API ut_unit *ut_divide(const ut_unit *const numer, const ut_unit *const denom);\n\n/*\n * Returns the result of raising a unit to a power.\n *\n * Arguments:\n *\tunit\tPointer to the unit.\n *\tpower\tThe power by which to raise \"unit\".  Must be greater than or\n *\t\tequal to -255 and less than or equal to 255.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be:\n *\t\t    UT_BAD_ARG\t\t\"unit\" is NULL or \"power\" is invalid.\n *\t\t    UT_OS\t\tOperating-system error. See \"errno\".\n *\telse\tPointer to the resulting unit.  The pointer should be passed to\n *\t\tut_free() when the unit is no longer needed by the client.\n */\nUDUNITS2_API ut_unit *ut_raise(const ut_unit *const unit, const int power);\n\n/*\n * Returns the result of taking the root of a unit.\n *\n * Arguments:\n *\tunit\tPointer to the unit.\n *\troot\tThe root to take of \"unit\".  Must be greater than or\n *\t\tequal to 1 and less than or equal to 255.\n * Returns:\n *\tNULL\tFailure.  \"ut_get_status()\" will be:\n *\t\t    UT_BAD_ARG\t\t\"unit\" is NULL, or \"root\" is invalid.\n *\t\t                        In particular, all powers of base units\n *\t\t                        in \"unit\" must be integral multiples of\n *\t\t                        \"root\".\n *\t\t    UT_OS\t\tOperating-system error. See \"errno\".\n *\telse\tPointer to the resulting unit.  The pointer should be passed to\n *\t\tut_free() when the unit is no longer needed by the client.\n */\nUDUNITS2_API ut_unit *ut_root(const ut_unit *const unit, const int root);\n\n/*\n * Returns the logarithmic unit corresponding to a logarithmic base and a\n * reference level.  For example, the following creates a decibel unit with a\n * one milliwatt reference level:\n *\n *     const ut_unit* watt = ...;\n *     const ut_unit* milliWatt = ut_scale(0.001, watt);\n *\n *     if (milliWatt != NULL) {\n *         const ut_unit* bel_1_mW = ut_log(10.0, milliWatt);\n *\n *         if (bel_1_mW != NULL) {\n *             const ut_unit* decibel_1_mW = ut_scale(0.1, bel_1_mW);\n *\n *             if (decibel_1_mW != NULL) {\n *                 ...\n *                 ut_free(decibel_1_mW);\n *             }\t\t\t// \"decibel_1_mW\" allocated\n *\n *             ut_free(bel_1_mW);\n *         }\t\t\t\t// \"bel_1_mW\" allocated\n *\n *         ut_free(milliWatt);\n *     }\t\t\t\t// \"milliWatt\" allocated\n *\n * Arguments:\n *\tbase\t\tThe logarithmic base (e.g., 2, M_E, 10).  Must be\n *                      greater than one.  \"M_E\" is defined in <math.h>.\n *\treference\tPointer to the reference value as a unit.\n * Returns:\n *\tNULL\t\tFailure.  \"ut_get_status()\" will be:\n *\t\t\t    UT_BAD_ARG\t        \"base\" is invalid or \"reference\"\n *                                              is NULL.\n *\t\t\t    UT_OS\t\tOperating-system error. See\n *\t\t\t\t\t\t\"errno\".\n *\telse\t\tPointer to the resulting unit.  The pointer should be\n *\t\t\tpassed to ut_free() when the unit is no longer needed by\n *\t\t\tthe client.\n */\nUDUNITS2_API ut_unit *ut_log(const double base, const ut_unit *const reference);\n\n/******************************************************************************\n * Parsing and Formatting Units:\n ******************************************************************************/\n\n/*\n * Returns the binary representation of a unit corresponding to a string\n * representation.\n *\n * Arguments:\n *\tsystem\t\tPointer to the unit-system in which the parsing will\n *\t\t\toccur.\n *\tstring\t\tThe string to be parsed (e.g., \"millimeters\").  There\n *\t\t\tshould be no leading or trailing whitespace in the\n *\t\t\tstring.  See ut_trim().\n *\tencoding\tThe encoding of \"string\".\n * Returns:\n *\tNULL\t\tFailure.  \"ut_get_status()\" will be one of\n *\t\t\t    UT_BAD_ARG\t\t\"system\" or \"string\" is NULL.\n *\t\t\t    UT_SYNTAX\t\t\"string\" contained a syntax\n *\t\t\t\t\t\terror.\n *\t\t\t    UT_UNKNOWN\t\t\"string\" contained an unknown\n *\t\t\t\t\t\tidentifier.\n *\t\t\t    UT_OS\t\tOperating-system failure.  See\n *\t\t\t\t\t\t\"errno\".\n *\telse\t\tPointer to the unit corresponding to \"string\".\n */\nUDUNITS2_API ut_unit *ut_parse(const ut_system *const system, const char *const string, const ut_encoding encoding);\n\n/*\n * Removes leading and trailing whitespace from a string.\n *\n * Arguments:\n *\tstring\t\tNUL-terminated string.  Will be modified if it contains\n *                      whitespace..\n *\tencoding\tThe character-encoding of \"string\".\n * Returns:\n *      \"string\", with all leading and trailing whitespace removed.\n */\nUDUNITS2_API char *ut_trim(char *const string, const ut_encoding encoding);\n\n/*\n * Formats a unit.\n *\n * Arguments:\n *\tunit\t\tPointer to the unit to be formatted.\n *\tbuf\t\tPointer to the buffer into which to format \"unit\".\n *\tsize\t\tSize of the buffer in bytes.\n *\topts\t\tFormatting options: bitwise-OR of zero or more of the\n *\t\t\tfollowing:\n *\t\t\t    UT_NAMES\t\tUse unit names instead of\n *\t\t\t\t\t\tsymbols\n *                          UT_DEFINITION       The formatted string should be\n *                                              the definition of \"unit\" in\n *                                              terms of basic-units instead of\n *\t\t\t\t\t\tstopping any expansion at the\n *\t\t\t\t\t\thighest level possible.\n *\t\t\t    UT_ASCII\t\tThe string should be formatted\n *\t\t\t\t\t\tusing the ASCII character set\n *\t\t\t\t\t\t(default).\n *\t\t\t    UT_LATIN1\t\tThe string should be formatted\n *\t\t\t\t\t\tusing the ISO Latin-1 (alias\n *\t\t\t\t\t\tISO-8859-1) character set.\n *\t\t\t    UT_UTF8\t\tThe string should be formatted\n *\t\t\t\t\t\tusing the UTF-8 character set.\n *\t\t\tUT_LATIN1 and UT_UTF8 are mutually exclusive: they may\n *\t\t\tnot both be specified.\n * Returns:\n *\t-1\t\tFailure:  \"ut_get_status()\" will be\n *\t\t\t    UT_BAD_ARG\t\t\"unit\" or \"buf\" is NULL, or both\n *                                              UT_LATIN1 and UT_UTF8 specified.\n *\t\t\t    UT_CANT_FORMAT\t\"unit\" can't be formatted in\n *\t\t\t\t\t\tthe desired manner.\n *      else\t\tSuccess.  Number of characters printed in \"buf\".  If\n *\t\t\tthe number is equal to the size of the buffer, then the\n *\t\t\tbuffer is too small to have a terminating NUL character.\n */\nUDUNITS2_API int ut_format(const ut_unit *const unit, char *buf, size_t size, unsigned opts);\n\n/*\n * Accepts a visitor to a unit.\n *\n * Arguments:\n *\tunit\t\tPointer to the unit to accept the visitor.\n *\tvisitor\t\tPointer to the visitor of \"unit\".\n *\targ\t\tAn arbitrary pointer that will be passed to \"visitor\".\n * Returns:\n *\tUT_BAD_ARG\t\"unit\" or \"visitor\" is NULL.\n *\tUT_VISIT_ERROR\tA error occurred in \"visitor\" while visiting \"unit\".\n *\tUT_SUCCESS\tSuccess.\n */\nUDUNITS2_API ut_status ut_accept_visitor(const ut_unit *const unit, const ut_visitor *const visitor, void *const arg);\n\n/******************************************************************************\n * Time Handling:\n ******************************************************************************/\n\n/*\n * Encodes a date as a double-precision value.\n *\n * Arguments:\n *\tyear\t\tThe year.\n *\tmonth\t\tThe month.\n *\tday\t\tThe day (1 = the first of the month).\n * Returns:\n *\tThe date encoded as a scalar value.\n */\nUDUNITS2_API double ut_encode_date(int year, int month, int day);\n\n/*\n * Encodes a time as a double-precision value.\n *\n * Arguments:\n *\thours\t\tThe number of hours (0 = midnight).\n *\tminutes\t\tThe number of minutes.\n *\tseconds\t\tThe number of seconds.\n * Returns:\n *\tThe clock-time encoded as a scalar value.\n */\nUDUNITS2_API double ut_encode_clock(int hours, int minutes, double seconds);\n\n/*\n * Encodes a time as a double-precision value.  The convenience function is\n * equivalent to \"ut_encode_date(year,month,day) +\n * ut_encode_clock(hour,minute,second)\"\n *\n * Arguments:\n *\tyear\tThe year.\n *\tmonth\tThe month.\n *\tday\tThe day.\n *\thour\tThe hour.\n *\tminute\tThe minute.\n *\tsecond\tThe second.\n * Returns:\n *\tThe time encoded as a scalar value.\n */\nUDUNITS2_API double ut_encode_time(const int year, const int month, const int day, const int hour, const int minute, const double second);\n\n/*\n * Decodes a time from a double-precision value.\n *\n * Arguments:\n *      value           The value to be decoded.\n *      year            Pointer to the variable to be set to the year.\n *      month           Pointer to the variable to be set to the month.\n *      day             Pointer to the variable to be set to the day.\n *      hour            Pointer to the variable to be set to the hour.\n *      minute          Pointer to the variable to be set to the minute.\n *      second          Pointer to the variable to be set to the second.\n *      resolution      Pointer to the variable to be set to the resolution\n *                      of the decoded time in seconds.\n */\nUDUNITS2_API void ut_decode_time(double value, int *year, int *month, int *day, int *hour, int *minute, double *second, double *resolution);\n\n/******************************************************************************\n * Error Handling:\n ******************************************************************************/\n\n/*\n * Returns the status of the last operation by the units module.  This function\n * will not change the status.\n */\nUDUNITS2_API ut_status ut_get_status(void);\n\n/*\n * Sets the status of the units module.  This function would not normally be\n * called by the user unless they were doing their own parsing or formatting.\n *\n * Arguments:\n *\tstatus\tThe status of the units module.\n */\nUDUNITS2_API void ut_set_status(ut_status status);\n\n/*\n * Handles an error-message.\n *\n * Arguments:\n *\tfmt\tThe format for the error-message.\n *\t...\tThe arguments for \"fmt\".\n * Returns:\n *\t<0\tAn output error was encountered.\n *\telse\tThe number of bytes of \"fmt\" and \"arg\" written excluding any\n *\t\tterminating NUL.\n */\nUDUNITS2_API int ut_handle_error_message(const char *const fmt, ...);\n\n/*\n * Returns the previously-installed error-message handler and optionally\n * installs a new handler.  The initial handler is \"ut_write_to_stderr()\".\n *\n * Arguments:\n *      handler\t\tNULL or pointer to the error-message handler.  If NULL,\n *\t\t\tthen the handler is not changed.  The\n *\t\t\tcurrently-installed handler can be obtained this way.\n * Returns:\n *\tPointer to the previously-installed error-message handler.\n */\nUDUNITS2_API ut_error_message_handler ut_set_error_message_handler(ut_error_message_handler handler);\n\n/*\n * Writes an error-message to the standard-error stream when received and\n * appends a newline.  This is the initial error-message handler.\n *\n * Arguments:\n *\tfmt\tThe format for the error-message.\n *\targs\tThe arguments of \"fmt\".\n * Returns:\n *\t<0\tA output error was encountered.  See \"errno\".\n *\telse\tThe number of bytes of \"fmt\" and \"arg\" written excluding any\n *\t\tterminating NUL.\n */\nUDUNITS2_API int ut_write_to_stderr(const char *const fmt, va_list args);\n\n/*\n * Does nothing with an error-message.\n *\n * Arguments:\n *\tfmt\tThe format for the error-message.\n *\targs\tThe arguments of \"fmt\".\n * Returns:\n *\t0\tAlways.\n */\nUDUNITS2_API int ut_ignore(const char *const fmt, va_list args);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "include/vapor/utils.h",
    "content": "\n#include <cstring>\n#include <vector>\n#include <limits>\n#include <vapor/common.h>\n\n#pragma once\n\nnamespace Wasp {\n\nclass COMMON_API SmartBuf {\npublic:\n    SmartBuf()\n    {\n        _buf = NULL;\n        _buf_sz = 0;\n    };\n\n    SmartBuf(size_t size)\n    {\n        _buf = new unsigned char[size];\n        _buf_sz = size;\n    };\n\n    SmartBuf(const SmartBuf &rhs)\n    {\n        _buf = new unsigned char[rhs._buf_sz];\n        _buf_sz = rhs._buf_sz;\n        memcpy(_buf, rhs._buf, rhs._buf_sz);\n    }\n\n    SmartBuf &operator=(const SmartBuf &rhs)\n    {\n        _buf = new unsigned char[rhs._buf_sz];\n        _buf_sz = rhs._buf_sz;\n        memcpy(_buf, rhs._buf, rhs._buf_sz);\n        return *this;\n    }\n\n    ~SmartBuf()\n    {\n        if (_buf) delete[] _buf;\n    };\n    void * Alloc(size_t size);\n    void * GetBuf() const { return (_buf); }\n    size_t GetBufSize() const { return (_buf_sz); }\n\nprivate:\n    unsigned char *_buf;\n    size_t         _buf_sz;\n};\n\n//! Linearize multi-dimensional coordinates\n//!\n//! Convert multi-dimensional coordinates, \\p coords, for a space\n//! with dimensions, \\p dims, to a linear offset from the origin\n//! of dims\n//!\n//! \\param[in] coords A vector of integer coordinates into a an\n//! array with dimensions given by \\p dims. The minimum coordinate value is\n//! zero. The maximum coordinate value is \\p dims[i] - 1.\n//! \\param[in] dims A vector defining the dimensions of an array. The size\n//! of \\p dims must equal size of \\p coords.\n//!\n//! \\retval offset The offset from the first element of the array to the\n//! address specified by \\p coords\n//\nCOMMON_API size_t LinearizeCoords(const size_t *coords, const size_t *dims, size_t n);\nCOMMON_API size_t LinearizeCoords(const std::vector<size_t> &coords, const std::vector<size_t> &dims);\n\n//! Linearize multi-dimensional coordinates\n//!\n//! Convert multi-dimensional coordinates, \\p coords, for a space\n//! with minimum and maximum coordinates given by \\p min, and \\p max,\n//! respectively.\n//!\n//! \\param[in] coords A vector of integer coordinates into a an\n//! array with boundaries defined by \\p min and \\p max. The minimum\n//! coordinate value is \\p min[i] and the maximum is \\p max[i].\n//! \\param[in] min Minimum valid coordinate value\n//! \\param[in] min Maximum valid coordinate value\n//!\n//! \\retval offset The offset from the first element of the array to the\n//! address specified by \\p coords\nCOMMON_API size_t LinearizeCoords(const size_t *coords, const size_t *min, const size_t *max, size_t n);\nCOMMON_API size_t LinearizeCoords(const std::vector<size_t> &coords, const std::vector<size_t> &min, const std::vector<size_t> &max);\n\n//! Increment a coordinate vector by one\n//!\n//! Increments \\p counter along the dimension \\p dim by one within the\n//! range of \\p min\n//! to \\p max. Overflow is possible, resulting in wraparound and setting\n//! \\p counter back to \\p min\n//\nCOMMON_API void IncrementCoords(const size_t *min, const size_t *max, size_t *counter, size_t n, int dim);\nCOMMON_API std::vector<size_t> IncrementCoords(const std::vector<size_t> &min, const std::vector<size_t> &max, std::vector<size_t> counter, int dim = 0);\n\n//! Return the dimesions of a subregion\n//!\n//! return the dimensions of a subregion enclosed by \\p min and \\p max\n//\nCOMMON_API std::vector<size_t> Dims(const std::vector<size_t> &min, const std::vector<size_t> &max);\n\n//! Return the scalar product of the elements of a vector\n//!\nCOMMON_API size_t VProduct(const size_t *a, size_t n);\nCOMMON_API size_t VProduct(const std::vector<size_t> &a);\n\n//! Vectorize a coordinate offset. Inverse of VectorizeLinearize\n//!\nCOMMON_API void VectorizeCoords(size_t offset, const size_t *min, const size_t *max, size_t *coords, size_t n);\nCOMMON_API std::vector<size_t> VectorizeCoords(size_t offset, const std::vector<size_t> &min, const std::vector<size_t> &max);\n\n//! Vectorize a coordinate offset. Inverse of VectorizeLinearize\n//!\nCOMMON_API void VectorizeCoords(size_t offset, const size_t *dims, size_t *coords, size_t n);\nCOMMON_API std::vector<size_t> VectorizeCoords(size_t offset, const std::vector<size_t> &dims);\n\n//\n// blocked submatrix Transpose suitable for multithreading\n//   *a : pointer to input matrix\n//   *b : pointer to output matrix\n//    p1,p2: starting index of submatrix (row,col)\n//    m1,m2: size of submatrix (row,col)\n//    s1,s2: size of entire matrix (row,col)\n//\nCOMMON_API void Transpose(const float *a, float *b, size_t p1, size_t m1, size_t s1, size_t p2, size_t m2, size_t s2);\n\n//\n// blocked matrix Transpose single threaded\n//   *a : pointer to input matrix\n//   *b : pointer to output matrix\n//    s1,s2: size of entire matrix (row,col)\n//\nCOMMON_API void Transpose(const float *a, float *b, size_t s1, size_t s2);\n\n// Perform a binary search in a sorted (increasing or decreasing) 1D\n// vector of values for the\n// intervale that contains 'x'. Return the offset 'i' of start of the\n// interval containing 'x' in 'sorted'.\n//\nCOMMON_API bool BinarySearchRange(const std::vector<double> &sorted, double x, size_t &i);\n\n//! Floating point comparison for near equality.\n//!\n//! Perform a floating point comparison to see if two values are nearly equal;\n//!\n//! For values close to zero the comparison is made directly againt\n//! \\p abs_th.\n//!\n//! For values not close to zero the comparison is made against \\p epsilon\n//! multiplied by the magnitude of \\p a + \\p b.\n//!\n//! See https://stackoverflow.com/questions/4915462/how-should-i-do-floating-point-comparison\n//\n//\nCOMMON_API bool NearlyEqual(float a, float b, float epsilon = std::numeric_limits<float>::epsilon(), float abs_th = std::numeric_limits<float>::epsilon());\n\n};    // namespace Wasp\n"
  },
  {
    "path": "include/vapor/vizutil.h",
    "content": "#ifndef _vizutil_h_\n#define _vizutil_h_\n\nnamespace VAPoR {\n\n//! Decompose a hexahedron into 5 tetrahedra\n//!\n//! This function takes as input the indecies of eight vertices defining\n//! a hexahedron, and decomposes the hexahedron into a sequence of 5\n//! tetrahedra. The ordering of the vertices in the input vector\n//! \\p hexahedron must follow the diagram below.\n//!\n//! Two possible decompositions are possible, case 1 and case 2.\n//!\n//! Case 1 results in 5 tetraheda comprised of the following indecies:\n//!\n//! 0,1,5,3; 0,5,6,3; 0,5,4,6; 0,3,6,2; 5,6,3,7;\n//!\n//! Case 2 results in 5 tetraheda comprised of the following indecies:\n//!\n//! 1,5,4,7; 1,4,2,7; 1,4,0,2; 1,7,2,3; 4,2,7,6\n//!\n//! Case 1 tetraheda are generated if the parity of the 0-vertex is\n//! even, case 2 if odd.\n//!\n//! Conformant meshes are possible when case 1 and case 2 are adjacent. I.e.\n//! if the input hexahedra are part of a conformant mesh face-adjacent\n//! hexahedra should have alternating 0-vertex parities.\n//!\n//!\n//!       6*--------*7\n//!       /|       /|\n//!      / |      / |\n//!     /  |     /  |\n//!    /  4*----/---*5\n//!  2*--------*3  /\n//!   |  /     |  /\n//!   | /      | /\n//!   |/       |/\n//!  0*--------*1\n//!\n//!\n//! \\param[in] hexahedron A eight-element array containing the unique vertex\n//! indecies of a hexahedron.\n//! \\param[out] tets A twenty-element array containing the resulting\n//! vertex indecies of the 5 tetrahedra that the hexahedron  is decomposed\n//! into.\n//\nvoid HexahedronToTets(const int hexahedron[8], int tets[5 * 4]);\n\n//! Decompose a quadrilateral into 2 triangles\n//!\n//! This function takes as input the indecies of four vertices defining\n//! a quadrilateral, and decomposes the quad into a sequence of 2\n//! triangles. The ordering of the vertices in the input vector\n//! \\p hexahedron must follow the diagram below.\n//!\n//!  2*--------*3\n//!   |        |\n//!   |        |\n//!   |        |\n//!  0*--------*1\n//!\n//! The decomposition results in 2 triangles comprised of the\n//! following indecies:\n//!\n//! 0,1,3; 0,3,2\n//!\n//!\n//! \\param[in] quad A four-element array containing the unique vertex\n//! indecies of a quadrilateral.\n//! \\param[out] tets A six-element array containing the resulting\n//! vertex indecies of the 2 triangles that the quadrilateral  is decomposed\n//! into.\n//\nvoid QuadToTris(const int quad[4], int tris[2 * 3]);\n\n//! Return the signed, double-area of a 2D triangle\n//!\n//! This function uses determinants to calculate double the signed area of a\n//! triange with 2D coordinates. Equivalently, this is the 3x3 determinant\n//! of a matrix whose last row is all ones.  The return value is positive\n//! if the vertices are given in counter-clockwise order, otherwise it\n//! is negtive. Thus the true area is 1/2 * |A|, where A is the returned\n//! value.\n//!\n//! \\param[in] a 2D coordinates of first vertex\n//! \\param[in] b 2D coordinates of second vertex\n//! \\param[in] c 2D coordinates of third vertex\n//!\ndouble SignedTriArea2D(const double a[2], const double b[2], const double c[2]);\n\n//! Compute the Barycentric coordinates for a point inside a 2D triangle\n//!\n//! \\param[in] verts an 6-element array of 2D triagle Cartesian coordinates,\n//! ordered x1, y1, x2, y2, x3, y3.\n//! \\param[in] pt the 2D Cartesian coordinates\n//! \\param[out] Barycentric coordinates for point \\pt.\n//!\n//! \\retval inside a flag indicating whether the point \\p pt\n//! is inside (or on the edge) of the triangle. I.e. all of the\n//! Barycentric coordinates\n//! are positive.\nbool BarycentricCoordsTri(const double verts[], const double pt[], double lambda[]);\n\n//! Compute the Wachspress coordinates for a point inside an irregular,\n//! convex, n-sided, planar polygon.\n//!\n//! This function uses a method adapted from Meyer2005 (Generalized\n//! Barycentric Coordinates on Irregular Polygons) to compute Wachspress\n//! (generalized barycentric) coordinates for a point relative to an\n//! n-sided, 2D, irregular  polygon. Wachspress coordinates for a point, p,\n//! inside a polygon, Q, have the properties that:\n//!\n//! The sum of the Wachspress coordinates is exactly 1.0\n//!\n//! The Cartesian coordinates of p are given by the sum of the products of\n//! Q's vertices with the Wachspress coordinates.\n//!\n//! If p is outside of Q at lease one of the Wachspress is negative\n//!\n//! \\param[in] verts an array of 2D polygon Cartesian coordinates\n//! describing a possibly irregular, convex polygon.\n//! \\param[in] pt the 2D Cartesian coordinates\n//! \\param[in] n The number of vertices in \\p verts. I.e. degree of polygon\n//! \\param[out] Wachspress coordinates for point \\pt. The number of\n//! Wachspress coordinates is given by \\p n.\n//!\n//! \\retval inside a flag indicating whether the point \\p pt\n//! is inside (or on the edge) of Q. I.e. all of the Wachspress coordinates\n//! are positive.\n//\nbool WachspressCoords2D(const double verts[], const double pt[], int n, double lambda[]);\n\n//! Test whether a point is inside (or on edge) of a convex polygon\n//!\n//! This function returns true of the point \\p pt is on an edge or in the\n//! interior of the 2D polygon defined by the ordered list of vertices\n//! \\p verts. It is the callers responsibility to ensure that the\n//! polygon is convex, otherwise results are undefined\n//\n//! \\param[in] verts an array of 2D polygon Cartesian coordinates\n//! describing a convex polygon.\n//! \\param[in] pt the 2D Cartesian coordinates\n//! \\param[in] n The number of vertices in \\p verts. I.e. degree of polygon\n//\nbool InsideConvexPolygon(const double verts[], const double pt[], int n);\n\n};    // namespace VAPoR\n\n#endif\n"
  },
  {
    "path": "lib/CMakeLists.txt",
    "content": "add_subdirectory (common)\nadd_subdirectory (wasp)\nexport (TARGETS common wasp NAMESPACE VAPOR:: FILE vapor-exports.cmake)\n\nif (BUILD_VDC OR BUILD_GUI)\n\tadd_subdirectory (vdc)\n\texport (TARGETS vdc NAMESPACE VAPOR:: APPEND FILE vapor-exports.cmake)\nendif()\n\n\nif (BUILD_GUI OR BUILD_PYTHON)\n    add_subdirectory(osgl)\n\tadd_subdirectory (params)\n    add_subdirectory( flow )\n\tadd_subdirectory (render)\n    if (NOT WIN32)\n        add_subdirectory (vapi)\n        export (TARGETS vapi NAMESPACE VAPOR:: APPEND FILE vapor-exports.cmake)\n    endif()\n    export (TARGETS render params flow osgl NAMESPACE VAPOR:: APPEND FILE vapor-exports.cmake)\nendif()\n\n"
  },
  {
    "path": "lib/common/Base16StringStream.cpp",
    "content": "#include <vapor/Base16StringStream.h>\n\nstd::streambuf::int_type Base16StreamBuf::overflow(std::streambuf::int_type c)\n{\n    if (c != EOF) {\n        _string += \"0123456789ABCDEF\"[(c & 0xF0) >> 4];\n        _string += \"0123456789ABCDEF\"[c & 0x0F];\n    }\n    return c;\n}\n\nvoid Base16DecoderStream::Base16Decode(const std::string &in, char *out)\n{\n    const char map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15};\n    for (int i = 0; i < in.size(); i += 2) { out[i / 2] = (map[in[i] - 48] << 4) | (map[in[i + 1] - 48]); }\n}\n\nBase16DecoderStream::Base16DecoderStream(const std::string &s) : std::istream(&_buf), _data(new char[s.size() / 2]), _buf(_data.get(), s.size() / 2) { Base16Decode(s, _data.get()); }\n"
  },
  {
    "path": "lib/common/CFuncs.cpp",
    "content": "#include <cstdarg>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <cerrno>\n#include <stack>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <vapor/MyBase.h>\n#include <vapor/CFuncs.h>\n#include <vapor/FileUtils.h>\n\n#ifdef Darwin\n    #include <mach/mach_time.h>\n#endif\n\n#include <iostream>\n#include <fstream>\n\n#ifdef WIN32\n    #include \"windows.h\"\n    #include \"Winbase.h\"\n    #pragma warning(disable : 4996)\n#endif\n\nnamespace {\n\n#ifdef WIN32\nstring Separator = \"\\\\\";\n#else\nstring Separator = \"/\";\n#endif\n\n};    // namespace\n\nusing namespace Wasp;\nusing namespace std;\n\nvoid Wasp::Splitpath(string path, string &volume, string &dir, string &file, bool nofile)\n{\n    volume.clear();\n    dir.clear();\n    file.clear();\n\n#ifdef WIN32\n    char drive_buf[_MAX_DRIVE];\n    char dir_buf[_MAX_DIR];\n    char fname_buf[_MAX_FNAME];\n    char ext_buf[_MAX_EXT];\n    _splitpath(path.c_str(), drive_buf, dir_buf, fname_buf, ext_buf);\n\n    volume = drive_buf;\n    dir = dir_buf;\n    file = fname_buf;\n    file += ext_buf;\n#else\n\n    if (nofile || (path.substr(path.size() - 1, 1) == \"/\") || (path.substr(path.size() - 2, 2) == \"/.\") || (path.substr(path.size() - 3, 3) == \"/..\")) {\n        dir = path;\n    } else {\n        dir = Wasp::FileUtils::Dirname(path);\n        file = Wasp::FileUtils::Basename(path);\n    }\n#endif\n}\n\n/*\nbool Wasp::IsAbsPath(string path) {\n\n    string vol, dir, fname;\n    Splitpath(path, vol, dir, fname, true);\n\n    return(dir.substr(0,1) == Separator);\n}\n */\n\ndouble Wasp::GetTime()\n{\n    double t = -1.0;\n#ifdef WIN32    // Windows does not have a nanosecond time function...\n    SYSTEMTIME sTime;\n    FILETIME   fTime;\n    GetSystemTime(&sTime);\n    SystemTimeToFileTime(&sTime, &fTime);\n    // Resulting system time is in 100ns increments\n    __int64 longlongtime = fTime.dwHighDateTime;\n    longlongtime <<= 32;\n    longlongtime += fTime.dwLowDateTime;\n    t = (double)longlongtime;\n    t *= 1.e-7;\n\n#endif\n#ifndef WIN32\n    struct timespec ts;\n    ts.tv_sec = ts.tv_nsec = 0;\n#endif\n\n#if defined(__linux__) || defined(AIX)\n    clock_gettime(CLOCK_REALTIME, &ts);\n    t = (double)ts.tv_sec + (double)ts.tv_nsec * 1.0e-9;\n#endif\n\n#ifdef Darwin\n    uint64_t                  tmac = mach_absolute_time();\n    mach_timebase_info_data_t info = {0, 0};\n    mach_timebase_info(&info);\n    ts.tv_sec = tmac * 1e-9;\n    ts.tv_nsec = tmac - (ts.tv_sec * 1e9);\n    t = (double)ts.tv_sec + (double)ts.tv_nsec * 1.0e-9;\n#endif\n\n    return (t);\n}\n\nint Wasp::MkDirHier(const string &dir) { return FileUtils::MakeDir(dir); }\n\nstd::string Wasp::GetEnvironmentalVariable(const std::string &name)\n{\n    const char *env = getenv(name.c_str());\n    if (env)\n        return string(env);\n    else\n        return \"\";\n}\n"
  },
  {
    "path": "lib/common/CMakeConfig.cpp.in",
    "content": "#include \"vapor/CMakeConfig.h\"\n\nconst int MAJOR = @VERSION_MAJOR@;\nconst int MINOR = @VERSION_MINOR@;\nconst int MICRO = @VERSION_MICRO@;\n\nconst CMakeConfigStringType VERSION_RC          = \"@VERSION_RC@\";\nconst CMakeConfigStringType VERSION_DATE        = \"@VERSION_DATE@\";\nconst CMakeConfigStringType VERSION_COMMIT      = \"@VERSION_COMMIT@\";\nconst CMakeConfigStringType VERSION_STRING      = \"@VERSION_STRING@\";\nconst CMakeConfigStringType VERSION_STRING_FULL = \"@VERSION_STRING_FULL@\";\n\nconst CMakeConfigStringType BUILD_TYPE          = \"@CMAKE_BUILD_TYPE@\";\nconst CMakeConfigStringType SOURCE_DIR          = \"@PROJECT_SOURCE_DIR@\";\nconst CMakeConfigStringType THIRD_PARTY_DIR     = \"@THIRD_PARTY_DIR@\";\n\nconst CMakeConfigStringType PYTHON_VERSION      = \"@Python_VERSION@\";\nconst CMakeConfigStringType PYTHON_DIR          = \"@PYTHONDIR@\";\nconst CMakeConfigStringType PYTHON_PATH         = \"@PYTHONPATH@\";\n"
  },
  {
    "path": "lib/common/CMakeLists.txt",
    "content": "configure_file (CMakeConfig.cpp.in CMakeConfig.cpp)\nset (SRC\n\tcommon.cpp\n\tMyBase.cpp\n\tOptionParser.cpp\n\tEasyThreads.cpp\n\tCFuncs.cpp\n\tVersion.cpp\n\tPVTime.cpp\n\tGetAppPath.cpp\n\tutils.cpp\n\tFileUtils.cpp\n\tResourcePath.cpp\n\tLegacyVectorMath.cpp\n\tSTLUtils.cpp\n\tVAssert.cpp\n\tProgress.cpp\n\tTMSUtils.cpp\n    Base16StringStream.cpp\n\t${CMAKE_CURRENT_BINARY_DIR}/CMakeConfig.cpp\n)\n\nset (HEADERS\n\t${PROJECT_SOURCE_DIR}/include/vapor/common.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/MyBase.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/OptionParser.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/EasyThreads.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/CFuncs.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Version.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/PVTime.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GetAppPath.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/utils.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/CMakeConfig.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/debug.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/FileUtils.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/ResourcePath.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/LegacyVectorMath.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/STLUtils.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/NonCopyableMixin.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VAssert.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Progress.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/TMSUtils.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Base16StringStream.h\n)\n\nadd_library (common SHARED ${SRC} ${HEADERS})\n\nif (APPLE)\n\tfind_library (COREFOUNDATION CoreFoundation)\n\ttarget_link_libraries (common ${COREFOUNDATION})\nendif()\n\nif (CONDA_BUILD AND UNIX AND NOT APPLE)\n    target_link_libraries (common rt)\nendif()\n\nif (NOT WIN32)\n\ttarget_link_libraries (common pthread ${HDF5_LIB})\n\tadd_definitions (-DENABLE_THREADS)\nendif()\n\nadd_definitions (-DCOMMON_EXPORTS)\n\n# This is necessary because we include external header files in our headers\ntarget_include_directories (common\n\tPUBLIC \"${PROJECT_SOURCE_DIR}/include\"\n\tPUBLIC \"${THIRD_PARTY_INC_DIR}\"\n\tPUBLIC \"${THIRD_PARTY_INC_DIR}/freetype2\"\n\t)\n\ninstall (\n\tTARGETS common\n\tDESTINATION ${INSTALL_LIB_DIR}\n\tCOMPONENT Libraries\n\t)\n\ninstall (\n\tFILES ${HEADERS}\n\tDESTINATION ${INSTALL_INCLUDE_DIR}\n\tCOMPONENT Libraries\n\t)\n\n# Not needed since vapor shares include directory\n# target_include_directories (common PUBLIC ${VAPOR_SOURCE_DIR}/include)\n"
  },
  {
    "path": "lib/common/EasyThreads.cpp",
    "content": "#include <sstream>\r\n#include <cstdlib>\r\n#include <cerrno>\r\n#include <cstring>\r\n#include <iostream>\r\n#ifndef WIN32\r\n    #include <unistd.h>\r\n#endif\r\n#include <vapor/EasyThreads.h>\r\n//#include <vapor/MyBase.h>\r\n\r\nusing namespace Wasp;\r\n\r\n#ifdef ENABLE_THREADS\r\n    #ifdef WIN32\r\n\r\ntypedef void *(*tfuncp)(void *);\r\nDWORD WINAPI runner(void *arg)\r\n{\r\n    void **info = (void **)arg;\r\n    tfuncp func = (tfuncp)info[0];\r\n    // if(info[1]) info[1] = *((void**)info[1]);\r\n    HANDLE *mutices = (HANDLE *)info[2];\r\n    int     nthreads = (int)info[3];\r\n    // lock one of the notifier mutices\r\n    for (int i = 0; i < nthreads; i++) {\r\n        if (WaitForSingleObject(mutices[i], 0) == 0) break;\r\n        if (i == nthreads - 1) printf(\"EasyThreads: Failed to lock block mutex!\");\r\n    }\r\n    // run the function\r\n    func(info[1]);\r\n    delete[] arg;\r\n    for (int i = 0; i < nthreads; i++) {\r\n        if (ReleaseMutex(mutices[i]) == TRUE) break;\r\n    }\r\n    return 0;\r\n}\r\n\r\n    #endif\r\n#endif\r\n\r\nEasyThreads::EasyThreads(int nthreads)\r\n{\r\n#ifndef WIN32\r\n    nthreads_c = 0;\r\n    threads_c = NULL;\r\n    block_c = 0;\r\n    count_c = 0;\r\n#else\r\n    nthreads_c = 0;\r\n    threads_c = NULL;\r\n    initialized_c = false;\r\n    nblocked_c = 0;\r\n    mutices_c = NULL;\r\n    bMutices_c = NULL;\r\n    mutex_c = NULL;\r\n    bMutex_c = NULL;\r\n#endif\r\n\r\n#ifdef ENABLE_THREADS\r\n    if (nthreads < 1) nthreads = NProc();\r\n    if (char *s = getenv(\"VAPOR_NTHREADS\")) {\r\n        istringstream ist(s);\r\n        ist >> nthreads;\r\n        cout << \"VAPOR_NTHREADS = \" << nthreads << endl;\r\n    }\r\n    #ifndef WIN32\r\n    int rc;\r\n    threads_c = NULL;\r\n    block_c = 0;\r\n    count_c = 0;\r\n    nthreads_c = nthreads;\r\n\r\n    rc = pthread_attr_init(&attr_c);\r\n    if (rc < 0) {\r\n        SetErrMsg(\"pthread_attr_init() : %s\", strerror(errno));\r\n        return;\r\n    }\r\n\r\n    rc = pthread_cond_init(&cond_c, NULL);\r\n    if (rc < 0) {\r\n        SetErrMsg(\"pthread_cond_init() : %s\", strerror(errno));\r\n        return;\r\n    }\r\n\r\n    rc = pthread_mutex_init(&barrier_lock_c, NULL);\r\n    if (rc < 0) {\r\n        SetErrMsg(\"pthread_mutex_init() : %s\", strerror(errno));\r\n        return;\r\n    }\r\n\r\n    rc = pthread_mutex_init(&mutex_lock_c, NULL);\r\n    if (rc < 0) {\r\n        SetErrMsg(\"pthread_mutex_init() : %s\", strerror(errno));\r\n        return;\r\n    }\r\n\r\n    pthread_attr_setdetachstate(&attr_c, PTHREAD_CREATE_JOINABLE);\r\n    if (rc < 0) {\r\n        SetErrMsg(\"pthread_attr_setdetachstate() : %s\", strerror(errno));\r\n        return;\r\n    }\r\n\r\n        #ifdef __sgi\r\n    rc = pthread_attr_setscope(&attr_c, PTHREAD_SCOPE_BOUND_NP);\r\n        #else\r\n    rc = pthread_attr_setscope(&attr_c, PTHREAD_SCOPE_SYSTEM);\r\n        #endif\r\n    if (rc < 0) {\r\n        SetErrMsg(\"pthread_attr_setscope() : %s\", strerror(errno));\r\n        return;\r\n    }\r\n\r\n    threads_c = new pthread_t[nthreads_c];\r\n\r\n    #else    // WIN32\r\n\r\n    // make sure we know if initialization failed.\r\n    initialized_c = false;\r\n    // initialize basic fields\r\n    nthreads_c = nthreads;\r\n    nblocked_c = 0;\r\n    // initialize threads and mutices\r\n    threads_c = new HANDLE[nthreads_c];\r\n    mutices_c = new HANDLE[nthreads_c];\r\n    bMutices_c = new HANDLE[nthreads_c];\r\n    for (int i = 0; i < nthreads_c; i++) {\r\n        // Set up each mutex. If it's NULL, exit without setting initialized\r\n        if ((mutices_c[i] = CreateMutex(NULL, FALSE, NULL)) == NULL) {\r\n            SetErrMsg(\"EasyThreads: Failed to initialize mutices (notifier)!\\n\");\r\n            return;\r\n        }\r\n    }\r\n    for (int i = 0; i < nthreads_c; i++) {\r\n        // Set up each mutex. If it's NULL, exit without setting initialized\r\n        if ((bMutices_c[i] = CreateMutex(NULL, FALSE, NULL)) == NULL) {\r\n            SetErrMsg(\"EasyThreads: Failed to initialize mutices (blocker)!\\n\");\r\n            return;\r\n        }\r\n    }\r\n    if ((mutex_c = CreateMutex(NULL, FALSE, \"main_mutex\")) == NULL) {\r\n        SetErrMsg(\"EasyThreads: Failed to initialize mutices (main)!\\n\");\r\n        return;\r\n    }\r\n    if ((bMutex_c = CreateMutex(NULL, FALSE, \"barrier_mutex\")) == NULL) {\r\n        SetErrMsg(\"EasyThreads: Failed to initialize mutices (barrier)!\\n\");\r\n        return;\r\n    }\r\n    // initialization succeeded!\r\n    initialized_c = true;\r\n\r\n    #endif    // OS-switch\r\n\r\n#endif    // ENABLE_THREADS\r\n}\r\n\r\nEasyThreads::~EasyThreads()\r\n{\r\n#ifdef ENABLE_THREADS\r\n\r\n    #ifndef WIN32    // Mac, Linux\r\n\r\n    pthread_attr_destroy(&attr_c);\r\n    if (threads_c) delete[] threads_c;\r\n    threads_c = NULL;\r\n\r\n    #else    // Windows\r\n\r\n    // close any mutices\r\n    for (int i = 0; i < nthreads_c && mutices_c[i] != NULL; i++) { CloseHandle(mutices_c[i]); }\r\n    for (int i = 0; i < nthreads_c && bMutices_c[i] != NULL; i++) { CloseHandle(bMutices_c[i]); }\r\n    if (mutex_c != NULL) CloseHandle(mutex_c);\r\n    if (bMutex_c != NULL) CloseHandle(bMutex_c);\r\n    // deallocate arrays\r\n    delete[] threads_c;\r\n    delete[] bMutices_c;\r\n    delete[] mutices_c;\r\n\r\n    #endif    // OS-switch\r\n\r\n#endif    // ENABLE_THREADS\r\n}\r\n\r\nint EasyThreads::ParRun(void *(*start)(void *), void **arg)\r\n{\r\n    vector<void *> argvec;\r\n    for (int i = 0; i < nthreads_c; i++) argvec.push_back(arg[i]);\r\n\r\n    return (EasyThreads::ParRun(start, argvec));\r\n}\r\n\r\nint EasyThreads::ParRun(void *(*start)(void *), std::vector<void *> argvec)\r\n{\r\n#ifdef ENABLE_THREADS\r\n\r\n    #ifndef WIN32\r\n    int i;\r\n    int rc;\r\n    int status = 0;\r\n\r\n    for (i = 0; i < nthreads_c; i++) {\r\n        rc = pthread_create(&threads_c[i], &attr_c, start, argvec[i]);\r\n        if (rc < 0) {\r\n            SetErrMsg(\"pthread_create() : %s\", strerror(errno));\r\n            return (-1);\r\n        }\r\n    }\r\n\r\n    for (i = 0; i < nthreads_c; i++) {\r\n        rc = pthread_join(threads_c[i], NULL);\r\n        if (rc < 0) {\r\n            SetErrMsg(\"pthread_join() : %s\", strerror(errno));\r\n            status = rc;\r\n        }\r\n    }\r\n    return (status);\r\n\r\n    #else    // WIN32\r\n\r\n    if (!initialized_c) return -1;\r\n    for (int i = 0; i < nthreads_c; i++) {\r\n        // parse the arguments into a package for the runner\r\n        void **info = new void *[4];    // TODO: Move to stack\r\n        info[0] = (void *)start;\r\n        info[1] = argvec[i];\r\n        info[2] = (void *)mutices_c;\r\n        info[3] = (void *)nthreads_c;\r\n        // launch the runners\r\n        if ((threads_c[i] = CreateThread(NULL, 0, runner, (void *)info, 0, NULL)) == NULL) {\r\n            // if any of them fail, close all of them and return an error code.\r\n            for (; i >= 0; i--) {\r\n                if (TerminateThread(threads_c[i], 0) == FALSE) { printf(\"EasyThreads: Failed to terminate thread after some failed to start!\\n\"); }\r\n            }\r\n            delete[] info;\r\n            SetErrMsg(\"EasyThreads: Failed to start threads.\\n\");\r\n            return -1;\r\n        }\r\n    }\r\n\r\n    // wait for the threads to finish, and then return success\r\n    WaitForMultipleObjects(nthreads_c, threads_c, TRUE, INFINITE);\r\n\r\n    return 0;\r\n\r\n    #endif\r\n\r\n#else\r\n    return 0;\r\n#endif\r\n}\r\n\r\nint EasyThreads::Barrier()\r\n{\r\n#ifdef ENABLE_THREADS\r\n\r\n    #ifndef WIN32\r\n\r\n    int local;\r\n    int rc;\r\n\r\n    if (nthreads_c > 1) {\r\n        rc = pthread_mutex_lock(&barrier_lock_c);\r\n        if (rc < 0) {\r\n            SetErrMsg(\"pthread_mutex_lock() : %s\", strerror(errno));\r\n            return (-1);\r\n        }\r\n        local = count_c;\r\n        block_c++;\r\n        if (block_c == nthreads_c) {\r\n            block_c = 0;\r\n            count_c++;\r\n            rc = pthread_cond_broadcast(&cond_c);\r\n            if (rc < 0) {\r\n                SetErrMsg(\"pthread_cond_broadcast() : %s\", strerror(errno));\r\n                return (-1);\r\n            }\r\n        }\r\n        while (local == count_c) {\r\n            rc = pthread_cond_wait(&cond_c, &barrier_lock_c);\r\n            if (rc < 0) {\r\n                SetErrMsg(\"pthread_cond_wait() : %s\", strerror(errno));\r\n                return (-1);\r\n            }\r\n        }\r\n        rc = pthread_mutex_unlock(&barrier_lock_c);\r\n        if (rc < 0) {\r\n            SetErrMsg(\"pthread_mutex_unlock() : %s\", strerror(errno));\r\n            return (-1);\r\n        }\r\n    }\r\n\r\n    #else    // WIN32\r\n    // In the windows implementation, the first thread to arrive locks all of the barrier mutices, then lets the other threads in.\r\n    // The other threads then release their notifier mutices to notify the first thread that they've arrived.\r\n    // Once the first thread owns all the notifier mutices, it releases the blocker and notifier mutices, and the other threads now each own a blocker mutex.\r\n    // When the other threads own a blocker mutex, they release it and relock their notifier mutices.\r\n    int status = 0;\r\n    if (!initialized_c) return -1;\r\n    if (nthreads_c == 1) return 0;\r\n    if (WaitForSingleObject(bMutex_c, INFINITE) != 0) { printf(\"EasyThreads: Failed to lock barrier mutex!\\n\"); }\r\n    nblocked_c++;\r\n    // printf(\"NUM: %d\\n\", nblocked_c);\r\n    // if we arrived first, set up the wait sequence for the others.\r\n    if (nblocked_c == 1) {\r\n        // printf(\"First thread has arrived at barrier.\\n\");\r\n        if (WaitForMultipleObjects(nthreads_c, bMutices_c, TRUE, 0) != 0) {\r\n            printf(\"EasyThreads: Failed to lock blocker mutices in barrier (early)!\\n\");\r\n            status |= 1;\r\n        }\r\n        // printf(\"First thread has locked the blocker mutices.\\n\");\r\n        if (ReleaseMutex(bMutex_c) == 0) {\r\n            printf(\"EasyThreads: Failed to release barrier function mutex (early)!\\n\");\r\n            status |= 2;\r\n        }\r\n        // printf(\"First thread has released the barrier function mutex.\\n\");\r\n        if (WaitForMultipleObjects(nthreads_c, mutices_c, TRUE, INFINITE) != 0) {\r\n            printf(\"EasyThreads: Failed to lock notifier mutices in barrier (early)!\\n\");\r\n            status |= 4;\r\n        }\r\n        // printf(\"First thread has locked the notifier mutices.\\n\");\r\n        for (int i = 0; i < nthreads_c; i++) {\r\n            if (ReleaseMutex(mutices_c[i]) == 0) {\r\n                printf(\"EasyThreads: Failed to release notifier mutices in barrier (early)!\\n\");\r\n                status |= 8;\r\n            }\r\n        }\r\n        // printf(\"First thread has unlocked the notifier mutices.\\n\");\r\n        for (int i = 0; i < nthreads_c; i++) {\r\n            if (ReleaseMutex(bMutices_c[i]) == 0) {\r\n                printf(\"EasyThreads: Failed to release blocker mutices in barrier (early)!\\n\");\r\n                status |= 16;\r\n            }\r\n        }\r\n        // printf(\"First thread has unlocked the blocker mutices.\\n\");\r\n    } else {\r\n        int n;\r\n        for (n = 0; n < nthreads_c; n++) {\r\n            if (ReleaseMutex(mutices_c[n]) != 0) break;\r\n            if (n == nthreads_c - 1) {\r\n                printf(\"EasyThreads: Failed to release notifier mutex (late)!\\n\");\r\n                status |= 32;\r\n            }\r\n        }\r\n        // printf(\"Thread %d has released its notifier mutex.\\n\", n);\r\n        if (ReleaseMutex(bMutex_c) == 0) {\r\n            printf(\"EasyThreads: Failed to release barrier function mutex (late)!\\n\");\r\n            status |= 64;\r\n        }\r\n        // printf(\"Thread %d has released the barrier function mutex.\\n\", n);\r\n        if (WaitForSingleObject(bMutices_c[n], INFINITE) != 0) {\r\n            printf(\"EasyThreads: Failed to lock blocker mutex in barrier (late)!\\n\");\r\n            status |= 128;\r\n        }\r\n        // printf(\"Thread %d has locked its blocker mutex.\\n\", n);\r\n        if (ReleaseMutex(bMutices_c[n]) == 0) {\r\n            printf(\"EasyThreads: Failed to release blocker mutex in barrier (late)!\\n\");\r\n            status |= 256;\r\n        }\r\n        // printf(\"Thread %d has released its blocker mutex.\\n\", n);\r\n        if (WaitForSingleObject(mutices_c[n], 0) != 0) {\r\n            printf(\"EasyThreads: Unable to re-lock notifier mutex (late)!\\n\");\r\n            status |= 512;\r\n        }\r\n        // printf(\"Thread %d has locked its notifier mutex.\\n\", n);\r\n    }\r\n    nblocked_c--;\r\n    return -status;\r\n\r\n    #endif\r\n\r\n#endif    // ENABLE_THREADS\r\n    return (0);\r\n}\r\n\r\nint EasyThreads::MutexLock()\r\n{\r\n#ifdef ENABLE_THREADS\r\n\r\n    #ifndef WIN32\r\n\r\n    if (nthreads_c > 1) {\r\n        int rc = pthread_mutex_lock(&mutex_lock_c);\r\n        if (rc < 0) {\r\n            SetErrMsg(\"pthread_mutex_lock() : %s\", strerror(errno));\r\n            return (-1);\r\n        }\r\n    }\r\n\r\n    #else    // WIN32\r\n\r\n    if (!initialized_c) return -1;\r\n    int result = WaitForSingleObject(mutex_c, INFINITE);\r\n    return result != 0 ? -1 : 0;\r\n\r\n    #endif\r\n\r\n#endif\r\n    return (0);\r\n}\r\n\r\nint EasyThreads::MutexUnlock()\r\n{\r\n#ifdef ENABLE_THREADS\r\n\r\n    #ifndef WIN32\r\n\r\n    if (nthreads_c > 1) {\r\n        int rc = pthread_mutex_unlock(&mutex_lock_c);\r\n        if (rc < 0) {\r\n            SetErrMsg(\"pthread_mutex_unlock() : %s\", strerror(errno));\r\n            return (-1);\r\n        }\r\n    }\r\n\r\n    #else\r\n\r\n    if (!initialized_c) return -1;\r\n    return (int)ReleaseMutex(mutex_c) - 1;\r\n\r\n    #endif\r\n\r\n#endif\r\n    return (0);\r\n}\r\n\r\nvoid EasyThreads::Decompose(int n, int size, int rank, int *offset, int *length)\r\n{\r\n    int remainder = n % size;\r\n    int chunk = n / size;\r\n\r\n    if (rank < remainder) {\r\n        *length = chunk + 1;\r\n        *offset = (chunk + 1) * rank;\r\n    } else {\r\n        *length = chunk;\r\n        *offset = (chunk + 1) * remainder + (rank - remainder) * chunk;\r\n    }\r\n}\r\nint EasyThreads::NProc()\r\n{\r\n#ifdef ENABLE_THREADS\r\n\r\n    #ifndef WIN32\r\n\r\n        #ifdef __sgi\r\n    return (sysconf(_SC_NPROC_ONLN));\r\n        #else\r\n    return (sysconf(_SC_NPROCESSORS_ONLN));\r\n        #endif\r\n\r\n    #else    // WIN32\r\n\r\n    SYSTEM_INFO info;\r\n    GetSystemInfo(&info);\r\n    return info.dwNumberOfProcessors;\r\n\r\n    #endif\r\n\r\n#else\r\n    return 1;\r\n#endif    // ENABLE_THREADS\r\n}\r\n"
  },
  {
    "path": "lib/common/FileUtils.cpp",
    "content": "#include \"vapor/FileUtils.h\"\n#include \"vapor/STLUtils.h\"\n#include <string.h>\n#include <algorithm>\n#include <sys/stat.h>\n#include <vapor/MyBase.h>\n\n#ifdef WIN32\n    #include <Windows.h>\n    #include <direct.h>\n#else\n    #include <libgen.h>\n    #include <pwd.h>\n    #include <unistd.h>\n    #include <dirent.h>\n#endif\n\nusing namespace Wasp;\nusing FileUtils::FileType;\nusing std::string;\n\n#ifdef WIN32\nconst string FileUtils::Separator = \"\\\\\";\n#else\nconst string FileUtils::Separator = \"/\";\n#endif\n\nstring FileUtils::ReadFileToString(const string &path)\n{\n    FILE *f = fopen(path.c_str(), \"r\");\n    if (f) {\n        fseek(f, 0, SEEK_END);\n        long length = ftell(f);\n        rewind(f);\n\n        char * buf = new char[length + 1];\n        size_t rv = fread(buf, length, 1, f);\n        fclose(f);\n        if (rv != 1) {\n            delete[] buf;\n            return string(\"\");\n        }\n\n        buf[length] = 0;\n        string ret(buf);\n        delete[] buf;\n\n        return ret;\n    } else {\n        return \"\";\n    }\n}\n\nstd::string FileUtils::HomeDir()\n{\n#ifdef WIN32\n    return string(getenv(\"USERPROFILE\"));\n#else\n    if (getenv(\"HOME\")) return string(getenv(\"HOME\"));\n    const struct passwd *pw = getpwuid(getuid());\n    const char *         homeDir = pw->pw_dir;\n    return string(homeDir);\n#endif\n}\n\nstd::string FileUtils::Basename(const std::string &path)\n{\n#ifdef WIN32\n    char fileName[_MAX_FNAME];\n    char extension[_MAX_EXT];\n    _splitpath_s(CleanupPath(path).c_str(), NULL, 0, NULL, 0, fileName, _MAX_FNAME, extension, _MAX_EXT);\n    return string(fileName) + string(extension);\n#else\n    char * copy = strdup(path.c_str());\n    string ret(basename(copy));\n    free(copy);\n    return ret;\n#endif\n}\n\nstd::string FileUtils::Dirname(const std::string &path)\n{\n#ifdef WIN32\n    char drive[_MAX_DRIVE];\n    char dir[_MAX_DIR];\n    _splitpath_s(CleanupPath(path).c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0);\n    return CleanupPath(string(drive) + string(dir));\n#else\n    char * copy = strdup(path.c_str());\n    string ret(dirname(copy));\n    free(copy);\n    return ret;\n#endif\n}\n\nstd::string FileUtils::Realpath(const std::string &path)\n{\n#ifdef WIN32\n    char real[_MAX_PATH];\n    if(_fullpath(real, path.c_str(), _MAX_PATH))\n        return string(real);\n    return path;\n#else\n    char real[PATH_MAX];\n    if (realpath(path.c_str(), real))\n        return string(real);\n    return path;\n#endif\n}\n\nstd::string FileUtils::Relpath(std::string path, std::string to)\n{\n    path = Realpath(path);\n    to = Realpath(to);\n    if (!IsDirectory(to))\n        to = Dirname(to);\n\n    auto common = CommonAncestor({path, to});\n    auto commonLevels = SplitPath(common).size();\n\n    path = JoinPaths(STLUtils::Slice(SplitPath(path), commonLevels));\n    to = JoinPaths(STLUtils::Slice(SplitPath(to), commonLevels));\n\n    for (const auto &_ : SplitPath(to)) {\n        (void)_;\n        path = JoinPaths({\"..\", path});\n    }\n\n    return path;\n}\n\nstd::string FileUtils::CommonAncestor(const std::vector<std::string> &paths_)\n{\n    if (paths_.empty())\n        return \"\";\n\n    std::vector<std::vector<std::string>> paths;\n    for (const auto &path : paths_)\n        paths.push_back(SplitPath(path));\n\n    int min_depth = 100000;\n    for (const auto &path : paths)\n        min_depth = min(min_depth, (int)path.size());\n\n    int same_depth = 0;\n    for (int i = 0; i < min_depth; i++) {\n        for (const auto &path: paths)\n            if (path[i] != paths[0][i])\n                goto stop;\n        same_depth = i+1;\n    }\n    stop:\n\n    if (same_depth <= 0)\n        return \"\";\n\n    return JoinPaths(std::vector<string>(paths[0].begin(), paths[0].begin() + same_depth));\n}\n\nstd::string FileUtils::Extension(const std::string &path)\n{\n    string basename = Basename(path);\n    size_t index = basename.rfind(\".\");\n    if (index == string::npos || index == 0)    // dotfile\n        return \"\";\n    return basename.substr(index + 1);\n}\n\nstd::string FileUtils::RemoveExtension(const std::string &path)\n{\n    const string extension = Extension(path);\n    if (extension.empty()) return path;\n    return path.substr(0, path.size() - Extension(path).size() - 1);\n}\n\nstd::string FileUtils::POSIXPathToWindows(std::string path)\n{\n    std::replace(path.begin(), path.end(), '/', '\\\\');\n    return path;\n}\n\nstd::string FileUtils::POSIXPathToCurrentOS(const std::string &path)\n{\n#ifdef WIN32\n    return POSIXPathToWindows(path);\n#else\n    return path;\n#endif\n}\n\nstd::string FileUtils::CleanupPath(std::string path)\n{\n#ifdef WIN32\n    std::replace(path.begin(), path.end(), '\\\\', '/');\n#endif\n    while (path.length() > 1 && (path.back() == '/' || path.back() == '\\\\')) path.pop_back();\n    while (path.find(\"//\") != std::string::npos) path = STLUtils::ReplaceAll(path, \"//\", \"/\");\n    if (path == \"\") path = \"\";\n    return path;\n}\n\nlong FileUtils::GetFileModifiedTime(const string &path)\n{\n    struct STAT64 attrib;\n    STAT64(path.c_str(), &attrib);\n    return attrib.st_mtime;\n}\n\nbool FileUtils::IsPathAbsolute(const std::string &path)\n{\n#ifdef WIN32\n    char dir[_MAX_DIR];\n    _splitpath_s(path.c_str(), NULL, 0, dir, _MAX_DIR, NULL, 0, NULL, 0);\n    return dir[0] == '/' || dir[0] == '\\\\';\n#else\n    return path[0] == '/';\n#endif\n}\n\nbool FileUtils::Exists(const std::string &path) { return FileUtils::GetFileType(path) != FileType::Does_Not_Exist; }\n\nbool FileUtils::IsRegularFile(const std::string &path) { return FileUtils::GetFileType(path) == FileType::File; }\n\nbool FileUtils::IsDirectory(const std::string &path) { return FileUtils::GetFileType(path) == FileType::Directory; }\n\nbool FileUtils::IsSubpath(const std::string &dir, const std::string &path){\n    return STLUtils::BeginsWith(FileUtils::SplitPath(path), FileUtils::SplitPath(dir));\n}\n\n#ifndef WIN32\nstatic unsigned long long GetFileInode(const std::string &path) {\n    struct STAT64 s;\n    if (STAT64(path.c_str(), &s) != 0)\n        return 0;\n    return s.st_ino;\n}\n#endif\n\nbool FileUtils::AreSameFile(const std::string &pathA, const std::string &pathB)\n{\n#ifdef WIN32\n    if (Realpath(pathA) != Realpath(pathB)) return false;\n    if (GetFileType(pathA) != GetFileType(pathB)) return false;\n    if (!IsDirectory(pathA) && GetFileSize(pathA) != GetFileSize(pathB)) return false;\n    if (GetFileModifiedTime(pathA) != GetFileModifiedTime(pathB)) return false;\n    return true;\n#else\n    return GetFileInode(pathA) == GetFileInode(pathB);\n#endif\n}\n\nFileType FileUtils::GetFileType(const std::string &path)\n{\n    struct STAT64 s;\n    if (STAT64(path.c_str(), &s) == 0) {\n        if (s.st_mode & S_IFDIR)\n            return FileType::Directory;\n        else if (s.st_mode & S_IFREG)\n            return FileType::File;\n        else\n            return FileType::Other;\n    } else\n        return FileType::Does_Not_Exist;\n}\n\nlong long FileUtils::GetFileSize(const std::string &path)\n{\n    struct STAT64 s;\n    if (STAT64(path.c_str(), &s) != 0)\n        return -1;\n    return s.st_size;\n}\n\nstd::vector<std::string> FileUtils::ListFiles(const std::string &path)\n{\n#ifdef WIN32\n    WIN32_FIND_DATA find;\n    HANDLE          h;\n    vector<string>  fileNames;\n    string          searchPath = path + \"\\\\*\";\n\n    h = FindFirstFile(searchPath.c_str(), &find);\n    if (h != INVALID_HANDLE_VALUE) {\n        do {\n            const string name(find.cFileName);\n            if (name == \".\") continue;\n            if (name == \"..\") continue;\n            fileNames.push_back(name);\n        } while (FindNextFile(h, &find));\n    }\n\n    FindClose(h);\n    return fileNames;\n#else\n    DIR *dir = opendir(path.c_str());\n    if (!dir) return {};\n\n    struct dirent *ent;\n    vector<string> fileNames;\n\n    while ((ent = readdir(dir))) {\n        const string name = ent->d_name;\n\n        if (name == \".\") continue;\n        if (name == \"..\") continue;\n\n        fileNames.push_back(name);\n    }\n\n    closedir(dir);\n    return fileNames;\n#endif\n}\n\nstd::string FileUtils::JoinPaths(const std::vector<std::string> &paths)\n{\n    string path;\n    for (auto it = paths.begin(); it != paths.end(); ++it) {\n        if (!it->empty()) {\n            if (!path.empty()) path += Separator;\n            path += *it;\n        }\n    }\n    return CleanupPath(path);\n}\n\nstd::vector<std::string> FileUtils::SplitPath(std::string path)\n{\n    std::replace(path.begin(), path.end(), '\\\\', '/');\n    auto parts = STLUtils::Split(CleanupPath(path), \"/\");\n    if (!path.empty() && path[0] == '/')\n        parts[0] = \"/\";\n    return STLUtils::Filter<std::string>(parts, [](const std::string &s) { return !s.empty(); });\n}\n\nint FileUtils::MakeDir(const std::string &path)\n{\n    if (IsDirectory(path)) return 0;\n\n    if (!Exists(Dirname(path))) MakeDir(Dirname(path));\n#if WIN32\n    return _mkdir(path.c_str());\n#else\n    return mkdir(path.c_str(), 0755);\n#endif\n}\n\nconst char *FileUtils::LegacyBasename(const char *path)\n{\n    const char *last;\n    last = strrchr(path, Separator[0]);\n    if (!last)\n        return path;\n    else\n        return last + 1;\n}\n"
  },
  {
    "path": "lib/common/GetAppPath.cpp",
    "content": "//\n// $Id$\n//\n#include <string>\n#include <iostream>\n#include <sstream>\n#include <cctype>\n#include <sys/stat.h>\n#include \"vapor/CMakeConfig.h\"\n#include \"vapor/FileUtils.h\"\n#ifdef Darwin\n    #include <CoreFoundation/CFBundle.h>\n    #include <CoreFoundation/CFString.h>\n    #include <CoreServices/CoreServices.h>\n#endif\n#include <vapor/MyBase.h>\n#define INCLUDE_DEPRECATED_GET_APP_PATH\n#include \"vapor/GetAppPath.h\"\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n#endif\nusing namespace std;\nusing namespace Wasp;\n\n#ifdef Darwin\nstring get_path_from_bundle(const string &app)\n{\n    string path;\n    path.clear();\n\n    string bundlename = app + \".app\";\n\n    //\n    // Get path to document directory from the application \"Bundle\";\n    //\n\n    CFBundleRef mainBundle = CFBundleGetMainBundle();\n    if (!mainBundle) return (\".\");\n\n    CFURLRef url = CFBundleCopyBundleURL(mainBundle);\n    if (!url) return (\".\");\n\n    const int kBufferLength = 1024;\n    UInt8     buffer[kBufferLength];\n    char      componentStr[kBufferLength];\n\n    CFIndex componentLength = CFURLGetBytes(url, buffer, kBufferLength);\n    if (componentLength < 0) return (\"\");\n    buffer[componentLength] = 0;\n\n    CFRange range;\n    CFRange rangeIncludingSeparators;\n\n    range = CFURLGetByteRangeForComponent(url, kCFURLComponentPath, &rangeIncludingSeparators);\n    if (range.location == kCFNotFound) return (\".\");\n\n    strncpy(componentStr, (const char *)&buffer[range.location], range.length);\n    componentStr[range.length] = 0;\n    string s = componentStr;\n\n    // Spaces are returned as %20. Quick fix below\n    size_t start;\n    while ((start = s.find(\"%20\")) != std::string::npos) s.replace(start, 3, \" \");\n\n    path = s;\n    return (path);\n}\n#endif\n\nbool pathExists(const string path)\n{\n    struct STAT64 statbuf;\n    return STAT64(path.c_str(), &statbuf) >= 0;\n}\n\nstd::string Wasp::GetAppPath(const string &app, const string &resource, const vector<string> &paths, bool forwardSeparator)\n{\n    string myResource = resource;\n\n#ifndef Darwin\n    if (myResource == \"home\") { myResource.clear(); }\n#endif\n    ostringstream oss;\n\n    oss << \"GetAppPath(\" << app << \", \" << myResource;\n    for (int i = 0; i < paths.size(); i++) { oss << \", \" << paths[i]; }\n    oss << \")\" << endl;\n    MyBase::SetDiagMsg(\"%s\", oss.str().c_str());\n\n    string separator, otherSeparator;\n    if (!forwardSeparator) {\n        separator = \"\\\\\";\n        otherSeparator = \"/\";\n    } else {\n        separator = \"/\";\n        otherSeparator = \"\\\\\";\n    }\n\n    string path;\n    path.clear();\n\n    string myapp = app;    // upper case app name\n    for (string::iterator itr = myapp.begin(); itr != myapp.end(); itr++) {\n        if (islower(*itr)) *itr = toupper(*itr);\n    }\n\n    string env(myapp);\n#ifdef WIN32\n    env.append(\"3\");\n#endif\n    env.append(\"_HOME\");\n\n    if (!((myResource.compare(\"lib\") == 0) || (myResource.compare(\"bin\") == 0) || (myResource.compare(\"share\") == 0) || (myResource.compare(\"plugins\") == 0) || (myResource.compare(\"home\") == 0)\n          || (myResource.compare(\"\") == 0))) {\n        MyBase::SetDiagMsg(\"GetAppPath() return : empty (unknown resources)\");\n        return (\"\");    // empty path, invalid resource\n    }\n\n    char *homestr = getenv(env.c_str());\n\n#ifdef Darwin\n    if (homestr) {\n        string s = homestr;\n        if (s.find(\".app\") != string::npos) {\n            path.assign(homestr);\n            path.append(separator);\n            homestr = NULL;\n        }\n    }\n#endif\n\n    if (homestr) {\n        path.assign(homestr);\n        if (!myResource.empty()) {\n            path.append(separator);\n            path.append(myResource);\n        }\n    }\n#ifdef Darwin\n    else {\n        if (path.empty()) { path = get_path_from_bundle(myapp); }\n        if (!path.empty()) {\n            path.append(\"Contents/\");\n            if ((myResource.compare(\"bin\") == 0) || (myResource.compare(\"\") == 0)) {\n                path.append(\"MacOS\");\n            } else if (myResource.compare(\"share\") == 0) {\n                path.append(\"share\");\n            } else if (myResource.compare(\"lib\") == 0) {\n                path.append(\"lib\");\n            } else if (myResource.compare(\"Frameworks\") == 0) {\n                path.append(\"Frameworks\");\n            } else if (myResource.compare(\"Resources\") == 0) {\n                path.append(\"Resources\");\n            } else if (myResource.compare(\"home\") == 0) {\n                path.erase(path.size() - 1, 1);\n            } else {    // must be plugins\n                path.append(\"Plugins\");\n            }\n        }\n    }\n#endif\n\n    if (!pathExists(path)) { path = \"\"; }\n\n    if (path.empty()) {\n        if (myResource.compare(\"share\") == 0) {\n            path.append(SOURCE_DIR);\n            path.append(separator);\n            path.append(\"share\");\n        }\n    }\n\n    if (path.empty()) {\n        MyBase::SetDiagMsg(\"GetAppPath() return : empty (path empty)\");\n        return (path);\n    }\n    // We may need to reverse the slashes in vapor_home\n    bool foundSep = true;\n    while (foundSep) {\n        std::size_t found = path.find(otherSeparator);\n        if (found != std::string::npos) {\n            path.replace(found, 1, separator);\n        } else\n            foundSep = false;\n    }\n    for (int i = 0; i < paths.size(); i++) {\n        path.append(separator);\n        path.append(paths[i]);\n    }\n\n    if (!pathExists(path)) {\n        MyBase::SetDiagMsg(\"GetAppPath() return : empty (path does not exist)\");\n        return (\"\");\n    }\n\n    MyBase::SetDiagMsg(\"GetAppPath() return : %s\", path.c_str());\n    return (path);\n}\n"
  },
  {
    "path": "lib/common/LegacyVectorMath.cpp",
    "content": "#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n#include \"vapor/VAssert.h\"\n#include <float.h>\n#include <string>\n#include <cmath>\n\nusing std::string;\nusing std::vector;\n\n/* The Identity matrix is useful for intializing transformations.\n */\nnamespace {\n\nfloat idmatrix[16] = {\n    1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,\n};\ndouble idmatrixd[16] = {\n    1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,\n};\n\n};    // namespace\n\nnamespace VAPoR {\n\nvoid vscale(float *v, float s)\n{\n    /* Scale the vector v in all directions by s.\n     */\n    v[0] *= s;\n    v[1] *= s;\n    v[2] *= s;\n}\nvoid vscale(double *v, double s)\n{\n    /* Scale the vector v in all directions by s.\n     */\n    v[0] *= s;\n    v[1] *= s;\n    v[2] *= s;\n}\nvoid vscale(vector<double> v, double s)\n{\n    /* Scale the vector v in all directions by s.\n     */\n    v[0] *= s;\n    v[1] *= s;\n    v[2] *= s;\n}\n// Scale, putting result in another vector\n//\nvoid vmult(const float *v, float s, float *w)\n{\n    w[0] = s * v[0];\n    w[1] = s * v[1];\n    w[2] = s * v[2];\n}\n// Scale, putting result in another vector\n//\nvoid vmult(const double *v, double s, double *w)\n{\n    w[0] = s * v[0];\n    w[1] = s * v[1];\n    w[2] = s * v[2];\n}\n\nvoid vhalf(const float *v1, const float *v2, float *half)\n{\n    /* Return in 'half' the unit vector\n     * half way between v1 and v2.  half can be v1 or v2.\n     */\n    float len;\n\n    vadd(v2, v1, half);\n    len = vlength(half);\n    if (len > 0)\n        vscale(half, 1 / len);\n    else\n        vcopy(v1, half);\n}\n\nvoid vcross(const float *v1, const float *v2, float *cross)\n{\n    /* Vector cross product.\n     */\n    float temp[3];\n\n    temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);\n    temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);\n    temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);\n    vcopy(temp, cross);\n}\nvoid vcross(const double *v1, const double *v2, double *cross)\n{\n    /* Vector cross product.\n     */\n    double temp[3];\n\n    temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);\n    temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);\n    temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);\n    vcopy(temp, cross);\n}\n\nvoid vreflect(const float *in, const float *mirror, float *out)\n{\n    /* Mirror defines a plane across which in is reflected.\n     */\n    float temp[3];\n\n    vcopy(mirror, temp);\n    vscale(temp, vdot(mirror, in));\n    vsub(temp, in, out);\n    vadd(temp, out, out);\n}\n\nvoid vtransform(const float *v, float mat[12], float *vt)\n{\n    /* Vector transform in software...\n     */\n    float t[3];\n\n    t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3];\n    t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7];\n    t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11];\n    vcopy(t, vt);\n}\nvoid vtransform(const float *v, float mat[12], double *vt)\n{\n    /* Vector transform in software...\n     */\n    double t[3];\n\n    t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3];\n    t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7];\n    t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11];\n    vcopy(t, vt);\n}\nvoid vtransform(const double *v, float mat[12], double *vt)\n{\n    /* Vector transform in software...\n     */\n    double t[3];\n\n    t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3];\n    t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7];\n    t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11];\n    vcopy(t, vt);\n}\n\nvoid vtransform(const double *v, double mat[12], double *vt)\n{\n    /* Vector transform in software...\n     */\n    double t[3];\n\n    t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3];\n    t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7];\n    t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11];\n    vcopy(t, vt);\n}\nvoid vtransform4(const float *v, float *mat, float *vt)\n{\n    /* Homogeneous coordinates.\n     */\n    float t[4];\n\n    t[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2] + mat[3];\n    t[1] = v[0] * mat[4] + v[1] * mat[5] + v[2] * mat[6] + mat[7];\n    t[2] = v[0] * mat[8] + v[1] * mat[9] + v[2] * mat[10] + mat[11];\n    t[3] = v[0] * mat[12] + v[1] * mat[13] + v[2] * mat[14] + mat[15];\n    qcopy(t, vt);\n}\nvoid vtransform3(const float *v, float *mat, float *vt)\n{\n    /* 3x3 matrix multiply\n     */\n    vt[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2];\n    vt[1] = v[0] * mat[3] + v[1] * mat[4] + v[2] * mat[5];\n    vt[2] = v[0] * mat[6] + v[1] * mat[7] + v[2] * mat[8];\n}\nvoid vtransform3(const double *v, double *mat, double *vt)\n{\n    /* 3x3 matrix multiply\n     */\n    vt[0] = v[0] * mat[0] + v[1] * mat[1] + v[2] * mat[2];\n    vt[1] = v[0] * mat[3] + v[1] * mat[4] + v[2] * mat[5];\n    vt[2] = v[0] * mat[6] + v[1] * mat[7] + v[2] * mat[8];\n}\nvoid vtransform3t(const float *v, float *mat, float *vt)\n{\n    /* 3x3 matrix multiply, using transpose of matrix\n     */\n    vt[0] = v[0] * mat[0] + v[1] * mat[3] + v[2] * mat[6];\n    vt[1] = v[0] * mat[1] + v[1] * mat[4] + v[2] * mat[7];\n    vt[2] = v[0] * mat[2] + v[1] * mat[5] + v[2] * mat[8];\n}\n// Test whether a planar point is right (or left) of the oriented line from\n// pt1 to pt2\nbool pointOnRight(double *pt1, double *pt2, const double *testPt)\n{\n    float rhs = pt1[0] * (pt1[1] - pt2[1]) + pt1[1] * (pt2[0] - pt1[0]);\n    float test = (pt2[0] - pt1[0]) * testPt[1] + (pt1[1] - pt2[1]) * testPt[0] - rhs;\n    return (test < 0.f);\n}\n\nvoid mcopy(float *m1, float *m2)\n{\n    /* Copy a 4x4 matrix\n     */\n    int row;\n\n    for (row = 0; row < 16; row++) m2[row] = m1[row];\n}\nvoid mcopy(double *m1, double *m2)\n{\n    /* Copy a 4x4 matrix\n     */\n    int row;\n\n    for (row = 0; row < 16; row++) m2[row] = m1[row];\n}\n\nvoid mmult(float *m1, float *m2, float *prod)\n{\n    /* Multiply two 4x4 matricies\n     */\n    int   row, col;\n    float temp[16];\n\n    /*for(row = 0 ; row < 4 ; row++)\n      for(col = 0 ; col < 4 ; col++)\n      temp[row + col*4] = (m1[row]   * m2[col*4] +\n      m1[row+4]  * m2[1+col*4] +\n      m1[row+8]  * m2[2+col*4] +\n      m1[row+12] * m2[3+col*4]);*/\n    /*\n     * Use OpenGL style matrix mult -- Wes.\n     */\n    for (row = 0; row < 4; row++)\n        for (col = 0; col < 4; col++) temp[row * 4 + col] = (m1[row * 4] * m2[col] + m1[1 + row * 4] * m2[col + 4] + m1[2 + row * 4] * m2[col + 8] + m1[3 + row * 4] * m2[col + 12]);\n    mcopy(temp, prod);\n}\nvoid mmult(double *m1, double *m2, double *prod)\n{\n    /* Multiply two 4x4 matricies\n     */\n    int    row, col;\n    double temp[16];\n\n    /*\n     * Use OpenGL style matrix mult -- Wes.\n     */\n    for (row = 0; row < 4; row++)\n        for (col = 0; col < 4; col++) temp[row * 4 + col] = (m1[row * 4] * m2[col] + m1[1 + row * 4] * m2[col + 4] + m1[2 + row * 4] * m2[col + 8] + m1[3 + row * 4] * m2[col + 12]);\n    mcopy(temp, prod);\n}\n\n// 4x4 matrix inversion.  Fixed (AN 4/07) so that it doesn't try to divide by very small\n// pivot elements.  Returns 0 if not invertible\nint minvert(const float *mat, float *result)\n{\n    // Invert a 4x4 matrix\n\n    int   i, j, k;\n    float temp;\n    float m[8][4];\n\n    mcopy(idmatrix, result);\n    // mat[i,j] is row j, col i:\n    for (i = 0; i < 4; i++) {\n        for (j = 0; j < 4; j++) {\n            m[i][j] = mat[i + 4 * j];\n            m[i + 4][j] = result[i + 4 * j];\n        }\n    }\n\n    // Work across by columns (i is col index):\n\n    for (i = 0; i < 4; i++) {\n        // Find largest entry in the column, below the diagonal:\n        float maxval = 0.f;\n        int   pivot = -1;\n        for (int rw = i; rw < 4; rw++) {\n            if (std::abs(m[i][rw]) > maxval) {\n                maxval = std::abs(m[i][rw]);\n                pivot = rw;\n            }\n        }\n        if (pivot < 0) return -1;    // otherwise, can't invert!\n\n        if (pivot != i) {    // Swap i and pivot row:\n            for (k = i; k < 8; k++) {\n                temp = m[k][i];\n                m[k][i] = m[k][pivot];\n                m[k][pivot] = temp;\n            }\n        }\n\n        // Divide original row by pivot element, which is now the [i][i] element:\n\n        for (j = 7; j >= i; j--) m[j][i] /= m[i][i];\n\n        // Subtract other rows, to make row i be the only row with nonzero elt in col i:\n\n        for (j = 0; j < 4; j++)\n            if (i != j)\n                for (k = 7; k >= i; k--) m[k][j] -= m[k][i] * m[i][j];\n    }\n    // copy back the last 4 columns:\n    for (i = 0; i < 4; i++)\n        for (j = 0; j < 4; j++) result[i + 4 * j] = m[i + 4][j];\n    return 0;\n}\nint minvert(const double *mat, double *result)\n{\n    // Invert a 4x4 matrix\n\n    int    i, j, k;\n    double temp;\n    double m[8][4];\n\n    mcopy(idmatrixd, result);\n    // mat[i,j] is row j, col i:\n    for (i = 0; i < 4; i++) {\n        for (j = 0; j < 4; j++) {\n            m[i][j] = mat[i + 4 * j];\n            m[i + 4][j] = result[i + 4 * j];\n        }\n    }\n\n    // Work across by columns (i is col index):\n\n    for (i = 0; i < 4; i++) {\n        // Find largest entry in the column, below the diagonal:\n        double maxval = 0.f;\n        int    pivot = -1;\n        for (int rw = i; rw < 4; rw++) {\n            if (std::abs(m[i][rw]) > maxval) {\n                maxval = std::abs(m[i][rw]);\n                pivot = rw;\n            }\n        }\n        if (pivot < 0) return -1;    // otherwise, can't invert!\n\n        if (pivot != i) {    // Swap i and pivot row:\n            for (k = i; k < 8; k++) {\n                temp = m[k][i];\n                m[k][i] = m[k][pivot];\n                m[k][pivot] = temp;\n            }\n        }\n\n        // Divide original row by pivot element, which is now the [i][i] element:\n\n        for (j = 7; j >= i; j--) m[j][i] /= m[i][i];\n\n        // Subtract other rows, to make row i be the only row with nonzero elt in col i:\n\n        for (j = 0; j < 4; j++)\n            if (i != j)\n                for (k = 7; k >= i; k--) m[k][j] -= m[k][i] * m[i][j];\n    }\n    // copy back the last 4 columns:\n    for (i = 0; i < 4; i++)\n        for (j = 0; j < 4; j++) result[i + 4 * j] = m[i + 4][j];\n    return 0;\n}\n\nvoid qnormal(float *q)\n{\n    /* Normalize a quaternion\n     */\n    float s;\n\n    s = 1 / sqrt((double)(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]));\n    q[0] *= s;\n    q[1] *= s;\n    q[2] *= s;\n    q[3] *= s;\n}\nvoid qinv(const float q1[4], float q2[4])\n{\n    // Inverse of quaternion is conjugate/norm-square.  4th coeff is real part!\n    float mag = q1[0] * q1[0] + q1[1] * q1[1] + q1[2] * q1[2] + q1[3] * q1[3];\n    VAssert(mag > 0.f);\n    for (int i = 0; i < 3; i++) q2[i] = -q1[i] / mag;\n    q2[3] = q1[3] / mag;\n    float reslt[4];\n    qmult(q1, q2, reslt);\n}\n\nvoid qmult(const float *q1, const float *q2, float *dest)\n{\n    /* Multiply two quaternions.  Note quaternion real part is 4th coefficient!\n     */\n    // static int\tcount = 0;\n    float t1[3], t2[3], t3[3];\n    float tf[4];\n\n    vcopy(q1, t1);\n    vscale(t1, q2[3]);\n\n    vcopy(q2, t2);\n    vscale(t2, q1[3]);\n\n    vcross(q2, q1, t3);\n    vadd(t1, t2, tf);\n    vadd(t3, tf, tf);\n    tf[3] = q1[3] * q2[3] - vdot(q1, q2);\n\n    qcopy(tf, dest);\n    // why is this code here?\n    // if (++count >= 97) {\n    //\tcount = 0;\n    //\tqnormal(dest);\n    //}\n}\n\nvoid qmult(const double *q1, const double *q2, double *dest)\n{\n    /* Multiply two quaternions.  Note quaternion real part is 4th coefficient!\n     */\n    // static int\tcount = 0;\n    double t1[3], t2[3], t3[3];\n    double tf[4];\n\n    vcopy(q1, t1);\n    vscale(t1, q2[3]);\n\n    vcopy(q2, t2);\n    vscale(t2, q1[3]);\n\n    vcross(q2, q1, t3);\n    vadd(t1, t2, tf);\n    vadd(t3, tf, tf);\n    tf[3] = q1[3] * q2[3] - vdot(q1, q2);\n\n    qcopy(tf, dest);\n    // why is this code here?\n    // if (++count >= 97) {\n    //\tcount = 0;\n    //\tqnormal(dest);\n    //}\n}\nvoid qmatrix(const float *q, float *m)\n{\n    /* Build a rotation matrix, given a quaternion rotation.\n     */\n    m[0] = 1 - 2 * (q[1] * q[1] + q[2] * q[2]);\n    m[1] = 2 * (q[0] * q[1] - q[2] * q[3]);\n    m[2] = 2 * (q[2] * q[0] + q[1] * q[3]);\n    m[3] = 0;\n\n    m[4] = 2 * (q[0] * q[1] + q[2] * q[3]);\n    m[5] = 1 - 2 * (q[2] * q[2] + q[0] * q[0]);\n    m[6] = 2 * (q[1] * q[2] - q[0] * q[3]);\n    m[7] = 0;\n\n    m[8] = 2 * (q[2] * q[0] - q[1] * q[3]);\n    m[9] = 2 * (q[1] * q[2] + q[0] * q[3]);\n    m[10] = 1 - 2 * (q[1] * q[1] + q[0] * q[0]);\n    m[11] = 0;\n\n    m[12] = 0;\n    m[13] = 0;\n    m[14] = 0;\n    m[15] = 1;\n}\n\n// This function results in row major matrix. OpenGL uses column major\n// as well as the rest of the matrix operations\nvoid qmatrix(const double *q, double *m)\n{\n    /* Build a rotation matrix, given a quaternion rotation.\n     */\n    m[0] = 1 - 2 * (q[1] * q[1] + q[2] * q[2]);\n    m[1] = 2 * (q[0] * q[1] - q[2] * q[3]);\n    m[2] = 2 * (q[2] * q[0] + q[1] * q[3]);\n    m[3] = 0;\n\n    m[4] = 2 * (q[0] * q[1] + q[2] * q[3]);\n    m[5] = 1 - 2 * (q[2] * q[2] + q[0] * q[0]);\n    m[6] = 2 * (q[1] * q[2] - q[0] * q[3]);\n    m[7] = 0;\n\n    m[8] = 2 * (q[2] * q[0] - q[1] * q[3]);\n    m[9] = 2 * (q[1] * q[2] + q[0] * q[3]);\n    m[10] = 1 - 2 * (q[1] * q[1] + q[0] * q[0]);\n    m[11] = 0;\n\n    m[12] = 0;\n    m[13] = 0;\n    m[14] = 0;\n    m[15] = 1;\n}\n/*  Convert a 4x4 rotation matrix to a quaternion.  q[3] is real part!\n    Code adapted from\nhttp://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion\n*/\n#define M_EPSILON 0.00000001\nvoid rotmatrix2q(float *m, float *q)\n{\n    float trace = m[0] + m[5] + m[10] + 1.0f;\n    if (trace > M_EPSILON) {\n        float s = 0.5f / sqrtf(trace);\n        q[3] = 0.25f / s;\n        q[0] = (m[9] - m[6]) * s;\n        q[1] = (m[2] - m[8]) * s;\n        q[2] = (m[4] - m[1]) * s;\n    } else {\n        if (m[0] > m[5] && m[0] > m[10]) {\n            float s = 2.0f * sqrtf(1.0f + m[0] - m[5] - m[10]);\n            q[0] = 0.25f * s;\n            q[1] = (m[1] + m[4]) / s;\n            q[2] = (m[2] + m[8]) / s;\n            q[3] = (m[6] - m[9]) / s;    //???? minus?\n        } else if (m[5] > m[10]) {\n            float s = 2.0f * sqrtf(1.0f + m[5] - m[0] - m[10]);\n            q[0] = (m[1] + m[4]) / s;\n            q[1] = 0.25f * s;\n            q[2] = (m[6] + m[9]) / s;\n            q[3] = (m[2] - m[8]) / s;\n        } else {\n            float s = 2.0f * sqrtf(1.0f + m[10] - m[0] - m[5]);\n            q[0] = (m[2] + m[8]) / s;\n            q[1] = (m[6] + m[9]) / s;\n            q[2] = 0.25f * s;\n            q[3] = (m[1] - m[4]) / s;    //?? off by minus??\n        }\n    }\n}\n\nvoid rotmatrix2q(double *m, double *q)\n{\n    double trace = m[0] + m[5] + m[10] + 1.0;\n    if (trace > M_EPSILON) {\n        double s = 0.5 / sqrt(trace);\n        q[3] = 0.25 / s;\n        q[0] = (m[9] - m[6]) * s;\n        q[1] = (m[2] - m[8]) * s;\n        q[2] = (m[4] - m[1]) * s;\n    } else {\n        if (m[0] > m[5] && m[0] > m[10]) {\n            double s = 2.0 * sqrt(1.0 + m[0] - m[5] - m[10]);\n            q[0] = 0.25 * s;\n            q[1] = (m[1] + m[4]) / s;\n            q[2] = (m[2] + m[8]) / s;\n            q[3] = (m[6] - m[9]) / s;    //???? minus?\n        } else if (m[5] > m[10]) {\n            double s = 2.0 * sqrt(1.0 + m[5] - m[0] - m[10]);\n            q[0] = (m[1] + m[4]) / s;\n            q[1] = 0.25 * s;\n            q[2] = (m[6] + m[9]) / s;\n            q[3] = (m[2] - m[8]) / s;\n        } else {\n            double s = 2.0 * sqrt(1.0 + m[10] - m[0] - m[5]);\n            q[0] = (m[2] + m[8]) / s;\n            q[1] = (m[6] + m[9]) / s;\n            q[2] = 0.25 * s;\n            q[3] = (m[1] - m[4]) / s;    //?? off by minus??\n        }\n    }\n}\n\nvoid rvec2q(const float rvec[3], float radians, float q[4])\n{\n    double rvec_normal[3];\n    double d;\n\n    d = sqrt(rvec[0] * rvec[0] + rvec[1] * rvec[1] + rvec[2] * rvec[2]);\n\n    if (d != 0.0) {\n        rvec_normal[0] = rvec[0] / d;\n        rvec_normal[1] = rvec[1] / d;\n        rvec_normal[2] = rvec[2] / d;\n    } else {\n        rvec_normal[0] = 0.0;\n        rvec_normal[1] = 0.0;\n        rvec_normal[2] = 1.0;\n    }\n\n    q[0] = sin(radians / 2.0) * rvec_normal[0];\n    q[1] = sin(radians / 2.0) * rvec_normal[1];\n    q[2] = sin(radians / 2.0) * rvec_normal[2];\n    q[3] = cos(radians / 2.0);\n}\nvoid rvec2q(const double rvec[3], double radians, double q[4])\n{\n    double rvec_normal[3];\n    double d;\n\n    d = sqrt(rvec[0] * rvec[0] + rvec[1] * rvec[1] + rvec[2] * rvec[2]);\n\n    if (d != 0.0) {\n        rvec_normal[0] = rvec[0] / d;\n        rvec_normal[1] = rvec[1] / d;\n        rvec_normal[2] = rvec[2] / d;\n    } else {\n        rvec_normal[0] = 0.0;\n        rvec_normal[1] = 0.0;\n        rvec_normal[2] = 1.0;\n    }\n\n    q[0] = sin(radians / 2.0) * rvec_normal[0];\n    q[1] = sin(radians / 2.0) * rvec_normal[1];\n    q[2] = sin(radians / 2.0) * rvec_normal[2];\n    q[3] = cos(radians / 2.0);\n}\n\nfloat ProjectToSphere(float r, float x, float y)\n{\n    /* Project an x,y pair onto a sphere of radius r or a hyperbolic sheet\n     * if we are away from the center of the sphere.\n     *\n     * On sphere, \tx*x + y*y + z*z = r*r\n     * On hyperbola, \tsqrt(x*x + y*y) * z = 1/2 r*r\n     * Tangent at\tz = r / sqrt(2)\n     */\n    float dd, tt;\n\n    dd = x * x + y * y;\n    tt = r * r * 0.5;\n\n    if (dd < tt)\n        return sqrt((double)(r * r - dd)); /* Inside sphere */\n    else\n        return tt / sqrt((double)dd); /* On hyperbola */\n}\n\nvoid CalcRotation(float *q, float newX, float newY, float oldX, float oldY, float ballsize)\n{\n    /* Given old and new mouse positions (scaled to [-1, 1]),\n     * Find the rotation quaternion q.\n     */\n    float p1[3], p2[3]; /* 3D mouse points  */\n    float L;            /* sin^2(2 * phi)   */\n\n    /* Check for zero rotation\n     */\n    if (newX == oldX && newY == oldY) {\n        qzero(q);\n        return;\n    }\n\n    /* Form two vectors based on input points, find rotation axis\n     */\n    vset(p1, newX, newY, ProjectToSphere(ballsize, newX, newY));\n    vset(p2, oldX, oldY, ProjectToSphere(ballsize, oldX, oldY));\n\n    vcross(p1, p2, q); /* axis of rotation from p1 and p2 */\n\n    L = vdot(q, q) / (vdot(p1, p1) * vdot(p2, p2));\n    L = sqrt((double)(1 - L));\n\n    vnormal(q);                             /* q' = axis of rotation */\n    vscale(q, sqrt((double)((1 - L) / 2))); /* q' = q' * sin(phi) */\n    q[3] = sqrt((double)((1 + L) / 2));     /* qs = qs * cos(phi) */\n}\nvoid CalcRotation(double *q, double newX, double newY, double oldX, double oldY, double ballsize)\n{\n    /* Given old and new mouse positions (scaled to [-1, 1]),\n     * Find the rotation quaternion q.\n     */\n    double p1[3], p2[3]; /* 3D mouse points  */\n    double L;            /* sin^2(2 * phi)   */\n\n    /* Check for zero rotation\n     */\n    if (newX == oldX && newY == oldY) {\n        qzero(q);\n        return;\n    }\n\n    /* Form two vectors based on input points, find rotation axis\n     */\n    vset(p1, newX, newY, ProjectToSphere(ballsize, newX, newY));\n    vset(p2, oldX, oldY, ProjectToSphere(ballsize, oldX, oldY));\n\n    vcross(p1, p2, q); /* axis of rotation from p1 and p2 */\n\n    L = vdot(q, q) / (vdot(p1, p1) * vdot(p2, p2));\n    L = sqrt((double)(1 - L));\n\n    vnormal(q);                             /* q' = axis of rotation */\n    vscale(q, sqrt((double)((1 - L) / 2))); /* q' = q' * sin(phi) */\n    q[3] = sqrt((double)((1 + L) / 2));     /* qs = qs * cos(phi) */\n}\n\nfloat ScalePoint(long pt, long origin, long size)\n{\n    /* Scales integer point to the range [-1, 1]\n     */\n    float x;\n\n    x = (float)(pt - origin) / (float)size;\n    if (x < 0) x = 0;\n    if (x > 1) x = 1;\n\n    return 2 * x - 1;\n}\n\n/* Make a translation matrix from a vector:\n */\nvoid makeTransMatrix(float *trans, float *mtrx)\n{\n    for (int i = 0; i < 12; i++) mtrx[i] = 0.f;\n    mtrx[0] = 1.f;\n    mtrx[5] = 1.f;\n    mtrx[10] = 1.f;\n    mtrx[15] = 1.f;\n    vcopy(trans, mtrx + 12);\n}\nvoid makeTransMatrix(double *trans, double *mtrx)\n{\n    for (int i = 0; i < 12; i++) mtrx[i] = 0.;\n    mtrx[0] = 1.;\n    mtrx[5] = 1.;\n    mtrx[10] = 1.;\n    mtrx[15] = 1.;\n    for (int i = 0; i < 3; i++) mtrx[i + 12] = (double)trans[i];\n}\nvoid makeTransMatrix(const std::vector<double> &trans, double *mtrx)\n{\n    for (int i = 0; i < 12; i++) mtrx[i] = 0.;\n    mtrx[0] = 1.;\n    mtrx[5] = 1.;\n    mtrx[10] = 1.;\n    mtrx[15] = 1.;\n    for (int i = 0; i < 3; i++) mtrx[i + 12] = trans[i];\n}\n\nvoid makeScaleMatrix(const double *scale, double *mtrx)\n{\n    for (int i = 0; i < 16; i++) mtrx[i] = 0.;\n    mtrx[0] = scale[0];\n    mtrx[5] = scale[1];\n    mtrx[10] = scale[2];\n    mtrx[15] = 1.;\n}\n\n/*\n * make a modelview matrix from viewer position, direction, and up vector\n * Vectors must be nonzero\n * side-effect:  will alter input values if not valid.\n */\nvoid makeModelviewMatrix(float *vpos, float *vdir, float *upvec, float *mtrx)\n{\n    float vtemp[3];\n    float left[3] = {-1.f, 0.f, 0.f};\n    float ydir[3] = {0.f, 1.f, 0.f};\n    float right[3];\n    // Normalize the vectors:\n    vnormal(upvec);\n    vnormal(vdir);\n    // Force the up vector to be orthogonal to viewDir\n    vcopy(vdir, vtemp);\n    vscale(vtemp, vdot(vdir, upvec));\n    // Subtract the component of up in the viewdir direction\n    vsub(upvec, vtemp, upvec);\n    // Make sure it's still valid\n    if (vdot(upvec, upvec) == 0.f) {\n        // First try up = viewdir x left\n        vcross(vdir, left, upvec);\n        if (vdot(upvec, upvec) == 0.f) {\n            // try viewdir x ydir\n            vcross(vdir, ydir, upvec);\n        }\n    }\n    vnormal(upvec);\n    // calculate \"right\" vector:\n    vcross(vdir, upvec, right);\n    // Construct matrix:\n    float minv[16];\n    // Fill in bottom row:\n    minv[3] = 0.f;\n    minv[7] = 0.f;\n    minv[11] = 0.f;\n    minv[15] = 1.f;\n    // copy in first 3 elements of columns\n    vcopy(right, minv);\n    vcopy(upvec, minv + 4);\n    // third col is neg of viewdir\n\n    vcopy(vdir, minv + 8);\n    vscale(minv + 8, -1.f);\n    vcopy(vpos, minv + 12);\n    int rc = minvert(minv, mtrx);\n    VAssert(rc >= 0);    // Only catch this in debug mode\n}\n/*\n * make a modelview matrix from viewer position, direction, and up vector\n * Vectors must be nonzero\n * side-effect:  will alter input values if not valid.\n */\nvoid makeModelviewMatrixD(double *vpos, double *vdir, double *upvec, double *mtrx)\n{\n    double vtemp[3];\n    double left[3] = {-1.f, 0.f, 0.f};\n    double ydir[3] = {0.f, 1.f, 0.f};\n    double right[3];\n    double dupvec[3], dvdir[3], dvpos[3];\n    for (int i = 0; i < 3; i++) {\n        dupvec[i] = upvec[i];\n        dvdir[i] = vdir[i];\n        dvpos[i] = vpos[i];\n    }\n\n    // Normalize the vectors:\n    vnormal(dupvec);\n    vnormal(dvdir);\n    // Force the up vector to be orthogonal to viewDir\n    vcopy(dvdir, vtemp);\n    vscale(vtemp, vdot(dvdir, dupvec));\n    // Subtract the component of up in the viewdir direction\n    vsub(dupvec, vtemp, dupvec);\n    // Make sure it's still valid\n    if (vdot(dupvec, dupvec) == 0.f) {\n        // First try up = viewdir x left\n        vcross(dvdir, left, dupvec);\n        if (vdot(dupvec, dupvec) == 0.f) {\n            // try viewdir x ydir\n            vcross(dvdir, ydir, dupvec);\n        }\n    }\n    vnormal(dupvec);\n    // calculate \"right\" vector:\n    vcross(dvdir, dupvec, right);\n    // Construct matrix:\n    double minv[16];\n    // Fill in bottom row:\n    minv[3] = 0.;\n    minv[7] = 0.;\n    minv[11] = 0.;\n    minv[15] = 1.;\n    // copy in first 3 elements of columns\n    vcopy(right, minv);\n    vcopy(dupvec, minv + 4);\n    // third col is neg of viewdir\n\n    vcopy(dvdir, minv + 8);\n    vscale(minv + 8, -1.);\n    vcopy(dvpos, minv + 12);\n    int rc = minvert(minv, mtrx);\n    VAssert(rc >= 0);    // Only catch this in debug mode\n}\n/*\n * make a modelview matrix from viewer position, direction, and up vector\n * Vectors must be nonzero\n * side-effect:  will alter input values if not valid.\n */\nvoid makeModelviewMatrixD(const std::vector<double> &vpos, const std::vector<double> &vdir, const std::vector<double> &upvec, double *mtrx)\n{\n    double vtemp[3];\n    double left[3] = {-1.f, 0.f, 0.f};\n    double ydir[3] = {0.f, 1.f, 0.f};\n    double right[3];\n    double dupvec[3], dvdir[3], dvpos[3];\n    for (int i = 0; i < 3; i++) {\n        dupvec[i] = upvec[i];\n        dvdir[i] = vdir[i];\n        dvpos[i] = vpos[i];\n    }\n\n    // Normalize the vectors:\n    vnormal(dupvec);\n    vnormal(dvdir);\n    // Force the up vector to be orthogonal to viewDir\n    vcopy(dvdir, vtemp);\n    vscale(vtemp, vdot(dvdir, dupvec));\n    // Subtract the component of up in the viewdir direction\n    vsub(dupvec, vtemp, dupvec);\n    // Make sure it's still valid\n    if (vdot(dupvec, dupvec) == 0.f) {\n        // First try up = viewdir x left\n        vcross(dvdir, left, dupvec);\n        if (vdot(dupvec, dupvec) == 0.f) {\n            // try viewdir x ydir\n            vcross(dvdir, ydir, dupvec);\n        }\n    }\n    vnormal(dupvec);\n    // calculate \"right\" vector:\n    vcross(dvdir, dupvec, right);\n    // Construct matrix:\n    double minv[16];\n    // Fill in bottom row:\n    minv[3] = 0.;\n    minv[7] = 0.;\n    minv[11] = 0.;\n    minv[15] = 1.;\n    // copy in first 3 elements of columns\n    vcopy(right, minv);\n    vcopy(dupvec, minv + 4);\n    // third col is neg of viewdir\n\n    vcopy(dvdir, minv + 8);\n    vscale(minv + 8, -1.);\n    vcopy(dvpos, minv + 12);\n    int rc = minvert(minv, mtrx);\n    VAssert(rc >= 0);    // Only catch this in debug mode\n}\nvoid matrix4x4_vec3_mult(const float m[16], const float a[4], float b[4])\n{\n    b[0] = m[0] * a[0] + m[4] * a[1] + m[8] * a[2] + m[12] * a[3];\n    b[1] = m[1] * a[0] + m[5] * a[1] + m[9] * a[2] + m[13] * a[3];\n    b[2] = m[2] * a[0] + m[6] * a[1] + m[10] * a[2] + m[14] * a[3];\n    b[3] = m[3] * a[0] + m[7] * a[1] + m[11] * a[2] + m[15] * a[3];\n\n    if (b[3] != 0.0 && b[3] != 1.0) {\n        b[0] /= b[3];\n        b[1] /= b[3];\n        b[2] /= b[3];\n        b[3] = 1.0;\n    }\n}\n\n//\n// Matrix Inversion\n// Adapted from Richard Carling\n// from \"Graphics Gems\", Academic Press, 1990\n//\n\n#define SMALL_NUMBER 1.e-8\n/*\n *   matrix4x4_inverse( original_matrix, inverse_matrix )\n *\n *    calculate the inverse of a 4x4 matrix\n *\n *     -1\n *     A  = ___1__ adjoint A\n *         det A\n */\n\nint matrix4x4_inverse(const float *in, float *out)\n{\n    int    i, j;\n    double det;\n    double det4x4(const float m[16]);\n    void   adjoint(const float *in, float *out);\n\n    /* calculate the adjoint matrix */\n\n    adjoint(in, out);\n\n    /*  calculate the 4x4 determinant\n     *  if the determinant is zero,\n     *  then the inverse matrix is not unique.\n     */\n\n    det = det4x4(in);\n\n    if (std::abs(det) < SMALL_NUMBER) {\n        //\tSingular matrix, no inverse!\n        return (-1);\n    }\n\n    /* scale the adjoint matrix to get the inverse */\n\n    for (i = 0; i < 4; i++) {\n        for (j = 0; j < 4; j++) { out[i * 4 + j] = out[i * 4 + j] / det; }\n    }\n    return (0);\n}\n\n/*\n *   adjoint( original_matrix, inverse_matrix )\n *\n *     calculate the adjoint of a 4x4 matrix\n *\n *      Let  a   denote the minor determinant of matrix A obtained by\n *           ij\n *\n *      deleting the ith row and jth column from A.\n *\n *                    i+j\n *     Let  b   = (-1)    a\n *          ij            ji\n *\n *    The matrix B = (b  ) is the adjoint of A\n *                     ij\n */\n\nvoid adjoint(const float *in, float *out)\n{\n    double a1, a2, a3, a4, b1, b2, b3, b4;\n    double c1, c2, c3, c4, d1, d2, d3, d4;\n    double det3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3);\n\n    /* assign to individual variable names to aid  */\n    /* selecting correct values  */\n\n    a1 = in[0 * 4 + 0];\n    b1 = in[0 * 4 + 1];\n    c1 = in[0 * 4 + 2];\n    d1 = in[0 * 4 + 3];\n\n    a2 = in[1 * 4 + 0];\n    b2 = in[1 * 4 + 1];\n    c2 = in[1 * 4 + 2];\n    d2 = in[1 * 4 + 3];\n\n    a3 = in[2 * 4 + 0];\n    b3 = in[2 * 4 + 1];\n    c3 = in[2 * 4 + 2];\n    d3 = in[2 * 4 + 3];\n\n    a4 = in[3 * 4 + 0];\n    b4 = in[3 * 4 + 1];\n    c4 = in[3 * 4 + 2];\n    d4 = in[3 * 4 + 3];\n\n    /* row column labeling reversed since we transpose rows & columns */\n\n    out[0 * 4 + 0] = det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);\n    out[1 * 4 + 0] = -det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);\n    out[2 * 4 + 0] = det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);\n    out[3 * 4 + 0] = -det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);\n\n    out[0 * 4 + 1] = -det3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);\n    out[1 * 4 + 1] = det3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);\n    out[2 * 4 + 1] = -det3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);\n    out[3 * 4 + 1] = det3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);\n\n    out[0 * 4 + 2] = det3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);\n    out[1 * 4 + 2] = -det3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);\n    out[2 * 4 + 2] = det3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);\n    out[3 * 4 + 2] = -det3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);\n\n    out[0 * 4 + 3] = -det3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);\n    out[1 * 4 + 3] = det3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);\n    out[2 * 4 + 3] = -det3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);\n    out[3 * 4 + 3] = det3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);\n}\n/*\n * double = det4x4( matrix )\n *\n * calculate the determinant of a 4x4 matrix.\n */\ndouble det4x4(const float m[16])\n{\n    double ans;\n    double a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;\n\n    double det3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3);\n\n    /* assign to individual variable names to aid selecting */\n    /*  correct elements */\n\n    a1 = m[0 * 4 + 0];\n    b1 = m[0 * 4 + 1];\n    c1 = m[0 * 4 + 2];\n    d1 = m[0 * 4 + 3];\n\n    a2 = m[1 * 4 + 0];\n    b2 = m[1 * 4 + 1];\n    c2 = m[1 * 4 + 2];\n    d2 = m[1 * 4 + 3];\n\n    a3 = m[2 * 4 + 0];\n    b3 = m[2 * 4 + 1];\n    c3 = m[2 * 4 + 2];\n    d3 = m[2 * 4 + 3];\n\n    a4 = m[3 * 4 + 0];\n    b4 = m[3 * 4 + 1];\n    c4 = m[3 * 4 + 2];\n    d4 = m[3 * 4 + 3];\n\n    ans = a1 * det3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) - b1 * det3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + c1 * det3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)\n        - d1 * det3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);\n    return ans;\n}\n\n/*\n * double = det3x3(  a1, a2, a3, b1, b2, b3, c1, c2, c3 )\n *\n * calculate the determinant of a 3x3 matrix\n * in the form\n *\n *     | a1,  b1,  c1 |\n *     | a2,  b2,  c2 |\n *     | a3,  b3,  c3 |\n */\n\ndouble det3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)\n{\n    double ans;\n    double det2x2(double a, double b, double c, double d);\n\n    ans = a1 * det2x2(b2, b3, c2, c3) - b1 * det2x2(a2, a3, c2, c3) + c1 * det2x2(a2, a3, b2, b3);\n    return ans;\n}\n\n/*\n * double = det2x2( double a, double b, double c, double d )\n *\n * calculate the determinant of a 2x2 matrix.\n */\n\ndouble det2x2(double a, double b, double c, double d)\n{\n    double ans;\n    ans = a * d - b * c;\n    return ans;\n}\n\n/*\n * Return true, if n is a power of 2.\n */\nbool powerOf2(size_t n) { return (n & (n - 1)) == 0; }\n\n/*\n * Return the next power of 2 that is equal or larger than n\n */\nsize_t nextPowerOf2(size_t n)\n{\n    if (powerOf2(n)) return n;\n\n    size_t p;\n\n    for (int i = 63; i >= 0; i--) {\n        p = n & ((size_t)1 << i);\n\n        if (p) {\n            p = ((size_t)1 << (i + 1));\n            break;\n        }\n    }\n\n    return p;\n}\n\n// Some routines to handle 3x3 rotation matrices, represented as 9 floats,\n// where the column index increments faster\nvoid mmult33(const double *m1, const double *m2, double *result)\n{\n    for (int row = 0; row < 3; row++) {\n        for (int col = 0; col < 3; col++) { result[row * 3 + col] = (m1[row * 3] * m2[col] + m1[1 + row * 3] * m2[col + 3] + m1[2 + row * 3] * m2[col + 6]); }\n    }\n}\n\n// Same as above, but use the transpose (i.e. inverse for rotations) on the left\nvoid mmultt33(const double *m1Trans, const double *m2, double *result)\n{\n    for (int row = 0; row < 3; row++) {\n        for (int col = 0; col < 3; col++) { result[row * 3 + col] = (m1Trans[row] * m2[col] + m1Trans[3 + row] * m2[col + 3] + m1Trans[6 + row] * m2[col + 6]); }\n    }\n}\n\n// Determine a rotation matrix from (theta, phi, psi) (radians), that is,\n// find the rotation matrix that first rotates in (x,y) by psi, then takes the vector (0,0,1)\n// to the vector with direction (theta,phi) by rotating by phi in the (x,z) plane and then\n// rotating in the (x,y)plane by theta.\nvoid getRotationMatrix(double theta, double phi, double psi, double *matrix)\n{\n    // do the theta-phi rotation first:\n    double mtrx1[9], mtrx2[9];\n    double cosTheta = cos(theta);\n    double sinTheta = sin(theta);\n    double cosPhi = cos(phi);\n    double sinPhi = sin(phi);\n    double cosPsi = cos(psi);\n    double sinPsi = sin(psi);\n    // specify mtrx1 as an (X,Z) rotation by -phi, followed by an (X,Y) rotation by theta:\n    mtrx1[0] = cosTheta * cosPhi;\n    mtrx1[1] = -sinTheta;\n    mtrx1[2] = cosTheta * sinPhi;\n    // 2nd row:\n    mtrx1[3] = sinTheta * cosPhi;\n    mtrx1[4] = cosTheta;\n    mtrx1[5] = sinTheta * sinPhi;\n    // 3rd row:\n    mtrx1[6] = -sinPhi;\n    mtrx1[7] = 0.f;\n    mtrx1[8] = cosPhi;\n    // mtrx2 is a rotation by psi in the x,y plane:\n    mtrx2[0] = cosPsi;\n    mtrx2[1] = -sinPsi;\n    mtrx2[2] = 0.f;\n    mtrx2[3] = sinPsi;\n    mtrx2[4] = cosPsi;\n    mtrx2[5] = 0.f;\n    mtrx2[6] = 0.f;\n    mtrx2[7] = 0.f;\n    mtrx2[8] = 1.f;\n    mmult33(mtrx1, mtrx2, matrix);\n}\n\n// Determine a rotation matrix about an axis:\nCOMMON_API void getAxisRotation(int axis, double rotation, double *matrix)\n{\n    for (int col = 0; col < 3; col++) {\n        for (int row = 0; row < 3; row++) {\n            if (row == axis && col == axis)\n                matrix[col + row * 3] = 1.f;\n            else if (row == axis || col == axis)\n                matrix[col + row * 3] = 0.f;\n            else {\n                if (row == col)\n                    matrix[col + row * 3] = cos(rotation);\n                else if (row > col)\n                    matrix[col + row * 3] = sin(rotation);\n                else\n                    matrix[col + row * 3] = -sin(rotation);\n            }\n        }\n    }\n}\n\n// Determine the psi, phi, theta (radians!) from a rotation matrix.\n// the rotation matrix rotates about the z-axis by psi,\n// then takes the z-axis to the unit vector with spherical\n// coordinates theta and phi.\nvoid getRotAngles(double *theta, double *phi, double *psi, const double *matrix)\n{\n    // First find phi and theta by looking at matrix applied to 0,0,1:\n    double vec[3];\n    double tempPhi, tempTheta;\n    double tempPsi = 0.;\n    double tMatrix1[9], tMatrix2[9];\n    vec[0] = matrix[2];\n    vec[1] = matrix[5];\n    vec[2] = matrix[8];\n    // float cosPhi = vec[2];\n    tempPhi = acos(vec[2]);    // unique angle between 0 and pi\n    // now project vec[0], vec[1] to x,y plane:\n\n    double normsq = (vec[0] * vec[0] + vec[1] * vec[1]);\n    if (normsq == 0.)\n        tempTheta = 0.;\n    else {\n        tempTheta = acos(vec[0] / sqrt(normsq));\n        // If sin(theta)<0 then theta is negative:\n        if (vec[1] < 0) tempTheta = -tempTheta;\n    }\n    // Find the transformation determined by theta, phi:\n    getRotationMatrix(tempTheta, tempPhi, tempPsi, tMatrix1);\n\n    // Apply the inverse of this to the input matrix:\n    mmultt33(tMatrix1, matrix, tMatrix2);\n    // Now the resulting matrix is a rotation by psi\n    // Cos psi and sin psi are in the first column:\n    if (std::abs(tMatrix2[0]) > 1.f) {\n        if (tMatrix2[0] > 0.f)\n            tMatrix2[0] = 1.f;\n        else\n            tMatrix2[0] = -1.f;\n    }\n    tempPsi = acos(tMatrix2[0]);\n    if (tMatrix2[3] < 0.f) tempPsi = -tempPsi;\n\n    *theta = tempTheta;\n    *phi = tempPhi;\n    *psi = tempPsi;\n    return;\n}\n// Intersect a ray with an axis-aligned box.\n// Ray is specified by start point and direction vector.\n// Box is specified by 6 floats (extents)\n// Return value is number of intersections found,\n// Results are specified as floats, increasing order, indicating the position R on the ray where\n// intersection = rayStart+R*rayDir.\nint rayBoxIntersect(const float rayStart[3], const float rayDir[3], const float boxExts[6], float results[2])\n{\n    // Loop over axes of cube.  Intersect faces with the ray, then test if it's inside box extents:\n    int numfound = 0;\n    for (int axis = 0; axis < 3; axis++) {\n        // Points along ray are rayStart+t*rayDir.\n        // To intersect face, rayStart+t*rayDir has axis coordinate equal to boxExts[axis] or boxExts[axis+3]\n        // so that t = (boxExts[axis+(0 or 3)] - rayStart[axis])/rayDir[axis];\n        if (rayDir[axis] == 0.f) continue;    // Plane is parallel to ray\n        // check front and back intersections:\n        for (int frontBack = 0; frontBack < 4; frontBack += 3) {\n            float t = (boxExts[axis + frontBack] - rayStart[axis]) / rayDir[axis];\n            // Check to see if point is within other two box bounds\n            float intersectPoint[3];\n            for (int j = 0; j < 3; j++) { intersectPoint[j] = rayStart[j] + t * rayDir[j]; }\n            bool pointOK = true;\n            for (int otherCoord = 0; otherCoord < 3; otherCoord++) {\n                if (otherCoord == axis) continue;\n                if (intersectPoint[otherCoord] < boxExts[otherCoord]) {\n                    pointOK = false;\n                    break;\n                }\n                if (intersectPoint[otherCoord] > boxExts[otherCoord + 3]) {\n                    pointOK = false;\n                    break;\n                }\n            }\n            if (pointOK) {\n                // Found an intersection!\n                results[numfound++] = t;\n                // order the points in increasing t:\n                if (numfound == 2 && (results[1] < results[0])) {\n                    float temp = results[0];\n                    results[0] = results[1];\n                    results[1] = temp;\n                }\n                if (numfound == 2) return numfound;\n            }\n        }\n    }\n    return numfound;\n}\nint rayBoxIntersect(const double rayStart[3], const double rayDir[3], const double boxExts[6], double results[2])\n{\n    // Loop over axes of cube.  Intersect faces with the ray, then test if it's inside box extents:\n    // Return at most two intersections, the max and min along the ray.\n    int    numfound = 0;\n    double tempResults[6];\n    double epsilons[3];    // Error tolerance is size/10^6\n    for (int i = 0; i < 3; i++) epsilons[i] = (boxExts[i + 3] - boxExts[i]) * 1.e-6;\n    for (int axis = 0; axis < 3; axis++) {\n        if (numfound == 6) break;\n        // Points along ray are rayStart+t*rayDir.\n        // To intersect face, rayStart+t*rayDir has axis coordinate equal to boxExts[axis] or boxExts[axis+3]\n        // so that t = (boxExts[axis+(0 or 3)] - rayStart[axis])/rayDir[axis];\n        if (rayDir[axis] == 0.) continue;    // Plane is parallel to ray\n        // check front and back intersections:\n        for (int frontBack = 0; frontBack < 4; frontBack += 3) {\n            float t = (boxExts[axis + frontBack] - rayStart[axis]) / rayDir[axis];\n            // Check to see if point is within other two box bounds\n            float intersectPoint[3];\n            for (int j = 0; j < 3; j++) { intersectPoint[j] = rayStart[j] + t * rayDir[j]; }\n            bool pointOK = true;\n            for (int otherCoord = 0; otherCoord < 3; otherCoord++) {\n                if (otherCoord == axis) continue;\n                if (intersectPoint[otherCoord] < boxExts[otherCoord] - epsilons[otherCoord]) {\n                    pointOK = false;\n                    break;\n                }\n                if (intersectPoint[otherCoord] > boxExts[otherCoord + 3] + epsilons[otherCoord]) {\n                    pointOK = false;\n                    break;\n                }\n            }\n            if (pointOK) {\n                // Found an intersection!\n                tempResults[numfound++] = t;\n            }\n            if (numfound == 6) break;\n        }\n    }\n    if (numfound == 0) return 0;\n    // Find the max and min t\n    double mint = DBL_MAX;\n    double maxt = -DBL_MAX;\n\n    for (int i = 0; i < numfound; i++) {\n        if (tempResults[i] < mint) { mint = tempResults[i]; }\n        if (tempResults[i] > maxt) { maxt = tempResults[i]; }\n    }\n    results[0] = mint;\n    if (numfound == 1) return 1;\n    results[1] = maxt;\n    return 2;\n}\n// Project box corners to ray\n// Ray is specified by start point and direction vector.\n// Box is specified by 6 doubles (extents)\n// Results are specified as doubles, increasing order, indicating the position R on the ray where\n// the corner is projected\nvoid rayBoxProject(vector<double> rayStart, vector<double> rayDir, const double boxExts[6], double results[2])\n{\n    // For each box corner,\n    // project to line of view\n    double cor[3], wrk[3], dir[3];\n    double maxProj = -DBL_MAX;\n    double minProj = DBL_MAX;\n    // Make sure rayDir is normalized:\n    for (int i = 0; i < 3; i++) dir[i] = rayDir[i];\n    vnormal(dir);\n    for (int i = 0; i < 8; i++) {\n        for (int j = 0; j < 3; j++) { cor[j] = ((i >> j) & 1) ? boxExts[j + 3] : boxExts[j]; }\n\n        vsub(cor, rayStart, wrk);\n\n        double mdist = vdot(wrk, dir);\n        if (minProj > mdist) { minProj = mdist; }\n        if (maxProj < mdist) { maxProj = mdist; }\n    }\n    results[0] = minProj;\n    results[1] = maxProj;\n}\n// Convert a camera view to a quaternion, for linear interpolation of viewpoints.\n\nvoid view2Quat(float vdir[3], float upvec[3], float q[4])\n{\n    float vtemp[3];\n    float left[3] = {-1.f, 0.f, 0.f};\n    float ydir[3] = {0.f, 1.f, 0.f};\n    float right[3];\n    // Normalize the vectors:\n    vnormal(upvec);\n    vnormal(vdir);\n    // Force the up vector to be orthogonal to viewDir\n    vcopy(vdir, vtemp);\n    vscale(vtemp, vdot(vdir, upvec));\n    // Subtract the component of up in the viewdir direction\n    vsub(upvec, vtemp, upvec);\n    // Make sure it's still valid\n    if (vdot(upvec, upvec) == 0.f) {\n        // First try up = viewdir x left\n        vcross(vdir, left, upvec);\n        if (vdot(upvec, upvec) == 0.f) {\n            // try viewdir x ydir\n            vcross(vdir, ydir, upvec);\n        }\n    }\n    vnormal(upvec);\n    // calculate \"right\" vector:\n    vcross(vdir, upvec, right);\n    // Construct 4x4 matrix.  Just because rotmatrix2q expects 4x4\n    float minv[16];\n    // Bottom row, right column not needed.\n    minv[3] = 0.f;\n    minv[7] = 0.f;\n    minv[11] = 0.f;\n    minv[15] = 1.f;\n    // copy in first 3 elements of columns\n    vcopy(right, minv);\n    vcopy(upvec, minv + 4);\n    // third col is neg of viewdir\n\n    vcopy(vdir, minv + 8);\n    vscale(minv + 8, -1.f);\n    vzero(minv + 12);\n    minv[15] = 1.f;\n    rotmatrix2q(minv, q);\n}\n\n// Convert two camera views to two pure imaginary quaternion, for linear interpolation of viewpoints.\n// If dot product is negative, the first quaternion is negated, to prevent interpolating the long way around.\nvoid views2ImagQuats(float vdir1[3], float upvec1[3], float vdir2[3], float upvec2[3], float q1[3], float q2[3])\n{\n    float quat1[4], quat2[4];\n    view2Quat(vdir1, upvec1, quat1);\n    view2Quat(vdir2, upvec2, quat2);\n    float dotprod = 0.;\n    for (int i = 0; i < 4; i++) dotprod += quat1[i] * quat2[i];\n    if (dotprod < 0.f)\n        for (int i = 0; i < 4; i++) quat1[i] = -quat1[i];\n    qnormal(quat2);    // force full quaternion to be norm-1 (correct round-off error)\n    qnormal(quat1);\n    float mag = vlength(quat1);    // norm of imaginary part\n    float re = acos(quat1[3]);\n    if (mag == 0.f)\n        for (int i = 0; i < 3; i++) q1[i] = 0.f;\n    else\n        for (int i = 0; i < 3; i++) q1[i] = quat1[i] * re / mag;\n    mag = vlength(quat2);    // norm of imaginary part\n    re = acos(quat2[3]);\n    if (mag == 0.f)\n        for (int i = 0; i < 3; i++) q2[i] = 0.f;\n    else\n        for (int i = 0; i < 3; i++) q2[i] = quat2[i] * re / mag;\n    return;\n}\n// Convert a pure-imaginary quaternion to camera view, for linear interpolation of viewpoints.\n\nvoid imagQuat2View(const float q[3], float vdir[3], float upvec[3])\n{\n    float quat[4];\n    float mtrx[16];\n    // First, calc exponential of q:\n    float mag = vlength(q);\n    quat[3] = cos(mag);\n    if (mag > 0.f) {\n        float s = sin(mag) / mag;\n        for (int i = 0; i < 3; i++) quat[i] = q[i] * s;\n    } else {\n        for (int i = 0; i < 3; i++) quat[i] = 0.f;\n    }\n    // then convert quat to a matrix\n    qmatrix(quat, mtrx);\n    // extract rows:\n    vcopy(mtrx + 4, upvec);\n    vcopy(mtrx + 8, vdir);\n    vscale(vdir, -1.f);\n}\nvoid quat2View(float quat[4], float vdir[3], float upvec[3])\n{\n    float mtrx[16];\n    // convert quat to a matrix\n    qmatrix(quat, mtrx);\n    // extract rows:\n    vcopy(mtrx + 4, upvec);\n    vcopy(mtrx + 8, vdir);\n    vscale(vdir, -1.f);\n}\n// Spherical linear interpolation between two unit quaternions.  t is between 0 and 1.\nvoid slerp(float quat0[4], float quat1[4], float t, float result[4])\n{\n    // Wikipedia:  slerp = q0*(q0^-1 * q1)**t\n    float q0inv[4], res1[4], res2[4], V[3];\n    // make sure they are unit quaternion:\n    qnormal(quat0);\n    qnormal(quat1);\n\n    // calculate quat0 inv\n    for (int i = 0; i < 3; i++) q0inv[i] = -quat0[i];\n    q0inv[3] = quat0[3];\n    qmult(q0inv, quat1, res1);\n    // now take res1 to power t:\n    // First express res1 as cos theta + V sin theta, = exp(theta*V)\n    if (res1[3] > 1.0) res1[3] = 1.0;\n    if (res1[3] < -1.0) res1[3] = -1.0;\n    double theta = acos((double)res1[3]);\n    float  sinTheta = sin(theta);\n\n    if (sinTheta == 0.f) {\n        vzero(V);\n    } else {\n        vcopy(res1, V);\n        vscale(V, 1. / sinTheta);\n    }\n    // Now take to power t, i.e. cos(t*theta)+sin(t*theta)*V\n    res2[3] = cos(t * theta);\n    for (int i = 0; i < 3; i++) res2[i] = V[i] * sin(t * theta);\n\n    // then multiply on the left by quat0:\n    qmult(quat0, res2, result);\n}\n// Logarithm of a unit quaternion\nvoid qlog(float quat[4], float quatlog[4])\n{\n    // express quat as cos theta + V sin theta, = exp(theta*V)\n    float V[3];\n    if (quat[3] > 1.0) quat[3] = 1.0;\n    if (quat[3] < -1.0) quat[3] = -1.0;\n    double theta = acos((double)quat[3]);\n    float  sinTheta = sin(theta);\n    if (sinTheta == 0.f) {\n        vzero(V);\n    } else {\n        vcopy(quat, V);\n        vscale(V, theta / sinTheta);\n    }\n    vcopy(V, quatlog);\n    quatlog[3] = 0.f;\n}\nvoid squad(float quat1[4], float quat2[4], float s1[4], float s2[4], float t, float result[4])\n{\n    float qa[4], qb[4];\n    slerp(quat1, quat2, t, qa);\n    slerp(s1, s2, t, qb);\n    slerp(qa, qb, 2. * t * (1. - t), result);\n}\nvoid qconj(float quat[4], float conj[4])\n{\n    conj[3] = quat[3];\n    conj[0] = -quat[0];\n    conj[1] = -quat[1];\n    conj[2] = -quat[2];\n}\nvoid doubleToString(const double d, string &s, int digits)\n{\n    char buf[30];\n    snprintf(buf, 30, \"%-.*G\", digits, d);\n    string ss(buf);\n    s = ss;\n}\n#define VAPOR3_0_0_ALPHA\n#ifdef VAPOR3_0_0_ALPHA\n\n    // Macros\n    #define LINEAR_INDEX(dim, x, y, z) ((x) + (dim[0]) * ((y) + (z) * (dim[1])))\n    #define sqr(x)                     ((x) * (x))\n\nvoid computeGradientData(int dim[3], int numChan, unsigned char *volume, unsigned char *gradient)\n{\n    for (int z = 0; z < dim[2]; z++)\n        for (int y = 0; y < dim[1]; y++)\n            for (int x = 0; x < dim[0]; x++) {\n                float gradient_temp[3];\n\n                // The following code computes the gradient for the volume data.\n                // For volumes with more than one channel, only the first channel\n                // is used to compute the gradient! The voxel index computation is\n                // very inefficient and can be optimized a lot using a simple\n                // incremental computation.\n\n                // Handle border cases correctly by using forward and backward\n                // differencing for the boundaries.\n                if (x == 0)\n                    // forward differencing\n                    gradient_temp[0] = ((float)volume[numChan * LINEAR_INDEX(dim, x + 1, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z)]);\n                else if (x == dim[0] - 1)\n                    // backward differencing\n                    gradient_temp[0] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x - 1, y, z)]);\n                else\n                    // central differencing\n                    gradient_temp[0] = (((float)volume[numChan * LINEAR_INDEX(dim, x + 1, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x - 1, y, z)]) / 2.0);\n\n                if (y == 0)\n                    gradient_temp[1] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y + 1, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z)]);\n                else if (y == dim[1] - 1)\n                    gradient_temp[1] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y - 1, z)]);\n                else\n                    gradient_temp[1] = (((float)volume[numChan * LINEAR_INDEX(dim, x, y + 1, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y - 1, z)]) / 2.0);\n\n                if (z == 0)\n                    gradient_temp[2] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y, z + 1)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z)]);\n                else if (z == dim[2] - 1)\n                    gradient_temp[2] = ((float)volume[numChan * LINEAR_INDEX(dim, x, y, z)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z - 1)]);\n                else\n                    gradient_temp[2] = (((float)volume[numChan * LINEAR_INDEX(dim, x, y, z + 1)] - (float)volume[numChan * LINEAR_INDEX(dim, x, y, z - 1)]) / 2.0);\n\n                // compute the magintude for the gradient\n                double mag = (sqrt(sqr(gradient_temp[0]) + sqr(gradient_temp[1]) + sqr(gradient_temp[2])));\n\n                // avoid any divide by zeros!\n                if (mag > 0.01) {\n                    gradient_temp[0] /= mag;\n                    gradient_temp[1] /= mag;\n                    gradient_temp[2] /= mag;\n                } else {\n                    gradient_temp[0] = gradient_temp[1] = gradient_temp[2] = 0.0;\n                }\n\n                // Map the floating point gradient values to the appropriate range\n                // in unsigned byte\n                unsigned long index = 4 * (LINEAR_INDEX(dim, x, y, z));\n                for (int i = 0; i < 3; i++) { gradient[index + i] = (signed char)floor(gradient_temp[i] * 128.0); }\n\n                // Set the alpha to be 1.0\n                gradient[index + 3] = 255;\n            }\n}\n\n#endif\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/common/MyBase.cpp",
    "content": "#include <cstdarg>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include \"vapor/VAssert.h\"\n#include <cerrno>\n#include <cctype>\n#include <string>\n#include <vector>\n#include <iostream>\n#include <sstream>\n\n#include <vapor/MyBase.h>\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n    #include \"windows.h\"\n#endif\n\n#include <iostream>\n\nusing namespace Wasp;\n\nusing namespace std;\n\n#ifdef NEW_DEBUG\nvoid *operator new(size_t sz)\n{\n    void *p = malloc(sz);\n    std::cout << \"Malloc \" << sz << \" bytes\" << endl;\n    if (!p) {\n        std::cerr << \"Malloc \" << sz << \" bytes failed!!!\" << endl;\n        exit(1);\n    }\n\n    return (p);\n}\n\nvoid *operator new[](size_t sz)\n{\n    void *p = malloc(sz);\n    cout << \"Malloc \" << sz << \" bytes\" << endl;\n\n    if (!p) {\n        std::cerr << \"Malloc \" << sz << \" bytes failed!!!\" << endl;\n        exit(1);\n    }\n    return (p);\n}\n#endif\n\nchar *MyBase::ErrMsg = NULL;\nint   MyBase::ErrMsgSize = 0;\nint   MyBase::ErrCode = 0;\nFILE *MyBase::ErrMsgFilePtr = NULL;\nvoid (*MyBase::ErrMsgCB)(const char *msg, int err_code) = NULL;\n\nchar *MyBase::DiagMsg = NULL;\nint   MyBase::DiagMsgSize = 0;\n#ifdef DEBUG\nFILE *MyBase::DiagMsgFilePtr = stderr;\n#else\nFILE *MyBase::DiagMsgFilePtr = NULL;\n#endif\nvoid (*MyBase::DiagMsgCB)(const char *msg) = NULL;\n\nbool MyBase::Enabled = true;\n\nMyBase::MyBase() { SetClassName(\"MyBase\"); }\n\nvoid MyBase::_SetErrMsg(char **msgbuf, int *msgbufsz, const char *format, va_list args)\n{\n    int       done = 0;\n    const int alloc_size = 4096;\n    int       rc;\n    //#ifdef WIN32\n    // CHAR szBuf[80];\n\n    // DWORD dw = GetLastError();\n\n    // sprintf(szBuf, \"Reporting error message: GetLastError returned %u\\n\", dw);\n    // MessageBox(NULL, szBuf, \"Error\", MB_OK);\n    //#endif\n    if (!*msgbuf) {\n        *msgbuf = new char[alloc_size];\n        VAssert(*msgbuf != NULL);\n        *msgbufsz = alloc_size;\n    }\n\n    string formatstr(format);\n    size_t loc;\n    while ((loc = formatstr.find(\"%M\", 0)) != string::npos) { formatstr.replace(loc, 2, strerror(errno), strlen(strerror(errno))); }\n\n    format = formatstr.c_str();\n\n    // Loop until we've successfully buffered the error message, growing\n    // the message buffer as needed\n    //\n    va_list argscopy;\n    while (!done) {\n        va_copy(argscopy, args);\n#ifdef WIN32\n        rc = _vsnprintf(*msgbuf, *msgbufsz, format, argscopy);\n\n#else\n        rc = vsnprintf(*msgbuf, *msgbufsz, format, argscopy);\n#endif\n        va_end(argscopy);\n\n        if (rc < (*msgbufsz - 1)) {\n            done = 1;\n        } else {\n            if (*msgbuf) delete[] * msgbuf;\n            *msgbuf = new char[*msgbufsz + alloc_size];\n            VAssert(*msgbuf != NULL);\n            *msgbufsz += alloc_size;\n        }\n    }\n}\n\nvoid MyBase::SetErrMsg(const char *format, ...)\n{\n    va_list args;    // initialize to make valgrind shutup\n\n    if (!Enabled) return;\n    ErrCode = 1;\n\n    va_start(args, format);\n    _SetErrMsg(&ErrMsg, &ErrMsgSize, format, args);\n    va_end(args);\n\n    if (ErrMsgCB) (*ErrMsgCB)(ErrMsg, ErrCode);\n\n    if (ErrMsgFilePtr) { (void)fprintf(ErrMsgFilePtr, \"%s\\n\", ErrMsg); }\n}\n\nvoid MyBase::SetErrMsg(int errcode, const char *format, ...)\n{\n    va_list args;    // initialize to make valgrind shutup\n\n    if (!Enabled) return;\n    ErrCode = errcode;\n\n    va_start(args, format);\n    _SetErrMsg(&ErrMsg, &ErrMsgSize, format, args);\n    va_end(args);\n\n    if (ErrMsgCB) (*ErrMsgCB)(ErrMsg, ErrCode);\n\n    if (ErrMsgFilePtr) { (void)fprintf(ErrMsgFilePtr, \"%s\\n\", ErrMsg); }\n}\n\nvoid MyBase::SetDiagMsg(const char *format, ...)\n{\n    va_list args;    // initialize to make valgrind shutup\n\n    va_start(args, format);\n    _SetErrMsg(&DiagMsg, &DiagMsgSize, format, args);\n    va_end(args);\n\n    if (DiagMsgCB) (*DiagMsgCB)(DiagMsg);\n\n    if (DiagMsgFilePtr) { (void)fprintf(DiagMsgFilePtr, \"%s\\n\", DiagMsg); }\n}\n\nint Wasp::IsPowerOfTwo(unsigned int x)\n{\n    if (!x) return 1;\n    while (!(x & 1)) x >>= 1;\n    return (x == 1);\n}\n\n// Find integer log, base 2, of a 32-bit positive integer:\nint Wasp::ILog2(int n)\n{\n    int i;\n    for (i = 0; i < 31; i++) {\n        if (n <= (1 << i)) break;\n    }\n    return i;\n}\nint Wasp::StrCmpNoCase(const string &s, const string &t)\n{\n    string::const_iterator sptr = s.begin();\n    string::const_iterator tptr = t.begin();\n\n    while (sptr != s.end() && tptr != t.end()) {\n        if (toupper(*sptr) != toupper(*tptr)) { return (toupper(*sptr) < toupper(*tptr) ? -1 : 1); }\n        *sptr++;\n        *tptr++;\n    }\n\n    return ((s.size() == t.size()) ? 0 : ((s.size() < t.size()) ? -1 : 1));\n}\n\nvoid Wasp::StrRmWhiteSpace(string &s)\n{\n    string::size_type i;\n\n    if (s.length() < 1) return;\n\n    i = 0;\n    while (i < s.length() && isspace(s[i])) i++;\n\n    if (i > 0) { s.replace(0, i, \"\", 0); }\n\n    if (s.length() < 1) return;\n    i = s.length() - 1;\n\n    while (isspace(s[i])) i--;\n\n    if (i < (s.length() - 1)) { s.replace(i + 1, s.length() - i + 1, \"\", 0); }\n}\n\nvoid Wasp::StrToWordVec(const string &s, vector<string> &v)\n{\n    string tmp = s;\n    v.clear();\n    while (!tmp.empty()) {\n        while (!tmp.empty() && isspace(tmp[0])) tmp.erase(0, 1);\n\n        int index = 0;\n        while (index < tmp.length()) {\n            if (isspace(tmp[index]))\n                if (index == 0 || tmp[index - 1] != '\\\\') break;\n            index++;\n        }\n\n        if (index) {\n            string word = tmp.substr(0, index);\n            v.push_back(word);\n            tmp.erase(0, index);\n        }\n    }\n}\n\nstd::vector<std::string> &Wasp::SplitString(const std::string &s, char delim, std::vector<std::string> &elems)\n{\n    elems.clear();\n\n    stringstream ss(s);\n    string       item;\n    while (getline(ss, item, delim)) {\n        if (!item.empty()) elems.push_back(item);\n    }\n    return elems;\n}\n\nnamespace {\n\ntemplate<class T> vector<T> &splitStringTemplate(const std::string &s, char delim, std::vector<T> &elems)\n{\n    elems.clear();\n    vector<string> tokens;\n    (void)Wasp::SplitString(s, delim, tokens);\n    for (int i = 0; i < tokens.size(); i++) {\n        stringstream ss(tokens[i]);\n        T            elem;\n        ss >> elem;\n        elems.push_back(elem);\n    }\n    return (elems);\n}\n\n};    // namespace\n\nstd::vector<size_t> &Wasp::SplitString(const std::string &s, char delim, std::vector<size_t> &elems) { return (splitStringTemplate(s, delim, elems)); }\n\nstd::vector<int> &Wasp::SplitString(const std::string &s, char delim, std::vector<int> &elems) { return (splitStringTemplate(s, delim, elems)); }\n\nstd::vector<float> &Wasp::SplitString(const std::string &s, char delim, std::vector<float> &elems) { return (splitStringTemplate(s, delim, elems)); }\n\nstd::vector<double> &Wasp::SplitString(const std::string &s, char delim, std::vector<double> &elems) { return (splitStringTemplate(s, delim, elems)); }\n\nunsigned long long Wasp::GetBits64(unsigned long long targ, int pos, int n) { return ((targ >> (pos + 1 - n)) & ~(~0ULL << n)); }\n\nunsigned long long Wasp::SetBits64(unsigned long long targ, int pos, int n, unsigned long long src)\n{\n    targ &= ~(~(~0ULL << n) << (pos + 1 - n));\n    targ |= (src & ~(~0ULL << n)) << (pos + 1 - n);\n    return (targ);\n}\n// From Numerical Recipes in C\n/*\nMinimal\" random number generator of Park and Miller with Bays-Durham shuffle and\nsafeguards. Returns a uniform random deviate between 0.0 and 1.0 (exclusive of the endpoint\nvalues). Call with idum a negative integer to initialize; thereafter, do not alter idum between\nsuccessive deviates in a sequence. RNMX should approximate the largest floating value that is\nless than 1.\n*/\n#define IA   16807\n#define IM   2147483647\n#define AM   (1.0 / IM)\n#define IQ   127773\n#define IR   2836\n#define NTAB 32\n#define NDIV (1 + (IM - 1) / NTAB)\n#define EPS  1.2e-7\n#define RNMX (1.0 - EPS)\n\ndouble Wasp::ran1(long *idum)\n{\n    int         j;\n    long        k;\n    static long iy = 0;\n    static long iv[NTAB];\n    double      temp;\n\n    if (*idum <= 0 || !iy) {\n        if (-(*idum) < 1)\n            *idum = 1;\n        else\n            *idum = -(*idum);\n        for (j = NTAB + 7; j >= 0; j--) {\n            k = (*idum) / IQ;\n            *idum = IA * (*idum - k * IQ) - IR * k;\n            if (*idum < 0) *idum += IM;\n            if (j < NTAB) iv[j] = *idum;\n        }\n        iy = iv[0];\n    }\n    k = (*idum) / IQ;\n    *idum = IA * (*idum - k * IQ) - IR * k;\n    if (*idum < 0) *idum += IM;\n    j = iy / NDIV;\n    iy = iv[j];\n    iv[j] = *idum;\n    if ((temp = AM * iy) > RNMX)\n        return RNMX;\n    else\n        return temp;\n}\n"
  },
  {
    "path": "lib/common/OptionParser.cpp",
    "content": "#include <cstdio>\n#include <cstdlib>\n#include <vector>\n#include <cstring>\n#include <algorithm>\n#include <vapor/OptionParser.h>\n#include \"vapor/VAssert.h\"\n#include <cctype>\n#include <sstream>\n#include <locale>\n#include <vapor/Version.h>\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n#endif\n\nusing namespace Wasp;\n\nnamespace Wasp {\nbool opt_cmp(OptionParser::_OptRec_T *a, OptionParser::_OptRec_T *b) { return (string(a->option) < string(b->option)); };\n}    // namespace Wasp\n\n/*\n * convert an array of strings into a singe contiguous array of strings\n */\nchar *copy_create_arg_string(char **argv, int argc)\n{\n    char *s, *t;\n    int   i, len; /* lenght of new arg string\t*/\n\n    for (len = 0, i = 0; i < argc; i++) {\n        len += (int)strlen(argv[i]);\n        len++; /* one for the space\t*/\n    }\n    s = (char *)malloc(len + 1);\n    VAssert(s != NULL);\n\n    s = strcpy(s, argv[0]);\n    for (i = 1, t = s; i < argc; i++) {\n        t += strlen(t);\n        *t++ = '\\0';\n        (void)strcpy(t, argv[i]);\n    }\n    return (s);\n}\n\n/*\n * convert a space seprated string to an array of contiguous strings\n */\nchar *fmt_opt_string(char *arg, int n)\n{\n    int   i;\n    char *s;\n\n    for (i = 1, s = arg; i < n; i++) {\n        while (*s && !isspace(*s)) s++;\n\n        if (!*s) { return (NULL); }\n        *s++ = '\\0';\n\n        while (*s && isspace(*s)) s++;\n    }\n    return (arg);\n}\n\n/*\n**\n**\tType converters. The following functions convert string representations\n**\tof data into their primitive data formats. A NULL 'from' value\n**\tshould result in a reasonable value.\n**\n*/\n\n/*\n *\tCvtToInt()\n *\n *\tconvert a ascii string to its integer value\n */\nint Wasp::CvtToInt(const char *from, /* the string\t*/\n                   void *      to)\n{\n    int *iptr = (int *)to;\n\n    if (!from) {\n        *iptr = 0;\n    } else if (sscanf(from, \"%d\", iptr) != 1) {\n        return (-1);\n    }\n    return (1);\n}\n\n/*\n *\tCvtToFloat()\n *\n *\tconvert a ascii string to its floating point value\n */\nint Wasp::CvtToFloat(const char *from, /* the string\t*/\n                     void *      to)\n{\n    float *fptr = (float *)to;\n\n    if (!from) {\n        *fptr = 0.0;\n    } else if (sscanf(from, \"%f\", fptr) != 1) {\n        return (-1);\n    }\n    return (1);\n}\n\n/*\n *\tCvtToDouble()\n *\n *\tconvert a ascii string to its floating point value\n */\nint Wasp::CvtToDouble(const char *from, /* the string\t*/\n                      void *      to)\n{\n    double *dptr = (double *)to;\n\n    if (!from) {\n        *dptr = 0.0;\n    } else if (sscanf(from, \"%lf\", dptr) != 1) {\n        return (-1);\n    }\n    return (1);\n}\n\n/*\n *\tCvtToChar()\n *\n *\tconvert a ascii string to a char.\n */\nint Wasp::CvtToChar(const char *from, /* the string\t*/\n                    void *      to)\n{\n    char *cptr = (char *)to;\n\n    if (!from) {\n        *cptr = '\\0';\n    } else if (sscanf(from, \"%c\", cptr) != 1) {\n        return (-1);\n    }\n    return (1);\n}\n\n/*\n *\tConvetToBoolean()\n *\n *\tconvert a ascii string containing either \"true\" or \"false\" to\n *\tto TRUE or FALSE\n */\nint Wasp::CvtToBoolean(const char *from, /* the string\t*/\n                       void *      to)\n{\n    OptionParser::Boolean_T *bptr = (OptionParser::Boolean_T *)to;\n\n    if (!from) {\n        *bptr = 0;\n    } else if (strcmp(\"true\", from) == 0) {\n        *bptr = 1;\n    } else if (strcmp(\"false\", from) == 0) {\n        *bptr = 0;\n    } else {\n        return (-1);\n    }\n    return (1);\n}\n\n/*\n *\tCvtToString()\n *\n */\nint Wasp::CvtToString(const char *from, /* the string\t*/\n                      void *      to)\n{\n    char **sptr = (char **)to;\n\n    *sptr = (char *)from;\n\n    return (1);\n}\n\n/*\n *\tCvtToCPPStr()\n *\n */\nint Wasp::CvtToCPPStr(const char *from, /* the string\t*/\n                      void *      to)\n{\n    string *sptr = (string *)to;\n\n    *sptr = from;\n\n    return (1);\n}\n\n/*\n *\tCvtToDimension2D()\n *\n *\tconvert a ascii string to a dimension.\n */\nint Wasp::CvtToDimension2D(const char *from, /* the string\t*/\n                           void *      to)\n{\n    OptionParser::Dimension2D_T *dptr = (OptionParser::Dimension2D_T *)to;\n\n    if (!from) {\n        dptr->nx = dptr->ny = 0;\n    } else if (!((sscanf(from, \"%dx%d\", &(dptr->nx), &(dptr->ny)) == 2) || (sscanf(from, \"%dX%d\", &(dptr->nx), &(dptr->ny)) == 2))) {\n        return (-1);\n    }\n    return (1);\n}\n\n//\n//\tCvtToDimension3D()\n//\n//\tconvert an ascii string to a 3D dimension.\n///\nint Wasp::CvtToDimension3D(const char *from, /* the string\t*/\n                           void *      to)\n{\n    OptionParser::Dimension3D_T *dptr = (OptionParser::Dimension3D_T *)to;\n\n    if (!from) {\n        dptr->nx = dptr->ny = dptr->nz = 0;\n    } else if (!((sscanf(from, \"%dx%dx%d\", &(dptr->nx), &(dptr->ny), &(dptr->nz)) == 3) || (sscanf(from, \"%dX%dX%d\", &(dptr->nx), &(dptr->ny), &(dptr->nz)) == 3))) {\n        return (-1);\n    }\n    return (1);\n}\n\n//\n//\tCvtToStrVec()\n//\n//\tconvert a colon delimited ascii string to vector of C++ STL strings\n//\nint Wasp::CvtToStrVec(const char *from, /* the string\t*/\n                      void *      to)\n{\n    vector<string> *vptr = (vector<string> *)to;\n    vptr->clear();\n\n    (void)SplitString(from, ':', *vptr);\n\n    return (1);\n}\n//\n//\tCvtToIntVec()\n//\n//\tconvert a colon delimited ascii string to vector of C++ STL ints\n//\nint Wasp::CvtToIntVec(const char *from, /* the string\t*/\n                      void *      to)\n{\n    vector<int> *vptr = (vector<int> *)to;\n    vptr->clear();\n\n    string s(from);\n    char   delim;\n    if (s.find(\":\") != string::npos) {\n        delim = ':';\n    } else {\n        delim = 'x';\n    }\n    (void)SplitString(from, delim, *vptr);\n\n    return (1);\n}\n\n//\n//\tCvtToSize_tVec()\n//\n//\tconvert a colon delimited ascii string to vector of C++ STL size_t\n//\nint Wasp::CvtToSize_tVec(const char *from, /* the string\t*/\n                         void *      to)\n{\n    vector<size_t> *vptr = (vector<size_t> *)to;\n    vptr->clear();\n\n    string s(from);\n    char   delim;\n    if (s.find(\":\") != string::npos) {\n        delim = ':';\n    } else {\n        delim = 'x';\n    }\n    (void)SplitString(from, delim, *vptr);\n\n    return (1);\n}\n\n//\n//\tCvtToFloatVec()\n//\n//\tconvert a colon delimited ascii string to vector of C++ STL float\n//\nint Wasp::CvtToFloatVec(const char *from, /* the string\t*/\n                        void *      to)\n{\n    vector<float> *vptr = (vector<float> *)to;\n    vptr->clear();\n\n    string s(from);\n    char   delim;\n    if (s.find(\":\") != string::npos) {\n        delim = ':';\n    } else {\n        delim = 'x';\n    }\n    (void)SplitString(from, delim, *vptr);\n\n    return (1);\n}\n\n//\n//\tCvtToDoubleVec()\n//\n//\tconvert a colon delimited ascii string to vector of C++ STL float\n//\nint Wasp::CvtToDoubleVec(const char *from, /* the string\t*/\n                         void *      to)\n{\n    vector<double> *vptr = (vector<double> *)to;\n    vptr->clear();\n\n    string s(from);\n    char   delim;\n    if (s.find(\":\") != string::npos) {\n        delim = ':';\n    } else {\n        delim = 'x';\n    }\n    (void)SplitString(from, delim, *vptr);\n\n    return (1);\n}\n\n//\n//\tCvtToIntRange()\n//\n//\tconvert a colon-delimited string of ints to a min/max pair\n///\nint Wasp::CvtToIntRange(const char *from, /* the string\t*/\n                        void *      to)\n{\n    OptionParser::IntRange_T *dptr = (OptionParser::IntRange_T *)to;\n\n    if (!from) {\n        dptr->min = dptr->max = 0;\n    } else if (!((sscanf(from, \"%d:%d\", &(dptr->min), &(dptr->max))) == 2)) {\n        return (-1);\n    }\n    return (1);\n}\n\nOptionParser::OptionParser() { _optTbl.clear(); }\n\nOptionParser::~OptionParser()\n{\n    _OptRec_T *o;\n\n    for (int i = 0; i < (int)_optTbl.size(); i++) {\n        o = _optTbl[i];\n        if (o->option) free((void *)o->option);\n        if (o->value) free((void *)o->value);\n        if (o->default_value) free((void *)o->default_value);\n        if (o->help) free((void *)o->help);\n        delete o;\n    }\n    _optTbl.clear();\n}\n\n/*\n *\tAppendOptions\n *\n *\tAdd a list of valid application options to the option table. All\n *\toptions are assumed to begin with a '-' and contain 0 or more arguments.\n *\n *\tThe fields of the DPOptDescRec struct are as follows:\n *\n *\tchar\t*option;\tname of option without preceeding '-'\n *\tint\targ_count;\tnum args expected by option\n *\tchar\t*value;\t\tdefault value for the argument - if 'arg_count'\n *\t\t\t\tis zero 'value' is ignored. if 'arg_count' is\n *\t\t\t\tgreater than 1 'value' is a string of space\n *\t\t\t\tseparted arguments.\n *\tchar\t*help;\t\thelp string for option\n *\n *\n * on entry\n *\tod\t\t: option descriptor\n *\toptd\t\t: Null terminated list of options\n *\n * on exit\n *\treturn\t\t: -1 => failure, else OK.\n */\nint OptionParser::AppendOptions(const OptDescRec_T *odr)\n{\n    int        i, j;\n    int        num;\n    _OptRec_T *opt_rec;\n\n    if (!odr[0].option) return (0);\n\n    /*\n     * make sure there are no duplicate names in the table. This only\n     * compares new entries with old entries. If there are duplicate\n     * entries within the new entries they won't be found. Count\n     * how many options there are as well\n     */\n    for (j = 0, num = 0; odr[j].option; j++) {\n        for (i = 0; i < (int)_optTbl.size(); i++) {\n            if (strcmp(_optTbl[i]->option, odr[j].option) == 0) {\n                SetErrMsg(\"Option %s already in option table\", odr[j].option);\n                return (-1); /* duplicate entry\t*/\n            }\n        }\n        num++;\n    }\n\n    /*\n     * copy all the options into the option table allocating memory\n     * as necessary.\n     */\n    for (i = 0; i < num; i++) {\n        opt_rec = new _OptRec_T;\n\n        _optTbl.push_back(opt_rec);\n\n        char *value = NULL;\n\n        if (odr[i].arg_count == 0) {\n            value = strdup(\"false\");\n        } else {\n            if (odr[i].value) value = strdup(odr[i].value);\n        }\n\n        if (!odr[i].option) {\n            SetErrMsg(\"Invalid option descriptor\");\n            return (-1);\n        }\n\n        if (value) {\n            value = fmt_opt_string(value, odr[i].arg_count);\n            if (!value) {\n                SetErrMsg(\"Arg string invalid: %s\", value);\n                return (-1);\n            }\n        }\n\n        opt_rec->option = strdup(odr[i].option);\n        opt_rec->default_value = value;\n        opt_rec->value = strdup(value);\n        opt_rec->help = strdup(odr[i].help);\n        opt_rec->arg_count = odr[i].arg_count;\n    }\n\n    return (0);\n}\n\n/*\n *\tRemoveOptions\n *\t[exported]\n *\n *\tRemove a list of application options from the option table.\n *\tOnly the 'option' field of the DPOptDescRec struct is referenced,\n *\tall other fields are ignored. The options to be freed must have\n *\tpreviously been set with a call to DPLoadOptionTable().\n *\n *\n * on entry\n *\tod\t\t: option descriptor\n *\todr\t\t: Null terminated list of options\n *\n */\nvoid OptionParser::RemoveOptions(vector<string> options)\n{\n    int                           j;\n    vector<_OptRec_T *>::iterator itr;\n\n    /*\n     * look for the option in the option table.\n     */\n    for (j = 0; j < options.size(); j++) {\n        for (itr = _optTbl.begin(); itr != _optTbl.end(); ++itr) {\n            _OptRec_T *o = *itr;\n            if (options[j].compare(o->option) == 0) {\n                if (o->option) free((void *)o->option);\n                if (o->value) free((void *)o->value);\n                if (o->default_value) free((void *)o->default_value);\n                if (o->help) free((void *)o->help);\n                _optTbl.erase(itr);\n                break;\n            }\n        }\n    }\n}\n\n/*\n *\tParseOption\n *\t[exported]\n *\n *\tparse the option table with the command line options. After the\n *\toption table is created with DPLoadOptionTable this function may\n *\tbe called to change values of options in the table. We assume\n *\targv[0] is the program name and we leave it unmolested\n *\n *\tDPErrLog() is invoked on error.\n *\n * on entry:\n *\t**argv\t\t: list of command line args\n *\t*argc\t\t: num elements in argv\n *\t*optds\t\t: additional options to merge into the option table\n * on exit\n *\t**argv\t\t: contains options not found in the option table\n *\t*argc\t\t: num elements in argv\n *\treturn\t\t: -1 => failure, else OK\n */\nint OptionParser::ParseOptions(int *argc, char **argv, Option_T *options)\n{\n    int        i;\n    int        new_argc = 1;\n    char **    next = argv + 1;\n    _OptRec_T *o;\n\n    if (!argv) return (1);\n\n    /*\n    **\tRestore default values for options in option table\n    */\n    for (i = 0; i < (int)_optTbl.size(); i++) {\n        o = _optTbl[i];\n        if (o->value) free((void *)o->value);\n        o->value = strdup(o->default_value);\n    }\n\n    /*\n     * look for matches between elements in argv and in the option table\n     */\n    for (i = 1; i < *argc; i++) {\n        if (*argv[i] == '-') { /* is it an option specifier?\t*/\n            o = _get_option((char *)(argv[i] + 1));\n        } else {\n            o = (_OptRec_T *)NULL; /* not a specifier */\n        }\n\n        if (o == (_OptRec_T *)-1) {\n            SetErrMsg(\"Ambiguous option: %s\", argv[i]);\n            return (-1);\n        }\n\n        /*\n         * if no match found leave option in argv along with anything\n         * that follows that is not an option specifier\n         */\n        if (!o) { /* not found\t*/\n            *next = argv[i];\n            new_argc++;\n            next++;\n            while (i + 1 < *argc && *argv[i + 1] != '-') {\n                i++;\n                new_argc++;\n                *next = argv[i];\n                next++;\n            }\n            continue;\n        }\n\n        /*\n         * make sure enough args for option\n         */\n        if ((i + o->arg_count) >= *argc) {\n            SetErrMsg(\"Option -%s expects %d args\", o->option, o->arg_count);\n            return (-1);\n        }\n\n        /*\n         * Options with no args are a special case. Assign them\n         * a value of true. They are false by default\n         */\n        if (o->arg_count == 0) {\n            o->value = strdup(\"true\");\n            continue;\n        }\n\n        /*\n         * convert the arg list to a single string and stash it\n         * in the option table\n         */\n        o->value = copy_create_arg_string(&argv[i + 1], o->arg_count);\n        i += o->arg_count;\n    }\n    *argc = new_argc;\n    argv[*argc] = NULL;\n\n    return (_parse_options(options));\n\n    return (0);\n}\n\n/*\n *\tDPParseEnvOptions()\n *\n *\tDPParseEnvOptions() is analogous to DPParseOptionTable except that\n *\tit takes a list of environment variables and their coresponding\n *\toption names instead of an argv list. If a given environment\n *\tvariable is set its value is used as the argument value for the\n *\toption with  which it is associated. If the environment variable\n *\tis not set the option/environemnt variable pair are ignored.\n *\n * on entry\n *\t*envv\t\t: NUll-terminated list of option/env pairs\n *\t*optds\t\t: additional options to merge into the option table\n *\n * on exit\n *\treturn\t\t: -1 => error, else OK\n */\nint OptionParser::ParseOptions(const EnvOpt_T *envv, Option_T *opts)\n{\n    const EnvOpt_T *envptr;     /* pointer to envv\t\t*/\n    char **         argv;       /* arg vector created from envv\t*/\n    int             argc;       /* size of argv list\t\t*/\n    char *          arg_string; /* env variable value\t\t*/\n    int             i;\n\n    // count the args\n    for (envptr = envv, argc = 0; envptr->option; envptr++, argc += 2)\n        ;\n\n    argv = new char *[argc + 2];\n    argv[0] = strdup(\"place_holder\");\n\n    /*\n     * look for environment variables. Generate the argument vector, argv\n     */\n\n    for (envptr = envv, i = 1; envptr->option; envptr++, i += 2) {\n        if ((arg_string = getenv(envptr->env_var))) {\n            argv[i] = new char[strlen(arg_string + 2)];\n            argv[i] = strcpy(argv[i], \"-\");\n            argv[i] = strcat(argv[i], envptr->option);\n            argv[i + 1] = strdup(arg_string);\n        }\n    }\n    argv[i] = NULL;\n\n    return (ParseOptions(&argc, argv, opts));\n}\n\n//\n//\tPrintOptionHelp()\n//\n//\tPrint help about each option.\n//\n//\tEach option known to the option table is printed, followed by\n//\tthe string \"arg0 arg1 ... argN\", where N+1 is the number of arguments\n//\texpected by the option, followed by the contents of the 'help' field.\n//\n// on entry\n//\t*fp\t\t: file pointer where output is written.\n//\nvoid OptionParser::PrintOptionHelp(FILE *fp, int linelimit, bool docopyright)\n{\n    std::sort(_optTbl.begin(), _optTbl.end(), opt_cmp);\n\n    string h1(\"OPTION\");\n    string d1(\"------\");\n    string h2(\"NUM_ARGS\");\n    string d2(\"--------\");\n    string h3(\"DEFAULT\");\n    string d3(\"-------\");\n    int    f1 = h1.size();\n    int    f2 = h2.size();\n    int    f3 = h3.size();\n    for (int i = 0; i < (int)_optTbl.size(); i++) {\n        string option = _optTbl[i]->option;\n        if (option.size() > f1) f1 = option.size();\n\n        string default_value = _optTbl[i]->default_value;\n        if (default_value.size() > f3) f3 = default_value.size();\n    }\n    f1 += 4;\n    f2 += 4;\n    f3 += 4;\n    ostringstream format;\n    format << \"    \";\n    format << \"%-\";\n    format << f1;\n    format << \".\";\n    format << f1;\n    format << \"s\";\n    format << \"%-\";\n    format << f2;\n    format << \".\";\n    format << f2;\n    format << \"s\";\n    format << \"%-\";\n    format << f3;\n    format << \".\";\n    format << f3;\n    format << \"s\";\n\n    fprintf(fp, format.str().c_str(), h1.c_str(), h2.c_str(), h3.c_str());\n    fprintf(fp, \"\\n\");\n    fprintf(fp, format.str().c_str(), d1.c_str(), d2.c_str(), d3.c_str());\n    fprintf(fp, \"\\n\");\n\n    string margin(\"        \");\n    for (int i = 0; i < (int)_optTbl.size(); i++) {\n        _OptRec_T *   o = _optTbl[i];\n        ostringstream arg_count_str;\n        arg_count_str << o->arg_count;\n        string option = \"-\";\n        option.append(o->option);\n        string defvalstr(o->default_value);\n        if (!defvalstr.size()) defvalstr = \"\\\"\\\"\";\n\n        fprintf(fp, format.str().c_str(), option.c_str(), arg_count_str.str().c_str(), defvalstr.c_str());\n\n        vector<string> helpvec;\n        string         helpstr(o->help);\n        StrToWordVec(helpstr, helpvec);\n\n        int linecount = linelimit;\n        for (int j = 0; j < helpvec.size(); j++) {\n            if (linecount + helpvec[j].size() < linelimit) {\n                fprintf(fp, \"%s \", helpvec[j].c_str());\n                linecount += helpvec[j].size() + 1;\n            } else {\n                linecount = 0;\n                fprintf(fp, \"\\n%s%s \", margin.c_str(), helpvec[j].c_str());\n                linecount += margin.size() + helpvec[j].size() + 1;\n            }\n        }\n        fprintf(fp, \"\\n\");\n    }\n\n#ifdef VAPOR3_0_0_ALPHA\n    for (i = 0; i < (int)_optTbl.size(); i++) {\n        _OptRec_T *o = _optTbl[i];\n\n        sprintf(buf, \"    -%-8.8s\", o->option);\n        if (o->arg_count < 4) {\n            for (j = 0; j < o->arg_count; j++) {\n                sprintf(sbf, \" arg%d\", j);\n                if (strlen(sbf) + strlen(buf) < sizeof(buf)) {\n                    (void)strcat(buf, sbf);\n                } else {\n                    break;\n                }\n            }\n        } else {\n            sprintf(sbf, \" arg0 .. arg%d\", o->arg_count - 1);\n            (void)strcat(buf, sbf);\n        }\n        (void)fprintf(fp, buf);\n        for (j = (int)strlen(buf); j < (int)sizeof(buf); j++) { putc(' ', fp); }\n        if (o->help) {\n            (void)fprintf(fp, \"%s\\n\", (char *)o->help);\n        } else {\n            (void)fprintf(fp, \"\\n\");\n        }\n    }\n#endif\n\n    if (!docopyright) return;\n\n    fprintf(fp, \"\\nCopyright 2007 The National Center for Atmospheric Research\\n\");\n\n    fprintf(fp, \"\\nVersion: %s (%s) www.vapor.ucar.edu\\n\", Version::GetVersionString().c_str(), Version::GetDateString().c_str());\n}\n\n//\n//\tget_option\n//\t[internal]\n//\n// on entry\n//\t*name\t\t: name to lookup\n// on exit\n//\treturn\t\t: if found return command obj ptr. If name is ambiguous\n//\t\t\t  return -1. If not found return NULL.\n//\nOptionParser::_OptRec_T *OptionParser::_get_option(const char *name)\n{\n    _OptRec_T *o;\n    _OptRec_T *found;\n    int        nmatches;\n    int        i;\n\n    nmatches = 0;\n    found = NULL;\n\n    for (i = 0; i < (int)_optTbl.size(); i++) {\n        o = _optTbl[i];\n\n        if (strcmp(o->option, name) == 0) {\n            return (o);    // exact match\n        }\n\n        if (strncmp(o->option, name, strlen(name)) == 0) {\n            nmatches++;\n            found = o;\n        };\n    }\n\n    if (nmatches > 1) /* ambiguous\t*/\n        return ((_OptRec_T *)-1);\n\n    return (found);\n}\n\n//\n//\n//\t_parse_options\n//\n//\tThe fields of the Option struct are as follows:\n//\n//\tchar\t\t*option_name;\tthe options name - used to look the\n//\t\t\t\t\trequested option in the option table.\n//\tint\t\t(*type_conv)();\toption type converter - converts the\n//\t\t\t\t\tstring representation of the option\n//\t\t\t\t\tvalue into a specified format and store\n//\t\t\t\t\tthe result at address given by 'offset'\n//\tvoid\t\t*offset;\toffset of return address\n//\tint\t\tsize;\t\tsize of option in bytes - if there are\n//\t\t\t\t\tmultiple arguments for a single option\n//\t\t\t\t\ttheir destination address is computed\n//\t\t\t\t\tby adding 'size' to 'offset' as\n//\t\t\t\t\tappropriate.\n//\n//\n// on entry\n//\toptions\t\t: Null terminated list of options to be returned\n//\n// on exit\n//\toptions\t\t: offset field of options record filled in\n//\treturn\t\t: -1 => failure, else OK\n//\nint OptionParser::_parse_options(const Option_T *options)\n{\n    int         i, j;\n    const char *s;\n    int         arg_count;\n\n    _OptRec_T *o;\n    void *     offset;\n\n    for (i = 0; options[i].option_name; i++) {\n        /*\n         * find the option */\n        o = _get_option(options[i].option_name);\n        if (o == (_OptRec_T *)-1) {\n            SetErrMsg(\"Ambiguous option: %s\", options[i].option_name);\n            return (-1);\n        }\n\n        if (!o) {\n            //\t\t\tSetErrMsg(\"Option %s unknown\", options[i].option_name);\n            //\t\t\treturn(-1);\n            continue;\n        }\n\n        /*\n         * zero arg_count options really do have a single argument\n         */\n        arg_count = o->arg_count ? o->arg_count : 1;\n\n        offset = options[i].offset;\n        for (j = 0, s = o->value; j < arg_count; j++) {\n            if (options[i].type_conv(s, offset) < 0) {\n                SetErrMsg(\"Type converter for option \\\"-%s\\\" \"\n                          \"failed to convert argument \\\"%s\\\"\",\n                          options[i].option_name, s);\n                return (-1);\n            }\n            if (s) s += strlen(s) + 1;\n            offset = (char *)offset + options[i].size;\n        }\n    }\n    return (0);\n}\n"
  },
  {
    "path": "lib/common/PVTime.cpp",
    "content": "//\n// $Id$\n//\n\n// pivotal_gmtime_r - a replacement for gmtime/localtime/mktime\n//                   that works around the 2038 bug on 32-bit\n//                    systems. (Version 3)\n//\n// Copyright (C) 2005  Paul Sheer\n//\n// Redistribution and use in source form, with or without modification,\n// is permitted provided that the above copyright notice, this list of\n// conditions, the following disclaimer, and the following char array\n// are retained.\n//\n// Redistribution and use in binary form must reproduce an\n//\n// acknowledgment: 'With software provided by http://2038bug.com/' in\n// the documentation and/or other materials provided with the\n// distribution, and wherever such acknowledgments are usually\n// accessible in Your program.\n//\n// This software is provided \"AS IS\" and WITHOUT WARRANTY, either\n// express or implied, including, without limitation, the warranties of\n// NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\n// PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THIS SOFTWARE IS WITH\n// YOU. Under no circumstances and under no legal theory, whether in\n// tort (including negligence), contract, or otherwise, shall the\n// copyright owners be liable for any direct, indirect, special,\n// incidental, or consequential damages of any character arising as a\n// result of the use of this software including, without limitation,\n// damages for loss of goodwill, work stoppage, computer failure or\n// malfunction, or any and all other commercial damages or losses. This\n// limitation of liability shall not apply to liability for death or\n// personal injury resulting from copyright owners' negligence to the\n// extent applicable law prohibits such limitation. Some jurisdictions\n// do not allow the exclusion or limitation of incidental or\n// consequential damages, so this exclusion and limitation may not apply\n// to You.\n\n#include <cstdarg>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include \"vapor/VAssert.h\"\n#include <cerrno>\n#include <ctime>\n#include <vapor/PVTime.h>\n\nusing namespace Wasp;\n\n// mktime64() is a 64-bit equivalent of mktime().\n// localtime64_r() is a 64-bit equivalent of localtime_r().\n// gmtime64_r() is a 64-bit equivalent of gmtime_r().\n\nstatic const int days[4][13] = {\n    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},\n    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},\n    {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},\n    {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},\n};\n\n#define LEAP_CHECK(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) != 0)\n#define WRAP(a, b, m) ((a) = ((a) < 0) ? ((b)--, (a) + (m)) : (a))\n\nTIME64_T pivot_time_t(const time_t *now, TIME64_T *_t)\n{\n    TIME64_T t;\n    t = *_t;\n    if (now && sizeof(time_t) == 4) {\n        time_t _now;\n        _now = *now;\n        if (_now < 1106500000 /* Jan 23 2005 - date of writing */) _now = 2147483647;\n        if ((TIME64_T)t + ((TIME64_T)1 << 31) < (TIME64_T)_now) t += (TIME64_T)1 << 32;\n    }\n    return t;\n}\n\nstatic struct tm *_gmtime64_r(const time_t *now, TIME64_T *_t, struct tm *p)\n{\n    int      v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday, v_tm_tday;\n    int      leap;\n    TIME64_T t;\n    long     m;\n    t = pivot_time_t(now, _t);\n    v_tm_sec = ((TIME64_T)t % (TIME64_T)60);\n    t /= 60;\n    v_tm_min = ((TIME64_T)t % (TIME64_T)60);\n    t /= 60;\n    v_tm_hour = ((TIME64_T)t % (TIME64_T)24);\n    t /= 24;\n    v_tm_tday = t;\n    WRAP(v_tm_sec, v_tm_min, 60);\n    WRAP(v_tm_min, v_tm_hour, 60);\n    WRAP(v_tm_hour, v_tm_tday, 24);\n    if ((v_tm_wday = (v_tm_tday + 4) % 7) < 0) v_tm_wday += 7;\n    m = (long)v_tm_tday;\n    if (m >= 0) {\n        p->tm_year = 70;\n        leap = LEAP_CHECK(p->tm_year);\n        while (m >= (long)days[leap + 2][12]) {\n            m -= (long)days[leap + 2][12];\n            p->tm_year++;\n            leap = LEAP_CHECK(p->tm_year);\n        }\n        v_tm_mon = 0;\n        while (m >= (long)days[leap][v_tm_mon]) {\n            m -= (long)days[leap][v_tm_mon];\n            v_tm_mon++;\n        }\n    } else {\n        p->tm_year = 69;\n        leap = LEAP_CHECK(p->tm_year);\n        while (m < (long)-days[leap + 2][12]) {\n            m += (long)days[leap + 2][12];\n            p->tm_year--;\n            leap = LEAP_CHECK(p->tm_year);\n        }\n        v_tm_mon = 11;\n        while (m < (long)-days[leap][v_tm_mon]) {\n            m += (long)days[leap][v_tm_mon];\n            v_tm_mon--;\n        }\n        m += (long)days[leap][v_tm_mon];\n    }\n    p->tm_mday = (int)m + 1;\n    p->tm_yday = days[leap + 2][v_tm_mon] + m;\n    p->tm_sec = v_tm_sec, p->tm_min = v_tm_min, p->tm_hour = v_tm_hour, p->tm_mon = v_tm_mon, p->tm_wday = v_tm_wday;\n    return p;\n}\n\nstatic struct tm *_localtime64_r(const time_t *now, TIME64_T *_t, struct tm *p)\n{\n    TIME64_T  tl;\n    time_t    t;\n    struct tm tm, tm_localtime, tm_gmtime;\n    _gmtime64_r(now, _t, &tm);\n    if (tm.tm_year > (2037 - 1900)) tm.tm_year = 2037 - 1900;\n    t = MkTime64(&tm);\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n    struct tm *tm_localtime_ptr, *tm_gmtime_ptr;\n\n    tm_localtime_ptr = localtime(&t);\n    tm_localtime = *tm_localtime_ptr;\n\n    tm_gmtime_ptr = gmtime(&t);\n    tm_gmtime = *tm_gmtime_ptr;\n#else\n    localtime_r(&t, &tm_localtime);\n    gmtime_r(&t, &tm_gmtime);\n#endif\n    tl = *_t;\n    tl += (MkTime64(&tm_localtime) - MkTime64(&tm_gmtime));\n    _gmtime64_r(now, &tl, p);\n    p->tm_isdst = tm_localtime.tm_isdst;\n    return p;\n}\n\nstruct tm *Wasp::GmTime64_r(const TIME64_T *_t, struct tm *p)\n{\n    TIME64_T t;\n    t = *_t;\n    return _gmtime64_r(NULL, &t, p);\n}\n\nTIME64_T Wasp::MkTime64(struct tm *t)\n{\n    int      i, y;\n    long     day = 0;\n    TIME64_T r;\n    if (t->tm_year < 70) {\n        y = 69;\n        do {\n            day -= 365 + LEAP_CHECK(y);\n            y--;\n        } while (y >= t->tm_year);\n    } else {\n        y = 70;\n        while (y < t->tm_year) {\n            day += 365 + LEAP_CHECK(y);\n            y++;\n        }\n    }\n    for (i = 0; i < t->tm_mon; i++) day += days[LEAP_CHECK(t->tm_year)][i];\n    day += t->tm_mday - 1;\n    t->tm_wday = (int)((day + 4) % 7);\n    r = (TIME64_T)day * 86400;\n    r += t->tm_hour * 3600;\n    r += t->tm_min * 60;\n    r += t->tm_sec;\n    return r;\n}\n\nstruct tm *Wasp::LocalTime64_r(const TIME64_T *_t, struct tm *p)\n{\n    TIME64_T tl;\n    tl = *_t;\n    return _localtime64_r(NULL, &tl, p);\n}\n"
  },
  {
    "path": "lib/common/Progress.cpp",
    "content": "#include <vapor/Progress.h>\n#include <cassert>\n\nusing namespace VAPoR;\n\nProgress::Start_t  Progress::_start = [](const std::string &, long, bool) {};\nProgress::Update_t Progress::_update = [](long, bool *) {};\nProgress::Finish_t Progress::_finish = []() {};\n\nbool Progress::_cancelled = false;\nlong Progress::_total = 1;\n\nvoid Progress::Start(const std::string &name, long total, bool cancelable)\n{\n    _start(name, total, cancelable);\n    _cancelled = false;\n    _total = total;\n}\n\nvoid Progress::StartIndefinite(const std::string &name, bool cancelable) { Progress::Start(name, 0, cancelable); }\n\nvoid Progress::Update(long completed)\n{\n    if (_total > 100 && completed % (_total / 100) != 0 && completed != 0) return;\n    _update(completed, &_cancelled);\n}\n\nvoid Progress::Finish() { _finish(); }\n\nvoid Progress::SetHandlers(Start_t start, Update_t update, Finish_t finish)\n{\n    assert((bool)start);\n    assert((bool)update);\n    assert((bool)finish);\n\n    _start = start;\n    _update = update;\n    _finish = finish;\n}\n\n#ifndef NDEBUG\n#ifndef WIN32\n    #include <unistd.h>\nvoid Progress::Sleep(double s) { usleep(s * 1e6L); }\n#endif\n#endif\n"
  },
  {
    "path": "lib/common/ResourcePath.cpp",
    "content": "#include <iostream>\n#include <climits>\n#include <vapor/ResourcePath.h>\n#include <vapor/CMakeConfig.h>\n#include <vapor/FileUtils.h>\n#include <vapor/CFuncs.h>\n#include <cassert>\n\n#define INCLUDE_DEPRECATED_GET_APP_PATH\n#include \"vapor/GetAppPath.h\"\n\n#define FORCE_USE_DEV_LIBS 0\n#if FORCE_USE_DEV_LIBS\n    #ifndef NDEBUG\n        #error Forced use of development libraries enabled for release build\n    #endif\n#endif\n\n#ifdef Darwin\n    #include <CoreFoundation/CFBundle.h>\n\nstring GetMacBundlePath()\n{\n    CFBundleRef mainBundle = CFBundleGetMainBundle();\n    CFURLRef    resourcesURL = CFBundleCopyBundleURL(mainBundle);\n    CFStringRef str = CFURLCopyFileSystemPath(resourcesURL, kCFURLPOSIXPathStyle);\n    CFRelease(resourcesURL);\n    char path[PATH_MAX];\n\n    CFStringGetCString(str, path, PATH_MAX, kCFStringEncodingASCII);\n    CFRelease(str);\n\n    return string(path);\n}\n#endif\n\nstring CallGetAppPathForResourceName(const string &name)\n{\n    vector<string> dirs;\n    string         getAppPathName;\n\n    Wasp::SplitString(name, '/', dirs);\n\n    if (dirs.empty()) {\n        getAppPathName = \"home\";\n    } else {\n        getAppPathName = dirs[0];\n        dirs.erase(dirs.begin());\n    }\n\n    return Wasp::GetAppPath(\"VAPOR\", getAppPathName, dirs);\n}\n\nstring GetInstalledResourceRoot()\n{\n    string path;\n\n#if defined Darwin\n    path = GetMacBundlePath();\n    path = Wasp::FileUtils::JoinPaths({path, \"Contents\"});\n#elif defined WIN32\n    path = string(Wasp::GetEnvironmentalVariable(\"VAPOR3_HOME\"));\n#else\n    path = string(Wasp::GetEnvironmentalVariable(\"VAPOR_HOME\"));\n#endif\n\n    return path;\n}\n\n#define TRY_PATH(p) {                                 \\\n    string path = Wasp::FileUtils::POSIXPathToCurrentOS(p); \\\n    if (Wasp::FileUtils::Exists(path)) {return path;}         \\\n}\n\nstd::string (*resourceFinderCB)(const std::string &) = nullptr;\n\nstring GetResourcePathFromCallback(const std::string &name)\n{\n    if (resourceFinderCB)\n        return resourceFinderCB(name);\n    return \"\";\n}\n\nstd::string Wasp::GetResourcePath(const std::string &name)\n{\n#if FORCE_USE_DEV_LIBS\n    TRY_PATH(FileUtils::JoinPaths({SOURCE_DIR, name}));\n#else\n    TRY_PATH(GetResourcePathFromCallback(name));\n    TRY_PATH(FileUtils::JoinPaths({GetInstalledResourceRoot(), name}));\n    TRY_PATH(FileUtils::JoinPaths({SOURCE_DIR, name}));\n    TRY_PATH(FileUtils::JoinPaths({THIRD_PARTY_DIR, name}));\n    TRY_PATH(CallGetAppPathForResourceName(name));\n#endif\n\n    return \"\";\n}\n\nstd::string Wasp::GetSharePath(const std::string &name) { return GetResourcePath(\"share/\" + name); }\n\n#if defined(WIN32)\n    #define PYTHON_MODULE_SUBDIR (\"python\" + string(PYTHON_VERSION))\n#else\n    #define PYTHON_MODULE_SUBDIR (\"lib/python\" + string(PYTHON_VERSION))\n#endif\n\nstd::string Wasp::GetPythonVersion() { return std::string(PYTHON_VERSION); }\n\nstd::string Wasp::GetPythonPath()\n{\n    string path = GetResourcePath(PYTHON_MODULE_SUBDIR);\n\n    if (!FileUtils::Exists(path)) path = string(PYTHON_PATH);\n\n    return path;\n}\n\nstd::string Wasp::GetPythonDir()\n{\n    std::string path2;\n    #if defined(__APPLE__)\n        string path = GetResourcePath(\"Resources\");\n    #else\n        string path = GetResourcePath(\"\");\n    #endif\n    std::string modulePath = FileUtils::JoinPaths( {path, PYTHON_MODULE_SUBDIR} );\n    if (!FileUtils::Exists( modulePath )) path = string(PYTHON_DIR);\n    return path;\n}\n\nvoid Wasp::RegisterResourceFinder(std::string (*cb)(const std::string &))\n{\n    assert(resourceFinderCB == nullptr);\n    resourceFinderCB = cb;\n}\n"
  },
  {
    "path": "lib/common/STLUtils.cpp",
    "content": "#include <chrono>\n#include <vapor/STLUtils.h>\n\nusing std::string;\nusing std::vector;\n\nbool STLUtils::Contains(const std::string &toSearch, const std::string &query) { return toSearch.find(query) != string::npos; }\n\nbool STLUtils::ContainsIgnoreCase(const std::string &toSearch, const std::string &query) { return Contains(ToLower(toSearch), ToLower(query)); }\n\nbool STLUtils::EndsWith(const std::string &str, const std::string &match) { return str.size() >= match.size() && equal(match.begin(), match.end(), str.end() - match.size()); }\n\nbool STLUtils::BeginsWith(const std::string &str, const std::string &match) { return STLUtils::BeginsWith<string>(str, match); }\n\nstd::string STLUtils::ToLower(std::string str)\n{\n    std::transform(str.begin(), str.end(), str.begin(), ::tolower);\n    return str;\n}\n\nstd::vector<std::string> STLUtils::Split(std::string str, const std::string &delimeter)\n{\n    size_t         index;\n    vector<string> parts;\n    while ((index = str.find(delimeter)) != string::npos) {\n        parts.push_back(str.substr(0, index));\n        str.erase(0, index + delimeter.length());\n    }\n    parts.push_back(str);\n    return parts;\n}\n\nstd::string STLUtils::Join(const std::vector<std::string> &parts, const std::string &delimeter)\n{\n    string whole;\n    auto   itr = parts.begin();\n    if (itr != parts.end()) whole = *itr++;\n    for (; itr != parts.end(); ++itr) whole += delimeter + *itr;\n    return whole;\n}\n\nstd::string STLUtils::ReplaceAll(std::string source, const std::string &oldSegment, const std::string &newSegment)\n{\n    size_t start = 0;\n\n    size_t index;\n    while ((index = source.find(oldSegment, start)) != string::npos) {\n        source.replace(index, oldSegment.length(), newSegment);\n        start = index + newSegment.length();\n    }\n    return source;\n}\n\nstd::string STLUtils::GetCurrentDateTimestamp()\n{\n    auto now = std::chrono::system_clock::now();\n    std::time_t now_c = std::chrono::system_clock::to_time_t(now);\n    std::string timeString = std::ctime(&now_c);\n    timeString.pop_back(); // Remove trailing endline\n    return timeString;\n}\n"
  },
  {
    "path": "lib/common/TMSUtils.cpp",
    "content": "#include <iostream>\n#include <sstream>\n#include <algorithm>\n#include <sys/stat.h>\n#include <vapor/MyBase.h>\n#include <vapor/TMSUtils.h>\n\nusing namespace Wasp;\n\n//! Returns true if \\p path is a Tile Mapping Service master file\n//\nbool TMSUtils::IsTMSFile(std::string path)\n{\n    if (path.rfind(\".tms\", path.size() - 4) != string::npos) { return true; }\n    return false;\n}\n\n//! Returns the path to the TMS file containing the specified tile\n//\nstd::string TMSUtils::TilePath(string file, size_t tileX, size_t tileY, int lod)\n{\n    // If we're given a file instead of a directory, remove the .tms extension\n    //\n    if (file.rfind(\".tms\", file.size() - 4) != string::npos) { file.erase(file.length() - 4, 4); }\n\n    size_t tmsTileY = tileY;\n\n    ostringstream oss;\n    oss << file;\n    oss << \"/\";\n    oss << lod;\n    oss << \"/\";\n    oss << tileX;\n    oss << \"/\";\n    oss << tmsTileY;\n\n    string base = oss.str();\n\n    string path = base + \".tif\";\n\n    struct stat statbuf;\n    if (stat(path.c_str(), &statbuf) == 0) return (path);\n\n    path = base + \".tiff\";\n\n    if (stat(path.c_str(), &statbuf) == 0) return (path);\n\n    // Tile does not exist\n    //\n    return (\"\");\n}\n\n//! Returns the number of LODs in the TMS file referened by \\p file\n//\nint TMSUtils::GetNumTMSLODs(std::string file)\n{\n    int lod = 0;\n    while (TilePath(file, 0, 0, lod) != \"\") { lod++; }\n    return lod;\n}\n"
  },
  {
    "path": "lib/common/VAssert.cpp",
    "content": "#include <vapor/VAssert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <signal.h>\n#include <string.h>\n#include <vapor/FileUtils.h>\n\nvoid Wasp::_VAssertFailed(const char *expr, const char *path, const unsigned int line)\n{\n    char *fileName = strdup(FileUtils::Basename(std::string(path)).c_str());\n\n    fprintf(stderr, \"VAssert(%s) failed in %s, line %i\\n\", expr, fileName, line);\n\n    free(fileName);\n\n#ifdef NDEBUG\n    exit(1);\n#else\n    raise(SIGINT);\n#endif\n}\n"
  },
  {
    "path": "lib/common/Version.cpp",
    "content": "#include <cstdio>\n#include <cstdlib>\n#include <vector>\n#include <cstring>\n#include <iostream>\n#include <sstream>\n#include <vapor/MyBase.h>\n#include <vapor/Version.h>\n\nusing namespace Wasp;\nusing namespace std;\n\n//\n// If these aren't defined here, the module won't link!\n//\nstring Version::_formatString;\nstring Version::_dateString;\n\nconst int Version::_majorVersion = MAJOR;\nconst int Version::_minorVersion = MINOR;\nconst int Version::_minorMinorVersion = MICRO;\n\nconst string &Version::GetVersionString()\n{\n    ostringstream oss;\n    oss << _majorVersion << \".\" << _minorVersion << \".\" << _minorMinorVersion;\n    if (GetRC().length()) oss << \".\" << GetRC();\n    _formatString = oss.str();\n    StrRmWhiteSpace(_formatString);\n    return (_formatString);\n}\n\nconst string &Version::GetFullVersionString()\n{\n    ostringstream oss;\n    oss << _majorVersion << \".\" << _minorVersion << \".\" << _minorMinorVersion;\n    if (GetRC().length()) oss << \".\" << GetRC();\n    oss << \".\" << GetBuildHash();\n    _formatString = oss.str();\n    StrRmWhiteSpace(_formatString);\n    return (_formatString);\n}\n\nconst string Version::GetBuildHash()\n{\n    string hash = string(VERSION_COMMIT);\n    if (hash.empty())\n        return \"<debug>\";\n    else\n        return hash;\n}\n\nint Version::Compare(int major, int minor, int minorminor)\n{\n    if (major != _majorVersion) { return (major > _majorVersion ? -1 : 1); }\n    if (minor != _minorVersion) { return (minor > _minorVersion ? -1 : 1); }\n    if (minorminor != _minorMinorVersion) { return (minorminor > _minorMinorVersion ? -1 : 1); }\n\n    return (0);\n}\n\nnamespace {\nvector<string> split(string s, string delim)\n{\n    size_t         pos = 0;\n    vector<string> tokens;\n    while ((pos = s.find(delim)) != std::string::npos) {\n        tokens.push_back(s.substr(0, pos));\n        s.erase(0, pos + delim.length());\n    }\n    if (!s.empty()) tokens.push_back(s);\n\n    return (tokens);\n}\n};    // namespace\n\nvoid Version::Parse(string s, int &major, int &minor, int &minorminor, string &rc)\n{\n    StrRmWhiteSpace(s);\n\n    major = 0;\n    minor = 0;\n    minorminor = 0;\n    rc = \"\";\n\n    vector<string> tokens = split(s, \".\");\n\n    if (tokens.size() > 0) {\n        istringstream ist(tokens[0]);\n        if (!ist.eof()) ist >> major;\n    }\n    if (tokens.size() > 1) {\n        istringstream ist(tokens[1]);\n        if (!ist.eof()) ist >> minor;\n    }\n    if (tokens.size() > 2) {\n        istringstream ist(tokens[2]);\n        if (!ist.eof()) ist >> minorminor;\n    }\n    if (tokens.size() > 3) { rc = tokens[3]; }\n}\n\nint Version::Compare(string v1, string v2)\n{\n    StrRmWhiteSpace(v1);\n    StrRmWhiteSpace(v2);\n\n    int    major1, minor1, minorminor1;\n    string rc1;\n\n    int    major2, minor2, minorminor2;\n    string rc2;\n\n    Version::Parse(v1, major1, minor1, minorminor1, rc1);\n    Version::Parse(v2, major2, minor2, minorminor2, rc2);\n\n    if (major1 < major2)\n        return (-1);\n    else if (major1 > major2)\n        return (1);\n\n    if (minor1 < minor2)\n        return (-1);\n    else if (minor1 > minor2)\n        return (1);\n\n    if (minorminor1 < minorminor2)\n        return (-1);\n    else if (minorminor1 > minorminor2)\n        return (1);\n\n    //\n    // comparison for rc token isn't lexicographical: version strings\n    // without a rc token are greater than version strings with a rc token\n    //\n    if (rc1.length() && rc2.length()) {\n        if (StrCmpNoCase(rc1, rc2) < 0)\n            return (-1);\n        else if (StrCmpNoCase(rc1, rc2) > 0)\n            return (1);\n    } else if (rc1.length() && !rc2.length()) {\n        return (1);\n    } else if (!rc1.length() && rc2.length()) {\n        return (-1);\n    }\n\n    return (0);\n}\n"
  },
  {
    "path": "lib/common/common.cpp",
    "content": "// common.cpp : Defines the entry point for the DLL application.\r\n//\r\n\r\n#ifdef WIN32\r\n    #include <vapor/common.h>\r\n    #include \"windows.h\"\r\n\r\nBOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)\r\n{\r\n    switch (ul_reason_for_call) {\r\n    case DLL_PROCESS_ATTACH:\r\n    case DLL_THREAD_ATTACH:\r\n    case DLL_THREAD_DETACH:\r\n    case DLL_PROCESS_DETACH: break;\r\n    }\r\n    return TRUE;\r\n}\r\n/*\r\n// This is an example of an exported variable\r\nCOMMON_API int ncommon=0;\r\n\r\n// This is an example of an exported function.\r\nCOMMON_API int fncommon(void)\r\n{\r\n    return 42;\r\n}\r\n\r\n// This is the constructor of a class that has been exported.\r\n// see common.h for the class definition\r\nCcommon::Ccommon()\r\n{\r\n    return;\r\n}\r\n*/\r\n#endif\r\n"
  },
  {
    "path": "lib/common/utils.cpp",
    "content": "#include \"vapor/VAssert.h\"\n#include <iostream>\n#include <algorithm>\n#include <cmath>\n#include <vapor/utils.h>\n\n#define MAXCOORDS 4\n\nusing namespace std;\nusing namespace Wasp;\n\nvoid *SmartBuf::Alloc(size_t size)\n{\n    if (size <= _buf_sz) return (_buf);\n\n    if (_buf) delete[] _buf;\n\n    _buf = new unsigned char[size];\n    _buf_sz = size;\n    return (_buf);\n}\n\n// convert tuple of multi-dimensional coordinates, 'coord', for a space\n// with min and max bounds to a linear offset from 'min'\n//\nsize_t Wasp::LinearizeCoords(const size_t *coords, const size_t *min, const size_t *max, size_t n)\n{\n    size_t offset = 0;\n\n    for (size_t i = 0; i < n; i++) {\n        VAssert(coords[i] >= min[i]);\n        VAssert(coords[i] <= max[i]);\n    }\n\n    size_t factor = 1;\n    for (size_t i = 0; i < n; i++) {\n        offset += factor * (coords[i] - min[i]);\n        factor *= max[i] - min[i] + 1;\n    }\n    return (offset);\n}\n\nsize_t Wasp::LinearizeCoords(const std::vector<size_t> &coords, const std::vector<size_t> &dims)\n{\n    VAssert(coords.size() == dims.size());\n    return (LinearizeCoords(coords.data(), dims.data(), coords.size()));\n}\n\nsize_t Wasp::LinearizeCoords(const size_t *coords, const size_t *dims, size_t n)\n{\n    VAssert(n <= MAXCOORDS);\n    size_t min[MAXCOORDS];\n    size_t max[MAXCOORDS];\n\n    for (size_t i = 0; i < n; i++) {\n        min[i] = 0;\n        max[i] = dims[i] - 1;\n    }\n\n    size_t returnVal = Wasp::LinearizeCoords(coords, min, max, n);\n\n    return (returnVal);\n}\n\nsize_t Wasp::LinearizeCoords(const std::vector<size_t> &coords, const std::vector<size_t> &min, const std::vector<size_t> &max)\n{\n    VAssert(coords.size() == min.size());\n    VAssert(coords.size() == max.size());\n    return (LinearizeCoords(coords.data(), min.data(), max.data(), coords.size()));\n}\n\nvoid Wasp::VectorizeCoords(size_t offset, const size_t *min, const size_t *max, size_t *coords, size_t n)\n{\n    size_t factor = 1;\n    for (size_t i = 0; i < n; i++) {\n        VAssert(min[i] <= max[i]);\n        coords[i] = (offset % (factor * (max[i] - min[i] + 1))) / factor;\n        offset = offset - coords[i] * factor;\n        factor *= (max[i] - min[i] + 1);\n    }\n    VAssert(offset == 0);\n}\n\nstd::vector<size_t> Wasp::VectorizeCoords(size_t offset, const std::vector<size_t> &min, const std::vector<size_t> &max)\n{\n    VAssert(min.size() == max.size());\n\n    size_t coords[MAXCOORDS];\n    VectorizeCoords(offset, min.data(), max.data(), coords, min.size());\n    std::vector<size_t> coordsvec(min.size(), 0);\n    for (int i = 0; i < min.size(); i++) coordsvec[i] = coords[i];\n    return (coordsvec);\n}\n\nvoid Wasp::VectorizeCoords(size_t offset, const size_t *dims, size_t *coords, size_t n)\n{\n    VAssert(n <= MAXCOORDS);\n    size_t min[MAXCOORDS];\n    size_t max[MAXCOORDS];\n    for (size_t i = 0; i < n; i++) {\n        min[i] = 0;\n        max[i] = dims[i] - 1;\n    }\n\n    Wasp::VectorizeCoords(offset, min, max, coords, n);\n}\n\nstd::vector<size_t> Wasp::VectorizeCoords(size_t offset, const std::vector<size_t> &dims)\n{\n    size_t coords[MAXCOORDS];\n    VectorizeCoords(offset, dims.data(), coords, dims.size());\n    std::vector<size_t> coordsvec(dims.size(), 0);\n    for (int i = 0; i < dims.size(); i++) coordsvec[i] = coords[i];\n\n    return (coordsvec);\n}\n\nvoid Wasp::IncrementCoords(const size_t *min, const size_t *max, size_t *counter, size_t n, int dim)\n{\n    for (int i = dim; i < n; i++) {\n        if (counter[i] < (max[i])) {\n            counter[i] += 1;\n            break;\n        }\n        counter[i] = min[i];\n    }\n}\n\nvector<size_t> Wasp::IncrementCoords(const vector<size_t> &min, const vector<size_t> &max, vector<size_t> counter, int dim)\n{\n    VAssert(min.size() == max.size());\n    VAssert(min.size() == counter.size());\n\n    IncrementCoords(min.data(), max.data(), counter.data(), min.size(), dim);\n    return (counter);\n}\n\nvector<size_t> Wasp::Dims(const vector<size_t> &min, const vector<size_t> &max)\n{\n    VAssert(min.size() == max.size());\n    vector<size_t> dims;\n\n    for (int i = 0; i < min.size(); i++) {\n        VAssert(min[i] <= max[i]);\n        dims.push_back(max[i] - min[i] + 1);\n    }\n    return (dims);\n}\n\nsize_t Wasp::VProduct(const size_t *a, size_t n)\n{\n    size_t ntotal = 1;\n\n    for (size_t i = 0; i < n; i++) ntotal *= a[i];\n\n    return (ntotal);\n}\n\nsize_t Wasp::VProduct(const std::vector<size_t> &a) { return (VProduct(a.data(), a.size())); }\n\n#define BLOCKSIZE 256\n\nvoid Wasp::Transpose(const float *a, float *b, size_t p1, size_t m1, size_t s1, size_t p2, size_t m2, size_t s2)\n{\n    size_t       I1, I2;\n    size_t       i1, i2;\n    size_t       q, r;\n    const size_t block = BLOCKSIZE;\n    for (I2 = p2; I2 < p2 + m2; I2 += block)\n        for (I1 = p1; I1 < p1 + m1; I1 += block)\n            for (i2 = I2; i2 < min(I2 + block, p2 + m2); i2++)\n                for (i1 = I1; i1 < min(I1 + block, p1 + m1); i1++) {\n                    q = i2 * s1 + i1;\n                    r = i1 * s2 + i2;\n                    b[r] = a[q];\n                }\n}\n\nvoid Wasp::Transpose(const float *a, float *b, size_t s1, size_t s2) { Wasp::Transpose(a, b, 0, s1, s1, 0, s2, s2); }\n\nbool Wasp::BinarySearchRange(const vector<double> &sorted, double x, size_t &i)\n{\n    i = 0;\n\n    if (sorted.size() == 1) return (sorted[0] == x);\n\n    // if sorted in ascending order\n    //\n    if (sorted[0] <= sorted[sorted.size() - 1]) {\n        if (x < sorted[0]) return (false);\n\n        if (x == sorted[sorted.size() - 1]) {\n            i = sorted.size() - 2;\n            return (true);\n        }\n\n        vector<double>::const_iterator itr;\n        itr = std::upper_bound(sorted.begin(), sorted.end(), x);\n        if (itr == sorted.end()) { return (false); }\n        if (itr != sorted.begin()) { --itr; }\n        i = itr - sorted.begin();\n\n    } else {\n        if (x < sorted[sorted.size() - 1]) return (false);\n\n        if (x == sorted[sorted.size() - 1]) {\n            i = sorted.size() - 2;\n            return (true);\n        }\n\n        vector<double>::const_reverse_iterator itr;\n        itr = std::lower_bound(sorted.rbegin(), sorted.rend(), x);\n        if (itr == sorted.rend()) { return (false); }\n        if (itr != sorted.rbegin()) { ++itr; }\n        i = sorted.rend() - itr;\n    }\n\n    return (true);\n}\n\n#ifdef DEPRECATED\n//\n// Remove after release 3.5\n//\n\nbool Wasp::NearlyEqual(float a, float b, float epsilon)\n{\n    float absA = std::fabs(a);\n    float absB = std::fabs(b);\n    float diff = std::fabs(a - b);\n\n    // shortcut, handles infinities\n    //\n    if (a == b) return (true);\n\n    if (a == 0.0 || b == 0.0 || (absA + absB < std::numeric_limits<float>::min())) {\n        // a or b is zero or both are extremely close to it\n        // relative error is less meaningful here\n        //\n        return (diff < (epsilon * std::numeric_limits<float>::min()));\n    }\n\n    // use relative error\n    return (diff / min((absA + absB), std::numeric_limits<float>::max()) < epsilon);\n}\n\n#endif\n\nbool Wasp::NearlyEqual(float a, float b, float epsilon, float abs_th)\n{\n    VAssert(std::numeric_limits<float>::epsilon() <= epsilon);\n    VAssert(epsilon < 1.f);\n\n    if (a == b) return true;\n\n    auto diff = std::abs(a - b);\n    auto norm = std::min((std::abs(a) + std::abs(b)), std::numeric_limits<float>::max());\n\n    return diff < std::max(abs_th, epsilon * norm);\n}\n"
  },
  {
    "path": "lib/flow/Advection.cpp",
    "content": "#include <iostream>\n#include \"vapor/Advection.h\"\n#include <fstream>\n#include <algorithm>\n\nusing namespace flow;\n\n// Constructor;\nAdvection::Advection() : _lowerAngle(3.0f), _upperAngle(15.0f)\n{\n    _lowerAngleCos = glm::cos(glm::radians(_lowerAngle));\n    _upperAngleCos = glm::cos(glm::radians(_upperAngle));\n\n    std::fill(_isPeriodic.begin(), _isPeriodic.end(), false);\n    std::fill(_periodicBounds.begin(), _periodicBounds.end(), glm::vec2(0.0, 0.0));\n}\n\nvoid Advection::UseSeedParticles(const std::vector<Particle> &seeds)\n{\n    _streams.clear();\n    _streams.resize(seeds.size());\n    for (size_t i = 0; i < seeds.size(); i++)\n      _streams[i].push_back(seeds[i]);\n\n    _separatorCount.assign(seeds.size(), 0);\n}\n\nint Advection::CheckReady() const\n{\n    for (const auto &s : _streams) {\n        if (s.size() < 1) return NO_SEED_PARTICLE_YET;\n    }\n\n    return 0;\n}\n\nint Advection::AdvectSteps(Field *velocity, double deltaT, size_t maxSteps, bool fixedStepSize, ADVECTION_METHOD method)\n{\n    int ready = CheckReady();\n    if (ready != 0) return ready;\n    bool happened = false;\n\n    // Observation: user parameters are not gonna change while this function executes.\n    // Action: lock these parameters.\n    if (velocity->LockParams() != 0) \n      return PARAMS_ERROR;\n\n    // The particle advection process can be parallelized per particle\n    // Each stream represents a trajectory for a single particle\n    #pragma omp parallel for\n    for (size_t streamIdx = 0; streamIdx < _streams.size(); streamIdx++) {\n        auto& s = _streams[streamIdx];\n        size_t numberOfSteps = s.size() - _separatorCount[streamIdx];\n        while (numberOfSteps < maxSteps) {\n            auto &past0 = s.back();\n            if (past0.IsSpecial())    // If the last particle is marked \"special,\"\n                break;                // terminate stream immediately.\n\n            double dt = deltaT;\n            if (!fixedStepSize && s.size() > 2)   // When not using fixed step sizes and there are at least 3 particles in the stream,\n            {                                     // none is a separator, we adjust *dt*.\n                const auto &past1 = s[s.size() - 2];\n                const auto &past2 = s[s.size() - 3];\n                if ((!past1.IsSpecial()) && (!past2.IsSpecial())) {\n                    // We enforce a factor of 20.0f as a limit of how much the step size\n                    // can be adjusted by _calcAdjustFactor().\n                    // I.e., the adjusted value can be at most 20X larger or 20X smaller.\n                    // The choice of 20.0f is just an empirical value that seems to work well.\n                    double mindt = deltaT / 20.0, maxdt = deltaT * 20.0;\n                    dt = past0.time - past1.time;    // step size used by last integration\n                    dt *= _calcAdjustFactor(past2, past1, past0);\n                    if (dt > 0)    // integrate forward\n                        dt = glm::clamp(dt, mindt, maxdt);\n                    else    // integrate backward\n                        dt = glm::clamp(dt, maxdt, mindt);\n                }\n            }\n\n            Particle p1;\n            int      rv = 0;\n            switch (method) {\n            case ADVECTION_METHOD::EULER:\n                rv = _advectEuler(velocity, past0, dt, p1);\n                _printNonZero(rv, __FILE__, __func__, __LINE__);\n                break;\n            case ADVECTION_METHOD::RK4:\n                rv = _advectRK4(velocity, past0, dt, p1);\n                _printNonZero(rv, __FILE__, __func__, __LINE__);\n                break;\n            }\n\n            if (rv == SUCCESS) {\n                // Bookmark_1\n                // The new particle *may* be the same as the old particle in case\n                // there's a sink, meaning the velocity is zero.\n                // In that case, we mark p1 as \"special\" and terminate the current stream.\n                if (p1.location == past0.location) {\n                    p1.SetSpecial(true);\n                    s.emplace_back(p1);\n                    _separatorCount[streamIdx]++;\n                    break;\n                } else {\n                    happened = true;\n                    s.emplace_back(p1);\n                    numberOfSteps++;\n                }\n            } else if (rv == MISSING_VAL) {\n                // Bookmark_2\n                // This is the annoying part: there are multiple possiblities.\n                // 1) past0 is really located at a missing value location;\n                // 2) past0 is inside the volume, but really close to the boundary,\n                //    causing RK4 method to fail;\n                // 3) past0 is not at a missing location, but out of the volume.\n                //\n                // Note that we need to detect and deal with each of these possibilities\n                //   here instead of using the periodic capabilities of a grid class,\n                //   because the advection code needs to have knowledge when a pathline\n                //   exits from one side and comes back from another sice, and record\n                //   this event by inserting a separator. The separator will later be used\n                //   by the rendering code to break a pathline into segments.\n\n                glm::vec3 vel;\n                bool isMissing = (velocity->GetVelocity(past0.time, past0.location, vel) == MISSING_VAL);\n                bool isInside = velocity->InsideVolumeVelocity(past0.time, past0.location);\n\n                if (isInside && isMissing) {    // Case 1)\n                    // We identified a particle at a bad location.\n                    // We mark it as special, and terminate the current stream.\n                    past0.SetSpecial(true);\n                    _separatorCount[streamIdx]++;\n                    break;\n                } else if (isInside && (!isMissing)) {    // Case 2)\n                    // Use Euler advection for this particle.\n                    rv = _advectEuler(velocity, past0, dt, p1);\n                    assert(rv == 0);\n                    s.emplace_back(p1);\n                    numberOfSteps++;\n                } else {    // Case 3)\n                    // We identified a particle that's out of the volume.\n                    // We treat it depending on field periodicity.\n                    // In case of no periodicity, we mark this particle special and\n                    //    terminate the current stream.\n                    // In case of periodicity enabled, we apply it!\n                    if ((!_isPeriodic[0]) && (!_isPeriodic[1]) && (!_isPeriodic[2])) {\n                        past0.SetSpecial(true);\n                        _separatorCount[streamIdx]++;\n                        break;\n                    } else {\n                        auto loc = past0.location;\n                        for (int i = 0; i < 3; i++) {\n                            if (_isPeriodic[i]) \n                              loc[i] = _applyPeriodic(loc[i], _periodicBounds[i][0], _periodicBounds[i][1]);\n                        }\n\n                        // Notice that loc isn't guaranteed to be inside the volume right now,\n                        // since periodic ain't enabled for all directions.\n                        // As a result, we need to test again\n                        if (velocity->InsideVolumeVelocity(past0.time, loc)) {\n                            past0.location = loc;\n                            Particle separator;\n                            separator.SetSpecial(true);\n                            auto it = s.end();\n                            --it;\n                            s.insert(it, separator);\n                            _separatorCount[streamIdx]++;\n                        } else {\n                            past0.SetSpecial(true);\n                            _separatorCount[streamIdx]++;\n                            break;\n                        }\n                    }\n                }\n\n            }       // end (rv == MISSING_VAL) condition\n            else    // Advection wasn't successful for other reasons\n                break;\n\n        }    // end loop for particle\n    }        // end loop for streams\n\n    velocity->UnlockParams();\n\n    if (happened)\n        return SUCCESS;\n    else\n        return NO_ADVECT_HAPPENED;\n}\n\nint Advection::AdvectTillTime(Field *velocity, double startT, double deltaT, double targetT, bool fixedStepSize, ADVECTION_METHOD method)\n{\n    int ready = CheckReady();\n    if (ready != 0) return ready;\n\n    bool   happened = false;\n    size_t streamIdx = 0;\n    size_t maxSteps = 10000;\n    for (auto &s : _streams)    // Process one stream at a time\n    {\n        Particle p0 = s.back();    // Start from the last particle in this stream\n        if (p0.time < startT)      // Skip this stream if it didn't advance to startT\n            continue;\n\n        if (p0.IsSpecial())       // Also skip this tream if it was marked special.\n            continue;\n\n        size_t thisStep = 0;\n\n        while (p0.time < targetT) {\n\n            // Check if the particle is inside of the volume.\n            // Wrap it along periodic dimensions if applicable.\n            if (!velocity->InsideVolumeVelocity(p0.time, p0.location)) {\n                bool locChanged = false;\n                auto itr = s.end();\n                --itr;    // pointing to the last element\n                auto loc = itr->location;\n                for (int i = 0; i < 3; i++) {\n                    if (_isPeriodic[i]) {\n                        loc[i] = _applyPeriodic(loc[i], _periodicBounds[i][0], _periodicBounds[i][1]);\n                        locChanged = true;\n                    }\n                }\n                if (!locChanged) {  // no dimension is periodic, append a separator\n                    Particle separator;\n                    separator.SetSpecial(true);\n                    s.push_back(separator);\n                    _separatorCount[streamIdx]++;\n                    break;          // break the while loop\n                }\n\n                // See if the new location is inside of the volume\n                if (velocity->InsideVolumeVelocity(itr->time, loc)) {\n                    itr->location = loc;\n                    p0 = *itr;    // p0 is equal to the wrapped particle\n\n                    Particle separator;\n                    separator.SetSpecial(true);\n                    s.insert(itr, separator);\n                    _separatorCount[streamIdx]++;\n                } else {  // Still outside, so we terminate the stream!\n                    Particle separator;\n                    separator.SetSpecial(true);\n                    s.push_back(separator);\n                    _separatorCount[streamIdx]++;\n                    break;    // break the while loop\n                }\n            } // Finish the out-of-volume condition\n\n            double dt = deltaT;\n            if (!fixedStepSize && s.size() > 2)\n            {\n                double mindt = deltaT / 20.0, maxdt = deltaT * 20.0;\n                maxdt = glm::min(maxdt, targetT - p0.time);\n                const auto &past1 = s[s.size() - 2];\n                const auto &past2 = s[s.size() - 3];\n                if ((!past1.IsSpecial()) && (!past2.IsSpecial())) {\n                    dt = p0.time - past1.time;    // step size used by last integration\n                    dt *= _calcAdjustFactor(past2, past1, p0);\n                    dt = glm::clamp(dt, mindt, maxdt);\n                }\n            }\n\n            Particle p1;\n            int      rv = 0;\n            switch (method) {\n            case ADVECTION_METHOD::EULER:\n                rv = _advectEuler(velocity, p0, dt, p1);\n                _printNonZero(rv, __FILE__, __func__, __LINE__);\n                break;\n            case ADVECTION_METHOD::RK4:\n                rv = _advectRK4(velocity, p0, dt, p1);\n                _printNonZero(rv, __FILE__, __func__, __LINE__);\n                break;\n            }\n\n            if (rv == SUCCESS) {\n                // Check out Bookmark_1\n                if (p1.location == p0.location) {\n                    p1.SetSpecial(true);\n                    s.push_back(p1);\n                    _separatorCount[streamIdx]++;\n                    break;\n                } else {\n                    happened = true;\n                    s.push_back(p1);\n                    p0 = p1;\n                }\n            } else if (rv == MISSING_VAL) {\n                // Check out Bookmark_2\n                glm::vec3 vel;\n                bool isMissing = (velocity->GetVelocity(p0.time, p0.location, vel) == MISSING_VAL);\n                bool isInside = velocity->InsideVolumeVelocity(p0.time, p0.location);\n\n                if (isInside && isMissing) {\n                    p1.SetSpecial(true);\n                    s.push_back(p1);\n                    _separatorCount[streamIdx]++;\n                    break;\n                } else if (isInside && (!isMissing)) {\n                    rv = _advectEuler(velocity, p0, dt, p1);\n                    assert(rv == 0);\n                    s.push_back(p1);\n                    p0 = p1;\n                } else {\n                    auto loc = p0.location;\n                    for (int i = 0; i < 3; i++) {\n                        if (_isPeriodic[i])\n                            loc[i] = _applyPeriodic(loc[i], _periodicBounds[i][0], _periodicBounds[i][1]);\n                    }\n\n                    if (velocity->InsideVolumeVelocity(p0.time, loc)) {\n                        p1.SetSpecial(true);\n                        auto it = s.end();\n                        --it;\n                        s.insert(it, p1);\n                        it = s.end();\n                        --it;\n                        it->location = loc;\n                        _separatorCount[streamIdx]++;\n                    } else {\n                        p1.SetSpecial(true);\n                        s.push_back(p1);\n                        _separatorCount[streamIdx]++;\n                        break;\n                    }\n                }\n            } // finish handling missing value\n\n            // Another termination criterion: when advecting at least 10,000 steps and\n            // more than 10X more than the previous max num of steps.\n            //\n            if (++thisStep == maxSteps) {\n                thisStep = maxSteps / 10;\n                p1.SetSpecial(true);\n                s.push_back(p1);\n                _separatorCount[streamIdx]++;\n                break;\n            }\n        }    // Finish advecting one particle\n\n        maxSteps = std::max(maxSteps, thisStep * 10);\n\n        streamIdx++;\n\n    }    // Finish advecting all particles\n\n    if (happened)\n        return ADVECT_HAPPENED;\n    else\n        return 0;\n}\n\nint Advection::CalculateParticleValues(Field *scalar, bool skipNonZero)\n{\n    // For steady fields, we calculate values one stream at a time\n    if (scalar->IsSteady) {\n        if (scalar->LockParams() != 0) return PARAMS_ERROR;\n\n        _valueVarName = scalar->ScalarName;\n\n        for (auto &s : _streams) {\n            for (auto &p : s) {\n                // Skip this particle if it's a separator\n                if (p.IsSpecial()) continue;\n\n                // Do not evaluate this particle if its value is non-zero\n                if (skipNonZero && p.value != 0.0f) continue;\n\n                float value;\n                int   rv = scalar->GetScalar(p.time, p.location, value);\n                if (rv == 0)            // The end of a stream could be outside of the volume,\n                    p.value = value;    // so let's only color it when the return value is 0.\n            }\n        }\n\n        scalar->UnlockParams();\n    }\n    // For unsteady fields, we calculate values at one timestep at a time\n    else {\n        size_t mostSteps = 0;\n        for (auto &s : _streams) {\n            if (s.size() > mostSteps) mostSteps = s.size();\n        }\n\n        _valueVarName = scalar->ScalarName;\n\n        for (size_t i = 0; i < mostSteps; i++) {\n            for (auto &s : _streams) {\n                if (i < s.size()) {\n                    auto &p = s[i];\n                    if (p.IsSpecial()) continue;\n\n                    // Do not evaluate this particle if its value is non-zero\n                    if (skipNonZero && p.value != 0.0f) continue;\n\n                    float val;\n                    int   rv = scalar->GetScalar(p.time, p.location, val);\n                    if (rv == 0) p.value = val;\n                }\n            }    // end of a stream\n        }        // end of all steps\n    }\n\n    return 0;\n}\n\n\nint Advection::CalculateParticleIntegratedValues(Field *scalar, const bool skipNonZero, const float distScale, const std::vector<double> &integrateWithinVolumeMin,\n                                                 const std::vector<double> &integrateWithinVolumeMax)\n{\n    // For steady fields, we calculate values one stream at a time\n    if (scalar->IsSteady) {\n        if (scalar->LockParams() != 0) return PARAMS_ERROR;\n\n        _valueVarName = scalar->ScalarName;\n\n        for (auto &s : _streams) {\n            if (s.size() && !s[0].IsSpecial()) s[0].value = 0;\n\n            for (int i = 1; i < s.size(); i++) {\n                auto &prev = s[i - 1];\n                auto &p = s[i];\n                _calculateParticleIntegratedValue(p, prev, scalar, skipNonZero, distScale, integrateWithinVolumeMin, integrateWithinVolumeMax);\n            }\n        }\n\n        scalar->UnlockParams();\n    }\n    // For unsteady fields, we calculate values at one timestep at a time\n    else {\n        size_t mostSteps = 0;\n        for (auto &s : _streams) {\n            if (s.size() > mostSteps) mostSteps = s.size();\n        }\n\n        _valueVarName = scalar->ScalarName;\n\n        for (auto &s : _streams)\n            if (s.size() && !s[0].IsSpecial()) s[0].value = 0;\n\n        for (size_t i = 1; i < mostSteps; i++) {\n            for (auto &s : _streams) {\n                if (i < s.size()) {\n                    auto &prev = s[i - 1];\n                    auto &p = s[i];\n                    _calculateParticleIntegratedValue(p, prev, scalar, skipNonZero, distScale, integrateWithinVolumeMin, integrateWithinVolumeMax);\n                }\n            }    // end of a stream\n        }        // end of all steps\n    }\n\n    return 0;\n}\n\nvoid Advection::_calculateParticleIntegratedValue(Particle &p, const Particle &prev, const Field *scalarField, const bool skipNonZero, const float distScale,\n                                                  const std::vector<double> &integrateWithinVolumeMin, const std::vector<double> &integrateWithinVolumeMax) const\n{\n    // Skip this particle if it is a separator\n    if (p.IsSpecial()) return;\n    if (prev.IsSpecial()) {\n        p.value = 0;\n        return;\n    }\n\n    // Do not evaluate this particle if its value is non-zero\n    if (skipNonZero && p.value != 0.0f) return;\n\n    if (!_isParticleInsideVolume(p, integrateWithinVolumeMin, integrateWithinVolumeMax)) {\n        p.value = prev.value;\n        return;\n    }\n\n    float value;\n    int   rv = scalarField->GetScalar(p.time, p.location, value);\n    if (rv != 0) {    // If non-0, then outside the volume\n        p.value = prev.value;\n        return;\n    }\n\n    float dist = glm::distance(prev.location, p.location);\n    p.value = prev.value + value * dist * distScale;\n}\n\nvoid Advection::SetAllStreamValuesToFinalValue(int realNSamples)\n{\n    for (auto &s : _streams) {\n        float finalValue = 0;\n\n        int sampleCount = 0;\n        for (auto &p : s) {\n            if (!p.IsSpecial()) {\n                finalValue = p.value;\n                sampleCount++;\n            }\n            if (sampleCount == realNSamples) break;\n        }\n\n        int setCount = 0;\n        for (auto &p : s) {\n            if (!p.IsSpecial()) {\n                p.value = finalValue;\n                setCount++;\n            }\n            if (setCount == sampleCount) break;\n        }\n    }\n}\n\nint Advection::CalculateParticleProperties(Field *scalar)\n{\n    // Test if this scalar property is already calculated.\n    if (std::find(_propertyVarNames.cbegin(), _propertyVarNames.cend(), scalar->ScalarName) != _propertyVarNames.cend()) return 0;\n\n    // Proceed if there is no current scalar property\n    _propertyVarNames.emplace_back(scalar->ScalarName);\n\n    // Test if this scalar field is the same as the one used to calculate particle values,\n    // if so, copy over the values.\n    if (scalar->ScalarName == _valueVarName) {\n        for (auto &s : _streams) {\n            for (auto &p : s) { p.AttachProperty(p.value); }\n        }\n\n        return 0;\n    }\n\n    // In case this property field is a brand new variable, we do the actual sampling work.\n    if (scalar->IsSteady) {\n        if (scalar->LockParams() != 0) return PARAMS_ERROR;\n\n        for (auto &s : _streams) {\n            for (auto &p : s) {\n                if (p.IsSpecial()) continue;\n\n                // At the end of a flow line, a particle might be outside of the volume.\n                // We attach something in that case as well.\n                float val = std::nanf(\"1\");\n                scalar->GetScalar(p.time, p.location, val);\n                p.AttachProperty(val);\n            }\n        }\n    } \n    else {\n        size_t mostSteps = 0;\n        for (const auto &s : _streams)\n            if (s.size() > mostSteps) mostSteps = s.size();\n\n        for (size_t i = 0; i < mostSteps; i++) {\n            for (auto &s : _streams) {\n                if (i < s.size()) {\n                    auto &p = s[i];\n                    if (p.IsSpecial()) continue;\n\n                    float value = std::nanf(\"1\");\n                    scalar->GetScalar(p.time, p.location, value);\n                    p.AttachProperty(value);\n                }\n            }\n        }\n    }\n\n    return 0;\n}\n\nvoid Advection::CalculateParticleHistogram(std::vector<double> &outBounds, std::vector<long> &bins)\n{\n    std::vector<float> samples;\n\n    for (const auto &s : _streams)\n        for (const auto &p : s)\n            if (!p.IsSpecial()) samples.push_back(p.value);\n\n    auto  bounds = std::minmax_element(samples.begin(), samples.end());\n    float minValue = *bounds.first;\n    float maxValue = *bounds.second;\n    float range = maxValue - minValue;\n\n    int nBins = bins.size();\n    assert(nBins != 0);\n    std::fill(bins.begin(), bins.end(), 0);\n\n    for (const auto &s : samples) { bins[std::min(nBins - 1, std::max(0, (int)((nBins - 1) * (s - minValue) / range)))]++; }\n\n    outBounds.resize(2);\n    outBounds[0] = minValue;\n    outBounds[1] = maxValue;\n}\n\nint Advection::_advectEuler(Field *velocity, const Particle &p0, double dt, Particle &p1) const\n{\n    glm::vec3 v0;\n    int       rv = velocity->GetVelocity(p0.time, p0.location, v0);\n    if (rv != 0) return rv;\n    float dt32 = float(dt);    // glm is strict about data types (which is a good thing).\n    p1.location = p0.location + dt32 * v0;\n    p1.time = p0.time + dt;\n    return 0;\n}\n\nint Advection::_advectRK4(Field *velocity, const Particle &p0, double dt, Particle &p1) const\n{\n    glm::vec3    k1, k2, k3, k4;\n    const double dt_half = dt * 0.5;\n    const float  dt32 = float(dt);              // glm is strict about data types (which is a good thing).\n    const float  dt_half32 = float(dt_half);    // glm is strict about data types (which is a good thing).\n    int          rv = 0;\n    rv = velocity->GetVelocity(p0.time, p0.location, k1);\n    _printNonZero(rv, __FILE__, __func__, __LINE__);\n    if (rv != 0) return rv;\n    rv = velocity->GetVelocity(p0.time + dt_half, p0.location + dt_half32 * k1, k2);\n    _printNonZero(rv, __FILE__, __func__, __LINE__);\n    if (rv != 0) return rv;\n    rv = velocity->GetVelocity(p0.time + dt_half, p0.location + dt_half32 * k2, k3);\n    _printNonZero(rv, __FILE__, __func__, __LINE__);\n    if (rv != 0) return rv;\n    rv = velocity->GetVelocity(p0.time + dt, p0.location + dt32 * k3, k4);\n    _printNonZero(rv, __FILE__, __func__, __LINE__);\n    if (rv != 0) return rv;\n    p1.location = p0.location + dt32 / 6.0f * (k1 + 2.0f * (k2 + k3) + k4);\n    p1.time = p0.time + dt;\n\n    return 0;\n}\n\nfloat Advection::_calcAdjustFactor(const Particle &p2, const Particle &p1, const Particle &p0) const\n{\n    glm::vec3 p2p1 = p1.location - p2.location;\n    glm::vec3 p1p0 = p0.location - p1.location;\n    float     denominator = glm::length(p2p1) * glm::length(p1p0);\n    float     cosine;\n    if (denominator < 1e-7)\n        return 1.0f;\n    else\n        cosine = glm::dot(p2p1, p1p0) / denominator;\n\n    if (cosine > _lowerAngleCos)    // Less than \"_lowerAngle\" degrees\n        return 1.25f;\n    else if (cosine < _upperAngleCos)    // More than \"_upperAngle\" degrees\n        return 0.5f;\n    else\n        return 1.0f;\n}\n\nsize_t Advection::GetNumberOfStreams() const { return _streams.size(); }\n\nconst std::vector<Particle> &Advection::GetStreamAt(size_t i) const\n{\n    // Since this function is almost always used together with GetNumberOfStreams(),\n    // I'm offloading the range check to std::vector.\n    return _streams.at(i);\n}\n\nsize_t Advection::GetMaxNumOfPart() const\n{\n    size_t max = 0;\n    size_t idx = 0;\n    for (const auto &s : _streams) {\n        size_t num = s.size() - _separatorCount[idx];\n        if (num > max) max = num;\n        idx++;\n    }\n    return max;\n}\n\nvoid Advection::ClearParticleProperties()\n{\n    _propertyVarNames.clear();\n    for (auto &stream : _streams)\n        for (auto &part : stream) part.ClearProperty();\n}\n\nvoid Advection::RemoveParticleProperty(const std::string &varToRemove)\n{\n    auto itr = std::find(_propertyVarNames.begin(), _propertyVarNames.end(), varToRemove);\n\n    // Do nothing if `varToRemove` does not exist\n    if (itr == _propertyVarNames.end())\n        return;\n    else {\n        auto rmI = std::distance(_propertyVarNames.begin(), itr);\n        _propertyVarNames.erase(itr);\n        for (auto &stream : _streams)\n            for (auto &part : stream) part.RemoveProperty(rmI);\n    }\n}\n\nvoid Advection::ResetParticleValues()\n{\n    for (auto &stream : _streams) {\n        std::for_each(stream.begin(), stream.end(), [](Particle &p) {\n            if (!p.IsSpecial()) p.value = 0.0f;\n        });\n    }\n}\n\nvoid Advection::SetXPeriodicity(bool isPeri, float min, float max)\n{\n    _isPeriodic[0] = isPeri;\n    if (isPeri)\n        _periodicBounds[0] = glm::vec2(min, max);\n    else\n        _periodicBounds[0] = glm::vec2(0.0f);\n}\n\nvoid Advection::SetYPeriodicity(bool isPeri, float min, float max)\n{\n    _isPeriodic[1] = isPeri;\n    if (isPeri)\n        _periodicBounds[1] = glm::vec2(min, max);\n    else\n        _periodicBounds[1] = glm::vec2(0.0f);\n}\n\nvoid Advection::SetZPeriodicity(bool isPeri, float min, float max)\n{\n    _isPeriodic[2] = isPeri;\n    if (isPeri)\n        _periodicBounds[2] = glm::vec2(min, max);\n    else\n        _periodicBounds[2] = glm::vec2(0.0f);\n}\n\nfloat Advection::_applyPeriodic(float val, float min, float max) const\n{\n    if (min >= max)    // ill params, return val\n        return val;\n    else if (val >= min && val <= max)    // nothing needs to change\n        return val;\n\n    // Let's do some serious work\n    float span = max - min;\n    float pval = val;\n    if (val < min) {\n        while (pval < min) pval += span;\n        return pval;\n    } else    // val > max\n    {\n        while (pval > max) pval -= span;\n        return pval;\n    }\n}\n\nvoid Advection::_printNonZero(int rtn, const char *file, const char *func, int line) const\n{\n#ifdef VPRINT\n    if (rtn != 0) {    // only print non-zero values\n        printf(\"Rtn == %d: %s:(%s):%d\\n\", rtn, file, func, line);\n    }\n#endif\n}\n\nauto Advection::GetValueVarName() const -> std::string { return _valueVarName; }\n\nauto Advection::GetPropertyVarNames() const -> std::vector<std::string> { return _propertyVarNames; }\n\nbool Advection::_isParticleInsideVolume(const Particle &p, const std::vector<double> &min, const std::vector<double> &max)\n{\n    if (p.location[0] < min[0] || p.location[1] < min[1] || p.location[0] > max[0] || p.location[1] > max[1]) { return false; }\n    if (min.size() > 2 && (p.location[2] < min[2] || p.location[2] > max[2])) { return false; }\n    return true;\n}\n"
  },
  {
    "path": "lib/flow/AdvectionIO.cpp",
    "content": "#include \"vapor/AdvectionIO.h\"\n#include <algorithm>\n#include <cctype>\n#include <fstream>\n#include <iostream>\n#include <iterator>    // std::distance\n#include <sstream>\n#include \"vapor/Proj4API.h\"\n#include \"vapor/UDUnitsClass.h\"\n\nauto flow::OutputFlowlinesNumSteps(const Advection *adv, const char *filename, size_t numSteps, const std::string &proj4string, bool append) -> int\n{\n    // First we need the infrastructure for time conversion\n    VAPoR::UDUnits udunits;\n    if (udunits.Initialize() < 0) return PARAMS_ERROR;\n\n    // Second we need the infrastructure for coordinate conversion\n    bool            needGeoConversion = false;\n    VAPoR::Proj4API proj4API;\n    if (!proj4string.empty()) {\n        if (proj4API.Initialize(proj4string, \"\") < 0) return PARAMS_ERROR;\n        needGeoConversion = true;\n    }\n\n    // Requesting the file handle\n    std::FILE *f = nullptr;\n    if (append)\n        f = std::fopen(filename, \"a\");\n    else\n        f = std::fopen(filename, \"w\");\n    if (f == nullptr) return FILE_ERROR;\n\n    auto propertyNames = adv->GetPropertyVarNames();\n\n    // Write the header\n    if (!append) {\n        std::fprintf(f, \"%s\", \"# ID,  X-position,  Y-position,  Z-position\");\n\n        for (auto &n : propertyNames) std::fprintf(f, \",  %s\", n.c_str());\n        std::fprintf(f, \"\\n\");\n    }\n\n    // Let's declare variables that will be used repeatedly for geo coordinate conversion\n    float cX = 0.f, cY = 0.f;    // converted X, Y coordinates\n\n    // Write the trajectories\n    for (size_t s_idx = 0; s_idx < adv->GetNumberOfStreams(); s_idx++) {\n        const auto &stream = adv->GetStreamAt(s_idx);\n\n        size_t step = 0;\n        for (const auto &p : stream) {\n            if (!p.IsSpecial()) {\n                // Let's also convert geo coordinates if needed.\n                cX = p.location.x;\n                cY = p.location.y;\n                if (needGeoConversion) proj4API.Transform(&cX, &cY, 1);\n\n                std::fprintf(f, \"%lu, %f, %f, %f\", s_idx, cX, cY, p.location.z);\n\n                auto props = p.GetPropertyList();\n                // A quick sanity check\n                assert(std::distance(props.cbegin(), props.cend()) == propertyNames.size());\n                for (const auto &val : props) std::fprintf(f, \", %f\", val);\n\n                std::fprintf(f, \"\\n\");    // end of one line\n                step++;\n            }\n            if (step > numSteps)    // when numSteps + 1 particles are printed.\n                break;\n        }\n    }\n\n    std::fclose(f);\n\n    return 0;\n}\n\nauto flow::OutputFlowlinesMaxTime(const Advection *adv, const char *filename, double maxTime, const std::string &proj4string, bool append) -> int\n{\n    // First we need the infrastructure for time conversion\n    VAPoR::UDUnits udunits;\n    if (udunits.Initialize() < 0) return PARAMS_ERROR;\n\n    // Second we need the infrastructure for coordinate conversion\n    bool            needGeoConversion = false;\n    VAPoR::Proj4API proj4API;\n    if (!proj4string.empty()) {\n        if (proj4API.Initialize(proj4string, \"\") < 0) return PARAMS_ERROR;\n        needGeoConversion = true;\n    }\n\n    // Requesting the file handle\n    std::FILE *f = nullptr;\n    if (append)\n        f = std::fopen(filename, \"a\");\n    else\n        f = std::fopen(filename, \"w\");\n    if (f == nullptr) return FILE_ERROR;\n\n    auto propertyNames = adv->GetPropertyVarNames();\n\n    // Write the header\n    if (!append) {\n        std::fprintf(f, \"%s\", \"# ID,  X-position,  Y-position,  Z-position,  Formatted-time, Raw-time\");\n\n        for (auto &n : propertyNames) std::fprintf(f, \",  %s\", n.c_str());\n        std::fprintf(f, \"\\n\");\n    }\n\n    // Let's declare variables that will be used repeatedly for time and geo coordinate conversion\n    int   year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;\n    float cX = 0.f, cY = 0.f;    // converted X, Y coordinates\n\n    // Write the trajectories\n    for (size_t s_idx = 0; s_idx < adv->GetNumberOfStreams(); s_idx++) {\n        const auto &stream = adv->GetStreamAt(s_idx);\n\n        for (const auto &p : stream) {\n            if (p.time > maxTime) break;\n\n            if (!p.IsSpecial()) {\n                // First, convert time.\n                udunits.DecodeTime(p.time, &year, &month, &day, &hour, &minute, &second);\n\n                // Also convert geo coordinates if needed.\n                cX = p.location.x;\n                cY = p.location.y;\n                if (needGeoConversion) proj4API.Transform(&cX, &cY, 1);\n\n                std::fprintf(f, \"%lu, %f, %f, %f, %.4d-%.2d-%.2d_%.2d:%.2d:%.2d, %f\", s_idx, cX, cY, p.location.z, year, month, day, hour, minute, second, p.time);\n\n                auto props = p.GetPropertyList();\n                // A quick sanity check\n                assert(std::distance(props.cbegin(), props.cend()) == propertyNames.size());\n                for (const auto &val : props) std::fprintf(f, \", %f\", val);\n\n                std::fprintf(f, \"\\n\");    // end of one line\n            }\n        }\n    }\n\n    std::fclose(f);\n\n    return 0;\n}\n\nauto flow::InputSeedsCSV(const std::string &filename) -> std::vector<flow::Particle>\n{\n    std::ifstream ifs(filename);\n    if (!ifs.is_open()) return {};\n\n    std::vector<Particle> newSeeds;\n\n    for (std::string line; std::getline(ifs, line);) {\n        // remove spaces/tabs in this line\n        line.erase(std::remove_if(line.begin(), line.end(), [](unsigned char c) { return std::isspace(c); }), line.end());\n\n        // skip this line if it's empty\n        if (line.empty()) continue;\n\n        // If leading by a #, then skip it.\n        if (line.front() == '#') continue;\n\n        // Now try to parse numbers separated by comma\n        std::stringstream  ss(line);\n        std::vector<float> valFloat;\n        valFloat.reserve(3);\n        for (std::string tmp; std::getline(ss, tmp, ',');) {\n            try {\n                valFloat.push_back(std::stof(tmp));\n            } catch (const std::invalid_argument &e) {\n                ifs.close();\n                return {};\n            }\n            if (valFloat.size() >= 3)    // we parse at most 3 values, and discard the rest of this line.\n                break;\n        }\n\n        if (valFloat.size() < 3) {    // less than 3 values provided in this line\n            ifs.close();\n            return {};    // Not accepting any seed when encountering a bad line\n        }\n\n        newSeeds.emplace_back(valFloat[0], valFloat[1], valFloat[2], 0.0);\n    }\n    ifs.close();\n\n    // Let's also remove duplicate seeds.\n    auto less = [](const flow::Particle &a, const flow::Particle &b) {\n        if (a.location.x != b.location.x)\n            return (a.location.x < b.location.x);\n        else if (a.location.y != b.location.y)\n            return (a.location.y < b.location.y);\n        else\n            return (a.location.z < b.location.z);\n    };\n    std::sort(newSeeds.begin(), newSeeds.end(), less);\n\n    auto equal = [](const flow::Particle &a, const flow::Particle &b) {\n        auto eq = glm::equal(a.location, b.location);\n        return glm::all(eq);\n    };\n    auto itr = std::unique(newSeeds.begin(), newSeeds.end(), equal);\n    newSeeds.erase(itr, newSeeds.end());\n\n    return newSeeds;\n}\n"
  },
  {
    "path": "lib/flow/CMakeLists.txt",
    "content": "set (SRC\n\tParticle.cpp\n\tAdvection.cpp\n\tField.cpp\n\tVaporField.cpp\n\tAdvectionIO.cpp\n)\n\nset (HEADERS\n\t${PROJECT_SOURCE_DIR}/include/vapor/Advection.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Particle.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Field.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VaporField.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/AdvectionIO.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ptr_cache.hpp\n)\n\nadd_library (flow SHARED ${SRC} ${HEADERS})\n\ntarget_link_libraries ( flow  PUBLIC vdc params )\n\nadd_definitions (-DFLOW_EXPORTS)\n\nOpenMPInstall (\n\tTARGETS flow\n\tDESTINATION ${INSTALL_LIB_DIR}\n\tCOMPONENT Libraries\n\t)\n\ninstall (\n\tFILES ${HEADERS}\n\tDESTINATION ${INSTALL_INCLUDE_DIR}\n\tCOMPONENT Libraries\n\t)\n"
  },
  {
    "path": "lib/flow/Field.cpp",
    "content": "#include <algorithm>\n#include \"vapor/Field.h\"\n\nusing namespace flow;\n\nint Field::GetNumOfEmptyVelocityNames() const\n{\n    return std::count_if(VelocityNames.begin(), VelocityNames.end(), [](const std::string &e) { return e.empty(); });\n}\n"
  },
  {
    "path": "lib/flow/Particle.cpp",
    "content": "#include \"vapor/Particle.h\"\n\nusing namespace flow;\n\nParticle::Particle(const glm::vec3 &loc, double t, float val)\n{\n    location = loc;\n    time = t;\n    value = val;\n}\n\nParticle::Particle(float x, float y, float z, double t, float val)\n{\n    location.x = x;\n    location.y = y;\n    location.z = z;\n    time = t;\n    value = val;\n}\n\nvoid Particle::AttachProperty(float v)\n{\n    auto before_itr = _properties.cbefore_begin();\n    for (auto itr = _properties.cbegin(); itr != _properties.cend(); ++itr) ++before_itr;\n\n    _properties.insert_after(before_itr, v);\n}\n\nauto Particle::GetPropertyList() const -> const std::forward_list<float> & { return _properties; }\n\nvoid Particle::ClearProperty() { _properties.clear(); }\n\nvoid Particle::RemoveProperty(size_t target_i)\n{\n    size_t current_i = 0;\n    auto   before_it = _properties.cbefore_begin();\n    for (auto it = _properties.cbegin(); it != _properties.cend(); ++it) {\n        if (current_i == target_i) {\n            _properties.erase_after(before_it);\n            break;\n        }\n        ++current_i;\n        ++before_it;\n    }\n}\n\nvoid Particle::SetSpecial(bool isSpecial)\n{\n    // Give both \"time\" and \"value\" a nan to indicate the \"special state.\"\n    // Accidental assignment of nan to one of the two variables would not\n    // render a \"special state.\"\n    if (isSpecial) {\n        time = std::nanf(\"1\");\n        value = std::nanf(\"1\");\n    } else {\n        time = 0.0f;\n        value = 0.0f;\n    }\n    location = {0.0f, 0.0f, 0.0f};\n}\n\nbool Particle::IsSpecial() const { return (std::isnan(time) && std::isnan(value)); }\n"
  },
  {
    "path": "lib/flow/VaporField.cpp",
    "content": "#include \"vapor/VaporField.h\"\n#include \"vapor/ConstantGrid.h\"\n\nusing namespace flow;\n\n//\n// Class GridKey\n//\nvoid GridKey::Reset(uint32_t ts, int32_t ref, int32_t comp, std::string var, VAPoR::CoordType min, VAPoR::CoordType max)\n{\n    _timestep = ts;\n    _refLev = ref;\n    _compLev = comp;\n\n    _varName = std::move(var);\n\n    _ext_min = min;\n    _ext_max = max;\n}\n\nbool GridKey::operator==(const GridKey &other) const\n{\n    // String comparison seems to occur most frequently, so put it at the first.\n    if (this->_varName != other._varName) return false;\n    if (this->_timestep != other._timestep) return false;\n    if (this->_refLev != other._refLev) return false;\n    if (this->_compLev != other._compLev) return false;\n    if (this->_ext_min != other._ext_min) return false;\n    if (this->_ext_max != other._ext_max) return false;\n\n    return true;\n}\n\nbool GridKey::emptyVar() const { return _varName.empty(); }\n\n//\n// Class GridWrapper\n//\nGridWrapper::GridWrapper(const VAPoR::Grid *gp, VAPoR::DataMgr *mp) : _gridPtr(gp), _mgr(mp) {}\n\nGridWrapper::~GridWrapper()\n{\n    if (_gridPtr && _mgr) {\n        _mgr->UnlockGrid(_gridPtr);\n        delete _gridPtr;\n    }\n}\n\nconst VAPoR::Grid *GridWrapper::grid() const { return _gridPtr; }\n\n//\n// Class VaporField\n//\nauto VaporField::LockParams() -> int\n{\n    if (!_isReady()) return 1;\n\n    // Retrieve param values and put them in the local cache.\n    _c_currentTS = _params->GetCurrentTimestep();\n    _c_refLev = _params->GetRefinementLevel();\n    _c_compLev = _params->GetCompressionLevel();\n    _c_vel_mult = _params->GetVelocityMultiplier();\n    _params->GetBox()->GetExtents(_c_ext_min, _c_ext_max);\n\n    _params_locked = true;\n    return 0;\n}\n\nauto VaporField::UnlockParams() -> int\n{\n    _c_currentTS = std::numeric_limits<uint32_t>::max(); // almost impossible value\n    _c_refLev = -2;   // Impossible value\n    _c_compLev = -2;  // Impossible value\n    _c_vel_mult = 0.0;\n    _c_ext_min = {0.0, 0.0, 0.0};\n    _c_ext_max = {0.0, 0.0, 0.0};\n\n    _params_locked = false;\n    return 0;\n}\n\nbool VaporField::InsideVolumeVelocity(double time, glm::vec3 pos) const\n{\n    VAPoR::CoordType            coords{pos.x, pos.y, pos.z};\n    const VAPoR::Grid *         grid = nullptr;\n    VAssert(_isReady());\n\n    // In case of steady field, we only check a specific time step\n    if (IsSteady) {\n        for (int i = 0; i < 3; i++) {\n          auto currentTS = _c_currentTS;\n          if (!_params_locked)\n              currentTS = _params->GetCurrentTimestep();\n          else\n              assert(currentTS == _params->GetCurrentTimestep());\n\n          grid = _getAGrid(currentTS, VelocityNames[i]);\n          if (grid == nullptr) return false;\n          if (!grid->InsideGrid(coords)) return false;\n        }\n    }\n    else {  // In case of unsteady, we check two time steps\n        // First check if the query time is within range\n        if (time < _timestamps.front() || time > _timestamps.back()) return false;\n\n        // Then locate the 2 time steps\n        size_t floor = 0;\n        int    rv = LocateTimestamp(time, floor);\n        if (rv != 0) return false;\n\n        // Then test if pos is inside of time step \"floor\"\n        for (auto &v : VelocityNames) {\n            grid = _getAGrid(floor, v);\n            if (grid == nullptr) return false;\n            if (!grid->InsideGrid(coords)) return false;\n        }\n\n        // If time is larger than _timestamps[floor], we also need to test _timestamps[floor+1]\n        if (time > _timestamps[floor]) {\n            for (auto &v : VelocityNames) {\n                grid = _getAGrid(floor + 1, v);\n                if (grid == nullptr) return false;\n                if (!grid->InsideGrid(coords)) return false;\n            }\n        }\n    }\n\n    return true;\n}\n\nbool VaporField::InsideVolumeScalar(double time, glm::vec3 pos) const\n{\n    // When this variable doesn't exist, it doesn't make sense to say if\n    // a position is inside of the volume, so simply return true.\n    if (ScalarName.empty()) return true;\n\n    VAPoR::CoordType            coords{pos.x, pos.y, pos.z};\n    const VAPoR::Grid *         grid = nullptr;\n    VAssert(_isReady());\n\n    // In case of steady field, we only check a specific time step\n    if (IsSteady) {\n        auto currentTS = _c_currentTS;\n        if (!_params_locked)\n            currentTS = _params->GetCurrentTimestep();\n        else\n            assert(currentTS == _params->GetCurrentTimestep());\n\n        grid = _getAGrid(currentTS, ScalarName);\n        if (grid == nullptr) return false;\n        return grid->InsideGrid(coords);\n    }\n    else {  // In case of unsteady field, we check two time steps\n        // First check if the query time is within range\n        if (time < _timestamps.front() || time > _timestamps.back()) return false;\n\n        // Then locate the 2 time steps\n        size_t floor = 0;\n        int    rv = LocateTimestamp(time, floor);\n        if (rv != 0) return false;\n\n        // Then test if pos is inside of time step \"floor\"\n        grid = _getAGrid(floor, ScalarName);\n        if (grid == nullptr) return false;\n        if (!grid->InsideGrid(coords)) return false;\n\n        // If time is larger than _timestamps[floor], we also need to test _timestamps[floor+1]\n        if (time > _timestamps[floor]) {\n            grid = _getAGrid(floor + 1, ScalarName);\n            if (grid == nullptr) return false;\n            if (!grid->InsideGrid(coords)) return false;\n        }\n\n        return true;\n    }\n}\n\nint VaporField::GetVelocityIntersection(size_t ts, glm::vec3 &minxyz, glm::vec3 &maxxyz) const\n{\n    const VAPoR::Grid *   grid = nullptr;\n    std::array<double, 3> min[3], max[3];\n\n    // For each velocity variables\n    for (int i = 0; i < 3; i++) {\n        grid = _getAGrid(ts, VelocityNames[i]);\n        if (grid == nullptr) {\n            Wasp::MyBase::SetErrMsg(\"Vector field not available at requested time step!\");\n            return GRID_ERROR;\n        } else\n            grid->GetUserExtents(min[i], max[i]);\n    }\n\n    minxyz = glm::vec3(min[0][0], min[0][1], min[0][2]);\n    maxxyz = glm::vec3(max[0][0], max[0][1], max[0][2]);\n\n    for (int i = 1; i < 3; i++) {\n        glm::vec3 xyz(min[i][0], min[i][1], min[i][2]);\n        minxyz = glm::max(minxyz, xyz);\n        xyz = glm::vec3(max[i][0], max[i][1], max[i][2]);\n        maxxyz = glm::min(maxxyz, xyz);\n    }\n\n    return 0;\n}\n\nint VaporField::GetVelocity(double time, glm::vec3 pos, glm::vec3 &velocity) const\n{\n    VAPoR::CoordType            coords{pos.x, pos.y, pos.z};\n    const VAPoR::Grid *         grid = nullptr;\n\n    // Retrieve the missing value and velocity multiplier\n    glm::vec3 missingV(0.0f);    // stores missing values for 3 velocity variables\n    velocity = glm::vec3(0.0f);\n\n    if (IsSteady) {\n        for (int i = 0; i < 3; i++) {\n            auto currentTS = _c_currentTS;\n            if (!_params_locked)\n                currentTS = _params->GetCurrentTimestep();\n            grid = _getAGrid(currentTS, VelocityNames[i]);\n            if (grid == nullptr) return GRID_ERROR;\n\n            velocity[i] = grid->GetValue(coords);\n            missingV[i] = grid->GetMissingValue();\n        }\n        auto  hasMissing = glm::equal(velocity, missingV);\n        // If missing values are represented using NaN, you cannot compare equality with them!\n        for (int i = 0; i < 3; i++) {\n          if (std::isnan(missingV[i]) && std::isnan(velocity[i]))\n            hasMissing[i] = true;\n        }\n        if (glm::any(hasMissing)) {\n            return MISSING_VAL;\n        }\n        else {\n            float mult = _params_locked ? _c_vel_mult : _params->GetVelocityMultiplier();\n            velocity *= mult;\n            return SUCCESS;\n        }\n    }    // Finish steady case\n    else {\n        // First check if the query time is within range\n        if (time < _timestamps.front() || time > _timestamps.back()) return TIME_ERROR;\n\n        // Then we locate the floor time step\n        size_t floorTS = 0;\n        int    rv = LocateTimestamp(time, floorTS);\n        VAssert(rv == 0);\n\n        // Find the velocity values at floor time step\n        glm::vec3 floorVelocity(0.f, 0.f, 0.f);\n        glm::vec3 ceilingVelocity(0.f, 0.f, 0.f);\n        for (int i = 0; i < 3; i++) {\n            grid = _getAGrid(floorTS, VelocityNames[i]);\n            if (grid == nullptr) return GRID_ERROR;\n\n            floorVelocity[i] = grid->GetValue(coords);\n            missingV[i] = grid->GetMissingValue();\n        }\n        auto hasMissing = glm::equal(floorVelocity, missingV);\n        if (glm::any(hasMissing)) { return MISSING_VAL; }\n\n        float mult = _params->GetVelocityMultiplier();\n        if (time == _timestamps[floorTS]) {\n            velocity = floorVelocity * mult;\n            return 0;\n        } \n        else {  // Find the velocity values at the ceiling time step, then interpolate.\n            // We need to make sure there aren't duplicate time stamps\n            VAssert(_timestamps[floorTS + 1] > _timestamps[floorTS]);\n            for (int i = 0; i < 3; i++) {\n                grid = _getAGrid(floorTS + 1, VelocityNames[i]);\n                if (grid == nullptr) return GRID_ERROR;\n                ceilingVelocity[i] = grid->GetValue(coords);\n                missingV[i] = grid->GetMissingValue();\n            }\n            hasMissing = glm::equal(ceilingVelocity, missingV);\n            if (glm::any(hasMissing)) { return MISSING_VAL; }\n\n            float weight = (time - _timestamps[floorTS]) / (_timestamps[floorTS + 1] - _timestamps[floorTS]);\n            velocity = glm::mix(floorVelocity, ceilingVelocity, weight) * mult;\n            return 0;\n        }\n    }    // end of unsteady condition\n}\n\nint VaporField::GetScalar(double time, glm::vec3 pos, float &scalar) const\n{\n    // When this variable doesn't exist, it doesn't make sense to get a scalar value\n    // from it, so just return that fact.\n    if (ScalarName.empty()) return NO_FIELD_YET;\n\n    VAPoR::CoordType            coords{pos.x, pos.y, pos.z};\n    const VAPoR::Grid *         grid = nullptr;\n\n    if (IsSteady) {\n        auto currentTS = _c_currentTS;\n        if (!_params_locked)\n            currentTS = _params->GetCurrentTimestep();\n            \n        grid = _getAGrid(currentTS, ScalarName);\n        if (grid == nullptr) return GRID_ERROR;\n\n        scalar = grid->GetValue(coords);\n        if (scalar == grid->GetMissingValue()) {\n            return MISSING_VAL;\n        } \n        else\n            return 0;\n    } \n    else {\n        // First check if the query time is within range\n        if (time < _timestamps.front() || time > _timestamps.back()) return TIME_ERROR;\n\n        // Then we locate the floor time step\n        size_t floorTS = 0;\n        int    rv = LocateTimestamp(time, floorTS);\n        VAssert(rv == 0);\n        grid = _getAGrid(floorTS, ScalarName);\n        if (grid == nullptr) return GRID_ERROR;\n\n        float floorScalar = grid->GetValue(coords);\n        if (floorScalar == grid->GetMissingValue()) { return MISSING_VAL; }\n\n        if (time == _timestamps[floorTS]) {\n            scalar = floorScalar;\n            return 0;\n        } \n        else {\n            grid = _getAGrid(floorTS + 1, ScalarName);\n            if (grid == nullptr) return GRID_ERROR;\n\n            float ceilingScalar = grid->GetValue(coords);\n            if (ceilingScalar == grid->GetMissingValue()) {\n                return MISSING_VAL;\n            } else {\n                float weight = (time - _timestamps[floorTS]) / (_timestamps[floorTS + 1] - _timestamps[floorTS]);\n                scalar = glm::mix(floorScalar, ceilingScalar, weight);\n                return 0;\n            }\n        }\n    }    // end of unsteady condition\n}\n\nbool VaporField::_isReady() const\n{\n    if (!_datamgr) return false;\n    if (!_params) return false;\n\n    return true;\n}\n\nvoid VaporField::AssignDataManager(VAPoR::DataMgr *dmgr)\n{\n    _datamgr = dmgr;\n\n    // Make a copy of the timestamps from the new data manager\n    _timestamps = dmgr->GetTimeCoordinates();\n}\n\nvoid VaporField::UpdateParams(const VAPoR::FlowParams *p)\n{\n    _params = p;\n    IsSteady = p->GetIsSteady();\n}\n\nint VaporField::LocateTimestamp(double time, size_t &floor) const\n{\n    if (_timestamps.empty()) return TIME_ERROR;\n    if (_timestamps.size() == 1) {\n        if (_timestamps[0] != time)\n            return TIME_ERROR;\n        else {\n            floor = 0;\n            return 0;\n        }\n    }\n\n    if (time < _timestamps.front() || time > _timestamps.back())\n        return TIME_ERROR;\n    else {\n        auto it = std::upper_bound(_timestamps.cbegin(), _timestamps.cend(), time);\n        floor = --it - _timestamps.cbegin();\n        return 0;\n    }\n}\n\nuint32_t VaporField::GetNumberOfTimesteps() const { return _timestamps.size(); }\n\nint VaporField::CalcDeltaTFromCurrentTimeStep(double &delT) const\n{\n    VAssert(_isReady());\n\n    // This function is called only one-time before advection starts,\n    // so don't worry about parameter locking here.\n    const auto currentTS = _params->GetCurrentTimestep();\n    const auto timestamp = _timestamps.at(currentTS);\n\n    // Let's find the intersection of 3 velocity components.\n    glm::vec3 minxyz(0.0f), maxxyz(0.0f);\n    int       rv = this->GetVelocityIntersection(currentTS, minxyz, maxxyz);\n    if (rv != 0) return rv;\n\n    // Let's make sure the max is greater than or equal to min\n    const auto invalid = glm::lessThan(maxxyz, minxyz);\n    if (glm::any(invalid)) {\n        Wasp::MyBase::SetErrMsg(\"One of the selected volume dimension is zero!\");\n        return GRID_ERROR;\n    }\n\n    // Let's sample some locations along each dimension.\n    const long      N = 10;    // Num of samples along each axis\n    const long      totalSamples = N * N * N;\n    const glm::vec3 numOfSteps(float(N + 1));\n    const glm::vec3 stepSizes = (maxxyz - minxyz) / numOfSteps;\n    glm::vec3       samples[totalSamples];\n    long            counter = 0;\n    for (long z = 1; z <= N; z++)\n        for (long y = 1; y <= N; y++)\n            for (long x = 1; x <= N; x++) {\n                samples[counter].x = minxyz.x + stepSizes.x * float(x);\n                samples[counter].y = minxyz.y + stepSizes.y * float(y);\n                samples[counter].z = minxyz.z + stepSizes.z * float(z);\n                counter++;\n            }\n\n    float     maxmag = 0.0f;\n    glm::vec3 vel;\n    for (long i = 0; i < totalSamples; i++) {\n        int rv = this->GetVelocity(timestamp, samples[i], vel);\n        // Among possible return values, 0 is good, and MISSING_VAL isn't too bad,\n        // we just need to ignore those values.\n        if (rv == flow::MISSING_VAL)\n            continue;\n        else if (rv != 0)\n            return rv;\n        else {\n            auto mag = glm::length(vel);\n            maxmag = std::max(maxmag, mag);\n        }\n    }\n\n    // If all sampled locations are missing values or zero values,\n    //   we give deltaT an arbitrary value and return a special value.\n    if (maxmag == 0.0 || std::isinf(maxmag)) {\n        delT = glm::distance(minxyz, maxxyz) / 1000.0;\n        return flow::FIELD_ALL_ZERO;\n    }\n\n    // Let's dictate that using the maximum velocity FROM OUR SAMPLES\n    //   a particle needs 1000 steps (in case of unstructured grids) or\n    //   twice the domain dimension (in case of structured grids)\n    //   to travel the entire space.\n    // Also, no matter what fidelity level we are at with the VDC data set,\n    //   we always use the domain dimensions of the full resolution.\n    double desiredNum = 1000.0;    // pre-defined value for unstructured grids\n    const auto *grid = _getAGrid(currentTS, VelocityNames[0]);\n    const auto *structuredGrid = dynamic_cast<const VAPoR::StructuredGrid *>(grid);\n    if (structuredGrid) {\n        auto dims = std::vector<size_t>();\n        // -1 indicates that querying the native resolution.\n        _datamgr->GetDimLensAtLevel(VelocityNames[0], -1, dims, currentTS);\n        // `dims` could have 2 or 3 elements, depending on the dimension of the variable.\n        assert(dims.size() == 2 || dims.size() == 3);\n        double numCellsDiagnal = 0.0;\n        if (dims.size() == 3)\n          numCellsDiagnal = std::sqrt(double(dims[0] * dims[0] + dims[1] * dims[1] + dims[2] * dims[2]));\n        else\n          numCellsDiagnal = std::sqrt(double(dims[0] * dims[0] + dims[1] * dims[1]));\n\n        desiredNum = 2.0 * numCellsDiagnal;\n    }\n\n    const double actualNum = double(glm::distance(minxyz, maxxyz)) / double(maxmag);\n    delT = actualNum / desiredNum;\n\n    // Another logic in determing the size of deltaT:\n    //   if deltaT will send a particle out of the domain in just one step in any direction,\n    //   then we halve deltaT until the particle can go one step inside of the volume.\n    float smallestD = std::numeric_limits<float>::max();\n    if (!VelocityNames[0].empty())\n      smallestD = std::min(smallestD, std::abs(minxyz.x - maxxyz.x));\n    if (!VelocityNames[1].empty())\n      smallestD = std::min(smallestD, std::abs(minxyz.y - maxxyz.y));\n    if (!VelocityNames[2].empty())\n      smallestD = std::min(smallestD, std::abs(minxyz.z - maxxyz.z));\n    while (maxmag * delT > double(smallestD)) {\n        delT /= 2.0;\n    }\n\n    // Finally, apply a multiplier to the estimated deltaT. See Github issue 3318:\n    // https://github.com/NCAR/VAPOR/issues/3318\n    delT *= _params->GetFirstStepSizeMultiplier();\n\n    return 0;\n}\n\nconst VAPoR::Grid *VaporField::_getAGrid(uint32_t timestep, const std::string &varName) const\n{\n    GridKey key;\n    if (_params_locked) {\n        // Because in unsteady case, both currentTS and currentTS + 1 will be queried,\n        // so we do a sanity check here. The assertion will be gone in release mode.\n        assert(timestep == _c_currentTS);\n        key.Reset(_c_currentTS, _c_refLev, _c_compLev, varName, _c_ext_min, _c_ext_max);\n    } else {\n        VAPoR::CoordType extMin, extMax;\n        _params->GetBox()->GetExtents(extMin, extMax);\n        int refLevel = _params->GetRefinementLevel();\n        int compLevel = _params->GetCompressionLevel();\n        key.Reset(timestep, refLevel, compLevel, varName, extMin, extMax);\n    }\n\n    // First check if we have the requested grid in our cache.\n    // If it exists, return the grid directly.\n    const auto* wrapper = _recentGrids.query(key);\n    if (wrapper != nullptr) { return wrapper->grid(); }\n\n    // There's no such grid in our cache!\n    // Let's create a new grid by doing one of the two things, and then put it in the cache.\n    // 1) create it by ourselves if a ConstantGrid is required, or\n    // 2) ask for it from the data manager,\n    //\n\n    // Note that we use a lock here, so no two threads querying _datamgr simultaneously.\n    const std::lock_guard<std::mutex> lock_gd(_grid_operation_mutex);\n\n    VAPoR::Grid *grid = nullptr;\n    if (key.emptyVar()) {\n        // In case of an empty variable name, we generate a constantGrid with zeros.\n        grid = new VAPoR::ConstantGrid(0.0f, 3);\n    } \n    else {\n        if (_params_locked) {\n            grid = _datamgr->GetVariable(_c_currentTS, varName, _c_refLev, _c_compLev, \n                                         _c_ext_min, _c_ext_max, true);\n        } \n        else {\n            VAPoR::CoordType extMin, extMax;\n            _params->GetBox()->GetExtents(extMin, extMax);\n            int refLevel = _params->GetRefinementLevel();\n            int compLevel = _params->GetCompressionLevel();\n            grid = _datamgr->GetVariable(timestep, varName, refLevel, compLevel, extMin, extMax, true);\n        }\n    }\n\n    if (grid == nullptr) {\n        Wasp::MyBase::SetErrMsg(\"Not able to get a grid!\");\n        return nullptr;\n    }\n\n    // Now we have this grid, but also put it in a GridWrapper so\n    // 1) it will be properly deleted, and\n    // 2) it is stored in our cache, where its ownership is kept.\n    auto dim = _datamgr->GetVarTopologyDim(varName);\n\n    if (dim == 1) {\n        Wasp::MyBase::SetErrMsg(\"Variable Dimension Wrong!\");\n        return nullptr;\n    }\n    _recentGrids.insert(key, new GridWrapper(grid, _datamgr));\n    return grid;\n}\n\n\nvoid VaporField::ReleaseLockedGrids()\n{\n    // Release locked grids by giving the cache a bunch of nullptrs with unique invalid keys.\n    GridKey key;\n    for (int i = 0; i < _recentGrids.size(); i++) {\n      key.Reset(std::numeric_limits<uint32_t>::max(), -(i + 2), -(i + 2), \"\", \n                {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0});\n      _recentGrids.insert(key, nullptr);\n    }\n}\n"
  },
  {
    "path": "lib/osgl/CMakeCopy.cmake",
    "content": "cmake_policy(SET CMP0057 NEW)\n\nfunction(COPY_HELPER FILE DESTINATION DEP_LIST)\n    get_filename_component(BASENAME \"${FILE}\" NAME)\n    if (\"${BASENAME}\" IN_LIST COPY_EXCLUDE)\n        return()\n    endif()\n    if (IS_DIRECTORY \"${FILE}\")\n        file(GLOB SUBFILES \"${FILE}/*\")\n        foreach (SUBFILE ${SUBFILES})\n            COPY_HELPER(\"${SUBFILE}\" \"${DESTINATION}/${BASENAME}\" \"${DEP_LIST}\")\n        endforeach()\n    else()\n        set(OUTFILE \"${DESTINATION}/${BASENAME}\")\n        add_custom_command(\n            OUTPUT \"${OUTFILE}\"\n            COMMAND ${CMAKE_COMMAND} -E copy \"${FILE}\" \"${OUTFILE}\"\n            MAIN_DEPENDENCY \"${FILE}\"\n            )\n        list(APPEND DEP_LIST \"${OUTFILE}\")\n        # of course this does not work for custom targets\n        # add_dependencies(target ${OUTFILE})\n    endif()\n    set(DEP_LIST \"${DEP_LIST}\" PARENT_SCOPE)\nendfunction()\n\nset(COPY_HELPER_TARGET_COUNTER 0)\n\nfunction(COPY FILE DESTINATION)\n    include(CMakeParseArguments)\n    cmake_parse_arguments(PARSE_ARGV 2\n        \"COPY\"\n        \"\"\n        \"\"\n        \"EXCLUDE\"\n        )\n\n    get_filename_component(FILE \"${FILE}\" REALPATH)\n\n    list(APPEND DEP_LIST \"\")\n    COPY_HELPER(\"${FILE}\" \"${DESTINATION}\" \"${DEP_LIST}\")\n\n    math(EXPR COPY_HELPER_TARGET_COUNTER \"${COPY_HELPER_TARGET_COUNTER}+1\")\n    set(COPY_HELPER_TARGET_COUNTER ${COPY_HELPER_TARGET_COUNTER} PARENT_SCOPE)\n\n    add_custom_target(\n        copy_helper_${COPY_HELPER_TARGET_COUNTER}\n        ALL\n        DEPENDS ${DEP_LIST}\n    )\nendfunction()\n\n"
  },
  {
    "path": "lib/osgl/CMakeLists.txt",
    "content": "set(LIB osgl)\n\ninclude(CMakeCopy.cmake)\n\nset(BUILD_MESA_DEFAULT OFF)\nif (BUILD_PYTHON AND (UNIX AND NOT APPLE))\n    set(BUILD_MESA_DEFAULT ON)\nendif()\noption (BUILD_MESA \"Build with OSMesa\" ${BUILD_MESA_DEFAULT})\n\noption (SOFTWARE_ONLY \"Disable EGL\" OFF)\nif (NOT SOFTWARE_ONLY)\n    if (UNIX AND NOT APPLE)\n        set(BUILD_EGL ON)\n    endif()\nendif()\n\nif (NOT PROJECT_NAME)\n\tcmake_minimum_required (VERSION 3.10)\n    project (${LIB})\n\tset (CMAKE_CXX_STANDARD 11)\n    # find_package (OpenGL REQUIRED)\n    # include_directories (${OPENGL_INCLUDE_DIRS})\n    set(CMAKE_INSTALL_BINDIR bin)\n    set(CMAKE_INSTALL_LIBDIR lib)\n    set(CMAKE_INSTALL_INCLUDEDIR include/vapor)\n    if(NOT CMAKE_BUILD_TYPE)\n\t    set(CMAKE_BUILD_TYPE \"Debug\" CACHE STRING \"Choose the type of build.\" FORCE)\n    endif()\nelse ()\n    set(CMAKE_INSTALL_BINDIR ${INSTALL_BIN_DIR})\n    set(CMAKE_INSTALL_LIBDIR ${INSTALL_LIB_DIR})\n    set(CMAKE_INSTALL_INCLUDEDIR ${INSTALL_INCLUDE_DIR})\nendif ()\n\nfile (GLOB HDRS ./include/vapor/*.h)\nfile (GLOB SRCS ./*.cpp)\nif (APPLE)\n\tfile (GLOB OBJC_SRCS ./*.mm)\n\tlist (APPEND SRCS ${OBJC_SRCS})\nendif ()\n\nlist(FILTER SRCS EXCLUDE REGEX \"test_[^/]*\\\\.cpp$\")\nlist(FILTER SRCS EXCLUDE REGEX \"ext_[^/]*\\\\.cpp$\")\n\nlist(APPEND SRCS glad/src/egl.c glad/src/gl.c)\nlist(APPEND HDRS glad/include/glad/egl.h glad/include/glad/gl.h)\n# file(COPY glad/include DESTINATION ${CMAKE_BINARY_DIR})\n\nadd_library (${LIB} SHARED ${SRCS} ${HDRS})\n# if (NOT SOFTWARE_ONLY)\n#     target_link_libraries (${LIB} ${OPENGL_LIBRARIES})\n# endif()\ntarget_link_libraries (${LIB} common)\n\nif (APPLE)\n\tfind_library (APPKIT AppKit)\n    target_link_libraries (${LIB} ${APPKIT})\nendif ()\n\nif (UNIX AND NOT APPLE)\n    target_link_libraries (${LIB} rt dl)\n    if (BUILD_EGL)\n        # target_link_libraries(${LIB} EGL)\n        target_compile_definitions(${LIB} PRIVATE BUILD_EGL)\n    endif ()\n    if (BUILD_MESA)\n        target_link_libraries (${LIB} OSMesa)\n        target_compile_definitions(${LIB} PRIVATE BUILD_MESA)\n    endif ()\nendif ()\n\n# if (CONDA_BUILD AND UNIX AND NOT APPLE)\n# target_link_libraries (${LIB} rt)\n# endif()\n\nif (NOT WIN32)\n    target_compile_options(${LIB} PRIVATE -Wno-deprecated-declarations)\nendif()\n# target_compile_options(${LIB} PRIVATE -Wno-unknown-warning-option)\n\n# file(COPY ${HDRS} DESTINATION ${CMAKE_BINARY_DIR}/include/vapor)\n# foreach (HDR ${HDRS})\n#     copy(${HDR} ${CMAKE_BINARY_DIR}/include/vapor) # Does not work with xcode...\n# endforeach()\n# target_include_directories (${LIB} PUBLIC ${CMAKE_BINARY_DIR}/include)\n\ntarget_include_directories (${LIB} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)\ntarget_include_directories (${LIB} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/glad/include)\n\nif (WIN32)\n    add_definitions (-DOSGL_EXPORTS)\n    add_definitions (-DGLAD_API_CALL_EXPORT_BUILD)\nendif()\n\ninstall (\n    TARGETS ${LIB}\n\tDESTINATION ${CMAKE_INSTALL_LIBDIR}\n\tCOMPONENT Libraries\n\t)\n\ninstall (\n\tFILES ${HDRS}\n\tDESTINATION ${CMAKE_INSTALL_INCLUDEDIR}\n\tCOMPONENT Libraries\n\t)\n\ninstall (\n    DIRECTORY glad/include/glad glad/include/KHR glad/include/EGL\n\tDESTINATION ${CMAKE_INSTALL_INCLUDEDIR}\n\tCOMPONENT Libraries\n    )\n\nset (BUILD_OSGL_TESTS OFF)\n\nif (NOT WIN32 AND BUILD_OSGL_TESTS)\n    file (GLOB TESTS ./test_*.cpp)\n    foreach (TEST ${TESTS})\n        get_filename_component(TEST_NAME \"${TEST}\" NAME_WE)\n        set(TEST_TARGET \"${LIB}_${TEST_NAME}\")\n        add_executable(${TEST_TARGET} \"${TEST}\")\n        target_link_libraries(${TEST_TARGET} ${LIB})\n        target_compile_options(${TEST_TARGET} PRIVATE -Wno-deprecated-declarations)\n        install(TARGETS ${TEST_TARGET} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Libraries)\n    endforeach()\nendif()\n"
  },
  {
    "path": "lib/osgl/GLContext.cpp",
    "content": "#include <vapor/GLContext.h>\n#include <vapor/GLContextProviderUtil.h>\n\nString GLContext::GetVersion()\n{\n    MakeCurrent();\n    return GLContextProviderUtil::GetGLVersion();\n}\n"
  },
  {
    "path": "lib/osgl/GLContextProvider.cpp",
    "content": "#include <vapor/GLContextProvider.h>\n#include <vapor/GLContextProviderMacOS.h>\n#include <vapor/GLContextProviderMesa.h>\n#include <vapor/GLContextProviderEGL.h>\n#include <vapor/GLContextProviderNvidia.h>\n#include <vapor/GLContextProviderUtil.h>\n\nGLContext *GLContextProvider::CreateContext()\n{\n#define returnIfSupportedContext(ctxProvider)          \\\n    {                                                  \\\n        GLContext *ctx = ctxProvider::CreateContext(); \\\n        if (isContextOk(ctx))                          \\\n            return ctx;                                \\\n        else if (ctx)                                  \\\n            delete ctx;                                \\\n    }\n#if MacOS\n    returnIfSupportedContext(GLContextProviderMacOS);\n#endif\n\n#if BUILD_EGL\n    returnIfSupportedContext(GLContextProviderNvidia);\n    returnIfSupportedContext(GLContextProviderEGL);\n#endif\n\n#if BUILD_MESA\n    LogWarning(\"Could not get an OpenGL context from the display manager. Is one running?\");\n    LogWarning(\"Falling back to software rendering\");\n    returnIfSupportedContext(GLContextProviderMesa);\n#endif\n\n    LogWarning(\"Could not create OpenGL context\");\n    return nullptr;\n}\n\nbool GLContextProvider::isContextOk(GLContext *ctx)\n{\n    if (ctx == nullptr) return false;\n    ctx->MakeCurrent();\n    return IsCurrentOpenGLVersionSupported();\n}\n\nbool GLContextProvider::IsCurrentOpenGLVersionSupported()\n{\n    int major, minor;\n    GLContextProviderUtil::GetGLVersion(&major, &minor);\n\n    int version = major * 100 + minor;\n\n    if (version >= 303) return true;\n    return false;\n}\n"
  },
  {
    "path": "lib/osgl/GLContextProviderEGL.cpp",
    "content": "#include <vapor/GLContextProviderEGL.h>\n\n#if BUILD_EGL\n\n#if !Linux\n    #error EGL only supported on linux\n#endif\n\n    #include <vapor/GLAD.h>\n    #include <glad/egl.h>\n\nGLContextProviderEGL::GLContextEGL::GLContextEGL(void *display, void *surface, void *context) : _display(display), _surface(surface), _context(context) {}\n\nGLContextProviderEGL::GLContextEGL::~GLContextEGL() { eglTerminate(_display); }\n\nvoid GLContextProviderEGL::GLContextEGL::MakeCurrent() { eglMakeCurrent(_display, _surface, _surface, _context); }\n\n#ifdef NDEBUG\n#define REQUIRED_EGL(f) if (f==NULL) { LogWarning(\"Could not load EGL function %s\", #f); return nullptr; }\n#else\n#define REQUIRED_EGL(f) printf(\"EGL function %-25s %s (%p)\\n\", #f, f?\"ok\":\"FAIL\", f)\n#endif\n\nGLContext *GLContextProviderEGL::CreateContext()\n{\n    if (!gladLoaderLoadEGL(nullptr)) {\n        LogWarning(\"Could not load EGL\");\n        return nullptr;\n    }\n    \n    REQUIRED_EGL(eglGetDisplay);\n    REQUIRED_EGL(eglGetError);\n    REQUIRED_EGL(eglMakeCurrent);\n    REQUIRED_EGL(eglTerminate);\n    \n    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);\n    EGLint     err = eglGetError();\n    if (display == nullptr || err != EGL_SUCCESS) {\n        LogWarning(\"Failed to get a display\");\n        LogWarning(\"EGL Error: %s\", stringifyEGLError(err));\n        return nullptr;\n    }\n\n    return createContextForDisplay(display);\n}\n\nGLContext *GLContextProviderEGL::createContextForDisplay(void *display)\n{\n    if (!gladLoaderLoadEGL(display)) {\n        LogWarning(\"Could not load EGL\");\n        return nullptr;\n    }\n    \n    REQUIRED_EGL(eglInitialize);\n    REQUIRED_EGL(eglGetError);\n    REQUIRED_EGL(eglChooseConfig);\n    REQUIRED_EGL(eglCreatePbufferSurface);\n    REQUIRED_EGL(eglBindAPI);\n    REQUIRED_EGL(eglCreateContext);\n    REQUIRED_EGL(eglGetProcAddress);\n    \n    EGLint     major, minor, err;\n    EGLBoolean ret = eglInitialize(display, &major, &minor);\n    err = eglGetError();\n    if (ret != EGL_TRUE || err != EGL_SUCCESS) {\n        LogWarning(\"Failed to initialize EGL\");\n        LogWarning(\"EGL Error: %s\", stringifyEGLError(err));\n        return nullptr;\n    }\n    LogInfo(\"EGL Version %i.%i\", major, minor);\n\n    EGLint       numConfigs;\n    EGLConfig    config;\n    const EGLint configAttribs[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE};\n\n    eglChooseConfig(display, configAttribs, &config, 1, &numConfigs);\n    err = eglGetError();\n    if (err != EGL_SUCCESS) {\n        LogWarning(\"Failed to get EGL config\");\n        LogWarning(\"EGL Error: %s\", stringifyEGLError(err));\n        return nullptr;\n    }\n\n    const EGLint pbufferAttribs[] = {\n        EGL_WIDTH, 100, EGL_HEIGHT, 100, EGL_NONE,\n    };\n\n    EGLSurface surface = eglCreatePbufferSurface(display, config, pbufferAttribs);\n    err = eglGetError();\n    if (surface == nullptr || err != EGL_SUCCESS) {\n        LogWarning(\"Failed to create surface\");\n        LogWarning(\"EGL Error: %s\", stringifyEGLError(err));\n        return nullptr;\n    }\n\n    eglBindAPI(EGL_OPENGL_API);\n    err = eglGetError();\n    if (err != EGL_SUCCESS) {\n        LogWarning(\"Failed to bind OpenGL API\");\n        LogWarning(\"EGL Error: %s\", stringifyEGLError(err));\n        return nullptr;\n    }\n\n    EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL);\n    err = eglGetError();\n    if (context == nullptr || err != EGL_SUCCESS) {\n        LogWarning(\"Failed to create context\");\n        LogWarning(\"EGL Error: %s\", stringifyEGLError(err));\n        return nullptr;\n    }\n\n    GLContextEGL *glContext = new GLContextEGL(display, surface, context);\n    \n    glContext->MakeCurrent();\n    if (!gladLoadGL((GLADloadfunc)eglGetProcAddress)) {\n        LogWarning(\"Failed to load GL\");\n        delete glContext;\n        return nullptr;\n    }\n\n    LogInfo(\"Created context: %s\", glContext->GetVersion().c_str());\n\n    return glContext;\n}\n\nconst char *GLContextProviderEGL::stringifyEGLError(int e)\n{\n    switch (e) {\n    case EGL_SUCCESS: return \"EGL_SUCCESS\";\n    case EGL_NOT_INITIALIZED: return \"EGL_NOT_INITIALIZED\";\n    case EGL_BAD_ACCESS: return \"EGL_BAD_ACCESS\";\n    case EGL_BAD_ALLOC: return \"EGL_BAD_ALLOC\";\n    case EGL_BAD_ATTRIBUTE: return \"EGL_BAD_ATTRIBUTE\";\n    case EGL_BAD_CONTEXT: return \"EGL_BAD_CONTEXT\";\n    case EGL_BAD_CONFIG: return \"EGL_BAD_CONFIG\";\n    case EGL_BAD_CURRENT_SURFACE: return \"EGL_BAD_CURRENT_SURFACE\";\n    case EGL_BAD_DISPLAY: return \"EGL_BAD_DISPLAY\";\n    case EGL_BAD_SURFACE: return \"EGL_BAD_SURFACE\";\n    case EGL_BAD_MATCH: return \"EGL_BAD_MATCH\";\n    case EGL_BAD_PARAMETER: return \"EGL_BAD_PARAMETER\";\n    case EGL_BAD_NATIVE_PIXMAP: return \"EGL_BAD_NATIVE_PIXMAP\";\n    case EGL_BAD_NATIVE_WINDOW: return \"EGL_BAD_NATIVE_WINDOW\";\n    case EGL_CONTEXT_LOST: return \"EGL_CONTEXT_LOST\";\n    default: return \"EGL_UNKNOWN_ERROR\";\n    }\n}\n\n#endif\n"
  },
  {
    "path": "lib/osgl/GLContextProviderMacOS.mm",
    "content": "#include <vapor/GLContextProviderMacOS.h>\n#include <objc/NSObjCRuntime.h> // This include shouldn't be required but Conda's compiler is sporadically improperly configured.\n#include <AppKit/NSOpenGL.h>\n#include <vapor/GLAD.h>\n#include <OpenGL/CGLContext.h>\n\n// This uses the macOS native libraries which are written in Objective-C.\n\nGLContextProviderMacOS::GLContextMacOS::GLContextMacOS(void *ctx)\n: _ctx(ctx) {}\n\nGLContextProviderMacOS::GLContextMacOS::~GLContextMacOS()\n{\n    NSOpenGLContext *ctx = (NSOpenGLContext *)_ctx;\n    [ctx dealloc];\n}\n\nvoid GLContextProviderMacOS::GLContextMacOS::MakeCurrent()\n{\n    NSOpenGLContext *ctx = (NSOpenGLContext *)_ctx;\n    [ctx makeCurrentContext];\n}\n\nGLContext *GLContextProviderMacOS::CreateContext()\n{\n    NSOpenGLPixelFormatAttribute attrs[] =\n    {\n        NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core, // Undocumented\n        0\n    };\n    \n    NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];\n    if (fmt == nil) {\n        LogWarning(\"Failed to create pixel format\\n\");\n        return nullptr;\n    }\n    \n    NSOpenGLContext *ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:nil];\n    if (ctx == nil) {\n        LogWarning(\"Failed to create context\\n\");\n        [fmt dealloc];\n        return nullptr;\n    }\n    \n    GLContextMacOS *glContext = new GLContextMacOS(ctx);\n    \n    glContext->MakeCurrent();\n    if (!gladLoaderLoadGL()) {\n        LogWarning(\"Failed to load GL\");\n        delete glContext;\n        return nullptr;\n    }\n    \n    LogInfo(\"Created context: %s\", glContext->GetVersion().c_str());\n    \n    return glContext;\n}\n"
  },
  {
    "path": "lib/osgl/GLContextProviderMesa.cpp",
    "content": "#include <vapor/GLContextProviderMesa.h>\n\n#if BUILD_MESA\n    #include <vapor/GLAD.h>\n    #include <GL/osmesa.h>\n\nGLContextProviderMesa::GLContextMesa::GLContextMesa(void *ctx) : _ctx(ctx) {}\n\nGLContextProviderMesa::GLContextMesa::~GLContextMesa()\n{\n    OSMesaContext ctx = (OSMesaContext)_ctx;\n    OSMesaDestroyContext(ctx);\n}\n\nvoid GLContextProviderMesa::GLContextMesa::MakeCurrent()\n{\n    OSMesaContext ctx = (OSMesaContext)_ctx;\n    bool          success = OSMesaMakeCurrent(ctx, _dummyBuffer, GL_UNSIGNED_BYTE, 4, 4);\n    assert(success);\n}\n\nvoid GLContextProviderMesa::GLContextMesa::DumpParameters() const\n{\n#define OSMPP(p) { int v; OSMesaGetIntegerv(p, &v); printf(\"\\t%s = %i\", #p, v); }\n    printf(\"OSMesa Parameters\\n\");\n    OSMPP(OSMESA_WIDTH);\n    OSMPP(OSMESA_HEIGHT);\n    OSMPP(OSMESA_FORMAT);\n    OSMPP(OSMESA_TYPE);\n    OSMPP(OSMESA_ROW_LENGTH);\n    OSMPP(OSMESA_Y_UP);\n#undef OSMPP\n}\n\nGLContext *GLContextProviderMesa::CreateContext()\n{\n    LogInfo(\"OSMesa %i.%i.%i\", OSMESA_MAJOR_VERSION, OSMESA_MINOR_VERSION, OSMESA_PATCH_VERSION);\n    \n    //  Attributes                    Values\n    //  --------------------------------------------------------------------------\n    //  OSMESA_FORMAT                 OSMESA_RGBA*, OSMESA_BGRA, OSMESA_ARGB, OSMESA_RGB etc.\n    //  OSMESA_DEPTH_BITS             0*, 16, 24, 32\n    //  OSMESA_STENCIL_BITS           0*, 8\n    //  OSMESA_ACCUM_BITS             0*, 16\n    //  OSMESA_PROFILE                OSMESA_COMPAT_PROFILE*, OSMESA_CORE_PROFILE\n    //  OSMESA_CONTEXT_MAJOR_VERSION  1*, 2, 3\n    //  OSMESA_CONTEXT_MINOR_VERSION  0+\n    //\n    //  Note: * = default value\n    //  Note: NULL terminated\n    int attrs[] = {\n        OSMESA_FORMAT, OSMESA_RGB,\n        OSMESA_PROFILE, OSMESA_CORE_PROFILE,\n        OSMESA_CONTEXT_MAJOR_VERSION, 3,\n        OSMESA_CONTEXT_MINOR_VERSION, 3,\n        NULL\n    };\n\n    OSMesaContext ctx = nullptr;\n    \n    ctx = OSMesaCreateContextAttribs(attrs, NULL);\n    \n    if (!ctx) {\n        LogWarning(\"OSMesaCreateContextAttribs failed\");\n        OSMesaCreateContextExt(OSMESA_RGB, 0, 0, 0, NULL);\n    }\n    \n    if (!ctx) {\n        LogWarning(\"OSMesaCreateContextExt failed\");\n        ctx = OSMesaCreateContext(OSMESA_RGB, NULL);\n    }\n    \n    if (!ctx) {\n        LogWarning(\"Failed to create context\");\n        return nullptr;\n    }\n\n    GLContextMesa *glContext = new GLContextMesa(ctx);\n    \n    glContext->MakeCurrent();\n    if (!gladLoadGL((GLADloadfunc)OSMesaGetProcAddress)) {\n        LogWarning(\"Failed to load GL\");\n        delete glContext;\n        return nullptr;\n    }\n\n    LogInfo(\"Created context: %s\", glContext->GetVersion().c_str());\n\n    return glContext;\n}\n\n#endif\n"
  },
  {
    "path": "lib/osgl/GLContextProviderNvidia.cpp",
    "content": "#include <vapor/GLContextProviderNvidia.h>\n#include <vapor/STLUtils.h>\n\n#if BUILD_EGL\n\n#if !Linux\n    #error EGL only supported on linux\n#endif\n\n    #include <vapor/GLAD.h>\n    #include <glad/egl.h>\n\n//    Required if using system EGL\n//    #define EGL_EGLEXT_PROTOTYPES\n//    #include <EGL/eglext.h>\n\nGLContext *GLContextProviderNvidia::CreateContext()\n{\n    if (!gladLoaderLoadEGL(nullptr)) {\n        LogWarning(\"Could not load EGL\");\n        return nullptr;\n    }\n    \n    const int    MAX_DEVICES = 8;\n    EGLDeviceEXT eglDevices[MAX_DEVICES];\n    String       eglDeviceStrings[MAX_DEVICES];\n    EGLint       numDevices;\n\n//    Required if using system EGL\n//    PFNEGLQUERYDEVICESEXTPROC       eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress(\"eglQueryDevicesEXT\");\n//    PFNEGLQUERYDEVICESTRINGEXTPROC  eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC)eglGetProcAddress(\"eglQueryDeviceStringEXT\");\n//    PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress(\"eglGetPlatformDisplayEXT\");\n\n    if (eglQueryDevicesEXT == nullptr || eglQueryDeviceStringEXT == nullptr || eglGetPlatformDisplayEXT == nullptr) {\n        LogWarning(\"Could not load Nvidia EGL extensions\");\n        return nullptr;\n    }\n\n    eglQueryDevicesEXT(MAX_DEVICES, eglDevices, &numDevices);\n    for (int i = 0; i < numDevices; i++) {\n        const char *str = eglQueryDeviceStringEXT(eglDevices[i], EGL_EXTENSIONS);\n        eglDeviceStrings[i] = String(str);\n    }\n\n    LogInfo(\"Found %i EGL devices:\", numDevices);\n    for (int i = 0; i < numDevices; i++) Log::Info(\"\\t[%i] = %s\", i, eglDeviceStrings[i].c_str());\n\n    int nvidiaDeviceId = -1;\n    for (int i = 0; i < numDevices; i++) {\n        if (STLUtils::Contains(STLUtils::ToLower(eglDeviceStrings[i]), \"nvidia\") ||\n            STLUtils::Contains(STLUtils::ToLower(eglDeviceStrings[i]), \"egl_nv_\") ) {\n            nvidiaDeviceId = i;\n            break;\n        }\n    }\n\n    if (nvidiaDeviceId >= 0) {\n        LogInfo(\"Found Nvidia GPU [%i] %s\", nvidiaDeviceId, eglDeviceStrings[nvidiaDeviceId].c_str());\n    } else {\n        LogWarning(\"Nvidia GPU not found\");\n        return nullptr;\n    }\n\n    EGLDisplay display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevices[nvidiaDeviceId], 0);\n    EGLint     err = eglGetError();\n    if (display == nullptr || err != EGL_SUCCESS) {\n        LogWarning(\"Failed to get display from Nvidia GPU\");\n        LogWarning(\"EGL Error: %s\", stringifyEGLError(err));\n        return nullptr;\n    }\n\n    return createContextForDisplay(display);\n}\n\n#endif\n"
  },
  {
    "path": "lib/osgl/GLContextProviderUtil.cpp",
    "content": "#include <vapor/GLContextProviderUtil.h>\n#include <vapor/GLInclude.h>\n\nString GLContextProviderUtil::GetGLVersion() {\n    const char *s = (const char *)glGetString(GL_VERSION);\n    assert(s);\n    if (!s)\n        return \"<FAILED glGetString(GL_VERSION)>\";\n    return String(s);\n}\n\nvoid GLContextProviderUtil::GetGLVersion(int *major, int *minor)\n{\n    // Only >=3.0 guarentees glGetIntegerv\n\n    String version = GetGLVersion();\n    version = version.substr(0, version.find(\" \"));\n    const String majorString = version.substr(0, version.find(\".\"));\n    *major = std::stoi(majorString);\n    if (majorString.length() < version.length()) {\n        version = version.substr(majorString.length() + 1);\n        const String minorString = version.substr(0, version.find(\".\"));\n        if (!minorString.empty())\n            *minor = std::stoi(minorString);\n        else\n            *minor = 0;\n    }\n}\n"
  },
  {
    "path": "lib/osgl/Log.cpp",
    "content": "#include <vapor/Log.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <string.h>\n#include <stdlib.h>\n\n#ifdef WIN32\n#include <algorithm>\n#endif\n\nbool Log::InfoLevelEnabled = true;\n\nvoid Log::printc(const char *format, ...)\n{\n    va_list args;\n    va_start(args, format);\n    vprintf(format, args);\n    va_end(args);\n}\n\nvoid Log::fatal() { exit(1); }\n\nString Log::AddLocationToFormat(const String &fmt, const char *file, int line)\n{\n    const char *base = strrchr(file, '/');\n    base = base ? base + 1 : file;\n    int extraPadding = std::max(4 - (int)std::to_string(line).size(), 0);\n    return \"[\" + String(base) + \":\" + std::to_string(line) + \"]\" + std::string(extraPadding, ' ') + fmt;\n}\n"
  },
  {
    "path": "lib/osgl/build.sh",
    "content": "#!/bin/bash\n\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\nexport\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\n\nmkdir build\ncd build\n\n# Since optimizations are disabled, need to disable fortify source otherwise will get barraged with warnings\nexport CPPFLAGS=\"`echo $CPPFLAGS|sed 's/-D_FORTIFY_SOURCE=2//g'`\"\n\n# Ignore extra warnings\nexport CPPFLAGS=\" \\\n    $CPPFLAGS \\\n    \"\n\n# Conda does not properly set CMake flags. This should fix it.\nexport CXXFLAGS=\"$CPPFLAGS $CXXFLAGS\"\nexport CFLAGS=\"$CPPFLAGS $CFLAGS\"\n\ncmake .. \\\n    -DCMAKE_INSTALL_PREFIX:PATH=\"$PREFIX\" \\\n    -DCMAKE_INSTALL_LIBDIR=lib \\\n    -DBUILD_SHARED_LIBS=ON \\\n    -DCMAKE_BUILD_TYPE=DEBUG \\\n    ${CMAKE_ARGS} \\\n    -DCMAKE_C_FLAGS_DEBUG=\"-g -O0\" \\\n    -DCMAKE_CXX_FLAGS_DEBUG=\"-g -O0\" \\\n    -DPython_EXECUTABLE=\"$PYTHON\"\n\n\nmake -j$(($CPU_COUNT+1))\nmake install\n\n\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\necho build =======================================================================================\n"
  },
  {
    "path": "lib/osgl/glad/include/EGL/eglplatform.h",
    "content": "#ifndef __eglplatform_h_\n#define __eglplatform_h_\n\n/*\n** Copyright 2007-2020 The Khronos Group Inc.\n** SPDX-License-Identifier: Apache-2.0\n*/\n\n/* Platform-specific types and definitions for egl.h\n *\n * Adopters may modify khrplatform.h and this file to suit their platform.\n * You are encouraged to submit all modifications to the Khronos group so that\n * they can be included in future versions of this file.  Please submit changes\n * by filing an issue or pull request on the public Khronos EGL Registry, at\n * https://www.github.com/KhronosGroup/EGL-Registry/\n */\n\n#include <KHR/khrplatform.h>\n\n/* Macros used in EGL function prototype declarations.\n *\n * EGL functions should be prototyped as:\n *\n * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);\n * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);\n *\n * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h\n */\n\n#ifndef EGLAPI\n#define EGLAPI KHRONOS_APICALL\n#endif\n\n#ifndef EGLAPIENTRY\n#define EGLAPIENTRY  KHRONOS_APIENTRY\n#endif\n#define EGLAPIENTRYP EGLAPIENTRY*\n\n/* The types NativeDisplayType, NativeWindowType, and NativePixmapType\n * are aliases of window-system-dependent types, such as X Display * or\n * Windows Device Context. They must be defined in platform-specific\n * code below. The EGL-prefixed versions of Native*Type are the same\n * types, renamed in EGL 1.3 so all types in the API start with \"EGL\".\n *\n * Khronos STRONGLY RECOMMENDS that you use the default definitions\n * provided below, since these changes affect both binary and source\n * portability of applications using EGL running on different EGL\n * implementations.\n */\n\n#if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES)\n\ntypedef void *EGLNativeDisplayType;\ntypedef void *EGLNativePixmapType;\ntypedef void *EGLNativeWindowType;\n\n#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN 1\n#endif\n#include <windows.h>\n\ntypedef HDC     EGLNativeDisplayType;\ntypedef HBITMAP EGLNativePixmapType;\ntypedef HWND    EGLNativeWindowType;\n\n#elif defined(__EMSCRIPTEN__)\n\ntypedef int EGLNativeDisplayType;\ntypedef int EGLNativePixmapType;\ntypedef int EGLNativeWindowType;\n\n#elif defined(__WINSCW__) || defined(__SYMBIAN32__)  /* Symbian */\n\ntypedef int   EGLNativeDisplayType;\ntypedef void *EGLNativePixmapType;\ntypedef void *EGLNativeWindowType;\n\n#elif defined(WL_EGL_PLATFORM)\n\ntypedef struct wl_display     *EGLNativeDisplayType;\ntypedef struct wl_egl_pixmap  *EGLNativePixmapType;\ntypedef struct wl_egl_window  *EGLNativeWindowType;\n\n#elif defined(__GBM__)\n\ntypedef struct gbm_device  *EGLNativeDisplayType;\ntypedef struct gbm_bo      *EGLNativePixmapType;\ntypedef void               *EGLNativeWindowType;\n\n#elif defined(__ANDROID__) || defined(ANDROID)\n\nstruct ANativeWindow;\nstruct egl_native_pixmap_t;\n\ntypedef void*                           EGLNativeDisplayType;\ntypedef struct egl_native_pixmap_t*     EGLNativePixmapType;\ntypedef struct ANativeWindow*           EGLNativeWindowType;\n\n#elif defined(USE_OZONE)\n\ntypedef intptr_t EGLNativeDisplayType;\ntypedef intptr_t EGLNativePixmapType;\ntypedef intptr_t EGLNativeWindowType;\n\n#elif defined(USE_X11)\n\n/* X11 (tentative)  */\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n\ntypedef Display *EGLNativeDisplayType;\ntypedef Pixmap   EGLNativePixmapType;\ntypedef Window   EGLNativeWindowType;\n\n#elif defined(__unix__)\n\ntypedef void             *EGLNativeDisplayType;\ntypedef khronos_uintptr_t EGLNativePixmapType;\ntypedef khronos_uintptr_t EGLNativeWindowType;\n\n#elif defined(__APPLE__)\n\ntypedef int   EGLNativeDisplayType;\ntypedef void *EGLNativePixmapType;\ntypedef void *EGLNativeWindowType;\n\n#elif defined(__HAIKU__)\n\n#include <kernel/image.h>\n\ntypedef void              *EGLNativeDisplayType;\ntypedef khronos_uintptr_t  EGLNativePixmapType;\ntypedef khronos_uintptr_t  EGLNativeWindowType;\n\n#elif defined(__Fuchsia__)\n\ntypedef void              *EGLNativeDisplayType;\ntypedef khronos_uintptr_t  EGLNativePixmapType;\ntypedef khronos_uintptr_t  EGLNativeWindowType;\n\n#else\n#error \"Platform not recognized\"\n#endif\n\n/* EGL 1.2 types, renamed for consistency in EGL 1.3 */\ntypedef EGLNativeDisplayType NativeDisplayType;\ntypedef EGLNativePixmapType  NativePixmapType;\ntypedef EGLNativeWindowType  NativeWindowType;\n\n\n/* Define EGLint. This must be a signed integral type large enough to contain\n * all legal attribute names and values passed into and out of EGL, whether\n * their type is boolean, bitmask, enumerant (symbolic constant), integer,\n * handle, or other.  While in general a 32-bit integer will suffice, if\n * handles are 64 bit types, then EGLint should be defined as a signed 64-bit\n * integer type.\n */\ntypedef khronos_int32_t EGLint;\n\n\n/* C++ / C typecast macros for special EGL handle values */\n#if defined(__cplusplus)\n#define EGL_CAST(type, value) (static_cast<type>(value))\n#else\n#define EGL_CAST(type, value) ((type) (value))\n#endif\n\n#endif /* __eglplatform_h */\n"
  },
  {
    "path": "lib/osgl/glad/include/KHR/khrplatform.h",
    "content": "#ifndef __khrplatform_h_\n#define __khrplatform_h_\n\n/*\n** Copyright (c) 2008-2018 The Khronos Group Inc.\n**\n** Permission is hereby granted, free of charge, to any person obtaining a\n** copy of this software and/or associated documentation files (the\n** \"Materials\"), to deal in the Materials without restriction, including\n** without limitation the rights to use, copy, modify, merge, publish,\n** distribute, sublicense, and/or sell copies of the Materials, and to\n** permit persons to whom the Materials are furnished to do so, subject to\n** the following conditions:\n**\n** The above copyright notice and this permission notice shall be included\n** in all copies or substantial portions of the Materials.\n**\n** THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.\n*/\n\n/* Khronos platform-specific types and definitions.\n *\n * The master copy of khrplatform.h is maintained in the Khronos EGL\n * Registry repository at https://github.com/KhronosGroup/EGL-Registry\n * The last semantic modification to khrplatform.h was at commit ID:\n *      67a3e0864c2d75ea5287b9f3d2eb74a745936692\n *\n * Adopters may modify this file to suit their platform. Adopters are\n * encouraged to submit platform specific modifications to the Khronos\n * group so that they can be included in future versions of this file.\n * Please submit changes by filing pull requests or issues on\n * the EGL Registry repository linked above.\n *\n *\n * See the Implementer's Guidelines for information about where this file\n * should be located on your system and for more details of its use:\n *    http://www.khronos.org/registry/implementers_guide.pdf\n *\n * This file should be included as\n *        #include <KHR/khrplatform.h>\n * by Khronos client API header files that use its types and defines.\n *\n * The types in khrplatform.h should only be used to define API-specific types.\n *\n * Types defined in khrplatform.h:\n *    khronos_int8_t              signed   8  bit\n *    khronos_uint8_t             unsigned 8  bit\n *    khronos_int16_t             signed   16 bit\n *    khronos_uint16_t            unsigned 16 bit\n *    khronos_int32_t             signed   32 bit\n *    khronos_uint32_t            unsigned 32 bit\n *    khronos_int64_t             signed   64 bit\n *    khronos_uint64_t            unsigned 64 bit\n *    khronos_intptr_t            signed   same number of bits as a pointer\n *    khronos_uintptr_t           unsigned same number of bits as a pointer\n *    khronos_ssize_t             signed   size\n *    khronos_usize_t             unsigned size\n *    khronos_float_t             signed   32 bit floating point\n *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds\n *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in\n *                                         nanoseconds\n *    khronos_stime_nanoseconds_t signed time interval in nanoseconds\n *    khronos_boolean_enum_t      enumerated boolean type. This should\n *      only be used as a base type when a client API's boolean type is\n *      an enum. Client APIs which use an integer or other type for\n *      booleans cannot use this as the base type for their boolean.\n *\n * Tokens defined in khrplatform.h:\n *\n *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.\n *\n *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.\n *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.\n *\n * Calling convention macros defined in this file:\n *    KHRONOS_APICALL\n *    KHRONOS_APIENTRY\n *    KHRONOS_APIATTRIBUTES\n *\n * These may be used in function prototypes as:\n *\n *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(\n *                                  int arg1,\n *                                  int arg2) KHRONOS_APIATTRIBUTES;\n */\n\n#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)\n#   define KHRONOS_STATIC 1\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APICALL\n *-------------------------------------------------------------------------\n * This precedes the return type of the function in the function prototype.\n */\n#if defined(KHRONOS_STATIC)\n    /* If the preprocessor constant KHRONOS_STATIC is defined, make the\n     * header compatible with static linking. */\n#   define KHRONOS_APICALL\n#elif defined(_WIN32)\n#   define KHRONOS_APICALL __declspec(dllimport)\n#elif defined (__SYMBIAN32__)\n#   define KHRONOS_APICALL IMPORT_C\n#elif defined(__ANDROID__)\n#   define KHRONOS_APICALL __attribute__((visibility(\"default\")))\n#else\n#   define KHRONOS_APICALL\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APIENTRY\n *-------------------------------------------------------------------------\n * This follows the return type of the function  and precedes the function\n * name in the function prototype.\n */\n#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)\n    /* Win32 but not WinCE */\n#   define KHRONOS_APIENTRY __stdcall\n#else\n#   define KHRONOS_APIENTRY\n#endif\n\n/*-------------------------------------------------------------------------\n * Definition of KHRONOS_APIATTRIBUTES\n *-------------------------------------------------------------------------\n * This follows the closing parenthesis of the function prototype arguments.\n */\n#if defined (__ARMCC_2__)\n#define KHRONOS_APIATTRIBUTES __softfp\n#else\n#define KHRONOS_APIATTRIBUTES\n#endif\n\n/*-------------------------------------------------------------------------\n * basic type definitions\n *-----------------------------------------------------------------------*/\n#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)\n\n\n/*\n * Using <stdint.h>\n */\n#include <stdint.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n/*\n * To support platform where unsigned long cannot be used interchangeably with\n * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.\n * Ideally, we could just use (u)intptr_t everywhere, but this could result in\n * ABI breakage if khronos_uintptr_t is changed from unsigned long to\n * unsigned long long or similar (this results in different C++ name mangling).\n * To avoid changes for existing platforms, we restrict usage of intptr_t to\n * platforms where the size of a pointer is larger than the size of long.\n */\n#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)\n#if __SIZEOF_POINTER__ > __SIZEOF_LONG__\n#define KHRONOS_USE_INTPTR_T\n#endif\n#endif\n\n#elif defined(__VMS ) || defined(__sgi)\n\n/*\n * Using <inttypes.h>\n */\n#include <inttypes.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)\n\n/*\n * Win32\n */\ntypedef __int32                 khronos_int32_t;\ntypedef unsigned __int32        khronos_uint32_t;\ntypedef __int64                 khronos_int64_t;\ntypedef unsigned __int64        khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif defined(__sun__) || defined(__digital__)\n\n/*\n * Sun or Digital\n */\ntypedef int                     khronos_int32_t;\ntypedef unsigned int            khronos_uint32_t;\n#if defined(__arch64__) || defined(_LP64)\ntypedef long int                khronos_int64_t;\ntypedef unsigned long int       khronos_uint64_t;\n#else\ntypedef long long int           khronos_int64_t;\ntypedef unsigned long long int  khronos_uint64_t;\n#endif /* __arch64__ */\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#elif 0\n\n/*\n * Hypothetical platform with no float or int64 support\n */\ntypedef int                     khronos_int32_t;\ntypedef unsigned int            khronos_uint32_t;\n#define KHRONOS_SUPPORT_INT64   0\n#define KHRONOS_SUPPORT_FLOAT   0\n\n#else\n\n/*\n * Generic fallback\n */\n#include <stdint.h>\ntypedef int32_t                 khronos_int32_t;\ntypedef uint32_t                khronos_uint32_t;\ntypedef int64_t                 khronos_int64_t;\ntypedef uint64_t                khronos_uint64_t;\n#define KHRONOS_SUPPORT_INT64   1\n#define KHRONOS_SUPPORT_FLOAT   1\n\n#endif\n\n\n/*\n * Types that are (so far) the same on all platforms\n */\ntypedef signed   char          khronos_int8_t;\ntypedef unsigned char          khronos_uint8_t;\ntypedef signed   short int     khronos_int16_t;\ntypedef unsigned short int     khronos_uint16_t;\n\n/*\n * Types that differ between LLP64 and LP64 architectures - in LLP64,\n * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears\n * to be the only LLP64 architecture in current use.\n */\n#ifdef KHRONOS_USE_INTPTR_T\ntypedef intptr_t               khronos_intptr_t;\ntypedef uintptr_t              khronos_uintptr_t;\n#elif defined(_WIN64)\ntypedef signed   long long int khronos_intptr_t;\ntypedef unsigned long long int khronos_uintptr_t;\n#else\ntypedef signed   long  int     khronos_intptr_t;\ntypedef unsigned long  int     khronos_uintptr_t;\n#endif\n\n#if defined(_WIN64)\ntypedef signed   long long int khronos_ssize_t;\ntypedef unsigned long long int khronos_usize_t;\n#else\ntypedef signed   long  int     khronos_ssize_t;\ntypedef unsigned long  int     khronos_usize_t;\n#endif\n\n#if KHRONOS_SUPPORT_FLOAT\n/*\n * Float type\n */\ntypedef          float         khronos_float_t;\n#endif\n\n#if KHRONOS_SUPPORT_INT64\n/* Time types\n *\n * These types can be used to represent a time interval in nanoseconds or\n * an absolute Unadjusted System Time.  Unadjusted System Time is the number\n * of nanoseconds since some arbitrary system event (e.g. since the last\n * time the system booted).  The Unadjusted System Time is an unsigned\n * 64 bit value that wraps back to 0 every 584 years.  Time intervals\n * may be either signed or unsigned.\n */\ntypedef khronos_uint64_t       khronos_utime_nanoseconds_t;\ntypedef khronos_int64_t        khronos_stime_nanoseconds_t;\n#endif\n\n/*\n * Dummy value used to pad enum types to 32 bits.\n */\n#ifndef KHRONOS_MAX_ENUM\n#define KHRONOS_MAX_ENUM 0x7FFFFFFF\n#endif\n\n/*\n * Enumerated boolean type\n *\n * Values other than zero should be considered to be true.  Therefore\n * comparisons should not be made against KHRONOS_TRUE.\n */\ntypedef enum {\n    KHRONOS_FALSE = 0,\n    KHRONOS_TRUE  = 1,\n    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM\n} khronos_boolean_enum_t;\n\n#endif /* __khrplatform_h_ */\n"
  },
  {
    "path": "lib/osgl/glad/include/glad/egl.h",
    "content": "/**\n * Loader generated by glad 2.0.0-beta on Wed Mar 23 06:44:04 2022\n *\n * Generator: C/C++\n * Specification: egl\n * Extensions: 6\n *\n * APIs:\n *  - egl=1.5\n *\n * Options:\n *  - ALIAS = False\n *  - DEBUG = False\n *  - HEADER_ONLY = False\n *  - LOADER = True\n *  - MX = False\n *  - MX_GLOBAL = False\n *  - ON_DEMAND = False\n *\n * Commandline:\n *    --api='egl=1.5' --extensions='EGL_EXT_device_base,EGL_EXT_device_enumeration,EGL_EXT_device_query,EGL_EXT_device_query_name,EGL_EXT_platform_base,EGL_EXT_platform_device' c --loader\n *\n * Online:\n *    http://glad.sh/#api=egl%3D1.5&extensions=EGL_EXT_device_base%2CEGL_EXT_device_enumeration%2CEGL_EXT_device_query%2CEGL_EXT_device_query_name%2CEGL_EXT_platform_base%2CEGL_EXT_platform_device&generator=c&options=LOADER\n *\n */\n\n#ifndef GLAD_EGL_H_\n#define GLAD_EGL_H_\n\n\n#define GLAD_EGL\n#define GLAD_OPTION_EGL_LOADER\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef GLAD_PLATFORM_H_\n#define GLAD_PLATFORM_H_\n\n#ifndef GLAD_PLATFORM_WIN32\n  #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)\n    #define GLAD_PLATFORM_WIN32 1\n  #else\n    #define GLAD_PLATFORM_WIN32 0\n  #endif\n#endif\n\n#ifndef GLAD_PLATFORM_APPLE\n  #ifdef __APPLE__\n    #define GLAD_PLATFORM_APPLE 1\n  #else\n    #define GLAD_PLATFORM_APPLE 0\n  #endif\n#endif\n\n#ifndef GLAD_PLATFORM_EMSCRIPTEN\n  #ifdef __EMSCRIPTEN__\n    #define GLAD_PLATFORM_EMSCRIPTEN 1\n  #else\n    #define GLAD_PLATFORM_EMSCRIPTEN 0\n  #endif\n#endif\n\n#ifndef GLAD_PLATFORM_UWP\n  #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)\n    #ifdef __has_include\n      #if __has_include(<winapifamily.h>)\n        #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1\n      #endif\n    #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_\n      #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1\n    #endif\n  #endif\n\n  #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY\n    #include <winapifamily.h>\n    #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n      #define GLAD_PLATFORM_UWP 1\n    #endif\n  #endif\n\n  #ifndef GLAD_PLATFORM_UWP\n    #define GLAD_PLATFORM_UWP 0\n  #endif\n#endif\n\n#ifdef __GNUC__\n  #define GLAD_GNUC_EXTENSION __extension__\n#else\n  #define GLAD_GNUC_EXTENSION\n#endif\n\n#ifndef GLAD_API_CALL\n  #if defined(GLAD_API_CALL_EXPORT)\n    #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)\n      #if defined(GLAD_API_CALL_EXPORT_BUILD)\n        #if defined(__GNUC__)\n          #define GLAD_API_CALL __attribute__ ((dllexport)) extern\n        #else\n          #define GLAD_API_CALL __declspec(dllexport) extern\n        #endif\n      #else\n        #if defined(__GNUC__)\n          #define GLAD_API_CALL __attribute__ ((dllimport)) extern\n        #else\n          #define GLAD_API_CALL __declspec(dllimport) extern\n        #endif\n      #endif\n    #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)\n      #define GLAD_API_CALL __attribute__ ((visibility (\"default\"))) extern\n    #else\n      #define GLAD_API_CALL extern\n    #endif\n  #else\n    #define GLAD_API_CALL extern\n  #endif\n#endif\n\n#ifdef APIENTRY\n  #define GLAD_API_PTR APIENTRY\n#elif GLAD_PLATFORM_WIN32\n  #define GLAD_API_PTR __stdcall\n#else\n  #define GLAD_API_PTR\n#endif\n\n#ifndef GLAPI\n#define GLAPI GLAD_API_CALL\n#endif\n\n#ifndef GLAPIENTRY\n#define GLAPIENTRY GLAD_API_PTR\n#endif\n\n#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)\n#define GLAD_VERSION_MAJOR(version) (version / 10000)\n#define GLAD_VERSION_MINOR(version) (version % 10000)\n\n#define GLAD_GENERATOR_VERSION \"2.0.0-beta\"\n\ntypedef void (*GLADapiproc)(void);\n\ntypedef GLADapiproc (*GLADloadfunc)(const char *name);\ntypedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);\n\ntypedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);\ntypedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);\n\n#endif /* GLAD_PLATFORM_H_ */\n\n#define EGL_ALPHA_FORMAT 0x3088\n#define EGL_ALPHA_FORMAT_NONPRE 0x308B\n#define EGL_ALPHA_FORMAT_PRE 0x308C\n#define EGL_ALPHA_MASK_SIZE 0x303E\n#define EGL_ALPHA_SIZE 0x3021\n#define EGL_BACK_BUFFER 0x3084\n#define EGL_BAD_ACCESS 0x3002\n#define EGL_BAD_ALLOC 0x3003\n#define EGL_BAD_ATTRIBUTE 0x3004\n#define EGL_BAD_CONFIG 0x3005\n#define EGL_BAD_CONTEXT 0x3006\n#define EGL_BAD_CURRENT_SURFACE 0x3007\n#define EGL_BAD_DEVICE_EXT 0x322B\n#define EGL_BAD_DISPLAY 0x3008\n#define EGL_BAD_MATCH 0x3009\n#define EGL_BAD_NATIVE_PIXMAP 0x300A\n#define EGL_BAD_NATIVE_WINDOW 0x300B\n#define EGL_BAD_PARAMETER 0x300C\n#define EGL_BAD_SURFACE 0x300D\n#define EGL_BIND_TO_TEXTURE_RGB 0x3039\n#define EGL_BIND_TO_TEXTURE_RGBA 0x303A\n#define EGL_BLUE_SIZE 0x3022\n#define EGL_BUFFER_DESTROYED 0x3095\n#define EGL_BUFFER_PRESERVED 0x3094\n#define EGL_BUFFER_SIZE 0x3020\n#define EGL_CLIENT_APIS 0x308D\n#define EGL_CL_EVENT_HANDLE 0x309C\n#define EGL_COLORSPACE 0x3087\n#define EGL_COLORSPACE_LINEAR 0x308A\n#define EGL_COLORSPACE_sRGB 0x3089\n#define EGL_COLOR_BUFFER_TYPE 0x303F\n#define EGL_CONDITION_SATISFIED 0x30F6\n#define EGL_CONFIG_CAVEAT 0x3027\n#define EGL_CONFIG_ID 0x3028\n#define EGL_CONFORMANT 0x3042\n#define EGL_CONTEXT_CLIENT_TYPE 0x3097\n#define EGL_CONTEXT_CLIENT_VERSION 0x3098\n#define EGL_CONTEXT_LOST 0x300E\n#define EGL_CONTEXT_MAJOR_VERSION 0x3098\n#define EGL_CONTEXT_MINOR_VERSION 0x30FB\n#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002\n#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001\n#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0\n#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1\n#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD\n#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD\n#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2\n#define EGL_CORE_NATIVE_ENGINE 0x305B\n#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)\n#define EGL_DEPTH_SIZE 0x3025\n#define EGL_DEVICE_EXT 0x322C\n#define EGL_DISPLAY_SCALING 10000\n#define EGL_DONT_CARE EGL_CAST(EGLint,-1)\n#define EGL_DRAW 0x3059\n#define EGL_EXTENSIONS 0x3055\n#define EGL_FALSE 0\n#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF\n#define EGL_GL_COLORSPACE 0x309D\n#define EGL_GL_COLORSPACE_LINEAR 0x308A\n#define EGL_GL_COLORSPACE_SRGB 0x3089\n#define EGL_GL_RENDERBUFFER 0x30B9\n#define EGL_GL_TEXTURE_2D 0x30B1\n#define EGL_GL_TEXTURE_3D 0x30B2\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6\n#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5\n#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7\n#define EGL_GL_TEXTURE_LEVEL 0x30BC\n#define EGL_GL_TEXTURE_ZOFFSET 0x30BD\n#define EGL_GREEN_SIZE 0x3023\n#define EGL_HEIGHT 0x3056\n#define EGL_HORIZONTAL_RESOLUTION 0x3090\n#define EGL_IMAGE_PRESERVED 0x30D2\n#define EGL_LARGEST_PBUFFER 0x3058\n#define EGL_LEVEL 0x3029\n#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF\n#define EGL_LUMINANCE_BUFFER 0x308F\n#define EGL_LUMINANCE_SIZE 0x303D\n#define EGL_MATCH_NATIVE_PIXMAP 0x3041\n#define EGL_MAX_PBUFFER_HEIGHT 0x302A\n#define EGL_MAX_PBUFFER_PIXELS 0x302B\n#define EGL_MAX_PBUFFER_WIDTH 0x302C\n#define EGL_MAX_SWAP_INTERVAL 0x303C\n#define EGL_MIN_SWAP_INTERVAL 0x303B\n#define EGL_MIPMAP_LEVEL 0x3083\n#define EGL_MIPMAP_TEXTURE 0x3082\n#define EGL_MULTISAMPLE_RESOLVE 0x3099\n#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B\n#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200\n#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A\n#define EGL_NATIVE_RENDERABLE 0x302D\n#define EGL_NATIVE_VISUAL_ID 0x302E\n#define EGL_NATIVE_VISUAL_TYPE 0x302F\n#define EGL_NONE 0x3038\n#define EGL_NON_CONFORMANT_CONFIG 0x3051\n#define EGL_NOT_INITIALIZED 0x3001\n#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)\n#define EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT,0)\n#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)\n#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)\n#define EGL_NO_RESET_NOTIFICATION 0x31BE\n#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)\n#define EGL_NO_SYNC EGL_CAST(EGLSync,0)\n#define EGL_NO_TEXTURE 0x305C\n#define EGL_OPENGL_API 0x30A2\n#define EGL_OPENGL_BIT 0x0008\n#define EGL_OPENGL_ES2_BIT 0x0004\n#define EGL_OPENGL_ES3_BIT 0x00000040\n#define EGL_OPENGL_ES_API 0x30A0\n#define EGL_OPENGL_ES_BIT 0x0001\n#define EGL_OPENVG_API 0x30A1\n#define EGL_OPENVG_BIT 0x0002\n#define EGL_OPENVG_IMAGE 0x3096\n#define EGL_PBUFFER_BIT 0x0001\n#define EGL_PIXEL_ASPECT_RATIO 0x3092\n#define EGL_PIXMAP_BIT 0x0002\n#define EGL_PLATFORM_DEVICE_EXT 0x313F\n#define EGL_READ 0x305A\n#define EGL_RED_SIZE 0x3024\n#define EGL_RENDERABLE_TYPE 0x3040\n#define EGL_RENDERER_EXT 0x335F\n#define EGL_RENDER_BUFFER 0x3086\n#define EGL_RGB_BUFFER 0x308E\n#define EGL_SAMPLES 0x3031\n#define EGL_SAMPLE_BUFFERS 0x3032\n#define EGL_SIGNALED 0x30F2\n#define EGL_SINGLE_BUFFER 0x3085\n#define EGL_SLOW_CONFIG 0x3050\n#define EGL_STENCIL_SIZE 0x3026\n#define EGL_SUCCESS 0x3000\n#define EGL_SURFACE_TYPE 0x3033\n#define EGL_SWAP_BEHAVIOR 0x3093\n#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400\n#define EGL_SYNC_CL_EVENT 0x30FE\n#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF\n#define EGL_SYNC_CONDITION 0x30F8\n#define EGL_SYNC_FENCE 0x30F9\n#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001\n#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0\n#define EGL_SYNC_STATUS 0x30F1\n#define EGL_SYNC_TYPE 0x30F7\n#define EGL_TEXTURE_2D 0x305F\n#define EGL_TEXTURE_FORMAT 0x3080\n#define EGL_TEXTURE_RGB 0x305D\n#define EGL_TEXTURE_RGBA 0x305E\n#define EGL_TEXTURE_TARGET 0x3081\n#define EGL_TIMEOUT_EXPIRED 0x30F5\n#define EGL_TRANSPARENT_BLUE_VALUE 0x3035\n#define EGL_TRANSPARENT_GREEN_VALUE 0x3036\n#define EGL_TRANSPARENT_RED_VALUE 0x3037\n#define EGL_TRANSPARENT_RGB 0x3052\n#define EGL_TRANSPARENT_TYPE 0x3034\n#define EGL_TRUE 1\n#define EGL_UNKNOWN EGL_CAST(EGLint,-1)\n#define EGL_UNSIGNALED 0x30F3\n#define EGL_VENDOR 0x3053\n#define EGL_VERSION 0x3054\n#define EGL_VERTICAL_RESOLUTION 0x3091\n#define EGL_VG_ALPHA_FORMAT 0x3088\n#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B\n#define EGL_VG_ALPHA_FORMAT_PRE 0x308C\n#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040\n#define EGL_VG_COLORSPACE 0x3087\n#define EGL_VG_COLORSPACE_LINEAR 0x308A\n#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020\n#define EGL_VG_COLORSPACE_sRGB 0x3089\n#define EGL_WIDTH 0x3057\n#define EGL_WINDOW_BIT 0x0004\n\n\n#include <KHR/khrplatform.h>\n#include <EGL/eglplatform.h>\n\n\n\n\n\n\n\n\n\n\n\nstruct AHardwareBuffer;\nstruct wl_buffer;\nstruct wl_display;\nstruct wl_resource;\n\ntypedef unsigned int EGLBoolean;\ntypedef unsigned int EGLenum;\ntypedef intptr_t EGLAttribKHR;\ntypedef intptr_t EGLAttrib;\ntypedef void *EGLClientBuffer;\ntypedef void *EGLConfig;\ntypedef void *EGLContext;\ntypedef void *EGLDeviceEXT;\ntypedef void *EGLDisplay;\ntypedef void *EGLImage;\ntypedef void *EGLImageKHR;\ntypedef void *EGLLabelKHR;\ntypedef void *EGLObjectKHR;\ntypedef void *EGLOutputLayerEXT;\ntypedef void *EGLOutputPortEXT;\ntypedef void *EGLStreamKHR;\ntypedef void *EGLSurface;\ntypedef void *EGLSync;\ntypedef void *EGLSyncKHR;\ntypedef void *EGLSyncNV;\ntypedef void (*__eglMustCastToProperFunctionPointerType)(void);\ntypedef khronos_utime_nanoseconds_t EGLTimeKHR;\ntypedef khronos_utime_nanoseconds_t EGLTime;\ntypedef khronos_utime_nanoseconds_t EGLTimeNV;\ntypedef khronos_utime_nanoseconds_t EGLuint64NV;\ntypedef khronos_uint64_t EGLuint64KHR;\ntypedef khronos_stime_nanoseconds_t EGLnsecsANDROID;\ntypedef int EGLNativeFileDescriptorKHR;\ntypedef khronos_ssize_t EGLsizeiANDROID;\ntypedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);\ntypedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);\nstruct EGLClientPixmapHI {\n    void  *pData;\n    EGLint iWidth;\n    EGLint iHeight;\n    EGLint iStride;\n};\ntypedef void (GLAD_API_PTR *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);\n#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC\n#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC\n#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC\n#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC\n\n\n#define EGL_VERSION_1_0 1\nGLAD_API_CALL int GLAD_EGL_VERSION_1_0;\n#define EGL_VERSION_1_1 1\nGLAD_API_CALL int GLAD_EGL_VERSION_1_1;\n#define EGL_VERSION_1_2 1\nGLAD_API_CALL int GLAD_EGL_VERSION_1_2;\n#define EGL_VERSION_1_3 1\nGLAD_API_CALL int GLAD_EGL_VERSION_1_3;\n#define EGL_VERSION_1_4 1\nGLAD_API_CALL int GLAD_EGL_VERSION_1_4;\n#define EGL_VERSION_1_5 1\nGLAD_API_CALL int GLAD_EGL_VERSION_1_5;\n#define EGL_EXT_device_base 1\nGLAD_API_CALL int GLAD_EGL_EXT_device_base;\n#define EGL_EXT_device_enumeration 1\nGLAD_API_CALL int GLAD_EGL_EXT_device_enumeration;\n#define EGL_EXT_device_query 1\nGLAD_API_CALL int GLAD_EGL_EXT_device_query;\n#define EGL_EXT_device_query_name 1\nGLAD_API_CALL int GLAD_EGL_EXT_device_query_name;\n#define EGL_EXT_platform_base 1\nGLAD_API_CALL int GLAD_EGL_EXT_platform_base;\n#define EGL_EXT_platform_device 1\nGLAD_API_CALL int GLAD_EGL_EXT_platform_device;\n\n\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDAPIPROC)(EGLenum api);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDTEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, const EGLint * attrib_list, EGLConfig * configs, EGLint config_size, EGLint * num_config);\ntypedef EGLint (GLAD_API_PTR *PFNEGLCLIENTWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLCOPYBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);\ntypedef EGLContext (GLAD_API_PTR *PFNEGLCREATECONTEXTPROC)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint * attrib_list);\ntypedef EGLImage (GLAD_API_PTR *PFNEGLCREATEIMAGEPROC)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC)(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint * attrib_list);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERSURFACEPROC)(EGLDisplay dpy, EGLConfig config, const EGLint * attrib_list);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint * attrib_list);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC)(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLint * attrib_list);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLint * attrib_list);\ntypedef EGLSync (GLAD_API_PTR *PFNEGLCREATESYNCPROC)(EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint * attrib_list);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSYNCPROC)(EGLDisplay dpy, EGLSync sync);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGSPROC)(EGLDisplay dpy, EGLConfig * configs, EGLint config_size, EGLint * num_config);\ntypedef EGLContext (GLAD_API_PTR *PFNEGLGETCURRENTCONTEXTPROC)(void);\ntypedef EGLDisplay (GLAD_API_PTR *PFNEGLGETCURRENTDISPLAYPROC)(void);\ntypedef EGLSurface (GLAD_API_PTR *PFNEGLGETCURRENTSURFACEPROC)(EGLint readdraw);\ntypedef EGLDisplay (GLAD_API_PTR *PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType display_id);\ntypedef EGLint (GLAD_API_PTR *PFNEGLGETERRORPROC)(void);\ntypedef EGLDisplay (GLAD_API_PTR *PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, void * native_display, const EGLAttrib * attrib_list);\ntypedef EGLDisplay (GLAD_API_PTR *PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum platform, void * native_display, const EGLint * attrib_list);\ntypedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char * procname);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLGETSYNCATTRIBPROC)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint * major, EGLint * minor);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);\ntypedef EGLenum (GLAD_API_PTR *PFNEGLQUERYAPIPROC)(void);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint * value);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDEVICEATTRIBEXTPROC)(EGLDeviceEXT device, EGLint attribute, EGLAttrib * value);\ntypedef const char * (GLAD_API_PTR *PFNEGLQUERYDEVICESTRINGEXTPROC)(EGLDeviceEXT device, EGLint name);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDEVICESEXTPROC)(EGLint max_devices, EGLDeviceEXT * devices, EGLint * num_devices);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYDISPLAYATTRIBEXTPROC)(EGLDisplay dpy, EGLint attribute, EGLAttrib * value);\ntypedef const char * (GLAD_API_PTR *PFNEGLQUERYSTRINGPROC)(EGLDisplay dpy, EGLint name);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint * value);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETHREADPROC)(void);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLSURFACEATTRIBPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPINTERVALPROC)(EGLDisplay dpy, EGLint interval);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLTERMINATEPROC)(EGLDisplay dpy);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITCLIENTPROC)(void);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITGLPROC)(void);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITNATIVEPROC)(EGLint engine);\ntypedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags);\n\nGLAD_API_CALL PFNEGLBINDAPIPROC glad_eglBindAPI;\n#define eglBindAPI glad_eglBindAPI\nGLAD_API_CALL PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage;\n#define eglBindTexImage glad_eglBindTexImage\nGLAD_API_CALL PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig;\n#define eglChooseConfig glad_eglChooseConfig\nGLAD_API_CALL PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync;\n#define eglClientWaitSync glad_eglClientWaitSync\nGLAD_API_CALL PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers;\n#define eglCopyBuffers glad_eglCopyBuffers\nGLAD_API_CALL PFNEGLCREATECONTEXTPROC glad_eglCreateContext;\n#define eglCreateContext glad_eglCreateContext\nGLAD_API_CALL PFNEGLCREATEIMAGEPROC glad_eglCreateImage;\n#define eglCreateImage glad_eglCreateImage\nGLAD_API_CALL PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer;\n#define eglCreatePbufferFromClientBuffer glad_eglCreatePbufferFromClientBuffer\nGLAD_API_CALL PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface;\n#define eglCreatePbufferSurface glad_eglCreatePbufferSurface\nGLAD_API_CALL PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface;\n#define eglCreatePixmapSurface glad_eglCreatePixmapSurface\nGLAD_API_CALL PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface;\n#define eglCreatePlatformPixmapSurface glad_eglCreatePlatformPixmapSurface\nGLAD_API_CALL PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC glad_eglCreatePlatformPixmapSurfaceEXT;\n#define eglCreatePlatformPixmapSurfaceEXT glad_eglCreatePlatformPixmapSurfaceEXT\nGLAD_API_CALL PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface;\n#define eglCreatePlatformWindowSurface glad_eglCreatePlatformWindowSurface\nGLAD_API_CALL PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC glad_eglCreatePlatformWindowSurfaceEXT;\n#define eglCreatePlatformWindowSurfaceEXT glad_eglCreatePlatformWindowSurfaceEXT\nGLAD_API_CALL PFNEGLCREATESYNCPROC glad_eglCreateSync;\n#define eglCreateSync glad_eglCreateSync\nGLAD_API_CALL PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface;\n#define eglCreateWindowSurface glad_eglCreateWindowSurface\nGLAD_API_CALL PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext;\n#define eglDestroyContext glad_eglDestroyContext\nGLAD_API_CALL PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage;\n#define eglDestroyImage glad_eglDestroyImage\nGLAD_API_CALL PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface;\n#define eglDestroySurface glad_eglDestroySurface\nGLAD_API_CALL PFNEGLDESTROYSYNCPROC glad_eglDestroySync;\n#define eglDestroySync glad_eglDestroySync\nGLAD_API_CALL PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib;\n#define eglGetConfigAttrib glad_eglGetConfigAttrib\nGLAD_API_CALL PFNEGLGETCONFIGSPROC glad_eglGetConfigs;\n#define eglGetConfigs glad_eglGetConfigs\nGLAD_API_CALL PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext;\n#define eglGetCurrentContext glad_eglGetCurrentContext\nGLAD_API_CALL PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay;\n#define eglGetCurrentDisplay glad_eglGetCurrentDisplay\nGLAD_API_CALL PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface;\n#define eglGetCurrentSurface glad_eglGetCurrentSurface\nGLAD_API_CALL PFNEGLGETDISPLAYPROC glad_eglGetDisplay;\n#define eglGetDisplay glad_eglGetDisplay\nGLAD_API_CALL PFNEGLGETERRORPROC glad_eglGetError;\n#define eglGetError glad_eglGetError\nGLAD_API_CALL PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay;\n#define eglGetPlatformDisplay glad_eglGetPlatformDisplay\nGLAD_API_CALL PFNEGLGETPLATFORMDISPLAYEXTPROC glad_eglGetPlatformDisplayEXT;\n#define eglGetPlatformDisplayEXT glad_eglGetPlatformDisplayEXT\nGLAD_API_CALL PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress;\n#define eglGetProcAddress glad_eglGetProcAddress\nGLAD_API_CALL PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib;\n#define eglGetSyncAttrib glad_eglGetSyncAttrib\nGLAD_API_CALL PFNEGLINITIALIZEPROC glad_eglInitialize;\n#define eglInitialize glad_eglInitialize\nGLAD_API_CALL PFNEGLMAKECURRENTPROC glad_eglMakeCurrent;\n#define eglMakeCurrent glad_eglMakeCurrent\nGLAD_API_CALL PFNEGLQUERYAPIPROC glad_eglQueryAPI;\n#define eglQueryAPI glad_eglQueryAPI\nGLAD_API_CALL PFNEGLQUERYCONTEXTPROC glad_eglQueryContext;\n#define eglQueryContext glad_eglQueryContext\nGLAD_API_CALL PFNEGLQUERYDEVICEATTRIBEXTPROC glad_eglQueryDeviceAttribEXT;\n#define eglQueryDeviceAttribEXT glad_eglQueryDeviceAttribEXT\nGLAD_API_CALL PFNEGLQUERYDEVICESTRINGEXTPROC glad_eglQueryDeviceStringEXT;\n#define eglQueryDeviceStringEXT glad_eglQueryDeviceStringEXT\nGLAD_API_CALL PFNEGLQUERYDEVICESEXTPROC glad_eglQueryDevicesEXT;\n#define eglQueryDevicesEXT glad_eglQueryDevicesEXT\nGLAD_API_CALL PFNEGLQUERYDISPLAYATTRIBEXTPROC glad_eglQueryDisplayAttribEXT;\n#define eglQueryDisplayAttribEXT glad_eglQueryDisplayAttribEXT\nGLAD_API_CALL PFNEGLQUERYSTRINGPROC glad_eglQueryString;\n#define eglQueryString glad_eglQueryString\nGLAD_API_CALL PFNEGLQUERYSURFACEPROC glad_eglQuerySurface;\n#define eglQuerySurface glad_eglQuerySurface\nGLAD_API_CALL PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage;\n#define eglReleaseTexImage glad_eglReleaseTexImage\nGLAD_API_CALL PFNEGLRELEASETHREADPROC glad_eglReleaseThread;\n#define eglReleaseThread glad_eglReleaseThread\nGLAD_API_CALL PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib;\n#define eglSurfaceAttrib glad_eglSurfaceAttrib\nGLAD_API_CALL PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers;\n#define eglSwapBuffers glad_eglSwapBuffers\nGLAD_API_CALL PFNEGLSWAPINTERVALPROC glad_eglSwapInterval;\n#define eglSwapInterval glad_eglSwapInterval\nGLAD_API_CALL PFNEGLTERMINATEPROC glad_eglTerminate;\n#define eglTerminate glad_eglTerminate\nGLAD_API_CALL PFNEGLWAITCLIENTPROC glad_eglWaitClient;\n#define eglWaitClient glad_eglWaitClient\nGLAD_API_CALL PFNEGLWAITGLPROC glad_eglWaitGL;\n#define eglWaitGL glad_eglWaitGL\nGLAD_API_CALL PFNEGLWAITNATIVEPROC glad_eglWaitNative;\n#define eglWaitNative glad_eglWaitNative\nGLAD_API_CALL PFNEGLWAITSYNCPROC glad_eglWaitSync;\n#define eglWaitSync glad_eglWaitSync\n\n\n\n\n\nGLAD_API_CALL int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr);\nGLAD_API_CALL int gladLoadEGL(EGLDisplay display, GLADloadfunc load);\n\n#ifdef GLAD_EGL\n\nGLAD_API_CALL int gladLoaderLoadEGL(EGLDisplay display);\n\nGLAD_API_CALL void gladLoaderUnloadEGL(void);\n\n#endif\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "lib/osgl/glad/include/glad/gl.h",
    "content": "/**\n * Loader generated by glad 2.0.0-beta on Wed Mar 23 06:44:05 2022\n *\n * Generator: C/C++\n * Specification: gl\n * Extensions: 0\n *\n * APIs:\n *  - gl:core=4.1\n *\n * Options:\n *  - ALIAS = False\n *  - DEBUG = False\n *  - HEADER_ONLY = False\n *  - LOADER = True\n *  - MX = False\n *  - MX_GLOBAL = False\n *  - ON_DEMAND = False\n *\n * Commandline:\n *    --api='gl:core=4.1' --extensions='' c --loader\n *\n * Online:\n *    http://glad.sh/#api=gl%3Acore%3D4.1&extensions=&generator=c&options=LOADER\n *\n */\n\n#ifndef GLAD_GL_H_\n#define GLAD_GL_H_\n\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wreserved-id-macro\"\n#endif\n#ifdef __gl_h_\n  #error OpenGL (gl.h) header already included (API: gl), remove previous include!\n#endif\n#define __gl_h_ 1\n#ifdef __gl3_h_\n  #error OpenGL (gl3.h) header already included (API: gl), remove previous include!\n#endif\n#define __gl3_h_ 1\n#ifdef __glext_h_\n  #error OpenGL (glext.h) header already included (API: gl), remove previous include!\n#endif\n#define __glext_h_ 1\n#ifdef __gl3ext_h_\n  #error OpenGL (gl3ext.h) header already included (API: gl), remove previous include!\n#endif\n#define __gl3ext_h_ 1\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n#define GLAD_GL\n#define GLAD_OPTION_GL_LOADER\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef GLAD_PLATFORM_H_\n#define GLAD_PLATFORM_H_\n\n#ifndef GLAD_PLATFORM_WIN32\n  #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)\n    #define GLAD_PLATFORM_WIN32 1\n  #else\n    #define GLAD_PLATFORM_WIN32 0\n  #endif\n#endif\n\n#ifndef GLAD_PLATFORM_APPLE\n  #ifdef __APPLE__\n    #define GLAD_PLATFORM_APPLE 1\n  #else\n    #define GLAD_PLATFORM_APPLE 0\n  #endif\n#endif\n\n#ifndef GLAD_PLATFORM_EMSCRIPTEN\n  #ifdef __EMSCRIPTEN__\n    #define GLAD_PLATFORM_EMSCRIPTEN 1\n  #else\n    #define GLAD_PLATFORM_EMSCRIPTEN 0\n  #endif\n#endif\n\n#ifndef GLAD_PLATFORM_UWP\n  #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)\n    #ifdef __has_include\n      #if __has_include(<winapifamily.h>)\n        #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1\n      #endif\n    #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_\n      #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1\n    #endif\n  #endif\n\n  #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY\n    #include <winapifamily.h>\n    #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)\n      #define GLAD_PLATFORM_UWP 1\n    #endif\n  #endif\n\n  #ifndef GLAD_PLATFORM_UWP\n    #define GLAD_PLATFORM_UWP 0\n  #endif\n#endif\n\n#ifdef __GNUC__\n  #define GLAD_GNUC_EXTENSION __extension__\n#else\n  #define GLAD_GNUC_EXTENSION\n#endif\n\n#ifndef GLAD_API_CALL\n  #if defined(GLAD_API_CALL_EXPORT)\n    #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)\n      #if defined(GLAD_API_CALL_EXPORT_BUILD)\n        #if defined(__GNUC__)\n          #define GLAD_API_CALL __attribute__ ((dllexport)) extern\n        #else\n          #define GLAD_API_CALL __declspec(dllexport) extern\n        #endif\n      #else\n        #if defined(__GNUC__)\n          #define GLAD_API_CALL __attribute__ ((dllimport)) extern\n        #else\n          #define GLAD_API_CALL __declspec(dllimport) extern\n        #endif\n      #endif\n    #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)\n      #define GLAD_API_CALL __attribute__ ((visibility (\"default\"))) extern\n    #else\n      #define GLAD_API_CALL extern\n    #endif\n  #else\n    #define GLAD_API_CALL extern\n  #endif\n#endif\n\n#ifdef APIENTRY\n  #define GLAD_API_PTR APIENTRY\n#elif GLAD_PLATFORM_WIN32\n  #define GLAD_API_PTR __stdcall\n#else\n  #define GLAD_API_PTR\n#endif\n\n#ifndef GLAPI\n#define GLAPI GLAD_API_CALL\n#endif\n\n#ifndef GLAPIENTRY\n#define GLAPIENTRY GLAD_API_PTR\n#endif\n\n#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)\n#define GLAD_VERSION_MAJOR(version) (version / 10000)\n#define GLAD_VERSION_MINOR(version) (version % 10000)\n\n#define GLAD_GENERATOR_VERSION \"2.0.0-beta\"\n\ntypedef void (*GLADapiproc)(void);\n\ntypedef GLADapiproc (*GLADloadfunc)(const char *name);\ntypedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);\n\ntypedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);\ntypedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);\n\n#endif /* GLAD_PLATFORM_H_ */\n\n#define GL_ACTIVE_ATTRIBUTES 0x8B89\n#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A\n#define GL_ACTIVE_PROGRAM 0x8259\n#define GL_ACTIVE_SUBROUTINES 0x8DE5\n#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48\n#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6\n#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47\n#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49\n#define GL_ACTIVE_TEXTURE 0x84E0\n#define GL_ACTIVE_UNIFORMS 0x8B86\n#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36\n#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35\n#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87\n#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E\n#define GL_ALL_SHADER_BITS 0xFFFFFFFF\n#define GL_ALPHA 0x1906\n#define GL_ALREADY_SIGNALED 0x911A\n#define GL_ALWAYS 0x0207\n#define GL_AND 0x1501\n#define GL_AND_INVERTED 0x1504\n#define GL_AND_REVERSE 0x1502\n#define GL_ANY_SAMPLES_PASSED 0x8C2F\n#define GL_ARRAY_BUFFER 0x8892\n#define GL_ARRAY_BUFFER_BINDING 0x8894\n#define GL_ATTACHED_SHADERS 0x8B85\n#define GL_BACK 0x0405\n#define GL_BACK_LEFT 0x0402\n#define GL_BACK_RIGHT 0x0403\n#define GL_BGR 0x80E0\n#define GL_BGRA 0x80E1\n#define GL_BGRA_INTEGER 0x8D9B\n#define GL_BGR_INTEGER 0x8D9A\n#define GL_BLEND 0x0BE2\n#define GL_BLEND_COLOR 0x8005\n#define GL_BLEND_DST 0x0BE0\n#define GL_BLEND_DST_ALPHA 0x80CA\n#define GL_BLEND_DST_RGB 0x80C8\n#define GL_BLEND_EQUATION 0x8009\n#define GL_BLEND_EQUATION_ALPHA 0x883D\n#define GL_BLEND_EQUATION_RGB 0x8009\n#define GL_BLEND_SRC 0x0BE1\n#define GL_BLEND_SRC_ALPHA 0x80CB\n#define GL_BLEND_SRC_RGB 0x80C9\n#define GL_BLUE 0x1905\n#define GL_BLUE_INTEGER 0x8D96\n#define GL_BOOL 0x8B56\n#define GL_BOOL_VEC2 0x8B57\n#define GL_BOOL_VEC3 0x8B58\n#define GL_BOOL_VEC4 0x8B59\n#define GL_BUFFER_ACCESS 0x88BB\n#define GL_BUFFER_ACCESS_FLAGS 0x911F\n#define GL_BUFFER_MAPPED 0x88BC\n#define GL_BUFFER_MAP_LENGTH 0x9120\n#define GL_BUFFER_MAP_OFFSET 0x9121\n#define GL_BUFFER_MAP_POINTER 0x88BD\n#define GL_BUFFER_SIZE 0x8764\n#define GL_BUFFER_USAGE 0x8765\n#define GL_BYTE 0x1400\n#define GL_CCW 0x0901\n#define GL_CLAMP_READ_COLOR 0x891C\n#define GL_CLAMP_TO_BORDER 0x812D\n#define GL_CLAMP_TO_EDGE 0x812F\n#define GL_CLEAR 0x1500\n#define GL_CLIP_DISTANCE0 0x3000\n#define GL_CLIP_DISTANCE1 0x3001\n#define GL_CLIP_DISTANCE2 0x3002\n#define GL_CLIP_DISTANCE3 0x3003\n#define GL_CLIP_DISTANCE4 0x3004\n#define GL_CLIP_DISTANCE5 0x3005\n#define GL_CLIP_DISTANCE6 0x3006\n#define GL_CLIP_DISTANCE7 0x3007\n#define GL_COLOR 0x1800\n#define GL_COLOR_ATTACHMENT0 0x8CE0\n#define GL_COLOR_ATTACHMENT1 0x8CE1\n#define GL_COLOR_ATTACHMENT10 0x8CEA\n#define GL_COLOR_ATTACHMENT11 0x8CEB\n#define GL_COLOR_ATTACHMENT12 0x8CEC\n#define GL_COLOR_ATTACHMENT13 0x8CED\n#define GL_COLOR_ATTACHMENT14 0x8CEE\n#define GL_COLOR_ATTACHMENT15 0x8CEF\n#define GL_COLOR_ATTACHMENT16 0x8CF0\n#define GL_COLOR_ATTACHMENT17 0x8CF1\n#define GL_COLOR_ATTACHMENT18 0x8CF2\n#define GL_COLOR_ATTACHMENT19 0x8CF3\n#define GL_COLOR_ATTACHMENT2 0x8CE2\n#define GL_COLOR_ATTACHMENT20 0x8CF4\n#define GL_COLOR_ATTACHMENT21 0x8CF5\n#define GL_COLOR_ATTACHMENT22 0x8CF6\n#define GL_COLOR_ATTACHMENT23 0x8CF7\n#define GL_COLOR_ATTACHMENT24 0x8CF8\n#define GL_COLOR_ATTACHMENT25 0x8CF9\n#define GL_COLOR_ATTACHMENT26 0x8CFA\n#define GL_COLOR_ATTACHMENT27 0x8CFB\n#define GL_COLOR_ATTACHMENT28 0x8CFC\n#define GL_COLOR_ATTACHMENT29 0x8CFD\n#define GL_COLOR_ATTACHMENT3 0x8CE3\n#define GL_COLOR_ATTACHMENT30 0x8CFE\n#define GL_COLOR_ATTACHMENT31 0x8CFF\n#define GL_COLOR_ATTACHMENT4 0x8CE4\n#define GL_COLOR_ATTACHMENT5 0x8CE5\n#define GL_COLOR_ATTACHMENT6 0x8CE6\n#define GL_COLOR_ATTACHMENT7 0x8CE7\n#define GL_COLOR_ATTACHMENT8 0x8CE8\n#define GL_COLOR_ATTACHMENT9 0x8CE9\n#define GL_COLOR_BUFFER_BIT 0x00004000\n#define GL_COLOR_CLEAR_VALUE 0x0C22\n#define GL_COLOR_LOGIC_OP 0x0BF2\n#define GL_COLOR_WRITEMASK 0x0C23\n#define GL_COMPARE_REF_TO_TEXTURE 0x884E\n#define GL_COMPATIBLE_SUBROUTINES 0x8E4B\n#define GL_COMPILE_STATUS 0x8B81\n#define GL_COMPRESSED_RED 0x8225\n#define GL_COMPRESSED_RED_RGTC1 0x8DBB\n#define GL_COMPRESSED_RG 0x8226\n#define GL_COMPRESSED_RGB 0x84ED\n#define GL_COMPRESSED_RGBA 0x84EE\n#define GL_COMPRESSED_RG_RGTC2 0x8DBD\n#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC\n#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE\n#define GL_COMPRESSED_SRGB 0x8C48\n#define GL_COMPRESSED_SRGB_ALPHA 0x8C49\n#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3\n#define GL_CONDITION_SATISFIED 0x911C\n#define GL_CONSTANT_ALPHA 0x8003\n#define GL_CONSTANT_COLOR 0x8001\n#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002\n#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001\n#define GL_CONTEXT_FLAGS 0x821E\n#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001\n#define GL_CONTEXT_PROFILE_MASK 0x9126\n#define GL_COPY 0x1503\n#define GL_COPY_INVERTED 0x150C\n#define GL_COPY_READ_BUFFER 0x8F36\n#define GL_COPY_WRITE_BUFFER 0x8F37\n#define GL_CULL_FACE 0x0B44\n#define GL_CULL_FACE_MODE 0x0B45\n#define GL_CURRENT_PROGRAM 0x8B8D\n#define GL_CURRENT_QUERY 0x8865\n#define GL_CURRENT_VERTEX_ATTRIB 0x8626\n#define GL_CW 0x0900\n#define GL_DECR 0x1E03\n#define GL_DECR_WRAP 0x8508\n#define GL_DELETE_STATUS 0x8B80\n#define GL_DEPTH 0x1801\n#define GL_DEPTH24_STENCIL8 0x88F0\n#define GL_DEPTH32F_STENCIL8 0x8CAD\n#define GL_DEPTH_ATTACHMENT 0x8D00\n#define GL_DEPTH_BUFFER_BIT 0x00000100\n#define GL_DEPTH_CLAMP 0x864F\n#define GL_DEPTH_CLEAR_VALUE 0x0B73\n#define GL_DEPTH_COMPONENT 0x1902\n#define GL_DEPTH_COMPONENT16 0x81A5\n#define GL_DEPTH_COMPONENT24 0x81A6\n#define GL_DEPTH_COMPONENT32 0x81A7\n#define GL_DEPTH_COMPONENT32F 0x8CAC\n#define GL_DEPTH_FUNC 0x0B74\n#define GL_DEPTH_RANGE 0x0B70\n#define GL_DEPTH_STENCIL 0x84F9\n#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A\n#define GL_DEPTH_TEST 0x0B71\n#define GL_DEPTH_WRITEMASK 0x0B72\n#define GL_DITHER 0x0BD0\n#define GL_DONT_CARE 0x1100\n#define GL_DOUBLE 0x140A\n#define GL_DOUBLEBUFFER 0x0C32\n#define GL_DOUBLE_MAT2 0x8F46\n#define GL_DOUBLE_MAT2x3 0x8F49\n#define GL_DOUBLE_MAT2x4 0x8F4A\n#define GL_DOUBLE_MAT3 0x8F47\n#define GL_DOUBLE_MAT3x2 0x8F4B\n#define GL_DOUBLE_MAT3x4 0x8F4C\n#define GL_DOUBLE_MAT4 0x8F48\n#define GL_DOUBLE_MAT4x2 0x8F4D\n#define GL_DOUBLE_MAT4x3 0x8F4E\n#define GL_DOUBLE_VEC2 0x8FFC\n#define GL_DOUBLE_VEC3 0x8FFD\n#define GL_DOUBLE_VEC4 0x8FFE\n#define GL_DRAW_BUFFER 0x0C01\n#define GL_DRAW_BUFFER0 0x8825\n#define GL_DRAW_BUFFER1 0x8826\n#define GL_DRAW_BUFFER10 0x882F\n#define GL_DRAW_BUFFER11 0x8830\n#define GL_DRAW_BUFFER12 0x8831\n#define GL_DRAW_BUFFER13 0x8832\n#define GL_DRAW_BUFFER14 0x8833\n#define GL_DRAW_BUFFER15 0x8834\n#define GL_DRAW_BUFFER2 0x8827\n#define GL_DRAW_BUFFER3 0x8828\n#define GL_DRAW_BUFFER4 0x8829\n#define GL_DRAW_BUFFER5 0x882A\n#define GL_DRAW_BUFFER6 0x882B\n#define GL_DRAW_BUFFER7 0x882C\n#define GL_DRAW_BUFFER8 0x882D\n#define GL_DRAW_BUFFER9 0x882E\n#define GL_DRAW_FRAMEBUFFER 0x8CA9\n#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6\n#define GL_DRAW_INDIRECT_BUFFER 0x8F3F\n#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43\n#define GL_DST_ALPHA 0x0304\n#define GL_DST_COLOR 0x0306\n#define GL_DYNAMIC_COPY 0x88EA\n#define GL_DYNAMIC_DRAW 0x88E8\n#define GL_DYNAMIC_READ 0x88E9\n#define GL_ELEMENT_ARRAY_BUFFER 0x8893\n#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895\n#define GL_EQUAL 0x0202\n#define GL_EQUIV 0x1509\n#define GL_EXTENSIONS 0x1F03\n#define GL_FALSE 0\n#define GL_FASTEST 0x1101\n#define GL_FILL 0x1B02\n#define GL_FIRST_VERTEX_CONVENTION 0x8E4D\n#define GL_FIXED 0x140C\n#define GL_FIXED_ONLY 0x891D\n#define GL_FLOAT 0x1406\n#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD\n#define GL_FLOAT_MAT2 0x8B5A\n#define GL_FLOAT_MAT2x3 0x8B65\n#define GL_FLOAT_MAT2x4 0x8B66\n#define GL_FLOAT_MAT3 0x8B5B\n#define GL_FLOAT_MAT3x2 0x8B67\n#define GL_FLOAT_MAT3x4 0x8B68\n#define GL_FLOAT_MAT4 0x8B5C\n#define GL_FLOAT_MAT4x2 0x8B69\n#define GL_FLOAT_MAT4x3 0x8B6A\n#define GL_FLOAT_VEC2 0x8B50\n#define GL_FLOAT_VEC3 0x8B51\n#define GL_FLOAT_VEC4 0x8B52\n#define GL_FRACTIONAL_EVEN 0x8E7C\n#define GL_FRACTIONAL_ODD 0x8E7B\n#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D\n#define GL_FRAGMENT_SHADER 0x8B30\n#define GL_FRAGMENT_SHADER_BIT 0x00000002\n#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B\n#define GL_FRAMEBUFFER 0x8D40\n#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215\n#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214\n#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210\n#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211\n#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216\n#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213\n#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7\n#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1\n#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0\n#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212\n#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4\n#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2\n#define GL_FRAMEBUFFER_BINDING 0x8CA6\n#define GL_FRAMEBUFFER_COMPLETE 0x8CD5\n#define GL_FRAMEBUFFER_DEFAULT 0x8218\n#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6\n#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB\n#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8\n#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7\n#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56\n#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC\n#define GL_FRAMEBUFFER_SRGB 0x8DB9\n#define GL_FRAMEBUFFER_UNDEFINED 0x8219\n#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD\n#define GL_FRONT 0x0404\n#define GL_FRONT_AND_BACK 0x0408\n#define GL_FRONT_FACE 0x0B46\n#define GL_FRONT_LEFT 0x0400\n#define GL_FRONT_RIGHT 0x0401\n#define GL_FUNC_ADD 0x8006\n#define GL_FUNC_REVERSE_SUBTRACT 0x800B\n#define GL_FUNC_SUBTRACT 0x800A\n#define GL_GEOMETRY_INPUT_TYPE 0x8917\n#define GL_GEOMETRY_OUTPUT_TYPE 0x8918\n#define GL_GEOMETRY_SHADER 0x8DD9\n#define GL_GEOMETRY_SHADER_BIT 0x00000004\n#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F\n#define GL_GEOMETRY_VERTICES_OUT 0x8916\n#define GL_GEQUAL 0x0206\n#define GL_GREATER 0x0204\n#define GL_GREEN 0x1904\n#define GL_GREEN_INTEGER 0x8D95\n#define GL_HALF_FLOAT 0x140B\n#define GL_HIGH_FLOAT 0x8DF2\n#define GL_HIGH_INT 0x8DF5\n#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B\n#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A\n#define GL_INCR 0x1E02\n#define GL_INCR_WRAP 0x8507\n#define GL_INFO_LOG_LENGTH 0x8B84\n#define GL_INT 0x1404\n#define GL_INTERLEAVED_ATTRIBS 0x8C8C\n#define GL_INT_2_10_10_10_REV 0x8D9F\n#define GL_INT_SAMPLER_1D 0x8DC9\n#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE\n#define GL_INT_SAMPLER_2D 0x8DCA\n#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF\n#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109\n#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C\n#define GL_INT_SAMPLER_2D_RECT 0x8DCD\n#define GL_INT_SAMPLER_3D 0x8DCB\n#define GL_INT_SAMPLER_BUFFER 0x8DD0\n#define GL_INT_SAMPLER_CUBE 0x8DCC\n#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E\n#define GL_INT_VEC2 0x8B53\n#define GL_INT_VEC3 0x8B54\n#define GL_INT_VEC4 0x8B55\n#define GL_INVALID_ENUM 0x0500\n#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506\n#define GL_INVALID_INDEX 0xFFFFFFFF\n#define GL_INVALID_OPERATION 0x0502\n#define GL_INVALID_VALUE 0x0501\n#define GL_INVERT 0x150A\n#define GL_ISOLINES 0x8E7A\n#define GL_KEEP 0x1E00\n#define GL_LAST_VERTEX_CONVENTION 0x8E4E\n#define GL_LAYER_PROVOKING_VERTEX 0x825E\n#define GL_LEFT 0x0406\n#define GL_LEQUAL 0x0203\n#define GL_LESS 0x0201\n#define GL_LINE 0x1B01\n#define GL_LINEAR 0x2601\n#define GL_LINEAR_MIPMAP_LINEAR 0x2703\n#define GL_LINEAR_MIPMAP_NEAREST 0x2701\n#define GL_LINES 0x0001\n#define GL_LINES_ADJACENCY 0x000A\n#define GL_LINE_LOOP 0x0002\n#define GL_LINE_SMOOTH 0x0B20\n#define GL_LINE_SMOOTH_HINT 0x0C52\n#define GL_LINE_STRIP 0x0003\n#define GL_LINE_STRIP_ADJACENCY 0x000B\n#define GL_LINE_WIDTH 0x0B21\n#define GL_LINE_WIDTH_GRANULARITY 0x0B23\n#define GL_LINE_WIDTH_RANGE 0x0B22\n#define GL_LINK_STATUS 0x8B82\n#define GL_LOGIC_OP_MODE 0x0BF0\n#define GL_LOWER_LEFT 0x8CA1\n#define GL_LOW_FLOAT 0x8DF0\n#define GL_LOW_INT 0x8DF3\n#define GL_MAJOR_VERSION 0x821B\n#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010\n#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008\n#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004\n#define GL_MAP_READ_BIT 0x0001\n#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020\n#define GL_MAP_WRITE_BIT 0x0002\n#define GL_MAX 0x8008\n#define GL_MAX_3D_TEXTURE_SIZE 0x8073\n#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF\n#define GL_MAX_CLIP_DISTANCES 0x0D32\n#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF\n#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E\n#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33\n#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32\n#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E\n#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F\n#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D\n#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E\n#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31\n#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C\n#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F\n#define GL_MAX_DRAW_BUFFERS 0x8824\n#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC\n#define GL_MAX_ELEMENTS_INDICES 0x80E9\n#define GL_MAX_ELEMENTS_VERTICES 0x80E8\n#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125\n#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C\n#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D\n#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49\n#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD\n#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123\n#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124\n#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0\n#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A\n#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29\n#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1\n#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C\n#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF\n#define GL_MAX_INTEGER_SAMPLES 0x9110\n#define GL_MAX_PATCH_VERTICES 0x8E7D\n#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905\n#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F\n#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8\n#define GL_MAX_RENDERBUFFER_SIZE 0x84E8\n#define GL_MAX_SAMPLES 0x8D57\n#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59\n#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111\n#define GL_MAX_SUBROUTINES 0x8DE7\n#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8\n#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C\n#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83\n#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81\n#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85\n#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89\n#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F\n#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D\n#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86\n#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82\n#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A\n#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80\n#define GL_MAX_TESS_GEN_LEVEL 0x8E7E\n#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84\n#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B\n#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872\n#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD\n#define GL_MAX_TEXTURE_SIZE 0x0D33\n#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70\n#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A\n#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B\n#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80\n#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30\n#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F\n#define GL_MAX_VARYING_COMPONENTS 0x8B4B\n#define GL_MAX_VARYING_FLOATS 0x8B4B\n#define GL_MAX_VARYING_VECTORS 0x8DFC\n#define GL_MAX_VERTEX_ATTRIBS 0x8869\n#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122\n#define GL_MAX_VERTEX_STREAMS 0x8E71\n#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C\n#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B\n#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A\n#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB\n#define GL_MAX_VIEWPORTS 0x825B\n#define GL_MAX_VIEWPORT_DIMS 0x0D3A\n#define GL_MEDIUM_FLOAT 0x8DF1\n#define GL_MEDIUM_INT 0x8DF4\n#define GL_MIN 0x8007\n#define GL_MINOR_VERSION 0x821C\n#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B\n#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904\n#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E\n#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37\n#define GL_MIRRORED_REPEAT 0x8370\n#define GL_MULTISAMPLE 0x809D\n#define GL_NAND 0x150E\n#define GL_NEAREST 0x2600\n#define GL_NEAREST_MIPMAP_LINEAR 0x2702\n#define GL_NEAREST_MIPMAP_NEAREST 0x2700\n#define GL_NEVER 0x0200\n#define GL_NICEST 0x1102\n#define GL_NONE 0\n#define GL_NOOP 0x1505\n#define GL_NOR 0x1508\n#define GL_NOTEQUAL 0x0205\n#define GL_NO_ERROR 0\n#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A\n#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2\n#define GL_NUM_EXTENSIONS 0x821D\n#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE\n#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9\n#define GL_OBJECT_TYPE 0x9112\n#define GL_ONE 1\n#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004\n#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002\n#define GL_ONE_MINUS_DST_ALPHA 0x0305\n#define GL_ONE_MINUS_DST_COLOR 0x0307\n#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB\n#define GL_ONE_MINUS_SRC1_COLOR 0x88FA\n#define GL_ONE_MINUS_SRC_ALPHA 0x0303\n#define GL_ONE_MINUS_SRC_COLOR 0x0301\n#define GL_OR 0x1507\n#define GL_OR_INVERTED 0x150D\n#define GL_OR_REVERSE 0x150B\n#define GL_OUT_OF_MEMORY 0x0505\n#define GL_PACK_ALIGNMENT 0x0D05\n#define GL_PACK_IMAGE_HEIGHT 0x806C\n#define GL_PACK_LSB_FIRST 0x0D01\n#define GL_PACK_ROW_LENGTH 0x0D02\n#define GL_PACK_SKIP_IMAGES 0x806B\n#define GL_PACK_SKIP_PIXELS 0x0D04\n#define GL_PACK_SKIP_ROWS 0x0D03\n#define GL_PACK_SWAP_BYTES 0x0D00\n#define GL_PATCHES 0x000E\n#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73\n#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74\n#define GL_PATCH_VERTICES 0x8E72\n#define GL_PIXEL_PACK_BUFFER 0x88EB\n#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED\n#define GL_PIXEL_UNPACK_BUFFER 0x88EC\n#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF\n#define GL_POINT 0x1B00\n#define GL_POINTS 0x0000\n#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128\n#define GL_POINT_SIZE 0x0B11\n#define GL_POINT_SIZE_GRANULARITY 0x0B13\n#define GL_POINT_SIZE_RANGE 0x0B12\n#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0\n#define GL_POLYGON_MODE 0x0B40\n#define GL_POLYGON_OFFSET_FACTOR 0x8038\n#define GL_POLYGON_OFFSET_FILL 0x8037\n#define GL_POLYGON_OFFSET_LINE 0x2A02\n#define GL_POLYGON_OFFSET_POINT 0x2A01\n#define GL_POLYGON_OFFSET_UNITS 0x2A00\n#define GL_POLYGON_SMOOTH 0x0B41\n#define GL_POLYGON_SMOOTH_HINT 0x0C53\n#define GL_PRIMITIVES_GENERATED 0x8C87\n#define GL_PRIMITIVE_RESTART 0x8F9D\n#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E\n#define GL_PROGRAM_BINARY_FORMATS 0x87FF\n#define GL_PROGRAM_BINARY_LENGTH 0x8741\n#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257\n#define GL_PROGRAM_PIPELINE_BINDING 0x825A\n#define GL_PROGRAM_POINT_SIZE 0x8642\n#define GL_PROGRAM_SEPARABLE 0x8258\n#define GL_PROVOKING_VERTEX 0x8E4F\n#define GL_PROXY_TEXTURE_1D 0x8063\n#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19\n#define GL_PROXY_TEXTURE_2D 0x8064\n#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B\n#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101\n#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103\n#define GL_PROXY_TEXTURE_3D 0x8070\n#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B\n#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B\n#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7\n#define GL_QUADS 0x0007\n#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C\n#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16\n#define GL_QUERY_BY_REGION_WAIT 0x8E15\n#define GL_QUERY_COUNTER_BITS 0x8864\n#define GL_QUERY_NO_WAIT 0x8E14\n#define GL_QUERY_RESULT 0x8866\n#define GL_QUERY_RESULT_AVAILABLE 0x8867\n#define GL_QUERY_WAIT 0x8E13\n#define GL_R11F_G11F_B10F 0x8C3A\n#define GL_R16 0x822A\n#define GL_R16F 0x822D\n#define GL_R16I 0x8233\n#define GL_R16UI 0x8234\n#define GL_R16_SNORM 0x8F98\n#define GL_R32F 0x822E\n#define GL_R32I 0x8235\n#define GL_R32UI 0x8236\n#define GL_R3_G3_B2 0x2A10\n#define GL_R8 0x8229\n#define GL_R8I 0x8231\n#define GL_R8UI 0x8232\n#define GL_R8_SNORM 0x8F94\n#define GL_RASTERIZER_DISCARD 0x8C89\n#define GL_READ_BUFFER 0x0C02\n#define GL_READ_FRAMEBUFFER 0x8CA8\n#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA\n#define GL_READ_ONLY 0x88B8\n#define GL_READ_WRITE 0x88BA\n#define GL_RED 0x1903\n#define GL_RED_INTEGER 0x8D94\n#define GL_RENDERBUFFER 0x8D41\n#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53\n#define GL_RENDERBUFFER_BINDING 0x8CA7\n#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52\n#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54\n#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51\n#define GL_RENDERBUFFER_HEIGHT 0x8D43\n#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44\n#define GL_RENDERBUFFER_RED_SIZE 0x8D50\n#define GL_RENDERBUFFER_SAMPLES 0x8CAB\n#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55\n#define GL_RENDERBUFFER_WIDTH 0x8D42\n#define GL_RENDERER 0x1F01\n#define GL_REPEAT 0x2901\n#define GL_REPLACE 0x1E01\n#define GL_RG 0x8227\n#define GL_RG16 0x822C\n#define GL_RG16F 0x822F\n#define GL_RG16I 0x8239\n#define GL_RG16UI 0x823A\n#define GL_RG16_SNORM 0x8F99\n#define GL_RG32F 0x8230\n#define GL_RG32I 0x823B\n#define GL_RG32UI 0x823C\n#define GL_RG8 0x822B\n#define GL_RG8I 0x8237\n#define GL_RG8UI 0x8238\n#define GL_RG8_SNORM 0x8F95\n#define GL_RGB 0x1907\n#define GL_RGB10 0x8052\n#define GL_RGB10_A2 0x8059\n#define GL_RGB10_A2UI 0x906F\n#define GL_RGB12 0x8053\n#define GL_RGB16 0x8054\n#define GL_RGB16F 0x881B\n#define GL_RGB16I 0x8D89\n#define GL_RGB16UI 0x8D77\n#define GL_RGB16_SNORM 0x8F9A\n#define GL_RGB32F 0x8815\n#define GL_RGB32I 0x8D83\n#define GL_RGB32UI 0x8D71\n#define GL_RGB4 0x804F\n#define GL_RGB5 0x8050\n#define GL_RGB565 0x8D62\n#define GL_RGB5_A1 0x8057\n#define GL_RGB8 0x8051\n#define GL_RGB8I 0x8D8F\n#define GL_RGB8UI 0x8D7D\n#define GL_RGB8_SNORM 0x8F96\n#define GL_RGB9_E5 0x8C3D\n#define GL_RGBA 0x1908\n#define GL_RGBA12 0x805A\n#define GL_RGBA16 0x805B\n#define GL_RGBA16F 0x881A\n#define GL_RGBA16I 0x8D88\n#define GL_RGBA16UI 0x8D76\n#define GL_RGBA16_SNORM 0x8F9B\n#define GL_RGBA2 0x8055\n#define GL_RGBA32F 0x8814\n#define GL_RGBA32I 0x8D82\n#define GL_RGBA32UI 0x8D70\n#define GL_RGBA4 0x8056\n#define GL_RGBA8 0x8058\n#define GL_RGBA8I 0x8D8E\n#define GL_RGBA8UI 0x8D7C\n#define GL_RGBA8_SNORM 0x8F97\n#define GL_RGBA_INTEGER 0x8D99\n#define GL_RGB_INTEGER 0x8D98\n#define GL_RG_INTEGER 0x8228\n#define GL_RIGHT 0x0407\n#define GL_SAMPLER_1D 0x8B5D\n#define GL_SAMPLER_1D_ARRAY 0x8DC0\n#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3\n#define GL_SAMPLER_1D_SHADOW 0x8B61\n#define GL_SAMPLER_2D 0x8B5E\n#define GL_SAMPLER_2D_ARRAY 0x8DC1\n#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4\n#define GL_SAMPLER_2D_MULTISAMPLE 0x9108\n#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B\n#define GL_SAMPLER_2D_RECT 0x8B63\n#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64\n#define GL_SAMPLER_2D_SHADOW 0x8B62\n#define GL_SAMPLER_3D 0x8B5F\n#define GL_SAMPLER_BINDING 0x8919\n#define GL_SAMPLER_BUFFER 0x8DC2\n#define GL_SAMPLER_CUBE 0x8B60\n#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C\n#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D\n#define GL_SAMPLER_CUBE_SHADOW 0x8DC5\n#define GL_SAMPLES 0x80A9\n#define GL_SAMPLES_PASSED 0x8914\n#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E\n#define GL_SAMPLE_ALPHA_TO_ONE 0x809F\n#define GL_SAMPLE_BUFFERS 0x80A8\n#define GL_SAMPLE_COVERAGE 0x80A0\n#define GL_SAMPLE_COVERAGE_INVERT 0x80AB\n#define GL_SAMPLE_COVERAGE_VALUE 0x80AA\n#define GL_SAMPLE_MASK 0x8E51\n#define GL_SAMPLE_MASK_VALUE 0x8E52\n#define GL_SAMPLE_POSITION 0x8E50\n#define GL_SAMPLE_SHADING 0x8C36\n#define GL_SCISSOR_BOX 0x0C10\n#define GL_SCISSOR_TEST 0x0C11\n#define GL_SEPARATE_ATTRIBS 0x8C8D\n#define GL_SET 0x150F\n#define GL_SHADER_BINARY_FORMATS 0x8DF8\n#define GL_SHADER_COMPILER 0x8DFA\n#define GL_SHADER_SOURCE_LENGTH 0x8B88\n#define GL_SHADER_TYPE 0x8B4F\n#define GL_SHADING_LANGUAGE_VERSION 0x8B8C\n#define GL_SHORT 0x1402\n#define GL_SIGNALED 0x9119\n#define GL_SIGNED_NORMALIZED 0x8F9C\n#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23\n#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22\n#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13\n#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12\n#define GL_SRC1_ALPHA 0x8589\n#define GL_SRC1_COLOR 0x88F9\n#define GL_SRC_ALPHA 0x0302\n#define GL_SRC_ALPHA_SATURATE 0x0308\n#define GL_SRC_COLOR 0x0300\n#define GL_SRGB 0x8C40\n#define GL_SRGB8 0x8C41\n#define GL_SRGB8_ALPHA8 0x8C43\n#define GL_SRGB_ALPHA 0x8C42\n#define GL_STATIC_COPY 0x88E6\n#define GL_STATIC_DRAW 0x88E4\n#define GL_STATIC_READ 0x88E5\n#define GL_STENCIL 0x1802\n#define GL_STENCIL_ATTACHMENT 0x8D20\n#define GL_STENCIL_BACK_FAIL 0x8801\n#define GL_STENCIL_BACK_FUNC 0x8800\n#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802\n#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803\n#define GL_STENCIL_BACK_REF 0x8CA3\n#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4\n#define GL_STENCIL_BACK_WRITEMASK 0x8CA5\n#define GL_STENCIL_BUFFER_BIT 0x00000400\n#define GL_STENCIL_CLEAR_VALUE 0x0B91\n#define GL_STENCIL_FAIL 0x0B94\n#define GL_STENCIL_FUNC 0x0B92\n#define GL_STENCIL_INDEX 0x1901\n#define GL_STENCIL_INDEX1 0x8D46\n#define GL_STENCIL_INDEX16 0x8D49\n#define GL_STENCIL_INDEX4 0x8D47\n#define GL_STENCIL_INDEX8 0x8D48\n#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95\n#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96\n#define GL_STENCIL_REF 0x0B97\n#define GL_STENCIL_TEST 0x0B90\n#define GL_STENCIL_VALUE_MASK 0x0B93\n#define GL_STENCIL_WRITEMASK 0x0B98\n#define GL_STEREO 0x0C33\n#define GL_STREAM_COPY 0x88E2\n#define GL_STREAM_DRAW 0x88E0\n#define GL_STREAM_READ 0x88E1\n#define GL_SUBPIXEL_BITS 0x0D50\n#define GL_SYNC_CONDITION 0x9113\n#define GL_SYNC_FENCE 0x9116\n#define GL_SYNC_FLAGS 0x9115\n#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001\n#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117\n#define GL_SYNC_STATUS 0x9114\n#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75\n#define GL_TESS_CONTROL_SHADER 0x8E88\n#define GL_TESS_CONTROL_SHADER_BIT 0x00000008\n#define GL_TESS_EVALUATION_SHADER 0x8E87\n#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010\n#define GL_TESS_GEN_MODE 0x8E76\n#define GL_TESS_GEN_POINT_MODE 0x8E79\n#define GL_TESS_GEN_SPACING 0x8E77\n#define GL_TESS_GEN_VERTEX_ORDER 0x8E78\n#define GL_TEXTURE 0x1702\n#define GL_TEXTURE0 0x84C0\n#define GL_TEXTURE1 0x84C1\n#define GL_TEXTURE10 0x84CA\n#define GL_TEXTURE11 0x84CB\n#define GL_TEXTURE12 0x84CC\n#define GL_TEXTURE13 0x84CD\n#define GL_TEXTURE14 0x84CE\n#define GL_TEXTURE15 0x84CF\n#define GL_TEXTURE16 0x84D0\n#define GL_TEXTURE17 0x84D1\n#define GL_TEXTURE18 0x84D2\n#define GL_TEXTURE19 0x84D3\n#define GL_TEXTURE2 0x84C2\n#define GL_TEXTURE20 0x84D4\n#define GL_TEXTURE21 0x84D5\n#define GL_TEXTURE22 0x84D6\n#define GL_TEXTURE23 0x84D7\n#define GL_TEXTURE24 0x84D8\n#define GL_TEXTURE25 0x84D9\n#define GL_TEXTURE26 0x84DA\n#define GL_TEXTURE27 0x84DB\n#define GL_TEXTURE28 0x84DC\n#define GL_TEXTURE29 0x84DD\n#define GL_TEXTURE3 0x84C3\n#define GL_TEXTURE30 0x84DE\n#define GL_TEXTURE31 0x84DF\n#define GL_TEXTURE4 0x84C4\n#define GL_TEXTURE5 0x84C5\n#define GL_TEXTURE6 0x84C6\n#define GL_TEXTURE7 0x84C7\n#define GL_TEXTURE8 0x84C8\n#define GL_TEXTURE9 0x84C9\n#define GL_TEXTURE_1D 0x0DE0\n#define GL_TEXTURE_1D_ARRAY 0x8C18\n#define GL_TEXTURE_2D 0x0DE1\n#define GL_TEXTURE_2D_ARRAY 0x8C1A\n#define GL_TEXTURE_2D_MULTISAMPLE 0x9100\n#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102\n#define GL_TEXTURE_3D 0x806F\n#define GL_TEXTURE_ALPHA_SIZE 0x805F\n#define GL_TEXTURE_ALPHA_TYPE 0x8C13\n#define GL_TEXTURE_BASE_LEVEL 0x813C\n#define GL_TEXTURE_BINDING_1D 0x8068\n#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C\n#define GL_TEXTURE_BINDING_2D 0x8069\n#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D\n#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104\n#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105\n#define GL_TEXTURE_BINDING_3D 0x806A\n#define GL_TEXTURE_BINDING_BUFFER 0x8C2C\n#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514\n#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A\n#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6\n#define GL_TEXTURE_BLUE_SIZE 0x805E\n#define GL_TEXTURE_BLUE_TYPE 0x8C12\n#define GL_TEXTURE_BORDER_COLOR 0x1004\n#define GL_TEXTURE_BUFFER 0x8C2A\n#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D\n#define GL_TEXTURE_COMPARE_FUNC 0x884D\n#define GL_TEXTURE_COMPARE_MODE 0x884C\n#define GL_TEXTURE_COMPRESSED 0x86A1\n#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0\n#define GL_TEXTURE_COMPRESSION_HINT 0x84EF\n#define GL_TEXTURE_CUBE_MAP 0x8513\n#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518\n#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517\n#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519\n#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F\n#define GL_TEXTURE_DEPTH 0x8071\n#define GL_TEXTURE_DEPTH_SIZE 0x884A\n#define GL_TEXTURE_DEPTH_TYPE 0x8C16\n#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107\n#define GL_TEXTURE_GREEN_SIZE 0x805D\n#define GL_TEXTURE_GREEN_TYPE 0x8C11\n#define GL_TEXTURE_HEIGHT 0x1001\n#define GL_TEXTURE_INTERNAL_FORMAT 0x1003\n#define GL_TEXTURE_LOD_BIAS 0x8501\n#define GL_TEXTURE_MAG_FILTER 0x2800\n#define GL_TEXTURE_MAX_LEVEL 0x813D\n#define GL_TEXTURE_MAX_LOD 0x813B\n#define GL_TEXTURE_MIN_FILTER 0x2801\n#define GL_TEXTURE_MIN_LOD 0x813A\n#define GL_TEXTURE_RECTANGLE 0x84F5\n#define GL_TEXTURE_RED_SIZE 0x805C\n#define GL_TEXTURE_RED_TYPE 0x8C10\n#define GL_TEXTURE_SAMPLES 0x9106\n#define GL_TEXTURE_SHARED_SIZE 0x8C3F\n#define GL_TEXTURE_STENCIL_SIZE 0x88F1\n#define GL_TEXTURE_SWIZZLE_A 0x8E45\n#define GL_TEXTURE_SWIZZLE_B 0x8E44\n#define GL_TEXTURE_SWIZZLE_G 0x8E43\n#define GL_TEXTURE_SWIZZLE_R 0x8E42\n#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46\n#define GL_TEXTURE_WIDTH 0x1000\n#define GL_TEXTURE_WRAP_R 0x8072\n#define GL_TEXTURE_WRAP_S 0x2802\n#define GL_TEXTURE_WRAP_T 0x2803\n#define GL_TIMEOUT_EXPIRED 0x911B\n#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF\n#define GL_TIMESTAMP 0x8E28\n#define GL_TIME_ELAPSED 0x88BF\n#define GL_TRANSFORM_FEEDBACK 0x8E22\n#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25\n#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E\n#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24\n#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F\n#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F\n#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23\n#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85\n#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84\n#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88\n#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83\n#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76\n#define GL_TRIANGLES 0x0004\n#define GL_TRIANGLES_ADJACENCY 0x000C\n#define GL_TRIANGLE_FAN 0x0006\n#define GL_TRIANGLE_STRIP 0x0005\n#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D\n#define GL_TRUE 1\n#define GL_UNDEFINED_VERTEX 0x8260\n#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C\n#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42\n#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43\n#define GL_UNIFORM_BLOCK_BINDING 0x8A3F\n#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40\n#define GL_UNIFORM_BLOCK_INDEX 0x8A3A\n#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1\n#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44\n#define GL_UNIFORM_BUFFER 0x8A11\n#define GL_UNIFORM_BUFFER_BINDING 0x8A28\n#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34\n#define GL_UNIFORM_BUFFER_SIZE 0x8A2A\n#define GL_UNIFORM_BUFFER_START 0x8A29\n#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E\n#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D\n#define GL_UNIFORM_NAME_LENGTH 0x8A39\n#define GL_UNIFORM_OFFSET 0x8A3B\n#define GL_UNIFORM_SIZE 0x8A38\n#define GL_UNIFORM_TYPE 0x8A37\n#define GL_UNPACK_ALIGNMENT 0x0CF5\n#define GL_UNPACK_IMAGE_HEIGHT 0x806E\n#define GL_UNPACK_LSB_FIRST 0x0CF1\n#define GL_UNPACK_ROW_LENGTH 0x0CF2\n#define GL_UNPACK_SKIP_IMAGES 0x806D\n#define GL_UNPACK_SKIP_PIXELS 0x0CF4\n#define GL_UNPACK_SKIP_ROWS 0x0CF3\n#define GL_UNPACK_SWAP_BYTES 0x0CF0\n#define GL_UNSIGNALED 0x9118\n#define GL_UNSIGNED_BYTE 0x1401\n#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362\n#define GL_UNSIGNED_BYTE_3_3_2 0x8032\n#define GL_UNSIGNED_INT 0x1405\n#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B\n#define GL_UNSIGNED_INT_10_10_10_2 0x8036\n#define GL_UNSIGNED_INT_24_8 0x84FA\n#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368\n#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E\n#define GL_UNSIGNED_INT_8_8_8_8 0x8035\n#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367\n#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1\n#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6\n#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2\n#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7\n#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A\n#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D\n#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5\n#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3\n#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8\n#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4\n#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F\n#define GL_UNSIGNED_INT_VEC2 0x8DC6\n#define GL_UNSIGNED_INT_VEC3 0x8DC7\n#define GL_UNSIGNED_INT_VEC4 0x8DC8\n#define GL_UNSIGNED_NORMALIZED 0x8C17\n#define GL_UNSIGNED_SHORT 0x1403\n#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366\n#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033\n#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365\n#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034\n#define GL_UNSIGNED_SHORT_5_6_5 0x8363\n#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364\n#define GL_UPPER_LEFT 0x8CA2\n#define GL_VALIDATE_STATUS 0x8B83\n#define GL_VENDOR 0x1F00\n#define GL_VERSION 0x1F02\n#define GL_VERTEX_ARRAY_BINDING 0x85B5\n#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F\n#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE\n#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622\n#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD\n#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A\n#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645\n#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623\n#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624\n#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625\n#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642\n#define GL_VERTEX_SHADER 0x8B31\n#define GL_VERTEX_SHADER_BIT 0x00000001\n#define GL_VIEWPORT 0x0BA2\n#define GL_VIEWPORT_BOUNDS_RANGE 0x825D\n#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F\n#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C\n#define GL_WAIT_FAILED 0x911D\n#define GL_WRITE_ONLY 0x88B9\n#define GL_XOR 0x1506\n#define GL_ZERO 0\n\n\n#include <KHR/khrplatform.h>\ntypedef unsigned int GLenum;\ntypedef unsigned char GLboolean;\ntypedef unsigned int GLbitfield;\ntypedef void GLvoid;\ntypedef khronos_int8_t GLbyte;\ntypedef khronos_uint8_t GLubyte;\ntypedef khronos_int16_t GLshort;\ntypedef khronos_uint16_t GLushort;\ntypedef int GLint;\ntypedef unsigned int GLuint;\ntypedef khronos_int32_t GLclampx;\ntypedef int GLsizei;\ntypedef khronos_float_t GLfloat;\ntypedef khronos_float_t GLclampf;\ntypedef double GLdouble;\ntypedef double GLclampd;\ntypedef void *GLeglClientBufferEXT;\ntypedef void *GLeglImageOES;\ntypedef char GLchar;\ntypedef char GLcharARB;\n#ifdef __APPLE__\ntypedef void *GLhandleARB;\n#else\ntypedef unsigned int GLhandleARB;\n#endif\ntypedef khronos_uint16_t GLhalf;\ntypedef khronos_uint16_t GLhalfARB;\ntypedef khronos_int32_t GLfixed;\n#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)\ntypedef khronos_intptr_t GLintptr;\n#else\ntypedef khronos_intptr_t GLintptr;\n#endif\n#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)\ntypedef khronos_intptr_t GLintptrARB;\n#else\ntypedef khronos_intptr_t GLintptrARB;\n#endif\n#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)\ntypedef khronos_ssize_t GLsizeiptr;\n#else\ntypedef khronos_ssize_t GLsizeiptr;\n#endif\n#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)\ntypedef khronos_ssize_t GLsizeiptrARB;\n#else\ntypedef khronos_ssize_t GLsizeiptrARB;\n#endif\ntypedef khronos_int64_t GLint64;\ntypedef khronos_int64_t GLint64EXT;\ntypedef khronos_uint64_t GLuint64;\ntypedef khronos_uint64_t GLuint64EXT;\ntypedef struct __GLsync *GLsync;\nstruct _cl_context;\nstruct _cl_event;\ntypedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);\ntypedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);\ntypedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);\ntypedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);\ntypedef unsigned short GLhalfNV;\ntypedef GLintptr GLvdpauSurfaceNV;\ntypedef void (GLAD_API_PTR *GLVULKANPROCNV)(void);\n\n\n#define GL_VERSION_1_0 1\nGLAD_API_CALL int GLAD_GL_VERSION_1_0;\n#define GL_VERSION_1_1 1\nGLAD_API_CALL int GLAD_GL_VERSION_1_1;\n#define GL_VERSION_1_2 1\nGLAD_API_CALL int GLAD_GL_VERSION_1_2;\n#define GL_VERSION_1_3 1\nGLAD_API_CALL int GLAD_GL_VERSION_1_3;\n#define GL_VERSION_1_4 1\nGLAD_API_CALL int GLAD_GL_VERSION_1_4;\n#define GL_VERSION_1_5 1\nGLAD_API_CALL int GLAD_GL_VERSION_1_5;\n#define GL_VERSION_2_0 1\nGLAD_API_CALL int GLAD_GL_VERSION_2_0;\n#define GL_VERSION_2_1 1\nGLAD_API_CALL int GLAD_GL_VERSION_2_1;\n#define GL_VERSION_3_0 1\nGLAD_API_CALL int GLAD_GL_VERSION_3_0;\n#define GL_VERSION_3_1 1\nGLAD_API_CALL int GLAD_GL_VERSION_3_1;\n#define GL_VERSION_3_2 1\nGLAD_API_CALL int GLAD_GL_VERSION_3_2;\n#define GL_VERSION_3_3 1\nGLAD_API_CALL int GLAD_GL_VERSION_3_3;\n#define GL_VERSION_4_0 1\nGLAD_API_CALL int GLAD_GL_VERSION_4_0;\n#define GL_VERSION_4_1 1\nGLAD_API_CALL int GLAD_GL_VERSION_4_1;\n\n\ntypedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program);\ntypedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture);\ntypedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);\ntypedef void (GLAD_API_PTR *PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode);\ntypedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum target, GLuint id);\ntypedef void (GLAD_API_PTR *PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id);\ntypedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode);\ntypedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);\ntypedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer);\ntypedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);\ntypedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer);\ntypedef void (GLAD_API_PTR *PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline);\ntypedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer);\ntypedef void (GLAD_API_PTR *PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler);\ntypedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture);\ntypedef void (GLAD_API_PTR *PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id);\ntypedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYPROC)(GLuint array);\ntypedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\ntypedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode);\ntypedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha);\ntypedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha);\ntypedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode);\ntypedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor);\ntypedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);\ntypedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);\ntypedef void (GLAD_API_PTR *PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst);\ntypedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);\ntypedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage);\ntypedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data);\ntypedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target);\ntypedef void (GLAD_API_PTR *PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp);\ntypedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask);\ntypedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);\ntypedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);\ntypedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble depth);\ntypedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d);\ntypedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s);\ntypedef GLenum (GLAD_API_PTR *PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);\ntypedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);\ntypedef void (GLAD_API_PTR *PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);\ntypedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader);\ntypedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data);\ntypedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data);\ntypedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data);\ntypedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data);\ntypedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data);\ntypedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data);\ntypedef void (GLAD_API_PTR *PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);\ntypedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border);\ntypedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);\ntypedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width);\ntypedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void);\ntypedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type);\ntypedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const* strings);\ntypedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode);\ntypedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers);\ntypedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers);\ntypedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program);\ntypedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint * pipelines);\ntypedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint * ids);\ntypedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers);\ntypedef void (GLAD_API_PTR *PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint * samplers);\ntypedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader);\ntypedef void (GLAD_API_PTR *PFNGLDELETESYNCPROC)(GLsync sync);\ntypedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures);\ntypedef void (GLAD_API_PTR *PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint * ids);\ntypedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint * arrays);\ntypedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func);\ntypedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag);\ntypedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f);\ntypedef void (GLAD_API_PTR *PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f);\ntypedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f);\ntypedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader);\ntypedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap);\ntypedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index);\ntypedef void (GLAD_API_PTR *PFNGLDISABLEIPROC)(GLenum target, GLuint index);\ntypedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count);\ntypedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void * indirect);\ntypedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);\ntypedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum buf);\ntypedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum * bufs);\ntypedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices);\ntypedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex);\ntypedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void * indirect);\ntypedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount);\ntypedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex);\ntypedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices);\ntypedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex);\ntypedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id);\ntypedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream);\ntypedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap);\ntypedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);\ntypedef void (GLAD_API_PTR *PFNGLENABLEIPROC)(GLenum target, GLuint index);\ntypedef void (GLAD_API_PTR *PFNGLENDCONDITIONALRENDERPROC)(void);\ntypedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum target);\ntypedef void (GLAD_API_PTR *PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index);\ntypedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKPROC)(void);\ntypedef GLsync (GLAD_API_PTR *PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags);\ntypedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void);\ntypedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void);\ntypedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length);\ntypedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);\ntypedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level);\ntypedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);\ntypedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);\ntypedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);\ntypedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode);\ntypedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers);\ntypedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers);\ntypedef void (GLAD_API_PTR *PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint * pipelines);\ntypedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei n, GLuint * ids);\ntypedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers);\ntypedef void (GLAD_API_PTR *PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint * samplers);\ntypedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures);\ntypedef void (GLAD_API_PTR *PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint * ids);\ntypedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint * arrays);\ntypedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei * length, GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei * length, GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint * values);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformBlockName);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei * length, GLchar * uniformName);\ntypedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint * uniformIndices, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders);\ntypedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean * data);\ntypedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data);\ntypedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 * params);\ntypedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void ** params);\ntypedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void * data);\ntypedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void * img);\ntypedef void (GLAD_API_PTR *PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble * data);\ntypedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble * data);\ntypedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void);\ntypedef void (GLAD_API_PTR *PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat * data);\ntypedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data);\ntypedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar * name);\ntypedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 * data);\ntypedef void (GLAD_API_PTR *PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 * data);\ntypedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint * data);\ntypedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data);\ntypedef void (GLAD_API_PTR *PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat * val);\ntypedef void (GLAD_API_PTR *PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLenum * binaryFormat, void * binary);\ntypedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog);\ntypedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei * length, GLchar * infoLog);\ntypedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint * values);\ntypedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 * params);\ntypedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 * params);\ntypedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat * params);\ntypedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog);\ntypedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision);\ntypedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source);\ntypedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params);\ntypedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name);\ntypedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGIPROC)(GLenum name, GLuint index);\ntypedef GLuint (GLAD_API_PTR *PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar * name);\ntypedef GLint (GLAD_API_PTR *PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei * length, GLint * values);\ntypedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void * pixels);\ntypedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat * params);\ntypedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params);\ntypedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name);\ntypedef GLuint (GLAD_API_PTR *PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar * uniformBlockName);\ntypedef void (GLAD_API_PTR *PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const* uniformNames, GLuint * uniformIndices);\ntypedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name);\ntypedef void (GLAD_API_PTR *PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble * params);\ntypedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params);\ntypedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint * params);\ntypedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble * params);\ntypedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer);\ntypedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble * params);\ntypedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params);\ntypedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIPROC)(GLenum target, GLuint index);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint id);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISSAMPLERPROC)(GLuint sampler);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISSYNCPROC)(GLsync sync);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id);\ntypedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYPROC)(GLuint array);\ntypedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width);\ntypedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program);\ntypedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum opcode);\ntypedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum target, GLenum access);\ntypedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);\ntypedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGPROC)(GLfloat value);\ntypedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei drawcount);\ntypedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount);\ntypedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount, const GLint * basevertex);\ntypedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat * values);\ntypedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value);\ntypedef void (GLAD_API_PTR *PFNGLPAUSETRANSFORMFEEDBACKPROC)(void);\ntypedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param);\ntypedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param);\ntypedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param);\ntypedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat * params);\ntypedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param);\ntypedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat size);\ntypedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode);\ntypedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units);\ntypedef void (GLAD_API_PTR *PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void * binary, GLsizei length);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLPROVOKINGVERTEXPROC)(GLenum mode);\ntypedef void (GLAD_API_PTR *PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target);\ntypedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum src);\ntypedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels);\ntypedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void);\ntypedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);\ntypedef void (GLAD_API_PTR *PFNGLRESUMETRANSFORMFEEDBACKPROC)(void);\ntypedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert);\ntypedef void (GLAD_API_PTR *PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask);\ntypedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint * param);\ntypedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint * param);\ntypedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param);\ntypedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat * param);\ntypedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param);\ntypedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint * param);\ntypedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (GLAD_API_PTR *PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint * v);\ntypedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height);\ntypedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint * v);\ntypedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length);\ntypedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length);\ntypedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask);\ntypedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask);\ntypedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask);\ntypedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask);\ntypedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass);\ntypedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);\ntypedef void (GLAD_API_PTR *PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer);\ntypedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void * pixels);\ntypedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels);\ntypedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);\ntypedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels);\ntypedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);\ntypedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint * params);\ntypedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param);\ntypedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params);\ntypedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);\ntypedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params);\ntypedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels);\ntypedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);\ntypedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels);\ntypedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM1DPROC)(GLint location, GLdouble x);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);\ntypedef void (GLAD_API_PTR *PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint * indices);\ntypedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum target);\ntypedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program);\ntypedef void (GLAD_API_PTR *PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program);\ntypedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program);\ntypedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble * v);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint * value);\ntypedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer);\ntypedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height);\ntypedef void (GLAD_API_PTR *PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat * v);\ntypedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h);\ntypedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat * v);\ntypedef void (GLAD_API_PTR *PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout);\n\nGLAD_API_CALL PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram;\n#define glActiveShaderProgram glad_glActiveShaderProgram\nGLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture;\n#define glActiveTexture glad_glActiveTexture\nGLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader;\n#define glAttachShader glad_glAttachShader\nGLAD_API_CALL PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;\n#define glBeginConditionalRender glad_glBeginConditionalRender\nGLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery;\n#define glBeginQuery glad_glBeginQuery\nGLAD_API_CALL PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed;\n#define glBeginQueryIndexed glad_glBeginQueryIndexed\nGLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;\n#define glBeginTransformFeedback glad_glBeginTransformFeedback\nGLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;\n#define glBindAttribLocation glad_glBindAttribLocation\nGLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer;\n#define glBindBuffer glad_glBindBuffer\nGLAD_API_CALL PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;\n#define glBindBufferBase glad_glBindBufferBase\nGLAD_API_CALL PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;\n#define glBindBufferRange glad_glBindBufferRange\nGLAD_API_CALL PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;\n#define glBindFragDataLocation glad_glBindFragDataLocation\nGLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;\n#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed\nGLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;\n#define glBindFramebuffer glad_glBindFramebuffer\nGLAD_API_CALL PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline;\n#define glBindProgramPipeline glad_glBindProgramPipeline\nGLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;\n#define glBindRenderbuffer glad_glBindRenderbuffer\nGLAD_API_CALL PFNGLBINDSAMPLERPROC glad_glBindSampler;\n#define glBindSampler glad_glBindSampler\nGLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture;\n#define glBindTexture glad_glBindTexture\nGLAD_API_CALL PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback;\n#define glBindTransformFeedback glad_glBindTransformFeedback\nGLAD_API_CALL PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;\n#define glBindVertexArray glad_glBindVertexArray\nGLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor;\n#define glBlendColor glad_glBlendColor\nGLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation;\n#define glBlendEquation glad_glBlendEquation\nGLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;\n#define glBlendEquationSeparate glad_glBlendEquationSeparate\nGLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei;\n#define glBlendEquationSeparatei glad_glBlendEquationSeparatei\nGLAD_API_CALL PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi;\n#define glBlendEquationi glad_glBlendEquationi\nGLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc;\n#define glBlendFunc glad_glBlendFunc\nGLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;\n#define glBlendFuncSeparate glad_glBlendFuncSeparate\nGLAD_API_CALL PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei;\n#define glBlendFuncSeparatei glad_glBlendFuncSeparatei\nGLAD_API_CALL PFNGLBLENDFUNCIPROC glad_glBlendFunci;\n#define glBlendFunci glad_glBlendFunci\nGLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;\n#define glBlitFramebuffer glad_glBlitFramebuffer\nGLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData;\n#define glBufferData glad_glBufferData\nGLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;\n#define glBufferSubData glad_glBufferSubData\nGLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;\n#define glCheckFramebufferStatus glad_glCheckFramebufferStatus\nGLAD_API_CALL PFNGLCLAMPCOLORPROC glad_glClampColor;\n#define glClampColor glad_glClampColor\nGLAD_API_CALL PFNGLCLEARPROC glad_glClear;\n#define glClear glad_glClear\nGLAD_API_CALL PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;\n#define glClearBufferfi glad_glClearBufferfi\nGLAD_API_CALL PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;\n#define glClearBufferfv glad_glClearBufferfv\nGLAD_API_CALL PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;\n#define glClearBufferiv glad_glClearBufferiv\nGLAD_API_CALL PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;\n#define glClearBufferuiv glad_glClearBufferuiv\nGLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor;\n#define glClearColor glad_glClearColor\nGLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth;\n#define glClearDepth glad_glClearDepth\nGLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf;\n#define glClearDepthf glad_glClearDepthf\nGLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil;\n#define glClearStencil glad_glClearStencil\nGLAD_API_CALL PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;\n#define glClientWaitSync glad_glClientWaitSync\nGLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask;\n#define glColorMask glad_glColorMask\nGLAD_API_CALL PFNGLCOLORMASKIPROC glad_glColorMaski;\n#define glColorMaski glad_glColorMaski\nGLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader;\n#define glCompileShader glad_glCompileShader\nGLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;\n#define glCompressedTexImage1D glad_glCompressedTexImage1D\nGLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;\n#define glCompressedTexImage2D glad_glCompressedTexImage2D\nGLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;\n#define glCompressedTexImage3D glad_glCompressedTexImage3D\nGLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;\n#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D\nGLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;\n#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D\nGLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;\n#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D\nGLAD_API_CALL PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;\n#define glCopyBufferSubData glad_glCopyBufferSubData\nGLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;\n#define glCopyTexImage1D glad_glCopyTexImage1D\nGLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;\n#define glCopyTexImage2D glad_glCopyTexImage2D\nGLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;\n#define glCopyTexSubImage1D glad_glCopyTexSubImage1D\nGLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;\n#define glCopyTexSubImage2D glad_glCopyTexSubImage2D\nGLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;\n#define glCopyTexSubImage3D glad_glCopyTexSubImage3D\nGLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram;\n#define glCreateProgram glad_glCreateProgram\nGLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader;\n#define glCreateShader glad_glCreateShader\nGLAD_API_CALL PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv;\n#define glCreateShaderProgramv glad_glCreateShaderProgramv\nGLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace;\n#define glCullFace glad_glCullFace\nGLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;\n#define glDeleteBuffers glad_glDeleteBuffers\nGLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;\n#define glDeleteFramebuffers glad_glDeleteFramebuffers\nGLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;\n#define glDeleteProgram glad_glDeleteProgram\nGLAD_API_CALL PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines;\n#define glDeleteProgramPipelines glad_glDeleteProgramPipelines\nGLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries;\n#define glDeleteQueries glad_glDeleteQueries\nGLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;\n#define glDeleteRenderbuffers glad_glDeleteRenderbuffers\nGLAD_API_CALL PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;\n#define glDeleteSamplers glad_glDeleteSamplers\nGLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader;\n#define glDeleteShader glad_glDeleteShader\nGLAD_API_CALL PFNGLDELETESYNCPROC glad_glDeleteSync;\n#define glDeleteSync glad_glDeleteSync\nGLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures;\n#define glDeleteTextures glad_glDeleteTextures\nGLAD_API_CALL PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks;\n#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks\nGLAD_API_CALL PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;\n#define glDeleteVertexArrays glad_glDeleteVertexArrays\nGLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc;\n#define glDepthFunc glad_glDepthFunc\nGLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask;\n#define glDepthMask glad_glDepthMask\nGLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange;\n#define glDepthRange glad_glDepthRange\nGLAD_API_CALL PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv;\n#define glDepthRangeArrayv glad_glDepthRangeArrayv\nGLAD_API_CALL PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed;\n#define glDepthRangeIndexed glad_glDepthRangeIndexed\nGLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef;\n#define glDepthRangef glad_glDepthRangef\nGLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader;\n#define glDetachShader glad_glDetachShader\nGLAD_API_CALL PFNGLDISABLEPROC glad_glDisable;\n#define glDisable glad_glDisable\nGLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;\n#define glDisableVertexAttribArray glad_glDisableVertexAttribArray\nGLAD_API_CALL PFNGLDISABLEIPROC glad_glDisablei;\n#define glDisablei glad_glDisablei\nGLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays;\n#define glDrawArrays glad_glDrawArrays\nGLAD_API_CALL PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect;\n#define glDrawArraysIndirect glad_glDrawArraysIndirect\nGLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;\n#define glDrawArraysInstanced glad_glDrawArraysInstanced\nGLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer;\n#define glDrawBuffer glad_glDrawBuffer\nGLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;\n#define glDrawBuffers glad_glDrawBuffers\nGLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements;\n#define glDrawElements glad_glDrawElements\nGLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;\n#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex\nGLAD_API_CALL PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect;\n#define glDrawElementsIndirect glad_glDrawElementsIndirect\nGLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;\n#define glDrawElementsInstanced glad_glDrawElementsInstanced\nGLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;\n#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex\nGLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;\n#define glDrawRangeElements glad_glDrawRangeElements\nGLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;\n#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex\nGLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback;\n#define glDrawTransformFeedback glad_glDrawTransformFeedback\nGLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream;\n#define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream\nGLAD_API_CALL PFNGLENABLEPROC glad_glEnable;\n#define glEnable glad_glEnable\nGLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;\n#define glEnableVertexAttribArray glad_glEnableVertexAttribArray\nGLAD_API_CALL PFNGLENABLEIPROC glad_glEnablei;\n#define glEnablei glad_glEnablei\nGLAD_API_CALL PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;\n#define glEndConditionalRender glad_glEndConditionalRender\nGLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery;\n#define glEndQuery glad_glEndQuery\nGLAD_API_CALL PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed;\n#define glEndQueryIndexed glad_glEndQueryIndexed\nGLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;\n#define glEndTransformFeedback glad_glEndTransformFeedback\nGLAD_API_CALL PFNGLFENCESYNCPROC glad_glFenceSync;\n#define glFenceSync glad_glFenceSync\nGLAD_API_CALL PFNGLFINISHPROC glad_glFinish;\n#define glFinish glad_glFinish\nGLAD_API_CALL PFNGLFLUSHPROC glad_glFlush;\n#define glFlush glad_glFlush\nGLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;\n#define glFlushMappedBufferRange glad_glFlushMappedBufferRange\nGLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;\n#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer\nGLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;\n#define glFramebufferTexture glad_glFramebufferTexture\nGLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;\n#define glFramebufferTexture1D glad_glFramebufferTexture1D\nGLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;\n#define glFramebufferTexture2D glad_glFramebufferTexture2D\nGLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;\n#define glFramebufferTexture3D glad_glFramebufferTexture3D\nGLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;\n#define glFramebufferTextureLayer glad_glFramebufferTextureLayer\nGLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace;\n#define glFrontFace glad_glFrontFace\nGLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers;\n#define glGenBuffers glad_glGenBuffers\nGLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;\n#define glGenFramebuffers glad_glGenFramebuffers\nGLAD_API_CALL PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines;\n#define glGenProgramPipelines glad_glGenProgramPipelines\nGLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries;\n#define glGenQueries glad_glGenQueries\nGLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;\n#define glGenRenderbuffers glad_glGenRenderbuffers\nGLAD_API_CALL PFNGLGENSAMPLERSPROC glad_glGenSamplers;\n#define glGenSamplers glad_glGenSamplers\nGLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures;\n#define glGenTextures glad_glGenTextures\nGLAD_API_CALL PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks;\n#define glGenTransformFeedbacks glad_glGenTransformFeedbacks\nGLAD_API_CALL PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;\n#define glGenVertexArrays glad_glGenVertexArrays\nGLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;\n#define glGenerateMipmap glad_glGenerateMipmap\nGLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;\n#define glGetActiveAttrib glad_glGetActiveAttrib\nGLAD_API_CALL PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName;\n#define glGetActiveSubroutineName glad_glGetActiveSubroutineName\nGLAD_API_CALL PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName;\n#define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName\nGLAD_API_CALL PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv;\n#define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv\nGLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;\n#define glGetActiveUniform glad_glGetActiveUniform\nGLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;\n#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName\nGLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;\n#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv\nGLAD_API_CALL PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;\n#define glGetActiveUniformName glad_glGetActiveUniformName\nGLAD_API_CALL PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;\n#define glGetActiveUniformsiv glad_glGetActiveUniformsiv\nGLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;\n#define glGetAttachedShaders glad_glGetAttachedShaders\nGLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;\n#define glGetAttribLocation glad_glGetAttribLocation\nGLAD_API_CALL PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;\n#define glGetBooleani_v glad_glGetBooleani_v\nGLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv;\n#define glGetBooleanv glad_glGetBooleanv\nGLAD_API_CALL PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;\n#define glGetBufferParameteri64v glad_glGetBufferParameteri64v\nGLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;\n#define glGetBufferParameteriv glad_glGetBufferParameteriv\nGLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;\n#define glGetBufferPointerv glad_glGetBufferPointerv\nGLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;\n#define glGetBufferSubData glad_glGetBufferSubData\nGLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;\n#define glGetCompressedTexImage glad_glGetCompressedTexImage\nGLAD_API_CALL PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v;\n#define glGetDoublei_v glad_glGetDoublei_v\nGLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev;\n#define glGetDoublev glad_glGetDoublev\nGLAD_API_CALL PFNGLGETERRORPROC glad_glGetError;\n#define glGetError glad_glGetError\nGLAD_API_CALL PFNGLGETFLOATI_VPROC glad_glGetFloati_v;\n#define glGetFloati_v glad_glGetFloati_v\nGLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv;\n#define glGetFloatv glad_glGetFloatv\nGLAD_API_CALL PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;\n#define glGetFragDataIndex glad_glGetFragDataIndex\nGLAD_API_CALL PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;\n#define glGetFragDataLocation glad_glGetFragDataLocation\nGLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;\n#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv\nGLAD_API_CALL PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;\n#define glGetInteger64i_v glad_glGetInteger64i_v\nGLAD_API_CALL PFNGLGETINTEGER64VPROC glad_glGetInteger64v;\n#define glGetInteger64v glad_glGetInteger64v\nGLAD_API_CALL PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;\n#define glGetIntegeri_v glad_glGetIntegeri_v\nGLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv;\n#define glGetIntegerv glad_glGetIntegerv\nGLAD_API_CALL PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;\n#define glGetMultisamplefv glad_glGetMultisamplefv\nGLAD_API_CALL PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary;\n#define glGetProgramBinary glad_glGetProgramBinary\nGLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;\n#define glGetProgramInfoLog glad_glGetProgramInfoLog\nGLAD_API_CALL PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog;\n#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog\nGLAD_API_CALL PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv;\n#define glGetProgramPipelineiv glad_glGetProgramPipelineiv\nGLAD_API_CALL PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv;\n#define glGetProgramStageiv glad_glGetProgramStageiv\nGLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;\n#define glGetProgramiv glad_glGetProgramiv\nGLAD_API_CALL PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv;\n#define glGetQueryIndexediv glad_glGetQueryIndexediv\nGLAD_API_CALL PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;\n#define glGetQueryObjecti64v glad_glGetQueryObjecti64v\nGLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;\n#define glGetQueryObjectiv glad_glGetQueryObjectiv\nGLAD_API_CALL PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;\n#define glGetQueryObjectui64v glad_glGetQueryObjectui64v\nGLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;\n#define glGetQueryObjectuiv glad_glGetQueryObjectuiv\nGLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv;\n#define glGetQueryiv glad_glGetQueryiv\nGLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;\n#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv\nGLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;\n#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv\nGLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;\n#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv\nGLAD_API_CALL PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;\n#define glGetSamplerParameterfv glad_glGetSamplerParameterfv\nGLAD_API_CALL PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;\n#define glGetSamplerParameteriv glad_glGetSamplerParameteriv\nGLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;\n#define glGetShaderInfoLog glad_glGetShaderInfoLog\nGLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;\n#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat\nGLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;\n#define glGetShaderSource glad_glGetShaderSource\nGLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv;\n#define glGetShaderiv glad_glGetShaderiv\nGLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString;\n#define glGetString glad_glGetString\nGLAD_API_CALL PFNGLGETSTRINGIPROC glad_glGetStringi;\n#define glGetStringi glad_glGetStringi\nGLAD_API_CALL PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex;\n#define glGetSubroutineIndex glad_glGetSubroutineIndex\nGLAD_API_CALL PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation;\n#define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation\nGLAD_API_CALL PFNGLGETSYNCIVPROC glad_glGetSynciv;\n#define glGetSynciv glad_glGetSynciv\nGLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage;\n#define glGetTexImage glad_glGetTexImage\nGLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;\n#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv\nGLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;\n#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv\nGLAD_API_CALL PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;\n#define glGetTexParameterIiv glad_glGetTexParameterIiv\nGLAD_API_CALL PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;\n#define glGetTexParameterIuiv glad_glGetTexParameterIuiv\nGLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;\n#define glGetTexParameterfv glad_glGetTexParameterfv\nGLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;\n#define glGetTexParameteriv glad_glGetTexParameteriv\nGLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;\n#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying\nGLAD_API_CALL PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;\n#define glGetUniformBlockIndex glad_glGetUniformBlockIndex\nGLAD_API_CALL PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;\n#define glGetUniformIndices glad_glGetUniformIndices\nGLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;\n#define glGetUniformLocation glad_glGetUniformLocation\nGLAD_API_CALL PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv;\n#define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv\nGLAD_API_CALL PFNGLGETUNIFORMDVPROC glad_glGetUniformdv;\n#define glGetUniformdv glad_glGetUniformdv\nGLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;\n#define glGetUniformfv glad_glGetUniformfv\nGLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;\n#define glGetUniformiv glad_glGetUniformiv\nGLAD_API_CALL PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;\n#define glGetUniformuiv glad_glGetUniformuiv\nGLAD_API_CALL PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;\n#define glGetVertexAttribIiv glad_glGetVertexAttribIiv\nGLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;\n#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv\nGLAD_API_CALL PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv;\n#define glGetVertexAttribLdv glad_glGetVertexAttribLdv\nGLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;\n#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv\nGLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;\n#define glGetVertexAttribdv glad_glGetVertexAttribdv\nGLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;\n#define glGetVertexAttribfv glad_glGetVertexAttribfv\nGLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;\n#define glGetVertexAttribiv glad_glGetVertexAttribiv\nGLAD_API_CALL PFNGLHINTPROC glad_glHint;\n#define glHint glad_glHint\nGLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer;\n#define glIsBuffer glad_glIsBuffer\nGLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled;\n#define glIsEnabled glad_glIsEnabled\nGLAD_API_CALL PFNGLISENABLEDIPROC glad_glIsEnabledi;\n#define glIsEnabledi glad_glIsEnabledi\nGLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;\n#define glIsFramebuffer glad_glIsFramebuffer\nGLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram;\n#define glIsProgram glad_glIsProgram\nGLAD_API_CALL PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline;\n#define glIsProgramPipeline glad_glIsProgramPipeline\nGLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery;\n#define glIsQuery glad_glIsQuery\nGLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;\n#define glIsRenderbuffer glad_glIsRenderbuffer\nGLAD_API_CALL PFNGLISSAMPLERPROC glad_glIsSampler;\n#define glIsSampler glad_glIsSampler\nGLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader;\n#define glIsShader glad_glIsShader\nGLAD_API_CALL PFNGLISSYNCPROC glad_glIsSync;\n#define glIsSync glad_glIsSync\nGLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture;\n#define glIsTexture glad_glIsTexture\nGLAD_API_CALL PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback;\n#define glIsTransformFeedback glad_glIsTransformFeedback\nGLAD_API_CALL PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;\n#define glIsVertexArray glad_glIsVertexArray\nGLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth;\n#define glLineWidth glad_glLineWidth\nGLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram;\n#define glLinkProgram glad_glLinkProgram\nGLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp;\n#define glLogicOp glad_glLogicOp\nGLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer;\n#define glMapBuffer glad_glMapBuffer\nGLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;\n#define glMapBufferRange glad_glMapBufferRange\nGLAD_API_CALL PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading;\n#define glMinSampleShading glad_glMinSampleShading\nGLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;\n#define glMultiDrawArrays glad_glMultiDrawArrays\nGLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;\n#define glMultiDrawElements glad_glMultiDrawElements\nGLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;\n#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex\nGLAD_API_CALL PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv;\n#define glPatchParameterfv glad_glPatchParameterfv\nGLAD_API_CALL PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri;\n#define glPatchParameteri glad_glPatchParameteri\nGLAD_API_CALL PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback;\n#define glPauseTransformFeedback glad_glPauseTransformFeedback\nGLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref;\n#define glPixelStoref glad_glPixelStoref\nGLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei;\n#define glPixelStorei glad_glPixelStorei\nGLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;\n#define glPointParameterf glad_glPointParameterf\nGLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;\n#define glPointParameterfv glad_glPointParameterfv\nGLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;\n#define glPointParameteri glad_glPointParameteri\nGLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;\n#define glPointParameteriv glad_glPointParameteriv\nGLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize;\n#define glPointSize glad_glPointSize\nGLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode;\n#define glPolygonMode glad_glPolygonMode\nGLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;\n#define glPolygonOffset glad_glPolygonOffset\nGLAD_API_CALL PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;\n#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex\nGLAD_API_CALL PFNGLPROGRAMBINARYPROC glad_glProgramBinary;\n#define glProgramBinary glad_glProgramBinary\nGLAD_API_CALL PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri;\n#define glProgramParameteri glad_glProgramParameteri\nGLAD_API_CALL PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d;\n#define glProgramUniform1d glad_glProgramUniform1d\nGLAD_API_CALL PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv;\n#define glProgramUniform1dv glad_glProgramUniform1dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f;\n#define glProgramUniform1f glad_glProgramUniform1f\nGLAD_API_CALL PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv;\n#define glProgramUniform1fv glad_glProgramUniform1fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i;\n#define glProgramUniform1i glad_glProgramUniform1i\nGLAD_API_CALL PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv;\n#define glProgramUniform1iv glad_glProgramUniform1iv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui;\n#define glProgramUniform1ui glad_glProgramUniform1ui\nGLAD_API_CALL PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv;\n#define glProgramUniform1uiv glad_glProgramUniform1uiv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d;\n#define glProgramUniform2d glad_glProgramUniform2d\nGLAD_API_CALL PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv;\n#define glProgramUniform2dv glad_glProgramUniform2dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f;\n#define glProgramUniform2f glad_glProgramUniform2f\nGLAD_API_CALL PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv;\n#define glProgramUniform2fv glad_glProgramUniform2fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i;\n#define glProgramUniform2i glad_glProgramUniform2i\nGLAD_API_CALL PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv;\n#define glProgramUniform2iv glad_glProgramUniform2iv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui;\n#define glProgramUniform2ui glad_glProgramUniform2ui\nGLAD_API_CALL PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv;\n#define glProgramUniform2uiv glad_glProgramUniform2uiv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d;\n#define glProgramUniform3d glad_glProgramUniform3d\nGLAD_API_CALL PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv;\n#define glProgramUniform3dv glad_glProgramUniform3dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f;\n#define glProgramUniform3f glad_glProgramUniform3f\nGLAD_API_CALL PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv;\n#define glProgramUniform3fv glad_glProgramUniform3fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i;\n#define glProgramUniform3i glad_glProgramUniform3i\nGLAD_API_CALL PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv;\n#define glProgramUniform3iv glad_glProgramUniform3iv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui;\n#define glProgramUniform3ui glad_glProgramUniform3ui\nGLAD_API_CALL PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv;\n#define glProgramUniform3uiv glad_glProgramUniform3uiv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d;\n#define glProgramUniform4d glad_glProgramUniform4d\nGLAD_API_CALL PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv;\n#define glProgramUniform4dv glad_glProgramUniform4dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f;\n#define glProgramUniform4f glad_glProgramUniform4f\nGLAD_API_CALL PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv;\n#define glProgramUniform4fv glad_glProgramUniform4fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i;\n#define glProgramUniform4i glad_glProgramUniform4i\nGLAD_API_CALL PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv;\n#define glProgramUniform4iv glad_glProgramUniform4iv\nGLAD_API_CALL PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui;\n#define glProgramUniform4ui glad_glProgramUniform4ui\nGLAD_API_CALL PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv;\n#define glProgramUniform4uiv glad_glProgramUniform4uiv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv;\n#define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv;\n#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv;\n#define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv;\n#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv;\n#define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv;\n#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv;\n#define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv;\n#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv;\n#define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv;\n#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv;\n#define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv;\n#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv;\n#define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv;\n#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv;\n#define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv;\n#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv;\n#define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv\nGLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv;\n#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv\nGLAD_API_CALL PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;\n#define glProvokingVertex glad_glProvokingVertex\nGLAD_API_CALL PFNGLQUERYCOUNTERPROC glad_glQueryCounter;\n#define glQueryCounter glad_glQueryCounter\nGLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer;\n#define glReadBuffer glad_glReadBuffer\nGLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels;\n#define glReadPixels glad_glReadPixels\nGLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;\n#define glReleaseShaderCompiler glad_glReleaseShaderCompiler\nGLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;\n#define glRenderbufferStorage glad_glRenderbufferStorage\nGLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;\n#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample\nGLAD_API_CALL PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;\n#define glResumeTransformFeedback glad_glResumeTransformFeedback\nGLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;\n#define glSampleCoverage glad_glSampleCoverage\nGLAD_API_CALL PFNGLSAMPLEMASKIPROC glad_glSampleMaski;\n#define glSampleMaski glad_glSampleMaski\nGLAD_API_CALL PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;\n#define glSamplerParameterIiv glad_glSamplerParameterIiv\nGLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;\n#define glSamplerParameterIuiv glad_glSamplerParameterIuiv\nGLAD_API_CALL PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;\n#define glSamplerParameterf glad_glSamplerParameterf\nGLAD_API_CALL PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;\n#define glSamplerParameterfv glad_glSamplerParameterfv\nGLAD_API_CALL PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;\n#define glSamplerParameteri glad_glSamplerParameteri\nGLAD_API_CALL PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;\n#define glSamplerParameteriv glad_glSamplerParameteriv\nGLAD_API_CALL PFNGLSCISSORPROC glad_glScissor;\n#define glScissor glad_glScissor\nGLAD_API_CALL PFNGLSCISSORARRAYVPROC glad_glScissorArrayv;\n#define glScissorArrayv glad_glScissorArrayv\nGLAD_API_CALL PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed;\n#define glScissorIndexed glad_glScissorIndexed\nGLAD_API_CALL PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv;\n#define glScissorIndexedv glad_glScissorIndexedv\nGLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary;\n#define glShaderBinary glad_glShaderBinary\nGLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource;\n#define glShaderSource glad_glShaderSource\nGLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc;\n#define glStencilFunc glad_glStencilFunc\nGLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;\n#define glStencilFuncSeparate glad_glStencilFuncSeparate\nGLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask;\n#define glStencilMask glad_glStencilMask\nGLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;\n#define glStencilMaskSeparate glad_glStencilMaskSeparate\nGLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp;\n#define glStencilOp glad_glStencilOp\nGLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;\n#define glStencilOpSeparate glad_glStencilOpSeparate\nGLAD_API_CALL PFNGLTEXBUFFERPROC glad_glTexBuffer;\n#define glTexBuffer glad_glTexBuffer\nGLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D;\n#define glTexImage1D glad_glTexImage1D\nGLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D;\n#define glTexImage2D glad_glTexImage2D\nGLAD_API_CALL PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;\n#define glTexImage2DMultisample glad_glTexImage2DMultisample\nGLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D;\n#define glTexImage3D glad_glTexImage3D\nGLAD_API_CALL PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;\n#define glTexImage3DMultisample glad_glTexImage3DMultisample\nGLAD_API_CALL PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;\n#define glTexParameterIiv glad_glTexParameterIiv\nGLAD_API_CALL PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;\n#define glTexParameterIuiv glad_glTexParameterIuiv\nGLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf;\n#define glTexParameterf glad_glTexParameterf\nGLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;\n#define glTexParameterfv glad_glTexParameterfv\nGLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri;\n#define glTexParameteri glad_glTexParameteri\nGLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;\n#define glTexParameteriv glad_glTexParameteriv\nGLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;\n#define glTexSubImage1D glad_glTexSubImage1D\nGLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;\n#define glTexSubImage2D glad_glTexSubImage2D\nGLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;\n#define glTexSubImage3D glad_glTexSubImage3D\nGLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;\n#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings\nGLAD_API_CALL PFNGLUNIFORM1DPROC glad_glUniform1d;\n#define glUniform1d glad_glUniform1d\nGLAD_API_CALL PFNGLUNIFORM1DVPROC glad_glUniform1dv;\n#define glUniform1dv glad_glUniform1dv\nGLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f;\n#define glUniform1f glad_glUniform1f\nGLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv;\n#define glUniform1fv glad_glUniform1fv\nGLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i;\n#define glUniform1i glad_glUniform1i\nGLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv;\n#define glUniform1iv glad_glUniform1iv\nGLAD_API_CALL PFNGLUNIFORM1UIPROC glad_glUniform1ui;\n#define glUniform1ui glad_glUniform1ui\nGLAD_API_CALL PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;\n#define glUniform1uiv glad_glUniform1uiv\nGLAD_API_CALL PFNGLUNIFORM2DPROC glad_glUniform2d;\n#define glUniform2d glad_glUniform2d\nGLAD_API_CALL PFNGLUNIFORM2DVPROC glad_glUniform2dv;\n#define glUniform2dv glad_glUniform2dv\nGLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f;\n#define glUniform2f glad_glUniform2f\nGLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv;\n#define glUniform2fv glad_glUniform2fv\nGLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i;\n#define glUniform2i glad_glUniform2i\nGLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv;\n#define glUniform2iv glad_glUniform2iv\nGLAD_API_CALL PFNGLUNIFORM2UIPROC glad_glUniform2ui;\n#define glUniform2ui glad_glUniform2ui\nGLAD_API_CALL PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;\n#define glUniform2uiv glad_glUniform2uiv\nGLAD_API_CALL PFNGLUNIFORM3DPROC glad_glUniform3d;\n#define glUniform3d glad_glUniform3d\nGLAD_API_CALL PFNGLUNIFORM3DVPROC glad_glUniform3dv;\n#define glUniform3dv glad_glUniform3dv\nGLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f;\n#define glUniform3f glad_glUniform3f\nGLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv;\n#define glUniform3fv glad_glUniform3fv\nGLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i;\n#define glUniform3i glad_glUniform3i\nGLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv;\n#define glUniform3iv glad_glUniform3iv\nGLAD_API_CALL PFNGLUNIFORM3UIPROC glad_glUniform3ui;\n#define glUniform3ui glad_glUniform3ui\nGLAD_API_CALL PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;\n#define glUniform3uiv glad_glUniform3uiv\nGLAD_API_CALL PFNGLUNIFORM4DPROC glad_glUniform4d;\n#define glUniform4d glad_glUniform4d\nGLAD_API_CALL PFNGLUNIFORM4DVPROC glad_glUniform4dv;\n#define glUniform4dv glad_glUniform4dv\nGLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f;\n#define glUniform4f glad_glUniform4f\nGLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv;\n#define glUniform4fv glad_glUniform4fv\nGLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i;\n#define glUniform4i glad_glUniform4i\nGLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv;\n#define glUniform4iv glad_glUniform4iv\nGLAD_API_CALL PFNGLUNIFORM4UIPROC glad_glUniform4ui;\n#define glUniform4ui glad_glUniform4ui\nGLAD_API_CALL PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;\n#define glUniform4uiv glad_glUniform4uiv\nGLAD_API_CALL PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;\n#define glUniformBlockBinding glad_glUniformBlockBinding\nGLAD_API_CALL PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv;\n#define glUniformMatrix2dv glad_glUniformMatrix2dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;\n#define glUniformMatrix2fv glad_glUniformMatrix2fv\nGLAD_API_CALL PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv;\n#define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;\n#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv\nGLAD_API_CALL PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv;\n#define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;\n#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv\nGLAD_API_CALL PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv;\n#define glUniformMatrix3dv glad_glUniformMatrix3dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;\n#define glUniformMatrix3fv glad_glUniformMatrix3fv\nGLAD_API_CALL PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv;\n#define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;\n#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv\nGLAD_API_CALL PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv;\n#define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;\n#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv\nGLAD_API_CALL PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv;\n#define glUniformMatrix4dv glad_glUniformMatrix4dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;\n#define glUniformMatrix4fv glad_glUniformMatrix4fv\nGLAD_API_CALL PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv;\n#define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;\n#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv\nGLAD_API_CALL PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv;\n#define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv\nGLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;\n#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv\nGLAD_API_CALL PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv;\n#define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv\nGLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;\n#define glUnmapBuffer glad_glUnmapBuffer\nGLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram;\n#define glUseProgram glad_glUseProgram\nGLAD_API_CALL PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages;\n#define glUseProgramStages glad_glUseProgramStages\nGLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;\n#define glValidateProgram glad_glValidateProgram\nGLAD_API_CALL PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline;\n#define glValidateProgramPipeline glad_glValidateProgramPipeline\nGLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;\n#define glVertexAttrib1d glad_glVertexAttrib1d\nGLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;\n#define glVertexAttrib1dv glad_glVertexAttrib1dv\nGLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;\n#define glVertexAttrib1f glad_glVertexAttrib1f\nGLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;\n#define glVertexAttrib1fv glad_glVertexAttrib1fv\nGLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;\n#define glVertexAttrib1s glad_glVertexAttrib1s\nGLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;\n#define glVertexAttrib1sv glad_glVertexAttrib1sv\nGLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;\n#define glVertexAttrib2d glad_glVertexAttrib2d\nGLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;\n#define glVertexAttrib2dv glad_glVertexAttrib2dv\nGLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;\n#define glVertexAttrib2f glad_glVertexAttrib2f\nGLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;\n#define glVertexAttrib2fv glad_glVertexAttrib2fv\nGLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;\n#define glVertexAttrib2s glad_glVertexAttrib2s\nGLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;\n#define glVertexAttrib2sv glad_glVertexAttrib2sv\nGLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;\n#define glVertexAttrib3d glad_glVertexAttrib3d\nGLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;\n#define glVertexAttrib3dv glad_glVertexAttrib3dv\nGLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;\n#define glVertexAttrib3f glad_glVertexAttrib3f\nGLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;\n#define glVertexAttrib3fv glad_glVertexAttrib3fv\nGLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;\n#define glVertexAttrib3s glad_glVertexAttrib3s\nGLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;\n#define glVertexAttrib3sv glad_glVertexAttrib3sv\nGLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;\n#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv\nGLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;\n#define glVertexAttrib4Niv glad_glVertexAttrib4Niv\nGLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;\n#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv\nGLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;\n#define glVertexAttrib4Nub glad_glVertexAttrib4Nub\nGLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;\n#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv\nGLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;\n#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv\nGLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;\n#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv\nGLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;\n#define glVertexAttrib4bv glad_glVertexAttrib4bv\nGLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;\n#define glVertexAttrib4d glad_glVertexAttrib4d\nGLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;\n#define glVertexAttrib4dv glad_glVertexAttrib4dv\nGLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;\n#define glVertexAttrib4f glad_glVertexAttrib4f\nGLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;\n#define glVertexAttrib4fv glad_glVertexAttrib4fv\nGLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;\n#define glVertexAttrib4iv glad_glVertexAttrib4iv\nGLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;\n#define glVertexAttrib4s glad_glVertexAttrib4s\nGLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;\n#define glVertexAttrib4sv glad_glVertexAttrib4sv\nGLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;\n#define glVertexAttrib4ubv glad_glVertexAttrib4ubv\nGLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;\n#define glVertexAttrib4uiv glad_glVertexAttrib4uiv\nGLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;\n#define glVertexAttrib4usv glad_glVertexAttrib4usv\nGLAD_API_CALL PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;\n#define glVertexAttribDivisor glad_glVertexAttribDivisor\nGLAD_API_CALL PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;\n#define glVertexAttribI1i glad_glVertexAttribI1i\nGLAD_API_CALL PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;\n#define glVertexAttribI1iv glad_glVertexAttribI1iv\nGLAD_API_CALL PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;\n#define glVertexAttribI1ui glad_glVertexAttribI1ui\nGLAD_API_CALL PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;\n#define glVertexAttribI1uiv glad_glVertexAttribI1uiv\nGLAD_API_CALL PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;\n#define glVertexAttribI2i glad_glVertexAttribI2i\nGLAD_API_CALL PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;\n#define glVertexAttribI2iv glad_glVertexAttribI2iv\nGLAD_API_CALL PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;\n#define glVertexAttribI2ui glad_glVertexAttribI2ui\nGLAD_API_CALL PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;\n#define glVertexAttribI2uiv glad_glVertexAttribI2uiv\nGLAD_API_CALL PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;\n#define glVertexAttribI3i glad_glVertexAttribI3i\nGLAD_API_CALL PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;\n#define glVertexAttribI3iv glad_glVertexAttribI3iv\nGLAD_API_CALL PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;\n#define glVertexAttribI3ui glad_glVertexAttribI3ui\nGLAD_API_CALL PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;\n#define glVertexAttribI3uiv glad_glVertexAttribI3uiv\nGLAD_API_CALL PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;\n#define glVertexAttribI4bv glad_glVertexAttribI4bv\nGLAD_API_CALL PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;\n#define glVertexAttribI4i glad_glVertexAttribI4i\nGLAD_API_CALL PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;\n#define glVertexAttribI4iv glad_glVertexAttribI4iv\nGLAD_API_CALL PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;\n#define glVertexAttribI4sv glad_glVertexAttribI4sv\nGLAD_API_CALL PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;\n#define glVertexAttribI4ubv glad_glVertexAttribI4ubv\nGLAD_API_CALL PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;\n#define glVertexAttribI4ui glad_glVertexAttribI4ui\nGLAD_API_CALL PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;\n#define glVertexAttribI4uiv glad_glVertexAttribI4uiv\nGLAD_API_CALL PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;\n#define glVertexAttribI4usv glad_glVertexAttribI4usv\nGLAD_API_CALL PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;\n#define glVertexAttribIPointer glad_glVertexAttribIPointer\nGLAD_API_CALL PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d;\n#define glVertexAttribL1d glad_glVertexAttribL1d\nGLAD_API_CALL PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv;\n#define glVertexAttribL1dv glad_glVertexAttribL1dv\nGLAD_API_CALL PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d;\n#define glVertexAttribL2d glad_glVertexAttribL2d\nGLAD_API_CALL PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv;\n#define glVertexAttribL2dv glad_glVertexAttribL2dv\nGLAD_API_CALL PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d;\n#define glVertexAttribL3d glad_glVertexAttribL3d\nGLAD_API_CALL PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv;\n#define glVertexAttribL3dv glad_glVertexAttribL3dv\nGLAD_API_CALL PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d;\n#define glVertexAttribL4d glad_glVertexAttribL4d\nGLAD_API_CALL PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv;\n#define glVertexAttribL4dv glad_glVertexAttribL4dv\nGLAD_API_CALL PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer;\n#define glVertexAttribLPointer glad_glVertexAttribLPointer\nGLAD_API_CALL PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;\n#define glVertexAttribP1ui glad_glVertexAttribP1ui\nGLAD_API_CALL PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;\n#define glVertexAttribP1uiv glad_glVertexAttribP1uiv\nGLAD_API_CALL PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;\n#define glVertexAttribP2ui glad_glVertexAttribP2ui\nGLAD_API_CALL PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;\n#define glVertexAttribP2uiv glad_glVertexAttribP2uiv\nGLAD_API_CALL PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;\n#define glVertexAttribP3ui glad_glVertexAttribP3ui\nGLAD_API_CALL PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;\n#define glVertexAttribP3uiv glad_glVertexAttribP3uiv\nGLAD_API_CALL PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;\n#define glVertexAttribP4ui glad_glVertexAttribP4ui\nGLAD_API_CALL PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;\n#define glVertexAttribP4uiv glad_glVertexAttribP4uiv\nGLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;\n#define glVertexAttribPointer glad_glVertexAttribPointer\nGLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport;\n#define glViewport glad_glViewport\nGLAD_API_CALL PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv;\n#define glViewportArrayv glad_glViewportArrayv\nGLAD_API_CALL PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf;\n#define glViewportIndexedf glad_glViewportIndexedf\nGLAD_API_CALL PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv;\n#define glViewportIndexedfv glad_glViewportIndexedfv\nGLAD_API_CALL PFNGLWAITSYNCPROC glad_glWaitSync;\n#define glWaitSync glad_glWaitSync\n\n\n\n\n\nGLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr);\nGLAD_API_CALL int gladLoadGL( GLADloadfunc load);\n\n\n#ifdef GLAD_GL\n\nGLAD_API_CALL int gladLoaderLoadGL(void);\nGLAD_API_CALL void gladLoaderUnloadGL(void);\n\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "lib/osgl/glad/src/egl.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <glad/egl.h>\n\n#ifndef GLAD_IMPL_UTIL_C_\n#define GLAD_IMPL_UTIL_C_\n\n#ifdef _MSC_VER\n#define GLAD_IMPL_UTIL_SSCANF sscanf_s\n#else\n#define GLAD_IMPL_UTIL_SSCANF sscanf\n#endif\n\n#endif /* GLAD_IMPL_UTIL_C_ */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n\nint GLAD_EGL_VERSION_1_0 = 0;\nint GLAD_EGL_VERSION_1_1 = 0;\nint GLAD_EGL_VERSION_1_2 = 0;\nint GLAD_EGL_VERSION_1_3 = 0;\nint GLAD_EGL_VERSION_1_4 = 0;\nint GLAD_EGL_VERSION_1_5 = 0;\nint GLAD_EGL_EXT_device_base = 0;\nint GLAD_EGL_EXT_device_enumeration = 0;\nint GLAD_EGL_EXT_device_query = 0;\nint GLAD_EGL_EXT_device_query_name = 0;\nint GLAD_EGL_EXT_platform_base = 0;\nint GLAD_EGL_EXT_platform_device = 0;\n\n\n\nPFNEGLBINDAPIPROC glad_eglBindAPI = NULL;\nPFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage = NULL;\nPFNEGLCHOOSECONFIGPROC glad_eglChooseConfig = NULL;\nPFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync = NULL;\nPFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers = NULL;\nPFNEGLCREATECONTEXTPROC glad_eglCreateContext = NULL;\nPFNEGLCREATEIMAGEPROC glad_eglCreateImage = NULL;\nPFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer = NULL;\nPFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface = NULL;\nPFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface = NULL;\nPFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface = NULL;\nPFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC glad_eglCreatePlatformPixmapSurfaceEXT = NULL;\nPFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface = NULL;\nPFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC glad_eglCreatePlatformWindowSurfaceEXT = NULL;\nPFNEGLCREATESYNCPROC glad_eglCreateSync = NULL;\nPFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface = NULL;\nPFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext = NULL;\nPFNEGLDESTROYIMAGEPROC glad_eglDestroyImage = NULL;\nPFNEGLDESTROYSURFACEPROC glad_eglDestroySurface = NULL;\nPFNEGLDESTROYSYNCPROC glad_eglDestroySync = NULL;\nPFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib = NULL;\nPFNEGLGETCONFIGSPROC glad_eglGetConfigs = NULL;\nPFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext = NULL;\nPFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay = NULL;\nPFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface = NULL;\nPFNEGLGETDISPLAYPROC glad_eglGetDisplay = NULL;\nPFNEGLGETERRORPROC glad_eglGetError = NULL;\nPFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay = NULL;\nPFNEGLGETPLATFORMDISPLAYEXTPROC glad_eglGetPlatformDisplayEXT = NULL;\nPFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress = NULL;\nPFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib = NULL;\nPFNEGLINITIALIZEPROC glad_eglInitialize = NULL;\nPFNEGLMAKECURRENTPROC glad_eglMakeCurrent = NULL;\nPFNEGLQUERYAPIPROC glad_eglQueryAPI = NULL;\nPFNEGLQUERYCONTEXTPROC glad_eglQueryContext = NULL;\nPFNEGLQUERYDEVICEATTRIBEXTPROC glad_eglQueryDeviceAttribEXT = NULL;\nPFNEGLQUERYDEVICESTRINGEXTPROC glad_eglQueryDeviceStringEXT = NULL;\nPFNEGLQUERYDEVICESEXTPROC glad_eglQueryDevicesEXT = NULL;\nPFNEGLQUERYDISPLAYATTRIBEXTPROC glad_eglQueryDisplayAttribEXT = NULL;\nPFNEGLQUERYSTRINGPROC glad_eglQueryString = NULL;\nPFNEGLQUERYSURFACEPROC glad_eglQuerySurface = NULL;\nPFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage = NULL;\nPFNEGLRELEASETHREADPROC glad_eglReleaseThread = NULL;\nPFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib = NULL;\nPFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers = NULL;\nPFNEGLSWAPINTERVALPROC glad_eglSwapInterval = NULL;\nPFNEGLTERMINATEPROC glad_eglTerminate = NULL;\nPFNEGLWAITCLIENTPROC glad_eglWaitClient = NULL;\nPFNEGLWAITGLPROC glad_eglWaitGL = NULL;\nPFNEGLWAITNATIVEPROC glad_eglWaitNative = NULL;\nPFNEGLWAITSYNCPROC glad_eglWaitSync = NULL;\n\n\nstatic void glad_egl_load_EGL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_VERSION_1_0) return;\n    glad_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) load(userptr, \"eglChooseConfig\");\n    glad_eglCopyBuffers = (PFNEGLCOPYBUFFERSPROC) load(userptr, \"eglCopyBuffers\");\n    glad_eglCreateContext = (PFNEGLCREATECONTEXTPROC) load(userptr, \"eglCreateContext\");\n    glad_eglCreatePbufferSurface = (PFNEGLCREATEPBUFFERSURFACEPROC) load(userptr, \"eglCreatePbufferSurface\");\n    glad_eglCreatePixmapSurface = (PFNEGLCREATEPIXMAPSURFACEPROC) load(userptr, \"eglCreatePixmapSurface\");\n    glad_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) load(userptr, \"eglCreateWindowSurface\");\n    glad_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) load(userptr, \"eglDestroyContext\");\n    glad_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) load(userptr, \"eglDestroySurface\");\n    glad_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) load(userptr, \"eglGetConfigAttrib\");\n    glad_eglGetConfigs = (PFNEGLGETCONFIGSPROC) load(userptr, \"eglGetConfigs\");\n    glad_eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, \"eglGetCurrentDisplay\");\n    glad_eglGetCurrentSurface = (PFNEGLGETCURRENTSURFACEPROC) load(userptr, \"eglGetCurrentSurface\");\n    glad_eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, \"eglGetDisplay\");\n    glad_eglGetError = (PFNEGLGETERRORPROC) load(userptr, \"eglGetError\");\n    glad_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC) load(userptr, \"eglGetProcAddress\");\n    glad_eglInitialize = (PFNEGLINITIALIZEPROC) load(userptr, \"eglInitialize\");\n    glad_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) load(userptr, \"eglMakeCurrent\");\n    glad_eglQueryContext = (PFNEGLQUERYCONTEXTPROC) load(userptr, \"eglQueryContext\");\n    glad_eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, \"eglQueryString\");\n    glad_eglQuerySurface = (PFNEGLQUERYSURFACEPROC) load(userptr, \"eglQuerySurface\");\n    glad_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) load(userptr, \"eglSwapBuffers\");\n    glad_eglTerminate = (PFNEGLTERMINATEPROC) load(userptr, \"eglTerminate\");\n    glad_eglWaitGL = (PFNEGLWAITGLPROC) load(userptr, \"eglWaitGL\");\n    glad_eglWaitNative = (PFNEGLWAITNATIVEPROC) load(userptr, \"eglWaitNative\");\n}\nstatic void glad_egl_load_EGL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_VERSION_1_1) return;\n    glad_eglBindTexImage = (PFNEGLBINDTEXIMAGEPROC) load(userptr, \"eglBindTexImage\");\n    glad_eglReleaseTexImage = (PFNEGLRELEASETEXIMAGEPROC) load(userptr, \"eglReleaseTexImage\");\n    glad_eglSurfaceAttrib = (PFNEGLSURFACEATTRIBPROC) load(userptr, \"eglSurfaceAttrib\");\n    glad_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) load(userptr, \"eglSwapInterval\");\n}\nstatic void glad_egl_load_EGL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_VERSION_1_2) return;\n    glad_eglBindAPI = (PFNEGLBINDAPIPROC) load(userptr, \"eglBindAPI\");\n    glad_eglCreatePbufferFromClientBuffer = (PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) load(userptr, \"eglCreatePbufferFromClientBuffer\");\n    glad_eglQueryAPI = (PFNEGLQUERYAPIPROC) load(userptr, \"eglQueryAPI\");\n    glad_eglReleaseThread = (PFNEGLRELEASETHREADPROC) load(userptr, \"eglReleaseThread\");\n    glad_eglWaitClient = (PFNEGLWAITCLIENTPROC) load(userptr, \"eglWaitClient\");\n}\nstatic void glad_egl_load_EGL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_VERSION_1_4) return;\n    glad_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) load(userptr, \"eglGetCurrentContext\");\n}\nstatic void glad_egl_load_EGL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_VERSION_1_5) return;\n    glad_eglClientWaitSync = (PFNEGLCLIENTWAITSYNCPROC) load(userptr, \"eglClientWaitSync\");\n    glad_eglCreateImage = (PFNEGLCREATEIMAGEPROC) load(userptr, \"eglCreateImage\");\n    glad_eglCreatePlatformPixmapSurface = (PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) load(userptr, \"eglCreatePlatformPixmapSurface\");\n    glad_eglCreatePlatformWindowSurface = (PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) load(userptr, \"eglCreatePlatformWindowSurface\");\n    glad_eglCreateSync = (PFNEGLCREATESYNCPROC) load(userptr, \"eglCreateSync\");\n    glad_eglDestroyImage = (PFNEGLDESTROYIMAGEPROC) load(userptr, \"eglDestroyImage\");\n    glad_eglDestroySync = (PFNEGLDESTROYSYNCPROC) load(userptr, \"eglDestroySync\");\n    glad_eglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYPROC) load(userptr, \"eglGetPlatformDisplay\");\n    glad_eglGetSyncAttrib = (PFNEGLGETSYNCATTRIBPROC) load(userptr, \"eglGetSyncAttrib\");\n    glad_eglWaitSync = (PFNEGLWAITSYNCPROC) load(userptr, \"eglWaitSync\");\n}\nstatic void glad_egl_load_EGL_EXT_device_base( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_EXT_device_base) return;\n    glad_eglQueryDeviceAttribEXT = (PFNEGLQUERYDEVICEATTRIBEXTPROC) load(userptr, \"eglQueryDeviceAttribEXT\");\n    glad_eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC) load(userptr, \"eglQueryDeviceStringEXT\");\n    glad_eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC) load(userptr, \"eglQueryDevicesEXT\");\n    glad_eglQueryDisplayAttribEXT = (PFNEGLQUERYDISPLAYATTRIBEXTPROC) load(userptr, \"eglQueryDisplayAttribEXT\");\n}\nstatic void glad_egl_load_EGL_EXT_device_enumeration( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_EXT_device_enumeration) return;\n    glad_eglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC) load(userptr, \"eglQueryDevicesEXT\");\n}\nstatic void glad_egl_load_EGL_EXT_device_query( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_EXT_device_query) return;\n    glad_eglQueryDeviceAttribEXT = (PFNEGLQUERYDEVICEATTRIBEXTPROC) load(userptr, \"eglQueryDeviceAttribEXT\");\n    glad_eglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC) load(userptr, \"eglQueryDeviceStringEXT\");\n    glad_eglQueryDisplayAttribEXT = (PFNEGLQUERYDISPLAYATTRIBEXTPROC) load(userptr, \"eglQueryDisplayAttribEXT\");\n}\nstatic void glad_egl_load_EGL_EXT_platform_base( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_EGL_EXT_platform_base) return;\n    glad_eglCreatePlatformPixmapSurfaceEXT = (PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) load(userptr, \"eglCreatePlatformPixmapSurfaceEXT\");\n    glad_eglCreatePlatformWindowSurfaceEXT = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) load(userptr, \"eglCreatePlatformWindowSurfaceEXT\");\n    glad_eglGetPlatformDisplayEXT = (PFNEGLGETPLATFORMDISPLAYEXTPROC) load(userptr, \"eglGetPlatformDisplayEXT\");\n}\n\n\n\nstatic int glad_egl_get_extensions(EGLDisplay display, const char **extensions) {\n    *extensions = eglQueryString(display, EGL_EXTENSIONS);\n\n    return extensions != NULL;\n}\n\nstatic int glad_egl_has_extension(const char *extensions, const char *ext) {\n    const char *loc;\n    const char *terminator;\n    if(extensions == NULL) {\n        return 0;\n    }\n    while(1) {\n        loc = strstr(extensions, ext);\n        if(loc == NULL) {\n            return 0;\n        }\n        terminator = loc + strlen(ext);\n        if((loc == extensions || *(loc - 1) == ' ') &&\n            (*terminator == ' ' || *terminator == '\\0')) {\n            return 1;\n        }\n        extensions = terminator;\n    }\n}\n\nstatic GLADapiproc glad_egl_get_proc_from_userptr(void *userptr, const char *name) {\n    return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);\n}\n\nstatic int glad_egl_find_extensions_egl(EGLDisplay display) {\n    const char *extensions;\n    if (!glad_egl_get_extensions(display, &extensions)) return 0;\n\n    GLAD_EGL_EXT_device_base = glad_egl_has_extension(extensions, \"EGL_EXT_device_base\");\n    GLAD_EGL_EXT_device_enumeration = glad_egl_has_extension(extensions, \"EGL_EXT_device_enumeration\");\n    GLAD_EGL_EXT_device_query = glad_egl_has_extension(extensions, \"EGL_EXT_device_query\");\n    GLAD_EGL_EXT_device_query_name = glad_egl_has_extension(extensions, \"EGL_EXT_device_query_name\");\n    GLAD_EGL_EXT_platform_base = glad_egl_has_extension(extensions, \"EGL_EXT_platform_base\");\n    GLAD_EGL_EXT_platform_device = glad_egl_has_extension(extensions, \"EGL_EXT_platform_device\");\n\n    return 1;\n}\n\nstatic int glad_egl_find_core_egl(EGLDisplay display) {\n    int major, minor;\n    const char *version;\n\n//    if (display == NULL) {\n//        display = EGL_NO_DISPLAY; /* this is usually NULL, better safe than sorry */\n//    }\n//    if (display == EGL_NO_DISPLAY) {\n//        display = eglGetCurrentDisplay();\n//    }\n//#ifdef EGL_VERSION_1_4\n//    if (display == EGL_NO_DISPLAY) {\n//        display = eglGetDisplay(EGL_DEFAULT_DISPLAY);\n//    }\n//#endif\n//#ifndef EGL_VERSION_1_5\n//    if (display == EGL_NO_DISPLAY) {\n//        return 0;\n//    }\n//#endif\n//\n//    version = eglQueryString(display, EGL_VERSION);\n    \n    // Modification: this needs to be called with NULL display to work properly\n    version = eglQueryString(EGL_NO_DISPLAY, EGL_VERSION);\n    (void) eglGetError();\n\n    if (version == NULL) {\n        major = 1;\n        minor = 0;\n    } else {\n        GLAD_IMPL_UTIL_SSCANF(version, \"%d.%d\", &major, &minor);\n    }\n\n    GLAD_EGL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;\n    GLAD_EGL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;\n    GLAD_EGL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;\n    GLAD_EGL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;\n    GLAD_EGL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;\n    GLAD_EGL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;\n\n    return GLAD_MAKE_VERSION(major, minor);\n}\n\nint gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void* userptr) {\n    int version;\n    eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, \"eglGetDisplay\");\n    eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, \"eglGetCurrentDisplay\");\n    eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, \"eglQueryString\");\n    eglGetError = (PFNEGLGETERRORPROC) load(userptr, \"eglGetError\");\n    if (eglGetDisplay == NULL || eglGetCurrentDisplay == NULL || eglQueryString == NULL || eglGetError == NULL) return 0;\n\n    version = glad_egl_find_core_egl(display);\n    if (!version) return 0;\n    glad_egl_load_EGL_VERSION_1_0(load, userptr);\n    glad_egl_load_EGL_VERSION_1_1(load, userptr);\n    glad_egl_load_EGL_VERSION_1_2(load, userptr);\n    glad_egl_load_EGL_VERSION_1_4(load, userptr);\n    glad_egl_load_EGL_VERSION_1_5(load, userptr);\n\n    if (!glad_egl_find_extensions_egl(display)) return 0;\n    glad_egl_load_EGL_EXT_device_base(load, userptr);\n    glad_egl_load_EGL_EXT_device_enumeration(load, userptr);\n    glad_egl_load_EGL_EXT_device_query(load, userptr);\n    glad_egl_load_EGL_EXT_platform_base(load, userptr);\n\n    return version;\n}\n\nint gladLoadEGL(EGLDisplay display, GLADloadfunc load) {\n    return gladLoadEGLUserPtr(display, glad_egl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);\n}\n\n \n\n#ifdef GLAD_EGL\n\n#ifndef GLAD_LOADER_LIBRARY_C_\n#define GLAD_LOADER_LIBRARY_C_\n\n#include <stddef.h>\n#include <stdlib.h>\n\n#if GLAD_PLATFORM_WIN32\n#include <windows.h>\n#else\n#include <dlfcn.h>\n#endif\n\n\nstatic void* glad_get_dlopen_handle(const char *lib_names[], int length) {\n    void *handle = NULL;\n    int i;\n\n    for (i = 0; i < length; ++i) {\n#if GLAD_PLATFORM_WIN32\n  #if GLAD_PLATFORM_UWP\n        size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR);\n        LPWSTR buffer = (LPWSTR) malloc(buffer_size);\n        if (buffer != NULL) {\n            int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size);\n            if (ret != 0) {\n                handle = (void*) LoadPackagedLibrary(buffer, 0);\n            }\n            free((void*) buffer);\n        }\n  #else\n        handle = (void*) LoadLibraryA(lib_names[i]);\n  #endif\n#else\n        handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL);\n#endif\n        if (handle != NULL) {\n            return handle;\n        }\n    }\n\n    return NULL;\n}\n\nstatic void glad_close_dlopen_handle(void* handle) {\n    if (handle != NULL) {\n#if GLAD_PLATFORM_WIN32\n        FreeLibrary((HMODULE) handle);\n#else\n        dlclose(handle);\n#endif\n    }\n}\n\nstatic GLADapiproc glad_dlsym_handle(void* handle, const char *name) {\n    if (handle == NULL) {\n        return NULL;\n    }\n\n#if GLAD_PLATFORM_WIN32\n    return (GLADapiproc) GetProcAddress((HMODULE) handle, name);\n#else\n    return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name);\n#endif\n}\n\n#endif /* GLAD_LOADER_LIBRARY_C_ */\n\nstruct _glad_egl_userptr {\n    void *handle;\n    PFNEGLGETPROCADDRESSPROC get_proc_address_ptr;\n};\n\nstatic GLADapiproc glad_egl_get_proc(void *vuserptr, const char* name) {\n    struct _glad_egl_userptr userptr = *(struct _glad_egl_userptr*) vuserptr;\n    GLADapiproc result = NULL;\n\n    result = glad_dlsym_handle(userptr.handle, name);\n    if (result == NULL) {\n        result = GLAD_GNUC_EXTENSION (GLADapiproc) userptr.get_proc_address_ptr(name);\n    }\n\n    return result;\n}\n\nstatic void* _egl_handle = NULL;\n\nstatic void* glad_egl_dlopen_handle(void) {\n#if GLAD_PLATFORM_APPLE\n    static const char *NAMES[] = {\"libEGL.dylib\"};\n#elif GLAD_PLATFORM_WIN32\n    static const char *NAMES[] = {\"libEGL.dll\", \"EGL.dll\"};\n#else\n    static const char *NAMES[] = {\"libEGL.so.1\", \"libEGL.so\"};\n#endif\n\n    if (_egl_handle == NULL) {\n        _egl_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));\n    }\n\n    return _egl_handle;\n}\n\nstatic struct _glad_egl_userptr glad_egl_build_userptr(void *handle) {\n    struct _glad_egl_userptr userptr;\n    userptr.handle = handle;\n    userptr.get_proc_address_ptr = (PFNEGLGETPROCADDRESSPROC) glad_dlsym_handle(handle, \"eglGetProcAddress\");\n    return userptr;\n}\n\nint gladLoaderLoadEGL(EGLDisplay display) {\n    int version = 0;\n    void *handle = NULL;\n    int did_load = 0;\n    struct _glad_egl_userptr userptr;\n\n    did_load = _egl_handle == NULL;\n    handle = glad_egl_dlopen_handle();\n    if (handle != NULL) {\n        userptr = glad_egl_build_userptr(handle);\n\n        if (userptr.get_proc_address_ptr != NULL) {\n            version = gladLoadEGLUserPtr(display, glad_egl_get_proc, &userptr);\n        }\n\n        if (!version && did_load) {\n            gladLoaderUnloadEGL();\n        }\n    }\n\n    return version;\n}\n\n\nvoid gladLoaderUnloadEGL() {\n    if (_egl_handle != NULL) {\n        glad_close_dlopen_handle(_egl_handle);\n        _egl_handle = NULL;\n    }\n}\n\n#endif /* GLAD_EGL */\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "lib/osgl/glad/src/gl.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <glad/gl.h>\n\n#ifndef GLAD_IMPL_UTIL_C_\n#define GLAD_IMPL_UTIL_C_\n\n#ifdef _MSC_VER\n#define GLAD_IMPL_UTIL_SSCANF sscanf_s\n#else\n#define GLAD_IMPL_UTIL_SSCANF sscanf\n#endif\n\n#endif /* GLAD_IMPL_UTIL_C_ */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\n\nint GLAD_GL_VERSION_1_0 = 0;\nint GLAD_GL_VERSION_1_1 = 0;\nint GLAD_GL_VERSION_1_2 = 0;\nint GLAD_GL_VERSION_1_3 = 0;\nint GLAD_GL_VERSION_1_4 = 0;\nint GLAD_GL_VERSION_1_5 = 0;\nint GLAD_GL_VERSION_2_0 = 0;\nint GLAD_GL_VERSION_2_1 = 0;\nint GLAD_GL_VERSION_3_0 = 0;\nint GLAD_GL_VERSION_3_1 = 0;\nint GLAD_GL_VERSION_3_2 = 0;\nint GLAD_GL_VERSION_3_3 = 0;\nint GLAD_GL_VERSION_4_0 = 0;\nint GLAD_GL_VERSION_4_1 = 0;\n\n\n\nPFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL;\nPFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;\nPFNGLATTACHSHADERPROC glad_glAttachShader = NULL;\nPFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;\nPFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;\nPFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL;\nPFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;\nPFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;\nPFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;\nPFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;\nPFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;\nPFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;\nPFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;\nPFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;\nPFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL;\nPFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;\nPFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;\nPFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;\nPFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;\nPFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;\nPFNGLBLENDCOLORPROC glad_glBlendColor = NULL;\nPFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;\nPFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;\nPFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL;\nPFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL;\nPFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;\nPFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;\nPFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL;\nPFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL;\nPFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;\nPFNGLBUFFERDATAPROC glad_glBufferData = NULL;\nPFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;\nPFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;\nPFNGLCLAMPCOLORPROC glad_glClampColor = NULL;\nPFNGLCLEARPROC glad_glClear = NULL;\nPFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;\nPFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;\nPFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;\nPFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;\nPFNGLCLEARCOLORPROC glad_glClearColor = NULL;\nPFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;\nPFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;\nPFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;\nPFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;\nPFNGLCOLORMASKPROC glad_glColorMask = NULL;\nPFNGLCOLORMASKIPROC glad_glColorMaski = NULL;\nPFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;\nPFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;\nPFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;\nPFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;\nPFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;\nPFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;\nPFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;\nPFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;\nPFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;\nPFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;\nPFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;\nPFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;\nPFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;\nPFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;\nPFNGLCREATESHADERPROC glad_glCreateShader = NULL;\nPFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;\nPFNGLCULLFACEPROC glad_glCullFace = NULL;\nPFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;\nPFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;\nPFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;\nPFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL;\nPFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;\nPFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;\nPFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;\nPFNGLDELETESHADERPROC glad_glDeleteShader = NULL;\nPFNGLDELETESYNCPROC glad_glDeleteSync = NULL;\nPFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;\nPFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;\nPFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;\nPFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;\nPFNGLDEPTHMASKPROC glad_glDepthMask = NULL;\nPFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;\nPFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL;\nPFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;\nPFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;\nPFNGLDETACHSHADERPROC glad_glDetachShader = NULL;\nPFNGLDISABLEPROC glad_glDisable = NULL;\nPFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;\nPFNGLDISABLEIPROC glad_glDisablei = NULL;\nPFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;\nPFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL;\nPFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;\nPFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;\nPFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;\nPFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;\nPFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;\nPFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL;\nPFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;\nPFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;\nPFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;\nPFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;\nPFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL;\nPFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL;\nPFNGLENABLEPROC glad_glEnable = NULL;\nPFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;\nPFNGLENABLEIPROC glad_glEnablei = NULL;\nPFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;\nPFNGLENDQUERYPROC glad_glEndQuery = NULL;\nPFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL;\nPFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;\nPFNGLFENCESYNCPROC glad_glFenceSync = NULL;\nPFNGLFINISHPROC glad_glFinish = NULL;\nPFNGLFLUSHPROC glad_glFlush = NULL;\nPFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;\nPFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;\nPFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;\nPFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;\nPFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;\nPFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;\nPFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;\nPFNGLFRONTFACEPROC glad_glFrontFace = NULL;\nPFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;\nPFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;\nPFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL;\nPFNGLGENQUERIESPROC glad_glGenQueries = NULL;\nPFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;\nPFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;\nPFNGLGENTEXTURESPROC glad_glGenTextures = NULL;\nPFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;\nPFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;\nPFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;\nPFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;\nPFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL;\nPFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL;\nPFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL;\nPFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;\nPFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;\nPFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;\nPFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;\nPFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;\nPFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;\nPFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;\nPFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;\nPFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;\nPFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;\nPFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;\nPFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;\nPFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;\nPFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;\nPFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL;\nPFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;\nPFNGLGETERRORPROC glad_glGetError = NULL;\nPFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL;\nPFNGLGETFLOATVPROC glad_glGetFloatv = NULL;\nPFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;\nPFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;\nPFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;\nPFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;\nPFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;\nPFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;\nPFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;\nPFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;\nPFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL;\nPFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;\nPFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL;\nPFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL;\nPFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL;\nPFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;\nPFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL;\nPFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;\nPFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;\nPFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;\nPFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;\nPFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;\nPFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;\nPFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;\nPFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;\nPFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;\nPFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;\nPFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;\nPFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;\nPFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;\nPFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;\nPFNGLGETSTRINGPROC glad_glGetString = NULL;\nPFNGLGETSTRINGIPROC glad_glGetStringi = NULL;\nPFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL;\nPFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL;\nPFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;\nPFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;\nPFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;\nPFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;\nPFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;\nPFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;\nPFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;\nPFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;\nPFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;\nPFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;\nPFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;\nPFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;\nPFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL;\nPFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL;\nPFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;\nPFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;\nPFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;\nPFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;\nPFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;\nPFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL;\nPFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;\nPFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;\nPFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;\nPFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;\nPFNGLHINTPROC glad_glHint = NULL;\nPFNGLISBUFFERPROC glad_glIsBuffer = NULL;\nPFNGLISENABLEDPROC glad_glIsEnabled = NULL;\nPFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;\nPFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;\nPFNGLISPROGRAMPROC glad_glIsProgram = NULL;\nPFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL;\nPFNGLISQUERYPROC glad_glIsQuery = NULL;\nPFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;\nPFNGLISSAMPLERPROC glad_glIsSampler = NULL;\nPFNGLISSHADERPROC glad_glIsShader = NULL;\nPFNGLISSYNCPROC glad_glIsSync = NULL;\nPFNGLISTEXTUREPROC glad_glIsTexture = NULL;\nPFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;\nPFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;\nPFNGLLINEWIDTHPROC glad_glLineWidth = NULL;\nPFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;\nPFNGLLOGICOPPROC glad_glLogicOp = NULL;\nPFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;\nPFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;\nPFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL;\nPFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;\nPFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;\nPFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;\nPFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL;\nPFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL;\nPFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;\nPFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;\nPFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;\nPFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;\nPFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;\nPFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;\nPFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;\nPFNGLPOINTSIZEPROC glad_glPointSize = NULL;\nPFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;\nPFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;\nPFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;\nPFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL;\nPFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL;\nPFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL;\nPFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL;\nPFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL;\nPFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL;\nPFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL;\nPFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL;\nPFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL;\nPFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL;\nPFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL;\nPFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL;\nPFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL;\nPFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL;\nPFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL;\nPFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL;\nPFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL;\nPFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL;\nPFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL;\nPFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL;\nPFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL;\nPFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL;\nPFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL;\nPFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL;\nPFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL;\nPFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL;\nPFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL;\nPFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL;\nPFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL;\nPFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL;\nPFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL;\nPFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL;\nPFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL;\nPFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL;\nPFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL;\nPFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;\nPFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;\nPFNGLREADBUFFERPROC glad_glReadBuffer = NULL;\nPFNGLREADPIXELSPROC glad_glReadPixels = NULL;\nPFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;\nPFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;\nPFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;\nPFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;\nPFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;\nPFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;\nPFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;\nPFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;\nPFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;\nPFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;\nPFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;\nPFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;\nPFNGLSCISSORPROC glad_glScissor = NULL;\nPFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL;\nPFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL;\nPFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL;\nPFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;\nPFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;\nPFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;\nPFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;\nPFNGLSTENCILMASKPROC glad_glStencilMask = NULL;\nPFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;\nPFNGLSTENCILOPPROC glad_glStencilOp = NULL;\nPFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;\nPFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;\nPFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;\nPFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;\nPFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;\nPFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;\nPFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;\nPFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;\nPFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;\nPFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;\nPFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;\nPFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;\nPFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;\nPFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;\nPFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;\nPFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;\nPFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;\nPFNGLUNIFORM1DPROC glad_glUniform1d = NULL;\nPFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL;\nPFNGLUNIFORM1FPROC glad_glUniform1f = NULL;\nPFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;\nPFNGLUNIFORM1IPROC glad_glUniform1i = NULL;\nPFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;\nPFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;\nPFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;\nPFNGLUNIFORM2DPROC glad_glUniform2d = NULL;\nPFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL;\nPFNGLUNIFORM2FPROC glad_glUniform2f = NULL;\nPFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;\nPFNGLUNIFORM2IPROC glad_glUniform2i = NULL;\nPFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;\nPFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;\nPFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;\nPFNGLUNIFORM3DPROC glad_glUniform3d = NULL;\nPFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL;\nPFNGLUNIFORM3FPROC glad_glUniform3f = NULL;\nPFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;\nPFNGLUNIFORM3IPROC glad_glUniform3i = NULL;\nPFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;\nPFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;\nPFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;\nPFNGLUNIFORM4DPROC glad_glUniform4d = NULL;\nPFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL;\nPFNGLUNIFORM4FPROC glad_glUniform4f = NULL;\nPFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;\nPFNGLUNIFORM4IPROC glad_glUniform4i = NULL;\nPFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;\nPFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;\nPFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;\nPFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;\nPFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL;\nPFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;\nPFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL;\nPFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;\nPFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL;\nPFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;\nPFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL;\nPFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;\nPFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL;\nPFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;\nPFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL;\nPFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;\nPFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL;\nPFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;\nPFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL;\nPFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;\nPFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL;\nPFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;\nPFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL;\nPFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;\nPFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;\nPFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;\nPFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;\nPFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;\nPFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;\nPFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;\nPFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;\nPFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;\nPFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;\nPFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;\nPFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;\nPFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;\nPFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;\nPFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;\nPFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;\nPFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;\nPFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;\nPFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;\nPFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;\nPFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;\nPFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;\nPFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;\nPFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;\nPFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;\nPFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;\nPFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;\nPFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;\nPFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;\nPFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;\nPFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;\nPFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;\nPFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;\nPFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;\nPFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;\nPFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;\nPFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;\nPFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;\nPFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;\nPFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;\nPFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;\nPFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;\nPFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;\nPFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;\nPFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;\nPFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;\nPFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;\nPFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;\nPFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;\nPFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;\nPFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;\nPFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;\nPFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;\nPFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;\nPFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;\nPFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;\nPFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;\nPFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;\nPFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;\nPFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;\nPFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;\nPFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;\nPFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;\nPFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL;\nPFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL;\nPFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL;\nPFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL;\nPFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL;\nPFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL;\nPFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL;\nPFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL;\nPFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL;\nPFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;\nPFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;\nPFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;\nPFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;\nPFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;\nPFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;\nPFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;\nPFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;\nPFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;\nPFNGLVIEWPORTPROC glad_glViewport = NULL;\nPFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL;\nPFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;\nPFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;\nPFNGLWAITSYNCPROC glad_glWaitSync = NULL;\n\n\nstatic void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_1_0) return;\n    glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, \"glBlendFunc\");\n    glad_glClear = (PFNGLCLEARPROC) load(userptr, \"glClear\");\n    glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, \"glClearColor\");\n    glad_glClearDepth = (PFNGLCLEARDEPTHPROC) load(userptr, \"glClearDepth\");\n    glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, \"glClearStencil\");\n    glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, \"glColorMask\");\n    glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, \"glCullFace\");\n    glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, \"glDepthFunc\");\n    glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, \"glDepthMask\");\n    glad_glDepthRange = (PFNGLDEPTHRANGEPROC) load(userptr, \"glDepthRange\");\n    glad_glDisable = (PFNGLDISABLEPROC) load(userptr, \"glDisable\");\n    glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC) load(userptr, \"glDrawBuffer\");\n    glad_glEnable = (PFNGLENABLEPROC) load(userptr, \"glEnable\");\n    glad_glFinish = (PFNGLFINISHPROC) load(userptr, \"glFinish\");\n    glad_glFlush = (PFNGLFLUSHPROC) load(userptr, \"glFlush\");\n    glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, \"glFrontFace\");\n    glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, \"glGetBooleanv\");\n    glad_glGetDoublev = (PFNGLGETDOUBLEVPROC) load(userptr, \"glGetDoublev\");\n    glad_glGetError = (PFNGLGETERRORPROC) load(userptr, \"glGetError\");\n    glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, \"glGetFloatv\");\n    glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, \"glGetIntegerv\");\n    glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, \"glGetString\");\n    glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC) load(userptr, \"glGetTexImage\");\n    glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load(userptr, \"glGetTexLevelParameterfv\");\n    glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load(userptr, \"glGetTexLevelParameteriv\");\n    glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, \"glGetTexParameterfv\");\n    glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, \"glGetTexParameteriv\");\n    glad_glHint = (PFNGLHINTPROC) load(userptr, \"glHint\");\n    glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, \"glIsEnabled\");\n    glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, \"glLineWidth\");\n    glad_glLogicOp = (PFNGLLOGICOPPROC) load(userptr, \"glLogicOp\");\n    glad_glPixelStoref = (PFNGLPIXELSTOREFPROC) load(userptr, \"glPixelStoref\");\n    glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, \"glPixelStorei\");\n    glad_glPointSize = (PFNGLPOINTSIZEPROC) load(userptr, \"glPointSize\");\n    glad_glPolygonMode = (PFNGLPOLYGONMODEPROC) load(userptr, \"glPolygonMode\");\n    glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, \"glReadBuffer\");\n    glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, \"glReadPixels\");\n    glad_glScissor = (PFNGLSCISSORPROC) load(userptr, \"glScissor\");\n    glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, \"glStencilFunc\");\n    glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, \"glStencilMask\");\n    glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, \"glStencilOp\");\n    glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC) load(userptr, \"glTexImage1D\");\n    glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, \"glTexImage2D\");\n    glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, \"glTexParameterf\");\n    glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, \"glTexParameterfv\");\n    glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, \"glTexParameteri\");\n    glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, \"glTexParameteriv\");\n    glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, \"glViewport\");\n}\nstatic void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_1_1) return;\n    glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, \"glBindTexture\");\n    glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load(userptr, \"glCopyTexImage1D\");\n    glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, \"glCopyTexImage2D\");\n    glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load(userptr, \"glCopyTexSubImage1D\");\n    glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, \"glCopyTexSubImage2D\");\n    glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, \"glDeleteTextures\");\n    glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, \"glDrawArrays\");\n    glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, \"glDrawElements\");\n    glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, \"glGenTextures\");\n    glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, \"glIsTexture\");\n    glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, \"glPolygonOffset\");\n    glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load(userptr, \"glTexSubImage1D\");\n    glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, \"glTexSubImage2D\");\n}\nstatic void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_1_2) return;\n    glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, \"glCopyTexSubImage3D\");\n    glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, \"glDrawRangeElements\");\n    glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, \"glTexImage3D\");\n    glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, \"glTexSubImage3D\");\n}\nstatic void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_1_3) return;\n    glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, \"glActiveTexture\");\n    glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load(userptr, \"glCompressedTexImage1D\");\n    glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, \"glCompressedTexImage2D\");\n    glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, \"glCompressedTexImage3D\");\n    glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load(userptr, \"glCompressedTexSubImage1D\");\n    glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, \"glCompressedTexSubImage2D\");\n    glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, \"glCompressedTexSubImage3D\");\n    glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load(userptr, \"glGetCompressedTexImage\");\n    glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, \"glSampleCoverage\");\n}\nstatic void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_1_4) return;\n    glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, \"glBlendColor\");\n    glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, \"glBlendEquation\");\n    glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, \"glBlendFuncSeparate\");\n    glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load(userptr, \"glMultiDrawArrays\");\n    glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load(userptr, \"glMultiDrawElements\");\n    glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load(userptr, \"glPointParameterf\");\n    glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load(userptr, \"glPointParameterfv\");\n    glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load(userptr, \"glPointParameteri\");\n    glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load(userptr, \"glPointParameteriv\");\n}\nstatic void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_1_5) return;\n    glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, \"glBeginQuery\");\n    glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, \"glBindBuffer\");\n    glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, \"glBufferData\");\n    glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, \"glBufferSubData\");\n    glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, \"glDeleteBuffers\");\n    glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, \"glDeleteQueries\");\n    glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, \"glEndQuery\");\n    glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, \"glGenBuffers\");\n    glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, \"glGenQueries\");\n    glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, \"glGetBufferParameteriv\");\n    glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, \"glGetBufferPointerv\");\n    glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load(userptr, \"glGetBufferSubData\");\n    glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load(userptr, \"glGetQueryObjectiv\");\n    glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, \"glGetQueryObjectuiv\");\n    glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, \"glGetQueryiv\");\n    glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, \"glIsBuffer\");\n    glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, \"glIsQuery\");\n    glad_glMapBuffer = (PFNGLMAPBUFFERPROC) load(userptr, \"glMapBuffer\");\n    glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, \"glUnmapBuffer\");\n}\nstatic void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_2_0) return;\n    glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, \"glAttachShader\");\n    glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, \"glBindAttribLocation\");\n    glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, \"glBlendEquationSeparate\");\n    glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, \"glCompileShader\");\n    glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, \"glCreateProgram\");\n    glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, \"glCreateShader\");\n    glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, \"glDeleteProgram\");\n    glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, \"glDeleteShader\");\n    glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, \"glDetachShader\");\n    glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, \"glDisableVertexAttribArray\");\n    glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, \"glDrawBuffers\");\n    glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, \"glEnableVertexAttribArray\");\n    glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, \"glGetActiveAttrib\");\n    glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, \"glGetActiveUniform\");\n    glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, \"glGetAttachedShaders\");\n    glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, \"glGetAttribLocation\");\n    glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, \"glGetProgramInfoLog\");\n    glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, \"glGetProgramiv\");\n    glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, \"glGetShaderInfoLog\");\n    glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, \"glGetShaderSource\");\n    glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, \"glGetShaderiv\");\n    glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, \"glGetUniformLocation\");\n    glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, \"glGetUniformfv\");\n    glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, \"glGetUniformiv\");\n    glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, \"glGetVertexAttribPointerv\");\n    glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load(userptr, \"glGetVertexAttribdv\");\n    glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, \"glGetVertexAttribfv\");\n    glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, \"glGetVertexAttribiv\");\n    glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, \"glIsProgram\");\n    glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, \"glIsShader\");\n    glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, \"glLinkProgram\");\n    glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, \"glShaderSource\");\n    glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, \"glStencilFuncSeparate\");\n    glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, \"glStencilMaskSeparate\");\n    glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, \"glStencilOpSeparate\");\n    glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, \"glUniform1f\");\n    glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, \"glUniform1fv\");\n    glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, \"glUniform1i\");\n    glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, \"glUniform1iv\");\n    glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, \"glUniform2f\");\n    glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, \"glUniform2fv\");\n    glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, \"glUniform2i\");\n    glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, \"glUniform2iv\");\n    glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, \"glUniform3f\");\n    glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, \"glUniform3fv\");\n    glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, \"glUniform3i\");\n    glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, \"glUniform3iv\");\n    glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, \"glUniform4f\");\n    glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, \"glUniform4fv\");\n    glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, \"glUniform4i\");\n    glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, \"glUniform4iv\");\n    glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, \"glUniformMatrix2fv\");\n    glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, \"glUniformMatrix3fv\");\n    glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, \"glUniformMatrix4fv\");\n    glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, \"glUseProgram\");\n    glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, \"glValidateProgram\");\n    glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load(userptr, \"glVertexAttrib1d\");\n    glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load(userptr, \"glVertexAttrib1dv\");\n    glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, \"glVertexAttrib1f\");\n    glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, \"glVertexAttrib1fv\");\n    glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load(userptr, \"glVertexAttrib1s\");\n    glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load(userptr, \"glVertexAttrib1sv\");\n    glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load(userptr, \"glVertexAttrib2d\");\n    glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load(userptr, \"glVertexAttrib2dv\");\n    glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, \"glVertexAttrib2f\");\n    glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, \"glVertexAttrib2fv\");\n    glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load(userptr, \"glVertexAttrib2s\");\n    glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load(userptr, \"glVertexAttrib2sv\");\n    glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load(userptr, \"glVertexAttrib3d\");\n    glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load(userptr, \"glVertexAttrib3dv\");\n    glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, \"glVertexAttrib3f\");\n    glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, \"glVertexAttrib3fv\");\n    glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load(userptr, \"glVertexAttrib3s\");\n    glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load(userptr, \"glVertexAttrib3sv\");\n    glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load(userptr, \"glVertexAttrib4Nbv\");\n    glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load(userptr, \"glVertexAttrib4Niv\");\n    glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load(userptr, \"glVertexAttrib4Nsv\");\n    glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load(userptr, \"glVertexAttrib4Nub\");\n    glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load(userptr, \"glVertexAttrib4Nubv\");\n    glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load(userptr, \"glVertexAttrib4Nuiv\");\n    glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load(userptr, \"glVertexAttrib4Nusv\");\n    glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load(userptr, \"glVertexAttrib4bv\");\n    glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load(userptr, \"glVertexAttrib4d\");\n    glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load(userptr, \"glVertexAttrib4dv\");\n    glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, \"glVertexAttrib4f\");\n    glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, \"glVertexAttrib4fv\");\n    glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load(userptr, \"glVertexAttrib4iv\");\n    glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load(userptr, \"glVertexAttrib4s\");\n    glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load(userptr, \"glVertexAttrib4sv\");\n    glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load(userptr, \"glVertexAttrib4ubv\");\n    glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load(userptr, \"glVertexAttrib4uiv\");\n    glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load(userptr, \"glVertexAttrib4usv\");\n    glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, \"glVertexAttribPointer\");\n}\nstatic void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_2_1) return;\n    glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, \"glUniformMatrix2x3fv\");\n    glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, \"glUniformMatrix2x4fv\");\n    glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, \"glUniformMatrix3x2fv\");\n    glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, \"glUniformMatrix3x4fv\");\n    glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, \"glUniformMatrix4x2fv\");\n    glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, \"glUniformMatrix4x3fv\");\n}\nstatic void glad_gl_load_GL_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_3_0) return;\n    glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) load(userptr, \"glBeginConditionalRender\");\n    glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load(userptr, \"glBeginTransformFeedback\");\n    glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, \"glBindBufferBase\");\n    glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, \"glBindBufferRange\");\n    glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) load(userptr, \"glBindFragDataLocation\");\n    glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, \"glBindFramebuffer\");\n    glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, \"glBindRenderbuffer\");\n    glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, \"glBindVertexArray\");\n    glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, \"glBlitFramebuffer\");\n    glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, \"glCheckFramebufferStatus\");\n    glad_glClampColor = (PFNGLCLAMPCOLORPROC) load(userptr, \"glClampColor\");\n    glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load(userptr, \"glClearBufferfi\");\n    glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load(userptr, \"glClearBufferfv\");\n    glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load(userptr, \"glClearBufferiv\");\n    glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load(userptr, \"glClearBufferuiv\");\n    glad_glColorMaski = (PFNGLCOLORMASKIPROC) load(userptr, \"glColorMaski\");\n    glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, \"glDeleteFramebuffers\");\n    glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, \"glDeleteRenderbuffers\");\n    glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, \"glDeleteVertexArrays\");\n    glad_glDisablei = (PFNGLDISABLEIPROC) load(userptr, \"glDisablei\");\n    glad_glEnablei = (PFNGLENABLEIPROC) load(userptr, \"glEnablei\");\n    glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) load(userptr, \"glEndConditionalRender\");\n    glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load(userptr, \"glEndTransformFeedback\");\n    glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, \"glFlushMappedBufferRange\");\n    glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, \"glFramebufferRenderbuffer\");\n    glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load(userptr, \"glFramebufferTexture1D\");\n    glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, \"glFramebufferTexture2D\");\n    glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load(userptr, \"glFramebufferTexture3D\");\n    glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, \"glFramebufferTextureLayer\");\n    glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, \"glGenFramebuffers\");\n    glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, \"glGenRenderbuffers\");\n    glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, \"glGenVertexArrays\");\n    glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, \"glGenerateMipmap\");\n    glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load(userptr, \"glGetBooleani_v\");\n    glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load(userptr, \"glGetFragDataLocation\");\n    glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, \"glGetFramebufferAttachmentParameteriv\");\n    glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, \"glGetIntegeri_v\");\n    glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, \"glGetRenderbufferParameteriv\");\n    glad_glGetStringi = (PFNGLGETSTRINGIPROC) load(userptr, \"glGetStringi\");\n    glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load(userptr, \"glGetTexParameterIiv\");\n    glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load(userptr, \"glGetTexParameterIuiv\");\n    glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load(userptr, \"glGetTransformFeedbackVarying\");\n    glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load(userptr, \"glGetUniformuiv\");\n    glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load(userptr, \"glGetVertexAttribIiv\");\n    glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load(userptr, \"glGetVertexAttribIuiv\");\n    glad_glIsEnabledi = (PFNGLISENABLEDIPROC) load(userptr, \"glIsEnabledi\");\n    glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, \"glIsFramebuffer\");\n    glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, \"glIsRenderbuffer\");\n    glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, \"glIsVertexArray\");\n    glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, \"glMapBufferRange\");\n    glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, \"glRenderbufferStorage\");\n    glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, \"glRenderbufferStorageMultisample\");\n    glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load(userptr, \"glTexParameterIiv\");\n    glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load(userptr, \"glTexParameterIuiv\");\n    glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load(userptr, \"glTransformFeedbackVaryings\");\n    glad_glUniform1ui = (PFNGLUNIFORM1UIPROC) load(userptr, \"glUniform1ui\");\n    glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load(userptr, \"glUniform1uiv\");\n    glad_glUniform2ui = (PFNGLUNIFORM2UIPROC) load(userptr, \"glUniform2ui\");\n    glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load(userptr, \"glUniform2uiv\");\n    glad_glUniform3ui = (PFNGLUNIFORM3UIPROC) load(userptr, \"glUniform3ui\");\n    glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load(userptr, \"glUniform3uiv\");\n    glad_glUniform4ui = (PFNGLUNIFORM4UIPROC) load(userptr, \"glUniform4ui\");\n    glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load(userptr, \"glUniform4uiv\");\n    glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) load(userptr, \"glVertexAttribI1i\");\n    glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) load(userptr, \"glVertexAttribI1iv\");\n    glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) load(userptr, \"glVertexAttribI1ui\");\n    glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) load(userptr, \"glVertexAttribI1uiv\");\n    glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) load(userptr, \"glVertexAttribI2i\");\n    glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) load(userptr, \"glVertexAttribI2iv\");\n    glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) load(userptr, \"glVertexAttribI2ui\");\n    glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) load(userptr, \"glVertexAttribI2uiv\");\n    glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) load(userptr, \"glVertexAttribI3i\");\n    glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) load(userptr, \"glVertexAttribI3iv\");\n    glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) load(userptr, \"glVertexAttribI3ui\");\n    glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) load(userptr, \"glVertexAttribI3uiv\");\n    glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) load(userptr, \"glVertexAttribI4bv\");\n    glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load(userptr, \"glVertexAttribI4i\");\n    glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load(userptr, \"glVertexAttribI4iv\");\n    glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) load(userptr, \"glVertexAttribI4sv\");\n    glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) load(userptr, \"glVertexAttribI4ubv\");\n    glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load(userptr, \"glVertexAttribI4ui\");\n    glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load(userptr, \"glVertexAttribI4uiv\");\n    glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) load(userptr, \"glVertexAttribI4usv\");\n    glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load(userptr, \"glVertexAttribIPointer\");\n}\nstatic void glad_gl_load_GL_VERSION_3_1( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_3_1) return;\n    glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, \"glBindBufferBase\");\n    glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, \"glBindBufferRange\");\n    glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load(userptr, \"glCopyBufferSubData\");\n    glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load(userptr, \"glDrawArraysInstanced\");\n    glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load(userptr, \"glDrawElementsInstanced\");\n    glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load(userptr, \"glGetActiveUniformBlockName\");\n    glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load(userptr, \"glGetActiveUniformBlockiv\");\n    glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) load(userptr, \"glGetActiveUniformName\");\n    glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load(userptr, \"glGetActiveUniformsiv\");\n    glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, \"glGetIntegeri_v\");\n    glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load(userptr, \"glGetUniformBlockIndex\");\n    glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load(userptr, \"glGetUniformIndices\");\n    glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) load(userptr, \"glPrimitiveRestartIndex\");\n    glad_glTexBuffer = (PFNGLTEXBUFFERPROC) load(userptr, \"glTexBuffer\");\n    glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load(userptr, \"glUniformBlockBinding\");\n}\nstatic void glad_gl_load_GL_VERSION_3_2( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_3_2) return;\n    glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load(userptr, \"glClientWaitSync\");\n    glad_glDeleteSync = (PFNGLDELETESYNCPROC) load(userptr, \"glDeleteSync\");\n    glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load(userptr, \"glDrawElementsBaseVertex\");\n    glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load(userptr, \"glDrawElementsInstancedBaseVertex\");\n    glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load(userptr, \"glDrawRangeElementsBaseVertex\");\n    glad_glFenceSync = (PFNGLFENCESYNCPROC) load(userptr, \"glFenceSync\");\n    glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) load(userptr, \"glFramebufferTexture\");\n    glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load(userptr, \"glGetBufferParameteri64v\");\n    glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load(userptr, \"glGetInteger64i_v\");\n    glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC) load(userptr, \"glGetInteger64v\");\n    glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load(userptr, \"glGetMultisamplefv\");\n    glad_glGetSynciv = (PFNGLGETSYNCIVPROC) load(userptr, \"glGetSynciv\");\n    glad_glIsSync = (PFNGLISSYNCPROC) load(userptr, \"glIsSync\");\n    glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) load(userptr, \"glMultiDrawElementsBaseVertex\");\n    glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC) load(userptr, \"glProvokingVertex\");\n    glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC) load(userptr, \"glSampleMaski\");\n    glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load(userptr, \"glTexImage2DMultisample\");\n    glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load(userptr, \"glTexImage3DMultisample\");\n    glad_glWaitSync = (PFNGLWAITSYNCPROC) load(userptr, \"glWaitSync\");\n}\nstatic void glad_gl_load_GL_VERSION_3_3( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_3_3) return;\n    glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) load(userptr, \"glBindFragDataLocationIndexed\");\n    glad_glBindSampler = (PFNGLBINDSAMPLERPROC) load(userptr, \"glBindSampler\");\n    glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load(userptr, \"glDeleteSamplers\");\n    glad_glGenSamplers = (PFNGLGENSAMPLERSPROC) load(userptr, \"glGenSamplers\");\n    glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) load(userptr, \"glGetFragDataIndex\");\n    glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load(userptr, \"glGetQueryObjecti64v\");\n    glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load(userptr, \"glGetQueryObjectui64v\");\n    glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) load(userptr, \"glGetSamplerParameterIiv\");\n    glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) load(userptr, \"glGetSamplerParameterIuiv\");\n    glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load(userptr, \"glGetSamplerParameterfv\");\n    glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load(userptr, \"glGetSamplerParameteriv\");\n    glad_glIsSampler = (PFNGLISSAMPLERPROC) load(userptr, \"glIsSampler\");\n    glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC) load(userptr, \"glQueryCounter\");\n    glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) load(userptr, \"glSamplerParameterIiv\");\n    glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) load(userptr, \"glSamplerParameterIuiv\");\n    glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load(userptr, \"glSamplerParameterf\");\n    glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load(userptr, \"glSamplerParameterfv\");\n    glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load(userptr, \"glSamplerParameteri\");\n    glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load(userptr, \"glSamplerParameteriv\");\n    glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load(userptr, \"glVertexAttribDivisor\");\n    glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC) load(userptr, \"glVertexAttribP1ui\");\n    glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC) load(userptr, \"glVertexAttribP1uiv\");\n    glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC) load(userptr, \"glVertexAttribP2ui\");\n    glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC) load(userptr, \"glVertexAttribP2uiv\");\n    glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC) load(userptr, \"glVertexAttribP3ui\");\n    glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC) load(userptr, \"glVertexAttribP3uiv\");\n    glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC) load(userptr, \"glVertexAttribP4ui\");\n    glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC) load(userptr, \"glVertexAttribP4uiv\");\n}\nstatic void glad_gl_load_GL_VERSION_4_0( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_4_0) return;\n    glad_glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC) load(userptr, \"glBeginQueryIndexed\");\n    glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC) load(userptr, \"glBindTransformFeedback\");\n    glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC) load(userptr, \"glBlendEquationSeparatei\");\n    glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC) load(userptr, \"glBlendEquationi\");\n    glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC) load(userptr, \"glBlendFuncSeparatei\");\n    glad_glBlendFunci = (PFNGLBLENDFUNCIPROC) load(userptr, \"glBlendFunci\");\n    glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC) load(userptr, \"glDeleteTransformFeedbacks\");\n    glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC) load(userptr, \"glDrawArraysIndirect\");\n    glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC) load(userptr, \"glDrawElementsIndirect\");\n    glad_glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC) load(userptr, \"glDrawTransformFeedback\");\n    glad_glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) load(userptr, \"glDrawTransformFeedbackStream\");\n    glad_glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC) load(userptr, \"glEndQueryIndexed\");\n    glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC) load(userptr, \"glGenTransformFeedbacks\");\n    glad_glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC) load(userptr, \"glGetActiveSubroutineName\");\n    glad_glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) load(userptr, \"glGetActiveSubroutineUniformName\");\n    glad_glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) load(userptr, \"glGetActiveSubroutineUniformiv\");\n    glad_glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC) load(userptr, \"glGetProgramStageiv\");\n    glad_glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC) load(userptr, \"glGetQueryIndexediv\");\n    glad_glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC) load(userptr, \"glGetSubroutineIndex\");\n    glad_glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) load(userptr, \"glGetSubroutineUniformLocation\");\n    glad_glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC) load(userptr, \"glGetUniformSubroutineuiv\");\n    glad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC) load(userptr, \"glGetUniformdv\");\n    glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC) load(userptr, \"glIsTransformFeedback\");\n    glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC) load(userptr, \"glMinSampleShading\");\n    glad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC) load(userptr, \"glPatchParameterfv\");\n    glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC) load(userptr, \"glPatchParameteri\");\n    glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC) load(userptr, \"glPauseTransformFeedback\");\n    glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC) load(userptr, \"glResumeTransformFeedback\");\n    glad_glUniform1d = (PFNGLUNIFORM1DPROC) load(userptr, \"glUniform1d\");\n    glad_glUniform1dv = (PFNGLUNIFORM1DVPROC) load(userptr, \"glUniform1dv\");\n    glad_glUniform2d = (PFNGLUNIFORM2DPROC) load(userptr, \"glUniform2d\");\n    glad_glUniform2dv = (PFNGLUNIFORM2DVPROC) load(userptr, \"glUniform2dv\");\n    glad_glUniform3d = (PFNGLUNIFORM3DPROC) load(userptr, \"glUniform3d\");\n    glad_glUniform3dv = (PFNGLUNIFORM3DVPROC) load(userptr, \"glUniform3dv\");\n    glad_glUniform4d = (PFNGLUNIFORM4DPROC) load(userptr, \"glUniform4d\");\n    glad_glUniform4dv = (PFNGLUNIFORM4DVPROC) load(userptr, \"glUniform4dv\");\n    glad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC) load(userptr, \"glUniformMatrix2dv\");\n    glad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC) load(userptr, \"glUniformMatrix2x3dv\");\n    glad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC) load(userptr, \"glUniformMatrix2x4dv\");\n    glad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC) load(userptr, \"glUniformMatrix3dv\");\n    glad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC) load(userptr, \"glUniformMatrix3x2dv\");\n    glad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC) load(userptr, \"glUniformMatrix3x4dv\");\n    glad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC) load(userptr, \"glUniformMatrix4dv\");\n    glad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC) load(userptr, \"glUniformMatrix4x2dv\");\n    glad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC) load(userptr, \"glUniformMatrix4x3dv\");\n    glad_glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC) load(userptr, \"glUniformSubroutinesuiv\");\n}\nstatic void glad_gl_load_GL_VERSION_4_1( GLADuserptrloadfunc load, void* userptr) {\n    if(!GLAD_GL_VERSION_4_1) return;\n    glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC) load(userptr, \"glActiveShaderProgram\");\n    glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC) load(userptr, \"glBindProgramPipeline\");\n    glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, \"glClearDepthf\");\n    glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC) load(userptr, \"glCreateShaderProgramv\");\n    glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC) load(userptr, \"glDeleteProgramPipelines\");\n    glad_glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC) load(userptr, \"glDepthRangeArrayv\");\n    glad_glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC) load(userptr, \"glDepthRangeIndexed\");\n    glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, \"glDepthRangef\");\n    glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC) load(userptr, \"glGenProgramPipelines\");\n    glad_glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC) load(userptr, \"glGetDoublei_v\");\n    glad_glGetFloati_v = (PFNGLGETFLOATI_VPROC) load(userptr, \"glGetFloati_v\");\n    glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) load(userptr, \"glGetProgramBinary\");\n    glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC) load(userptr, \"glGetProgramPipelineInfoLog\");\n    glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC) load(userptr, \"glGetProgramPipelineiv\");\n    glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, \"glGetShaderPrecisionFormat\");\n    glad_glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC) load(userptr, \"glGetVertexAttribLdv\");\n    glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC) load(userptr, \"glIsProgramPipeline\");\n    glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC) load(userptr, \"glProgramBinary\");\n    glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) load(userptr, \"glProgramParameteri\");\n    glad_glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC) load(userptr, \"glProgramUniform1d\");\n    glad_glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC) load(userptr, \"glProgramUniform1dv\");\n    glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC) load(userptr, \"glProgramUniform1f\");\n    glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC) load(userptr, \"glProgramUniform1fv\");\n    glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC) load(userptr, \"glProgramUniform1i\");\n    glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC) load(userptr, \"glProgramUniform1iv\");\n    glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC) load(userptr, \"glProgramUniform1ui\");\n    glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC) load(userptr, \"glProgramUniform1uiv\");\n    glad_glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC) load(userptr, \"glProgramUniform2d\");\n    glad_glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC) load(userptr, \"glProgramUniform2dv\");\n    glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC) load(userptr, \"glProgramUniform2f\");\n    glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC) load(userptr, \"glProgramUniform2fv\");\n    glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC) load(userptr, \"glProgramUniform2i\");\n    glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC) load(userptr, \"glProgramUniform2iv\");\n    glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC) load(userptr, \"glProgramUniform2ui\");\n    glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC) load(userptr, \"glProgramUniform2uiv\");\n    glad_glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC) load(userptr, \"glProgramUniform3d\");\n    glad_glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC) load(userptr, \"glProgramUniform3dv\");\n    glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC) load(userptr, \"glProgramUniform3f\");\n    glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC) load(userptr, \"glProgramUniform3fv\");\n    glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC) load(userptr, \"glProgramUniform3i\");\n    glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC) load(userptr, \"glProgramUniform3iv\");\n    glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC) load(userptr, \"glProgramUniform3ui\");\n    glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC) load(userptr, \"glProgramUniform3uiv\");\n    glad_glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC) load(userptr, \"glProgramUniform4d\");\n    glad_glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC) load(userptr, \"glProgramUniform4dv\");\n    glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC) load(userptr, \"glProgramUniform4f\");\n    glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC) load(userptr, \"glProgramUniform4fv\");\n    glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC) load(userptr, \"glProgramUniform4i\");\n    glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC) load(userptr, \"glProgramUniform4iv\");\n    glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC) load(userptr, \"glProgramUniform4ui\");\n    glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC) load(userptr, \"glProgramUniform4uiv\");\n    glad_glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC) load(userptr, \"glProgramUniformMatrix2dv\");\n    glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC) load(userptr, \"glProgramUniformMatrix2fv\");\n    glad_glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) load(userptr, \"glProgramUniformMatrix2x3dv\");\n    glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) load(userptr, \"glProgramUniformMatrix2x3fv\");\n    glad_glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) load(userptr, \"glProgramUniformMatrix2x4dv\");\n    glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) load(userptr, \"glProgramUniformMatrix2x4fv\");\n    glad_glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC) load(userptr, \"glProgramUniformMatrix3dv\");\n    glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC) load(userptr, \"glProgramUniformMatrix3fv\");\n    glad_glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) load(userptr, \"glProgramUniformMatrix3x2dv\");\n    glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) load(userptr, \"glProgramUniformMatrix3x2fv\");\n    glad_glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) load(userptr, \"glProgramUniformMatrix3x4dv\");\n    glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) load(userptr, \"glProgramUniformMatrix3x4fv\");\n    glad_glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC) load(userptr, \"glProgramUniformMatrix4dv\");\n    glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC) load(userptr, \"glProgramUniformMatrix4fv\");\n    glad_glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) load(userptr, \"glProgramUniformMatrix4x2dv\");\n    glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) load(userptr, \"glProgramUniformMatrix4x2fv\");\n    glad_glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) load(userptr, \"glProgramUniformMatrix4x3dv\");\n    glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) load(userptr, \"glProgramUniformMatrix4x3fv\");\n    glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, \"glReleaseShaderCompiler\");\n    glad_glScissorArrayv = (PFNGLSCISSORARRAYVPROC) load(userptr, \"glScissorArrayv\");\n    glad_glScissorIndexed = (PFNGLSCISSORINDEXEDPROC) load(userptr, \"glScissorIndexed\");\n    glad_glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC) load(userptr, \"glScissorIndexedv\");\n    glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, \"glShaderBinary\");\n    glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC) load(userptr, \"glUseProgramStages\");\n    glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC) load(userptr, \"glValidateProgramPipeline\");\n    glad_glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC) load(userptr, \"glVertexAttribL1d\");\n    glad_glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC) load(userptr, \"glVertexAttribL1dv\");\n    glad_glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC) load(userptr, \"glVertexAttribL2d\");\n    glad_glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC) load(userptr, \"glVertexAttribL2dv\");\n    glad_glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC) load(userptr, \"glVertexAttribL3d\");\n    glad_glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC) load(userptr, \"glVertexAttribL3dv\");\n    glad_glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC) load(userptr, \"glVertexAttribL4d\");\n    glad_glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC) load(userptr, \"glVertexAttribL4dv\");\n    glad_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC) load(userptr, \"glVertexAttribLPointer\");\n    glad_glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC) load(userptr, \"glViewportArrayv\");\n    glad_glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC) load(userptr, \"glViewportIndexedf\");\n    glad_glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC) load(userptr, \"glViewportIndexedfv\");\n}\n\n\n\n#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)\n#define GLAD_GL_IS_SOME_NEW_VERSION 1\n#else\n#define GLAD_GL_IS_SOME_NEW_VERSION 0\n#endif\n\nstatic int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) {\n#if GLAD_GL_IS_SOME_NEW_VERSION\n    if(GLAD_VERSION_MAJOR(version) < 3) {\n#else\n    (void) version;\n    (void) out_num_exts_i;\n    (void) out_exts_i;\n#endif\n        if (glad_glGetString == NULL) {\n            return 0;\n        }\n        *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS);\n#if GLAD_GL_IS_SOME_NEW_VERSION\n    } else {\n        unsigned int index = 0;\n        unsigned int num_exts_i = 0;\n        char **exts_i = NULL;\n        if (glad_glGetStringi == NULL || glad_glGetIntegerv == NULL) {\n            return 0;\n        }\n        glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i);\n        if (num_exts_i > 0) {\n            exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i));\n        }\n        if (exts_i == NULL) {\n            return 0;\n        }\n        for(index = 0; index < num_exts_i; index++) {\n            const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index);\n            size_t len = strlen(gl_str_tmp) + 1;\n\n            char *local_str = (char*) malloc(len * sizeof(char));\n            if(local_str != NULL) {\n                memcpy(local_str, gl_str_tmp, len * sizeof(char));\n            }\n\n            exts_i[index] = local_str;\n        }\n\n        *out_num_exts_i = num_exts_i;\n        *out_exts_i = exts_i;\n    }\n#endif\n    return 1;\n}\nstatic void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) {\n    if (exts_i != NULL) {\n        unsigned int index;\n        for(index = 0; index < num_exts_i; index++) {\n            free((void *) (exts_i[index]));\n        }\n        free((void *)exts_i);\n        exts_i = NULL;\n    }\n}\nstatic int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) {\n    if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) {\n        const char *extensions;\n        const char *loc;\n        const char *terminator;\n        extensions = exts;\n        if(extensions == NULL || ext == NULL) {\n            return 0;\n        }\n        while(1) {\n            loc = strstr(extensions, ext);\n            if(loc == NULL) {\n                return 0;\n            }\n            terminator = loc + strlen(ext);\n            if((loc == extensions || *(loc - 1) == ' ') &&\n                (*terminator == ' ' || *terminator == '\\0')) {\n                return 1;\n            }\n            extensions = terminator;\n        }\n    } else {\n        unsigned int index;\n        for(index = 0; index < num_exts_i; index++) {\n            const char *e = exts_i[index];\n            if(strcmp(e, ext) == 0) {\n                return 1;\n            }\n        }\n    }\n    return 0;\n}\n\nstatic GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) {\n    return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);\n}\n\nstatic int glad_gl_find_extensions_gl( int version) {\n    const char *exts = NULL;\n    unsigned int num_exts_i = 0;\n    char **exts_i = NULL;\n    if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0;\n\n    (void) glad_gl_has_extension;\n\n    glad_gl_free_extensions(exts_i, num_exts_i);\n\n    return 1;\n}\n\nstatic int glad_gl_find_core_gl(void) {\n    int i;\n    const char* version;\n    const char* prefixes[] = {\n        \"OpenGL ES-CM \",\n        \"OpenGL ES-CL \",\n        \"OpenGL ES \",\n        \"OpenGL SC \",\n        NULL\n    };\n    int major = 0;\n    int minor = 0;\n    version = (const char*) glad_glGetString(GL_VERSION);\n    if (!version) return 0;\n    for (i = 0;  prefixes[i];  i++) {\n        const size_t length = strlen(prefixes[i]);\n        if (strncmp(version, prefixes[i], length) == 0) {\n            version += length;\n            break;\n        }\n    }\n\n    GLAD_IMPL_UTIL_SSCANF(version, \"%d.%d\", &major, &minor);\n\n    GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;\n    GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;\n    GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;\n    GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;\n    GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;\n    GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;\n    GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;\n    GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2;\n    GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;\n    GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;\n    GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;\n    GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;\n    GLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4;\n    GLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4;\n\n    return GLAD_MAKE_VERSION(major, minor);\n}\n\nint gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) {\n    int version;\n\n    glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, \"glGetString\");\n    if(glad_glGetString == NULL) return 0;\n    if(glad_glGetString(GL_VERSION) == NULL) return 0;\n    version = glad_gl_find_core_gl();\n\n    glad_gl_load_GL_VERSION_1_0(load, userptr);\n    glad_gl_load_GL_VERSION_1_1(load, userptr);\n    glad_gl_load_GL_VERSION_1_2(load, userptr);\n    glad_gl_load_GL_VERSION_1_3(load, userptr);\n    glad_gl_load_GL_VERSION_1_4(load, userptr);\n    glad_gl_load_GL_VERSION_1_5(load, userptr);\n    glad_gl_load_GL_VERSION_2_0(load, userptr);\n    glad_gl_load_GL_VERSION_2_1(load, userptr);\n    glad_gl_load_GL_VERSION_3_0(load, userptr);\n    glad_gl_load_GL_VERSION_3_1(load, userptr);\n    glad_gl_load_GL_VERSION_3_2(load, userptr);\n    glad_gl_load_GL_VERSION_3_3(load, userptr);\n    glad_gl_load_GL_VERSION_4_0(load, userptr);\n    glad_gl_load_GL_VERSION_4_1(load, userptr);\n\n    if (!glad_gl_find_extensions_gl(version)) return 0;\n\n\n\n    return version;\n}\n\n\nint gladLoadGL( GLADloadfunc load) {\n    return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);\n}\n\n\n\n \n\n#ifdef GLAD_GL\n\n#ifndef GLAD_LOADER_LIBRARY_C_\n#define GLAD_LOADER_LIBRARY_C_\n\n#include <stddef.h>\n#include <stdlib.h>\n\n#if GLAD_PLATFORM_WIN32\n#include <windows.h>\n#else\n#include <dlfcn.h>\n#endif\n\n\nstatic void* glad_get_dlopen_handle(const char *lib_names[], int length) {\n    void *handle = NULL;\n    int i;\n\n    for (i = 0; i < length; ++i) {\n#if GLAD_PLATFORM_WIN32\n  #if GLAD_PLATFORM_UWP\n        size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR);\n        LPWSTR buffer = (LPWSTR) malloc(buffer_size);\n        if (buffer != NULL) {\n            int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size);\n            if (ret != 0) {\n                handle = (void*) LoadPackagedLibrary(buffer, 0);\n            }\n            free((void*) buffer);\n        }\n  #else\n        handle = (void*) LoadLibraryA(lib_names[i]);\n  #endif\n#else\n        handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL);\n#endif\n        if (handle != NULL) {\n            return handle;\n        }\n    }\n\n    return NULL;\n}\n\nstatic void glad_close_dlopen_handle(void* handle) {\n    if (handle != NULL) {\n#if GLAD_PLATFORM_WIN32\n        FreeLibrary((HMODULE) handle);\n#else\n        dlclose(handle);\n#endif\n    }\n}\n\nstatic GLADapiproc glad_dlsym_handle(void* handle, const char *name) {\n    if (handle == NULL) {\n        return NULL;\n    }\n\n#if GLAD_PLATFORM_WIN32\n    return (GLADapiproc) GetProcAddress((HMODULE) handle, name);\n#else\n    return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name);\n#endif\n}\n\n#endif /* GLAD_LOADER_LIBRARY_C_ */\n\ntypedef void* (GLAD_API_PTR *GLADglprocaddrfunc)(const char*);\nstruct _glad_gl_userptr {\n    void *handle;\n    GLADglprocaddrfunc gl_get_proc_address_ptr;\n};\n\nstatic GLADapiproc glad_gl_get_proc(void *vuserptr, const char *name) {\n    struct _glad_gl_userptr userptr = *(struct _glad_gl_userptr*) vuserptr;\n    GLADapiproc result = NULL;\n\n    if(userptr.gl_get_proc_address_ptr != NULL) {\n        result = GLAD_GNUC_EXTENSION (GLADapiproc) userptr.gl_get_proc_address_ptr(name);\n    }\n    if(result == NULL) {\n        result = glad_dlsym_handle(userptr.handle, name);\n    }\n\n    return result;\n}\n\nstatic void* _gl_handle = NULL;\n\nstatic void* glad_gl_dlopen_handle(void) {\n#if GLAD_PLATFORM_APPLE\n    static const char *NAMES[] = {\n        \"../Frameworks/OpenGL.framework/OpenGL\",\n        \"/Library/Frameworks/OpenGL.framework/OpenGL\",\n        \"/System/Library/Frameworks/OpenGL.framework/OpenGL\",\n        \"/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL\"\n    };\n#elif GLAD_PLATFORM_WIN32\n    static const char *NAMES[] = {\"opengl32.dll\"};\n#else\n    static const char *NAMES[] = {\n  #if defined(__CYGWIN__)\n        \"libGL-1.so\",\n  #endif\n        \"libGL.so.1\",\n        \"libGL.so\"\n    };\n#endif\n\n    if (_gl_handle == NULL) {\n        _gl_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));\n    }\n\n    return _gl_handle;\n}\n\nstatic struct _glad_gl_userptr glad_gl_build_userptr(void *handle) {\n    struct _glad_gl_userptr userptr;\n\n    userptr.handle = handle;\n#if GLAD_PLATFORM_APPLE || defined(__HAIKU__)\n    userptr.gl_get_proc_address_ptr = NULL;\n#elif GLAD_PLATFORM_WIN32\n    userptr.gl_get_proc_address_ptr =\n        (GLADglprocaddrfunc) glad_dlsym_handle(handle, \"wglGetProcAddress\");\n#else\n    userptr.gl_get_proc_address_ptr =\n        (GLADglprocaddrfunc) glad_dlsym_handle(handle, \"glXGetProcAddressARB\");\n#endif\n\n    return userptr;\n}\n\nint gladLoaderLoadGL(void) {\n    int version = 0;\n    void *handle;\n    int did_load = 0;\n    struct _glad_gl_userptr userptr;\n\n    did_load = _gl_handle == NULL;\n    handle = glad_gl_dlopen_handle();\n    if (handle) {\n        userptr = glad_gl_build_userptr(handle);\n\n        version = gladLoadGLUserPtr(glad_gl_get_proc, &userptr);\n\n        if (did_load) {\n            gladLoaderUnloadGL();\n        }\n    }\n\n    return version;\n}\n\n\n\nvoid gladLoaderUnloadGL(void) {\n    if (_gl_handle != NULL) {\n        glad_close_dlopen_handle(_gl_handle);\n        _gl_handle = NULL;\n    }\n}\n\n#endif /* GLAD_GL */\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLAD.h",
    "content": "#pragma once\n\n// Differentiate between gl and glad requirements\n\n#include <glad/gl.h>\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLContext.h",
    "content": "#pragma once\n\n#include <vapor/GLContextProviderCommon.h>\n\n//! \\class GLContext\n//! \\ingroup HeadlessGL\n//! \\brief Object that abstracts an OpenGL context since they are differnet in every case.\n//! \\author Stas Jaroszynski\n\nclass OSGL_API GLContext {\npublic:\n    virtual ~GLContext() {}\n    virtual void MakeCurrent() = 0;\n    String       GetVersion();\n};\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLContextProvider.h",
    "content": "#pragma once\n\n#include <vapor/GLContext.h>\n\n//! \\class GLContextProvider\n//! \\ingroup HeadlessGL\n//! \\brief Interface for creating an OpenGL context.\n//! \\author Stas Jaroszynski\n\nclass OSGL_API GLContextProvider {\npublic:\n    //! Creates an OpenGL context. The returned pointer is optional for managing\n    //! multiple contexts.\n    static GLContext *CreateContext();\n    static bool       IsCurrentOpenGLVersionSupported();\n\nprivate:\n    static bool isContextOk(GLContext *ctx);\n};\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLContextProviderCommon.h",
    "content": "#pragma once\n\n#include <vapor/common.h>\n#include <cassert>\n#include <string>\n#include <vector>\n\ntypedef std::string String;\nusing std::vector;\n\n#undef MacOS\n#undef Linux\n#undef Windows\n#if __APPLE__\n    #define MacOS 1\n#elif __linux__\n    #define Linux 1\n#elif WIN32\n    #define Windows 1\n#endif\n\n#include \"Log.h\"\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLContextProviderEGL.h",
    "content": "#pragma once\n#include <vapor/GLContext.h>\n\n//! \\class GLContextProviderEGL\n//! \\ingroup HeadlessGL\n//! \\brief Creates an OpenGL context using the EGL library.\n//! \\author Stas Jaroszynski\n\nclass OSGL_API GLContextProviderEGL {\n    class GLContextEGL : public GLContext {\n        void *_display = nullptr;\n        void *_surface = nullptr;\n        void *_context = nullptr;\n\n    public:\n        GLContextEGL(void *display, void *surface, void *context);\n        virtual ~GLContextEGL() override;\n        virtual void MakeCurrent() override;\n    };\n\npublic:\n    static GLContext *CreateContext();\n\nprotected:\n    static GLContext * createContextForDisplay(void *display);\n    static const char *stringifyEGLError(int e);\n};\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLContextProviderMacOS.h",
    "content": "#pragma once\n\n#include <vapor/GLContext.h>\n\n//! \\class GLContextProviderMacOS\n//! \\ingroup HeadlessGL\n//! \\brief Creates an OpenGL context using macOS's libraries.\n//! \\author Stas Jaroszynski\n\nclass OSGL_API GLContextProviderMacOS {\n    class GLContextMacOS : public GLContext {\n        void *_ctx = nullptr;\n\n    public:\n        GLContextMacOS(void *ctx);\n        virtual ~GLContextMacOS() override;\n        virtual void MakeCurrent() override;\n\n        friend class GLContextProviderMacOS;\n    };\n\npublic:\n    static GLContext *CreateContext();\n};\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLContextProviderMesa.h",
    "content": "#pragma once\n#include <vapor/GLContext.h>\n\n//! \\class GLContextProviderMesa\n//! \\ingroup HeadlessGL\n//! \\brief Uses OSMesa for headless OpenGL Context creation.\n//! \\author Stas Jaroszynski\n\nclass OSGL_API GLContextProviderMesa {\n    class GLContextMesa : public GLContext {\n        void *_ctx = nullptr;\n        char  _dummyBuffer[4 * 4 * 3];\n\n    public:\n        GLContextMesa(void *ctx);\n        virtual ~GLContextMesa() override;\n        virtual void MakeCurrent() override;\n        void DumpParameters() const;\n    };\n\npublic:\n    static GLContext *CreateContext();\n};\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLContextProviderNvidia.h",
    "content": "#pragma once\n\n#include <vapor/GLContextProviderEGL.h>\n\n//! \\class GLContextProviderNvidia\n//! \\ingroup HeadlessGL\n//! \\brief Implements nvidia's API for headless OpenGL Context creation.\n//! \\author Stas Jaroszynski\n\nclass OSGL_API GLContextProviderNvidia : private GLContextProviderEGL {\npublic:\n    static GLContext *CreateContext();\n};\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLContextProviderUtil.h",
    "content": "#pragma once\n\n#include <vapor/GLContextProviderCommon.h>\n\nclass OSGL_API GLContextProviderUtil {\npublic:\n    static String GetGLVersion();\n    static void   GetGLVersion(int *major, int *minor);\n};\n"
  },
  {
    "path": "lib/osgl/include/vapor/GLInclude.h",
    "content": "#pragma once\n\n//#ifdef __APPLE__\n//    #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED\n//    #include <OpenGL/gl3.h>\n//#else\n//    #include <GL/gl.h>\n//#endif\n\n#include \"glad/gl.h\"\n"
  },
  {
    "path": "lib/osgl/include/vapor/Log.h",
    "content": "#pragma once\n\n#include <vapor/GLContextProviderCommon.h>\n\nclass OSGL_API Log {\n    template<typename... Args> static void print(String fmt, Args... args)\n    {\n        fmt += \"\\n\";\n        printc(fmt.c_str(), args...);\n    }\n\n    static void printc(const char *format, ...);\n    static void fatal();\n\npublic:\n    static bool InfoLevelEnabled;\n    \n    static String AddLocationToFormat(const String &fmt, const char *file, int line);\n\n    template<typename... Args> static void Fatal(const String &fmt, Args... args)\n    {\n        print(fmt, args...);\n        fatal();\n    }\n\n    template<typename... Args> static void Message(const String &fmt, Args... args) { print(fmt, args...); }\n\n    template<typename... Args> static void Info(const String &fmt, Args... args)\n    {\n        if (InfoLevelEnabled)\n            print(fmt, args...);\n    }\n\n    template<typename... Args> static void Warning(const String &fmt, Args... args) { print(fmt, args...); }\n};\n\n#define _Log(type, fmt, ...) Log::type(Log::AddLocationToFormat(fmt, __FILE__, __LINE__), ##__VA_ARGS__)\n#define LogFatal(fmt, ...)   _Log(Fatal, fmt, ##__VA_ARGS__)\n#define LogMessage(fmt, ...) _Log(Message, fmt, ##__VA_ARGS__)\n#define LogInfo(fmt, ...)    _Log(Info, fmt, ##__VA_ARGS__)\n#define LogWarning(fmt, ...) _Log(Warning, fmt, ##__VA_ARGS__)\n"
  },
  {
    "path": "lib/osgl/meta.yaml",
    "content": "package:\n  name: osgl\n  version: \"0.01\"\n\nsource:\n  path: /osgl\n\n#build:\n#  script: |\n#    echo build =======================================================================================\n#    echo build =======================================================================================\n#    echo build =======================================================================================\n#    echo build =======================================================================================\n#    echo SRC_DIR=${SRC_DIR}\n#    echo PREFIX=${PREFIX}\n#    cd ${SRC_DIR}\n#    pwd\n#    echo build =======================================================================================\n#    echo build =======================================================================================\n#    echo build =======================================================================================\n#    echo build =======================================================================================\n\nbuild:\n  skip_compile_pyc:\n    - \"*.py\"\n\nrequirements:\n  build:\n    - make\n    - cmake=3.21.3\n    - cppyy=2.2.0\n      # missing from vapor website\n    - glm\n      # This does not provide opengl apparently\n    - mesalib\n    - libglu\n    - {{ cdt('mesa-libgl-devel') }}  # [linux]\n    - {{ cdt('mesa-libgl') }}  # [linux]\n    - {{ cdt('mesa-libegl-devel') }}  # [linux]\n      # - mesa-libegl-devel-cos6-x86_64\n      # - {{ cdt('mesa-dri-drivers') }}  # [linux]\n      # - {{ cdt('libselinux') }}  # [linux]\n      # - {{ cdt('libxdamage') }}  # [linux]\n      # - {{ cdt('libxxf86vm') }}  # [linux]\n      # - {{ cdt('libxext') }}     # [linux]\n  run:\n    - mesalib\n"
  },
  {
    "path": "lib/osgl/stb_image_write.h",
    "content": "/* stb_image_write - v1.16 - public domain - http://nothings.org/stb\n   writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015\n                                     no warranty implied; use at your own risk\n\n   Before #including,\n\n       #define STB_IMAGE_WRITE_IMPLEMENTATION\n\n   in the file that you want to have the implementation.\n\n   Will probably not work correctly with strict-aliasing optimizations.\n\nABOUT:\n\n   This header file is a library for writing images to C stdio or a callback.\n\n   The PNG output is not optimal; it is 20-50% larger than the file\n   written by a decent optimizing implementation; though providing a custom\n   zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.\n   This library is designed for source code compactness and simplicity,\n   not optimal image file size or run-time performance.\n\nBUILDING:\n\n   You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.\n   You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace\n   malloc,realloc,free.\n   You can #define STBIW_MEMMOVE() to replace memmove()\n   You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function\n   for PNG compression (instead of the builtin one), it must have the following signature:\n   unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);\n   The returned data will be freed with STBIW_FREE() (free() by default),\n   so it must be heap allocated with STBIW_MALLOC() (malloc() by default),\n\nUNICODE:\n\n   If compiling for Windows and you wish to use Unicode filenames, compile\n   with\n       #define STBIW_WINDOWS_UTF8\n   and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert\n   Windows wchar_t filenames to utf8.\n\nUSAGE:\n\n   There are five functions, one for each image file format:\n\n     int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);\n     int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);\n     int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);\n     int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);\n     int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);\n\n     void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically\n\n   There are also five equivalent functions that use an arbitrary write function. You are\n   expected to open/close your file-equivalent before and after calling these:\n\n     int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);\n     int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n     int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n     int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);\n     int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);\n\n   where the callback is:\n      void stbi_write_func(void *context, void *data, int size);\n\n   You can configure it with these global variables:\n      int stbi_write_tga_with_rle;             // defaults to true; set to 0 to disable RLE\n      int stbi_write_png_compression_level;    // defaults to 8; set to higher for more compression\n      int stbi_write_force_png_filter;         // defaults to -1; set to 0..5 to force a filter mode\n\n\n   You can define STBI_WRITE_NO_STDIO to disable the file variant of these\n   functions, so the library will not use stdio.h at all. However, this will\n   also disable HDR writing, because it requires stdio for formatted output.\n\n   Each function returns 0 on failure and non-0 on success.\n\n   The functions create an image file defined by the parameters. The image\n   is a rectangle of pixels stored from left-to-right, top-to-bottom.\n   Each pixel contains 'comp' channels of data stored interleaved with 8-bits\n   per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is\n   monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.\n   The *data pointer points to the first byte of the top-left-most pixel.\n   For PNG, \"stride_in_bytes\" is the distance in bytes from the first byte of\n   a row of pixels to the first byte of the next row of pixels.\n\n   PNG creates output files with the same number of components as the input.\n   The BMP format expands Y to RGB in the file format and does not\n   output alpha.\n\n   PNG supports writing rectangles of data even when the bytes storing rows of\n   data are not consecutive in memory (e.g. sub-rectangles of a larger image),\n   by supplying the stride between the beginning of adjacent rows. The other\n   formats do not. (Thus you cannot write a native-format BMP through the BMP\n   writer, both because it is in BGR order and because it may have padding\n   at the end of the line.)\n\n   PNG allows you to set the deflate compression level by setting the global\n   variable 'stbi_write_png_compression_level' (it defaults to 8).\n\n   HDR expects linear float data. Since the format is always 32-bit rgb(e)\n   data, alpha (if provided) is discarded, and for monochrome data it is\n   replicated across all three channels.\n\n   TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed\n   data, set the global variable 'stbi_write_tga_with_rle' to 0.\n\n   JPEG does ignore alpha channels in input data; quality is between 1 and 100.\n   Higher quality looks better but results in a bigger image.\n   JPEG baseline (no JPEG progressive).\n\nCREDITS:\n\n\n   Sean Barrett           -    PNG/BMP/TGA\n   Baldur Karlsson        -    HDR\n   Jean-Sebastien Guay    -    TGA monochrome\n   Tim Kelsey             -    misc enhancements\n   Alan Hickman           -    TGA RLE\n   Emmanuel Julien        -    initial file IO callback implementation\n   Jon Olick              -    original jo_jpeg.cpp code\n   Daniel Gibson          -    integrate JPEG, allow external zlib\n   Aarni Koskela          -    allow choosing PNG filter\n\n   bugfixes:\n      github:Chribba\n      Guillaume Chereau\n      github:jry2\n      github:romigrou\n      Sergio Gonzalez\n      Jonas Karlsson\n      Filip Wasil\n      Thatcher Ulrich\n      github:poppolopoppo\n      Patrick Boettcher\n      github:xeekworx\n      Cap Petschulat\n      Simon Rodriguez\n      Ivan Tikhonov\n      github:ignotion\n      Adam Schackart\n      Andrew Kensler\n\nLICENSE\n\n  See end of file for license information.\n\n*/\n\n#ifndef INCLUDE_STB_IMAGE_WRITE_H\n#define INCLUDE_STB_IMAGE_WRITE_H\n\n#include <stdlib.h>\n\n// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'\n#ifndef STBIWDEF\n#ifdef STB_IMAGE_WRITE_STATIC\n#define STBIWDEF  static\n#else\n#ifdef __cplusplus\n#define STBIWDEF  extern \"C\"\n#else\n#define STBIWDEF  extern\n#endif\n#endif\n#endif\n\n#ifndef STB_IMAGE_WRITE_STATIC  // C++ forbids static forward declarations\nSTBIWDEF int stbi_write_tga_with_rle;\nSTBIWDEF int stbi_write_png_compression_level;\nSTBIWDEF int stbi_write_force_png_filter;\n#endif\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);\nSTBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);\nSTBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void  *data, int quality);\n\n#ifdef STBIW_WINDOWS_UTF8\nSTBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);\n#endif\n#endif\n\ntypedef void stbi_write_func(void *context, void *data, int size);\n\nSTBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);\nSTBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);\nSTBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void  *data, int quality);\n\nSTBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);\n\n#endif//INCLUDE_STB_IMAGE_WRITE_H\n\n#ifdef STB_IMAGE_WRITE_IMPLEMENTATION\n\n#ifdef _WIN32\n   #ifndef _CRT_SECURE_NO_WARNINGS\n   #define _CRT_SECURE_NO_WARNINGS\n   #endif\n   #ifndef _CRT_NONSTDC_NO_DEPRECATE\n   #define _CRT_NONSTDC_NO_DEPRECATE\n   #endif\n#endif\n\n#ifndef STBI_WRITE_NO_STDIO\n#include <stdio.h>\n#endif // STBI_WRITE_NO_STDIO\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n\n#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))\n// ok\n#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)\n// ok\n#else\n#error \"Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED).\"\n#endif\n\n#ifndef STBIW_MALLOC\n#define STBIW_MALLOC(sz)        malloc(sz)\n#define STBIW_REALLOC(p,newsz)  realloc(p,newsz)\n#define STBIW_FREE(p)           free(p)\n#endif\n\n#ifndef STBIW_REALLOC_SIZED\n#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)\n#endif\n\n\n#ifndef STBIW_MEMMOVE\n#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)\n#endif\n\n\n#ifndef STBIW_ASSERT\n#include <assert.h>\n#define STBIW_ASSERT(x) assert(x)\n#endif\n\n#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)\n\n#ifdef STB_IMAGE_WRITE_STATIC\nstatic int stbi_write_png_compression_level = 8;\nstatic int stbi_write_tga_with_rle = 1;\nstatic int stbi_write_force_png_filter = -1;\n#else\nint stbi_write_png_compression_level = 8;\nint stbi_write_tga_with_rle = 1;\nint stbi_write_force_png_filter = -1;\n#endif\n\nstatic int stbi__flip_vertically_on_write = 0;\n\nSTBIWDEF void stbi_flip_vertically_on_write(int flag)\n{\n   stbi__flip_vertically_on_write = flag;\n}\n\ntypedef struct\n{\n   stbi_write_func *func;\n   void *context;\n   unsigned char buffer[64];\n   int buf_used;\n} stbi__write_context;\n\n// initialize a callback-based context\nstatic void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)\n{\n   s->func    = c;\n   s->context = context;\n}\n\n#ifndef STBI_WRITE_NO_STDIO\n\nstatic void stbi__stdio_write(void *context, void *data, int size)\n{\n   fwrite(data,1,size,(FILE*) context);\n}\n\n#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)\n#ifdef __cplusplus\n#define STBIW_EXTERN extern \"C\"\n#else\n#define STBIW_EXTERN extern\n#endif\nSTBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);\nSTBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);\n\nSTBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)\n{\n   return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);\n}\n#endif\n\nstatic FILE *stbiw__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)\n   wchar_t wMode[64];\n   wchar_t wFilename[1024];\n   if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))\n      return 0;\n\n   if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))\n      return 0;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != _wfopen_s(&f, wFilename, wMode))\n      f = 0;\n#else\n   f = _wfopen(wFilename, wMode);\n#endif\n\n#elif defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\nstatic int stbi__start_write_file(stbi__write_context *s, const char *filename)\n{\n   FILE *f = stbiw__fopen(filename, \"wb\");\n   stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);\n   return f != NULL;\n}\n\nstatic void stbi__end_write_file(stbi__write_context *s)\n{\n   fclose((FILE *)s->context);\n}\n\n#endif // !STBI_WRITE_NO_STDIO\n\ntypedef unsigned int stbiw_uint32;\ntypedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];\n\nstatic void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)\n{\n   while (*fmt) {\n      switch (*fmt++) {\n         case ' ': break;\n         case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));\n                     s->func(s->context,&x,1);\n                     break; }\n         case '2': { int x = va_arg(v,int);\n                     unsigned char b[2];\n                     b[0] = STBIW_UCHAR(x);\n                     b[1] = STBIW_UCHAR(x>>8);\n                     s->func(s->context,b,2);\n                     break; }\n         case '4': { stbiw_uint32 x = va_arg(v,int);\n                     unsigned char b[4];\n                     b[0]=STBIW_UCHAR(x);\n                     b[1]=STBIW_UCHAR(x>>8);\n                     b[2]=STBIW_UCHAR(x>>16);\n                     b[3]=STBIW_UCHAR(x>>24);\n                     s->func(s->context,b,4);\n                     break; }\n         default:\n            STBIW_ASSERT(0);\n            return;\n      }\n   }\n}\n\nstatic void stbiw__writef(stbi__write_context *s, const char *fmt, ...)\n{\n   va_list v;\n   va_start(v, fmt);\n   stbiw__writefv(s, fmt, v);\n   va_end(v);\n}\n\nstatic void stbiw__write_flush(stbi__write_context *s)\n{\n   if (s->buf_used) {\n      s->func(s->context, &s->buffer, s->buf_used);\n      s->buf_used = 0;\n   }\n}\n\nstatic void stbiw__putc(stbi__write_context *s, unsigned char c)\n{\n   s->func(s->context, &c, 1);\n}\n\nstatic void stbiw__write1(stbi__write_context *s, unsigned char a)\n{\n   if ((size_t)s->buf_used + 1 > sizeof(s->buffer))\n      stbiw__write_flush(s);\n   s->buffer[s->buf_used++] = a;\n}\n\nstatic void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)\n{\n   int n;\n   if ((size_t)s->buf_used + 3 > sizeof(s->buffer))\n      stbiw__write_flush(s);\n   n = s->buf_used;\n   s->buf_used = n+3;\n   s->buffer[n+0] = a;\n   s->buffer[n+1] = b;\n   s->buffer[n+2] = c;\n}\n\nstatic void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)\n{\n   unsigned char bg[3] = { 255, 0, 255}, px[3];\n   int k;\n\n   if (write_alpha < 0)\n      stbiw__write1(s, d[comp - 1]);\n\n   switch (comp) {\n      case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case\n      case 1:\n         if (expand_mono)\n            stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp\n         else\n            stbiw__write1(s, d[0]);  // monochrome TGA\n         break;\n      case 4:\n         if (!write_alpha) {\n            // composite against pink background\n            for (k = 0; k < 3; ++k)\n               px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;\n            stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);\n            break;\n         }\n         /* FALLTHROUGH */\n      case 3:\n         stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);\n         break;\n   }\n   if (write_alpha > 0)\n      stbiw__write1(s, d[comp - 1]);\n}\n\nstatic void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)\n{\n   stbiw_uint32 zero = 0;\n   int i,j, j_end;\n\n   if (y <= 0)\n      return;\n\n   if (stbi__flip_vertically_on_write)\n      vdir *= -1;\n\n   if (vdir < 0) {\n      j_end = -1; j = y-1;\n   } else {\n      j_end =  y; j = 0;\n   }\n\n   for (; j != j_end; j += vdir) {\n      for (i=0; i < x; ++i) {\n         unsigned char *d = (unsigned char *) data + (j*x+i)*comp;\n         stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);\n      }\n      stbiw__write_flush(s);\n      s->func(s->context, &zero, scanline_pad);\n   }\n}\n\nstatic int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)\n{\n   if (y < 0 || x < 0) {\n      return 0;\n   } else {\n      va_list v;\n      va_start(v, fmt);\n      stbiw__writefv(s, fmt, v);\n      va_end(v);\n      stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);\n      return 1;\n   }\n}\n\nstatic int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)\n{\n   if (comp != 4) {\n      // write RGB bitmap\n      int pad = (-x*3) & 3;\n      return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,\n              \"11 4 22 4\" \"4 44 22 444444\",\n              'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header\n               40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header\n   } else {\n      // RGBA bitmaps need a v4 header\n      // use BI_BITFIELDS mode with 32bpp and alpha mask\n      // (straight BI_RGB with alpha mask doesn't work in most readers)\n      return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,\n         \"11 4 22 4\" \"4 44 22 444444 4444 4 444 444 444 444\",\n         'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header\n         108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header\n   }\n}\n\nSTBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_bmp_core(&s, x, y, comp, data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_bmp_core(&s, x, y, comp, data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif //!STBI_WRITE_NO_STDIO\n\nstatic int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)\n{\n   int has_alpha = (comp == 2 || comp == 4);\n   int colorbytes = has_alpha ? comp-1 : comp;\n   int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3\n\n   if (y < 0 || x < 0)\n      return 0;\n\n   if (!stbi_write_tga_with_rle) {\n      return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,\n         \"111 221 2222 11\", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);\n   } else {\n      int i,j,k;\n      int jend, jdir;\n\n      stbiw__writef(s, \"111 221 2222 11\", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);\n\n      if (stbi__flip_vertically_on_write) {\n         j = 0;\n         jend = y;\n         jdir = 1;\n      } else {\n         j = y-1;\n         jend = -1;\n         jdir = -1;\n      }\n      for (; j != jend; j += jdir) {\n         unsigned char *row = (unsigned char *) data + j * x * comp;\n         int len;\n\n         for (i = 0; i < x; i += len) {\n            unsigned char *begin = row + i * comp;\n            int diff = 1;\n            len = 1;\n\n            if (i < x - 1) {\n               ++len;\n               diff = memcmp(begin, row + (i + 1) * comp, comp);\n               if (diff) {\n                  const unsigned char *prev = begin;\n                  for (k = i + 2; k < x && len < 128; ++k) {\n                     if (memcmp(prev, row + k * comp, comp)) {\n                        prev += comp;\n                        ++len;\n                     } else {\n                        --len;\n                        break;\n                     }\n                  }\n               } else {\n                  for (k = i + 2; k < x && len < 128; ++k) {\n                     if (!memcmp(begin, row + k * comp, comp)) {\n                        ++len;\n                     } else {\n                        break;\n                     }\n                  }\n               }\n            }\n\n            if (diff) {\n               unsigned char header = STBIW_UCHAR(len - 1);\n               stbiw__write1(s, header);\n               for (k = 0; k < len; ++k) {\n                  stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);\n               }\n            } else {\n               unsigned char header = STBIW_UCHAR(len - 129);\n               stbiw__write1(s, header);\n               stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);\n            }\n         }\n      }\n      stbiw__write_flush(s);\n   }\n   return 1;\n}\n\nSTBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_tga_core(&s, x, y, comp, (void *) data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR writer\n// by Baldur Karlsson\n\n#define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))\n\n#ifndef STBI_WRITE_NO_STDIO\n\nstatic void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)\n{\n   int exponent;\n   float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));\n\n   if (maxcomp < 1e-32f) {\n      rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;\n   } else {\n      float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;\n\n      rgbe[0] = (unsigned char)(linear[0] * normalize);\n      rgbe[1] = (unsigned char)(linear[1] * normalize);\n      rgbe[2] = (unsigned char)(linear[2] * normalize);\n      rgbe[3] = (unsigned char)(exponent + 128);\n   }\n}\n\nstatic void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)\n{\n   unsigned char lengthbyte = STBIW_UCHAR(length+128);\n   STBIW_ASSERT(length+128 <= 255);\n   s->func(s->context, &lengthbyte, 1);\n   s->func(s->context, &databyte, 1);\n}\n\nstatic void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)\n{\n   unsigned char lengthbyte = STBIW_UCHAR(length);\n   STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code\n   s->func(s->context, &lengthbyte, 1);\n   s->func(s->context, data, length);\n}\n\nstatic void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)\n{\n   unsigned char scanlineheader[4] = { 2, 2, 0, 0 };\n   unsigned char rgbe[4];\n   float linear[3];\n   int x;\n\n   scanlineheader[2] = (width&0xff00)>>8;\n   scanlineheader[3] = (width&0x00ff);\n\n   /* skip RLE for images too small or large */\n   if (width < 8 || width >= 32768) {\n      for (x=0; x < width; x++) {\n         switch (ncomp) {\n            case 4: /* fallthrough */\n            case 3: linear[2] = scanline[x*ncomp + 2];\n                    linear[1] = scanline[x*ncomp + 1];\n                    linear[0] = scanline[x*ncomp + 0];\n                    break;\n            default:\n                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];\n                    break;\n         }\n         stbiw__linear_to_rgbe(rgbe, linear);\n         s->func(s->context, rgbe, 4);\n      }\n   } else {\n      int c,r;\n      /* encode into scratch buffer */\n      for (x=0; x < width; x++) {\n         switch(ncomp) {\n            case 4: /* fallthrough */\n            case 3: linear[2] = scanline[x*ncomp + 2];\n                    linear[1] = scanline[x*ncomp + 1];\n                    linear[0] = scanline[x*ncomp + 0];\n                    break;\n            default:\n                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];\n                    break;\n         }\n         stbiw__linear_to_rgbe(rgbe, linear);\n         scratch[x + width*0] = rgbe[0];\n         scratch[x + width*1] = rgbe[1];\n         scratch[x + width*2] = rgbe[2];\n         scratch[x + width*3] = rgbe[3];\n      }\n\n      s->func(s->context, scanlineheader, 4);\n\n      /* RLE each component separately */\n      for (c=0; c < 4; c++) {\n         unsigned char *comp = &scratch[width*c];\n\n         x = 0;\n         while (x < width) {\n            // find first run\n            r = x;\n            while (r+2 < width) {\n               if (comp[r] == comp[r+1] && comp[r] == comp[r+2])\n                  break;\n               ++r;\n            }\n            if (r+2 >= width)\n               r = width;\n            // dump up to first run\n            while (x < r) {\n               int len = r-x;\n               if (len > 128) len = 128;\n               stbiw__write_dump_data(s, len, &comp[x]);\n               x += len;\n            }\n            // if there's a run, output it\n            if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd\n               // find next byte after run\n               while (r < width && comp[r] == comp[x])\n                  ++r;\n               // output run up to r\n               while (x < r) {\n                  int len = r-x;\n                  if (len > 127) len = 127;\n                  stbiw__write_run_data(s, len, comp[x]);\n                  x += len;\n               }\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)\n{\n   if (y <= 0 || x <= 0 || data == NULL)\n      return 0;\n   else {\n      // Each component is stored separately. Allocate scratch space for full output scanline.\n      unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);\n      int i, len;\n      char buffer[128];\n      char header[] = \"#?RADIANCE\\n# Written by stb_image_write.h\\nFORMAT=32-bit_rle_rgbe\\n\";\n      s->func(s->context, header, sizeof(header)-1);\n\n#ifdef __STDC_LIB_EXT1__\n      len = sprintf_s(buffer, sizeof(buffer), \"EXPOSURE=          1.0000000000000\\n\\n-Y %d +X %d\\n\", y, x);\n#else\n      len = sprintf(buffer, \"EXPOSURE=          1.0000000000000\\n\\n-Y %d +X %d\\n\", y, x);\n#endif\n      s->func(s->context, buffer, len);\n\n      for(i=0; i < y; i++)\n         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i));\n      STBIW_FREE(scratch);\n      return 1;\n   }\n}\n\nSTBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_hdr_core(&s, x, y, comp, (float *) data);\n}\n\nSTBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif // STBI_WRITE_NO_STDIO\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PNG writer\n//\n\n#ifndef STBIW_ZLIB_COMPRESS\n// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()\n#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)\n#define stbiw__sbm(a)   stbiw__sbraw(a)[0]\n#define stbiw__sbn(a)   stbiw__sbraw(a)[1]\n\n#define stbiw__sbneedgrow(a,n)  ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))\n#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)\n#define stbiw__sbgrow(a,n)  stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))\n\n#define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))\n#define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)\n#define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)\n\nstatic void *stbiw__sbgrowf(void **arr, int increment, int itemsize)\n{\n   int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;\n   void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);\n   STBIW_ASSERT(p);\n   if (p) {\n      if (!*arr) ((int *) p)[1] = 0;\n      *arr = (void *) ((int *) p + 2);\n      stbiw__sbm(*arr) = m;\n   }\n   return *arr;\n}\n\nstatic unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)\n{\n   while (*bitcount >= 8) {\n      stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));\n      *bitbuffer >>= 8;\n      *bitcount -= 8;\n   }\n   return data;\n}\n\nstatic int stbiw__zlib_bitrev(int code, int codebits)\n{\n   int res=0;\n   while (codebits--) {\n      res = (res << 1) | (code & 1);\n      code >>= 1;\n   }\n   return res;\n}\n\nstatic unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)\n{\n   int i;\n   for (i=0; i < limit && i < 258; ++i)\n      if (a[i] != b[i]) break;\n   return i;\n}\n\nstatic unsigned int stbiw__zhash(unsigned char *data)\n{\n   stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);\n   hash ^= hash << 3;\n   hash += hash >> 5;\n   hash ^= hash << 4;\n   hash += hash >> 17;\n   hash ^= hash << 25;\n   hash += hash >> 6;\n   return hash;\n}\n\n#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))\n#define stbiw__zlib_add(code,codebits) \\\n      (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())\n#define stbiw__zlib_huffa(b,c)  stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)\n// default huffman tables\n#define stbiw__zlib_huff1(n)  stbiw__zlib_huffa(0x30 + (n), 8)\n#define stbiw__zlib_huff2(n)  stbiw__zlib_huffa(0x190 + (n)-144, 9)\n#define stbiw__zlib_huff3(n)  stbiw__zlib_huffa(0 + (n)-256,7)\n#define stbiw__zlib_huff4(n)  stbiw__zlib_huffa(0xc0 + (n)-280,8)\n#define stbiw__zlib_huff(n)  ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))\n#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))\n\n#define stbiw__ZHASH   16384\n\n#endif // STBIW_ZLIB_COMPRESS\n\nSTBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)\n{\n#ifdef STBIW_ZLIB_COMPRESS\n   // user provided a zlib compress implementation, use that\n   return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);\n#else // use builtin\n   static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };\n   static unsigned char  lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,  4,  5,  5,  5,  5,  0 };\n   static unsigned short distc[]   = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };\n   static unsigned char  disteb[]  = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };\n   unsigned int bitbuf=0;\n   int i,j, bitcount=0;\n   unsigned char *out = NULL;\n   unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));\n   if (hash_table == NULL)\n      return NULL;\n   if (quality < 5) quality = 5;\n\n   stbiw__sbpush(out, 0x78);   // DEFLATE 32K window\n   stbiw__sbpush(out, 0x5e);   // FLEVEL = 1\n   stbiw__zlib_add(1,1);  // BFINAL = 1\n   stbiw__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman\n\n   for (i=0; i < stbiw__ZHASH; ++i)\n      hash_table[i] = NULL;\n\n   i=0;\n   while (i < data_len-3) {\n      // hash next 3 bytes of data to be compressed\n      int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;\n      unsigned char *bestloc = 0;\n      unsigned char **hlist = hash_table[h];\n      int n = stbiw__sbcount(hlist);\n      for (j=0; j < n; ++j) {\n         if (hlist[j]-data > i-32768) { // if entry lies within window\n            int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);\n            if (d >= best) { best=d; bestloc=hlist[j]; }\n         }\n      }\n      // when hash table entry is too long, delete half the entries\n      if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {\n         STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);\n         stbiw__sbn(hash_table[h]) = quality;\n      }\n      stbiw__sbpush(hash_table[h],data+i);\n\n      if (bestloc) {\n         // \"lazy matching\" - check match at *next* byte, and if it's better, do cur byte as literal\n         h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);\n         hlist = hash_table[h];\n         n = stbiw__sbcount(hlist);\n         for (j=0; j < n; ++j) {\n            if (hlist[j]-data > i-32767) {\n               int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);\n               if (e > best) { // if next match is better, bail on current match\n                  bestloc = NULL;\n                  break;\n               }\n            }\n         }\n      }\n\n      if (bestloc) {\n         int d = (int) (data+i - bestloc); // distance back\n         STBIW_ASSERT(d <= 32767 && best <= 258);\n         for (j=0; best > lengthc[j+1]-1; ++j);\n         stbiw__zlib_huff(j+257);\n         if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);\n         for (j=0; d > distc[j+1]-1; ++j);\n         stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);\n         if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);\n         i += best;\n      } else {\n         stbiw__zlib_huffb(data[i]);\n         ++i;\n      }\n   }\n   // write out final bytes\n   for (;i < data_len; ++i)\n      stbiw__zlib_huffb(data[i]);\n   stbiw__zlib_huff(256); // end of block\n   // pad with 0 bits to byte boundary\n   while (bitcount)\n      stbiw__zlib_add(0,1);\n\n   for (i=0; i < stbiw__ZHASH; ++i)\n      (void) stbiw__sbfree(hash_table[i]);\n   STBIW_FREE(hash_table);\n\n   // store uncompressed instead if compression was worse\n   if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {\n      stbiw__sbn(out) = 2;  // truncate to DEFLATE 32K window and FLEVEL = 1\n      for (j = 0; j < data_len;) {\n         int blocklen = data_len - j;\n         if (blocklen > 32767) blocklen = 32767;\n         stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression\n         stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN\n         stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));\n         stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN\n         stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));\n         memcpy(out+stbiw__sbn(out), data+j, blocklen);\n         stbiw__sbn(out) += blocklen;\n         j += blocklen;\n      }\n   }\n\n   {\n      // compute adler32 on input\n      unsigned int s1=1, s2=0;\n      int blocklen = (int) (data_len % 5552);\n      j=0;\n      while (j < data_len) {\n         for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }\n         s1 %= 65521; s2 %= 65521;\n         j += blocklen;\n         blocklen = 5552;\n      }\n      stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));\n      stbiw__sbpush(out, STBIW_UCHAR(s2));\n      stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));\n      stbiw__sbpush(out, STBIW_UCHAR(s1));\n   }\n   *out_len = stbiw__sbn(out);\n   // make returned pointer freeable\n   STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);\n   return (unsigned char *) stbiw__sbraw(out);\n#endif // STBIW_ZLIB_COMPRESS\n}\n\nstatic unsigned int stbiw__crc32(unsigned char *buffer, int len)\n{\n#ifdef STBIW_CRC32\n    return STBIW_CRC32(buffer, len);\n#else\n   static unsigned int crc_table[256] =\n   {\n      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,\n      0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,\n      0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,\n      0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,\n      0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,\n      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,\n      0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,\n      0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,\n      0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,\n      0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,\n      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,\n      0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,\n      0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,\n      0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,\n      0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\n      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,\n      0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,\n      0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,\n      0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,\n      0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,\n      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,\n      0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,\n      0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,\n      0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,\n      0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,\n      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,\n      0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,\n      0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,\n      0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,\n      0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\n      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,\n      0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D\n   };\n\n   unsigned int crc = ~0u;\n   int i;\n   for (i=0; i < len; ++i)\n      crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];\n   return ~crc;\n#endif\n}\n\n#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)\n#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));\n#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])\n\nstatic void stbiw__wpcrc(unsigned char **data, int len)\n{\n   unsigned int crc = stbiw__crc32(*data - len - 4, len+4);\n   stbiw__wp32(*data, crc);\n}\n\nstatic unsigned char stbiw__paeth(int a, int b, int c)\n{\n   int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);\n   if (pb <= pc) return STBIW_UCHAR(b);\n   return STBIW_UCHAR(c);\n}\n\n// @OPTIMIZE: provide an option that always forces left-predict or paeth predict\nstatic void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)\n{\n   static int mapping[] = { 0,1,2,3,4 };\n   static int firstmap[] = { 0,1,0,5,6 };\n   int *mymap = (y != 0) ? mapping : firstmap;\n   int i;\n   int type = mymap[filter_type];\n   unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);\n   int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;\n\n   if (type==0) {\n      memcpy(line_buffer, z, width*n);\n      return;\n   }\n\n   // first loop isn't optimized since it's just one pixel\n   for (i = 0; i < n; ++i) {\n      switch (type) {\n         case 1: line_buffer[i] = z[i]; break;\n         case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;\n         case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;\n         case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;\n         case 5: line_buffer[i] = z[i]; break;\n         case 6: line_buffer[i] = z[i]; break;\n      }\n   }\n   switch (type) {\n      case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break;\n      case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break;\n      case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;\n      case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break;\n      case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break;\n      case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;\n   }\n}\n\nSTBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)\n{\n   int force_filter = stbi_write_force_png_filter;\n   int ctype[5] = { -1, 0, 4, 2, 6 };\n   unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };\n   unsigned char *out,*o, *filt, *zlib;\n   signed char *line_buffer;\n   int j,zlen;\n\n   if (stride_bytes == 0)\n      stride_bytes = x * n;\n\n   if (force_filter >= 5) {\n      force_filter = -1;\n   }\n\n   filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;\n   line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }\n   for (j=0; j < y; ++j) {\n      int filter_type;\n      if (force_filter > -1) {\n         filter_type = force_filter;\n         stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);\n      } else { // Estimate the best filter by running through all of them:\n         int best_filter = 0, best_filter_val = 0x7fffffff, est, i;\n         for (filter_type = 0; filter_type < 5; filter_type++) {\n            stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);\n\n            // Estimate the entropy of the line using this filter; the less, the better.\n            est = 0;\n            for (i = 0; i < x*n; ++i) {\n               est += abs((signed char) line_buffer[i]);\n            }\n            if (est < best_filter_val) {\n               best_filter_val = est;\n               best_filter = filter_type;\n            }\n         }\n         if (filter_type != best_filter) {  // If the last iteration already got us the best filter, don't redo it\n            stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);\n            filter_type = best_filter;\n         }\n      }\n      // when we get here, filter_type contains the filter type, and line_buffer contains the data\n      filt[j*(x*n+1)] = (unsigned char) filter_type;\n      STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);\n   }\n   STBIW_FREE(line_buffer);\n   zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);\n   STBIW_FREE(filt);\n   if (!zlib) return 0;\n\n   // each tag requires 12 bytes of overhead\n   out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);\n   if (!out) return 0;\n   *out_len = 8 + 12+13 + 12+zlen + 12;\n\n   o=out;\n   STBIW_MEMMOVE(o,sig,8); o+= 8;\n   stbiw__wp32(o, 13); // header length\n   stbiw__wptag(o, \"IHDR\");\n   stbiw__wp32(o, x);\n   stbiw__wp32(o, y);\n   *o++ = 8;\n   *o++ = STBIW_UCHAR(ctype[n]);\n   *o++ = 0;\n   *o++ = 0;\n   *o++ = 0;\n   stbiw__wpcrc(&o,13);\n\n   stbiw__wp32(o, zlen);\n   stbiw__wptag(o, \"IDAT\");\n   STBIW_MEMMOVE(o, zlib, zlen);\n   o += zlen;\n   STBIW_FREE(zlib);\n   stbiw__wpcrc(&o, zlen);\n\n   stbiw__wp32(o,0);\n   stbiw__wptag(o, \"IEND\");\n   stbiw__wpcrc(&o,0);\n\n   STBIW_ASSERT(o == out + *out_len);\n\n   return out;\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)\n{\n   FILE *f;\n   int len;\n   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);\n   if (png == NULL) return 0;\n\n   f = stbiw__fopen(filename, \"wb\");\n   if (!f) { STBIW_FREE(png); return 0; }\n   fwrite(png, 1, len, f);\n   fclose(f);\n   STBIW_FREE(png);\n   return 1;\n}\n#endif\n\nSTBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)\n{\n   int len;\n   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);\n   if (png == NULL) return 0;\n   func(context, png, len);\n   STBIW_FREE(png);\n   return 1;\n}\n\n\n/* ***************************************************************************\n *\n * JPEG writer\n *\n * This is based on Jon Olick's jo_jpeg.cpp:\n * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html\n */\n\nstatic const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,\n      24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };\n\nstatic void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {\n   int bitBuf = *bitBufP, bitCnt = *bitCntP;\n   bitCnt += bs[1];\n   bitBuf |= bs[0] << (24 - bitCnt);\n   while(bitCnt >= 8) {\n      unsigned char c = (bitBuf >> 16) & 255;\n      stbiw__putc(s, c);\n      if(c == 255) {\n         stbiw__putc(s, 0);\n      }\n      bitBuf <<= 8;\n      bitCnt -= 8;\n   }\n   *bitBufP = bitBuf;\n   *bitCntP = bitCnt;\n}\n\nstatic void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {\n   float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;\n   float z1, z2, z3, z4, z5, z11, z13;\n\n   float tmp0 = d0 + d7;\n   float tmp7 = d0 - d7;\n   float tmp1 = d1 + d6;\n   float tmp6 = d1 - d6;\n   float tmp2 = d2 + d5;\n   float tmp5 = d2 - d5;\n   float tmp3 = d3 + d4;\n   float tmp4 = d3 - d4;\n\n   // Even part\n   float tmp10 = tmp0 + tmp3;   // phase 2\n   float tmp13 = tmp0 - tmp3;\n   float tmp11 = tmp1 + tmp2;\n   float tmp12 = tmp1 - tmp2;\n\n   d0 = tmp10 + tmp11;       // phase 3\n   d4 = tmp10 - tmp11;\n\n   z1 = (tmp12 + tmp13) * 0.707106781f; // c4\n   d2 = tmp13 + z1;       // phase 5\n   d6 = tmp13 - z1;\n\n   // Odd part\n   tmp10 = tmp4 + tmp5;       // phase 2\n   tmp11 = tmp5 + tmp6;\n   tmp12 = tmp6 + tmp7;\n\n   // The rotator is modified from fig 4-8 to avoid extra negations.\n   z5 = (tmp10 - tmp12) * 0.382683433f; // c6\n   z2 = tmp10 * 0.541196100f + z5; // c2-c6\n   z4 = tmp12 * 1.306562965f + z5; // c2+c6\n   z3 = tmp11 * 0.707106781f; // c4\n\n   z11 = tmp7 + z3;      // phase 5\n   z13 = tmp7 - z3;\n\n   *d5p = z13 + z2;         // phase 6\n   *d3p = z13 - z2;\n   *d1p = z11 + z4;\n   *d7p = z11 - z4;\n\n   *d0p = d0;  *d2p = d2;  *d4p = d4;  *d6p = d6;\n}\n\nstatic void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {\n   int tmp1 = val < 0 ? -val : val;\n   val = val < 0 ? val-1 : val;\n   bits[1] = 1;\n   while(tmp1 >>= 1) {\n      ++bits[1];\n   }\n   bits[0] = val & ((1<<bits[1])-1);\n}\n\nstatic int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {\n   const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };\n   const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };\n   int dataOff, i, j, n, diff, end0pos, x, y;\n   int DU[64];\n\n   // DCT rows\n   for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {\n      stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);\n   }\n   // DCT columns\n   for(dataOff=0; dataOff<8; ++dataOff) {\n      stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],\n                     &CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);\n   }\n   // Quantize/descale/zigzag the coefficients\n   for(y = 0, j=0; y < 8; ++y) {\n      for(x = 0; x < 8; ++x,++j) {\n         float v;\n         i = y*du_stride+x;\n         v = CDU[i]*fdtbl[j];\n         // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));\n         // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?\n         DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);\n      }\n   }\n\n   // Encode DC\n   diff = DU[0] - DC;\n   if (diff == 0) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);\n   } else {\n      unsigned short bits[2];\n      stbiw__jpg_calcBits(diff, bits);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);\n   }\n   // Encode ACs\n   end0pos = 63;\n   for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {\n   }\n   // end0pos = first element in reverse order !=0\n   if(end0pos == 0) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);\n      return DU[0];\n   }\n   for(i = 1; i <= end0pos; ++i) {\n      int startpos = i;\n      int nrzeroes;\n      unsigned short bits[2];\n      for (; DU[i]==0 && i<=end0pos; ++i) {\n      }\n      nrzeroes = i-startpos;\n      if ( nrzeroes >= 16 ) {\n         int lng = nrzeroes>>4;\n         int nrmarker;\n         for (nrmarker=1; nrmarker <= lng; ++nrmarker)\n            stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);\n         nrzeroes &= 15;\n      }\n      stbiw__jpg_calcBits(DU[i], bits);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);\n   }\n   if(end0pos != 63) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);\n   }\n   return DU[0];\n}\n\nstatic int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {\n   // Constants that don't pollute global namespace\n   static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};\n   static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};\n   static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};\n   static const unsigned char std_ac_luminance_values[] = {\n      0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\n      0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\n      0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\n      0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\n      0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\n      0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\n      0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa\n   };\n   static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};\n   static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};\n   static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};\n   static const unsigned char std_ac_chrominance_values[] = {\n      0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\n      0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\n      0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\n      0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\n      0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\n      0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\n      0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa\n   };\n   // Huffman tables\n   static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};\n   static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};\n   static const unsigned short YAC_HT[256][2] = {\n      {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}\n   };\n   static const unsigned short UVAC_HT[256][2] = {\n      {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}\n   };\n   static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,\n                             37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};\n   static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,\n                              99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};\n   static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,\n                                 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };\n\n   int row, col, i, k, subsample;\n   float fdtbl_Y[64], fdtbl_UV[64];\n   unsigned char YTable[64], UVTable[64];\n\n   if(!data || !width || !height || comp > 4 || comp < 1) {\n      return 0;\n   }\n\n   quality = quality ? quality : 90;\n   subsample = quality <= 90 ? 1 : 0;\n   quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;\n   quality = quality < 50 ? 5000 / quality : 200 - quality * 2;\n\n   for(i = 0; i < 64; ++i) {\n      int uvti, yti = (YQT[i]*quality+50)/100;\n      YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);\n      uvti = (UVQT[i]*quality+50)/100;\n      UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);\n   }\n\n   for(row = 0, k = 0; row < 8; ++row) {\n      for(col = 0; col < 8; ++col, ++k) {\n         fdtbl_Y[k]  = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);\n         fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);\n      }\n   }\n\n   // Write Headers\n   {\n      static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };\n      static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };\n      const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),\n                                      3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };\n      s->func(s->context, (void*)head0, sizeof(head0));\n      s->func(s->context, (void*)YTable, sizeof(YTable));\n      stbiw__putc(s, 1);\n      s->func(s->context, UVTable, sizeof(UVTable));\n      s->func(s->context, (void*)head1, sizeof(head1));\n      s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);\n      s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));\n      stbiw__putc(s, 0x10); // HTYACinfo\n      s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);\n      s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));\n      stbiw__putc(s, 1); // HTUDCinfo\n      s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);\n      s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));\n      stbiw__putc(s, 0x11); // HTUACinfo\n      s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);\n      s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));\n      s->func(s->context, (void*)head2, sizeof(head2));\n   }\n\n   // Encode 8x8 macroblocks\n   {\n      static const unsigned short fillBits[] = {0x7F, 7};\n      int DCY=0, DCU=0, DCV=0;\n      int bitBuf=0, bitCnt=0;\n      // comp == 2 is grey+alpha (alpha is ignored)\n      int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;\n      const unsigned char *dataR = (const unsigned char *)data;\n      const unsigned char *dataG = dataR + ofsG;\n      const unsigned char *dataB = dataR + ofsB;\n      int x, y, pos;\n      if(subsample) {\n         for(y = 0; y < height; y += 16) {\n            for(x = 0; x < width; x += 16) {\n               float Y[256], U[256], V[256];\n               for(row = y, pos = 0; row < y+16; ++row) {\n                  // row >= height => use last input row\n                  int clamped_row = (row < height) ? row : height - 1;\n                  int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;\n                  for(col = x; col < x+16; ++col, ++pos) {\n                     // if col >= width => use pixel from last input column\n                     int p = base_p + ((col < width) ? col : (width-1))*comp;\n                     float r = dataR[p], g = dataG[p], b = dataB[p];\n                     Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;\n                     U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;\n                     V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;\n                  }\n               }\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0,   16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8,   16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n\n               // subsample U,V\n               {\n                  float subU[64], subV[64];\n                  int yy, xx;\n                  for(yy = 0, pos = 0; yy < 8; ++yy) {\n                     for(xx = 0; xx < 8; ++xx, ++pos) {\n                        int j = yy*32+xx*2;\n                        subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;\n                        subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;\n                     }\n                  }\n                  DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n                  DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n               }\n            }\n         }\n      } else {\n         for(y = 0; y < height; y += 8) {\n            for(x = 0; x < width; x += 8) {\n               float Y[64], U[64], V[64];\n               for(row = y, pos = 0; row < y+8; ++row) {\n                  // row >= height => use last input row\n                  int clamped_row = (row < height) ? row : height - 1;\n                  int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;\n                  for(col = x; col < x+8; ++col, ++pos) {\n                     // if col >= width => use pixel from last input column\n                     int p = base_p + ((col < width) ? col : (width-1))*comp;\n                     float r = dataR[p], g = dataG[p], b = dataB[p];\n                     Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;\n                     U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;\n                     V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;\n                  }\n               }\n\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y,  DCY, YDC_HT, YAC_HT);\n               DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n               DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n            }\n         }\n      }\n\n      // Do the bit alignment of the EOI marker\n      stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);\n   }\n\n   // EOI\n   stbiw__putc(s, 0xFF);\n   stbiw__putc(s, 0xD9);\n\n   return 1;\n}\n\nSTBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);\n}\n\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n\n#endif // STB_IMAGE_WRITE_IMPLEMENTATION\n\n/* Revision history\n      1.16  (2021-07-11)\n             make Deflate code emit uncompressed blocks when it would otherwise expand\n             support writing BMPs with alpha channel\n      1.15  (2020-07-13) unknown\n      1.14  (2020-02-02) updated JPEG writer to downsample chroma channels\n      1.13\n      1.12\n      1.11  (2019-08-11)\n\n      1.10  (2019-02-07)\n             support utf8 filenames in Windows; fix warnings and platform ifdefs\n      1.09  (2018-02-11)\n             fix typo in zlib quality API, improve STB_I_W_STATIC in C++\n      1.08  (2018-01-29)\n             add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter\n      1.07  (2017-07-24)\n             doc fix\n      1.06 (2017-07-23)\n             writing JPEG (using Jon Olick's code)\n      1.05   ???\n      1.04 (2017-03-03)\n             monochrome BMP expansion\n      1.03   ???\n      1.02 (2016-04-02)\n             avoid allocating large structures on the stack\n      1.01 (2016-01-16)\n             STBIW_REALLOC_SIZED: support allocators with no realloc support\n             avoid race-condition in crc initialization\n             minor compile issues\n      1.00 (2015-09-14)\n             installable file IO function\n      0.99 (2015-09-13)\n             warning fixes; TGA rle support\n      0.98 (2015-04-08)\n             added STBIW_MALLOC, STBIW_ASSERT etc\n      0.97 (2015-01-18)\n             fixed HDR asserts, rewrote HDR rle logic\n      0.96 (2015-01-17)\n             add HDR output\n             fix monochrome BMP\n      0.95 (2014-08-17)\n             add monochrome TGA output\n      0.94 (2014-05-31)\n             rename private functions to avoid conflicts with stb_image.h\n      0.93 (2014-05-27)\n             warning fixes\n      0.92 (2010-08-01)\n             casts to unsigned char to fix warnings\n      0.91 (2010-07-17)\n             first public release\n      0.90   first internal release\n*/\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "lib/osgl/test_framebuffer_glad.cpp",
    "content": "#include <vapor/GLInclude.h>\n#include <vapor/GLContextProvider.h>\n// #include <vapor/GLInclude.h>\n\n\n//#include <GL/osmesa.h>\n\n\n#define STB_IMAGE_WRITE_IMPLEMENTATION\n#include \"stb_image_write.h\"\n\n#define GL_SILENCE_DEPRECATION\n\n#define GLERRTEST if (glGetError() != GL_NO_ERROR) printf(\"OPENGL ERROR\\n\");\n\nint main(int argc, char **argv)\n{\n    printf(\"Framebuffer test\\n\");\n\n    auto ctx = GLContextProvider::CreateContext();\n    assert(ctx);\n    ctx->MakeCurrent();\n\n    LogMessage(\"Context: %s\", glGetString(GL_VERSION));\n\n    \n    GLuint _colorBuffer;\n    glGenTextures(1, &_colorBuffer);\n    glBindTexture(GL_TEXTURE_2D, _colorBuffer);\n\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    \n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 100, 100, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);\n    \n    printf(\"[%i] About to gen framebuffer\\n\", __LINE__);\n    GLuint _id;\n    glGenFramebuffers(1, &_id);\n    printf(\"[%i] Framebuffer generated: %i\\n\", __LINE__, _id);\n\n    glBindFramebuffer(GL_FRAMEBUFFER, _id);\n\n    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorBuffer, 0);\n    \n    glBindFramebuffer(GL_FRAMEBUFFER, _id);\n    \n    glViewport(0, 0, 100, 100);\n    \n    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);\n    glClear(GL_COLOR_BUFFER_BIT);\n    glFlush();\n    \n    unsigned char *pixels[100*100*3];\n    memset(pixels, 1, 100*100*3);\n    glPixelStorei(GL_PACK_ALIGNMENT, 1);\n    glReadPixels(0, 0, 100, 100, GL_RGB, GL_UNSIGNED_BYTE, pixels);\n    \n    stbi_write_png(\"out-framebuffer-red.png\", 100, 100, 3, pixels, 0);\n    \n    GLERRTEST;\n\n    return 0;\n}\n"
  },
  {
    "path": "lib/osgl/test_version.cpp",
    "content": "#include <vapor/GLContextProvider.h>\n#include <vapor/GLInclude.h>\n\nint main(int argc, char **argv)\n{\n    LogMessage(\"Version Test\");\n    auto ctx = GLContextProvider::CreateContext();\n    assert(ctx);\n    ctx->MakeCurrent();\n    LogMessage(\"Context: %s\", glGetString(GL_VERSION));\n    return 0;\n}\n"
  },
  {
    "path": "lib/params/AnimationParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tAnimationParams.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJanuary 2005\n//\n//\tDescription:\tImplements the AnimationParams class\n//\t\tThis is derived from the Params class\n//\t\tIt contains all the parameters required for animation\n\n//\n\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n\n#include <vapor/AnimationParams.h>\n\nusing namespace VAPoR;\nconst string AnimationParams::_maxRateTag = \"MaxFrameRate\";\nconst string AnimationParams::_startTimestepTag = \"StartTimestep\";\nconst string AnimationParams::_endTimestepTag = \"EndTimestep\";\nconst string AnimationParams::_currentTimestepTag = \"CurrentTimestep\";\nconst string AnimationParams::_playBackwardsTag = \"PlayBackwards\";\nconst string AnimationParams::CaptureStartTag = \"CaptureStartTag\";\nconst string AnimationParams::CaptureEndTag = \"CaptureEndTag\";\nconst string AnimationParams::CaptureModeTag = \"CaptureModeTag\";\nconst string AnimationParams::CaptureTypeTag = \"CaptureTypeTag\";\nconst string AnimationParams::CaptureFileNameTag = \"CaptureFileNameTag\";\nconst string AnimationParams::CaptureFileDirTag = \"CaptureFileDirTag\";\nconst string AnimationParams::CaptureFileTimeTag = \"CaptureFileTimeTag\";\nconst string AnimationParams::CaptureTimeSeriesFileNameTag = \"CaptureTimeSeriesFileNameTag\";\nconst string AnimationParams::CaptureTimeSeriesTimeTag = \"CaptureTimeSeriesTimeTag\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<AnimationParams> registrar(AnimationParams::GetClassType());\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nAnimationParams::AnimationParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, AnimationParams::GetClassType()) { _init(); }\n\nAnimationParams::AnimationParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    // If node isn't tagged correctly we correct the tag and reinitialize\n    // from scratch;\n    //\n    if (node->GetTag() != AnimationParams::GetClassType()) {\n        node->SetTag(AnimationParams::GetClassType());\n        _init();\n    }\n}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nAnimationParams::~AnimationParams() { MyBase::SetDiagMsg(\"AnimationParams::~AnimationParams() this=%p\", this); }\n\n// Reset to initial state\n//\nvoid AnimationParams::_init()\n{\n    // set everything to default state:\n    SetPlayBackwards(false);\n    SetStartTimestep(0);\n    SetEndTimestep(10000000);\n    SetCurrentTimestep(0);\n    SetMaxFrameRate(10);\n    SetValueLong(AnimationParams::CaptureModeTag, \"Set default value for image capture mode\", AnimationParams::SingleImage);\n    SetValueLong(AnimationParams::CaptureTypeTag, \"Set default value for capture mode image filetype\", AnimationParams::TIFF);\n    SetValueLong(AnimationParams::CaptureStartTag, \"Set default value for capturing imagery start time\", GetStartTimestep());\n    SetValueLong(AnimationParams::CaptureEndTag, \"Set default value for capturing imagery end time\", GetEndTimestep());\n}\n"
  },
  {
    "path": "lib/params/AnnotationParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2015\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tAnnotationParams.cpp\n//\n//\tAuthor:\tScott Pearse\n//\t\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune 2015\n//\n//\tDescription:\tImplements the AnnotationParams class.\n//\t\tThis class supports parameters associted with the\n//\t\tvisualizer features in the annotation panel\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <vector>\n#include <string>\n#include <iostream>\n\n#include <vapor/AnnotationParams.h>\n\n\nusing namespace VAPoR;\n\nconst string AnnotationParams::_domainFrameTag = \"DomainFrame\";\nconst string AnnotationParams::_domainColorTag = \"DomainColor\";\nconst string AnnotationParams::_regionFrameTag = \"RegionFrame\";\nconst string AnnotationParams::_regionColorTag = \"RegionColor\";\nconst string AnnotationParams::_backgroundColorTag = \"BackgroundColor\";\nconst string AnnotationParams::_axisAnnotationEnabledTag = \"AxisAnnotationiEnabled\";\nconst string AnnotationParams::_axisColorTag = \"AxisColor\";\nconst string AnnotationParams::_axisDigitsTag = \"AxisDigits\";\nconst string AnnotationParams::_axisTextHeightTag = \"AxisTextHeight\";\nconst string AnnotationParams::_axisFontSizeTag = \"AxisFontSize\";\nconst string AnnotationParams::_ticWidthTag = \"TicWidths\";\nconst string AnnotationParams::_ticDirsTag = \"TicDirections\";\nconst string AnnotationParams::_ticSizeTag = \"TicSizes\";\nconst string AnnotationParams::_minTicsTag = \"TicMinPositions\";\nconst string AnnotationParams::_maxTicsTag = \"TicMaxPositions\";\nconst string AnnotationParams::_numTicsTag = \"NumberTics\";\nconst string AnnotationParams::_currentAxisDataMgrTag = \"AxisDataMgr\";\nconst string AnnotationParams::_latLonAxesTag = \"LatLonAxes\";\nconst string AnnotationParams::_axisOriginTag = \"AxisOrigin\";\nconst string AnnotationParams::AxisArrowEnabledTag = \"ShowAxisArrows\";\nconst string AnnotationParams::AxisArrowSizeTag = \"AxisArrowSize\";\nconst string AnnotationParams::AxisArrowXPosTag = \"AxisArrowXPos\";\nconst string AnnotationParams::AxisArrowYPosTag = \"AxisArrowYPos\";\nconst string AnnotationParams::_axisAnnotationsTag = \"AxisAnnotations\";\nconst string AnnotationParams::_timeLLXTag = \"TimeLLX\";\nconst string AnnotationParams::_timeLLYTag = \"TimeLLY\";\nconst string AnnotationParams::_timeColorTag = \"TimeColor\";\nconst string AnnotationParams::_timeTypeTag = \"TimeType\";\nconst string AnnotationParams::_timeSizeTag = \"TimeSize\";\nconst string AnnotationParams::_projStringTag = \"ProjString\";\n\nvector<double> AnnotationParams::_previousStretch;\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<AnnotationParams> registrar(AnnotationParams::GetClassType());\n\nnamespace {\nstring defaultAnnotation = \"default\";\n}\n\nAnnotationParams::AnnotationParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, AnnotationParams::GetClassType())\n{\n    _init();\n\n    _axisAnnotations = new ParamsContainer(ssave, _axisAnnotationsTag);\n    _axisAnnotations->SetParent(this);\n}\n\nAnnotationParams::AnnotationParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    if (node->HasChild(_axisAnnotationsTag)) {\n        _axisAnnotations = new ParamsContainer(ssave, node->GetChild(_axisAnnotationsTag));\n    } else {\n        _axisAnnotations = new ParamsContainer(ssave, _axisAnnotationsTag);\n        _axisAnnotations->SetParent(this);\n    }\n}\n\nAnnotationParams::AnnotationParams(const AnnotationParams &rhs) : ParamsBase(rhs) { _axisAnnotations = new ParamsContainer(*(rhs._axisAnnotations)); }\n\nvoid AnnotationParams::_init()\n{\n    SetDomainColor({1.0,1.0,1.0});\n    SetRegionColor({1.0,0.0,0.0});\n    SetBackgroundColor({0.118,0.118,0.118});\n    SetUseRegionFrame(false);\n    SetUseDomainFrame(true);\n    SetValueLong(AxisArrowEnabledTag, \"Initializing AxisArrowEnabledTag\", 0);\n    SetValueDouble(AxisArrowSizeTag, \"Initializing AxisArrowSizeTag\", .2);\n    SetValueDouble(AxisArrowXPosTag, \"Initializing AxisArrowXPosTag\", .05);\n    SetValueDouble(AxisArrowYPosTag, \"Initializing AxisArrowYPosTag\", .05);\n    SetValueDouble(_timeLLXTag, \"Initializing timestep llx coordinate\", 0.01);\n    SetValueDouble(_timeLLYTag, \"Initializing timestep lly coordinate\", 0.01);\n    SetValueLong(_timeSizeTag, \"Initializing timestep font size\", 24);\n    SetValueDoubleVec(_timeColorTag, \"Initializing timestep color\", {1., 1., 1.});\n    SetValueLong(_latLonAxesTag, \"Initializing axis annotation enabled default\", 0);\n}\n\nvoid AnnotationParams::_getColor(vector<double> &color, string tag) const\n{\n    color.clear();\n\n    vector<double> defaultv(3, 1.0);\n    color = GetValueDoubleVec(tag, defaultv);\n    for (int i = 0; i < color.size(); i++) {\n        if (color[i] < 0.0) color[i] = 0.0;\n        if (color[i] > 1.0) color[i] = 1.0;\n    }\n}\n\nvoid AnnotationParams::m_setColor(vector<double> color, string tag, string msg)\n{\n    VAssert(color.size() == 3);\n    for (int i = 0; i < color.size(); i++) {\n        if (color[i] < 0.0) color[i] = 0.0;\n        if (color[i] > 1.0) color[i] = 1.0;\n    }\n    SetValueDoubleVec(tag, msg, color);\n}\n\nvoid AnnotationParams::GetDomainColor(double color[3]) const { m_getColor(color, _domainColorTag); }\n\nvoid AnnotationParams::SetDomainColor(vector<double> color) { m_setColor(color, _domainColorTag, \"Set domain frame color\"); }\n\nvoid AnnotationParams::GetRegionColor(double color[3]) const { m_getColor(color, _regionColorTag); }\n\nvoid AnnotationParams::SetRegionColor(vector<double> color) { m_setColor(color, _regionColorTag, \"Set region frame color\"); }\n\nvoid AnnotationParams::GetBackgroundColor(double color[3]) const { m_getColor(color, _backgroundColorTag); }\n\nvoid AnnotationParams::SetBackgroundColor(vector<double> color) { m_setColor(color, _backgroundColorTag, \"Set background color\"); }\n\nstring AnnotationParams::GetCurrentAxisDataMgrName() const { return GetValueString(_currentAxisDataMgrTag, defaultAnnotation); }\n\nvoid AnnotationParams::SetCurrentAxisDataMgrName(string dmName)\n{\n    string msg = \"Setting current DataMgr w.r.t. axis annotations\";\n    SetValueString(_currentAxisDataMgrTag, msg, dmName);\n}\n\nAxisAnnotation *AnnotationParams::GetAxisAnnotation()\n{\n    vector<string> names = _axisAnnotations->GetNames();\n    if (_axisAnnotations->GetParams(defaultAnnotation) == NULL) {\n        AxisAnnotation newAnnotation(_ssave);\n        _axisAnnotations->Insert(&newAnnotation, defaultAnnotation);\n    }\n    AxisAnnotation *aa;\n    aa = (AxisAnnotation *)_axisAnnotations->GetParams(defaultAnnotation);\n    if (!aa->GetAxisAnnotationInitialized()) { aa->Initialize(); }\n    return aa;\n}\n\nvoid AnnotationParams::SetAxisArrowEnabled(bool enabled) { SetValueLong(AxisArrowEnabledTag, \"Set axis arrow to enabled/disabled\", (long)enabled); }\n\nvoid AnnotationParams::SetAxisArrowSize(double val) { SetValueDouble(AxisArrowSizeTag, \"Set axis arrow size\", val); }\n\nvoid AnnotationParams::SetAxisArrowXPos(double val) { SetValueDouble(AxisArrowXPosTag, \"Set axis arrow X coordinate\", val); }\n\nvoid AnnotationParams::SetAxisArrowYPos(double val) { SetValueDouble(AxisArrowYPosTag, \"Set axis arrow Y coordinate\", val); }\n\nbool AnnotationParams::GetAxisArrowEnabled() const { return (bool)GetValueLong(AxisArrowEnabledTag, false); }\n\ndouble AnnotationParams::GetAxisArrowSize() const { return GetValueDouble(AxisArrowSizeTag, .2); }\n\ndouble AnnotationParams::GetAxisArrowXPos() const { return GetValueDouble(AxisArrowXPosTag, .05); }\n\ndouble AnnotationParams::GetAxisArrowYPos() const { return GetValueDouble(AxisArrowYPosTag, .05); }\n\ndouble AnnotationParams::GetTimeLLX() const { return GetValueDouble(_timeLLXTag, 0.01); }\n\nvoid AnnotationParams::SetTimeLLX(double llx) { SetValueDouble(_timeLLXTag, \"Timestep llx coordinate\", llx); }\n\ndouble AnnotationParams::GetTimeLLY() const { return GetValueDouble(_timeLLYTag, 0.01); }\n\nvoid AnnotationParams::SetTimeLLY(double lly) { SetValueDouble(_timeLLYTag, \"Timestep lly coordinate\", lly); }\n\nstd::vector<double> AnnotationParams::GetTimeColor() const\n{\n    std::vector<double> defaultv(3, 1.0);\n    std::vector<double> val = GetValueDoubleVec(_timeColorTag, defaultv);\n    return val;\n}\n\nvoid AnnotationParams::SetTimeColor(vector<double> color) { SetValueDoubleVec(_timeColorTag, \"Timestep color\", color); }\n\nint AnnotationParams::GetTimeType() const { return (int)GetValueLong(_timeTypeTag, 0); }\n\nvoid AnnotationParams::SetTimeType(int type) { SetValueLong(_timeTypeTag, \"Timestep annotation type\", type); }\n\nint AnnotationParams::GetTimeSize() const { return (int)GetValueDouble(_timeSizeTag, 24); }\n\nvoid AnnotationParams::SetTimeSize(int size) { SetValueDouble(_timeSizeTag, \"Timestep font size\", size); }\n"
  },
  {
    "path": "lib/params/AxisAnnotation.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tAxisAnnotation.cpp\n//\n//\tAuthor:\t\tScott Pearse\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tMay 2017\n//\n//\tDescription:\tImplements the AxisAnnotation class\n//\t\tImplements axis annotation ParamsContainer, which stores parameters\n//\t\tfor Renderers or DataMgrs to draw axes.\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n#include <vapor/AxisAnnotation.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nconst string AxisAnnotation::_backgroundColorTag = \"BackgroundColor\";\nconst string AxisAnnotation::_annotationEnabledTag = \"AxisAnnotation\";\nconst string AxisAnnotation::_colorTag = \"AxisColor\";\nconst string AxisAnnotation::_digitsTag = \"AxisDigits\";\nconst string AxisAnnotation::_textHeightTag = \"AxisTextHeight\";\nconst string AxisAnnotation::_fontSizeTag = \"AxisFontSize\";\nconst string AxisAnnotation::_ticWidthTag = \"TicWidths\";\nconst string AxisAnnotation::_ticDirsTag = \"TicDirections\";\nconst string AxisAnnotation::_ticSizeTag = \"TicSizes\";\nconst string AxisAnnotation::_minTicsTag = \"TicMinPositions\";\nconst string AxisAnnotation::_maxTicsTag = \"TicMaxPositions\";\nconst string AxisAnnotation::_numTicsTag = \"NumberTics\";\nconst string AxisAnnotation::_dataMgrTag = \"AxisDataMgr\";\nconst string AxisAnnotation::_latLonAxesTag = \"LatLonAxes\";\nconst string AxisAnnotation::_originTag = \"AxisOrigin\";\nconst string AxisAnnotation::_initializedTag = \"AxisAnnotaitonInitialized\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<AxisAnnotation> registrar(AxisAnnotation::GetClassType());\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nAxisAnnotation::AxisAnnotation(ParamsBase::StateSave *ssave) : ParamsBase(ssave, AxisAnnotation::GetClassType()) {}\n\nAxisAnnotation::AxisAnnotation(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nAxisAnnotation::~AxisAnnotation() { MyBase::SetDiagMsg(\"AxisAnnotation::~AxisAnnotation() this=%p\", this); }\n\nvoid AxisAnnotation::Initialize()\n{\n    vector<double> minExts(3, 0.0);\n    vector<double> maxExts(3, 1.0);\n\n    SetMinTics(minExts);\n    SetMaxTics(maxExts);\n    SetAxisOrigin(minExts);\n    SetValueDoubleVec(_backgroundColorTag, \"Axis annotation background color\", {0.0, 0.0, 0.0});\n    SetValueDoubleVec(_colorTag, \"Axis annotation text color\", {1.0, 1.0, 1.0});\n    SetValueLong(_fontSizeTag, \"Axis annotation font size\", 24);\n    SetValueLong(_digitsTag, \"Set axis num digits\", 2);\n    SetTicWidth(1);\n    SetAxisAnnotationInitialized(true);\n}\n\nvoid AxisAnnotation::SetAxisAnnotationEnabled(bool val)\n{\n    string msg = \"Toggle axis annotation on/off\";\n    SetValueLong(_annotationEnabledTag, msg, (long)val);\n}\n\nbool AxisAnnotation::GetAxisAnnotationEnabled() const { return (0 != GetValueLong(_annotationEnabledTag, (long)false)); }\n\nstd::vector<double> AxisAnnotation::GetAxisBackgroundColor() const\n{\n    vector<double> defaultv(4, 0.0);\n    vector<double> val = GetValueDoubleVec(_backgroundColorTag, defaultv);\n    if (val == defaultv) val[3] = 1.f;\n    return val;\n}\n\nvoid AxisAnnotation::SetAxisBackgroundColor(std::vector<double> color)\n{\n    string msg = \"Axis annotation background color\";\n    if (color.size() == 3) color.push_back(1.f);\n    SetValueDoubleVec(_backgroundColorTag, msg, color);\n}\n\nstd::vector<double> AxisAnnotation::GetAxisColor() const\n{\n    vector<double> defaultv(4, 1.0);\n    vector<double> val = GetValueDoubleVec(_colorTag, defaultv);\n    return val;\n}\n\nvoid AxisAnnotation::SetAxisColor(std::vector<double> color)\n{\n    return;\n    string msg = \"Axis annotation text color\";\n    SetValueDoubleVec(_colorTag, msg, color);\n}\n\nvoid AxisAnnotation::SetNumTics(std::vector<double> num)\n{\n    VAssert(num.size() >= 2);\n    for (int i = 0; i < num.size(); i++) {\n        if (num[i] < 0) num[i] = 0;\n        if (num[i] > 100) num[i] = 100;\n    }\n\n    SetValueDoubleVec(_numTicsTag, \"Set number of axis tics\", num);\n}\n\nstd::vector<double> AxisAnnotation::GetNumTics() const\n{\n    vector<double> defaultv = {3, 3, 2};\n    vector<double> val = GetValueDoubleVec(_numTicsTag, defaultv);\n\n    for (int i = 0; i < val.size(); i++) {\n        if (val[i] < 0) val[i] = 0;\n        if (val[i] > 100) val[i] = 100;\n    }\n    return (val);\n}\n\nvoid AxisAnnotation::SetAxisOrigin(vector<double> orig)\n{\n    VAssert(orig.size() >= 2);\n    SetValueDoubleVec(_originTag, \"Set axis val\", orig);\n}\n\nvector<double> AxisAnnotation::GetAxisOrigin() const\n{\n    vector<double> defaultv(3, 0.0);\n    return GetValueDoubleVec(_originTag, defaultv);\n}\n\nvoid AxisAnnotation::SetMinTics(vector<double> ticMin)\n{\n    VAssert(ticMin.size() >= 2);\n    SetValueDoubleVec(_minTicsTag, \"Set minimum tics\", ticMin);\n}\n\nvector<double> AxisAnnotation::GetMinTics() const\n{\n    vector<double> defaultv(3, 0.0);\n    return GetValueDoubleVec(_minTicsTag, defaultv);\n}\n\nvoid AxisAnnotation::SetMaxTics(vector<double> ticMax)\n{\n    VAssert(ticMax.size() >= 2);\n    SetValueDoubleVec(_maxTicsTag, \"Set maximum tics\", ticMax);\n}\n\nvector<double> AxisAnnotation::GetMaxTics() const\n{\n    vector<double> defaultv(3, 1.0);\n    vector<double> myVec = GetValueDoubleVec(_maxTicsTag, defaultv);\n    return myVec;\n}\n\nvoid AxisAnnotation::SetTicSize(vector<double> ticSizes)\n{\n    VAssert(ticSizes.size() >= 2);\n    SetValueDoubleVec(_ticSizeTag, \"Set tic sizes\", ticSizes);\n}\n\nvector<double> AxisAnnotation::GetTicSize() const\n{\n    vector<double> defaultv(3, 0.05);\n    return GetValueDoubleVec(_ticSizeTag, defaultv);\n}\n\nvoid AxisAnnotation::SetXTicDir(double dir)\n{\n    std::vector<double> v = GetTicDirs();\n    v[0] = dir;\n    SetTicDirs(v);\n}\n\nint AxisAnnotation::GetXTicDir() const { return GetTicDirs()[0]; }\n\nint AxisAnnotation::GetYTicDir() const { return GetTicDirs()[1]; }\n\nint AxisAnnotation::GetZTicDir() const { return GetTicDirs()[2]; }\n\nvoid AxisAnnotation::SetYTicDir(double dir)\n{\n    std::vector<double> v = GetTicDirs();\n    v[1] = dir;\n    SetTicDirs(v);\n}\n\nvoid AxisAnnotation::SetZTicDir(double dir)\n{\n    std::vector<double> v = GetTicDirs();\n    v[2] = dir;\n    SetTicDirs(v);\n}\n\nvoid AxisAnnotation::SetTicDirs(vector<double> ticDirs)\n{\n    VAssert(ticDirs.size() >= 2);\n    SetValueDoubleVec(_ticDirsTag, \"Set tic direction\", ticDirs);\n}\n\nvector<double> AxisAnnotation::GetTicDirs() const\n{\n    vector<double> defaultv(3, 0);\n    defaultv[0] = 1;\n    return GetValueDoubleVec(_ticDirsTag, defaultv);\n}\n\ndouble AxisAnnotation::GetTicWidth() const { return GetValueDouble(_ticWidthTag, 1.0); }\n\nvoid AxisAnnotation::SetTicWidth(double width)\n{\n    if (width < 1) width = 1;\n    SetValueDouble(_ticWidthTag, \"Set tic width\", width);\n}\n\nlong AxisAnnotation::GetAxisTextHeight() const { return GetValueLong(_textHeightTag, 10); }\n\nvoid AxisAnnotation::SetAxisTextHeight(long height)\n{\n    if (height < 1) height = 1;\n    SetValueLong(_textHeightTag, \"Set axis text height\", height);\n}\n\nlong AxisAnnotation::GetAxisDigits() const { return GetValueLong(_digitsTag, 2); }\n\nvoid AxisAnnotation::SetAxisDigits(long numDigits)\n{\n    if (numDigits < 0) numDigits = 4;\n    SetValueLong(_digitsTag, \"Set axis num digits\", numDigits);\n}\n\nvoid AxisAnnotation::SetLatLonAxesEnabled(bool val) { SetValueLong(_latLonAxesTag, \"toggle axes lat/lon\", (long)val); }\n\nbool AxisAnnotation::GetLatLonAxesEnabled() const { return (0 != GetValueLong(_latLonAxesTag, (long)false)); }\n\nstring AxisAnnotation::GetDataMgrName() const { return GetValueString(_dataMgrTag, \"\"); }\n\nvoid AxisAnnotation::SetDataMgrName(string dataMgr)\n{\n    string msg = \"Set DataManager currently associated \"\n                 \"with the axis annotations\";\n    SetValueString(_dataMgrTag, msg, dataMgr);\n}\n\nvoid AxisAnnotation::SetAxisFontSize(int size) { SetValueDouble(_fontSizeTag, \"Axis annotation font size\", size); }\n\nint AxisAnnotation::GetAxisFontSize() const { return (int)GetValueDouble(_fontSizeTag, 16); }\n\nvoid AxisAnnotation::SetAxisAnnotationInitialized(bool val)\n{\n    string msg = \"Axis annotation object initialized\";\n    SetValueDouble(_initializedTag, msg, val);\n}\n\nbool AxisAnnotation::GetAxisAnnotationInitialized() const { return (bool)GetValueDouble(_initializedTag, false); }\n"
  },
  {
    "path": "lib/params/BarbParams.cpp",
    "content": "\n#include <string>\n#include <vapor/RenderParams.h>\n#include <vapor/BarbParams.h>\n#include <vapor/DataMgrUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n#define X 0\n#define Y 1\n#define Z 2\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<BarbParams> registrar(BarbParams::GetClassType());\n\nconst string BarbParams::_needToRecalculateScalesTag = \"NeedToRecalc\";\nconst string BarbParams::_thicknessScaleTag = \"LineThickness\";\nconst string BarbParams::_lengthScaleTag = \"VectorScale\";\nconst string BarbParams::_xBarbsCountTag = \"BarbsCountTag_X\";\nconst string BarbParams::_yBarbsCountTag = \"BarbsCountTag_Y\";\nconst string BarbParams::_zBarbsCountTag = \"BarbsCountTag_Z\";\nconst string BarbParams::_alignGridTag = \"GridAlignedToData\";\nconst string BarbParams::_alignGridStridesTag = \"GridAlignedStrides\";\nconst string BarbParams::_varsAre3dTag = \"VarsAre3D\";\n\nBarbParams::BarbParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, BarbParams::GetClassType())\n{\n    SetDiagMsg(\"BarbParams::BarbParams() this=%p\", this);\n\n    _init();\n}\n\nBarbParams::BarbParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node) {}\n\nBarbParams::~BarbParams() { SetDiagMsg(\"BarbParams::~BarbParams() this=%p\", this); }\n\nvoid BarbParams::SetNeedToRecalculateScales(bool val)\n{\n    double dval = val ? 1.0 : 0.0;\n    SetValueDouble(_needToRecalculateScalesTag, \"Whether or not scales need to be recalculated\", dval);\n}\n\nvoid BarbParams::_init()\n{\n    SetDiagMsg(\"BarbParams::_init()\");\n\n    SetVariableName(\"\");\n    SetUseSingleColor(false);\n    float rgb[] = {1.f, 1.f, 1.f};\n    SetConstantColor(rgb);\n    int grid[] = {10, 10, 1};\n    SetGrid(grid);\n    SetLineThickness(1);\n    SetLengthScale(1);\n    SetValueLong(RenderParams::LightingEnabledTag, \"Enable Barb lighting by default\", 1);\n}\n"
  },
  {
    "path": "lib/params/BookmarkParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tBookmarkParams.cpp\n//\n//\tAuthor:\t\tStas Jaroszynski\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n\n#include <vapor/BookmarkParams.h>\n\nusing namespace VAPoR;\n\nconst string BookmarkParams::NameTag = \"NameTag\";\nconst string BookmarkParams::DataTag = \"DataTag\";\nconst string BookmarkParams::IconDataTag = \"IconDataTag\";\nconst string BookmarkParams::IconSizeTag = \"IconSizeTag\";\n\nstatic ParamsRegistrar<BookmarkParams> registrar(BookmarkParams::GetClassType());\n\nvoid BookmarkParams::_init() {}\n\nBookmarkParams::BookmarkParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, GetClassType()) { _init(); }\n\nBookmarkParams::BookmarkParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    if (node->GetTag() != BookmarkParams::GetClassType()) {\n        node->SetTag(BookmarkParams::GetClassType());\n        _init();\n    }\n}\n\nBookmarkParams::BookmarkParams(const BookmarkParams &rhs) : ParamsBase(rhs) {}\n"
  },
  {
    "path": "lib/params/Box.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2011\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tBox.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tApril 2011\n//\n//\tDescription:\tImplements the Box class.\n//\t\tUsed to control extents and orientation of 2D and 3D data regions.\n//\t\tSupports time-varying extents.\n//\n\n#include <cfloat>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <vapor/Grid.h>\n#include <vapor/Box.h>\n\nusing namespace std;\nusing namespace VAPoR;\nusing namespace Wasp;\n\nconst std::string Box::m_anglesTag = \"Angles\";\nconst std::string Box::m_extentsTag = \"Extents\";\nconst std::string Box::m_planarTag = \"Planar\";\nconst std::string Box::m_orientationTag = \"Orientation\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<Box> registrar(Box::GetClassType());\n\nBox::Box(ParamsBase::StateSave *ssave, string name) : ParamsBase(ssave, name)\n{\n    MyBase::SetDiagMsg(\"Box::Box() this=%p\", this);\n\n    // Initialize with default box:\n    //\n    SetPlanar(false);\n\n    vector<double> minExt, maxExt;\n    for (int i = 0; i < 3; i++) minExt.push_back(0.0);\n    for (int i = 0; i < 3; i++) maxExt.push_back(1.0);\n    SetExtents(minExt, maxExt);\n\n    vector<double> angles;\n    angles.push_back(0.);\n    angles.push_back(0.);\n    angles.push_back(0.);\n    SetAngles(angles);\n\n    SetOrientation(XYZ);\n}\n\nBox::Box(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\nBox::~Box() { MyBase::SetDiagMsg(\"Box::~Box() this=%p\", this); }\n\nvoid Box::SetExtents(const vector<double> &minExt, const vector<double> &maxExt)\n{\n    VAssert(minExt.size() == maxExt.size());\n\n    vector<double> exts;\n    for (int i = 0; i < minExt.size(); i++) exts.push_back(minExt[i]);\n    for (int i = minExt.size(); i < 3; i++) exts.push_back(0.0);\n\n    for (int i = 0; i < maxExt.size(); i++) exts.push_back(maxExt[i]);\n    for (int i = maxExt.size(); i < 3; i++) exts.push_back(0.0);\n\n    SetValueDoubleVec(m_extentsTag, \"Set box extents\", exts);\n}\n\nvoid Box::SetExtents(const VAPoR::CoordType &minExt, const VAPoR::CoordType &maxExt)\n{\n    vector<double> mind(3, 0), maxd(3, 0);\n    for (int i = 0; i < minExt.size(); i++) {\n        mind[i] = minExt[i];\n        maxd[i] = maxExt[i];\n    }\n    SetExtents(mind, maxd);\n}\n\nvoid Box::GetExtents(vector<double> &minExt, vector<double> &maxExt) const\n{\n    minExt.clear();\n    maxExt.clear();\n    minExt.reserve(3);\n    maxExt.reserve(3);\n\n    vector<double> defaultv;\n    defaultv.reserve(6);\n    for (int i = 0; i < 3; i++) defaultv.push_back(0.0);\n    for (int i = 0; i < 3; i++) defaultv.push_back(1.0);\n\n    // exts is guaranteed to have the same number of elements as\n    // defaultv\n    //\n    vector<double> exts = GetValueDoubleVec(m_extentsTag, defaultv);\n\n    int n = IsPlanar() ? 2 : 3;\n    for (int i = 0; i < n; i++) minExt.push_back(exts[i]);\n    for (int i = 0; i < n; i++) maxExt.push_back(exts[i + 3]);\n}\n\nvoid Box::GetExtents(VAPoR::CoordType &minExt, VAPoR::CoordType &maxExt) const\n{\n    minExt = {0.0, 0.0, 0.0};\n    maxExt = {0.0, 0.0, 0.0};\n\n    vector<double> defaultv = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};\n    // exts is guaranteed to have the same number of elements as\n    // defaultv\n    //\n    vector<double> exts = GetValueDoubleVec(m_extentsTag, defaultv);\n\n    int n = 3;\n    for (int i = 0; i < n; i++) minExt[i] = exts[i];\n    for (int i = 0; i < n; i++) maxExt[i] = exts[i + 3];\n}\n\nvoid Box::SetPlanar(bool value)\n{\n    SetValueLong(Box::m_planarTag, \"Set box planar value\", (long)value);\n    //    SetValueLong(m_orientationTag, \"\", value?XYZ:XY);\n}\n\nbool Box::IsPlanar() const\n{\n    return GetValueLong(Box::m_planarTag, (long)false);\n    //    return GetValueLong(Box::m_orientationTag, XY);\n}\n\n#ifdef VAPOR3_0_0_ALPHA\nint Box::GetStretchedLocalExtents(double extents[6], int timestep)\n{\n    double exts[6];\n    int    rc = GetLocalExtents(exts, timestep);\n    if (rc) return rc;\n    vector<double> stretch = _dataStatus->getStretchFactors();\n    for (int i = 0; i < 6; i++) extents[i] = exts[i] * stretch[i % 3];\n    return 0;\n}\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\nint Box::SetStretchedLocalExtents(const double extents[6], int timestep)\n{\n    vector<double> exts;\n    vector<double> stretch = _dataStatus->getStretchFactors();\n    for (int i = 0; i < 6; i++) exts.push_back((double)(extents[i] / stretch[i % 3]));\n    SetLocalExtents(exts, timestep);\n}\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\nvoid Box::buildLocalCoordTransform(double transformMatrix[12], double extraThickness, int timestep, double rotation, int axis) const\n{\n    double theta, phi, psi;\n    if (rotation != 0.) {\n        convertThetaPhiPsi(&theta, &phi, &psi, axis, rotation);\n    } else {\n        vector<double> angles = GetAngles();\n        theta = angles[0];\n        phi = angles[1];\n        psi = angles[2];\n    }\n\n    double boxSize[3];\n    double boxExts[6];\n    GetLocalExtents(boxExts, timestep);\n\n    for (int i = 0; i < 3; i++) {\n        boxExts[i] -= extraThickness;\n        boxExts[i + 3] += extraThickness;\n        boxSize[i] = (boxExts[i + 3] - boxExts[i]);\n    }\n\n    // Get the 3x3 rotation matrix:\n    double rotMatrix[9];\n    getRotationMatrix(theta * M_PI / 180., phi * M_PI / 180., psi * M_PI / 180., rotMatrix);\n\n    // then scale according to box:\n    transformMatrix[0] = 0.5 * boxSize[0] * rotMatrix[0];\n    transformMatrix[1] = 0.5 * boxSize[1] * rotMatrix[1];\n    transformMatrix[2] = 0.5 * boxSize[2] * rotMatrix[2];\n    // 2nd row:\n    transformMatrix[4] = 0.5 * boxSize[0] * rotMatrix[3];\n    transformMatrix[5] = 0.5 * boxSize[1] * rotMatrix[4];\n    transformMatrix[6] = 0.5 * boxSize[2] * rotMatrix[5];\n    // 3rd row:\n    transformMatrix[8] = 0.5 * boxSize[0] * rotMatrix[6];\n    transformMatrix[9] = 0.5 * boxSize[1] * rotMatrix[7];\n    transformMatrix[10] = 0.5 * boxSize[2] * rotMatrix[8];\n    // last column, i.e. translation:\n    transformMatrix[3] = .5 * (boxExts[3] + boxExts[0]);\n    transformMatrix[7] = .5 * (boxExts[4] + boxExts[1]);\n    transformMatrix[11] = .5 * (boxExts[5] + boxExts[2]);\n}\n\n// Determine a new value of theta phi and psi when the probe is rotated around either the\n// x-, y-, or z- axis.  axis is 0,1,or 2 1. rotation is in degrees.\n// newTheta and newPhi are in degrees, with theta between -180 and 180, phi between 0 and 180\n// and newPsi between -180 and 180\nvoid Box::convertThetaPhiPsi(double *newTheta, double *newPhi, double *newPsi, int axis, double rotation) const\n{\n    // First, get original rotation matrix R0(theta, phi, psi)\n    double         origMatrix[9], axisRotate[9], newMatrix[9];\n    vector<double> angles = GetAngles();\n    getRotationMatrix(angles[0] * M_PI / 180., angles[1] * M_PI / 180., angles[2] * M_PI / 180., origMatrix);\n    // Second, get rotation matrix R1(axis,rotation)\n    getAxisRotation(axis, rotation * M_PI / 180., axisRotate);\n    // New rotation matrix is R1*R0\n    mmult33(axisRotate, origMatrix, newMatrix);\n    // Calculate newTheta, newPhi, newPsi from R1*R0\n    getRotAngles(newTheta, newPhi, newPsi, newMatrix);\n    // Convert back to degrees:\n    (*newTheta) *= (180. / M_PI);\n    (*newPhi) *= (180. / M_PI);\n    (*newPsi) *= (180. / M_PI);\n    return;\n}\n\n// Following calculates box corners in user space.  Does not use\n// stretching.\nvoid Box::calcLocalBoxCorners(double corners[8][3], float extraThickness, int timestep, double rotation, int axis) const\n{\n    double transformMatrix[12];\n    buildLocalCoordTransform(transformMatrix, extraThickness, timestep, rotation, axis);\n    double boxCoord[3];\n    // Return the corners of the box (in world space)\n    // Go counter-clockwise around the back, then around the front\n    // X increases fastest, then y then z;\n\n    // Fatten box slightly, in case it is degenerate.  This will\n    // prevent us from getting invalid face normals.\n\n    boxCoord[0] = -1.f;\n    boxCoord[1] = -1.f;\n    boxCoord[2] = -1.f;\n    vtransform(boxCoord, transformMatrix, corners[0]);\n    boxCoord[0] = 1.f;\n    vtransform(boxCoord, transformMatrix, corners[1]);\n    boxCoord[1] = 1.f;\n    vtransform(boxCoord, transformMatrix, corners[3]);\n    boxCoord[0] = -1.f;\n    vtransform(boxCoord, transformMatrix, corners[2]);\n    boxCoord[1] = -1.f;\n    boxCoord[2] = 1.f;\n    vtransform(boxCoord, transformMatrix, corners[4]);\n    boxCoord[0] = 1.f;\n    vtransform(boxCoord, transformMatrix, corners[5]);\n    boxCoord[1] = 1.f;\n    vtransform(boxCoord, transformMatrix, corners[7]);\n    boxCoord[0] = -1.f;\n    vtransform(boxCoord, transformMatrix, corners[6]);\n}\n\n// Find the smallest stretched extents containing the rotated box\n// Similar to above, using stretched extents\nvoid Box::calcRotatedStretchedBoxExtents(vector<double> stretchFactors, double *bigBoxExtents) const\n{\n    // Determine the smallest axis-aligned cube that contains the probe.  This is\n    // obtained by mapping all 8 corners into the space.\n    // It will not necessarily fit inside the unit cube.\n    double corners[8][3];\n    calcLocalBoxCorners(corners, 0.f, -1);\n\n    double boxMin[3], boxMax[3];\n    int    crd, cor;\n\n    // initialize extents, and variables that will be min,max\n    for (crd = 0; crd < 3; crd++) {\n        boxMin[crd] = DBL_MAX;\n        boxMax[crd] = -DBL_MAX;\n    }\n\n    for (cor = 0; cor < 8; cor++) {\n        // make sure the container includes it:\n        for (crd = 0; crd < 3; crd++) {\n            if (corners[cor][crd] < boxMin[crd]) boxMin[crd] = corners[cor][crd];\n            if (corners[cor][crd] > boxMax[crd]) boxMax[crd] = corners[cor][crd];\n        }\n    }\n\n    for (crd = 0; crd < 3; crd++) {\n        bigBoxExtents[crd] = (boxMin[crd] * stretchFactors[crd]);\n        bigBoxExtents[crd + 3] = (boxMax[crd] * stretchFactors[crd]);\n    }\n}\n\n// Find the smallest extents containing the rotated box\nvoid Box::calcRotatedBoxExtents(double *bigBoxExtents) const\n{\n    // Determine the smallest axis-aligned cube that contains the probe.  This is\n    // obtained by mapping all 8 corners into the space.\n    // It will not necessarily fit inside the unit cube.\n    double corners[8][3];\n    calcLocalBoxCorners(corners, 0.f, -1);\n\n    double boxMin[3], boxMax[3];\n    int    crd, cor;\n\n    // initialize extents, and variables that will be min,max\n    for (crd = 0; crd < 3; crd++) {\n        boxMin[crd] = DBL_MAX;\n        boxMax[crd] = -DBL_MAX;\n    }\n\n    for (cor = 0; cor < 8; cor++) {\n        // make sure the container includes it:\n        for (crd = 0; crd < 3; crd++) {\n            if (corners[cor][crd] < boxMin[crd]) boxMin[crd] = corners[cor][crd];\n            if (corners[cor][crd] > boxMax[crd]) boxMax[crd] = corners[cor][crd];\n        }\n    }\n    // Now convert the min,max back into extents\n\n    for (crd = 0; crd < 3; crd++) {\n        bigBoxExtents[crd] = boxMin[crd];\n        bigBoxExtents[crd + 3] = boxMax[crd];\n    }\n}\n\n// Clip the probe to the specified box extents\n// Return false (and make no change) if the probe rectangle does not have a positive (rectangular)\n// intersection in the box.\n\nbool Box::cropToBox(const double bxExts[6])\n{\n    // 0.  Initially need a startPoint that is in the box and on the probe center plane.\n    // 1.  Check if probe center works.  If not call intersectRotatedBox() to get another startPoint (on middle plane) inside box.\n    // 2.  Using the new startPoint, construct x-direction line.  Find its first two intersections (+ and -) with box.  Reset the start point to be the\n    //\t\tmiddle of the resulting line segment.\n    // 3.  Construct the y-direction line from the new startPoint.  Again find first + and - intersection points.\n    // 4.  Take 4 diagonals of x- and y- direction lines, find first box intersection (or corner if box intersection is after corner.\n    // 5.  find largest rectangle inside four diagonal points.  Use this as the new probe.\n\n    // Transform the four probe corners to local region\n    double transformMatrix[12];\n    double prCenter[3];    // original probe center in world coords\n    double startPoint[3];\n    double pmid[3] = {0., 0., 0.};\n    double pxp[3] = {1., 0., 0.};\n    double pyp[3] = {0., 1., 0.};\n    double psize[2];\n    double prbexts[4];    // probe extents relative to startPoint, in the 2 probe axis directions.\n    double probeCoords[2] = {0., 0.};\n    double pendx[3], pendy[3];\n\n    double exts[6];\n    GetLocalExtents(exts);\n\n    double boxExts[6];\n    // shrink box slightly, otherwise errors occur with highly stretched domains.\n    for (int i = 0; i < 3; i++) {\n        boxExts[i] = bxExts[i] + (bxExts[i + 3] - bxExts[i]) * 1.e-4;\n        boxExts[i + 3] = bxExts[i + 3] - (bxExts[i + 3] - bxExts[i]) * 1.e-4;\n    }\n    buildLocalCoordTransform(transformMatrix, 0.f, -1);\n    // initially set startPoint to probe center:\n    vtransform(pmid, transformMatrix, startPoint);\n    vcopy(startPoint, prCenter);\n    // Determine probe size in world coords.\n    vtransform(pxp, transformMatrix, pendx);\n    vtransform(pyp, transformMatrix, pendy);\n    vsub(pendx, startPoint, pendx);\n    vsub(pendy, startPoint, pendy);\n    psize[0] = vlength(pendx);\n    psize[1] = vlength(pendy);\n    prbexts[2] = vlength(pendx);\n    prbexts[3] = vlength(pendy);\n    prbexts[0] = -prbexts[2];\n    prbexts[1] = -prbexts[3];\n\n    // Get direction vectors for rotated probe\n    double                rotMatrix[9];\n    const vector<double> &angles = GetAngles();\n    getRotationMatrix((float)(angles[0] * M_PI / 180.), (float)(angles[1] * M_PI / 180.), (float)(angles[2] * M_PI / 180.), rotMatrix);\n    // determine the probe x- and y- direction vectors\n    double vecx[3] = {1., 0., 0.};\n    double vecy[3] = {0., 1., 0.};\n    // Direction vectors:\n    double dir[4][3];\n    // Intersection parameters\n    double result[4][2];\n    double edgeDist[4];    // distances from start point to probe edges\n\n    // Construct 2 rays in x-axis directions\n    vtransform3(vecx, rotMatrix, dir[0]);\n    vtransform3(vecy, rotMatrix, dir[1]);\n    vnormal(dir[0]);\n    vnormal(dir[1]);\n\n    // also negate:\n    vmult(dir[0], -1.f, dir[2]);\n    vmult(dir[1], -1.f, dir[3]);\n\n    // Test:  is startPoint inside box?\n    bool pointInBox = true;\n    for (int i = 0; i < 3; i++) {\n        if (startPoint[i] < boxExts[i]) {\n            pointInBox = false;\n            break;\n        }\n        if (startPoint[i] > boxExts[i + 3]) {\n            pointInBox = false;\n            break;\n        }\n    }\n    if (!pointInBox) {\n        pointInBox = intersectRotatedBox(boxExts, startPoint, probeCoords);\n        if (!pointInBox) return false;\n        // Modify prbexts to have probe exts relative to new value of startPoint\n        // probeCoords values are along the dir[0] and dir[1] directions, with a value of +1 indicating the probe x-width\n        // Thus the startPoint in world coords is\n        // prCenter + psize[0]*probeCoords[0]*dir[0] + psize[1]*probeCoords[1]*dir[1]\n        // and the probe extents are similarly translated:\n        prbexts[0] = prbexts[0] - probeCoords[0] * psize[0];\n        prbexts[2] = prbexts[2] - probeCoords[0] * psize[0];\n        prbexts[1] = prbexts[1] - probeCoords[1] * psize[1];\n        prbexts[3] = prbexts[3] - probeCoords[1] * psize[1];\n    }\n\n    // Shoot rays in axis directions from startPoint.\n\n    // Intersect each line with the box, get the nearest intersections\n    int numpts;\n    for (int i = 0; i < 4; i += 2) {\n        numpts = rayBoxIntersect(startPoint, dir[i], boxExts, result[i]);\n        // Each ray should have two intersection points with the box\n        if (numpts < 2 || result[i][1] < 0.0) return false;\n\n        // find the distance from the start point to the second intersection point\n        double interpt[3];\n        // calculate the intersection point\n        for (int j = 0; j < 3; j++) { interpt[j] = result[i][1] * dir[i][j] + startPoint[j]; }\n        // find the distances from the intersection points to starting point\n        for (int j = 0; j < 3; j++) { interpt[j] = interpt[j] - startPoint[j]; }\n        edgeDist[i] = vlength(interpt);\n        // shorten the distance if it exceeds the probe extent in that direction\n        if (i == 0 && edgeDist[i] > prbexts[2]) edgeDist[i] = prbexts[2];\n        if (i == 2 && edgeDist[i] > -prbexts[0]) edgeDist[i] = -prbexts[0];\n    }\n    // Find the midpoint of the line connecting the x intersections\n    double midDist = edgeDist[0] - edgeDist[2];\n    // Move startPoint  to the center\n    for (int i = 0; i < 3; i++) { startPoint[i] = startPoint[i] + dir[0][i] * midDist * 0.5; }\n    // Modify edgeDist so that the new startPoint is the center.\n    edgeDist[0] = edgeDist[2] = 0.5 * (edgeDist[0] + edgeDist[2]);\n\n    // Now shoot rays in the y directions\n    for (int i = 1; i < 4; i += 2) {\n        numpts = rayBoxIntersect(startPoint, dir[i], boxExts, result[i]);\n        // Each ray should have two intersection points with the box\n        if (numpts < 2 || result[i][1] < 0.0) return false;\n\n        // find the distance from the start point to the second intersection point\n        double interpt[3];\n        // calculate the intersection point\n        for (int j = 0; j < 3; j++) { interpt[j] = result[i][1] * dir[i][j] + startPoint[j]; }\n        // find the distances from the intersection points to starting point\n        for (int j = 0; j < 3; j++) { interpt[j] = interpt[j] - startPoint[j]; }\n        edgeDist[i] = vlength(interpt);\n        // Shorten the distance if it exceeds the probe\n        if (i == 1 && edgeDist[i] > prbexts[3]) edgeDist[i] = prbexts[3];\n        if (i == 3 && edgeDist[i] > -prbexts[1]) edgeDist[i] = -prbexts[1];\n    }\n\n    // Now shoot rays in the diagonal directions from startPoint.\n    // First determine the diagonal directions and the distances to the diagonal corners\n    double diagDirs[4][3];\n    double diagDist[4];\n    for (int j = 0; j < 4; j++) {\n        // Determine vector from startPoint to corner:\n        for (int i = 0; i < 3; i++) { diagDirs[j][i] = edgeDist[j] * dir[j][i] + edgeDist[(j + 1) % 4] * dir[(j + 1) % 4][i]; }\n        diagDist[j] = vlength(diagDirs[j]);\n        vnormal(diagDirs[j]);\n    }\n    // Now shoot rays in the diagonal directions\n    double diagInterDist[4];\n    double diagInterPt[4][3];\n    double component[4][2];    // components of the resulting diagonals along probe x and y axes\n    for (int i = 0; i < 4; i++) {\n        numpts = rayBoxIntersect(startPoint, diagDirs[i], bxExts, result[i]);\n        // Each ray should have two intersection points with the box\n        if (numpts < 2 || result[i][1] < 0.0) return false;\n        // and result[i][1] is the distance along diagonal i to intersection 1\n\n        // find the distance from the start point to the second intersection point\n        // calculate the intersection point\n        for (int j = 0; j < 3; j++) { diagInterPt[i][j] = result[i][1] * diagDirs[i][j] + startPoint[j]; }\n\n        // find the distances from the intersection points to starting point\n        double interVec[3];\n        for (int j = 0; j < 3; j++) { interVec[j] = diagInterPt[i][j] - startPoint[j]; }\n        diagInterDist[i] = vlength(interVec);\n        // Make sure the diagonal distance does not exceed the distance to the corner\n        double shrinkFactor = 1.;\n        if (diagInterDist[i] > diagDist[i]) { shrinkFactor = diagDist[i] / diagInterDist[i]; }\n        // project in probe directions to get components:\n        component[i][0] = vdot(dir[0], diagDirs[i]) * result[i][1] * shrinkFactor;\n        component[i][1] = vdot(dir[1], diagDirs[i]) * result[i][1] * shrinkFactor;\n    }\n\n    // Find the x,y extents (relative to startPoint):\n    double pExts[4];\n    // maxx must be the smaller of the two x displacements:\n    pExts[2] = Min(component[3][0], component[0][0]);    // maxx\n    pExts[0] = Max(component[1][0], component[2][0]);    // minx\n    pExts[1] = Max(component[2][1], component[3][1]);    // miny\n    pExts[3] = Min(component[0][1], component[1][1]);    // maxy\n\n    double wid = pExts[2] - pExts[0];\n    double ht = pExts[3] - pExts[1];\n\n    // New probe center is translated from startPoint by average of extents:\n    // add dir[0]*(pexts[2]+pexts[0])*.5 to move probe x coordinate, similarly for y:\n    // Use dir[] to hold the resulting displacements.\n    double probeCenter[3];\n    vcopy(startPoint, probeCenter);\n    vmult(dir[0], 0.5 * (pExts[0] + pExts[2]), dir[0]);\n    vmult(dir[1], 0.5 * (pExts[1] + pExts[3]), dir[1]);\n    vadd(startPoint, dir[0], probeCenter);\n    vadd(probeCenter, dir[1], probeCenter);\n\n    double depth = exts[5] - exts[2];\n    // apply these as offsets to startPoint, to get probe local extents.\n    // Don't change the z extents.\n\n    exts[0] = probeCenter[0] - wid * 0.5;\n    exts[1] = probeCenter[1] - ht * 0.5;\n    exts[3] = probeCenter[0] + wid * 0.5;\n    exts[4] = probeCenter[1] + ht * 0.5;\n    exts[2] = probeCenter[2] - depth * 0.5;\n    exts[5] = probeCenter[2] + depth * 0.5;\n\n    SetLocalExtents(exts);\n\n    return true;\n}\n\n// Find a point that lies in the probe plane and in a box, if the probe intersects a face of the box.\n// Return false if there is no such intersection\nbool Box::intersectRotatedBox(double boxExts[6], double intersectPoint[3], double probeCoords[2])\n{\n    // Transform the four probe corners to local region\n    double transformMatrix[12];\n    double cor[4][3];                  // probe corners in local user coords\n    double pcorn[3] = {0., 0., 0.};    // local probe corner coordinates\n\n    buildLocalCoordTransform(transformMatrix, 0.f, -1);\n\n    bool cornerInFace[4][6];\n    for (int i = 0; i < 4; i++) {\n        // make pcorn rotate counter-clockwise around probe\n        pcorn[0] = -1.;\n        pcorn[1] = -1.;\n        if (i > 1) pcorn[1] = 1.;\n        if (i == 1 || i == 2) pcorn[0] = 1.;\n        vtransform(pcorn, transformMatrix, cor[i]);\n        for (int k = 0; k < 3; k++) {\n            // Classify each corner as to whether it is inside or outside the half-space defined by each face\n            // cornerInFace[i][j] is true if the cor[i][j] is inside the half-space\n            if (cor[i][k] <= boxExts[k])\n                cornerInFace[i][k] = false;\n            else\n                cornerInFace[i][k] = true;\n            if (cor[i][k] >= boxExts[k + 3])\n                cornerInFace[i][k + 3] = false;\n            else\n                cornerInFace[i][k + 3] = true;\n        }\n    }\n\n    // initialize probe min & max:\n    double minx = -1., miny = -1.;\n    double maxx = 1., maxy = 1.;\n    // 2. For each box face:\n    for (int face = 0; face < 6; face++) {\n        int faceDim = face % 3;    //(x, y, or z-oriented face)\n        int faceDir = face / 3;    // either low or high face\n        // Intersect this face with four sides of probe.\n        // A side of probe is determined by line (1-t)*cor[k] + t*cor[(k+1)%4], going from cor[k] to cor[k+1]\n        // for each pair of corners, equation is\n        // (1-t)*cor[k][faceDim] + t*cor[k+1][faceDim] = boxExts[faceDim+faceDir*3]\n        // t*(cor[(k+1)%4][faceDim] - cor[k][faceDim]) = boxExts[faceDim+faceDir*3] - cor[k][faceDim]\n        // i.e.: t = (boxExts[faceDim+faceDir*3] - cor[k][faceDim])/(cor[(k+1)%4][faceDim] - cor[k][faceDim]);\n        int    interNum = 0;\n        double interPoint[2][3];\n        double interT[2];\n        int    interSide[2];\n        // a. determine either 2 or 0 intersection points between probe boundary and box face, by intersecting all sides of probe with face\n        for (int k = 0; k < 4; k++) {\n            double denom = (cor[(k + 1) % 4][faceDim] - cor[k][faceDim]);\n            if (denom == 0.) continue;\n            double t = (boxExts[faceDim + faceDir * 3] - cor[k][faceDim]) / denom;\n            if (t < 0. || t > 1.) continue;\n            for (int j = 0; j < 3; j++) { interPoint[interNum][j] = (1. - t) * cor[k][j] + t * cor[(k + 1) % 4][j]; }\n            // Replace t with T, going from -1 to +1, increasing with x and y\n            // This simplifies the logic later.\n            if (k > 1) t = 1. - t;             // make t increase with x and y\n            interT[interNum] = 2. * t - 1.;    // make T go from -1 to 1 instead of 0 to 1\n            interSide[interNum] = k;\n            interNum++;\n        }\n        VAssert(interNum == 0 || interNum == 2);\n        // Are there two intersections?\n        if (interNum == 2) {\n            // are they on opposite sides?\n            if (interSide[1] - interSide[0] == 2) {\n                // Does it intersect the two horizonal edges?\n                if (interSide[0] == 0) {\n                    // is vertex 0 in this half-space? If so use min t-coordinate to cut the probe max x-extents\n                    if (cornerInFace[interSide[0]][face]) {\n                        double mint = Min(interT[0], interT[1]);\n                        if (maxx > mint) maxx = mint;\n                    } else {    // must be vertex 0 is outside half-space, so use maxt to trim probe min x-extents\n                        double maxt = Max(interT[0], interT[1]);\n                        if (minx < maxt) minx = maxt;\n                    }\n                } else {    // It must intersect the two vertical edges, check if vertex 0 is inside half-space\n                    VAssert(interSide[0] == 1);\n                    if (cornerInFace[interSide[0]][face]) {\n                        double mint = Min(interT[0], interT[1]);\n                        if (maxy > mint) maxy = mint;\n                    } else {    // must be vertex 0 is outside half-space, so use max to trim\n                        double maxt = Max(interT[0], interT[1]);\n                        if (miny < maxt) miny = maxt;\n                    }\n                }\n            } else {    // The two intersections must cut off a corner of the probe\n                // The possible cases for interSide's are: 0,1 (cuts of vertex 1); 0,3 (cuts off vertex 0);\n                // 1,2 (cuts off vertex 2); 2,3(cuts off vertex 3);  each case can exclude or include the corner vertex\n                if (interSide[0] == 0 && interSide[1] == 1) {\n                    // new corner is midpoint of line between the two intersection points.\n                    double newcorx = 0.5 * (interT[0] + 1.);\n                    double newcory = 0.5 * (interT[1] - 1.);\n                    if (cornerInFace[interSide[1]][face]) {\n                        // if vertex 1 is inside then minx must be at least as large as newcorx, maxy as small as newcory\n                        minx = Max(minx, newcorx);\n                        maxy = Min(maxy, newcory);\n                    } else {    // maxx must be as small as newcorx, miny must be as large as newcory\n                        maxx = Min(maxx, newcorx);\n                        miny = Max(miny, newcory);\n                    }\n                } else if (interSide[0] == 0 && interSide[1] == 3) {\n                    // new corner is midpoint of line between the two intersection points.\n                    double newcorx = 0.5 * (interT[0] - 1.);\n                    double newcory = 0.5 * (interT[1] - 1.);\n                    if (cornerInFace[interSide[0]][face]) {\n                        // if vertex 0 is inside then maxx must be at least as small as newcorx, maxy as small as newcory\n                        maxx = Min(maxx, newcorx);\n                        maxy = Min(maxy, newcory);\n                    } else {    // minx must be as large as newcorx, miny must be as large as newcory\n                        minx = Max(minx, newcorx);\n                        miny = Max(miny, newcory);\n                    }\n                } else if (interSide[0] == 1 && interSide[1] == 2) {\n                    // new corner is midpoint of line between the two intersection points.\n                    double newcory = 0.5 * (interT[0] + 1.);\n                    double newcorx = 0.5 * (interT[1] + 1.);\n                    if (cornerInFace[interSide[1]][face]) {\n                        // if vertex 2 is inside then minx must be at least as large as newcorx, miny as large as newcory\n                        minx = Max(minx, newcorx);\n                        miny = Max(miny, newcory);\n                    } else {    // maxx must be as small as newcorx, maxy must be as small as newcory\n                        maxx = Min(maxx, newcorx);\n                        maxy = Min(maxy, newcory);\n                    }\n                } else if (interSide[0] == 2 && interSide[1] == 3) {\n                    // new corner is midpoint of line between the two intersection points.\n                    double newcorx = 0.5 * (interT[0] - 1.);\n                    double newcory = 0.5 * (interT[1] + 1.);\n                    if (cornerInFace[interSide[1]][face]) {\n                        // if vertex 3 is inside then maxx must be at least as small as newcorx, miny as large as newcory\n                        maxx = Min(maxx, newcorx);\n                        minx = Max(miny, newcory);\n                    } else {    // minx must be as large as newcorx, maxy must be as small as newcory\n                        minx = Max(minx, newcorx);\n                        maxy = Min(maxy, newcory);\n                    }\n                } else\n                    VAssert(0);\n            }    // end of cutting off corner\n        } else {\n            // If no intersections, check if the probe is completely outside slab determined by the face\n            // If any corner is outside, entire probe is outside, so check first corner\n\n            if (faceDir == 0 && cor[0][faceDim] < boxExts[face]) return false;\n            if (faceDir == 1 && cor[0][faceDim] > boxExts[face]) return false;\n\n            // OK, entire probe is inside this face\n        }\n    }    // finished with all 6 faces.\n    // Use minx, miny, maxx, maxy to find a rectangle in probe and box\n\n    // 3.  rectangle defined as intersection of all limits found\n    // probeCoords uses middle:\n    probeCoords[0] = 0.5 * (minx + maxx);\n    probeCoords[1] = 0.5 * (miny + maxy);\n    // convert minx, miny, maxx, maxy to interpolate between 0 and 1 (instead of -1 and +1)\n    maxx = 0.5 * (maxx + 1.);\n    maxy = 0.5 * (maxy + 1.);\n    minx = 0.5 * (minx + 1.);\n    miny = 0.5 * (miny + 1.);\n    // Determine center of intersection (in world coords) by bilinearly interpolating from corners using minx, maxx, miny,maxy,\n    // then taking average.\n\n    double newCor[4][3];\n    for (int k = 0; k < 3; k++) {\n        newCor[0][k] = ((1. - minx) * cor[0][k] + minx * cor[1][k]) * (1. - miny) + miny * ((1. - minx) * cor[3][k] + minx * cor[2][k]);\n        newCor[1][k] = ((1. - maxx) * cor[0][k] + maxx * cor[1][k]) * (1. - miny) + miny * ((1. - maxx) * cor[3][k] + maxx * cor[2][k]);\n        newCor[2][k] = ((1. - maxx) * cor[0][k] + maxx * cor[1][k]) * (1. - maxy) + maxy * ((1. - maxx) * cor[3][k] + maxx * cor[2][k]);\n        newCor[3][k] = ((1. - minx) * cor[0][k] + minx * cor[1][k]) * (1. - maxy) + maxy * ((1. - minx) * cor[3][k] + minx * cor[2][k]);\n        intersectPoint[k] = 0.25 * (newCor[0][k] + newCor[1][k] + newCor[2][k] + newCor[3][k]);\n    }\n    return true;\n}\n\n// Find probe extents that are maximal and fit in box\nbool Box::fitToBox(const double boxExts[6])\n{\n    // Increase the box if it is flat:\n    double modBoxExts[6];\n    for (int i = 0; i < 3; i++) {\n        modBoxExts[i] = boxExts[i];\n        modBoxExts[i + 3] = boxExts[i + 3];\n        if (boxExts[i] >= boxExts[i + 3]) {\n            if (boxExts[i] > 0.f) {\n                modBoxExts[i] = boxExts[i] * 0.99999f;\n                modBoxExts[i + 3] = boxExts[i] * 1.00001f;\n            } else if (boxExts[i] < 0.f) {\n                modBoxExts[i] = boxExts[i] * 1.00001f;\n                modBoxExts[i + 3] = boxExts[i] * 0.99999f;\n            } else {\n                modBoxExts[i] = -1.e-20f;\n                modBoxExts[i + 3] = 1.e-20f;\n            }\n        }\n    }\n\n    // find a point in the probe that lies in the box.   Do this by finding the intersections\n    // of the box with the probe plane and averaging the resulting points:\n    double startPoint[3];\n    double interceptPoints[6][3];\n    int    numintercept = interceptBox(modBoxExts, interceptPoints);\n    if (numintercept < 3) return false;\n    vzero(startPoint);\n    for (int i = 0; i < numintercept; i++) {\n        for (int j = 0; j < 3; j++) { startPoint[j] += interceptPoints[i][j] * (1.f / (double)numintercept); }\n    }\n\n    // Expand the probe so that it will exceed the box extents in all dimensions\n    // Begin with the startPoint and intersect horizontal rays with the far edges of the box.\n\n    double probeCenter[3];\n    double exts[6];\n    GetLocalExtents(exts);\n    for (int i = 0; i < 3; i++) probeCenter[i] = 0.5 * (exts[i] + exts[i + 3]);\n\n    double                rotMatrix[9];\n    const vector<double> &angles = GetAngles();\n    getRotationMatrix((float)(angles[0] * M_PI / 180.), (float)(angles[1] * M_PI / 180.), (float)(angles[2] * M_PI / 180.), rotMatrix);\n\n    // determine the probe x- and y- direction vectors\n    double vecx[3] = {1., 0., 0.};\n    double vecy[3] = {0., 1., 0.};\n\n    // Direction vectors:\n    double dir[4][3];\n    // Intersection parameters\n    double result[4][2];\n    double edgeDist[4];    // distances from center to probe edges\n\n    // Construct 4 rays in axis directions\n\n    vtransform3(vecx, rotMatrix, dir[0]);\n    vtransform3(vecy, rotMatrix, dir[1]);\n\n    vnormal(dir[0]);\n    vnormal(dir[1]);\n    // also negate:\n    vmult(dir[0], -1.f, dir[2]);\n    vmult(dir[1], -1.f, dir[3]);\n\n    // Intersect with each line\n    int numpts;\n    for (int i = 0; i < 4; i++) {\n        numpts = rayBoxIntersect(startPoint, dir[i], modBoxExts, result[i]);\n        // Each ray should have two intersection points with the box\n        if (numpts < 2 || result[i][1] < 0.f) return false;\n    }\n    // Use the distance from the probe center to the second intersection point as the new probe size\n    for (int i = 0; i < 4; i++) {\n        double interpt[3];\n        // calculate the intersection point\n        for (int j = 0; j < 3; j++) { interpt[j] = result[i][1] * dir[i][j] + startPoint[j]; }\n        // find the distance from the intersection point to the probe center\n        for (int j = 0; j < 3; j++) { interpt[j] = interpt[j] - probeCenter[j]; }\n        edgeDist[i] = vlength(interpt);\n    }\n    // Stretch a bit to ensure adequate coverage\n    double wid = 2.1 * Max(edgeDist[0], edgeDist[2]);\n    double ht = 2.1 * Max(edgeDist[1], edgeDist[3]);\n\n    double depth = abs(exts[5] - exts[2]);\n    exts[0] = probeCenter[0] - 0.5f * wid;\n    exts[3] = probeCenter[0] + 0.5f * wid;\n    exts[1] = probeCenter[1] - 0.5f * ht;\n    exts[4] = probeCenter[1] + 0.5f * ht;\n    exts[2] = probeCenter[2] - 0.5f * depth;\n    exts[5] = probeCenter[2] + 0.5f * depth;\n\n    SetLocalExtents(exts);\n    bool success = cropToBox(boxExts);\n    // bool success = true;\n    return success;\n}\n\n// Calculate up to six intersections of box edges with probe plane, return the number found.\n// Up to 6 intersection points are placed in intercept array\nint Box::interceptBox(const double boxExts[6], double intercept[6][3])\n{\n    int numfound = 0;\n    // Get the equation of the probe plane\n    // First, find normal to plane:\n    double                rotMatrix[9];\n    const double          vecz[3] = {0., 0., 1.};\n    const double          vec0[3] = {0., 0., 0.};\n    double                probeNormal[3], probeCenter[3];\n    const vector<double> &angles = GetAngles();\n    getRotationMatrix((float)(angles[0] * M_PI / 180.), (float)(angles[1] * M_PI / 180.), (float)(angles[2] * M_PI / 180.), rotMatrix);\n\n    vtransform3(vecz, rotMatrix, probeNormal);\n    double transformMatrix[12];\n\n    buildLocalCoordTransform(transformMatrix, 0.01, -1);\n    vtransform(vec0, transformMatrix, probeCenter);\n    vnormal(probeNormal);\n    // The equation of the probe plane is dot(V, probeNormal) = dst:\n    double dst = vdot(probeNormal, probeCenter);\n    // Now intersect the plane with all 6 edges of box.\n    // each edge is defined by two equations of the form\n    // x = boxExts[0] or boxExts[3]; y = boxExts[1] or boxExts[4]; z = boxExts[2] or boxExts[5]\n    for (int edge = 0; edge < 12; edge++) {\n        // edge%3 is the coordinate that varies;\n        // equation holds (edge+1)%3 to low or high value, based on (edge/3)%2\n        // holds (edge+2) to low or high value based on (edge/6)\n        // Thus equations associated with edge are:\n        // vcoord = edge%3, coord1 is (edge+1)%3, coord2 is (edge+2)%3;\n        // boxExts[vcoord] <= pt[vcoord] <= boxExts[vcoord+3]\n        // pt[coord1] = boxExts[coord1+3*((edge/3)%2)]\n        // pt[coord2] = boxExts[coord2+3*((edge/6))]\n        int    vcoord = edge % 3;\n        int    coord1 = (edge + 1) % 3;\n        int    coord2 = (edge + 2) % 3;\n        double rhs = dst - boxExts[coord1 + 3 * ((edge / 3) % 2)] * probeNormal[coord1] - boxExts[coord2 + 3 * (edge / 6)] * probeNormal[coord2];\n        // and the equation is V*probeNormal[vcoord] = rhs\n        // Question is whether the other (vcoord) coordinate of the intersection point lies between\n        // boxExts[vcoord] and boxExts[vcoord+3]\n\n        if (probeNormal[vcoord] == 0.f) continue;\n        if (rhs / probeNormal[vcoord] < boxExts[vcoord]) continue;\n        if (rhs / probeNormal[vcoord] > boxExts[vcoord + 3]) continue;\n        // Intersection found!\n        intercept[numfound][coord1] = boxExts[coord1 + 3 * ((edge / 3) % 2)];\n        intercept[numfound][coord2] = boxExts[coord2 + 3 * (edge / 6)];\n        intercept[numfound][vcoord] = rhs / probeNormal[vcoord];\n        numfound++;\n        if (numfound == 6) return numfound;\n    }\n    return numfound;\n}\n\nvoid Box::getRotatedVoxelExtents(string varname, float voxdims[2], int numRefinements)\n{\n    StructuredGrid *rGrid = GetDataMgr()->GetVariable(_dataStatus->getMinTimestep(), varname, numRefinements, 0);\n    VAssert(rGrid);\n    double exts[6], fullSizes[3];\n    rGrid->GetUserExtents(exts);\n    for (int i = 0; i < 3; i++) fullSizes[i] = exts[i + 3] - exts[i];\n    double sliceCoord[3];\n    // Can ignore depth, just mapping center plane\n    sliceCoord[2] = 0.f;\n    double transformMatrix[12];\n\n    // Set up to transform from probe into volume:\n    buildLocalCoordTransform(transformMatrix, 0.f, -1);\n\n    // Get the data dimensions (at this resolution):\n    size_t dataSize[3];\n\n    // Start by initializing integer extents\n    rGrid->GetDimensions(dataSize);\n\n    double cor[4][3];\n\n    for (int cornum = 0; cornum < 4; cornum++) {\n        double dataCoord[3];\n        // coords relative to (-1,1)\n        sliceCoord[1] = -1.f + 2. * (double)(cornum / 2);\n        sliceCoord[0] = -1.f + 2. * (double)(cornum % 2);\n        // Then transform to values in data\n        vtransform(sliceCoord, transformMatrix, dataCoord);\n        // Then get array coords:\n        for (int i = 0; i < 3; i++) { cor[cornum][i] = ((double)dataSize[i]) * (dataCoord[i]) / (fullSizes[i]); }\n    }\n    double vecWid[3], vecHt[3];\n\n    vsub(cor[1], cor[0], vecWid);\n    vsub(cor[3], cor[1], vecHt);\n    voxdims[0] = vlength(vecWid);\n    voxdims[1] = vlength(vecHt);\n    return;\n}\n\nvoid Box::rotateAndRenormalize(int axis, double rotVal)\n{\n    // Now finalize the rotation\n    double newTheta, newPhi, newPsi;\n    convertThetaPhiPsi(&newTheta, &newPhi, &newPsi, axis, rotVal);\n    double angles[3];\n    angles[0] = newTheta;\n    angles[1] = newPhi;\n    angles[2] = newPsi;\n    SetAngles(angles);\n    return;\n}\n\nvoid Box::setBoxToExtents(const double extents[6])\n{\n    // First try to fit to extents.  If we fail, then move to fit\n    bool success = fitToBox(extents);\n    if (success) return;\n\n    // Move the box so that it is centered in the extents:\n    double pExts[6];\n    GetLocalExtents(pExts);\n\n    for (int i = 0; i < 3; i++) {\n        double psize = pExts[i + 3] - pExts[i];\n        pExts[i] = 0.5 * (extents[i] + extents[i + 3] - psize);\n        pExts[i + 3] = 0.5 * (extents[i] + extents[i + 3] + psize);\n    }\n    SetLocalExtents(pExts, -1);\n    success = fitToBox(extents);\n\n    VAssert(success);\n\n    return;\n}\n\n#endif\n"
  },
  {
    "path": "lib/params/CMakeLists.txt",
    "content": "set (SRC\n\tXmlNode.cpp\n\tParamsBase.cpp\n\tColorMap.cpp\n\tOpacityMap.cpp\n\tMapperFunction.cpp\n\tBox.cpp\n\tColorbarPbase.cpp\n\tRenderParams.cpp\n\tTwoDDataParams.cpp\n\tBarbParams.cpp\n\tViewpoint.cpp\n\tTransform.cpp\n\tViewpointParams.cpp\n\tregionparams.cpp\n\tParamsMgr.cpp\n\tDataStatus.cpp\n\tAnnotationParams.cpp\n\tHelloParams.cpp\n\tImageParams.cpp\n\tTFInterpolator.cpp\n\tContourParams.cpp\n\tRayCasterParams.cpp\n\tAxisAnnotation.cpp\n\tWireFrameParams.cpp\n    SliceParams.cpp\n\tDatasetsParams.cpp\n\tFlowParams.cpp\n\tVolumeParams.cpp\n\tVolumeIsoParams.cpp\n\tModelParams.cpp\n\tParticleParams.cpp\n    AnimationParams.cpp\n    MouseModeParams.cpp\n    BookmarkParams.cpp\n    GUIStateParams.cpp\n    SettingsParams.cpp\n)\n\nset (HEADERS\n\t${PROJECT_SOURCE_DIR}/include/vapor/XmlNode.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ParamsBase.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ColorMap.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/OpacityMap.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/MapperFunction.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Box.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ColorbarPbase.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/RenderParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/TwoDDataParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/BarbParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Viewpoint.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ViewpointParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/regionparams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ParamsMgr.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DataStatus.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/AnnotationParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/HelloParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ImageParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/TFInterpolator.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ContourParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/AxisAnnotation.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WireFrameParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DatasetsParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/SliceParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/RayCasterParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/FlowParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeIsoParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ModelParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ParticleParams.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Transform.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/AnimationParams.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/MouseModeParams.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/BookmarkParams.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/GUIStateParams.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/SettingsParams.h\n)\n\nadd_library (params SHARED ${SRC} ${HEADERS})\n\nif (${CMAKE_SYSTEM_NAME} MATCHES \"Darwin\")\n\tfind_library (AGL AGL)\n\ttarget_link_libraries (params PUBLIC ${AGL})\nendif()\n\ntarget_link_libraries (params PUBLIC vdc ${EXPAT})\n\nadd_definitions (-DPARAMS_EXPORTS)\n\nOpenMPInstall (\n\tTARGETS params\n\tDESTINATION ${INSTALL_LIB_DIR}\n\tCOMPONENT Libraries\n\t)\n\ninstall (\n\tFILES ${HEADERS}\n\tDESTINATION ${INSTALL_INCLUDE_DIR}\n\tCOMPONENT Libraries\n\t)\n"
  },
  {
    "path": "lib/params/ColorMap.cpp",
    "content": "//--ColorMap.cpp ------------------------------------------------------------\n//\n// Copyright (C) 2006 Kenny Gruchalla.  All rights reserved.\n//\n// A map from data value to/from color.\n//\n//----------------------------------------------------------------------------\n\n#include <iostream>\n#include <sstream>\n#include <algorithm>\n#include \"vapor/VAssert.h\"\n#include <vapor/ColorMap.h>\n\n#ifndef MAX\n    #define MAX(a, b) ((a) > (b) ? (a) : (b))\n#endif\n\n#ifndef MIN\n    #define MIN(a, b) ((a) < (b) ? (a) : (b))\n#endif\n\nusing namespace std;\nusing namespace VAPoR;\nusing namespace Wasp;\n\n//----------------------------------------------------------------------------\n// Static member initalization\n//----------------------------------------------------------------------------\nconst string ColorMap::_controlPointsTag = \"ColorMapControlPoints\";\nconst string ColorMap::_interpTypeTag = \"ColorInterpolationType\";\nconst string ColorMap::_useWhitespaceTag = \"UseWhitespace\";\nconst string ColorMap::_dataBoundsTag = \"DataBounds\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<ColorMap> registrar(ColorMap::GetClassType());\n\n//============================================================================\n// Class ColorMap::Color\n//============================================================================\n\n//----------------------------------------------------------------------------\n// Default constructor (white)\n//----------------------------------------------------------------------------\nColorMap::Color::Color() : _hue(0.0), _sat(0.0), _val(1.0) {}\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nColorMap::Color::Color(float h, float s, float v) : _hue(h), _sat(s), _val(v) {}\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nColorMap::Color::Color(double h, double s, double v) : _hue((float)h), _sat((float)s), _val((float)v) {}\n\n//----------------------------------------------------------------------------\n// Copy Constructor\n//----------------------------------------------------------------------------\nColorMap::Color::Color(const Color &c) : _hue(c._hue), _sat(c._sat), _val(c._val) {}\n\n//----------------------------------------------------------------------------\n// Return the rgb components of the color (0.0 ... 1.0)\n//----------------------------------------------------------------------------\nvoid ColorMap::Color::toRGB(float *rgb) const\n{\n    /*\n     *  hsv-rgb Conversion function.  inputs and outputs\tbetween 0 and 1\n     *\tcopied (with corrections) from Hearn/Baker\n     */\n    if (_sat == 0.f)    // grey\n    {\n        rgb[0] = rgb[1] = rgb[2] = _val;\n        return;\n    }\n\n    int   sector = (int)(_hue * 6.f);\n    float sectCrd = _hue * 6.f - (float)sector;\n\n    if (sector == 6) { sector = 0; }\n\n    float a = _val * (1.f - _sat);\n    float b = _val * (1.f - sectCrd * _sat);\n    float c = _val * (1.f - (_sat * (1.f - sectCrd)));\n\n    switch (sector) {\n    case (0):    // red to green, r>g\n        rgb[0] = _val;\n        rgb[1] = c;\n        rgb[2] = a;\n        break;\n    case (1):    // red to green, g>r\n        rgb[1] = _val;\n        rgb[2] = a;\n        rgb[0] = b;\n        break;\n    case (2):    // green to blue, gr>bl\n        rgb[0] = a;\n        rgb[1] = _val;\n        rgb[2] = c;\n        break;\n    case (3):    // green to blue, gr<bl\n        rgb[0] = a;\n        rgb[2] = _val;\n        rgb[1] = b;\n        break;\n    case (4):    // blue to red, bl>red\n        rgb[1] = a;\n        rgb[2] = _val;\n        rgb[0] = c;\n        break;\n    case (5):    // blue to red, bl<red\n        rgb[1] = a;\n        rgb[0] = _val;\n        rgb[2] = b;\n        break;\n    default: VAssert(0);\n    }\n}\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\n\nColorMap::ColorMap(ParamsBase::StateSave *ssave) : ParamsBase(ssave, ColorMap::GetClassType())\n{\n    SetInterpType(TFInterpolator::diverging);\n    SetUseWhitespace(1);\n\n    // Create a default color map with 4 control points:\n    //\n    // Ken Moreland's \"Smooth Cool Warm\" color map\n    //\n    vector<double> cps;\n    cps.push_back(232.0 / 360.0);\n    cps.push_back(.695);\n    cps.push_back(.757);\n    cps.push_back(0.);\n    cps.push_back(348.0 / 360.0);\n    cps.push_back(.977);\n    cps.push_back(.706);\n    cps.push_back(.99);\n\n    SetControlPoints(cps);\n}\n\nColorMap::ColorMap(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nColorMap::~ColorMap() {}\n\n//----------------------------------------------------------------------------\n// Clear (& deallocated) the control points\n//----------------------------------------------------------------------------\nvoid ColorMap::clear()\n{\n    vector<double> cps;\n    SetControlPoints(cps);\n}\n\n//----------------------------------------------------------------------------\n// Return the control point's color\n//----------------------------------------------------------------------------\nColorMap::Color ColorMap::controlPointColor(int index) const\n{\n    vector<double> cps = GetControlPoints();\n    if (index + 4 > cps.size() * 4) return Color();\n\n    return Color(cps[4 * index], cps[4 * index + 1], cps[4 * index + 2]);\n}\n\n//----------------------------------------------------------------------------\n// Set the control point's color.\n//----------------------------------------------------------------------------\nvoid ColorMap::controlPointColor(int index, Color color)\n{\n    vector<double> cps = GetControlPoints();\n    if (index + 4 > cps.size() * 4) return;    // no-op\n\n    cps[4 * index] = color.hue();\n    cps[4 * index + 1] = color.sat();\n    cps[4 * index + 2] = color.val();\n    SetControlPoints(cps);\n}\n\nfloat ColorMap::controlPointValueNormalized(int index) const\n{\n    vector<double> cps = GetControlPoints();\n    return (float)cps[4 * index + 3];\n}\n\n//----------------------------------------------------------------------------\n// Return the control point's value (in data coordinates).\n//----------------------------------------------------------------------------\nfloat ColorMap::controlPointValue(int index) const { return (controlPointValueNormalized(index) * (maxValue() - minValue()) + minValue()); }\n\n//----------------------------------------------------------------------------\n// Set the control point's value (in data coordinates).\n//----------------------------------------------------------------------------\nvoid ColorMap::controlPointValue(int index, float value)\n{\n    vector<double> cps = GetControlPoints();\n    if (index + 4 > cps.size() * 4) return;    // no-op\n\n    float nv = (value - minValue()) / (maxValue() - minValue());\n\n    float minVal = 0.0;\n    float maxVal = 1.0;\n\n    if (index > 0) { minVal = (cps[3]); }\n    if (index < cps.size() / 4 - 1) maxVal = cps[cps.size() - 1];\n\n    if (nv < minVal) {\n        nv = minVal;\n    } else if (nv > maxVal) {\n        nv = maxVal;\n    }\n    cps[index * 4 + 3] = nv;\n    SetControlPoints(cps);\n}\n\n//----------------------------------------------------------------------------\n// Add a new control point to the colormap.\n//----------------------------------------------------------------------------\nvoid ColorMap::addControlPointAt(float value)\n{\n    float nv = (value - minValue()) / (maxValue() - minValue());\n    addNormControlPointAt(nv);\n}\n\nint ColorMap::addNormControlPointAt(float nv)\n{\n    Color c = colorNormalized(nv);\n\n    vector<double> cps = GetControlPoints();\n    // Find the insertion point:\n    int indx = leftIndex(nv) * 4 + 4;\n    cps.insert(cps.begin() + indx++, c.hue());\n    cps.insert(cps.begin() + indx++, c.sat());\n    cps.insert(cps.begin() + indx++, c.val());\n    cps.insert(cps.begin() + indx, nv);\n\n    SetControlPoints(cps);\n    return indx / 4;\n}\n\n//----------------------------------------------------------------------------\n// Add a new control point to the colormap.\n//----------------------------------------------------------------------------\nvoid ColorMap::addControlPointAt(float value, Color color)\n{\n    vector<double> cps = GetControlPoints();\n    // Find the insertion point:\n    int indx = leftIndex(value) * 4;\n    cps.insert(cps.begin() + indx++, color.hue());\n    cps.insert(cps.begin() + indx++, color.sat());\n    cps.insert(cps.begin() + indx++, color.val());\n    cps.insert(cps.begin() + indx, value);\n\n    SetControlPoints(cps);\n}\n\n//----------------------------------------------------------------------------\n// Add a new control point to the colormap.\n//----------------------------------------------------------------------------\nint ColorMap::addNormControlPoint(float normValue, Color color)\n{\n    vector<double> cps = GetControlPoints();\n    // Find the insertion point:\n    int indx = (leftIndex(normValue) + 1) * 4;\n    cps.insert(cps.begin() + indx++, color.hue());\n    cps.insert(cps.begin() + indx++, color.sat());\n    cps.insert(cps.begin() + indx++, color.val());\n    cps.insert(cps.begin() + indx, normValue);\n\n    SetControlPoints(cps);\n\n    return indx / 4;\n}\n\n//----------------------------------------------------------------------------\n// Delete the control point.\n//----------------------------------------------------------------------------\nvoid ColorMap::deleteControlPoint(int index)\n{\n    vector<double> cps = GetControlPoints();\n    if (index >= 0 && index < cps.size() / 4) {\n        cps.erase(cps.begin() + 4 * index, cps.begin() + 4 * index + 4);\n\n        SetControlPoints(cps);\n    }\n}\n\n//----------------------------------------------------------------------------\n// Move the control point, but not past adjacent control points\n//----------------------------------------------------------------------------\nvoid ColorMap::move(int index, float delta)\n{\n    vector<double> cps = GetControlPoints();\n    if (index > 0 && index < cps.size() / 4 - 1)    // don't move first or last control point!\n    {\n        float ndx = delta / (maxValue() - minValue());\n\n        float minVal = cps[index * 4 - 1];    // value to the left\n\n        float maxVal = cps[index * 4 + 7];    // value to the right\n\n        float value = cps[index * 4 + 3] + ndx;\n\n        if (value < 0.005) value = 0.005;\n\n        if (value <= minVal) {\n            value = minVal;\n        } else if (value >= maxVal) {\n            value = maxVal;\n        }\n\n        cps[index * 4 + 3] = value;\n        SetControlPoints(cps);\n    }\n}\n\nColorMap::Color ColorMap::getDivergingColor(float ratio, float index) const\n{\n    vector<double> cps = GetControlPoints();\n    float          hsv1[3] = {(float)cps[4 * index], (float)cps[4 * index + 1], (float)cps[4 * index + 2]};\n    float          hsv2[3] = {(float)cps[4 * index + 4], (float)cps[4 * index + 5], (float)cps[4 * index + 6]};\n    float          rgb1[3], rgb2[3];\n    float          rgbOutput[3], hsvOutput[3];\n\n    TFInterpolator::hsv2rgb(hsv1, rgb1);\n    rgb1[0] = rgb1[0] * 255.0;\n    rgb1[1] = rgb1[1] * 255.0;\n    rgb1[2] = rgb1[2] * 255.0;\n\n    TFInterpolator::hsv2rgb(hsv2, rgb2);\n    rgb2[0] = rgb2[0] * 255.0;\n    rgb2[1] = rgb2[1] * 255.0;\n    rgb2[2] = rgb2[2] * 255.0;\n\n    if (GetUseWhitespace())\n        TFInterpolator::correctiveDivergentInterpolation(rgb2, rgb1, rgbOutput, ratio);\n    else\n        TFInterpolator::divergentInterpolation(rgb2, rgb1, rgbOutput, ratio);\n    TFInterpolator::rgb2hsv(rgbOutput, hsvOutput);\n\n    // Normalize HSV output\n    hsvOutput[0] = hsvOutput[0] / 360.0;\n    hsvOutput[2] = (float)hsvOutput[2] / 255.0;\n    return Color(hsvOutput[0], hsvOutput[1], hsvOutput[2]);\n}\n\nColorMap::Color ColorMap::color(float value) const\n{\n    float nv = (value - minValue()) / (maxValue() - minValue());\n    return colorNormalized(nv);\n}\n\nnamespace {\n\nvoid lab2lch(const float lab[3], float lch[3])\n{\n    const float l = lab[0];\n    const float a = lab[1];\n    const float b = lab[2];\n\n    const float c = sqrtf(a * a + b * b);\n    const float h = fmod((atan2f(b, a) / (2 * M_PI) * 360 + 360), 360.f);\n\n    lch[0] = l;\n    lch[1] = c;\n    lch[2] = h;\n}\n\nvoid lch2lab(const float lch[3], float lab[3])\n{\n    const float l = lch[0];\n    const float c = lch[1];\n    float       h = lch[2];\n\n    h = h / 360.f * 2 * M_PI;\n\n    lab[0] = l;\n    lab[1] = cosf(h) * c;\n    lab[2] = sinf(h) * c;\n}\n\ntemplate <typename T> void clamp(T &v, const T min, const T max)\n{\n    if (v < min) v = min;\n    if (v > max) v = max;\n}\n\nvoid clamp3(float c[3], const vector<float> &min, const vector<float> &max)\n{\n    for (int i = 0; i < 3; i++) clamp(c[i], min[i], max[i]);\n}\n\n}    // namespace\n\n//----------------------------------------------------------------------------\n// Interpolate a color at the value (data coordinates)\n//\n// Developed by Alan Norton.\n//----------------------------------------------------------------------------\nColorMap::Color ColorMap::colorNormalized(float nv) const\n{\n    vector<double> cps = GetControlPoints();\n    //\n    // Find the bounding control points\n    //\n    int index = leftIndex(nv);\n\n    if (index < 0) return controlPointColor(0);\n    if (index >= numControlPoints() - 1) return controlPointColor(numControlPoints() - 1);\n\n    VAssert(index >= 0 && index * 4 + 7 < cps.size());\n    double leftVal = cps[4 * index + 3];\n    double rightVal = cps[4 * index + 7];\n\n    float ratio = (nv - leftVal) / (rightVal - leftVal);\n\n    if (ratio > 0.f && ratio < 1.f) {\n        TFInterpolator::type itype = GetInterpType();\n        if (itype == TFInterpolator::diverging) {\n            ColorMap::Color divergingColor;\n            divergingColor = getDivergingColor(ratio, index);\n            return divergingColor;\n        } else if (itype == TFInterpolator::linear) {\n            float h = TFInterpolator::interpCirc(itype,\n                                                 cps[4 * index],    // hue\n                                                 cps[4 * index + 4], ratio);\n\n            float s = TFInterpolator::interpolate(itype,\n                                                  cps[4 * index + 1],    // sat\n                                                  cps[4 * index + 5], ratio);\n\n            float v = TFInterpolator::interpolate(itype,\n                                                  cps[4 * index + 2],    // val\n                                                  cps[4 * index + 6], ratio);\n\n            return Color(h, s, v);\n        } else if (itype == TFInterpolator::linearRGB) {\n            Color a(cps[4 * index + 0 + 0], cps[4 * index + 1 + 0], cps[4 * index + 2 + 0]);\n            Color b(cps[4 * index + 0 + 4], cps[4 * index + 1 + 4], cps[4 * index + 2 + 4]);\n            float aRGB[3], bRGB[3];\n            a.toRGB(aRGB);\n            b.toRGB(bRGB);\n\n            float rgb[3];\n            for (int i = 0; i < 3; i++) rgb[i] = aRGB[i] + (bRGB[i] - aRGB[i]) * ratio;\n\n            float hsv[3];\n            TFInterpolator::rgb2hsv(rgb, hsv);\n            hsv[0] /= 360.f;\n            return Color(hsv[0], hsv[1], hsv[2]);\n        } else if (itype == TFInterpolator::linearLAB) {\n            Color a(cps[4 * index + 0 + 0], cps[4 * index + 1 + 0], cps[4 * index + 2 + 0]);\n            Color b(cps[4 * index + 0 + 4], cps[4 * index + 1 + 4], cps[4 * index + 2 + 4]);\n            float aRGB[3], bRGB[3];\n            a.toRGB(aRGB);\n            b.toRGB(bRGB);\n\n            float aSRGB[3], bSRGB[3], rgb[3];\n            for (int i = 0; i < 3; i++) {\n                aRGB[i] *= 100;\n                bRGB[i] *= 100;\n            }\n            TFInterpolator::rgb2srgb(aRGB, aSRGB);\n            TFInterpolator::rgb2srgb(bRGB, bSRGB);\n\n            float aLAB[3], bLAB[3], lab[3];\n            TFInterpolator::srgb2lab(aSRGB, aLAB);\n            TFInterpolator::srgb2lab(bSRGB, bLAB);\n            clamp3(aLAB, {0, -110, -110}, {100, 110, 110});\n            clamp3(bLAB, {0, -110, -110}, {100, 110, 110});\n\n            for (int i = 0; i < 3; i++) lab[i] = aLAB[i] + (bLAB[i] - aLAB[i]) * ratio;\n\n            float srgb[3];\n            TFInterpolator::lab2srgb(lab, srgb);\n            TFInterpolator::srgb2rgb(srgb, rgb);\n            for (int i = 0; i < 3; i++) rgb[i] /= 100.f;\n            clamp3(rgb, {0, 0, 0}, {1, 1, 1});\n\n            float hsv[3];\n            TFInterpolator::rgb2hsv(rgb, hsv);\n            hsv[0] /= 360.f;\n\n            return Color(hsv[0], hsv[1], hsv[2]);\n        } else if (itype == TFInterpolator::linearLCH) {\n            Color a(cps[4 * index + 0 + 0], cps[4 * index + 1 + 0], cps[4 * index + 2 + 0]);\n            Color b(cps[4 * index + 0 + 4], cps[4 * index + 1 + 4], cps[4 * index + 2 + 4]);\n            float aRGB[3], bRGB[3];\n            a.toRGB(aRGB);\n            b.toRGB(bRGB);\n\n            float rgb[3];\n            float hsv[3];\n\n            float aSRGB[3], bSRGB[3];\n            for (int i = 0; i < 3; i++) {\n                aRGB[i] *= 100;\n                bRGB[i] *= 100;\n            }\n            TFInterpolator::rgb2srgb(aRGB, aSRGB);\n            TFInterpolator::rgb2srgb(bRGB, bSRGB);\n\n            float aLAB[3], bLAB[3];\n            TFInterpolator::srgb2lab(aSRGB, aLAB);\n            TFInterpolator::srgb2lab(bSRGB, bLAB);\n            clamp3(aLAB, {0, -110, -110}, {100, 110, 110});\n            clamp3(bLAB, {0, -110, -110}, {100, 110, 110});\n\n            float aLCH[3], bLCH[3], lch[3];\n            lab2lch(aLAB, aLCH);\n            lab2lch(bLAB, bLCH);\n            clamp3(aLCH, {0, 0, 0}, {100, 140, 360});\n            clamp3(bLCH, {0, 0, 0}, {100, 140, 360});\n\n            for (int i = 0; i < 2; i++) lch[i] = aLCH[i] + (bLCH[i] - aLCH[i]) * ratio;\n\n            float h, ah = aLCH[2], bh = bLCH[2];\n            if (fabsf(bh - ah) > 180) {\n                if (bh > ah)\n                    ah += 360;\n                else\n                    bh += 360;\n            }\n            h = ah + (bh - ah) * ratio;\n\n            lch[2] = h;\n\n            float lab[3];\n            lch2lab(lch, lab);\n            clamp3(lab, {0, -110, -110}, {100, 110, 110});\n\n            float srgb[3];\n            TFInterpolator::lab2srgb(lab, srgb);\n            TFInterpolator::srgb2rgb(srgb, rgb);\n            for (int i = 0; i < 3; i++) rgb[i] /= 100.f;\n            clamp3(rgb, {0, 0, 0}, {1, 1, 1});\n            TFInterpolator::rgb2hsv(rgb, hsv);\n            hsv[0] /= 360.f;\n\n            return Color(hsv[0], hsv[1], hsv[2]);\n        } else if (itype == TFInterpolator::discrete) {\n            if (ratio < .5) {\n                float h = cps[4 * index];\n                float s = cps[4 * index + 1];\n                float v = cps[4 * index + 2];\n                return Color(h, s, v);\n            } else {\n                float h = cps[4 * index + 4];\n                float s = cps[4 * index + 5];\n                float v = cps[4 * index + 6];\n                return Color(h, s, v);\n            }\n        }\n    }\n\n    if (ratio >= 1.0) { return Color(cps[4 * index + 4], cps[4 * index + 5], cps[4 * index + 6]); }\n\n    return Color(cps[4 * index], cps[4 * index + 1], cps[4 * index + 2]);\n}\n\n//----------------------------------------------------------------------------\n// binary search , find the index of the largest control point <= val\n// Requires that control points are increasing.\n//\n// Not developed by Alan Norton.\n//----------------------------------------------------------------------------\nint ColorMap::leftIndex(float val) const\n{\n    int n = numControlPoints();\n    if (n == 0) return -1;\n\n    for (int i = 0; i < n; i++)\n        if (controlPointValueNormalized(i) > val) return i - 1;\n\n    return n - 1;\n}\n\nvector<double> ColorMap::GetControlPoints() const\n{\n    vector<double> cps = GetValueDoubleVec(_controlPointsTag);\n\n    while (cps.size() % 4) cps.push_back(0.0);\n\n    for (int i = 0; i < cps.size(); i += 4)\n        clamp(cps[i], 0.0, 1.0);\n\n    return (cps);\n}\n\nvoid ColorMap::SetControlPoints(const vector<double> &controlPoints)\n{\n    vector<double> mycp = controlPoints;\n\n    while (mycp.size() % 4) mycp.push_back(0.0);\n\n    SetValueDoubleVec(_controlPointsTag, \"Set color control points\", mycp);\n}\n\nvoid ColorMap::SetInterpType(TFInterpolator::type t) { SetValueLong(_interpTypeTag, \"Set Color Interpolation\", (long)t); }\n\nvoid ColorMap::SetUseWhitespace(bool enabled)\n{\n    SetValueLong(_useWhitespaceTag,\n                 \"Set the use of whitespace for \"\n                 \"diverging colormaps\",\n                 enabled);\n}\n\nbool ColorMap::GetUseWhitespace() const { return GetValueLong(_useWhitespaceTag, true); }\n\nvoid ColorMap::SetDataBounds(const vector<double> &bounds)\n{\n    VAssert(bounds.size() == 2);\n\n    SetValueDoubleVec(_dataBoundsTag, \"Set min max map value\", bounds);\n}\n\nvector<double> ColorMap::GetDataBounds() const\n{\n    vector<double> defaultv(2, 0.0);\n\n    vector<double> bounds = GetValueDoubleVec(_dataBoundsTag, defaultv);\n\n    if (bounds.size() != 2) bounds = defaultv;\n\n    return (bounds);\n}\n\nvoid ColorMap::Reverse()\n{\n    auto           old = GetControlPoints();\n    vector<double> cps;\n\n    for (int i = numControlPoints() - 1; i >= 0; i--) {\n        double r = old[i * 4 + 0];\n        double g = old[i * 4 + 1];\n        double b = old[i * 4 + 2];\n        double v = old[i * 4 + 3];\n\n        cps.push_back(r);\n        cps.push_back(g);\n        cps.push_back(b);\n        cps.push_back(1.0 - v);\n    }\n\n    SetControlPoints(cps);\n}\n"
  },
  {
    "path": "lib/params/ColorbarPbase.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t\t\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t\t\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tColorbarPbase.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tFebruary 2016\n//\n//\tDescription:\tImplements the ColorbarPbase class.\n//\t\tUsed to control parameters of a color bar.\n//\n\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <vapor/ColorbarPbase.h>\n\nusing namespace VAPoR;\nconst string ColorbarPbase::_colorbarBackColorTag = \"ColorbarBackgroundColor\";\nconst string ColorbarPbase::_colorbarFrontColorTag = \"ColorbarForegroundColor\";\nconst string ColorbarPbase::_colorbarSizeXTag = \"ColorbarSize_X\";\nconst string ColorbarPbase::_colorbarSizeYTag = \"ColorbarSize_Y\";\nconst string ColorbarPbase::_colorbarPositionXTag = \"ColorbarPosition_X\";\nconst string ColorbarPbase::_colorbarPositionYTag = \"ColorbarPosition_Y\";\nconst string ColorbarPbase::_colorbarFontSizeTag = \"ColorbarFontsize\";\nconst string ColorbarPbase::_colorbarNumDigitsTag = \"ColorbarNumDigits\";\nconst string ColorbarPbase::_colorbarTitleTag = \"ColorbarTitle\";\nconst string ColorbarPbase::_colorbarNumTicksTag = \"ColorbarNumTicks\";\nconst string ColorbarPbase::_colorbarEnabledTag = \"ColorbarEnabled\";\n\nconst string ColorbarPbase::UseScientificNotationTag = \"UseScientificNotationTag\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<ColorbarPbase> registrar(ColorbarPbase::GetClassType());\n\nColorbarPbase::ColorbarPbase(ParamsBase::StateSave *ssave) : ParamsBase(ssave, ColorbarPbase::GetClassType())\n{\n    MyBase::SetDiagMsg(\"ColorbarPbase::ColorbarPbase() this=%p\", this);\n\n    // Initialize with default values\n    SetCornerPosition(vector<double>(2, 0.03));\n    SetSize(vector<double>(2, 0.1));\n    SetTitle(\"\");\n    SetFontSize(10);\n    SetNumDigits(4);\n    SetNumTicks(6);\n    SetBackgroundColor(vector<double>(3, 1.));\n    SetForegroundColor(vector<double>(3, 0.));\n    SetEnabled(false);\n    SetValueLong(UseScientificNotationTag, \"\", false);\n}\n\nColorbarPbase::ColorbarPbase(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\nColorbarPbase::~ColorbarPbase() { MyBase::SetDiagMsg(\"ColorbarPbase::~ColorbarPbase() this=%p\", this); }\n\nvector<double> ColorbarPbase::GetCornerPosition() const\n{\n    vector<double> val(2, 0.0);\n    val[0] = GetValueDouble(_colorbarPositionXTag, 0);\n    val[1] = GetValueDouble(_colorbarPositionYTag, 0);\n    for (int i = 0; i < 2; i++) {\n        if (val[i] < 0.0) val[i] = 0.0;\n        if (val[i] > 1.0) val[i] = 1.0;\n    }\n    return (val);\n}\n\n//! Set the X,Y corner (upper left) coordinates\n//! Relative to [0,1]\n//! \\param[in] posn = x,y coordinates\nvoid ColorbarPbase::SetCornerPosition(vector<double> posn)\n{\n    vector<double> defaultv(2, 0.0);\n    if (posn.size() != 2) posn = defaultv;\n    for (int i = 0; i < 2; i++) {\n        if (posn[i] < 0.0) posn[i] = 0.0;\n        if (posn[i] > 1.0) posn[i] = 1.0;\n    }\n\n    BeginGroup(\"Colorbar_Position\");\n    SetValueDouble(_colorbarPositionXTag, \"\", posn[0]);\n    SetValueDouble(_colorbarPositionYTag, \"\", posn[1]);\n    EndGroup();\n}\n\n//! Get the X,Y size\n//! Relative to [0,1]\n//! \\retval pair of x,y sizes\nvector<double> ColorbarPbase::GetSize() const\n{\n    vector<double> val(2, 0.0);\n    val[0] = GetValueDouble(_colorbarSizeXTag, 0);\n    val[1] = GetValueDouble(_colorbarSizeYTag, 0);\n    for (int i = 0; i < 2; i++) {\n        if (val[i] < 0.0) val[i] = 0.0;\n        if (val[i] > 1.0) val[i] = 1.0;\n    }\n    return (val);\n}\n\n//! Set the X,Y sizes\n//! Relative to [0,1]\n//! \\param[in] posn = x,y sizes\nvoid ColorbarPbase::SetSize(vector<double> sz)\n{\n    vector<double> defaultv(2, 0.0);\n    if (sz.size() != 2) sz = defaultv;\n    for (int i = 0; i < 2; i++) {\n        if (sz[i] < 0.0) sz[i] = 0.0;\n        if (sz[i] > 1.0) sz[i] = 1.0;\n    }\n    SetValueDouble(_colorbarSizeXTag, \"\", sz[0]);\n    SetValueDouble(_colorbarSizeYTag, \"\", sz[1]);\n}\n\n//! Determine colorbar text size\n//! \\return pointsize\nlong ColorbarPbase::GetFontSize() const\n{\n    float val = (float)GetValueLong(_colorbarFontSizeTag, 10);\n    if (val < 2) val = 2;\n    if (val > 96) val = 96;\n    return (val);\n}\n\n//! Set colorbar text size\n//! \\param[in] val text point size\nvoid ColorbarPbase::SetFontSize(long val)\n{\n    if (val < 2) val = 2;\n    if (val > 96) val = 96;\n    SetValueLong(_colorbarFontSizeTag, \"Set colorbar fontsize\", val);\n}\n\n//! Determine colorbar num tics\n//! \\return number of tics\nlong ColorbarPbase::GetNumTicks() const\n{\n    long val = GetValueLong(_colorbarNumTicksTag, 8);\n    if (val < 0) val = 0;\n    if (val > 20) val = 20;\n    return (val);\n}\n\n//! Set colorbar number of tic marks\n//! \\param[in] val number of tics\nvoid ColorbarPbase::SetNumTicks(long val)\n{\n    if (val < 0) val = 0;\n    if (val > 20) val = 20;\n    SetValueLong(_colorbarNumTicksTag, \"set num tics\", val);\n}\n\n//! Determine colorbar num digits to display\n//! \\return number of digits\nlong ColorbarPbase::GetNumDigits() const\n{\n    long val = GetValueLong(_colorbarNumDigitsTag, 4);\n    if (val < 0) val = 0;\n    if (val > 8) val = 8;\n    return (val);\n}\n\n//! Set colorbar number of digits\n//! \\param[in] val number of digits\nvoid ColorbarPbase::SetNumDigits(long val)\n{\n    if (val < 0) val = 0;\n    if (val > 8) val = 8;\n    SetValueLong(_colorbarNumDigitsTag, \"set num digits\", val);\n}\n\n//! Get the background color\n//! as an rgb triple\n//! \\retval rgb color\nvector<double> ColorbarPbase::GetBackgroundColor() const\n{\n    vector<double> defaultv(4, 1.0);\n    vector<double> color = GetValueDoubleVec(_colorbarBackColorTag, defaultv);\n    for (int i = 0; i < color.size(); i++) {\n        if (color[i] < 0.0) color[i] = 0.0;\n        if (color[i] > 1.0) color[i] = 1.0;\n    }\n    return (color);\n}\n\n//! Set the background color as an rgb triple\n//! \\param[in] color = (r,g,b)\nvoid ColorbarPbase::SetBackgroundColor(vector<double> color)\n{\n    VAssert(color.size() == 3 || color.size() == 4);\n    for (int i = 0; i < color.size(); i++) {\n        if (color[i] < 0.0) color[i] = 0.0;\n        if (color[i] > 1.0) color[i] = 1.0;\n    }\n    SetValueDoubleVec(_colorbarBackColorTag, \"set colorbar background color\", color);\n}\n\nvector<double> ColorbarPbase::GetForegroundColor() const\n{\n    vector<double> defaultv(3, 0.0);\n    vector<double> color = GetValueDoubleVec(_colorbarFrontColorTag, defaultv);\n    for (int i = 0; i < color.size(); i++) {\n        if (color[i] < 0.0) color[i] = 0.0;\n        if (color[i] > 1.0) color[i] = 1.0;\n    }\n    return (color);\n}\n\nvoid ColorbarPbase::SetForegroundColor(vector<double> color)\n{\n    color.resize(3, 0);\n    for (int i = 0; i < color.size(); i++) {\n        if (color[i] < 0.0) color[i] = 0.0;\n        if (color[i] > 1.0) color[i] = 1.0;\n    }\n    SetValueDoubleVec(_colorbarFrontColorTag, \"set colorbar background color\", color);\n}\n\nvoid ColorbarPbase::copyTo(ColorbarPbase *target)\n{\n    target->SetBackgroundColor(GetBackgroundColor());\n    target->SetForegroundColor(GetForegroundColor());\n    target->SetSize(GetSize());\n    target->SetFontSize(GetFontSize());\n    target->SetNumDigits(GetNumDigits());\n    target->SetNumTicks(GetNumTicks());\n}\n"
  },
  {
    "path": "lib/params/ContourParams.cpp",
    "content": "\n#include <string>\n#include <vapor/RenderParams.h>\n#include <vapor/ContourParams.h>\n\nnamespace VAPoR {\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<ContourParams>        registrar(ContourParams::GetClassType());\nstatic ParamsRegistrar<ContourParams::Contours> registrar2(ContourParams::Contours::GetClassType());\n\nconst string ContourParams::_thicknessScaleTag = \"LineThickness\";\nconst string ContourParams::_contoursTag = \"Contours\";\nconst string ContourParams::_numDigitsTag = \"NumDigits\";\nconst string ContourParams::_textDensityTag = \"TextDensity\";\nconst string ContourParams::_lineColorTag = \"LineColor\";\nconst string ContourParams::_textEnabledTag = \"TextEnabled\";\nconst string ContourParams::_lockToTFTag = \"LockToTF\";\nconst string ContourParams::Contours::_valuesTag = \"Values\";\n\nContourParams::ContourParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, ContourParams::GetClassType(), 3)\n{\n    SetDiagMsg(\"ContourParams::ContourParams() this=%p\", this);\n\n    _contours = new ParamsContainer(ssave, _contoursTag);\n    _contours->SetParent(this);\n\n    _init();\n}\n\nContourParams::ContourParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3)\n{\n    SetDiagMsg(\"ContourParams::ContourParams() this=%p\", this);\n\n    if (node->HasChild(_contoursTag)) {\n        _contours = new ParamsContainer(ssave, node->GetChild(_contoursTag));\n    } else {\n        // Node doesn't contain a contours container\n        _contours = new ParamsContainer(ssave, _contoursTag);\n        _contours->SetParent(this);\n    }\n}\n\nContourParams::ContourParams(const ContourParams &rhs) : RenderParams(rhs) { _contours = new ParamsContainer(*(rhs._contours)); }\n\nContourParams &ContourParams::operator=(const ContourParams &rhs)\n{\n    if (_contours) delete _contours;\n\n    ParamsBase::operator=(rhs);\n    _contours = new ParamsContainer(*(rhs._contours));\n\n    return (*this);\n}\n\nContourParams::~ContourParams()\n{\n    SetDiagMsg(\"ContourParams::~ContourParams() this=%p\", this);\n\n    if (_contours != NULL) {\n        delete _contours;\n        _contours = NULL;\n    }\n}\n\nvector<double> ContourParams::GetIsoValues(const string &variable) { return GetContourValues(variable); }\n\nvoid ContourParams::SetIsoValues(const string &variable, const vector<double> &values) { SetContourValues(variable, values); }\n\nvector<double> ContourParams::GetContourValues(const string &varName)\n{\n    Contours *c = (Contours *)_contours->GetParams(varName);\n    if (c == NULL) {\n        bool wasEnabled = _ssave->GetEnabled();\n        _ssave->SetEnabled(false);\n        MakeNewContours(varName);\n        _ssave->SetEnabled(wasEnabled);\n        c = (Contours *)_contours->GetParams(varName);\n    }\n    return c->GetContourValues();\n}\n\nvoid ContourParams::SetContourValues(const string &varName, const vector<double> &vals)\n{\n    Contours *c = (Contours *)_contours->GetParams(varName);\n    if (c == NULL) {\n        MakeNewContours(varName);\n        c = (Contours *)_contours->GetParams(varName);\n    }\n    c->SetContourValues(vals);\n}\n\nContourParams::Contours *ContourParams::GetCurrentContours()\n{\n    string                   varName = GetVariableName();\n    ContourParams::Contours *c = (ContourParams::Contours *)_contours->GetParams(varName);\n    if (c == NULL) {\n        MakeNewContours(varName);\n        c = (ContourParams::Contours *)_contours->GetParams(varName);\n    }\n    return c;\n}\n\nvoid ContourParams::MakeNewContours(string varName)\n{\n    Contours newContours(_ssave);\n\n    MapperFunction *mf = GetMapperFunc(varName);\n    VAssert(mf);\n    vector<double> minMax = mf->getMinMaxMapValue();\n    int            numContours = newContours.GetContourValues().size();\n    double         spacing = (minMax[1] - minMax[0]) / (numContours - 1);\n\n    GenerateContourValues(minMax[0], spacing, numContours, &newContours);\n\n    _contours->Insert(&newContours, varName);\n}\n\nvoid ContourParams::GenerateContourValues(double start, double spacing, int num, Contours *c)\n{\n    if (!c) c = GetCurrentContours();\n\n    vector<double> vals;\n    for (int i = 0; i < num; i++) vals.push_back(start + i * spacing);\n    c->SetContourValues(vals);\n}\n\n// Set everything to default values\nvoid ContourParams::_init()\n{\n    SetDiagMsg(\"ContourParams::_init()\");\n\n    float rgb[] = {1., 1., 1.};\n    SetConstantColor(rgb);\n\n    GetBox()->SetPlanar(true);\n    GetBox()->SetOrientation(VAPoR::Box::XY);\n    SetDefaultVariables(2, true);\n}\n\nint ContourParams::GetContourCount()\n{\n    Contours *     c = GetCurrentContours();\n    vector<double> vals = c->GetContourValues();\n    return vals.size();\n}\n\ndouble ContourParams::GetContourMin()\n{\n    Contours *     c = GetCurrentContours();\n    vector<double> vals = c->GetContourValues();\n    return vals[0];\n}\n\ndouble ContourParams::GetContourMax()\n{\n    Contours *     c = GetCurrentContours();\n    vector<double> vals = c->GetContourValues();\n    return vals[vals.size() - 1];\n}\n\ndouble ContourParams::GetContourSpacing()\n{\n    Contours *     c = GetCurrentContours();\n    vector<double> vals = c->GetContourValues();\n\n    if (vals.size() < 2)\n        return 1;\n    else\n        return vals[1] - vals[0];\n}\n\nvoid ContourParams::SetContourCount(int num) { GenerateContourValues(GetContourMin(), GetContourSpacing(), num); }\n\nvoid ContourParams::SetContourMin(double val) { GenerateContourValues(val, GetContourSpacing(), GetContourCount()); }\n\nvoid ContourParams::SetContourSpacing(double val) { GenerateContourValues(GetContourMin(), val, GetContourCount()); }\n\nvoid ContourParams::GetLineColor(int lineNum, float color[3])\n{\n    if (UseSingleColor()) {\n        GetConstantColor(color);\n    } else {\n        string          varName = GetVariableName();\n        MapperFunction *tf = 0;\n        tf = (MapperFunction *)GetMapperFunc(varName);\n        VAssert(tf);\n\n        vector<double> vals = GetContourValues(varName);\n        double         val = vals[lineNum];\n\n        tf->rgbValue(val, color);\n    }\n}\n\nvoid ContourParams::SetLockToTF(bool lock)\n{\n    string l = \"false\";\n    if (lock) { l = \"true\"; }\n    SetValueString(_lockToTFTag, \"Lock settings to TF\", l);\n}\n\nbool ContourParams::GetLockToTF() const\n{\n    if (GetValueString(_lockToTFTag, \"false\") == \"false\") {\n        return false;\n    } else {\n        return true;\n    }\n}\n\nbool ContourParams::GetTextEnabled() const\n{\n    if (GetValueString(_textEnabledTag, \"false\") == \"false\") {\n        return false;\n    } else {\n        return true;\n    }\n}\n\nvoid ContourParams::SetTFLock(bool lock)\n{\n    string l = \"false\";\n    if (lock) l = \"true\";\n    SetValueString(_lockToTFTag,\n                   \"Lock contours to transfer function\"\n                   \" bounds\",\n                   l);\n}\n\nbool ContourParams::GetTFLock()\n{\n    string l = GetValueString(_lockToTFTag, \"false\");\n    if (l == \"false\") return false;\n    return true;\n}\n\nContourParams::Contours::Contours(ParamsBase::StateSave *ssave) : ParamsBase(ssave, Contours::GetClassType()) {}\n\nContourParams::Contours::Contours(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\nContourParams::Contours::~Contours() { MyBase::SetDiagMsg(\"Contours::~Contours() this=%p\", this); }\n\n};    // end namespace VAPoR\n"
  },
  {
    "path": "lib/params/DataStatus.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tDataStatus.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tFebruary 2006\n//\n//\tDescription:\tImplements the DataStatus class\n//\n#ifdef WIN32\n    #pragma warning(disable : 4251 4100)\n#endif\n\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <cfloat>\n#include <algorithm>\n\n#include <vapor/DataStatus.h>\n#include <vapor/DataMgr.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/PythonDataMgr.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/Proj4API.h>\n#include <vapor/UDUnitsClass.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nnamespace {\nvoid print_extents(string header, const CoordType &minExts, const CoordType &maxExts)\n{\n#ifdef DEBUG\n    VAssert(minExts.size() == maxExts.size());\n\n    cout << endl;\n    cout << header << endl;\n\n    for (int i = 0; i < minExts.size(); i++) { cout << \"\\t\" << minExts[i] << \" \" << maxExts[i] << endl; }\n    cout << endl;\n#endif\n}\n};    // namespace\n\n// Default constructor\n// Whether or not it exists on disk, what's its max and min\n// What resolutions are available.\n//\nDataStatus::DataStatus(size_t cacheSize, int nThreads)\n{\n    _cacheSize = cacheSize;\n    _nThreads = nThreads;\n\n    _dataMgrs.clear();\n    _timeCoords.clear();\n    _timeCoordsFormatted.clear();\n    _timeMap.clear();\n\n    reset_time();\n}\n\nint DataStatus::Open(const std::vector<string> &files, const std::vector<string> &options, string name, string format)\n{\n    VAssert(!name.empty());\n    vector<string> myOptions = options;\n\n    Close(name);\n    \n    DataMgr *dataMgr;\n    if (format == \"ram\")\n        dataMgr = new PythonDataMgr(format, _cacheSize, _nThreads);\n    else\n        dataMgr = new DataMgr(format, _cacheSize, _nThreads);\n\n    // Ensure all data managers use the same proj4 string. Note, it's\n    // possible that 'options' will already have a -proj4 string argument.\n    // The one we add here will take precedence because it is last in\n    // the list. This is a bit of a hack. To ensure that a -proj argument\n    // already present in the 'options' parameter is honored the dataMgr\n    // map should be empty. I.e. the first open data mgr.\n    //\n    if (_dataMgrs.size()) {\n        map<string, DataMgr *>::iterator itr = _dataMgrs.begin();\n        DataMgr *                        dm0 = itr->second;\n\n        myOptions.push_back(\"-proj4\");\n        myOptions.push_back(dm0->GetMapProjection());\n    }\n\n    int rc = dataMgr->Initialize(files, myOptions);\n    if (rc < 0) {\n        delete dataMgr;\n        return (-1);\n    }\n\n    _dataMgrs[name] = dataMgr;\n\n    reset_time();\n\n    return (0);\n}\n\nvoid DataStatus::Close(string name)\n{\n    if (name.empty()) name = \"DataSet1\";\n\n    map<string, DataMgr *>::iterator itr;\n    if ((itr = _dataMgrs.find(name)) != _dataMgrs.end()) {\n        if (itr->second) delete itr->second;\n        _dataMgrs.erase(itr);\n    }\n\n    reset_time();\n}\n\n// const DataMgr *DataStatus::GetDataMgr(string name) const\nDataMgr *DataStatus::GetDataMgr(string name) const\n{\n    if (name.empty()) name = \"DataSet1\";\n\n    map<string, DataMgr *>::const_iterator itr;\n    itr = _dataMgrs.find(name);\n\n    if (itr == _dataMgrs.end()) return (NULL);\n\n    return (itr->second);\n}\n\nvector<string> DataStatus::GetDataMgrNames() const\n{\n    vector<string> names;\n\n    map<string, DataMgr *>::const_iterator itr;\n    for (itr = _dataMgrs.begin(); itr != _dataMgrs.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nvoid DataStatus::_getExtents(size_t ts, const map<string, vector<var_info_t>> &varMap, CoordType &minExts, CoordType &maxExts) const\n{\n    minExts = {0.0, 0.0, 0.0};\n    maxExts = {0.0, 0.0, 0.0};\n\n    if (varMap.empty()) return;\n\n    vector<double> tmpMinExts(3, std::numeric_limits<double>::max());\n    vector<double> tmpMaxExts(3, std::numeric_limits<double>::lowest());\n\n    map<string, vector<var_info_t>>::const_iterator itr;\n    for (itr = varMap.begin(); itr != varMap.end(); ++itr) {\n        string dataSetName = itr->first;\n\n        DataMgr *dataMgr = GetDataMgr(dataSetName);\n        if (!dataMgr) continue;\n\n        size_t local_ts = MapGlobalToLocalTimeStep(dataSetName, ts);\n\n        const vector<var_info_t> &variables = itr->second;\n\n        for (auto it = variables.begin(); it != variables.end(); ++it) {\n            const var_info_t &var = *it;\n\n            CoordType      minVExts, maxVExts;\n            vector<int>    axes;\n            bool           status = DataMgrUtils::GetExtents(dataMgr, local_ts, var.varnames, var.refLevel, var.compLevel, minVExts, maxVExts, axes);\n            if (!status) continue;\n\n            if (axes.size() == 2) {\n                bool has3D = !dataMgr->GetDataVarNames(3).empty();\n\n                if (has3D) {\n                    double z = DataMgrUtils::Get2DRendererDefaultZ(dataMgr, ts, var.refLevel, var.compLevel);\n                    minVExts[2] = z;\n                    maxVExts[2] = z;\n                    axes.push_back(2);\n                }\n            }\n\n            print_extents(dataSetName, minVExts, maxVExts);\n\n            for (int i = 0; i < axes.size(); i++) {\n                int axis = axes[i];\n\n                if (minVExts[i] < tmpMinExts[axis]) { tmpMinExts[axis] = minVExts[i]; }\n                if (maxVExts[i] > tmpMaxExts[axis]) { tmpMaxExts[axis] = maxVExts[i]; }\n            }\n        }\n    }\n\n    // tmp{Min,Max}Exts are always 3D vectors. If all variables are 2D\n    // and live in same plane the returned {min,max}Exts should have\n    // size of 2.\n    //\n    for (int i = 0; i < tmpMinExts.size(); i++) {\n        if (tmpMinExts[i] != std::numeric_limits<double>::max()) {\n            minExts[i] = tmpMinExts[i];\n            maxExts[i] = tmpMaxExts[i];\n        }\n    }\n    print_extents(\"Dataset union\", minExts, maxExts);\n    return;\n}\n\nmap<string, vector<DataStatus::var_info_t>> DataStatus::_getFirstVar(string dataSetName, size_t &ts) const\n{\n    map<string, vector<var_info_t>> defaultVars;\n\n    DataMgr *dataMgr = GetDataMgr(dataSetName);\n    for (int dim = 3; dim > 1; dim--) {\n        string varname;\n        bool   ok = DataMgrUtils::GetFirstExistingVariable(dataMgr, 0, 0, dim, varname, ts);\n        if (ok) {\n            var_info_t var;\n            var.varnames = vector<string>(1, varname);\n            var.refLevel = 0;\n            var.compLevel = 0;\n            defaultVars[dataSetName] = vector<var_info_t>(1, var);\n            break;\n        }\n    }\n    return (defaultVars);\n}\n\nvoid DataStatus::GetActiveExtents(const ParamsMgr *paramsMgr, string winName, string dataSetName, size_t ts, CoordType &minExts, CoordType &maxExts) const\n{\n    map<string, vector<var_info_t>> varMap;\n\n    vector<RenderParams *> rParams;\n    paramsMgr->GetRenderParams(winName, dataSetName, rParams);\n\n    vector<var_info_t> variables;\n    for (int j = 0; j < rParams.size(); j++) {\n        if (!rParams[j]->IsEnabled()) continue;\n        string     varname = rParams[j]->GetVariableName();\n        var_info_t var;\n        var.refLevel = rParams[j]->GetRefinementLevel();\n        var.compLevel = rParams[j]->GetCompressionLevel();\n\n        if (!varname.empty()) {\n            var.varnames.push_back(varname);\n            variables.push_back(var);\n        }\n\n        vector<string> fvarnames = rParams[j]->GetFieldVariableNames();\n        for (int k = 0; k < fvarnames.size(); k++) {\n            if (!fvarnames[k].empty()) {\n                var.varnames.push_back(fvarnames[k]);\n                variables.push_back(var);\n            }\n        }\n\n        vector<string> auxVarNames = rParams[j]->GetAuxVariableNames();\n        for (int k = 0; k < auxVarNames.size(); k++) {\n            if (!auxVarNames[k].empty()) var.varnames.push_back(auxVarNames[k]);\n            variables.push_back(var);\n        }\n    }\n    if (variables.size()) {\n        varMap[dataSetName] = variables;\n    } else {\n        // If we didn't find any enabled variable use the first variables\n        // found in each data set\n        //\n        varMap = _getFirstVar(dataSetName, ts);\n    }\n\n    _getExtents(ts, varMap, minExts, maxExts);\n}\n\nvoid DataStatus::GetActiveExtents(const ParamsMgr *paramsMgr, string winName, size_t ts, CoordType &minExts, CoordType &maxExts) const\n{\n    for (int i = 0; i < minExts.size(); i++) {\n        minExts[i] = std::numeric_limits<double>::max();\n        maxExts[i] = std::numeric_limits<double>::lowest();\n    }\n\n    vector<string> dataSetNames = GetDataMgrNames();\n\n    for (int i = 0; i < dataSetNames.size(); i++) {\n        CoordType minWExts, maxWExts;\n        GetActiveExtents(paramsMgr, winName, dataSetNames[i], ts, minWExts, maxWExts);\n\n        for (int j = 0; j < minWExts.size(); j++) {\n            if (minWExts[j] < minExts[j]) { minExts[j] = minWExts[j]; }\n            if (maxWExts[j] > maxExts[j]) { maxExts[j] = maxWExts[j]; }\n        }\n    }\n}\n\nvoid DataStatus::GetActiveExtents(const ParamsMgr *paramsMgr, size_t ts, CoordType &minExts, CoordType &maxExts) const\n{\n    for (int i = 0; i < minExts.size(); i++) {\n        minExts[i] = std::numeric_limits<double>::max();\n        maxExts[i] = std::numeric_limits<double>::lowest();\n    }\n\n    vector<string> winNames = paramsMgr->GetVisualizerNames();\n\n    for (int i = 0; i < winNames.size(); i++) {\n        CoordType minWExts, maxWExts;\n        GetActiveExtents(paramsMgr, winNames[i], ts, minWExts, maxWExts);\n\n        for (int j = 0; j < minWExts.size(); j++) {\n            if (minWExts[j] < minExts[j]) { minExts[j] = minWExts[j]; }\n            if (maxWExts[j] > maxExts[j]) { maxExts[j] = maxWExts[j]; }\n        }\n    }\n}\n\nsize_t DataStatus::MapGlobalToLocalTimeStep(string dataSetName, size_t ts) const\n{\n    map<string, vector<size_t>>::const_iterator itr;\n    itr = _timeMap.find(dataSetName);\n    if (itr == _timeMap.end()) return (0);\n\n    const vector<size_t> &ref = itr->second;\n    if (ts >= ref.size()) { ts = ref.size() - 1; }\n    return (ref[ts]);\n}\n\nvoid DataStatus::MapLocalToGlobalTimeRange(string dataSetName, size_t local_ts, size_t &min_ts, size_t &max_ts) const\n{\n    min_ts = max_ts = 0;\n\n    map<string, vector<size_t>>::const_iterator itr;\n    itr = _timeMap.find(dataSetName);\n    if (itr == _timeMap.end()) return;\n\n    const vector<size_t> &                 ref = itr->second;\n    vector<size_t>::const_iterator         itr1;\n    vector<size_t>::const_reverse_iterator itr2;\n\n    itr1 = find(ref.begin(), ref.end(), local_ts);\n    if (itr1 == ref.end()) return;\n\n    itr2 = find(ref.rbegin(), ref.rend(), local_ts);\n    if (itr2 == ref.rend()) return;\n\n    min_ts = itr1 - ref.begin();\n    max_ts = ref.rend() - itr2 - 1;\n}\n\nstring DataStatus::GetMapProjection() const\n{\n    if (_dataMgrs.empty()) return (\"\");\n\n    map<string, DataMgr *>::const_iterator itr = _dataMgrs.begin();\n    DataMgr *                              dm0 = itr->second;\n\n    return (dm0->GetMapProjection());\n}\n\nstring DataStatus::GetMapProjectionDefault(string dataSetName) const\n{\n    DataMgr *dataMgr = GetDataMgr(dataSetName);\n    if (!dataMgr) return (\"\");\n\n    return (dataMgr->GetMapProjectionDefault());\n}\n\nnamespace {\nint find_nearest(const vector<double> &timeCoords, double time)\n{\n    if (!timeCoords.size()) return (-1);\n\n    if (time <= timeCoords[0]) return (0);\n    if (time >= timeCoords[timeCoords.size() - 1]) return (timeCoords.size() - 1);\n\n    // If we get to here there must be at least two elements in timeCoords\n    //\n    VAssert(timeCoords.size() >= 2);\n\n    for (int i = 0; i < timeCoords.size() - 1; i++) {\n        if (time >= timeCoords[i] && time <= timeCoords[i + 1]) {\n            VAssert(timeCoords[i] != timeCoords[i + 1]);\n\n            double s = (time - timeCoords[i]) / (timeCoords[i + 1] - timeCoords[i]);\n            if (s <= 0.5) {\n                return (i);\n            } else {\n                return (i + 1);\n            }\n        }\n    }\n    VAssert(0);\n    return -1;\n}\n};    // namespace\n\nvoid DataStatus::reset_time_helper()\n{\n    _timeCoordsFormatted = vector<string>(_timeCoords.size(), \"\");\n\n    UDUnits udunits;\n    int     rc = udunits.Initialize();\n    if (rc < 0) return;\n\n    char buf[80];\n\n    for (int i = 0; i < _timeCoords.size(); i++) {\n        int year, month, day, hour, minute, second;\n\n        udunits.DecodeTime(_timeCoords[i], &year, &month, &day, &hour, &minute, &second);\n        snprintf(buf, 80, \"%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d\", year, month, day, hour, minute, second);\n\n        _timeCoordsFormatted[i] = string(buf);\n    }\n}\n\nvoid DataStatus::reset_time()\n{\n    _timeCoords.clear();\n    _timeMap.clear();\n\n    if (_dataMgrs.size() == 0) return;\n\n    // First construct global list of time coordinates\n    //\n    map<string, DataMgr *>::const_iterator itr;\n    for (itr = _dataMgrs.begin(); itr != _dataMgrs.end(); ++itr) {\n        DataMgr *dataMgr = itr->second;\n\n        vector<double> t = dataMgr->GetTimeCoordinates();\n        _timeCoords.insert(_timeCoords.end(), t.begin(), t.end());\n    }\n\n    sort(_timeCoords.begin(), _timeCoords.end());\n    // This is a NOP as it is used incorrectly and has been since 2017 so disabling for now\n    // unique(_timeCoords.begin(), _timeCoords.end());\n\n    for (itr = _dataMgrs.begin(); itr != _dataMgrs.end(); ++itr) {\n        string   dataSetName = itr->first;\n        DataMgr *dataMgr = itr->second;\n\n        vector<size_t> timeSteps;\n        vector<double> t = dataMgr->GetTimeCoordinates();\n        for (int i = 0; i < _timeCoords.size(); i++) {\n            int idx = find_nearest(t, _timeCoords[i]);\n            timeSteps.push_back(idx);\n        }\n        _timeMap[dataSetName] = timeSteps;\n    }\n\n    reset_time_helper();\n}\n\nDataStatus::~DataStatus() {}\n\n#ifdef VAPOR3_0_0_ALPHA\n// Map corners of box to voxels.\nvoid DataStatus::mapBoxToVox(Box *box, string varname, int refLevel, int lod, int timestep, size_t voxExts[6])\n{\n    double userExts[6];\n    box->GetUserExtents(userExts, (size_t)timestep);\n    vector<double> minexts, maxexts;\n    for (int i = 0; i < 3; i++) {\n        minexts.push_back(userExts[i]);\n        maxexts.push_back(userExts[i + 3]);\n    }\n    bool            errEnabled = MyBase::EnableErrMsg(false);\n    StructuredGrid *rg = dataMgr->GetVariable(timestep, varname, refLevel, lod, minexts, maxexts);\n    MyBase::EnableErrMsg(errEnabled);\n\n    if (rg) {\n        rg->GetIJKIndex(minexts[0], minexts[1], minexts[2], voxExts, voxExts + 1, voxExts + 2);\n        rg->GetIJKIndex(maxexts[0], maxexts[1], maxexts[2], voxExts + 3, voxExts + 4, voxExts + 5);\n    } else {\n        for (int i = 0; i < 6; i++) voxExts[i] = 0;\n    }\n    //(Note: this can be expensive with layered data)\n    return;\n}\n\n#endif\n"
  },
  {
    "path": "lib/params/DatasetsParams.cpp",
    "content": "\n#include <string>\n#include <vapor/ParamsBase.h>\n#include <vapor/DatasetsParams.h>\n\nnamespace VAPoR {\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<DatasetsParams>              registrar(DatasetsParams::GetClassType());\nstatic ParamsRegistrar<DatasetParams>               registrar1(DatasetParams::GetClassType());\nstatic ParamsRegistrar<DatasetParams::ScriptParams> registrar2(DatasetParams::ScriptParams::GetClassType());\n\nconst string DatasetsParams::_datasetsTag = \"Datasets\";\n\nconst string DatasetParams::_datasetTag = \"Dataset\";\nconst string DatasetParams::_scriptsTag = \"Scripts\";\n\nconst string DatasetParams::ScriptParams::_scriptTag = \"Script\";\nconst string DatasetParams::ScriptParams::_inputVarNamesTag = \"InputVarNames\";\nconst string DatasetParams::ScriptParams::_outputVarNamesTag = \"OutputVarNames\";\nconst string DatasetParams::ScriptParams::_outputVarMeshesTag = \"OutputVarMeshes\";\nconst string DatasetParams::ScriptParams::_coordFlagTag = \"CoordFlag\";\n\n// DatasetsParams class: A collection of data sets\n//\n\nDatasetsParams::DatasetsParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, DatasetsParams::GetClassType())\n{\n    SetDiagMsg(\"DatasetsParams::DatasetsParams() this=%p\", this);\n\n    _datasets = new ParamsContainer(ssave, _datasetsTag);\n    _datasets->SetParent(this);\n}\n\nDatasetsParams::DatasetsParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    SetDiagMsg(\"DatasetsParams::DatasetsParams() this=%p\", this);\n\n    if (node->HasChild(_datasetsTag)) {\n        _datasets = new ParamsContainer(ssave, node->GetChild(_datasetsTag));\n    } else {\n        // Node doesn't contain a contours container\n        _datasets = new ParamsContainer(ssave, _datasetsTag);\n        _datasets->SetParent(this);\n    }\n}\n\nDatasetsParams::DatasetsParams(const DatasetsParams &rhs) : ParamsBase(rhs) { _datasets = new ParamsContainer(*(rhs._datasets)); }\n\nDatasetsParams &DatasetsParams::operator=(const DatasetsParams &rhs)\n{\n    if (_datasets) delete _datasets;\n\n    ParamsBase::operator=(rhs);\n    _datasets = new ParamsContainer(*(rhs._datasets));\n\n    return (*this);\n}\n\nDatasetsParams::~DatasetsParams()\n{\n    SetDiagMsg(\"DatasetsParams::~DatasetsParams() this=%p\", this);\n\n    if (_datasets != NULL) {\n        delete _datasets;\n        _datasets = NULL;\n    }\n}\n\nvoid DatasetsParams::SetScript(string datasetName, string name, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames, const vector<string> &outputVarMeshes,\n                               bool coordFlag)\n{\n    DatasetParams *s = (DatasetParams *)_datasets->GetParams(datasetName);\n    if (s == NULL) {\n        DatasetParams sParams(_ssave);\n\n        _datasets->Insert(&sParams, datasetName);\n        s = (DatasetParams *)_datasets->GetParams(datasetName);\n        VAssert(s);\n    }\n\n    s->SetScript(name, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag);\n}\n\nbool DatasetsParams::GetScript(string datasetName, string name, string &script, vector<string> &inputVarNames, vector<string> &outputVarNames, vector<string> &outputVarMeshes, bool &coordFlag) const\n{\n    script.clear();\n    inputVarNames.clear();\n    outputVarNames.clear();\n    outputVarMeshes.clear();\n\n    DatasetParams *s = (DatasetParams *)_datasets->GetParams(datasetName);\n    if (s == NULL) return (false);\n\n    s->GetScript(name, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag);\n\n    return (true);\n}\n\nvoid DatasetsParams::RemoveScript(string datasetName, string scriptName)\n{\n    DatasetParams *s = (DatasetParams *)_datasets->GetParams(datasetName);\n    if (s == NULL) return;\n    s->RemoveScript(scriptName);\n}\n\nvector<string> DatasetsParams::GetScriptNames(string datasetName) const\n{\n    DatasetParams *s = (DatasetParams *)_datasets->GetParams(datasetName);\n    if (s == NULL) return (vector<string>());\n    return (s->GetScriptNames());\n}\n\n// DatasetParams class: A single data set\n//\nDatasetParams::DatasetParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, DatasetParams::GetClassType())\n{\n    SetDiagMsg(\"DatasetParams::DatasetParams() this=%p\", this);\n\n    _scripts = new ParamsContainer(ssave, _scriptsTag);\n    _scripts->SetParent(this);\n}\n\nDatasetParams::DatasetParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    SetDiagMsg(\"DatasetParams::DatasetParams() this=%p\", this);\n\n    // If node isn't tagged correctly we correct the tag and reinitialize\n    // from scratch;\n    //\n    if (node->GetTag() != DatasetParams::GetClassType()) { node->SetTag(DatasetParams::GetClassType()); }\n\n    if (node->HasChild(_scriptsTag)) {\n        _scripts = new ParamsContainer(ssave, node->GetChild(_scriptsTag));\n    } else {\n        // Node doesn't contain a contours container\n        _scripts = new ParamsContainer(ssave, _scriptsTag);\n        _scripts->SetParent(this);\n    }\n}\n\nDatasetParams::DatasetParams(const DatasetParams &rhs) : ParamsBase(rhs) { _scripts = new ParamsContainer(*(rhs._scripts)); }\n\nDatasetParams &DatasetParams::operator=(const DatasetParams &rhs)\n{\n    if (_scripts) delete _scripts;\n\n    ParamsBase::operator=(rhs);\n    _scripts = new ParamsContainer(*(rhs._scripts));\n\n    return (*this);\n}\n\nDatasetParams::~DatasetParams()\n{\n    SetDiagMsg(\"DatasetParams::~DatasetParams() this=%p\", this);\n\n    if (_scripts != NULL) {\n        delete _scripts;\n        _scripts = NULL;\n    }\n}\n\nvoid DatasetParams::SetScript(string name, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames, const vector<string> &outputVarMeshes, bool coordFlag)\n{\n    ScriptParams *s = (ScriptParams *)_scripts->GetParams(name);\n    if (s == NULL) {\n        ScriptParams sParams(_ssave);\n\n        _scripts->Insert(&sParams, name);\n        s = (ScriptParams *)_scripts->GetParams(name);\n        VAssert(s);\n    }\n\n    s->SetScript(script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag);\n}\n\nbool DatasetParams::GetScript(string name, string &script, vector<string> &inputVarNames, vector<string> &outputVarNames, vector<string> &outputVarMeshes, bool &coordFlag) const\n{\n    script.clear();\n    inputVarNames.clear();\n    outputVarNames.clear();\n    outputVarMeshes.clear();\n\n    ScriptParams *s = (ScriptParams *)_scripts->GetParams(name);\n    if (s == NULL) return (false);\n\n    s->GetScript(script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag);\n\n    return (true);\n}\n\n};    // end namespace VAPoR\n"
  },
  {
    "path": "lib/params/FlowParams.cpp",
    "content": "#include \"vapor/FlowParams.h\"\n#include <vapor/FileUtils.h>\n#include <vapor/ResourcePath.h>\n\nusing namespace VAPoR;\n\nconst std::string FlowParams::RenderTypeTag = \"RenderTypeTag\";\nconst std::string FlowParams::RenderRadiusBaseTag = \"RenderRadiusBaseTag\";\nconst std::string FlowParams::RenderRadiusScalarTag = \"RenderRadiusScalarTag\";\nconst std::string FlowParams::RenderGeom3DTag = \"RenderGeom3DTag\";\nconst std::string FlowParams::RenderLightAtCameraTag = \"RenderLightAtCameraTag\";\nconst std::string FlowParams::RenderShowStreamDirTag = \"RenderShowStreamDirTag\";\nconst std::string FlowParams::RenderGlyphTypeTag = \"RenderGlyphTypeTag\";\nconst std::string FlowParams::RenderGlyphStrideTag = \"RenderGlyphStrideTag\";\nconst std::string FlowParams::RenderGlyphOnlyLeadingTag = \"RenderGlyphOnlyLeadingTag\";\nconst std::string FlowParams::RenderDensityFalloffTag = \"RenderDensityFalloffTag\";\nconst std::string FlowParams::RenderDensityToneMappingTag = \"RenderDensityToneMappingTag\";\nconst std::string FlowParams::RenderFadeTailTag = \"RenderFadeTailTag\";\nconst std::string FlowParams::RenderFadeTailStartTag = \"RenderFadeTailStartTag\";\nconst std::string FlowParams::RenderFadeTailStopTag = \"RenderFadeTailStopTag\";\nconst std::string FlowParams::RenderFadeTailLengthTag = \"RenderFadeTailLengthTag\";\nconst std::string FlowParams::PhongAmbientTag = \"PhongAmbientTag\";\nconst std::string FlowParams::PhongDiffuseTag = \"PhongDiffuseTag\";\nconst std::string FlowParams::PhongSpecularTag = \"PhongSpecularTag\";\nconst std::string FlowParams::PhongShininessTag = \"PhongShininessTag\";\n\nconst std::string FlowParams::_isSteadyTag = \"IsSteadyTag\";\nconst std::string FlowParams::_velocityMultiplierTag = \"VelocityMultiplierTag\";\nconst std::string FlowParams::_firstStepSizeMultiplierTag = \"FirstStepSizeMultiplierTag\";\nconst std::string FlowParams::_fixedAdvectionStepTag= \"FixedAdvectionStepTag\";\nconst std::string FlowParams::_fixedAdvectionStepSizeTag= \"FixedAdvectionStepSizeTag\";\nconst std::string FlowParams::_steadyNumOfStepsTag = \"SteadyNumOfStepsTag\";\nconst std::string FlowParams::_seedGenModeTag = \"SeedGenModeTag\";\nconst std::string FlowParams::_seedInputFilenameTag = \"SeedInputFilenameTag\";\nconst std::string FlowParams::_flowlineOutputFilenameTag = \"FlowlineOutputFilenameTag\";\nconst std::string FlowParams::_flowOutputMoreVariablesTag = \"FlowOutputMoreVariablesTag\";\nconst std::string FlowParams::_flowDirectionTag = \"FlowDirectionTag\";\nconst std::string FlowParams::_needFlowlineOutputTag = \"NeedFlowlineOutputTag\";\nconst std::string FlowParams::_xPeriodicTag = \"PeriodicTag_X\";\nconst std::string FlowParams::_yPeriodicTag = \"PeriodicTag_Y\";\nconst std::string FlowParams::_zPeriodicTag = \"PeriodicTag_Z\";\nconst std::string FlowParams::_rakeTag = \"RakeTag\";\nconst std::string FlowParams::_doIntegrationTag = \"DoIntegrationTag\";\nconst std::string FlowParams::_integrationScalarTag = \"IntegrationScalarTag\";\nconst std::string FlowParams::_integrationSetAllToFinalValueTag = \"IntegrationSetAllToFinalValueTag\";\nconst std::string FlowParams::_integrationBoxTag = \"IntegrationBoxTag\";\nconst std::string FlowParams::_rakeBiasVariable = \"RakeBiasVariable\";\nconst std::string FlowParams::_rakeBiasStrength = \"RakeBiasStrength\";\nconst std::string FlowParams::_pastNumOfTimeSteps = \"PastNumOfTimeSteps\";\nconst std::string FlowParams::_seedInjInterval = \"SeedInjInterval\";\nconst std::string FlowParams::_xGridNumOfSeedsTag = \"GridNumOfSeeds_X\";\nconst std::string FlowParams::_yGridNumOfSeedsTag = \"GridNumOfSeeds_Y\";\nconst std::string FlowParams::_zGridNumOfSeedsTag = \"GridNumOfSeeds_Z\";\nconst std::string FlowParams::_randomNumOfSeedsTag = \"RandomNumOfSeeds\";\n\nstatic RenParamsRegistrar<FlowParams> registrar(FlowParams::GetClassType());\n\n// Constructor\nFlowParams::FlowParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave) : RenderParams(dataManager, stateSave, FlowParams::GetClassType(), 3 /* max dim */)\n{\n    SetVariableName(\"\");\n    SetDiagMsg(\"FlowParams::FlowParams() this=%p\", this);\n\n    SetValueLong(RenderTypeTag, \"\", RenderTypeStream);\n    SetValueDouble(RenderRadiusBaseTag, \"\", -1);\n    SetValueDouble(RenderRadiusScalarTag, \"\", 1);\n    SetValueLong(RenderGeom3DTag, \"\", false);\n    SetValueLong(RenderLightAtCameraTag, \"\", true);\n    SetValueLong(RenderShowStreamDirTag, \"\", false);\n\n    SetValueLong(RenderGlyphTypeTag, \"\", GlpyhTypeSphere);\n    SetValueLong(RenderGlyphStrideTag, \"\", 5);\n    SetValueLong(RenderGlyphOnlyLeadingTag, \"\", false);\n\n    SetValueDouble(RenderDensityFalloffTag, \"\", 1);\n    SetValueDouble(RenderDensityToneMappingTag, \"\", 1);\n\n    SetValueLong(RenderFadeTailTag, \"\", false);\n    SetValueLong(RenderFadeTailStartTag, \"\", 10);\n    SetValueLong(RenderFadeTailLengthTag, \"\", 10);\n    SetValueLong(RenderFadeTailStopTag, \"\", 0);\n\n    SetValueDouble(PhongAmbientTag, \"\", 0.4);\n    SetValueDouble(PhongDiffuseTag, \"\", 0.8);\n    SetValueDouble(PhongSpecularTag, \"\", 0);\n    SetValueDouble(PhongShininessTag, \"\", 2);\n\n    // Give the random bias variable the same as color mapping variable.\n    auto colorvar = GetColorMapVariableName();\n    SetValueString(_rakeBiasVariable, \"which variable to bias with\", colorvar);\n}\n\nFlowParams::FlowParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *node) : RenderParams(dataManager, stateSave, node, 3 /* max dim */)\n{\n    _initialized = true;\n    SetDiagMsg(\"FlowParams::FlowParams() this=%p\", this);\n}\n\n// Destructor\nFlowParams::~FlowParams()\n{\n    SetDiagMsg(\"FlowParams::~FlowParams() this=%p\", this);\n    if (_fakeRakeBox) delete _fakeRakeBox;\n    if (_fakeIntegrationBox) delete _fakeIntegrationBox;\n}\n\nint FlowParams::Initialize()\n{\n    int rc = RenderParams::Initialize();\n    if (rc < 0) return (rc);\n    if (_initialized) return 0;\n\n    // At this point the base class is initialized, and the _Box is\n    // properly initialized\n    // to be the extents of the domain. Let's use that information to\n    // initialize the rake!\n    //\n    std::vector<double> minext, maxext;\n    auto                box = RenderParams::GetBox();\n    box->GetExtents(minext, maxext);\n    std::vector<float> floats(minext.size() * 2);\n    for (int i = 0; i < minext.size(); i++) {\n        floats[i * 2] = minext[i];\n        floats[i * 2 + 1] = maxext[i];\n    }\n    this->SetRake(floats);\n    this->SetIntegrationVolume(floats);\n\n    vector<float> rake;\n    rake.push_back(minext[0]);\n    rake.push_back(maxext[0]);\n    rake.push_back(minext[1]);\n    rake.push_back(maxext[1]);\n    if (minext.size() == 3) {\n        rake.push_back(minext[2]);\n        rake.push_back(maxext[2]);\n    }\n    SetRake(rake);\n    SetIntegrationVolume(rake);\n\n    SetFlowDirection((int)FlowDir::FORWARD);\n    SetSteadyNumOfSteps(100);\n    SetVelocityMultiplier(1.0);\n    SetFirstStepSizeMultiplier(1.0);\n    SetUseFixedAdvectionSteps(false);\n    SetFixedAdvectionStepSize(0.0);\n    SetPeriodic(vector<bool>(3, false));\n    SetGridNumOfSeeds({5, 5, 1});\n    SetRandomNumOfSeeds(50);\n    SetFlowlineOutputFilename(Wasp::FileUtils::HomeDir() + \"/VaporFlow.txt\");\n    SetSeedInputFilename(Wasp::GetSharePath(\"examples/listOfSeeds.txt\"));\n    SetIsSteady(true);\n    SetPastNumOfTimeSteps(std::max(_dataMgr->GetNumTimeSteps() - 1, 1));\n    SetValueLong(_doIntegrationTag, \"\", false);\n    SetValueDouble(_integrationScalarTag, \"\", 1.f);\n    SetValueLong(_integrationSetAllToFinalValueTag, \"\", false);\n\n    return (0);\n}\n\nvoid FlowParams::SetDefaultVariables(int dim, bool secondaryColormapVariable) {\n    RenderParams::SetDefaultVariables(dim, secondaryColormapVariable);\n\n    std::vector<std::string> varnames = _dataMgr->GetDataVarNames(dim);\n    if (varnames.size())\n        SetRakeBiasVariable(varnames[0]);\n}\n\nvoid FlowParams::SetIsSteady(bool steady) { SetValueLong(_isSteadyTag, \"are we using steady advection\", long(steady)); }\n\nbool FlowParams::GetIsSteady() const\n{\n    long rv = GetValueLong(_isSteadyTag, long(true));\n    return bool(rv);\n}\n\nvoid FlowParams::SetNeedFlowlineOutput(bool need) { SetValueLong(_needFlowlineOutputTag, \"need to do an output of the flow lines\", long(need)); }\n\nbool FlowParams::GetNeedFlowlineOutput() const\n{\n    long rv = GetValueLong(_needFlowlineOutputTag, long(false));\n    return bool(rv);\n}\n\ndouble FlowParams::GetVelocityMultiplier() const { return GetValueDouble(_velocityMultiplierTag, 1.0); }\n\ndouble FlowParams::GetFirstStepSizeMultiplier() const { return GetValueDouble(_firstStepSizeMultiplierTag, 1.0); }\n\nbool FlowParams::GetUseFixedAdvectionSteps() const { return GetValueLong(_fixedAdvectionStepTag, 0); }\n\ndouble FlowParams::GetFixedAdvectionStepSize() const { return GetValueDouble(_fixedAdvectionStepSizeTag, 0.0); }\n\nvoid FlowParams::SetVelocityMultiplier(double coeff) { SetValueDouble(_velocityMultiplierTag, \"Field Scale Factor\", coeff); }\n\nvoid FlowParams::SetFirstStepSizeMultiplier(double coeff) { SetValueDouble(_firstStepSizeMultiplierTag, \"first step size multiplier\", coeff); }\n\nvoid FlowParams::SetUseFixedAdvectionSteps(bool fixed) { SetValueLong(_fixedAdvectionStepTag, \"Use Fixed Advection Steps\", long(fixed)); }\n\nvoid FlowParams::SetFixedAdvectionStepSize(double step) { SetValueDouble(_fixedAdvectionStepSizeTag, \"Fixed Advection Step Size\", step); }\n\nlong FlowParams::GetSteadyNumOfSteps() const { return GetValueLong(_steadyNumOfStepsTag, 100); }\n\nvoid FlowParams::SetSteadyNumOfSteps(long i) { SetValueLong(_steadyNumOfStepsTag, \"num of steps for a steady integration\", i); }\n\nint FlowParams::GetSeedGenMode() const { return GetValueLong(_seedGenModeTag, (int)FlowSeedMode::UNIFORM); }\n\nvoid FlowParams::SetSeedGenMode(int i) { SetValueLong(_seedGenModeTag, \"\", i); }\n\nstd::string FlowParams::GetSeedInputFilename() const { return GetValueString(_seedInputFilenameTag, \"\"); }\n\nvoid FlowParams::SetSeedInputFilename(const std::string &name) { SetValueString(_seedInputFilenameTag, \"filename for input seeding list\", name); }\n\nstd::string FlowParams::GetFlowlineOutputFilename() const { return GetValueString(_flowlineOutputFilenameTag, \"\"); }\nvoid        FlowParams::SetFlowlineOutputFilename(const std::string &name) { SetValueString(_flowlineOutputFilenameTag, \"filename for output flow lines\", name); }\n\nstd::vector<std::string> FlowParams::GetFlowOutputMoreVariables() const { return GetValueStringVec(_flowOutputMoreVariablesTag); }\nvoid FlowParams::SetFlowOutputMoreVariables(std::vector<std::string> vars) { SetValueStringVec(_flowOutputMoreVariablesTag, \"\", vars); }\n\nint FlowParams::GetFlowDirection() const { return GetValueLong(_flowDirectionTag, (int)FlowDir::FORWARD); }\n\nvoid FlowParams::SetFlowDirection(int i)\n{\n    VAssert(i == (int)FlowDir::FORWARD || i == (int)FlowDir::BACKWARD || i == (int)FlowDir::BI_DIR);\n    SetValueLong(_flowDirectionTag, \"\", i);\n}\n\nstd::vector<bool> FlowParams::GetPeriodic() const\n{\n    vector<bool> sav;\n    sav.push_back(GetValueLong(_xPeriodicTag, false));\n    sav.push_back(GetValueLong(_yPeriodicTag, false));\n    if (GetRenderDim() == 3) sav.push_back(GetValueLong(_zPeriodicTag, false));\n\n    return sav;\n}\n\nvoid FlowParams::SetPeriodic(const std::vector<bool> &bools)\n{\n    VAssert(bools.size() == 3 || bools.size() == 2);\n    SetValueLong(_xPeriodicTag, \"\", bools[0]);\n    SetValueLong(_yPeriodicTag, \"\", bools[1]);\n    if (bools.size() == 3) SetValueLong(_zPeriodicTag, \"\", bools[2]);\n}\n\nvoid FakeRakeBox::Initialize(string tag)\n{\n    _tag = tag;\n\n    vector<double> flowBox = parent->GetValueDoubleVec(tag);\n    if (flowBox.size() != 4 && flowBox.size() != 6) {\n        vector<double> min, max;\n        parent->GetBox()->GetExtents(min, max);\n        SetExtents(min, max);\n        flowBox = parent->GetValueDoubleVec(tag);\n    }\n    vector<double> min, max;\n\n    min.push_back(flowBox[0]);\n    max.push_back(flowBox[1]);\n    min.push_back(flowBox[2]);\n    max.push_back(flowBox[3]);\n    if (flowBox.size() == 6) {\n        min.push_back(flowBox[4]);\n        max.push_back(flowBox[5]);\n    }\n\n    Box::SetExtents(min, max);\n}\n\nvoid FakeRakeBox::SetExtents(const vector<double> &min, const vector<double> &max)\n{\n    VAssert(parent);\n\n    vector<double> rake;\n    rake.push_back(min[0]);\n    rake.push_back(max[0]);\n    rake.push_back(min[1]);\n    rake.push_back(max[1]);\n    if (min.size() == 3) {\n        rake.push_back(min[2]);\n        rake.push_back(max[2]);\n    }\n\n    BeginGroup(\"Set fake region\");\n    parent->SetValueDoubleVec(_tag, \"\", rake);\n    Initialize(_tag);\n    EndGroup();\n}\n\nBox *FlowParams::GetRakeBox()\n{\n    if (!_fakeRakeBox) {\n        _fakeRakeBox = new FakeRakeBox(&_fakeRakeStateSave);\n        _fakeRakeBox->parent = this;\n    }\n\n    Box *extBox = GetBox();\n    _fakeRakeBox->SetPlanar(extBox->IsPlanar());\n    _fakeRakeBox->SetOrientation(extBox->GetOrientation());\n\n    _fakeRakeBox->Initialize(_rakeTag);\n\n    return _fakeRakeBox;\n}\n\nBox *FlowParams::GetIntegrationBox()\n{\n    if (!_fakeIntegrationBox) {\n        _fakeIntegrationBox = new FakeRakeBox(&_fakeRakeStateSave);\n        _fakeIntegrationBox->parent = this;\n    }\n\n    Box *extBox = GetBox();\n    _fakeIntegrationBox->SetPlanar(extBox->IsPlanar());\n    _fakeIntegrationBox->SetOrientation(extBox->GetOrientation());\n\n    _fakeIntegrationBox->Initialize(_integrationBoxTag);\n\n    return _fakeIntegrationBox;\n}\n\nstd::vector<float> FlowParams::GetRake() const\n{\n    auto          doubles = GetValueDoubleVec(_rakeTag);\n    vector<float> ret;\n\n    int dim = GetRenderDim();\n    for (int i = 0; i < dim * 2; i++) {\n        if (i < doubles.size())\n            ret.push_back(doubles[i]);\n        else\n            ret.push_back(5);\n    }\n    return ret;\n}\n\nvoid FlowParams::SetRake(const std::vector<float> &rake)\n{\n    const auto rakesize = rake.size();\n    VAssert(rakesize == 4 || rakesize == 6);\n    std::vector<double> doubles(rakesize);\n    std::copy(rake.cbegin(), rake.cend(), doubles.begin());\n    SetValueDoubleVec(_rakeTag, \"rake boundaries\", doubles);\n}\n\nvoid FlowParams::SetIntegrationVolume(const std::vector<float> &rake)\n{\n    const auto rakesize = rake.size();\n    VAssert(rakesize == 4 || rakesize == 6);\n    std::vector<double> doubles(rakesize);\n    std::copy(rake.cbegin(), rake.cend(), doubles.begin());\n    SetValueDoubleVec(_integrationBoxTag, \"\", doubles);\n}\n\nstd::vector<long> FlowParams::GetGridNumOfSeeds() const\n{\n    vector<long> sav(3);\n    sav[0] = GetValueLong(_xGridNumOfSeedsTag, 5);\n    sav[1] = GetValueLong(_yGridNumOfSeedsTag, 5);\n    sav[2] = GetValueLong(_zGridNumOfSeedsTag, 5);\n\n    vector<long> ret;\n    int          dims = GetRenderDim();\n\n    for (int i = 0; i < dims; i++) ret.push_back(sav[i]);\n\n    return ret;\n}\n\nvoid FlowParams::SetGridNumOfSeeds(const std::vector<long> &num)\n{\n    VAssert(num.size() == 3 || num.size() == 2);\n    SetValueLong(_xGridNumOfSeedsTag, \"\", num[0]);\n    SetValueLong(_yGridNumOfSeedsTag, \"\", num[1]);\n    if (num.size() == 3) SetValueLong(_zGridNumOfSeedsTag, \"\", num[2]);\n}\n\nlong FlowParams::GetRandomNumOfSeeds() const { return GetValueLong(_randomNumOfSeedsTag, 50); }\n\nvoid FlowParams::SetRandomNumOfSeeds(long num)\n{\n    VAssert(num >= 0);\n    SetValueLong(_randomNumOfSeedsTag, \"random num of seeds\", num);\n}\n\nstd::string FlowParams::GetRakeBiasVariable() const\n{\n    std::string empty;\n    return GetValueString(_rakeBiasVariable, empty);\n}\n\nvoid FlowParams::SetRakeBiasVariable(const std::string &varname) { SetValueString(_rakeBiasVariable, \"which variable to bias with\", varname); }\n\nlong FlowParams::GetRakeBiasStrength() const { return (GetValueLong(_rakeBiasStrength, 0)); }\n\nvoid FlowParams::SetRakeBiasStrength(long strength) { SetValueLong(_rakeBiasStrength, \"bias strength\", strength); }\n\nint FlowParams::GetPastNumOfTimeSteps() const\n{\n    // return -1 as an obvious invalid value. Valid values are greater than 0\n    return int(GetValueLong(_pastNumOfTimeSteps, -1));\n}\n\nvoid FlowParams::SetPastNumOfTimeSteps(int val) { SetValueLong(_pastNumOfTimeSteps, \"how many past time steps to render\", val); }\n\nint FlowParams::GetSeedInjInterval() const\n{\n    // return -1 as an obvious invalid value.\n    // 0 means no repeated seed injection\n    // 1 means every time step, 2 means every other time step, etc.\n    return int(GetValueLong(_seedInjInterval, -1));\n}\n\nvoid FlowParams::SetSeedInjInterval(int val) { SetValueLong(_seedInjInterval, \"What's the interval of injecting seeds into an unsteady flow advection\", val); }\n\ndouble FlowParams::_getRakeCenter(int dim)\n{\n    Box *rakeBox = GetRakeBox();\n    if (rakeBox == nullptr) return 0.;\n    VAPoR::CoordType minExt, maxExt;\n    rakeBox->GetExtents(minExt, maxExt);\n    return (maxExt[dim] + minExt[dim]) / 2.;\n}\n\nvoid FlowParams::_setRakeCenter(int dim, double center)\n{\n    Box *rakeBox = GetRakeBox();\n    if (rakeBox == nullptr) return;\n\n    VAPoR::CoordType minExt, maxExt;\n    rakeBox->GetExtents(minExt, maxExt);\n    double length = (maxExt[dim] - minExt[dim]) / 2.;\n    maxExt[dim] = center + length;\n    minExt[dim] = center - length;\n    rakeBox->SetExtents(minExt, maxExt);\n}\n\ndouble FlowParams::GetXRakeCenter() { return _getRakeCenter(0); }\n\nvoid FlowParams::SetXRakeCenter(double center) { _setRakeCenter(0, center); }\n\ndouble FlowParams::GetYRakeCenter() { return _getRakeCenter(1); }\n\nvoid FlowParams::SetYRakeCenter(double center) { _setRakeCenter(1, center); }\n\ndouble FlowParams::GetZRakeCenter() { return _getRakeCenter(2); }\n\nvoid FlowParams::SetZRakeCenter(double center) { _setRakeCenter(2, center); }\n"
  },
  {
    "path": "lib/params/GUIStateParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tGUIStateParams.cpp\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tAugust 2016\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n#include <cassert>\n\n#include <vapor/FileUtils.h>\n#include <vapor/MouseModeParams.h>\n#include <vapor/GUIStateParams.h>\n#include <vapor/BookmarkParams.h>\n#include <vapor/STLUtils.h>\n\nusing namespace VAPoR;\n\nconst string GUIStateParams::m_activeVisualizer = \"ActiveVisualizer\";\nconst string GUIStateParams::m_pathParamsTag = \"PathParamsTag\";\nconst string GUIStateParams::m_sessionFileTag = \"SessionFileTag\";\nconst string GUIStateParams::m_imagePathTag = \"ImagePathTag\";\nconst string GUIStateParams::m_imageSavePathTag = \"ImageSavePathTag\";\nconst string GUIStateParams::m_pythonPathTag = \"PythonPathTag\";\nconst string GUIStateParams::m_flowPathTag = \"FlowPathTag\";\nconst string GUIStateParams::m_tfPathTag = \"TFPathTag\";\nconst string GUIStateParams::m_statsDatasetNameTag = \"StatsDatasetNameTag\";\nconst string GUIStateParams::m_plotDatasetNameTag = \"PlotDatasetNameTag\";\nconst string GUIStateParams::m_proj4StringTag = \"Proj4StringTag\";\nconst string GUIStateParams::m_openDataSetsTag = \"OpenDataSetsTag\";\nconst string GUIStateParams::_flowDimensionalityTag = \"_flowDimensionalityTag\";\nconst string GUIStateParams::BookmarksTag = \"BookmarksTag\";\nconst string GUIStateParams::MovingDomainTrackCameraTag = \"MovingDomainTrackCameraTag\";\nconst string GUIStateParams::MovingDomainTrackRenderRegionsTag = \"MovingDomainTrackRenderRegionsTag\";\nconst string GUIStateParams::ImportDataTypeTag = \"ImportDataTypeTag\";\nconst string GUIStateParams::SessionNewTag = \"SessionNewTag\";\nconst string GUIStateParams::DataSetParam::m_dataSetPathsTag = \"DataSetPathsTag\";\nconst string GUIStateParams::DataSetParam::m_dataSetRelativePathsTag = \"DataSetRelativePathsTag\";\nconst string GUIStateParams::DataSetParam::m_dataSetFormatTag = \"DataSetFormatTag\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<GUIStateParams>               registrar(GUIStateParams::GetClassType());\nstatic ParamsRegistrar<GUIStateParams::DataSetParam> registrar_dsp(GUIStateParams::DataSetParam::GetClassType());\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nGUIStateParams::GUIStateParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, GetClassType())\n{\n    _init();\n\n    m_activeRenderer = new ActiveRenderer(ssave);\n    m_activeRenderer->GetNode()->SetParent(GetNode());\n\n    m_mouseModeParams = new MouseModeParams(ssave);\n    m_mouseModeParams->GetNode()->SetParent(GetNode());\n\n    // Create a Params container for multiple opacity maps\n    //\n    m_openDataSets = new ParamsContainer(ssave, m_openDataSetsTag);\n    m_openDataSets->SetParent(this);\n\n    _bookmarks = new ParamsContainer(ssave, BookmarksTag);\n    _bookmarks->SetParent(this);\n}\n\nGUIStateParams::GUIStateParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    // If node isn't tagged correctly we correct the tag and reinitialize\n    // from scratch;\n    //\n    if (node->GetTag() != GUIStateParams::GetClassType()) {\n        node->SetTag(GUIStateParams::GetClassType());\n        _init();\n    }\n\n    if (node->HasChild(MouseModeParams::GetClassType())) {\n        m_mouseModeParams = new MouseModeParams(ssave, node->GetChild(MouseModeParams::GetClassType()));\n    } else {\n        m_mouseModeParams = new MouseModeParams(ssave);\n        m_mouseModeParams->GetNode()->SetParent(GetNode());\n    }\n\n    if (node->HasChild(ActiveRenderer::GetClassType())) {\n        m_activeRenderer = new ActiveRenderer(ssave, node->GetChild(ActiveRenderer::GetClassType()));\n    } else {\n        m_activeRenderer = new ActiveRenderer(ssave);\n        m_activeRenderer->GetNode()->SetParent(GetNode());\n    }\n\n    if (node->HasChild(m_openDataSetsTag)) {\n        m_openDataSets = new ParamsContainer(ssave, node->GetChild(m_openDataSetsTag));\n    } else {\n        // Node doesn't contain a opacity map\n        //\n        m_openDataSets = new ParamsContainer(ssave, m_openDataSetsTag);\n        m_openDataSets->SetParent(this);\n    }\n\n    if (node->HasChild(BookmarksTag)) {\n        _bookmarks = new ParamsContainer(ssave, node->GetChild(BookmarksTag));\n    } else {\n        _bookmarks = new ParamsContainer(ssave, BookmarksTag);\n        _bookmarks->SetParent(this);\n    }\n}\n\nGUIStateParams::GUIStateParams(const GUIStateParams &rhs) : ParamsBase(rhs)\n{\n    m_mouseModeParams = new MouseModeParams(*(rhs.m_mouseModeParams));\n    m_activeRenderer = new ActiveRenderer(*(rhs.m_activeRenderer));\n    _bookmarks = new ParamsContainer(*(rhs._bookmarks));\n}\n\nGUIStateParams &GUIStateParams::operator=(const GUIStateParams &rhs)\n{\n    m_mouseModeParams = new MouseModeParams(*(rhs.m_mouseModeParams));\n    m_activeRenderer = new ActiveRenderer(*(rhs.m_activeRenderer));\n    _bookmarks = new ParamsContainer(*(rhs._bookmarks));\n\n    return (*this);\n}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nGUIStateParams::~GUIStateParams() {}\n\n//----------------------------------------------------------------------------\n// Getters and Setters\n//----------------------------------------------------------------------------\n\nstring GUIStateParams::GetActiveVizName() const\n{\n    string defaultv;\n    return (GetValueString(m_activeVisualizer, defaultv));\n}\n\nvoid GUIStateParams::SetActiveVizName(string vizWin) {\n    bool e = _ssave->GetUndoEnabled();\n    _ssave->SetUndoEnabled(false);\n    SetValueString(m_activeVisualizer, \"Set active visualizer window\", vizWin);\n    _ssave->SetUndoEnabled(e);\n}\n\n//! Get active renderer class and instance name for a visualizer\n//\nvoid GUIStateParams::GetActiveRenderer(string vizWin, string &renderType, string &renderInst) const { m_activeRenderer->GetActiveRenderer(vizWin, renderType, renderInst); }\n\nstring GUIStateParams::GetActiveRendererInst() const\n{\n    string renderType, renderInst;\n    GetActiveRenderer(GetActiveVizName(), renderType, renderInst);\n    return renderInst;\n}\n\n//! Set active renderer class and instance name for a visualizer\n//\nvoid GUIStateParams::SetActiveRenderer(string vizWin, string renderType, string renderInst) {\n    bool e = _ssave->GetUndoEnabled();\n    _ssave->SetUndoEnabled(false);\n    BeginGroup(\"Set active \" + renderInst);\n    SetValueString(\"Active_Dataset\", \"\", \"\");\n    m_activeRenderer->SetActiveRenderer(vizWin, renderType, renderInst);\n    EndGroup();\n    _ssave->SetUndoEnabled(e);\n}\n\nstring GUIStateParams::GetActiveDataset() const\n{\n    string name = GetValueString(\"Active_Dataset\", \"\");\n    if (!STLUtils::Contains(GetOpenDataSetNames(), name))\n        return \"\";\n    return name;\n}\n\nvoid GUIStateParams::SetActiveDataset(std::string name)\n{\n    assert(STLUtils::Contains(GetOpenDataSetNames(), name));\n    bool e = _ssave->GetUndoEnabled();\n    _ssave->SetUndoEnabled(false);\n    BeginGroup(\"Set active dataset\");\n    SetActiveRenderer(GetActiveVizName(), \"\", \"\");\n    SetValueString(\"Active_Dataset\", \"\", name);\n    EndGroup();\n    _ssave->SetUndoEnabled(e);\n}\n\nstring GUIStateParams::GetCurrentSessionFile() const { return (GetValueString(m_sessionFileTag, \"\")); }\n\nvoid GUIStateParams::SetCurrentSessionFile(string path) { SetValueString(m_sessionFileTag, \"Set current session file path\", path); }\n\n//! method identifies the current session file\n//! \\retval session file path\nstring GUIStateParams::GetCurrentImagePath() const { return (GetValueString(m_imagePathTag, Wasp::FileUtils::HomeDir())); }\n\n//! method sets the current session path\n//! \\param[in] path string\nvoid GUIStateParams::SetCurrentImagePath(string path) { SetValueString(m_imagePathTag, \"Set current image path\", path); }\n\n//! method identifies the current session file\n//! \\retval session file path\nstring GUIStateParams::GetCurrentImageSavePath() const { return (GetValueString(m_imageSavePathTag, Wasp::FileUtils::HomeDir())); }\n\n//! method sets the current session path\n//! \\param[in] path string\nvoid GUIStateParams::SetCurrentImageSavePath(string path) { SetValueString(m_imageSavePathTag, \"Set current image path\", path); }\n\n//! method identifies the current session file\n//! \\retval session file path\nstring GUIStateParams::GetCurrentTFPath() { return (GetValueString(m_tfPathTag, Wasp::FileUtils::HomeDir())); }\n\n//! method sets the current session path\n//! \\param[in] path string\nvoid GUIStateParams::SetCurrentTFPath(string path) { SetValueString(m_tfPathTag, \"Set current tf path\", path); }\n\n//! method identifies the current session file\n//! \\retval session file path\nstring GUIStateParams::GetCurrentPythonPath() const { return (GetValueString(m_pythonPathTag, Wasp::FileUtils::HomeDir())); }\n\n//! method sets the current session path\n//! \\param[in] path string\nvoid GUIStateParams::SetCurrentPythonPath(string path) { SetValueString(m_pythonPathTag, \"Set current python path\", path); }\n\n//! method identifies the current session file\n//! \\retval session file path\nstring GUIStateParams::GetCurrentFlowPath() const { return (GetValueString(m_flowPathTag, Wasp::FileUtils::HomeDir())); }\n\n//! method sets the current session path\n//! \\param[in] path string\nvoid GUIStateParams::SetCurrentFlowPath(string path) { SetValueString(m_flowPathTag, \"Set current flow path\", path); }\n\nMouseModeParams *GUIStateParams::GetMouseModeParams() const { return (m_mouseModeParams); }\n\n//----------------------------------------------------------------------------\n// Funcs\n//----------------------------------------------------------------------------\n\nvector<string> GUIStateParams::GetOpenDataSetPaths(string dataSetName) const\n{\n    DataSetParam *dsParams = (DataSetParam *)m_openDataSets->GetParams(dataSetName);\n\n    if (!dsParams) { return (vector<string>()); }\n\n    vector<string> paths = dsParams->GetPaths();\n    if (paths.empty()) paths.push_back(\"\");\n\n    return (paths);\n}\n\nvector<string> GUIStateParams::GetOpenDataSetRelativePaths(string dataSetName) const\n{\n    DataSetParam *dsParams = (DataSetParam *)m_openDataSets->GetParams(dataSetName);\n    if (!dsParams) { return (vector<string>()); }\n    return dsParams->GetRelativePaths();\n}\n\nstring GUIStateParams::GetOpenDataSetFormat(string dataSetName) const\n{\n    DataSetParam *dsParams = (DataSetParam *)m_openDataSets->GetParams(dataSetName);\n\n    if (!dsParams) { return (\"\"); }\n\n    return (dsParams->GetFormat());\n}\n\nvoid GUIStateParams::InsertOpenDataSet(string dataSetName, string format, const vector<string> &paths, const vector<string> &relPaths)\n{\n    m_openDataSets->Remove(dataSetName);\n\n    DataSetParam dsParam(_ssave);\n    dsParam.SetPaths(paths);\n    dsParam.SetFormat(format);\n\n    if (relPaths.size() == paths.size())\n        dsParam.SetRelativePaths(relPaths);\n\n    m_openDataSets->Insert(&dsParam, dataSetName);\n}\n\nvoid GUIStateParams::AddBookmark(BookmarkParams *bookmark) { _bookmarks->Insert(bookmark, \"i_\" + std::to_string(_bookmarks->Size())); }\n\nBookmarkParams *GUIStateParams::CreateBookmark() { return (BookmarkParams *)_bookmarks->Create(BookmarkParams::GetClassType(), \"i_\" + std::to_string(_bookmarks->Size())); }\n\nvoid GUIStateParams::SetBookmarks(const vector<BookmarkParams *> &all)\n{\n    ClearBookmarks();\n\n    for (auto b : all) AddBookmark(b);\n}\n\nvoid GUIStateParams::DeleteBookmark(int i)\n{\n    auto b = GetBookmark(i);\n    if (b) _bookmarks->Remove(b);\n}\n\nvoid GUIStateParams::ClearBookmarks()\n{\n    auto names = _bookmarks->GetNames();\n\n    for (auto &name : names) _bookmarks->Remove(name);\n}\n\nvector<BookmarkParams *> GUIStateParams::GetBookmarks() const\n{\n    vector<BookmarkParams *> ret;\n    auto                     names = _bookmarks->GetNames();\n\n    for (auto &name : names) ret.push_back((BookmarkParams *)_bookmarks->GetParams(name));\n\n    return ret;\n}\n\nint GUIStateParams::GetNumBookmarks() const { return _bookmarks->Size(); }\n\nBookmarkParams *GUIStateParams::GetBookmark(int i) const\n{\n    assert(i >= 0 && i < _bookmarks->Size());\n    if (i < 0 && i >= _bookmarks->Size()) return NULL;\n\n    return (BookmarkParams *)_bookmarks->GetParams(_bookmarks->GetNames()[i]);\n}\n\nvoid GUIStateParams::_init() {\n    SetActiveVizName(\"\");\n    SetValueLong(MovingDomainTrackCameraTag, \"\", true);\n    SetValueLong(MovingDomainTrackRenderRegionsTag, \"\", true);\n    SetValueString(ImportDataTypeTag, \"Default dataset to import\", \"WRF-ARW\") ;\n    SetValueLong(SessionNewTag, \"Open dataset as a new session\", true);\n}\n\nvoid GUIStateParams::ActiveRenderer::SetActiveRenderer(string vizWin, string renderType, string renderInst)\n{\n    std::vector<string> v;\n    v.push_back(renderType);\n    v.push_back(renderInst);\n\n    bool e = _ssave->GetUndoEnabled();\n    _ssave->SetUndoEnabled(false);\n    SetValueStringVec(vizWin, \"Set active render type and instance\", v);\n    _ssave->SetUndoEnabled(e);\n}\n\nvoid GUIStateParams::ActiveRenderer::GetActiveRenderer(string vizWin, string &renderType, string &renderInst) const\n{\n    std::vector<string> defaultv(2, \"\");\n    std::vector<string> v = GetValueStringVec(vizWin, defaultv);\n    renderType = v[0];\n    renderInst = v[1];\n}\n\nstd::string GUIStateParams::GetStatsDatasetName() const { return GetValueString(m_statsDatasetNameTag, \"\"); }\n\nvoid GUIStateParams::SetStatsDatasetName(std::string &name) { SetValueString(m_statsDatasetNameTag, \"Name of the active data set in Statistics\", name); }\n\nstd::string GUIStateParams::GetPlotDatasetName() const { return GetValueString(m_plotDatasetNameTag, \"\"); }\n\nvoid GUIStateParams::SetPlotDatasetName(std::string &name) { SetValueString(m_plotDatasetNameTag, \"Name of the active data set in Plot\", name); }\n\nstring GUIStateParams::ActiveTab() const { return GetValueString(\"ActiveTabTag\", \"\"); }\nvoid   GUIStateParams::SetActiveTab(const string &t) {\n    bool e = _ssave->GetUndoEnabled();\n    _ssave->SetUndoEnabled(false);\n    SetValueString(\"ActiveTabTag\", \"\", t);\n    _ssave->SetUndoEnabled(e);\n}\n\nint GUIStateParams::GetFlowDimensionality() const { return GetValueLong(_flowDimensionalityTag, -1); }\n\nvoid GUIStateParams::SetFlowDimensionality(int nDims)\n{\n    if (nDims > 3)\n        nDims = 3;\n    else if (nDims < 2)\n        nDims = 2;\n\n    SetValueLong(_flowDimensionalityTag, _flowDimensionalityTag, nDims);\n}\n"
  },
  {
    "path": "lib/params/HelloParams.cpp",
    "content": "\n#include <string>\n#include <vapor/HelloParams.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n// Provide values for all the tags\nconst string HelloParams::m_lineThicknessTag = \"LineThickness\";\nconst string HelloParams::m_point1Tag = \"Point1\";\nconst string HelloParams::m_point2Tag = \"Point2\";\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<HelloParams> registrar(HelloParams::GetClassType());\n\nHelloParams::HelloParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, HelloParams::GetClassType())\n{\n    // restart provides default values even with no data mgr\n    _init();\n}\n\nHelloParams::HelloParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node) {}\n\nHelloParams::~HelloParams() {}\n\n// Set everything to default values.\n// Data Manager is absent.\nvoid HelloParams::_init()\n{\n    SetLineThickness(1.0);\n\n    vector<double> pt1;\n    vector<double> pt2;\n\n    GetBox()->GetExtents(pt1, pt2);\n\n    SetPoint1(pt1);\n    SetPoint2(pt2);\n}\n"
  },
  {
    "path": "lib/params/ImageParams.cpp",
    "content": "#include <vapor/ImageParams.h>\n#include <vapor/ResourcePath.h>\n#include <vapor/DataMgrUtils.h>\n\nusing namespace VAPoR;\n\nconst std::string ImageParams::_fileNameTag = \"FileName\";\nconst std::string ImageParams::_isGeoRefTag = \"IsGeoRefTag\";\nconst std::string ImageParams::_ignoreTransparencyTag = \"IgnoreTransparency\";\nconst std::string ImageParams::_opacityTag = \"Opacity\";\nconst std::string ImageParams::_orientationTag = \"Orientation\";\nconst std::string ImageParams::_TMSLODTag = \"TMSLevelOfDetail\";\nconst std::string ImageParams::_numTMSLODTag = \"numTMSLevelOfDetail\";\n\n//\n// Register class with object factory\n//\nstatic RenParamsRegistrar<ImageParams> registrar(ImageParams::GetClassType());\n\nImageParams::ImageParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave) : RenderParams(dataManager, stateSave, ImageParams::GetClassType(), 2)\n{\n    SetVariableName(\"\");\n    SetFieldVariableNames(vector<string>());\n    SetDiagMsg(\"ImageParams::ImageParams() this=%p\", this);\n}\n\nImageParams::ImageParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *node) : RenderParams(dataManager, stateSave, node, 2) { _initialized = true; }\n\nImageParams::~ImageParams() { SetDiagMsg(\"ImageParams::~ImageParams() this=%p\", this); }\n\nint ImageParams::Initialize()\n{\n    int rc = RenderParams::Initialize();\n    if (rc < 0) return (rc);\n    if (_initialized) return 0;\n\n    // RenderParams will initialize the Box class based on the dimensionality\n    // of the variable's supported by a particular renderer. The image renderer\n    // is unique in that it operates on 2D variables if they exist. If they\n    // don't we'll use any 3D variables to set up the Box correctly\n    //\n    for (int ndim = 2; ndim < 4; ndim++) {\n        size_t ts;\n        string varname;\n        if (DataMgrUtils::GetFirstExistingVariable(_dataMgr, 0, 0, ndim, varname, ts)) {\n            if (InitBoxFromVariable(ts, varname)) break;\n        }\n    }\n\n    // The image renderer behaves like a 2D renderer, but it doesn't operate\n    // on any data variables. Make sure the box is planar.\n    //\n    GetBox()->SetOrientation(VAPoR::Box::XY);\n    GetBox()->SetPlanar(true);\n\n    SetImagePath(Wasp::GetSharePath(\"images/NaturalEarth.tms\"));\n    SetIsGeoRef(true);\n    SetIgnoreTransparency(false);\n\n    _initialized = true;\n\n    return (0);\n}\n\nstd::string ImageParams::GetImagePath() const\n{\n    std::string defaultImage = Wasp::GetSharePath(\"images/NaturalEarth.tms\");\n\n    return GetValueString(_fileNameTag, defaultImage);\n}\n"
  },
  {
    "path": "lib/params/MapperFunction.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2005\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tMapperFunction.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tAugust 2005\n//\n//\tDescription:\tImplements the MapperFunction class\n//\t\tProvides separate mapping of color and opacity with separate domain\n//\t\tbounds.\n//\n//\n#ifdef WIN32\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <iostream>\n#include <sstream>\n#include <fstream>\n#include \"vapor/VAssert.h\"\n#include <algorithm>\n#include <vapor/MapperFunction.h>\n#include <vapor/ColorMap.h>\n#include <vapor/XmlNode.h>\n#include <vapor/ParamsBase.h>\n#include <cassert>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nconst string MapperFunction::_dataBoundsTag = \"DataBounds\";\nconst string MapperFunction::_opacityCompositionTag = \"OpacityComposition\";\nconst string MapperFunction::_opacityScaleTag = \"OpacityScale\";\nconst string MapperFunction::_opacityMapsTag = \"OpacityMaps\";\nconst string MapperFunction::_opacityMapTag = \"OpacityMap\";\nconst string MapperFunction::_autoUpdateHistoTag = \"AutoUpdateHisto\";\nconst string MapperFunction::_secondaryVarMapperTag = \"SecondaryVarMapper\";\nconst string MapperFunction::CustomMappingSliderRangeTag = \"CustomMappingSliderRange\";\nconst string MapperFunction::IsUsingCustomMappingSliderRangeTag = \"IsUsingCustomMappingSliderRange\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<MapperFunction> registrar(MapperFunction::GetClassType());\n\n//----------------------------------------------------------------------------\n// Constructor for empty, default Mapper function\n//----------------------------------------------------------------------------\n\nMapperFunction::MapperFunction(ParamsBase::StateSave *ssave) : ParamsBase(ssave, MapperFunction::GetClassType()), _numEntries(256)\n{\n    m_colorMap = NULL;\n    m_opacityMaps = NULL;\n\n    setOpacityScale(1.0);\n    setOpacityComposition(ADDITION);\n\n    m_colorMap = new ColorMap(ssave);\n    m_colorMap->SetParent(this);\n\n    // Create a Params container for multiple opacity maps\n    //\n    m_opacityMaps = new ParamsContainer(ssave, _opacityMapsTag);\n    m_opacityMaps->SetParent(this);\n\n    // Populate container with a single default opacity map\n    //\n    OpacityMap opacityMap(ssave);\n\n    m_opacityMaps->Insert(&opacityMap, _make_omap_name(0));\n\n    setMinMaxMapValue(1., -1.);\n}\n\nMapperFunction::MapperFunction(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node), _numEntries(256)\n{\n    m_colorMap = NULL;\n    m_opacityMaps = NULL;\n\n    if (node->HasChild(ColorMap::GetClassType())) {\n        m_colorMap = new ColorMap(ssave, node->GetChild(ColorMap::GetClassType()));\n    } else {\n        // Node doesn't contain a colormap\n        //\n        m_colorMap = new ColorMap(ssave);\n        m_colorMap->SetParent(this);\n    }\n\n    if (node->HasChild(_opacityMapsTag)) {\n        m_opacityMaps = new ParamsContainer(ssave, node->GetChild(_opacityMapsTag));\n    } else {\n        // Node doesn't contain a opacity map\n        //\n        m_opacityMaps = new ParamsContainer(ssave, _opacityMapsTag);\n        m_opacityMaps->SetParent(this);\n\n        // Populate container with a single default opacity map\n        //\n        OpacityMap opacityMap(ssave);\n\n        m_opacityMaps->Insert(&opacityMap, _make_omap_name(0));\n    }\n}\n\nMapperFunction::MapperFunction(const MapperFunction &rhs) : ParamsBase(rhs), _numEntries(256)\n{\n    m_colorMap = NULL;\n    m_opacityMaps = NULL;\n\n    m_colorMap = new ColorMap(*(rhs.m_colorMap));\n    m_colorMap->SetParent(this);\n\n    m_opacityMaps = new ParamsContainer(*(rhs.m_opacityMaps));\n    m_opacityMaps->SetParent(this);\n}\n\nMapperFunction &MapperFunction::operator=(const MapperFunction &rhs)\n{\n    if (m_colorMap) delete m_colorMap;\n\n    if (m_opacityMaps) delete m_opacityMaps;\n\n    ParamsBase::operator=(rhs);\n\n    m_colorMap = NULL;\n    m_opacityMaps = NULL;\n\n    m_colorMap = new ColorMap(rhs._ssave, rhs.m_colorMap->GetNode());\n    m_colorMap->SetParent(this);\n\n    m_opacityMaps = new ParamsContainer(rhs._ssave, rhs.m_opacityMaps->GetNode());\n    m_opacityMaps->SetParent(this);\n\n    return (*this);\n}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nMapperFunction::~MapperFunction()\n{\n    MyBase::SetDiagMsg(\"MapperFunction::~MapperFunction()\");\n\n    if (m_colorMap) delete m_colorMap;\n    if (m_opacityMaps) delete m_opacityMaps;\n}\n\n//----------------------------------------------------------------------------\n// Create a mapper function by parsing a file.\n//----------------------------------------------------------------------------\nint MapperFunction::LoadFromFile(string path)\n{\n    XmlParser xmlparser;\n\n    XmlNode *node = new XmlNode();\n\n    int rc = xmlparser.LoadFromFile(node, path);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Failed to read file %s : %M\", path.c_str());\n        return (-1);\n    }\n\n    // Create a new MapperFunction from the XmlNode tree\n    //\n    XmlNode *       parent = this->GetNode()->GetParent();\n    MapperFunction *newTF = new MapperFunction(_ssave, node);\n\n    // Assign (copy) new TF to this object\n    //\n    *this = *newTF;\n    this->GetNode()->SetParent(parent);\n\n    // Delete the new tree\n    //\n    delete newTF;\n\n    _ssave->Save(_node, \"Load transfer function from file\");\n\n    return (0);\n}\n\nint MapperFunction::LoadColormapFromFile(string path)\n{\n    MapperFunction temp = *this;\n    int            rc = temp.LoadFromFile(path);\n    if (rc < 0) return rc;\n\n    *m_colorMap = *temp.GetColorMap();\n    m_colorMap->SetParent(this);\n\n    // Apparently the colormap stores its own copy of the mapping range.\n    // This could be solved differently but the fact that this\n    // is a valid solution is amusing.\n    setMinMaxMapValue(getMinMapValue(), getMaxMapValue());\n\n    return rc;\n}\n\n//----------------------------------------------------------------------------\n// Save the mapper function to a file.\n//----------------------------------------------------------------------------\nint MapperFunction::SaveToFile(string path)\n{\n    ofstream out(path);\n    if (!out) {\n        MyBase::SetErrMsg(\"Failed to open file %s : %M\", path.c_str());\n        return (-1);\n    }\n\n    XmlNode *node = GetNode();\n\n    out << *node;\n\n    if (out.bad()) {\n        MyBase::SetErrMsg(\"Failed to write file %s : %M\", path.c_str());\n        return (-1);\n    }\n    out.close();\n\n    return (0);\n}\n\n//----------------------------------------------------------------------------\n// Calculate the opacity given the data value\n//----------------------------------------------------------------------------\nfloat MapperFunction::getOpacityValueData(float value) const\n{\n    int count = 0;\n\n    //\n    // Using the square of the opacity scaling factor gives\n    // better control over low opacity values.\n    // But this correction will be made in the GUI\n    //\n    float opacScale = getOpacityScale();\n\n    float opacity = 0.0;\n\n    if (getOpacityComposition() == MULTIPLICATION) { opacity = 1.0; }\n\n    for (int i = 0; i < getNumOpacityMaps(); i++) {\n        OpacityMap *omap = GetOpacityMap(i);\n\n        // if (omap->IsEnabled() && omap->inDataBounds(value)) {\n        if (omap->IsEnabled()) { // Bounds handling was buggy and bounded opacity maps are no longer used\n            if (getOpacityComposition() == ADDITION) {\n                opacity += omap->opacityData(value);\n            } else    // _compType == MULTIPLICATION\n            {\n                opacity *= omap->opacityData(value);\n            }\n\n            count++;\n\n            if (opacity * opacScale > 1.0) { return 1.0; }\n        }\n    }\n\n    if (count) return opacity * opacScale;\n\n    return 0.0;\n}\n\n//----------------------------------------------------------------------------\n// Calculate the color given the data value\n//----------------------------------------------------------------------------\nvoid MapperFunction::hsvValue(float value, float *h, float *s, float *v) const\n{\n    ColorMap *cmap = GetColorMap();\n    if (cmap) {\n        ColorMap::Color color = cmap->color(value);\n\n        *h = color.hue();\n        *s = color.sat();\n        *v = color.val();\n    }\n}\n\n//----------------------------------------------------------------------------\n// Populate at a RGBA lookup table\n//----------------------------------------------------------------------------\nvoid MapperFunction::makeLut(float *clut) const\n{\n    float step = (getMaxMapValue() - getMinMapValue()) / float(_numEntries - 1);\n    for (int i = 0; i < _numEntries; i++) {\n        float v = getMinMapValue() + i * step;\n        m_colorMap->color(v).toRGB(&clut[4 * i]);\n        clut[4 * i + 3] = getOpacityValueData(v);\n    }\n}\n\n//----------------------------------------------------------------------------\n// Populate at a RGBA lookup table with std::vector input\n//----------------------------------------------------------------------------\nvoid MapperFunction::makeLut(std::vector<float> &clut) const\n{\n    float *cluta = new float[4 * _numEntries];\n    makeLut(cluta);\n    clut.assign(cluta, cluta + 4 * _numEntries);\n    delete[] cluta;\n}\n\nstd::vector<float> MapperFunction::makeLut() const\n{\n    vector<float> v;\n    makeLut(v);\n    return v;\n}\n\n//! Set both minimum and maximum mapping (histo) values\n//! \\param[in] val1 minimum value\n//! \\param[in] val2 maximum value\nvoid MapperFunction::setMinMaxMapValue(float val1, float val2)\n{\n    if (val1 > val2) val2 = val1;\n\n    vector<double> bnds;\n    bnds.push_back(val1);\n    bnds.push_back(val2);\n\n    SetValueDoubleVec(_dataBoundsTag, \"Set min max map value\", bnds);\n\n    // Need to set the bounds of color and opacity maps\n    //\n    ColorMap *cmap = GetColorMap();\n    if (cmap) cmap->SetDataBounds(bnds);\n\n    for (int i = 0; i < getNumOpacityMaps(); i++) { GetOpacityMap(i)->SetDataBounds(bnds); }\n}\n\nvector<double> MapperFunction::getMinMaxMapValue() const\n{\n    vector<double> defaultv(2, 0.0);\n    vector<double> bounds = GetValueDoubleVec(_dataBoundsTag, defaultv);\n    if (bounds.size() != 2) bounds = defaultv;\n    return (bounds);\n}\n\nvector<double> MapperFunction::GetCustomMappingSliderRange() const\n{\n    vector<double> defaultv(2, 0);\n    return GetValueDoubleVec(CustomMappingSliderRangeTag, defaultv);\n}\n\nbool MapperFunction::IsUsingCustomMappingSliderRange() const { return GetValueLong(IsUsingCustomMappingSliderRangeTag, false); }\n\nvoid MapperFunction::SetCustomMappingSliderRange(const vector<double> &range) { return SetValueDoubleVec(CustomMappingSliderRangeTag, CustomMappingSliderRangeTag, range); }\n\nvoid MapperFunction::SetUsingCustomMappingSliderRange(bool b) { SetValueLong(IsUsingCustomMappingSliderRangeTag, IsUsingCustomMappingSliderRangeTag, b); }\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nOpacityMap *MapperFunction::createOpacityMap(OpacityMap::Type type)\n{\n    int index = m_opacityMaps->Size();\n\n    OpacityMap opacityMap(_ssave);\n    opacityMap.SetType(type);\n\n    m_opacityMaps->Insert(&opacityMap, _make_omap_name(index));\n\n    return ((OpacityMap *)m_opacityMaps->GetParams(_make_omap_name(index)));\n}\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nvoid MapperFunction::DeleteOpacityMap(const OpacityMap *omap) { m_opacityMaps->Remove(omap); }\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nOpacityMap *MapperFunction::GetOpacityMap(int index) const\n{\n    if (index >= m_opacityMaps->Size()) return (NULL);\n\n    return ((OpacityMap *)m_opacityMaps->GetParams(_make_omap_name(index)));\n}\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\n\n//----------------------------------------------------------------------------\n// Reset to starting values\n//----------------------------------------------------------------------------\n\n//----------------------------------------------------------------------------\n// Static utility function to map and quantize a float\n//----------------------------------------------------------------------------\nint MapperFunction::mapPosition(float x, float minValue, float maxValue, int hSize)\n{\n    double psn = (0.5 + ((((double)x - (double)minValue) * hSize) / ((double)maxValue - (double)minValue)));\n    // constrain to integer size limit\n    if (psn < -1000000000.f) psn = -1000000000.f;\n    if (psn > 1000000000.f) psn = 1000000000.f;\n    return (int)psn;\n}\n\n//----------------------------------------------------------------------------\n// hsv-rgb Conversion function.  inputs and outputs between 0 and 1\n// copied (with corrections) from Hearn/Baker\n//----------------------------------------------------------------------------\nvoid MapperFunction::hsvToRgb(float *hsv, float *rgb)\n{\n    if (hsv[1] == 0.f) {    // grey\n        rgb[0] = rgb[1] = rgb[2] = hsv[2];\n        return;\n    }\n\n    int sector = (int)(hsv[0] * 6.f);\n\n    float sectCrd = hsv[0] * 6.f - (float)sector;\n    if (sector == 6) sector = 0;\n    float a = hsv[2] * (1.f - hsv[1]);\n    float b = hsv[2] * (1.f - sectCrd * hsv[1]);\n    float c = hsv[2] * (1.f - (hsv[1] * (1.f - sectCrd)));\n\n    switch (sector) {\n    case (0):\n        // red to green, r>g\n        rgb[0] = hsv[2];\n        rgb[1] = c;\n        rgb[2] = a;\n        break;\n    case (1):    // red to green, g>r\n        rgb[1] = hsv[2];\n        rgb[2] = a;\n        rgb[0] = b;\n        break;\n    case (2):    // green to blue, gr>bl\n        rgb[0] = a;\n        rgb[1] = hsv[2];\n        rgb[2] = c;\n        break;\n    case (3):    // green to blue, gr<bl\n        rgb[0] = a;\n        rgb[2] = hsv[2];\n        rgb[1] = b;\n        break;\n    case (4):    // blue to red, bl>red\n        rgb[1] = a;\n        rgb[2] = hsv[2];\n        rgb[0] = c;\n        break;\n    case (5):    // blue to red, bl<red\n        rgb[1] = a;\n        rgb[0] = hsv[2];\n        rgb[2] = b;\n        break;\n    default: VAssert(0);\n    }\n    return;\n}\n\n//----------------------------------------------------------------------------\n// rgb-hsv Conversion function.  inputs and outputs between 0 and 1\n// copied (with corrections) from Hearn/Baker\n//----------------------------------------------------------------------------\nvoid MapperFunction::rgbToHsv(float *rgb, float *hsv)\n{\n    // value is max (r,g,b)\n    float maxval = Max(rgb[0], Max(rgb[1], rgb[2]));\n    float minval = Min(rgb[0], Min(rgb[1], rgb[2]));\n    float delta = maxval - minval;    // chrominance\n    hsv[2] = maxval;\n    if (maxval != 0.f)\n        hsv[1] = delta / maxval;\n    else\n        hsv[1] = 0.f;\n    if (hsv[1] == 0.f)\n        hsv[0] = 0.f;    // no hue!\n    else {\n        if (rgb[0] == maxval) {\n            hsv[0] = (rgb[1] - rgb[2]) / delta;\n            if (hsv[0] < 0.f) hsv[0] += 6.f;\n        } else if (rgb[1] == maxval) {\n            hsv[0] = 2.f + (rgb[2] - rgb[0]) / delta;\n        } else {\n            hsv[0] = 4.f + (rgb[0] - rgb[1]) / delta;\n        }\n        hsv[0] /= 6.f;    // Put between 0 and 1\n    }\n    return;\n}\n\nvector<float> MapperFunction::rgbToHsv(vector<float> rgb)\n{\n    assert(rgb.size() == 3);\n    vector<float> hsv;\n    rgb.resize(3, 0);\n    hsv.resize(3, 0);\n    rgbToHsv(rgb.data(), hsv.data());\n    return hsv;\n}\n\n//----------------------------------------------------------------------------\n// Set the opacity function to 1.\n//----------------------------------------------------------------------------\nvoid MapperFunction::setOpaque()\n{\n    for (int i = 0; i < getNumOpacityMaps(); i++) { GetOpacityMap(i)->setOpaque(); }\n}\nbool MapperFunction::isOpaque() const\n{\n    for (int i = 0; i < getNumOpacityMaps(); i++) {\n        if (GetOpacityMap(i)->isOpaque()) return false;\n    }\n    return true;\n}\n\nstring MapperFunction::_make_omap_name(int index) const\n{\n    stringstream ss;\n\n    ss << MapperFunction::_opacityMapTag;\n    ss << \"_\";\n    ss << index;\n    return (ss.str());\n}\n"
  },
  {
    "path": "lib/params/ModelParams.cpp",
    "content": "\n#include <vapor/ModelParams.h>\n#include <string>\n#include <cassert>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nconst std::string ModelParams::FileTag = \"FileTag\";\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<ModelParams> registrar(ModelParams::GetClassType());\n\nModelParams::ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, ModelParams::GetClassType(), 3)\n{\n    SetDiagMsg(\"ModelParams::ModelParams() this=%p\", this);\n    _init();\n}\n\nModelParams::ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType) : RenderParams(dataMgr, ssave, classType, 3)\n{\n    SetDiagMsg(\"ModelParams::ModelParams() this=%p\", this);\n    _init();\n}\n\nModelParams::ModelParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) {}\n\nModelParams::~ModelParams() { SetDiagMsg(\"ModelParams::~ModelParams() this=%p\", this); }\n\n// Set everything to default values\nvoid ModelParams::_init() { SetDiagMsg(\"ModelParams::_init()\"); }\n"
  },
  {
    "path": "lib/params/MouseModeParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2014\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tMouseModeParams.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tApril 2014\n//\n//\tDescription:\tImplements the MouseModeParams class.\n//\t\tThis class supports parameters associted with the\n//\t\tmouse mode\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <vector>\n#include <string>\n\n#include \"../../apps/vaporgui/images/wheel.xpm\"\n#include \"../../apps/vaporgui/images/cube.xpm\"\n#include <vapor/MouseModeParams.h>\n\nconst std::string MouseModeParams::_currentMouseModeTag = \"CurrentMouseModeTag\";\n\nusing namespace VAPoR;\n\nMouseModeParams::MouseModeParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, MouseModeParams::GetClassType())\n{\n    _setUpDefault();\n    _init();\n}\n\nMouseModeParams::MouseModeParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    _setUpDefault();\n\n    // If node isn't tagged correctly we correct the tag and reinitialize\n    // from scratch;\n    //\n    if (node->GetTag() != MouseModeParams::GetClassType()) {\n        node->SetTag(MouseModeParams::GetClassType());\n        _init();\n    }\n}\n\nMouseModeParams::~MouseModeParams() {}\n\n// Reset region settings to initial state\nvoid MouseModeParams::_init()\n{\n    // Set to navigation mode\n    SetCurrentMouseMode(GetNavigateModeName());\n}\n\n//! Static method called at startup to register all the built-in mouse modes\nvoid MouseModeParams::_setUpDefault()\n{\n    _modes.push_back({GetNavigateModeName(), wheel});\n    _modes.push_back({GetRegionModeName(), cube});\n\n    // RegisterMouseMode(\"Barb rake\", 1, arrowrake );\n    // RegisterMouseMode(\"Contours\", 3, isoline);\n    // RegisterMouseMode(Params::GetClassType(),1, \"Flow rake\",rake );\n    // RegisterMouseMode(Params::GetClassType(),3,\"Probe\", probe);\n    // RegisterMouseMode(\"2D Data\", 2, twoDData);\n    // RegisterMouseMode(\"Image\", 2, twoDImage);\n}\n\nvoid MouseModeParams::SetCurrentMouseMode(string t)\n{\n    // Make sure mode is registered. If not, use default\n    //\n    auto itr = _modes.cbegin();\n    for (; itr != _modes.cend(); ++itr)\n        if (itr->name == t) break;\n    if (itr == _modes.cend()) t = GetNavigateModeName();\n\n    SetValueString(_currentMouseModeTag, \"Set mouse mode\", t);\n}\n"
  },
  {
    "path": "lib/params/OpacityMap.cpp",
    "content": "//--OpacityMap.cpp -------------------------------------------------------\n//\n// Copyright (C) 2006 Kenny Gruchalla.  All rights reserved.\n//\n// Various types of mappings from opacity to data value.\n//\n//----------------------------------------------------------------------------\n\n#include <iostream>\n#include <sstream>\n#include <cmath>\n#include <vector>\n#include <algorithm>\n\n#include <vapor/OpacityMap.h>\n\n#ifndef MAX\n    #define MAX(a, b) ((a) > (b) ? (a) : (b))\n#endif\n\n#ifndef MIN\n    #define MIN(a, b) ((a) < (b) ? (a) : (b))\n#endif\n\n#ifndef M_PI\n    #define M_PI 3.1415926535897932384626433832795\n#endif\n\n#ifndef M_E\n    #define M_E 2.71828182845904523536\n#endif\n\nusing namespace std;\nusing namespace VAPoR;\nusing namespace Wasp;\n\n//----------------------------------------------------------------------------\n// Static member initalization\n//----------------------------------------------------------------------------\nconst string OpacityMap::_relMinTag = \"RelMinValue\";\nconst string OpacityMap::_relMaxTag = \"RelMaxValue\";\nconst string OpacityMap::_enabledTag = \"Enabled\";\nconst string OpacityMap::_meanTag = \"Mean\";\nconst string OpacityMap::_ssqTag = \"SSq\";\nconst string OpacityMap::_freqTag = \"Freq\";\nconst string OpacityMap::_phaseTag = \"Phase\";\nconst string OpacityMap::_typeTag = \"Type\";\nconst string OpacityMap::_controlPointsTag = \"OpacityMapControlPoints\";\nconst string OpacityMap::_interpTypeTag = \"OpacityInterpolation\";\nconst string OpacityMap::_opacityMapIndexTag = \"OpacityMapIndex\";\nconst string OpacityMap::_dataBoundsTag = \"DataBounds\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<OpacityMap> registrar(OpacityMap::GetClassType());\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\n\nOpacityMap::OpacityMap(ParamsBase::StateSave *ssave) : ParamsBase(ssave, OpacityMap::GetClassType()), _minSSq(0.0001), _maxSSq(1.0), _minFreq(1.0), _maxFreq(30.0), _minPhase(0.0), _maxPhase(2 * M_PI)\n{\n    SetInterpType(TFInterpolator::linear);\n    SetType(CONTROL_POINT);\n    SetEnabled(true);\n    SetMean(0.5);\n    SetSSQ(0.1);\n    SetFreq(5.0);\n    SetPhase(2. * M_PI);\n\n    vector<double> bounds(2, 0.0);\n\n    SetDataBounds(bounds);\n\n    setMinValue(bounds[0]);\n    setMaxValue(bounds[1]);\n    vector<double> cps;\n    for (int i = 0; i < 4; i++) {\n        cps.push_back(1.f);\n        cps.push_back((double)i / 3.);\n        //\t  cps.push_back((double)i/3.);\n        //\t  cps.push_back((double)i/3.);\n    }\n    SetControlPoints(cps);\n}\n\nOpacityMap::OpacityMap(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node), _minSSq(0.0001), _maxSSq(1.0), _minFreq(1.0), _maxFreq(30.0), _minPhase(0.0), _maxPhase(2 * M_PI) {}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nOpacityMap::~OpacityMap() {}\n\n//----------------------------------------------------------------------------\n// Clear  the control points\n//----------------------------------------------------------------------------\nvoid OpacityMap::clear()\n{\n    vector<double> cps;\n    SetControlPoints(cps);\n}\n\n//----------------------------------------------------------------------------\n// Add a new control point to the opacity map.\n//----------------------------------------------------------------------------\nvoid OpacityMap::addNormControlPoint(float normVal, float opacity)\n{\n    vector<double> cps = GetControlPoints();\n    // cps.insert position is before where new element goes, so must add 2\n    int index = leftControlIndex(normVal) * 2 + 2;\n    cps.insert(cps.begin() + index++, opacity);\n    cps.insert(cps.begin() + index, normVal);\n    SetControlPoints(cps);\n}\n\n//----------------------------------------------------------------------------\n// Add a new control point to the opacity map.\n//----------------------------------------------------------------------------\nvoid OpacityMap::addControlPoint(float value, float opacity)\n{\n    float normVal = (value - minValue()) / (maxValue() - minValue());\n    addNormControlPoint(normVal, opacity);\n}\n\n//----------------------------------------------------------------------------\n// Delete the control point.\n//----------------------------------------------------------------------------\nvoid OpacityMap::deleteControlPoint(int index)\n{\n    vector<double> cps = GetControlPoints();\n\n    if (index >= 0 && index < cps.size() / 2 - 1 && cps.size() > 2) {\n        cps.erase(cps.begin() + 2 * index, cps.begin() + 2 * index + 2);\n        SetControlPoints(cps);\n    }\n}\n\n//----------------------------------------------------------------------------\n// Move the control point.\n//----------------------------------------------------------------------------\nvoid OpacityMap::moveControlPoint(int index, float dx, float dy)\n{\n    vector<double> cps = GetControlPoints();\n    if (index >= 0 && index <= cps.size() / 2 - 1) {\n        float minVal = 0.0;\n        float maxVal = 1.0;\n        float ndx = dx / (maxValue() - minValue());\n\n        if (index != 0) { minVal = cps[2 * index - 1]; }\n\n        if (index < cps.size() / 2 - 1) { maxVal = cps[2 * index + 3]; }\n\n        float value = cps[2 * index + 1] + ndx;\n\n        if (value < minVal) {\n            value = minVal;\n        } else if (value > maxVal) {\n            value = maxVal;\n        }\n\n        cps[2 * index + 1] = value;\n\n        float opacity = cps[2 * index] + dy;\n\n        if (opacity < 0.0) {\n            opacity = 0.0;\n        } else if (opacity > 1.0) {\n            opacity = 1.0;\n        }\n\n        cps[2 * index] = opacity;\n    }\n    SetControlPoints(cps);\n}\n\n//----------------------------------------------------------------------------\n// Return the control point's opacity.\n//----------------------------------------------------------------------------\nfloat OpacityMap::controlPointOpacity(int index) const\n{\n    if (index < 0) { return 0.0; }\n    vector<double> cps = GetControlPoints();\n    if (index > cps.size() / 2 - 1) { return 1.0; }\n\n    return cps[2 * index];\n}\n\n//----------------------------------------------------------------------------\n// Set the control point's opacity.\n//----------------------------------------------------------------------------\nvoid OpacityMap::controlPointOpacity(int index, float opacity)\n{\n    vector<double> cps = GetControlPoints();\n    if (index < 0 || 2 * index >= cps.size()) return;\n\n    if (opacity < 0.0)\n        opacity = 0.;\n    else if (opacity > 1.0)\n        opacity = 1.;\n\n    cps[index * 2] = opacity;\n    SetControlPoints(cps);\n}\n\nfloat OpacityMap::controlPointValue(int index) const { return (controlPointValueNormalized(index) * (maxValue() - minValue()) + minValue()); }\n\n//----------------------------------------------------------------------------\n// Return the control point's value (in data coordinates).\n//----------------------------------------------------------------------------\nfloat OpacityMap::controlPointValueNormalized(int index) const\n{\n    if (index < 0) { return minValue(); }\n    vector<double> cps = GetControlPoints();\n    if (2 * index + 1 >= cps.size()) { return maxValue(); }\n\n    float norm = cps[2 * index + 1];\n\n    return norm;\n}\n\nvoid OpacityMap::controlPointValue(int index, float value)\n{\n    float nv = (value - minValue()) / (maxValue() - minValue());\n    controlPointValueNormalized(index, nv);\n}\n\n//----------------------------------------------------------------------------\n// Set the control point's value (in data coordinates).\n//----------------------------------------------------------------------------\nvoid OpacityMap::controlPointValueNormalized(int index, float nv)\n{\n    vector<double> cps = GetControlPoints();\n    if (index < 0 || index * 2 >= cps.size()) { return; }\n\n    float minVal = 0.0;\n    float maxVal = 1.0;\n\n    if (index > 0) { minVal = cps[2 * index - 1]; }\n\n    if (index * 2 + 3 < cps.size()) { maxVal = cps[2 * index + 3]; }\n\n    if (nv < minVal) {\n        nv = minVal;\n    } else if (nv > maxVal) {\n        nv = maxVal;\n    }\n\n    cps[2 * index + 1] = nv;\n}\n\n//----------------------------------------------------------------------------\n// Set the mean value (normalized coordinates) for the gaussian function\n//----------------------------------------------------------------------------\nvoid OpacityMap::SetMean(double mean) { SetValueDouble(_meanTag, \"Set opacity mean\", mean); }\n\n//----------------------------------------------------------------------------\n// Set the sigma squared value (normalized coordinates) for the gaussian\n// function\n//----------------------------------------------------------------------------\nvoid OpacityMap::SetSSQ(double ssq) { SetValueDouble(_ssqTag, \"Set Opac SSQ\", ssq); }\n\n//----------------------------------------------------------------------------\n// Set the frequency (normalized coordinates) of the sine function\n//----------------------------------------------------------------------------\nvoid OpacityMap::SetFreq(double freq) { SetValueDouble(_freqTag, \"Set Opac Freq\", freq); }\n\n//----------------------------------------------------------------------------\n// Set the phase (normalized coordinates) of the sine function\n//----------------------------------------------------------------------------\nvoid OpacityMap::SetPhase(double p) { SetValueDouble(_phaseTag, \"Set Opac Phase\", denormSinePhase(p)); }\n\nfloat OpacityMap::opacityData(float value) const\n{\n    float nv = (value - minValue()) / (maxValue() - minValue());\n    return opacityDataAtNorm(nv);\n}\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nfloat OpacityMap::opacityDataAtNorm(float nv) const\n{\n    vector<double> cps = GetControlPoints();\n    if (nv < 0.0) { nv = 0; }\n\n    if (nv > 1.0) { nv = 1.0; }\n    OpacityMap::Type _type = GetType();\n    switch (_type) {\n    case CONTROL_POINT: {\n        //\n        // Find the bounding control points\n        //\n        int index = leftControlIndex(nv);\n        if (numControlPoints() == 1) return controlPointOpacity(index);\n\n        double val0 = cps[2 * index + 1];\n        double val1 = cps[2 * index + 3];\n\n        float ratio = (nv - val0) / (val1 - val0);\n\n        if (ratio > 0. && ratio < 1.) {\n            float o = TFInterpolator::interpolate(GetInterpType(), cps[2 * index], cps[2 * index + 2], ratio);\n            return o;\n        }\n\n        if (ratio >= 1.0) { return cps[2 * index + 2]; }\n\n        return cps[2 * index];\n    }\n\n    case GAUSSIAN: {\n        return pow(M_E, -((nv - GetMean()) * (nv - GetMean())) / (2.0 * GetSSQ()));\n    }\n\n    case INVERTED_GAUSSIAN: {\n        return 1.0 - pow(M_E, -((nv - GetMean()) * (nv - GetMean())) / (2.0 * GetSSQ()));\n    }\n\n    case SINE: {\n        return (0.5 + sin(GetFreq() * M_PI * nv + GetPhase()) / 2);\n    }\n    }\n\n    return 0.0;\n}\n\n//----------------------------------------------------------------------------\n// Determine if the opacity map bounds the value.\n//----------------------------------------------------------------------------\nbool OpacityMap::inDataBounds(float value) const { return (value >= minValue() && value <= maxValue()); }\n\nvoid OpacityMap::SetDataBounds(const vector<double> &bounds)\n{\n    VAssert(bounds.size() == 2);\n\n    SetValueDoubleVec(_dataBoundsTag, \"Set min max map value\", bounds);\n}\n\nvector<double> OpacityMap::GetDataBounds() const\n{\n    vector<double> defaultv(2, 0.0);\n\n    vector<double> bounds = GetValueDoubleVec(_dataBoundsTag, defaultv);\n\n    if (bounds.size() != 2) bounds = defaultv;\n\n    return (bounds);\n}\n\n//----------------------------------------------------------------------------\n// binary search , find the index of the largest control point <= val\n// Requires that control points are increasing.\n//\n// Developed by Alan Norton.\n//----------------------------------------------------------------------------\nint OpacityMap::leftControlIndex(float normval) const\n{\n    vector<double> cps = GetControlPoints();\n    int            left = 0;\n    int            right = cps.size() / 2 - 1;\n\n    //\n    // Iterate, keeping left to the left of ctrl point\n    //\n    while (right - left > 1) {\n        int mid = left + (right - left) / 2;\n        if (cps[mid * 2 + 1] > normval) {\n            right = mid;\n        } else {\n            left = mid;\n        }\n    }\n\n    return left;\n}\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\ndouble OpacityMap::normSSq(double ssq) { return (ssq - _minSSq) / (_maxSSq - _minSSq); }\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\ndouble OpacityMap::denormSSq(double ssq) { return _minSSq + (ssq * (_maxSSq - _minSSq)); }\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\ndouble OpacityMap::normSineFreq(double freq) { return (freq - _minFreq) / (_maxFreq - _minFreq); }\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\ndouble OpacityMap::denormSineFreq(double freq) { return _minFreq + (freq * (_maxFreq - _minFreq)); }\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\ndouble OpacityMap::normSinePhase(double phase) { return (phase - _minPhase) / (_maxPhase - _minPhase); }\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\ndouble OpacityMap::denormSinePhase(double phase) { return _minPhase + (phase * (_maxPhase - _minPhase)); }\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nvoid OpacityMap::setOpaque()\n{\n    vector<double> cps = GetControlPoints();\n    for (int i = 0; i < cps.size() / 2; i++) { cps[2 * i] = 1.; }\n    SetControlPoints(cps);\n}\nbool OpacityMap::isOpaque() const\n{\n    vector<double> cps = GetControlPoints();\n    for (int i = 0; i < cps.size(); i += 2) {\n        if (cps[i] < 1.0) return false;\n    }\n    return true;\n}\n\nvoid OpacityMap::SetEnabled(bool val) { SetValueLong(_enabledTag, \"Change opacity map enabled\", (long)val); }\n\nvector<double> OpacityMap::GetControlPoints() const\n{\n    vector<double> cps = GetValueDoubleVec(_controlPointsTag);\n\n    while (cps.size() % 2) cps.push_back(0.0);\n\n    return (cps);\n}\n\nvoid OpacityMap::SetControlPoints(const vector<double> &controlPoints)\n{\n    vector<double> mycp = controlPoints;\n\n    while (mycp.size() % 2) mycp.push_back(0.0);\n\n    SetValueDoubleVec(_controlPointsTag, \"Set opacity control points\", mycp);\n}\n\nvoid OpacityMap::SetInterpType(TFInterpolator::type t) { SetValueLong(_interpTypeTag, \"Set Opacity Interpolation\", (long)t); }\n\nvoid OpacityMap::SetType(OpacityMap::Type t) { SetValueLong(_typeTag, \"Set Opacity Map Type\", (long)t); }\n\n//----------------------------------------------------------------------------\n// Set the minimum value of the opacity map (in data coordinates).\n//\n// The minimum value is stored as normalized coordinates in the parameter\n// space. Therefore, the opacity map will change relative to any changes in\n// the parameter space.\n//----------------------------------------------------------------------------\nvoid OpacityMap::setMinValue(double val)\n{\n    vector<double> minmaxmap = GetDataBounds();\n    if (val > minmaxmap[1]) val = minmaxmap[1];\n    if (val < minmaxmap[0]) val = minmaxmap[0];\n\n    // change to relative max\n    if (minmaxmap[1] > minmaxmap[0])\n        val = (val - minmaxmap[0]) / (minmaxmap[1] - minmaxmap[0]);\n    else\n        val = 0.;\n\n    SetValueDouble(_relMinTag, \"Set Opacity min\", val);\n}\n//----------------------------------------------------------------------------\n// Set the minimum value of the opacity map (in data coordinates).\n//\n// The minimum value is stored as normalized coordinates in the parameter\n// space. Therefore, the opacity map will change relative to any changes in\n// the parameter space.\n//----------------------------------------------------------------------------\nvoid OpacityMap::setMaxValue(double val)\n{\n    vector<double> minmaxmap = GetDataBounds();\n    if (val < minmaxmap[0]) val = minmaxmap[0];\n    if (val > minmaxmap[1]) val = minmaxmap[1];\n\n    // change to relative max\n    if (minmaxmap[1] > minmaxmap[0])\n        val = (val - minmaxmap[0]) / (minmaxmap[1] - minmaxmap[0]);\n    else\n        val = 1.;\n\n    SetValueDouble(_relMaxTag, \"Set Opacity max\", val);\n}\n\ndouble OpacityMap::minValue() const\n{\n    vector<double> minmaxmap = GetDataBounds();\n    double         relmin = GetValueDouble(_relMinTag, 0.0);\n    return (minmaxmap[0] + relmin * (minmaxmap[1] - minmaxmap[0]));\n}\n\ndouble OpacityMap::maxValue() const\n{\n    vector<double> minmaxmap = GetDataBounds();\n    double         relmax = GetValueDouble(_relMaxTag, 1.0);\n    return (minmaxmap[0] + relmax * (minmaxmap[1] - minmaxmap[0]));\n}\n"
  },
  {
    "path": "lib/params/ParamsBase.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2008\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t *\n//************************************************************************/\n//\n//\tFile:\t\tParamsBase.cpp\n//\n//\tAuthor:\t\tJohn Clyne with modifications by Alan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tMarch 2008\n//\n//\tDescription:\tImplements the ParamsBase class\n//\t\tThis is  abstract class for classes that use a ParamNode\n//\t\tto support get/set functionality, and to support dirty bits\n//\t\tIt is a base class for Params, MapperFunction and other classes\n//\t\tthat retain their state in xml nodes\n//\n#include <string>\n#include \"vapor/VAssert.h\"\n#include <functional>\n#include <vapor/XmlNode.h>\n#include <vapor/ParamsBase.h>\n#include <vapor/STLUtils.h>\n\nusing namespace VAPoR;\n\nnamespace {\n\nvoid string_replace(vector<string> &v, string olds, string news)\n{\n    for (int i = 0; i < v.size(); i++) {\n        if (v[i] == olds) { v[i] = news; }\n    }\n}\n};    // namespace\n\nParamsBase::ParamsBase(StateSave *ssave, const string &classname)\n{\n    VAssert(ssave != NULL);\n\n    _ssave = ssave;\n    _node = NULL;\n\n    map<string, string> attrs;\n    _node = new XmlNode(classname, attrs);\n}\n\nParamsBase::ParamsBase(StateSave *ssave, XmlNode *node)\n{\n    VAssert(ssave != NULL);\n    VAssert(node != NULL);\n\n    _ssave = ssave;\n    _node = node;\n}\n\nParamsBase::ParamsBase(const ParamsBase &rhs)\n{\n    _ssave = rhs._ssave;\n    _node = NULL;\n\n    _node = new XmlNode(*(rhs._node));\n}\n\nParamsBase::ParamsBase(StateSave *ssave)\n{\n    VAssert(ssave != NULL);\n\n    _ssave = ssave;\n    _node = NULL;\n}\n\nParamsBase &ParamsBase::operator=(const ParamsBase &rhs)\n{\n    MyBase::operator=(rhs);\n\n    if (_node) {\n        _node->SetParent(NULL);\n        delete _node;\n    }\n\n    _ssave = rhs._ssave;\n    _node = NULL;\n\n    _node = new XmlNode(*(rhs._node));\n\n    return (*this);\n}\n\nParamsBase::~ParamsBase()\n{\n    // Only delete the Xml tree if this is the root node\n    //\n    if (_node && _node->IsRoot()) { delete _node; }\n\n    _node = NULL;\n    _ssave = NULL;\n}\n\nvoid ParamsBase::SetParent(ParamsBase *parent)\n{\n    GetNode()->SetParent(parent ? parent->GetNode() : NULL);\n    _ssave->Save(GetNode(), \"Set parent node\");\n}\n\nvector<long> ParamsBase::GetValueLongVec(const string tag) const\n{\n    vector<long> empty;\n    if (!_node->HasElementLong(tag)) return (empty);\n\n    return (_node->GetElementLong(tag));\n}\n\nvector<long> ParamsBase::GetValueLongVec(const string tag, const vector<long> &defaultVal) const\n{\n    if (!_node->HasElementLong(tag)) return (defaultVal);\n\n    vector<long> v = _node->GetElementLong(tag);\n    if (v.size() < defaultVal.size()) {\n        for (int i = v.size(); i < defaultVal.size(); i++) { v.push_back(defaultVal[i]); }\n    } else if (v.size() > defaultVal.size()) {\n        while (v.size() > defaultVal.size()) { v.pop_back(); }\n    }\n\n    return (v);\n}\n\nlong ParamsBase::GetValueLong(const string tag, long defaultVal) const\n{\n    vector<long> defaultValVec(1, defaultVal);\n    vector<long> v = ParamsBase::GetValueLongVec(tag, defaultValVec);\n\n    if (!v.size()) return (defaultVal);\n\n    return (v[0]);\n}\n\nvector<double> ParamsBase::GetValueDoubleVec(const string tag) const\n{\n    vector<double> empty;\n\n    VAssert(_node);\n\n    bool test = _node->HasElementDouble(tag);\n    if (!test) return (empty);\n    // if (! _node->HasElementDouble(tag)) return(empty);\n\n    return (_node->GetElementDouble(tag));\n}\n\nvector<double> ParamsBase::GetValueDoubleVec(const string tag, const vector<double> &defaultVal) const\n{\n    if (!_node->HasElementDouble(tag)) return (defaultVal);\n\n    vector<double> v = _node->GetElementDouble(tag);\n    if (v.size() < defaultVal.size()) {\n        for (int i = v.size(); i < defaultVal.size(); i++) { v.push_back(defaultVal[i]); }\n    } else if (v.size() > defaultVal.size()) {\n        while (v.size() > defaultVal.size()) { v.pop_back(); }\n    }\n\n    return (v);\n}\n\ndouble ParamsBase::GetValueDouble(const string tag, double defaultVal) const\n{\n    vector<double> defaultValVec(1, defaultVal);\n    vector<double> v = ParamsBase::GetValueDoubleVec(tag, defaultValVec);\n\n    if (!v.size()) return (defaultVal);\n\n    return (v[0]);\n}\n\nvector<string> ParamsBase::GetValueStringVec(const string tag) const\n{\n    vector<string> empty;\n    if (!_node->HasElementString(tag)) return (empty);\n\n    vector<string> v;\n    _node->GetElementStringVec(tag, v);\n\n    string_replace(v, \"NULL\", \"\");\n\n    return (v);\n}\n\nvector<string> ParamsBase::GetValueStringVec(const string tag, const vector<string> &defaultVal) const\n{\n    if (!_node->HasElementString(tag)) return (defaultVal);\n\n    vector<string> v;\n    _node->GetElementStringVec(tag, v);\n\n    string_replace(v, \"NULL\", \"\");\n\n    if (v.size() < defaultVal.size()) {\n        for (int i = v.size(); i < defaultVal.size(); i++) { v.push_back(defaultVal[i]); }\n    } else if (v.size() > defaultVal.size()) {\n        while (v.size() > defaultVal.size()) { v.pop_back(); }\n    }\n\n    return (v);\n}\n\nstring ParamsBase::GetValueString(const string tag, string defaultVal) const\n{\n    if (!_node->HasElementString(tag)) return (defaultVal);\n\n    string v = _node->GetElementString(tag);\n    v = STLUtils::ReplaceAll(v, \"\\\\ \", \" \");\n\n    if (v == \"NULL\") { v = \"\"; }\n\n    return (v);\n}\n\nvoid ParamsBase::SetValueLong(const string &tag, string description, long value)\n{\n    vector<long> values(1, value);\n    ParamsBase::SetValueLongVec(tag, description, values);\n}\n\nvoid ParamsBase::SetValueLongVec(const string &tag, string description, const vector<long> &values)\n{\n    vector<long> current = GetValueLongVec(tag);\n    if (current == values) return;\n\n    _node->SetElementLong(tag, values);\n\n    _ssave->Save(_node, description);\n}\n\nvoid ParamsBase::SetValueDouble(const string &tag, string description, double value)\n{\n    vector<double> values(1, value);\n    ParamsBase::SetValueDoubleVec(tag, description, values);\n}\n\nvoid ParamsBase::SetValueDoubleVec(const string &tag, string description, const vector<double> &values)\n{\n    vector<double> current = GetValueDoubleVec(tag);\n    if (current == values) return;\n\n    _node->SetElementDouble(tag, values);\n\n    _ssave->Save(_node, description);\n}\n\nvoid ParamsBase::SetValueString(const string &tag, string description, const string &value)\n{\n    vector<string> values(1, value);\n    ParamsBase::SetValueStringVec(tag, description, values);\n}\n\nvoid ParamsBase::SetValueStringVec(const string &tag, string description, const vector<string> &values)\n{\n    vector<string> current = GetValueStringVec(tag);\n    if (current == values) return;\n\n    // Replace empty strings with a token\n    //\n    vector<string> my_values = values;\n    string_replace(my_values, \"\", \"NULL\");\n\n    _node->SetElementStringVec(tag, my_values);\n\n    _ssave->Save(_node, description);\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// ParamsSeparator Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nParamsSeparator::ParamsSeparator(StateSave *ssave, const string &name) : ParamsBase(ssave, name) {}\n\nParamsSeparator::ParamsSeparator(StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\nParamsSeparator::ParamsSeparator(ParamsSeparator *parent, const string &name) : ParamsBase(parent->_ssave)\n{\n    if (parent->GetNode()->HasChild(name)) {\n        _node = parent->GetNode()->GetChild(name);\n        VAssert(_node);\n    } else {\n        _node = parent->GetNode()->NewChild(name);\n        parent->_ssave->Save(parent->GetNode(), \"New params\");\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// ParamsFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nParamsBase *ParamsFactory::CreateInstance(string className, ParamsBase::StateSave *ssave, XmlNode *node)\n{\n    ParamsBase *instance = NULL;\n\n    // find className in the registry and call factory method.\n    //\n    auto it = m_factoryFunctionRegistry.find(className);\n    if (it != m_factoryFunctionRegistry.end()) instance = it->second(ssave, node);\n\n    if (instance != NULL)\n        return instance;\n    else\n        return NULL;\n}\n\nvector<string> ParamsFactory::GetFactoryNames() const\n{\n    vector<string>                                                                          names;\n    map<string, function<ParamsBase *(ParamsBase::StateSave *, XmlNode *)>>::const_iterator itr;\n\n    for (itr = m_factoryFunctionRegistry.begin(); itr != m_factoryFunctionRegistry.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// ParamsContainer Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nParamsContainer::ParamsContainer(ParamsBase::StateSave *ssave, const string &name)\n{\n    VAssert(ssave != NULL);\n\n    _ssave = ssave;\n    _separator = NULL;\n    _elements.clear();\n\n    _separator = new ParamsSeparator(ssave, name);\n}\n\nParamsContainer::ParamsContainer(ParamsBase::StateSave *ssave, XmlNode *node)\n{\n    VAssert(ssave != NULL);\n    VAssert(node != NULL);\n\n    _ssave = ssave;\n    _separator = new ParamsSeparator(ssave, node);\n    _elements.clear();\n\n    for (int i = 0; i < node->GetNumChildren(); i++) {\n        XmlNode *eleNameNode = node->GetChild(i);\n        if (!eleNameNode->HasChild(0)) continue;    // bad node\n\n        XmlNode *eleNode = eleNameNode->GetChild(0);\n\n        string eleName = eleNameNode->GetTag();\n        string classname = eleNode->GetTag();\n\n        ParamsBase *pB = ParamsFactory::Instance()->CreateInstance(classname, ssave, eleNode);\n        if (pB == NULL) {\n            SetDiagMsg(\"ParamsContainer::ParamsContainer() unrecognized class: %s\", classname.c_str());\n            continue;\n        }\n\n        _elements[eleName] = pB;\n    }\n}\n\nParamsContainer::ParamsContainer(const ParamsContainer &rhs)\n{\n    _ssave = rhs._ssave;\n    _separator = NULL;\n    _elements.clear();\n\n    _ssave->BeginGroup(\"Params container\");\n\n    _separator = new ParamsSeparator(*(rhs._separator));\n    _separator->SetParent(NULL);\n\n    vector<string> names = rhs.GetNames();\n    for (int i = 0; i < names.size(); i++) {\n        // Make copy of ParamsBase\n        //\n        ParamsBase *rhspb = rhs.GetParams(names[i]);\n        XmlNode *   node = new XmlNode(*(rhspb->GetNode()));\n\n        string      classname = rhspb->GetName();\n        ParamsBase *mypb = ParamsFactory::Instance()->CreateInstance(classname, _ssave, node);\n        mypb->SetParent(_separator);\n\n        _elements[names[i]] = mypb;\n    }\n\n    _ssave->EndGroup();\n}\n\nParamsContainer &ParamsContainer::operator=(const ParamsContainer &rhs)\n{\n    VAssert(_separator);\n\n    vector<string> mynames = GetNames();\n    for (int i = 0; i < mynames.size(); i++) { Remove(mynames[i]); }\n    _elements.clear();\n\n    _ssave->BeginGroup(\"Params container\");\n\n    _separator = rhs._separator;\n    _ssave = rhs._ssave;\n\n    vector<string> names = rhs.GetNames();\n    for (int i = 0; i < names.size(); i++) {\n        XmlNode *eleNameNode = _separator->GetNode()->GetChild(names[i]);\n        VAssert(eleNameNode);\n\n        ParamsSeparator mySep(_ssave, eleNameNode);\n\n        XmlNode *eleNode = eleNameNode->GetChild(0);\n\n        string eleName = eleNameNode->GetTag();\n        string classname = eleNode->GetTag();\n\n        ParamsBase *mypb = ParamsFactory::Instance()->CreateInstance(classname, _ssave, eleNode);\n        mypb->SetParent(&mySep);\n\n        _elements[names[i]] = mypb;\n    }\n\n    _ssave->EndGroup();\n\n    return (*this);\n}\n\nParamsContainer::~ParamsContainer()\n{\n    map<string, ParamsBase *>::iterator itr;\n    for (itr = _elements.begin(); itr != _elements.end(); ++itr) {\n        if (itr->second) delete itr->second;\n    }\n\n    if (_separator) delete _separator;\n}\n\nParamsBase *ParamsContainer::Insert(ParamsBase *pb, string name)\n{\n    VAssert(pb != NULL);\n    if (name.empty()) { name = \"NULL\"; }\n\n    map<string, ParamsBase *>::iterator itr = _elements.find(name);\n    if (itr != _elements.end()) { delete itr->second; }\n\n    _ssave->BeginGroup(\"Params container\");\n\n    // Create a separator node\n    //\n    ParamsSeparator mySep(_ssave, name);\n    mySep.SetParent(_separator);\n\n    // Create element name node\n    //\n    string      classname = pb->GetName();\n    XmlNode *   node = new XmlNode(*(pb->GetNode()));\n    ParamsBase *mypb = ParamsFactory::Instance()->CreateInstance(classname, _ssave, node);\n    VAssert(mypb != NULL);\n    mypb->SetParent(&mySep);\n\n    _elements[name] = mypb;\n\n    _ssave->EndGroup();\n\n    return (mypb);\n}\n\nParamsBase *ParamsContainer::Create(string className, string name)\n{\n    VAssert(!className.empty());\n    VAssert(!name.empty());\n\n    map<string, ParamsBase *>::iterator itr = _elements.find(name);\n    if (itr != _elements.end()) { delete itr->second; }\n\n    _ssave->BeginGroup(\"Params container\");\n\n    // Create a separator node\n    //\n    ParamsSeparator mySep(_ssave, name);\n    mySep.SetParent(_separator);\n\n    // Create the desired class\n    //\n    ParamsBase *mypb = ParamsFactory::Instance()->CreateInstance(className, _ssave, NULL);\n    VAssert(mypb != NULL);\n\n    mypb->SetParent(&mySep);\n\n    _elements[name] = mypb;\n\n    _ssave->EndGroup();\n\n    return (mypb);\n}\n\nvoid ParamsContainer::Remove(string name)\n{\n    map<string, ParamsBase *>::iterator itr = _elements.find(name);\n    if (itr == _elements.end()) return;\n\n    ParamsBase *mypb = itr->second;\n\n    // Set parent to root so  Xml representation will be deleted\n    //\n    mypb->SetParent(NULL);\n    delete mypb;\n\n    _elements.erase(itr);\n\n    _ssave->Save(_separator->GetNode(), \"Delete params\");\n}\n\nParamsBase *ParamsContainer::GetParams(string name) const\n{\n    if (name.empty()) { name = \"NULL\"; }\n\n    map<string, ParamsBase *>::const_iterator itr = _elements.find(name);\n    if (itr != _elements.end()) return (itr->second);\n\n    return (NULL);\n}\n\nstring ParamsContainer::GetParamsName(const ParamsBase *pb) const\n{\n    map<string, ParamsBase *>::const_iterator itr;\n    for (itr = _elements.begin(); itr != _elements.end(); ++itr) {\n        if (itr->second == pb) return (itr->first);\n    }\n\n    return (\"\");\n}\n\nvector<string> ParamsContainer::GetNames() const\n{\n    map<string, ParamsBase *>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _elements.begin(); itr != _elements.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n"
  },
  {
    "path": "lib/params/ParamsMgr.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tparamsmgr.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tOctober 2004\n//\n//\tDescription:\tImplements the ParamsMgr class\n//\t\tThis manages the collection of Params classes that are active in VAPOR\n//\n#include <iostream>\n#include <sstream>\n#include <fstream>\n#include <algorithm>\n\n#include <vapor/ParamsMgr.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/regionparams.h>\n#include <vapor/STLUtils.h>\n\nusing namespace VAPoR;\n//----------------------------------------------------------------------------\n// Static member initialization.\n//----------------------------------------------------------------------------\nconst string ParamsMgr::_rootTag = \"VAPOR\";\nconst string ParamsMgr::_globalTag = \"Global\";\nconst string ParamsMgr::_windowsTag = \"Windows\";\nconst string ParamsMgr::_renderersTag = \"Renderers\";\nconst string ParamsMgr::_appRenderersTag = \"AppRenderers\";\n\nvoid ParamsMgr::_init(vector<string> appParams, XmlNode *node)\n{\n    _renderParamsMap.clear();\n\n    if (node) {\n        if (node->GetTag() != _rootTag) { node->SetTag(_rootTag); }\n        _rootSeparator = new ParamsSeparator(&_ssave, node);\n    } else {\n        _rootSeparator = new ParamsSeparator(&_ssave, _rootTag);\n        node = _rootSeparator->GetNode();\n    }\n\n    // State save class needs root node of state tree\n    //\n    _ssave.Reinit(node);\n\n    XmlNode *child = node->GetChild(_globalTag);\n    if (child) {\n        _otherParams = new ParamsContainer(&_ssave, child);\n    } else {\n        _otherParams = new ParamsContainer(&_ssave, _globalTag);\n        _otherParams->SetParent(_rootSeparator);\n    }\n\n    if (!_otherParams->GetParams(RegionParams::GetClassType())) { _otherParams->Create(RegionParams::GetClassType(), RegionParams::GetClassType()); }\n\n    if (!_otherParams->GetParams(AnnotationParams::GetClassType())) { _otherParams->Create(AnnotationParams::GetClassType(), AnnotationParams::GetClassType()); }\n\n    if (!_otherParams->GetParams(DatasetsParams::GetClassType())) { _otherParams->Create(DatasetsParams::GetClassType(), DatasetsParams::GetClassType()); }\n\n    // Deal with any Params registered by the application\n    //\n    for (int i = 0; i < appParams.size(); i++) {\n        if (!_otherParams->GetParams(appParams[i])) { _otherParams->Create(appParams[i], appParams[i]); }\n    }\n}\n\nParamsMgr::ParamsMgr(std::vector<string> appParamNames, std::vector<string> appRenderParamNames)\n{\n    _appParamNames = appParamNames;\n    _appRenderParamNames = appRenderParamNames;\n    _dataMgrMap.clear();\n\n    _ssave.SetEnabled(false);\n    _init(appParamNames, NULL);\n    _ssave.SetEnabled(true);\n}\n\nvoid ParamsMgr::_destroy()\n{\n    // Delete all of the render containers\n    //\n    delete_ren_containers();\n\n    // Now delete all of the viewpoint params\n    //\n    map<string, ViewpointParams *>::iterator vpitr;\n    for (vpitr = _viewpointParamsMap.begin(); vpitr != _viewpointParamsMap.end(); ++vpitr) {\n        if (vpitr->second) delete vpitr->second;\n    }\n    _viewpointParamsMap.clear();\n\n    if (_otherParams) delete _otherParams;\n\n    map<string, RenParamsContainer *>::iterator itr;\n    for (itr = _otherRenParams.begin(); itr != _otherRenParams.end(); ++itr) {\n        if (itr->second) delete itr->second;\n    }\n    _otherRenParams.clear();\n\n    if (_rootSeparator) delete _rootSeparator;\n}\n\nParamsMgr::~ParamsMgr()\n{\n    _destroy();\n}\n\nvoid ParamsMgr::LoadState()\n{\n    // Don't know if this is necessary but previous code would always wrap call\n    BeginSaveStateGroup(\"Load state\");\n    _destroy();\n\n    _init(_appParamNames, NULL);\n\n    // If data loaded set up data dependent parameters from default state.\n    //\n    if (_dataMgrMap.size()) { addDataMgrNew(); }\n    EndSaveStateGroup();\n}\n\nvoid ParamsMgr::LoadState(const XmlNode *node)\n{\n    _destroy();\n\n    XmlNode *mynode = new XmlNode(*node);\n\n    _init(_appParamNames, mynode);\n\n    ParamsSeparator *windowsSep = new ParamsSeparator(_rootSeparator, _windowsTag);\n\n    XmlNode *winNode = windowsSep->GetNode();\n    for (int i = 0; i < winNode->GetNumChildren(); i++) {\n        string winName = winNode->GetChild(i)->GetTag();\n\n        (void)make_vp_params(winName);\n    }\n\n    delete windowsSep;\n\n    // If data loaded set up data dependent parameters from new state.\n    //\n    vector<string> dataSetNames = GetDataMgrNames();\n    for (auto dataSetName : dataSetNames) {\n        map<string, DataMgr *>::const_iterator itr = _dataMgrMap.find(dataSetName);\n        if (itr != _dataMgrMap.end()) addDataMgrMerge(itr->first);\n    }\n}\n\nint ParamsMgr::LoadState(string stateFile)\n{\n    BeginSaveStateGroup(\"Load state\");\n\n    XmlParser parser;\n    XmlNode   node;\n\n    int rc = parser.LoadFromFile(&node, stateFile);\n    if (rc < 0) {\n        SetErrMsg(\"Invalid session file : %s\", stateFile.c_str());\n        EndSaveStateGroup();\n        return (-1);\n    }\n\n    LoadState(&node);\n    EndSaveStateGroup();\n    return (0);\n}\n\nvoid ParamsMgr::addDataMgrNew()\n{\n    // Delete all of the renderer containers\n    //\n    delete_ren_containers();\n}\n\nvoid ParamsMgr::addDataMgrMerge(string dataSetName)\n{\n    ParamsSeparator *windowsSep = new ParamsSeparator(_rootSeparator, _windowsTag);\n\n    XmlNode *winSepNode = windowsSep->GetNode();\n    for (int i = 0; i < winSepNode->GetNumChildren(); i++) {\n        XmlNode *winNode = winSepNode->GetChild(i);\n        string   winName = winNode->GetTag();\n\n        if (winNode->HasChild(_renderersTag)) {\n            XmlNode *renderersNode = winNode->GetChild(_renderersTag);\n\n            for (int j = 0; j < renderersNode->GetNumChildren(); j++) {\n                XmlNode *dataSepNode = renderersNode->GetChild(j);\n                string   s = dataSepNode->GetTag();\n\n                if (s != dataSetName) continue;\n\n                for (int k = 0; k < dataSepNode->GetNumChildren(); k++) { (void)make_ren_container(winName, dataSetName, dataSepNode->GetChild(k)->GetTag()); }\n            }\n        }\n    }\n\n    delete windowsSep;\n\n    _createAppRenParams(dataSetName);\n}\n\nvoid ParamsMgr::_createAppRenParams(string dataSetName)\n{\n    // Deal with any application render Params registered by the application\n    //\n\n    ParamsSeparator *appRenParamsSep = new ParamsSeparator(_rootSeparator, _appRenderersTag);\n\n    // Delete any existing container for this data set\n    //\n    map<string, RenParamsContainer *>::const_iterator itr;\n    itr = _otherRenParams.find(dataSetName);\n    RenParamsContainer *rpc = itr == _otherRenParams.end() ? NULL : itr->second;\n    if (rpc) delete rpc;\n\n    if (appRenParamsSep->HasChild(dataSetName)) {\n        XmlNode *node = appRenParamsSep->GetNode()->GetChild(dataSetName);\n        VAssert(node);\n\n        rpc = new RenParamsContainer(_dataMgrMap[dataSetName], &_ssave, node);\n    } else {\n        rpc = new RenParamsContainer(_dataMgrMap[dataSetName], &_ssave, dataSetName);\n        rpc->GetSeparator()->SetParent(appRenParamsSep);\n    }\n\n    delete appRenParamsSep;\n\n    // Now add any application render params to the container for this\n    // data set\n    //\n    for (int i = 0; i < _appRenderParamNames.size(); i++) {\n        if (!rpc->GetParams(_appRenderParamNames[i])) { rpc->Create(_appRenderParamNames[i], _appRenderParamNames[i]); }\n    }\n    _otherRenParams[dataSetName] = rpc;\n}\n\nvoid ParamsMgr::AddDataMgr(string dataSetName, DataMgr *dataMgr)\n{\n    _dataMgrMap[dataSetName] = dataMgr;\n\n    // If state already exist use it. Otherwise, create new, default\n    // state\n    //\n    if (_rootSeparator->HasChild(_windowsTag)) {\n        addDataMgrMerge(dataSetName);\n    } else {\n        addDataMgrNew();\n    }\n\n    ParamsSeparator windowsSep(_rootSeparator, _windowsTag);\n    XmlNode *       winSepNode = windowsSep.GetNode();\n    for (int i = 0; i < winSepNode->GetNumChildren(); i++) {\n        string winName = winSepNode->GetChild(i)->GetTag();\n\n        // Instantiating ParamsSeparator classes will add child nodes to the\n        // XML tree as a side effect\n        //\n        ParamsSeparator windowSep(&windowsSep, winName);\n\n        ParamsSeparator renderSep(&windowSep, _renderersTag);\n\n        ParamsSeparator dataSep(&renderSep, dataSetName);\n    }\n}\n\nvoid ParamsMgr::RemoveVisualizer(string winName)\n{\n    if (!_rootSeparator->HasChild(_windowsTag)) return;\n\n    ParamsSeparator windowsSep(_rootSeparator, _windowsTag);\n\n    if (!windowsSep.HasChild(winName)) return;\n\n    _ssave.BeginGroup(\"ParamsMgr::RemoveVisualizer\");\n\n    delete_ren_containers(winName);\n\n    RemoveVisualizerParamsInstance(winName);\n\n    ParamsSeparator windowSep(ParamsSeparator(&windowsSep, winName));\n\n    // Set parent to root so  Xml representation will be deleted\n    //\n    windowSep.SetParent(NULL);\n\n    _ssave.EndGroup();\n}\n\nvoid ParamsMgr::RemoveDataMgr(string dataSetName)\n{\n    map<string, DataMgr *>::iterator itr;\n    itr = _dataMgrMap.find(dataSetName);\n    if (itr == _dataMgrMap.end()) return;\n\n    _dataMgrMap.erase(itr);\n\n    delete_datasets(dataSetName);\n}\n\nvector<string> ParamsMgr::GetDataMgrNames() const\n{\n    vector<string> dataMgrNames;\n\n    ParamsSeparator windowsSep(_rootSeparator, _windowsTag);\n\n    XmlNode *winSepNode = windowsSep.GetNode();\n    for (int i = 0; i < winSepNode->GetNumChildren(); i++) {\n        XmlNode *winNode = winSepNode->GetChild(i);\n        string   winName = winNode->GetTag();\n\n        if (winNode->HasChild(_renderersTag)) {\n            XmlNode *renderersNode = winNode->GetChild(_renderersTag);\n\n            for (int j = 0; j < renderersNode->GetNumChildren(); j++) {\n                XmlNode *dataSepNode = renderersNode->GetChild(j);\n                string   s = dataSepNode->GetTag();\n\n                dataMgrNames.push_back(s);\n            }\n        }\n    }\n\n    sort(dataMgrNames.begin(), dataMgrNames.end());\n    dataMgrNames.erase(unique(dataMgrNames.begin(), dataMgrNames.end()), dataMgrNames.end());\n\n    return (dataMgrNames);\n}\n\n// Legacy moved from VizWinMgr\nstatic string make_viz_name(vector<string> currentNames)\n{\n    int    index = 0;\n    bool   found = false;\n    string name;\n    while (!found) {\n        std::stringstream out;\n        out << index;\n        name = \"Visualizer_No._\" + out.str();\n\n        found = true;\n        for (int i = 0; i < currentNames.size(); i++) {\n            if (currentNames[i] == name) found = false;\n        }\n        index++;\n    }\n    return (name);\n}\n\nstring ParamsMgr::CreateVisualizerParamsInstance(string winName)\n{\n    const auto previousVisualizerNames = GetVisualizerNames();\n    if (winName == \"__AUTO__\")\n        winName = make_viz_name(previousVisualizerNames);\n\n    _ssave.BeginGroup(\"CreateVisualizerParamsInstance\");\n\n    ViewpointParams *vpParams = get_vp_params(winName);\n    if (!vpParams) { vpParams = make_vp_params(winName); }\n    VAssert(vpParams != NULL);\n\n    // TODO initialize viewpoint params\n    // This shouldn't be done here but this was previously accomplished by spaghetti\n    // involving the qt event system and there currently isn't a good place to put it.\n    if (previousVisualizerNames.size() >= 1) {\n        auto pvp = get_vp_params(previousVisualizerNames[0]);\n        vpParams->SetModelViewMatrix(pvp->GetModelViewMatrix());\n        vpParams->SetRotationCenter(pvp->GetRotationCenter());\n\n        for (auto name : pvp->GetTransformNames()) {\n            auto nt = vpParams->GetTransform(name);\n            auto pt = pvp->GetTransform(name);\n            nt->SetTranslations(pt->GetTranslations());\n            nt->SetScales(pt->GetScales());\n            nt->SetRotations(pt->GetRotations());\n            nt->SetOrigin(pt->GetOrigin());\n            nt->SetOriginInitialized(pt->IsOriginInitialized());\n        }\n    }\n\n    _ssave.EndGroup();\n\n    return winName;\n}\n\nvoid ParamsMgr::RemoveVisualizerParamsInstance(string winName)\n{\n    _ssave.BeginGroup(\"RemoveVisualizerParamsInstance\");\n\n    map<string, ViewpointParams *>::const_iterator itr;\n    itr = _viewpointParamsMap.find(winName);\n    if (itr == _viewpointParamsMap.end()) return;\n\n    ViewpointParams *vParams = itr->second;\n\n    // Set parent to root so  Xml representation will be deleted\n    //\n    vParams->SetParent(NULL);\n    delete vParams;\n\n    _viewpointParamsMap.erase(itr);\n\n    _ssave.EndGroup();\n}\n\nRenParamsContainer *ParamsMgr::createRenderParamsHelper(string winName, string dataSetName, string className, string instName)\n{\n    map<string, DataMgr *>::const_iterator itr;\n    itr = _dataMgrMap.find(dataSetName);\n    if (itr == _dataMgrMap.end()) {\n        SetErrMsg(\"Invalid state : no data set\");\n        return (NULL);\n    }\n\n    vector<string> instNames;\n    GetRenderParamNames(instNames);\n    if (find(instNames.begin(), instNames.end(), instName) != instNames.end()) {\n        string myWinName, myDataSetName, myClassName;\n        (void)RenderParamsLookup(instName, myWinName, myDataSetName, myClassName);\n        if (!(myWinName == winName) && (myDataSetName == dataSetName) && (myClassName == className)) {\n            SetErrMsg(\"Non-unique render instance name : %s\", instName.c_str());\n            return (NULL);\n        }\n    }\n\n    // Create ViewpointParams if we don't have one\n    //\n    ViewpointParams *vpParams = get_vp_params(winName);\n    if (!vpParams) {\n        CreateVisualizerParamsInstance(winName);\n        vpParams = get_vp_params(winName);\n    }\n    VAssert(vpParams != NULL);\n\n    RenParamsContainer *container = get_ren_container(winName, dataSetName, className);\n    if (!container) { container = make_ren_container(winName, dataSetName, className); }\n    VAssert(container != NULL);\n\n    return (container);\n}\n\nRenderParams *ParamsMgr::CreateRenderParamsInstance(string winName, string dataSetName, string className, string instName)\n{\n    _ssave.BeginGroup(\"CreateRenderParamsInstance\");\n\n    RenParamsContainer *container = createRenderParamsHelper(winName, dataSetName, className, instName);\n    if (!container) {\n        _ssave.EndGroup();\n        return (NULL);\n    }\n\n    RenderParams *rp = container->GetParams(instName);\n    if (!rp) { rp = container->Create(className, instName); }\n\n    _ssave.EndGroup();\n\n    if (!rp) {\n        SetErrMsg(\"Invalid derived RenderParams  class name %s\", className.c_str());\n        return (NULL);\n    }\n\n    return (rp);\n}\n\nRenderParams *ParamsMgr::CreateRenderParamsInstance(string winName, string dataSetName, string instName, const RenderParams *rp)\n{\n    VAssert(rp);\n\n    _ssave.BeginGroup(\"CreateRenderParamsInstance\");\n\n    string              className = rp->GetName();\n    RenParamsContainer *container = createRenderParamsHelper(winName, dataSetName, className, instName);\n    if (!container) {\n        _ssave.EndGroup();\n        return (NULL);\n    }\n\n    RenderParams *newRP = container->Insert(rp, instName);\n\n    _ssave.EndGroup();\n\n    if (!newRP) {\n        SetErrMsg(\"Invalid derived RenderParams  class name %s\", className.c_str());\n        return (NULL);\n    }\n\n    return (newRP);\n}\n\nvoid ParamsMgr::RemoveRenderParamsInstance(string winName, string dataSetName, string className, string instName)\n{\n    RenParamsContainer *container = get_ren_container(winName, dataSetName, className);\n    if (!container) return;\n\n    container->Remove(instName);\n}\n\nRenderParams *ParamsMgr::GetRenderParams(string winName, string dataSetName, string className, string instName) const\n{\n    RenParamsContainer *container = get_ren_container(winName, dataSetName, className);\n    if (!container) { return (NULL); }\n\n    return (container->GetParams(instName));\n}\n\nvoid ParamsMgr::GetRenderParams(string winName, string dataSetName, vector<RenderParams *> &rParams) const\n{\n    rParams.clear();\n\n    const map<string, RenParamsContainer *> *m1Ptr;\n    m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName);\n    if (!m1Ptr) return;\n\n    // m1Ptr[className]\n    //\n    const map<string, RenParamsContainer *> &         ref = *m1Ptr;\n    map<string, RenParamsContainer *>::const_iterator itr;\n    for (itr = ref.begin(); itr != ref.end(); ++itr) {\n        RenParamsContainer *rpc = itr->second;\n        vector<string>      names = rpc->GetNames();\n        for (int i = 0; i < names.size(); i++) { rParams.push_back(rpc->GetParams(names[i])); }\n    }\n}\n\nvoid ParamsMgr::GetRenderParams(string winName, vector<RenderParams *> &rParams) const\n{\n    rParams.clear();\n\n    const map<string, map<string, RenParamsContainer *>> *m2Ptr;\n    m2Ptr = getWinMap3(_renderParamsMap, winName);\n    if (!m2Ptr) return;\n\n    // m2Ptr[dataSetName][className]\n    //\n    const map<string, map<string, RenParamsContainer *>> &         ref = *m2Ptr;\n    map<string, map<string, RenParamsContainer *>>::const_iterator itr;\n    for (itr = ref.begin(); itr != ref.end(); ++itr) {\n        vector<RenderParams *> tmp;\n        GetRenderParams(winName, itr->first, tmp);\n        rParams.insert(rParams.end(), tmp.begin(), tmp.end());\n    }\n}\n\nvoid ParamsMgr::GetRenderParams(vector<RenderParams *> &rParams) const\n{\n    rParams.clear();\n\n    map<string, map<string, map<string, RenParamsContainer *>>>::const_iterator itr;\n\n    for (itr = _renderParamsMap.begin(); itr != _renderParamsMap.end(); ++itr) {\n        vector<RenderParams *> tmp;\n        GetRenderParams(itr->first, tmp);\n        rParams.insert(rParams.end(), tmp.begin(), tmp.end());\n    }\n}\n\nvoid ParamsMgr::GetRenderParamNames(string winName, string dataSetName, string className, vector<string> &instNames) const\n{\n    instNames.clear();\n\n    RenParamsContainer *container = get_ren_container(winName, dataSetName, className);\n    if (!container) return;\n\n    instNames = container->GetNames();\n\n    // Sanity check.  Names should always be unique!\n    //\n    sort(instNames.begin(), instNames.end());\n    instNames.erase(unique(instNames.begin(), instNames.end()), instNames.end());\n}\n\nvoid ParamsMgr::GetRenderParamNames(string winName, string dataSetName, vector<string> &instNames) const\n{\n    instNames.clear();\n\n    const map<string, RenParamsContainer *> *m1Ptr;\n    m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName);\n    if (!m1Ptr) return;\n\n    // m1Ptr[className]\n    //\n    const map<string, RenParamsContainer *> &         ref = *m1Ptr;\n    map<string, RenParamsContainer *>::const_iterator itr;\n    for (itr = ref.begin(); itr != ref.end(); ++itr) {\n        vector<string> tmp;\n        GetRenderParamNames(winName, dataSetName, itr->first, tmp);\n\n        instNames.insert(instNames.end(), tmp.begin(), tmp.end());\n    }\n    sort(instNames.begin(), instNames.end());\n    instNames.erase(unique(instNames.begin(), instNames.end()), instNames.end());\n}\n\nvoid ParamsMgr::GetRenderParamNames(string winName, vector<string> &instNames) const\n{\n    instNames.clear();\n\n    const map<string, map<string, RenParamsContainer *>> *m2Ptr;\n    m2Ptr = getWinMap3(_renderParamsMap, winName);\n    if (!m2Ptr) return;\n\n    // m2Ptr[dataSetName][className]\n    //\n    const map<string, map<string, RenParamsContainer *>> &         ref = *m2Ptr;\n    map<string, map<string, RenParamsContainer *>>::const_iterator itr;\n    for (itr = ref.begin(); itr != ref.end(); ++itr) {\n        vector<string> tmp;\n        GetRenderParamNames(winName, itr->first, tmp);\n        instNames.insert(instNames.end(), tmp.begin(), tmp.end());\n    }\n    sort(instNames.begin(), instNames.end());\n    instNames.erase(unique(instNames.begin(), instNames.end()), instNames.end());\n}\n\nvoid ParamsMgr::GetRenderParamNames(vector<string> &instNames) const\n{\n    instNames.clear();\n\n    map<string, map<string, map<string, RenParamsContainer *>>>::const_iterator itr;\n\n    for (itr = _renderParamsMap.begin(); itr != _renderParamsMap.end(); ++itr) {\n        vector<string> tmp;\n        GetRenderParamNames(itr->first, tmp);\n        instNames.insert(instNames.end(), tmp.begin(), tmp.end());\n    }\n    sort(instNames.begin(), instNames.end());\n    instNames.erase(unique(instNames.begin(), instNames.end()), instNames.end());\n}\n\nvector<string> ParamsMgr::GetRenderParamNames() const\n{\n    vector<string> ret;\n    GetRenderParamNames(ret);\n    return ret;\n}\n\nvector<string> ParamsMgr::GetRenderParamNamesForDataset(string datasetName) const\n{\n    vector<string> names, t;\n    for (const auto &viz : GetVisualizerNames()) {\n        GetRenderParamNames(viz, datasetName, t);\n        STLUtils::AppendTo(names, t);\n    }\n    return names;\n}\n\nbool ParamsMgr::RenderParamsLookup(string instName, string &winName, string &dataSetName, string &className) const\n{\n    winName.clear();\n    dataSetName.clear();\n    className.clear();\n\n    // Exhaustively search through _renderParamsMap looking for an\n    // occurrence of instName\n    //\n    map<string, map<string, map<string, RenParamsContainer *>>>::const_iterator itr1;\n    for (itr1 = _renderParamsMap.begin(); itr1 != _renderParamsMap.end(); ++itr1) {\n        map<string, map<string, RenParamsContainer *>>::const_iterator itr2;\n        for (itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2) {\n            map<string, RenParamsContainer *>::const_iterator itr3;\n            for (itr3 = itr2->second.begin(); itr3 != itr2->second.end(); ++itr3) {\n                const RenParamsContainer &ref = *(itr3->second);\n                vector<string>            instNames = ref.GetNames();\n\n                if (find(instNames.begin(), instNames.end(), instName) != instNames.end()) {\n                    winName = itr1->first;\n                    dataSetName = itr2->first;\n                    className = itr3->first;\n                    return (true);\n                }\n            }\n        }\n    }\n    return (false);\n}\n\nbool ParamsMgr::RenderParamsLookup(RenderParams *inst, string &instName, string &winName, string &dataSetName, string &className) const\n{\n    winName.clear();\n    dataSetName.clear();\n    className.clear();\n\n    map<string, map<string, map<string, RenParamsContainer *>>>::const_iterator itr1;\n    for (itr1 = _renderParamsMap.begin(); itr1 != _renderParamsMap.end(); ++itr1) {\n        map<string, map<string, RenParamsContainer *>>::const_iterator itr2;\n        for (itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2) {\n            map<string, RenParamsContainer *>::const_iterator itr3;\n            for (itr3 = itr2->second.begin(); itr3 != itr2->second.end(); ++itr3) {\n                const RenParamsContainer &ref = *(itr3->second);\n                vector<string>            instNames = ref.GetNames();\n\n                for (const auto & name : instNames) {\n                    if (ref.GetParams(name) == inst) {\n                        instName = name;\n                        winName = itr1->first;\n                        dataSetName = itr2->first;\n                        className = itr3->first;\n                        return (true);\n                    }\n                }\n            }\n        }\n    }\n    return (false);\n}\n\n\nvector<string> ParamsMgr::GetVisualizerNames() const\n{\n    vector<string> vizNames;\n\n    map<string, ViewpointParams *>::const_iterator itr;\n    for (itr = _viewpointParamsMap.begin(); itr != _viewpointParamsMap.end(); ++itr) { vizNames.push_back(itr->first); }\n\n    return (vizNames);\n}\n\n// m2[b][c] <- m3[a][b][c]\n//\nconst map<string, map<string, RenParamsContainer *>> *ParamsMgr::getWinMap3(const map<string, map<string, map<string, RenParamsContainer *>>> &m3, string key) const\n{\n    // map[a][b][c]\n    //\n    map<string, map<string, map<string, RenParamsContainer *>>>::const_iterator itr;\n\n    itr = m3.find(key);\n    if (itr == m3.end()) return (NULL);\n\n    return (&(itr->second));\n}\n\n// m1[c] <- m3[a][b][c]\n//\nconst map<string, RenParamsContainer *> *ParamsMgr::getWinMap3(const map<string, map<string, map<string, RenParamsContainer *>>> &m3, string key1, string key2) const\n{\n    const map<string, map<string, RenParamsContainer *>> *m2Ptr;\n    m2Ptr = getWinMap3(m3, key1);\n    if (!m2Ptr) return (NULL);\n\n    const map<string, RenParamsContainer *> *m1Ptr;\n    m1Ptr = getWinMap2(*m2Ptr, key2);\n\n    return (m1Ptr);\n}\n\n// m1[c] <- m2[b][c]\n//\nconst map<string, RenParamsContainer *> *ParamsMgr::getWinMap2(const map<string, map<string, RenParamsContainer *>> &m2, string key) const\n{\n    // map[b][c]\n    //\n    map<string, map<string, RenParamsContainer *>>::const_iterator itr;\n\n    itr = m2.find(key);\n    if (itr == m2.end()) return (NULL);\n\n    return (&(itr->second));\n}\n\n// m2[b][c] <- m3[a][b][c]\n//\nmap<string, map<string, RenParamsContainer *>> *ParamsMgr::getWinMap3(map<string, map<string, map<string, RenParamsContainer *>>> &m3, string key) const\n{\n    // map[a][b][c]\n    //\n    map<string, map<string, map<string, RenParamsContainer *>>>::iterator itr;\n\n    itr = m3.find(key);\n    if (itr == m3.end()) return (NULL);\n\n    return (&(itr->second));\n}\n\n// m1[c] <- m3[a][b][c]\n//\nmap<string, RenParamsContainer *> *ParamsMgr::getWinMap3(map<string, map<string, map<string, RenParamsContainer *>>> &m3, string key1, string key2) const\n{\n    map<string, map<string, RenParamsContainer *>> *m2Ptr;\n    m2Ptr = getWinMap3(m3, key1);\n    if (!m2Ptr) return (NULL);\n\n    map<string, RenParamsContainer *> *m1Ptr;\n    m1Ptr = getWinMap2(*m2Ptr, key2);\n\n    return (m1Ptr);\n}\n\n// m1[c] <- m2[b][c]\n//\nmap<string, RenParamsContainer *> *ParamsMgr::getWinMap2(map<string, map<string, RenParamsContainer *>> &m2, string key) const\n{\n    // map[b][c]\n    //\n    map<string, map<string, RenParamsContainer *>>::iterator itr;\n\n    itr = m2.find(key);\n    if (itr == m2.end()) return (NULL);\n\n    return (&(itr->second));\n}\n\nvector<string> ParamsMgr::GetRenderParamsClassNames(string winName, string dataSetName) const\n{\n    vector<string> rClassNames;\n\n    // _renderParamsMap[winName][dataSetName][className]\n    //\n\n    const map<string, RenParamsContainer *> *m1Ptr;\n    m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName);\n    if (!m1Ptr) return (rClassNames);\n\n    // m1Ptr[className]\n    //\n    const map<string, RenParamsContainer *> &ref = *m1Ptr;\n\n    map<string, RenParamsContainer *>::const_iterator itr;\n    for (itr = ref.begin(); itr != ref.end(); ++itr) { rClassNames.push_back(itr->first); }\n\n    // remove duplicates\n    //\n    sort(rClassNames.begin(), rClassNames.end());\n    rClassNames.erase(unique(rClassNames.begin(), rClassNames.end()), rClassNames.end());\n    return (rClassNames);\n}\n\nvector<string> ParamsMgr::GetRenderParamsClassNames(string winName) const\n{\n    vector<string> rClassNames;\n\n    // _renderParamsMap[winName][dataSetName][className]\n    //\n\n    const map<string, map<string, RenParamsContainer *>> *m2Ptr;\n    m2Ptr = getWinMap3(_renderParamsMap, winName);\n    if (!m2Ptr) return (rClassNames);\n\n    // m2Ptr[dataSetName][className]\n    //\n\n    const map<string, map<string, RenParamsContainer *>> &ref = *m2Ptr;\n\n    map<string, map<string, RenParamsContainer *>>::const_iterator itr;\n    for (itr = ref.begin(); itr != ref.end(); ++itr) {\n        string dataSetName = itr->first;\n\n        vector<string> tmpV = GetRenderParamsClassNames(winName, dataSetName);\n        rClassNames.insert(rClassNames.end(), tmpV.begin(), tmpV.end());\n    }\n\n    // remove duplicates\n    //\n    sort(rClassNames.begin(), rClassNames.end());\n    rClassNames.erase(unique(rClassNames.begin(), rClassNames.end()), rClassNames.end());\n    return (rClassNames);\n}\n\nvector<string> ParamsMgr::GetRenderParamInstances(string winName, string dataSetName, string className) const\n{\n    vector<string> instances;\n\n    RenParamsContainer *rpc = get_ren_container(winName, dataSetName, className);\n    if (rpc) {\n        vector<string> names = rpc->GetNames();\n        instances.insert(instances.end(), names.begin(), names.end());\n    }\n\n    // Sanity check.  Names should always be unique!\n    //\n    sort(instances.begin(), instances.end());\n    instances.erase(unique(instances.begin(), instances.end()), instances.end());\n    return (instances);\n}\n\nvector<string> ParamsMgr::GetRenderParamInstances(string winName, string className) const\n{\n    vector<string> instances;\n\n    const map<string, map<string, RenParamsContainer *>> *m2Ptr;\n    m2Ptr = getWinMap3(_renderParamsMap, winName);\n    if (!m2Ptr) return (instances);\n\n    const map<string, map<string, RenParamsContainer *>> &         ref = *m2Ptr;\n    map<string, map<string, RenParamsContainer *>>::const_iterator itr;\n\n    for (itr = ref.begin(); itr != ref.end(); ++itr) {\n        string dataSetName = itr->first;\n\n        RenParamsContainer *rpc = get_ren_container(winName, dataSetName, className);\n        if (rpc) {\n            vector<string> names = rpc->GetNames();\n            instances.insert(instances.end(), names.begin(), names.end());\n        }\n    }\n\n    // Sanity check.  Names should always be unique!\n    //\n    sort(instances.begin(), instances.end());\n    instances.erase(unique(instances.begin(), instances.end()), instances.end());\n    return (instances);\n}\n\nViewpointParams *ParamsMgr::GetViewpointParams(string winName) const { return (get_vp_params(winName)); }\n\n#ifdef VAPOR3_0_0_ALPHA\nvoid ParamsMgr::InsertRenderParamsInstance(RenderParams *rp, string winName, string instName)\n{\n    string className = rp->GetName();\n\n    RenParamsContainer *container = get_ren_container(winName, className);\n    if (!container) { container = make_ren_container(className, winName); }\n    VAssert(container != NULL);\n\n    container->Insert(rp, instName);\n}\n#endif\n\nRenParamsContainer *ParamsMgr::get_ren_container(string winName, string dataSetName, string renderName) const\n{\n    // map[winName][dataSetName][renderName]\n    //\n\n    const map<string, RenParamsContainer *> *m1Ptr;\n    m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName);\n    if (!m1Ptr) return (NULL);\n\n    // m1Ptr[className]\n    //\n    const map<string, RenParamsContainer *> &ref = *m1Ptr;\n\n    map<string, RenParamsContainer *>::const_iterator itr;\n    itr = ref.find(renderName);\n    if (itr == ref.end()) return (NULL);\n\n    return (itr->second);\n}\n\nvoid ParamsMgr::delete_ren_container(string winName, string dataSetName, string renderName)\n{\n    // _renderParamsMap[winName][dataSetName][renderName] -> ref[renderName]\n    //\n    map<string, RenParamsContainer *> *m1Ptr;\n    m1Ptr = getWinMap3(_renderParamsMap, winName, dataSetName);\n    if (!m1Ptr) return;\n\n    // *m1Ptr[renderName] == ref[renderName]\n    //\n    map<string, RenParamsContainer *> &ref = *m1Ptr;\n\n    map<string, RenParamsContainer *>::iterator itr;\n    itr = ref.find(renderName);\n    if (itr == ref.end()) return;\n\n    RenParamsContainer *rpc = itr->second;\n    ref.erase(renderName);\n\n    if (!rpc) return;\n\n    // Set parent to root so  Xml representation will be deleted\n    //\n    rpc->GetNode()->SetParent(NULL);\n    delete rpc;\n}\n\nvoid ParamsMgr::delete_ren_containers(string winName, string dataSetName)\n{\n    // _renderParamsMap[winName][dataSetName][renderName] ->\n    //\t\tref1[dataSetName][renderName]\n    //\n    map<string, map<string, RenParamsContainer *>> *m2Ptr;\n    m2Ptr = getWinMap3(_renderParamsMap, winName);\n    if (!m2Ptr) return;\n\n    map<string, map<string, RenParamsContainer *>> &ref1 = *m2Ptr;\n\n    map<string, map<string, RenParamsContainer *>>::iterator itr1;\n    itr1 = ref1.find(dataSetName);\n    if (itr1 == ref1.end()) return;\n\n    //\tref1[dataSetName][renderName] -> ref2[renderName]\n    //\n    map<string, RenParamsContainer *> &         ref2 = itr1->second;\n    map<string, RenParamsContainer *>::iterator itr2;\n    while ((itr2 = ref2.begin()) != ref2.end()) { delete_ren_container(winName, dataSetName, itr2->first); }\n    ref1.erase(dataSetName);\n}\n\nvoid ParamsMgr::delete_ren_containers(string winName)\n{\n    // _renderParamsMap[winName][dataSetName][renderName] ->\n    //\t\tref1[dataSetName][renderName]\n    //\n    map<string, map<string, RenParamsContainer *>> *m2Ptr;\n    m2Ptr = getWinMap3(_renderParamsMap, winName);\n    if (!m2Ptr) return;\n\n    map<string, map<string, RenParamsContainer *>> &         ref = *m2Ptr;\n    map<string, map<string, RenParamsContainer *>>::iterator itr;\n    while ((itr = ref.begin()) != ref.end()) { delete_ren_containers(winName, itr->first); }\n\n    _renderParamsMap.erase(winName);\n}\n\nvoid ParamsMgr::delete_ren_containers()\n{\n    // For each window name delete all of the windows render containers\n    //\n    map<string, map<string, map<string, RenParamsContainer *>>>::iterator itr;\n    while ((itr = _renderParamsMap.begin()) != _renderParamsMap.end()) { delete_ren_containers(itr->first); }\n}\n\nvoid ParamsMgr::delete_datasets(string dataSetName)\n{\n    ParamsSeparator windowsSep(_rootSeparator, _windowsTag);\n\n    XmlNode *winSepNode = windowsSep.GetNode();\n    for (int i = 0; i < winSepNode->GetNumChildren(); i++) {\n        XmlNode *winNode = winSepNode->GetChild(i);\n        string   winName = winNode->GetTag();\n\n        delete_ren_containers(winName, dataSetName);\n\n        XmlNode *renderersNode = winNode->GetChild(_renderersTag);\n        for (int j = 0; j < renderersNode->GetNumChildren(); j++) {\n            XmlNode *dataSepNode = renderersNode->GetChild(j);\n            string   s = dataSepNode->GetTag();\n\n            if (s == dataSetName) {\n                dataSepNode->SetParent(NULL);\n                break;\n            }\n        }\n    }\n}\n\nRenParamsContainer *ParamsMgr::make_ren_container(string winName, string dataSetName, string renderName)\n{\n    ParamsSeparator *windowsSep = new ParamsSeparator(_rootSeparator, _windowsTag);\n\n    ParamsSeparator *windowSep = new ParamsSeparator(windowsSep, winName);\n\n    ParamsSeparator *renderSep = new ParamsSeparator(windowSep, _renderersTag);\n\n    ParamsSeparator *dataSep = new ParamsSeparator(renderSep, dataSetName);\n\n    // Delete any existing occurences with the same name\n    //\n    RenParamsContainer *rpc = get_ren_container(winName, dataSetName, renderName);\n    if (rpc) delete rpc;\n\n    if (dataSep->HasChild(renderName)) {\n        XmlNode *node = dataSep->GetNode()->GetChild(renderName);\n        VAssert(node);\n\n        rpc = new RenParamsContainer(_dataMgrMap[dataSetName], &_ssave, node);\n    } else {\n        rpc = new RenParamsContainer(_dataMgrMap[dataSetName], &_ssave, renderName);\n        rpc->GetSeparator()->SetParent(dataSep);\n    }\n\n    _renderParamsMap[winName][dataSetName][renderName] = rpc;\n\n    delete dataSep;\n    delete renderSep;\n    delete windowSep;\n    delete windowsSep;\n\n    return (rpc);\n}\n\nViewpointParams *ParamsMgr::get_vp_params(string winName) const\n{\n    map<string, ViewpointParams *>::const_iterator itr;\n    itr = _viewpointParamsMap.find(winName);\n    if (itr == _viewpointParamsMap.end()) return (NULL);\n\n    return (itr->second);\n}\n\nViewpointParams *ParamsMgr::make_vp_params(string winName)\n{\n    ParamsSeparator *windowsSep = new ParamsSeparator(_rootSeparator, _windowsTag);\n\n    ParamsSeparator *windowSep = new ParamsSeparator(windowsSep, winName);\n\n    // Delete any existing occurences with the same name\n    //\n    ViewpointParams *vpParams = get_vp_params(winName);\n    if (vpParams) delete vpParams;\n\n    if (windowSep->HasChild(ViewpointParams::GetClassType())) {\n        XmlNode *node = windowSep->GetNode()->GetChild(ViewpointParams::GetClassType());\n        VAssert(node);\n\n        vpParams = new ViewpointParams(&_ssave, node);\n    } else {\n        vpParams = new ViewpointParams(&_ssave);\n        vpParams->SetParent(windowSep);\n    }\n\n    _viewpointParamsMap[winName] = vpParams;\n\n    delete windowsSep;\n    delete windowSep;\n\n    return (vpParams);\n}\n\n#ifdef VAPOR3_0_0_ALPHA\n//----------------------------------------------------------------------------\n// Create a transfer function by parsing a file.\n//----------------------------------------------------------------------------\nint ParamsMgr::loadFromFile(string path)\n{\n    XmlParser xmlparser;\n\n    XmlNode *node = GetNode();\n\n    int rc = xmlparser.LoadFromFile(node, path);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Failed to read file %s : %M\", path.c_str());\n        return (-1);\n    }\n    return (0);\n}\n\n#endif\n\nvoid ParamsMgr::GetAppRenderParams(string dataSetName, vector<RenderParams *> &appRenderParams) const\n{\n    appRenderParams.clear();\n    std::map<string, RenParamsContainer *>::const_iterator itr;\n    itr = _otherRenParams.find(dataSetName);\n    if (itr == _otherRenParams.cend()) return;\n    vector<string> v = itr->second->GetNames();\n    for (int i = 0; i < v.size(); i++) {\n        if (itr->second->GetParams(v[i])) { appRenderParams.push_back(itr->second->GetParams(v[i])); }\n    }\n}\n\n//----------------------------------------------------------------------------\n// Save the transfer function to a file.\n//----------------------------------------------------------------------------\nint ParamsMgr::SaveToFile(string path) const\n{\n    ofstream out(path);\n    if (!out) {\n        MyBase::SetErrMsg(\"Failed to open file %s : %M\", path.c_str());\n        return (-1);\n    }\n\n    out << *(_rootSeparator->GetNode());\n\n    if (out.bad()) {\n        MyBase::SetErrMsg(\"Failed to write file %s : %M\", path.c_str());\n        return (-1);\n    }\n    out.close();\n\n    return (0);\n}\n\nbool ParamsMgr::undoRedoHelper()\n{\n    string description;\n\n    // Get top of **undo** stack\n    //\n    const XmlNode *newNode = _ssave.GetTopUndo(description);\n    if (!newNode) { newNode = _ssave.GetBase(); }\n    if (!newNode) return (false);    // nothing to undo - shouldnt get here\n\n    // Need to disable state saving so the undo itself doesn't trigger\n    // saving of intermediate state\n    //\n    bool saveState = GetSaveStateEnabled();\n    SetSaveStateEnabled(false);\n\n    // Load the new Xml tree (which destroys the old one)\n    //\n    LoadState(newNode);\n\n    // Restore state saving\n    //\n    SetSaveStateEnabled(saveState);\n\n    return (true);\n}\n\nbool ParamsMgr::Undo()\n{\n    bool status = _ssave.Undo();\n\n    if (!status) return (status);\n\n    return (undoRedoHelper());\n}\n\nbool ParamsMgr::Redo()\n{\n    bool status = _ssave.Redo();\n\n    if (!status) return (status);\n\n    return (undoRedoHelper());\n}\n\nvoid ParamsMgr::UndoRedoClear()\n{\n    _ssave.Clear();\n    RebaseStateSave();\n}\n\nvoid ParamsMgr::ManuallyAddCurrentStateToUndoStack(const string &note)\n{\n    _ssave.ManuallyAddCurrentStateToUndoStack(note);\n}\n\nstring ParamsMgr::GetTopUndoDesc() const\n{\n    string s;\n    _ssave.GetTopUndo(s);\n    return (s);\n}\n\nstring ParamsMgr::GetTopRedoDesc() const\n{\n    string s;\n    _ssave.GetTopRedo(s);\n    return (s);\n}\n\nParamsMgr::PMgrStateSave::PMgrStateSave(int stackSize) : StateSave()\n{\n    _enabled = true;\n    _stackSize = stackSize;\n    _rootNode = NULL;\n    _state0 = NULL;\n    _undoStack.clear();\n    _redoStack.clear();\n}\n\nParamsMgr::PMgrStateSave::~PMgrStateSave()\n{\n    cleanStack(0, _undoStack);\n    cleanStack(0, _redoStack);\n    if (_state0) delete _state0;\n}\n\nvoid ParamsMgr::PMgrStateSave::Save(const XmlNode *node, string description)\n{\n    VAssert(_rootNode);\n    VAssert(node);\n\n    if (!GetEnabled()) { return; }\n\n    // Only save state if the node is a branch of the tree rooted at\n    // the node named by _rootTag\n    //\n    vector<string> pathvec = node->GetPathVec();\n    if ((!pathvec.size()) || (pathvec[0] != _rootTag)) { return; }\n\n    if (GetUndoEnabled()) {\n        const XmlNode *topNode = NULL;\n        string         s;\n        topNode = GetTopUndo(s);\n        if (topNode && (*topNode == *_rootNode)) {\n            // Don't save tree if no changes\n            return;\n        }\n    }\n\n    if (!_groups.empty()) { return; }\n\n    if (!_state0) { _state0 = new XmlNode(*_rootNode); }\n\n    // Delete oldest elements if needed\n    //\n    cleanStack(_stackSize, _undoStack);\n\n    // It not inside a group push this element onto the stack\n    //\n    if (GetUndoEnabled()) {\n        _undoStack.push_back(make_pair(description, new XmlNode(*_rootNode)));\n    }\n\n//#define DEBUG\n#ifdef DEBUG\n    cout << \"ParamsMgr::PMgrStateSave::Save() : saving node \" << node->GetTag() << \" : \" << description << endl;\n#endif\n\n    // Clear redo stack\n    //\n    cleanStack(0, _redoStack);\n\n    emitStateChange(description);\n}\n\nvoid ParamsMgr::PMgrStateSave::BeginGroup(string description)\n{\n    VAssert(_rootNode);\n    VAssert(!description.empty());\n    if (!GetEnabled()) return;\n\n    _groups.push(description);\n}\n\nvoid ParamsMgr::PMgrStateSave::EndGroup()\n{\n    VAssert(_rootNode);\n\n    if (!GetEnabled()) return;\n\n    assert(_groups.size());\n    if (!_groups.size()) return;    // BeginGroup() not called\n\n    string desc = _groups.top();\n    _groups.pop();\n\n    // Don't do anything until _groups is empty\n    //\n    if (_groups.size()) return;\n\n    if (GetUndoEnabled()) {\n        const XmlNode *topNode = NULL;\n        string         s;\n        topNode = GetTopUndo(s);\n\n        if (topNode && (*topNode == *_rootNode)) {\n            // Don't save tree if no changes\n            //\n            return;\n        }\n    }\n\n    if (!_state0) { _state0 = new XmlNode(*_rootNode); }\n\n#ifdef DEBUG\n    cout << \"ParamsMgr::PMgrStateSave::EndGroup() : saving \"\n         << \" : \" << desc << endl;\n#endif\n\n    // Delete oldest elements if needed\n    //\n    cleanStack(_stackSize, _undoStack);\n\n    // Clear redo stack\n    //\n    cleanStack(0, _redoStack);\n\n    if (GetUndoEnabled())\n        _undoStack.push_back(make_pair(desc, new XmlNode(*_rootNode)));\n\n    emitStateChange(desc);\n}\n\nvoid ParamsMgr::PMgrStateSave::TriggerManualStateChangeEvent(const string &reason, const bool overrideEnabled)\n{\n    if (!GetEnabled() && !overrideEnabled) return;\n    emitStateChange(\"Manually triggered\" + (reason.empty() ? \"\" : (\": \" + reason)));\n}\n\nvoid ParamsMgr::PMgrStateSave::IntermediateChange() { emitIntermediateStateChange(); }\n\n\nvoid ParamsMgr::PMgrStateSave::SetUndoEnabled(bool b)\n{\n    if (!_groups.empty()) {\n        return;    // Can't change inside group\n    }\n    _addToUndoEnabled = b;\n}\n\nconst XmlNode *ParamsMgr::PMgrStateSave::GetTopUndo(string &description) const\n{\n    VAssert(_rootNode);\n    description.clear();\n\n    if (!_undoStack.size()) return (NULL);\n\n    const pair<string, XmlNode *> &p1 = _undoStack.back();\n\n    description = p1.first;\n    return (p1.second);\n}\n\nconst XmlNode *ParamsMgr::PMgrStateSave::GetTopRedo(string &description) const\n{\n    VAssert(_rootNode);\n    description.clear();\n\n    if (!_redoStack.size()) return (NULL);\n\n    const pair<string, XmlNode *> &p1 = _redoStack.back();\n\n    description = p1.first;\n    return (p1.second);\n}\n\nbool ParamsMgr::PMgrStateSave::Undo()\n{\n    VAssert(_rootNode);\n\n    if (!_undoStack.size()) return (false);\n\n    pair<string, XmlNode *> &p1 = _undoStack.back();\n\n    // Delete oldest elements if needed\n    //\n    cleanStack(_stackSize, _redoStack);\n\n    _redoStack.push_back(p1);\n\n    _undoStack.pop_back();\n\n    if (GetEnabled())\n        emitStateChange(\"Undo \" + p1.first);\n\n    return (true);\n}\n\nbool ParamsMgr::PMgrStateSave::Redo()\n{\n    VAssert(_rootNode);\n\n    if (!_redoStack.size()) return (false);\n\n    pair<string, XmlNode *> &p1 = _redoStack.back();\n\n    // Delete oldest elements if needed\n    //\n    cleanStack(_stackSize, _undoStack);\n\n    _undoStack.push_back(p1);\n\n    _redoStack.pop_back();\n\n    if (GetEnabled())\n        emitStateChange(\"Redo \" + p1.first);\n\n    return (true);\n}\n\nvoid ParamsMgr::PMgrStateSave::Clear()\n{\n    VAssert(_rootNode);\n\n    cleanStack(0, _undoStack);\n    cleanStack(0, _redoStack);\n//    while (_groups.size()) _groups.pop();\n}\n\nvoid ParamsMgr::PMgrStateSave::ManuallyAddCurrentStateToUndoStack(const string &note)\n{\n    // Delete oldest elements if needed\n    cleanStack(_stackSize, _undoStack);\n\n    // Clear redo stack\n    cleanStack(0, _redoStack);\n\n    assert(GetUndoEnabled());\n    _undoStack.push_back(make_pair(note, new XmlNode(*_rootNode)));\n}\n\n\nvoid ParamsMgr::PMgrStateSave::cleanStack(int maxN, std::deque<std::pair<string, XmlNode *>> &s)\n{\n    // Delete oldest elements if needed\n    //\n    while (s.size() > maxN) {\n        pair<string, XmlNode *> &p1 = s.front();\n\n        if (p1.second) { delete p1.second; }\n\n        s.pop_front();\n    }\n}\n\nvoid ParamsMgr::PMgrStateSave::emitStateChange(const string &reason)\n{\n    _stateChangeReasonDescription = reason;\n    // Trigger state change flags and CBs\n    //\n    for (int i = 0; i < _stateChangeFlags.size(); i++) { *(_stateChangeFlags[i]) = true; }\n    for (int i = 0; i < _stateChangeCBs.size(); i++) { _stateChangeCBs[i](); }\n}\n\nvoid ParamsMgr::PMgrStateSave::emitIntermediateStateChange(const string &reason)\n{\n    _stateChangeReasonDescription = reason;\n    for (auto func : _intermediateStateChangeCBs) func();\n}\n"
  },
  {
    "path": "lib/params/ParticleParams.cpp",
    "content": "#include <vapor/ParticleParams.h>\n#include <vapor/STLUtils.h>\n#include <string>\n#include <cassert>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n\nstatic RenParamsRegistrar<ParticleParams> registrar(ParticleParams::GetClassType());\n\nconst std::string ParticleParams::ShowDirectionTag = \"ShowDirectionTag\";\nconst std::string ParticleParams::DirectionScaleTag = \"DirectionScaleTag\";\nconst std::string ParticleParams::StrideTag = \"StrideTag\";\nconst std::string ParticleParams::RenderRadiusScalarTag = \"RenderRadiusScalarTag\";\nPARAMS_IMPL_TAG(ParticleParams, RenderRadiusVariableTag);\nPARAMS_IMPL_TAG(ParticleParams, RenderRadiusVariableStrengthTag);\nPARAMS_IMPL_TAG(ParticleParams, RecalculateRadiusBaseRequestTag);\nconst std::string ParticleParams::LightingEnabledTag = \"LightingEnabledTag\";\nconst std::string ParticleParams::RenderRadiusBaseTag = \"RenderRadiusBaseTag\";\nconst std::string ParticleParams::RenderLegacyTag = \"RenderLegacyTag\";\nconst std::string ParticleParams::PhongAmbientTag = \"PhongAmbientTag\";\nconst std::string ParticleParams::PhongDiffuseTag = \"PhongDiffuseTag\";\nconst std::string ParticleParams::PhongSpecularTag = \"PhongSpecularTag\";\nconst std::string ParticleParams::PhongShininessTag = \"PhongShininessTag\";\n\nParticleParams::ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, ParticleParams::GetClassType(), 3)\n{\n    SetDiagMsg(\"ParticleParams::ParticleParams() this=%p\", this);\n    _init();\n}\n\nParticleParams::ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType) : RenderParams(dataMgr, ssave, classType, 3)\n{\n    SetDiagMsg(\"ParticleParams::ParticleParams() this=%p\", this);\n    _init();\n}\n\nParticleParams::ParticleParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) {}\n\n\nParticleParams::~ParticleParams() { SetDiagMsg(\"ParticleParams::~ParticleParams() this=%p\", this); }\n\n// Set everything to default values\nvoid ParticleParams::_init()\n{\n    SetDiagMsg(\"ParticleParams::_init()\");\n\n    SetValueLong(ShowDirectionTag, \"\", false);\n    SetValueDouble(DirectionScaleTag, \"\", 1);\n    SetValueLong(StrideTag, \"\", 1);\n    SetValueDouble(RenderRadiusScalarTag, \"\", 8.);\n    SetValueDouble(RenderRadiusVariableStrengthTag, \"\", 1.);\n    SetValueDouble(RenderRadiusBaseTag, \"\", -1);\n    SetValueLong(RenderLegacyTag, \"\", false);\n    SetValueLong(LightingEnabledTag, \"\", true);\n    SetValueDouble(PhongAmbientTag, \"\", .4);\n    SetValueDouble(PhongDiffuseTag, \"\", .8);\n    SetValueDouble(PhongSpecularTag, \"\", 0.);\n    SetValueDouble(PhongShininessTag, \"\", 0.5);\n\n    RenderParams::SetDefaultVariables(3, true);\n}\n"
  },
  {
    "path": "lib/params/RayCasterParams.cpp",
    "content": "#include \"vapor/RayCasterParams.h\"\n\nusing namespace VAPoR;\n\nconst std::string RayCasterParams::_lightingTag = \"LightingTag\";\nconst std::string RayCasterParams::_lightingCoeffsTag = \"LightingCoeffTag\";\nconst std::string RayCasterParams::_castingModeTag = \"CastingModeTag\";\nconst std::string RayCasterParams::_sampleMultiplierTag = \"SampleMultiplierTag\";\n\nRayCasterParams::RayCasterParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, std::string classType) : RenderParams(dataManager, stateSave, classType, 3 /* max dim */)\n{\n    SetFieldVariableNames(vector<string>());\n    SetDiagMsg(\"RayCasterParams::RayCasterParams() this=%p\", this);\n}\n\n// Constructor\nRayCasterParams::RayCasterParams(DataMgr *dataManager, ParamsBase::StateSave *stateSave, XmlNode *node) : RenderParams(dataManager, stateSave, node, 3 /* max dim */)\n{\n    SetDiagMsg(\"RayCasterParams::RayCasterParams() this=%p\", this);\n}\n\n// Destructor\nRayCasterParams::~RayCasterParams() { SetDiagMsg(\"RayCasterParams::~RayCasterParams() this=%p\", this); }\n\nMapperFunction *RayCasterParams::GetMapperFunc() { return RenderParams::GetMapperFunc(GetVariableName()); }\n\nvoid RayCasterParams::SetLighting(bool lightingOn) { SetValueLong(_lightingTag, \"Apply lighting or not\", (long int)lightingOn); }\n\nbool RayCasterParams::GetLighting() const\n{\n    long l = GetValueLong(_lightingTag, 1);\n\n    return (bool)l;\n}\n\nstd::vector<double> RayCasterParams::GetLightingCoeffs() const\n{\n    std::vector<double> defaultVec(4);\n    defaultVec[0] = 0.2;\n    defaultVec[1] = 0.5;\n    defaultVec[2] = 0.25;\n    defaultVec[3] = 8.0;\n    return GetValueDoubleVec(_lightingCoeffsTag, defaultVec);\n}\n\nvoid RayCasterParams::SetLightingCoeffs(const std::vector<double> &coeffs) { SetValueDoubleVec(_lightingCoeffsTag, \"Coefficients for lighting effects\", coeffs); }\n\nlong RayCasterParams::GetCastingMode() const\n{\n    return GetValueLong(_castingModeTag, 0);    // 0 means it's not set by the user yet.\n}\n\nvoid RayCasterParams::SetCastingMode(long mode)\n{\n    if (mode == 1 || mode == 2)    // currently supported casting modes\n        SetValueLong(_castingModeTag, \"Which ray casting mode\", mode);\n    else    // put mode 1 here\n        SetValueLong(_castingModeTag, \"Which ray casting mode\", 1);\n}\n\nlong RayCasterParams::GetSampleRateMultiplier() const { return GetValueLong(_sampleMultiplierTag, 0); }\n\nvoid RayCasterParams::SetSampleRateMultiplier(long val)\n{\n    if (val >= 0 && val < 7)\n        SetValueLong(_sampleMultiplierTag, \"How to adjust the sample rate\", val);\n    else\n        SetValueLong(_sampleMultiplierTag, \"How to adjust the sample rate\", 0);\n}\n"
  },
  {
    "path": "lib/params/RenderParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2014\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tRenderParams.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJuly 2014\n//\n//\tDescription:\tImplements the RenderParams class.\n//\t\tThis is an abstract class for all the tabbed panel rendering params classes.\n//\t\tSupports functionality common to all the tabbed panel render params.\n//\n#include <iostream>\n#include <sstream>\n#include <string>\n#include <cstring>\n#include <string>\n#include <float.h>\n#include \"vapor/VAssert.h\"\n#include <vapor/RenderParams.h>\n#include <vapor/DataMgr.h>\n#include <vapor/DataMgrUtils.h>\n\nusing namespace VAPoR;\n\nconst string RenderParams::_EnabledTag = \"Enabled\";\nconst string RenderParams::_histoScaleTag = \"HistoScale\";\nconst string RenderParams::_editBoundsTag = \"EditBounds\";\nconst string RenderParams::_histoBoundsTag = \"HistoBounds\";\nconst string RenderParams::_cursorCoordsTag = \"CursorCoords\";\nconst string RenderParams::_heightVariableNameTag = \"HeightVariable\";\nconst string RenderParams::_colorMapVariableNameTag = \"ColorMapVariable\";\nconst string RenderParams::_xFieldVariableNameTag = \"FieldVariableName_X\";\nconst string RenderParams::_yFieldVariableNameTag = \"FieldVariableName_Y\";\nconst string RenderParams::_zFieldVariableNameTag = \"FieldVariableName_Z\";\nconst string RenderParams::_auxVariableNamesTag = \"AuxVariableNames\";\nconst string RenderParams::_distribVariableNamesTag = \"DistributionVariableNames\";\nconst string RenderParams::_variableNameTag = \"VariableName\";\nconst string RenderParams::_useSingleColorTag = \"UseSingleColor\";\nconst string RenderParams::_constantColorTag = \"ConstantColor\";\nconst string RenderParams::_constantOpacityTag = \"ConstantOpacity\";\nconst string RenderParams::CustomHistogramDataTag = \"CustomHistogramData\";\nconst string RenderParams::CustomHistogramRangeTag = \"CustomHistogramRange\";\nconst string RenderParams::_CompressionLevelTag = \"CompressionLevel\";\nconst string RenderParams::_RefinementLevelTag = \"RefinementLevel\";\nconst string RenderParams::_transferFunctionsTag = \"MapperFunctions\";\nconst string RenderParams::_stretchFactorsTag = \"StretchFactors\";\nconst string RenderParams::_currentTimestepTag = \"CurrentTimestep\";\nconst string RenderParams::XSlicePlaneOriginTag = \"XSlicePlaneOrigin\";\nconst string RenderParams::YSlicePlaneOriginTag = \"YSlicePlaneOrigin\";\nconst string RenderParams::ZSlicePlaneOriginTag = \"ZSlicePlaneOrigin\";\nconst string RenderParams::XSlicePlaneRotationTag = \"XSlicePlaneRotation\";\nconst string RenderParams::YSlicePlaneRotationTag = \"YSlicePlaneRotation\";\nconst string RenderParams::ZSlicePlaneRotationTag = \"ZSlicePlaneRotation\";\nconst string RenderParams::SampleRateTag = \"SampleRate\";\nconst string RenderParams::SliceOffsetTag = \"SliceOffsetTag\";\nconst string RenderParams::SlicePlaneNormalXTag = \"SlicePlaneNormalXTag\";\nconst string RenderParams::SlicePlaneNormalYTag = \"SlicePlaneNormalYTag\";\nconst string RenderParams::SlicePlaneNormalZTag = \"SlicePlaneNormalZTag\";\nconst string RenderParams::SlicePlaneOrientationModeTag = \"SlicePlaneOrientationModeTag\";\nconst string RenderParams::LightingEnabledTag = \"LightingEnabled\";\nconst string RenderParams::UserNameTag = \"UserNameTag\";\nconst string RenderParams::DrawInFrontTag = \"DrawInFrontTag\";\n\n#define REQUIRED_SAMPLE_SIZE 1000000\n\nnamespace {\nvector<string> string_replace(vector<string> v, string olds, string news)\n{\n    for (int i = 0; i < v.size(); i++) {\n        if (v[i] == olds) v[i] = news;\n    }\n    return (v);\n}\n\nstring string_replace(string s, string olds, string news)\n{\n    if (s == olds) s = news;\n    return (s);\n}\n\n};    // namespace\n\nvoid RenderParams::SetDefaultVariables(int dim = 3, bool secondaryColormapVariable = false)\n{\n    // Find the first variable in the data collection of\n    // the requested dimesion that exists and make it the default.\n    //\n    string varname;\n    size_t ts;\n    bool   ok = false;\n    for (int i = dim; i > 1; i--) {\n        if (ok = DataMgrUtils::GetFirstExistingVariable(_dataMgr, 0, 0, i, varname, ts)) break;\n    }\n    if (!ok) varname = \"\";\n    SetVariableName(varname);\n    SetColorMapVariableName(varname);\n\n    // Now set the rest of the variable name fields. It's not important\n    // that these exist or not\n    //\n    vector<string> varnames;\n    varnames = _dataMgr->GetDataVarNames(dim);\n\n    // Try to find U, V, and W vector variables\n    vector<string> fieldVarNames(3, \"\");\n    fieldVarNames[0] = _findVarStartingWithLetter(varnames, 'u');\n    fieldVarNames[1] = _findVarStartingWithLetter(varnames, 'v');\n    if (dim == 3) {\n        fieldVarNames[2] = _findVarStartingWithLetter(varnames, 'w');\n        SetHeightVariableName(\"\");\n    }\n\n    // If we can't find U or V, look for variables that correspond with the X, Y, and Z dimensions such as bx, by, and bz\n    if (fieldVarNames[0] == \"\" || fieldVarNames[1] == \"\") {\n        fieldVarNames[0] = _findVarEndingWithLetter(varnames, 'x');\n        fieldVarNames[1] = _findVarEndingWithLetter(varnames, 'y');\n        if (dim == 3) fieldVarNames[2] = _findVarEndingWithLetter(varnames, 'z');\n    }\n\n    SetFieldVariableNames(fieldVarNames);\n\n    string colorVar = varname;\n    if (secondaryColormapVariable) colorVar = _findVarStartingWithLetter(varnames, 't');\n\n    if (!colorVar.empty()) SetColorMapVariableName(colorVar);\n}\n\nvoid RenderParams::_init()\n{\n    SetEnabled(true);\n\n    SetDefaultVariables(_maxDim);\n\n    SetRefinementLevel(0);\n    SetCompressionLevel(0);\n    SetHistoStretch(1.0);\n\n    float rgb[] = {1.0, 1.0, 1.0};\n    SetConstantColor(rgb);\n    SetConstantOpacity(1.0);\n    SetDrawInFront(false);\n}\n\nint RenderParams::Initialize()\n{\n    if (_classInitialized) return (0);\n\n    //\n    // Initialize box with bounds of a single variable. First check\n    // variable returned by GetVariableName(). If not available,\n    // look for others\n    //\n    string varname = GetVariableName();\n    size_t ts = GetCurrentTimestep();\n    size_t tsInit = ts;\n    int    ndim = _maxDim;\n    bool   foundVar = false;\n    if (!varname.empty()) {\n        for (size_t ts = 0; ts < _dataMgr->GetNumTimeSteps() && !foundVar; ts++) {\n            if (!_dataMgr->VariableExists(ts, varname, 0, 0)) { foundVar = true; }\n        }\n    }\n\n    if (!foundVar) {\n        // Probably should have a _minDim here..\n        //\n        varname.clear();\n        for (; ndim > 0; ndim--) {\n            bool ok = DataMgrUtils::GetFirstExistingVariable(_dataMgr, 0, 0, ndim, varname, ts);\n            if (ok) {\n                foundVar = true;\n                if (_dataMgr->VariableExists(tsInit, varname, 0, 0)) {\n                    ts = tsInit;\n                    break;\n                }\n            }\n        }\n    }\n\n    if (!foundVar) return (0);\n\n    (void)InitBoxFromVariable(ts, varname);\n\n    _classInitialized = true;\n    return (0);\n}\n\n\nint RenderParams::ResetUserExtentsToDataExents(string var)\n{\n    if (var.empty())\n        var = GetVariableName();\n    \n    CoordType minExt, maxExt;\n    \n    int rc = _dataMgr->GetVariableExtents(GetCurrentTimestep(), var, 0, 0, minExt, maxExt);\n    if (rc < 0) return (-1);\n\n    VAssert(minExt.size() == maxExt.size() && (minExt.size() == 2 || minExt.size() == 3));\n\n    bool planar = _dataMgr->GetNumDimensions(var) == 2;\n    if (planar) {\n        _Box->SetOrientation(VAPoR::Box::XY);\n    } else {\n        _Box->SetOrientation(VAPoR::Box::XYZ);\n    }\n\n    _Box->SetExtents(minExt, maxExt);\n    _Box->SetPlanar(planar);\n\n    vector<double> origin(minExt.size());\n    for (int i = 0; i < minExt.size(); i++) { origin[i] = minExt[i] + (maxExt[i] - minExt[i]) * 0.5; }\n    _transform->SetOrigin(origin);\n    \n    return 0;\n}\n\n\nRenderParams::RenderParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, const string &classname, int maxdim) : ParamsBase(ssave, classname)\n{\n    _classInitialized = false;\n    _dataMgr = dataMgr;\n    _maxDim = maxdim;\n    _stride = 1;\n\n    // Initialize DataMgr dependent parameters\n    //\n    _init();\n\n    _TFs = new ParamsContainer(ssave, _transferFunctionsTag);\n    _TFs->SetParent(this);\n\n    _Box = new Box(ssave);\n    _Box->SetParent(this);\n\n    _Colorbar = new ColorbarPbase(ssave);\n    _Colorbar->SetParent(this);\n\n    _transform = new Transform(ssave);\n    _transform->SetParent(this);\n}\n\nRenderParams::RenderParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node, int maxdim) : ParamsBase(ssave, node)\n{\n    _classInitialized = true;\n    _dataMgr = dataMgr;\n    _maxDim = maxdim;\n    _stride = 1;\n\n    // Reconcile DataMgr dependent parameters\n    //\n\n    if (node->HasChild(_transferFunctionsTag)) {\n        _TFs = new ParamsContainer(ssave, node->GetChild(_transferFunctionsTag));\n\n    } else {\n        // Node doesn't contain a transfer function container\n        //\n        _TFs = new ParamsContainer(ssave, _transferFunctionsTag);\n        _TFs->SetParent(this);\n    }\n\n    if (node->HasChild(Box::GetClassType())) {\n        _Box = new Box(ssave, node->GetChild(Box::GetClassType()));\n    } else {\n        // Node doesn't contain a Box\n        //\n        _Box = new Box(ssave);\n        _Box->SetParent(this);\n    }\n\n    if (node->HasChild(ColorbarPbase::GetClassType())) {\n        _Colorbar = new ColorbarPbase(ssave, node->GetChild(ColorbarPbase::GetClassType()));\n    } else {\n        // Node doesn't contain a ColorbarPbase\n        //\n        _Colorbar = new ColorbarPbase(ssave);\n        _Colorbar->SetParent(this);\n    }\n\n    if (node->HasChild(Transform::GetClassType())) {\n        _transform = new Transform(ssave, node->GetChild(Transform::GetClassType()));\n    } else {\n        // Node doesn't contain a Transform\n        //\n        _transform = new Transform(ssave);\n        _transform->SetParent(this);\n    }\n}\n\nRenderParams::RenderParams(const RenderParams &rhs) : ParamsBase(rhs)\n{\n    _dataMgr = rhs._dataMgr;\n\n    _TFs = new ParamsContainer(*(rhs._TFs));\n    _Box = new Box(*(rhs._Box));\n    _Colorbar = new ColorbarPbase(*(rhs._Colorbar));\n    _transform = new Transform(*(rhs._transform));\n}\n\nRenderParams &RenderParams::operator=(const RenderParams &rhs)\n{\n    if (_TFs) delete _TFs;\n    if (_Box) delete _Box;\n    if (_Colorbar) delete _Colorbar;\n    if (_transform) delete _transform;\n\n    ParamsBase::operator=(rhs);\n\n    _dataMgr = rhs._dataMgr;\n\n    _TFs = new ParamsContainer(*(rhs._TFs));\n    _Box = new Box(*(rhs._Box));\n    _Colorbar = new ColorbarPbase(*(rhs._Colorbar));\n    _transform = new Transform(*(rhs._transform));\n\n    return (*this);\n}\n\nRenderParams::~RenderParams()\n{\n    if (_TFs) delete _TFs;\n    if (_Box) delete _Box;\n    if (_Colorbar) delete _Colorbar;\n    if (_transform) delete _transform;\n}\n\nvoid RenderParams::SetEnabled(bool val) { SetValueLong(_EnabledTag, \"enable/disable renderer\", val); }\n\nvoid RenderParams::SetVariableName(string varname)\n{\n    varname = string_replace(varname, \"<no-variable>\", \"NULL\");\n    varname = string_replace(varname, \"\", \"NULL\");\n\n    SetValueString(_variableNameTag, \"Specify variable name\", varname);\n}\n\nstring RenderParams::GetVariableName() const\n{\n    string varname = GetValueString(_variableNameTag, \"\");\n\n    varname = string_replace(varname, \"NULL\", \"\");\n    return (varname);\n}\n\nint RenderParams::GetCompressionLevel() const { return GetValueLong(_CompressionLevelTag, 0); }\n\nvoid RenderParams::SetCompressionLevel(int level) { SetValueLong(_CompressionLevelTag, \"Set compression level\", level); }\n\nvoid RenderParams::SetRefinementLevel(int level)\n{\n    if (level < 0) level = 0;\n    SetValueLong(_RefinementLevelTag, \"Set refinement level\", level);\n}\n\nint RenderParams::GetRefinementLevel() const { return (GetValueLong(_RefinementLevelTag, 0)); }\n\nvoid RenderParams::SetHistoStretch(float factor)\n{\n    if (factor < 0.0) factor = 0.0;\n    SetValueDouble(_histoScaleTag, \"Set histo stretch\", (double)factor);\n}\n\nfloat RenderParams::GetHistoStretch() const\n{\n    float factor = GetValueDouble(_histoScaleTag, (float)1.0);\n    if (factor < 0.0) factor = 0.0;\n    return (factor);\n}\n\nvoid RenderParams::SetColorbarPbase(ColorbarPbase *pb)\n{\n    if (_Colorbar) delete _Colorbar;\n\n    _Colorbar = new ColorbarPbase(*pb);\n    _Colorbar->SetParent(this);\n}\n\nvoid RenderParams::_calculateStride(string varName)\n{\n    if (varName.empty() || varName == \"NULL\") {\n        _stride = 1;\n        return;\n    }\n\n    std::vector<size_t> dimsAtLevel;\n    int                 ref = GetRefinementLevel();\n\n    // Yikes.  Error reporting is turned off, so ignore the return code\n    _dataMgr->GetDimLensAtLevel(varName, ref, dimsAtLevel, GetCurrentTimestep());\n\n    int size = 1;\n    for (int i = 0; i < dimsAtLevel.size(); i++) size *= dimsAtLevel[i];\n\n    _stride = 1;\n    if (size > REQUIRED_SAMPLE_SIZE) _stride = 1 + size / REQUIRED_SAMPLE_SIZE;\n}\n\nMapperFunction *RenderParams::GetMapperFunc(string varname)\n{\n    // This way we always return a valid MapperFunction\n    //\n    if (varname.empty()) { varname = \"NULL\"; }\n    MapperFunction *tfptr = dynamic_cast<MapperFunction *>(_TFs->GetParams(varname));\n\n    if (tfptr) { return (tfptr); }\n\n    // Disable state saving for Get function\n    //\n    bool enabled = _ssave->GetEnabled();\n    _ssave->SetEnabled(false);\n\n    MapperFunction tf(_ssave);\n\n    _calculateStride(varname);\n\n    size_t ts = 0;\n    int    level = 0;\n    int    lod = 0;\n    if (_dataMgr->VariableExists(ts, varname, level, lod)) {\n        CoordType minExt, maxExt;\n        _Box->GetExtents(minExt, maxExt);\n\n        vector<double> range;\n        bool           prev = EnableErrMsg(false);    // no error handling\n        int            rc = _dataMgr->GetDataRange(ts, varname, level, lod, minExt, maxExt, range);\n        if (rc < 0) { range = {0.0, 1.0}; }\n        EnableErrMsg(prev);\n        tf.setMinMaxMapValue(range[0], range[1]);\n    }\n\n    _TFs->Insert(&tf, varname);\n    tfptr = (MapperFunction *)_TFs->GetParams(varname);\n    VAssert(tfptr != NULL);\n\n    _ssave->SetEnabled(enabled);\n\n    return (tfptr);\n}\n\nvoid RenderParams::RemoveMapperFunc(string varname) { _TFs->Remove(varname); }\n\nvoid RenderParams::SetMapperFunc(string varname, MapperFunction *mf)\n{\n    if (_TFs->GetParams(varname)) { _TFs->Remove(varname); }\n\n    _TFs->Insert(mf, varname);\n}\n\nvoid RenderParams::SetCursorCoords(const float coords[2])\n{\n    vector<double> coordsv;\n    coordsv.push_back(coords[0]);\n    coordsv.push_back(coords[1]);\n    SetValueDoubleVec(_cursorCoordsTag, \"set cursor coords\", coordsv);\n}\n\nvoid RenderParams::GetCursorCoords(float coords[2]) const\n{\n    coords[0] = coords[1] = 2;\n    vector<double> defaultv(2, 0.0);\n\n    vector<double> coordsv = GetValueDoubleVec(_cursorCoordsTag, defaultv);\n}\n\nvector<string> RenderParams::GetFieldVariableNames() const\n{\n    //\tvector <string> defaultv(3, \"\");\n    vector<string> varnames(3);\n\n    //    varnames = GetValueStringVec(_fieldVariableNamesTag, defaultv);\n    varnames[0] = GetValueString(_xFieldVariableNameTag, \"\");\n    varnames[1] = GetValueString(_yFieldVariableNameTag, \"\");\n    varnames[2] = GetValueString(_zFieldVariableNameTag, \"\");\n    varnames = string_replace(varnames, \"NULL\", \"\");\n    for (int i = varnames.size(); i < 3; i++) varnames.push_back(\"\");\n\n    return (varnames);\n}\n\nvoid RenderParams::SetFieldVariableNames(vector<string> varnames)\n{\n    varnames = string_replace(varnames, \"<no-variable>\", \"NULL\");\n    varnames = string_replace(varnames, \"\", \"NULL\");\n    for (int i = varnames.size(); i < 3; i++) varnames.push_back(\"NULL\");\n\n    SetValueString(_xFieldVariableNameTag, \"\", varnames[0]);\n    SetValueString(_yFieldVariableNameTag, \"\", varnames[1]);\n    SetValueString(_zFieldVariableNameTag, \"\", varnames[2]);\n}\n\nstd::string RenderParams::GetXFieldVariableName() const\n{\n    std::vector<std::string> fieldVars = GetFieldVariableNames();\n    VAssert(fieldVars.size() == 3);\n    return fieldVars[0];\n}\n\nvoid RenderParams::SetXFieldVariableName(std::string varName)\n{\n    std::vector<std::string> fieldVars = GetFieldVariableNames();\n    VAssert(fieldVars.size() == 3);\n    fieldVars[0] = varName;\n    SetFieldVariableNames(fieldVars);\n}\n\nstd::string RenderParams::GetYFieldVariableName() const\n{\n    std::vector<std::string> fieldVars = GetFieldVariableNames();\n    VAssert(fieldVars.size() == 3);\n    return fieldVars[1];\n}\n\nvoid RenderParams::SetYFieldVariableName(std::string varName)\n{\n    std::vector<std::string> fieldVars = GetFieldVariableNames();\n    VAssert(fieldVars.size() == 3);\n    fieldVars[1] = varName;\n    SetFieldVariableNames(fieldVars);\n}\n\nstd::string RenderParams::GetZFieldVariableName() const\n{\n    std::vector<std::string> fieldVars = GetFieldVariableNames();\n    VAssert(fieldVars.size() == 3);\n    return fieldVars[2];\n}\n\nvoid RenderParams::SetZFieldVariableName(std::string varName)\n{\n    std::vector<std::string> fieldVars = GetFieldVariableNames();\n    VAssert(fieldVars.size() == 3);\n    fieldVars[2] = varName;\n    SetFieldVariableNames(fieldVars);\n}\n\nvector<string> RenderParams::GetAuxVariableNames() const\n{\n    std::vector<std::string> varnames = GetValueStringVec(_auxVariableNamesTag);\n    varnames = string_replace(varnames, \"NULL\", \"\");\n    return (varnames);\n}\n\nvoid RenderParams::SetAuxVariableNames(std::vector<std::string> varnames)\n{\n    varnames = string_replace(varnames, \"<no-variable>\", \"NULL\");\n    varnames = string_replace(varnames, \"\", \"NULL\");\n    SetValueStringVec(_auxVariableNamesTag, \"Specify auxiliary varnames\", varnames);\n}\n\nstring RenderParams::GetFirstVariableName() const\n{\n    string str = GetVariableName();\n    if (str.length()) return str;    // scalar\n    vector<string> strvec = GetFieldVariableNames();\n    for (int i = 0; i < strvec.size(); i++) {\n        if (strvec[i] != \"\") return strvec[i];    // vector\n    }\n    str = GetColorMapVariableName();\n    if (!str.empty()) return str;\n    str = GetHeightVariableName();\n    if (str.length()) return str;    // height\n    return \"\";                       // none\n}\n\nstring RenderParams::GetHeightVariableName() const\n{\n    string varname = GetValueString(_heightVariableNameTag, \"\");\n\n    varname = string_replace(varname, \"NULL\", \"\");\n\n    return (varname);\n}\n\nvoid RenderParams::SetHeightVariableName(string varname)\n{\n    varname = string_replace(varname, \"<no-variable>\", \"NULL\");\n    varname = string_replace(varname, \"\", \"NULL\");\n\n    SetValueString(_heightVariableNameTag, \"Set height variable name\", varname);\n    //\tsetAllBypass(false);\n}\n\nstring RenderParams::GetColorMapVariableName() const\n{\n    string varname = GetValueString(_colorMapVariableNameTag, \"\");\n\n    varname = string_replace(varname, \"NULL\", \"\");\n\n    return (varname);\n}\n\nbool RenderParams::UseSingleColor() const { return GetValueLong(_useSingleColorTag, GetUseSingleColorDefault()); }\n\nvoid RenderParams::SetUseSingleColor(bool val) { SetValueLong(_useSingleColorTag, \"enable/disable use single color\", (long)val); }\n\nvoid RenderParams::SetColorMapVariableName(string varname)\n{\n    varname = string_replace(varname, \"<no-variable>\", \"NULL\");\n    varname = string_replace(varname, \"\", \"NULL\");\n\n    SetValueString(_colorMapVariableNameTag, \"Set color map variable name\", varname);\n}\n\nvoid RenderParams::SetConstantColor(const float rgb[3])\n{\n    vector<double> rgbv;\n    for (int i = 0; i < 3; i++) {\n        float v = rgb[i];\n        if (v < 0.0) v = 0.0;\n        if (v > 1.0) v = 1.0;\n        rgbv.push_back(v);\n    }\n    SetValueDoubleVec(_constantColorTag, \"Specify constant color in RGB\", rgbv);\n}\n\nvoid RenderParams::SetConstantColor(vector<float> rgb)\n{\n    rgb.resize(3, 0);\n    SetConstantColor(rgb.data());\n}\n\nvoid RenderParams::GetConstantColor(float rgb[3]) const\n{\n    vector<double> defaultv(3, 1.0);\n    vector<double> rgbv = GetValueDoubleVec(_constantColorTag, defaultv);\n\n    for (int i = 0; i < rgbv.size() && i < 3; i++) {\n        float v = rgbv[i];\n        if (v < 0.0) v = 0.0;\n        if (v > 1.0) v = 1.0;\n        rgb[i] = rgbv[i];\n    }\n};\n\nvoid RenderParams::SetConstantOpacity(float o)\n{\n    if (o < 0.0) o = 0.0;\n    if (o > 1.0) o = 1.0;\n\n    SetValueDouble(_constantOpacityTag, \"Specify constant opacity\", o);\n}\n\nfloat RenderParams::GetConstantOpacity() const\n{\n    vector<double> defaultv(1, 1.0);\n    vector<double> vec = GetValueDoubleVec(_constantOpacityTag, defaultv);\n\n    float o = 1.0;\n    if (vec.size()) o = vec[0];\n\n    if (o < 0.0) o = 0.0;\n    if (o > 1.0) o = 1.0;\n\n    return (o);\n}\n\nstring RenderParams::_findVarStartingWithLetter(vector<string> searchVars, char letter)\n{\n    for (auto &element : searchVars) {\n        if (element[0] == letter || element[0] == toupper(letter)) { return element; }\n    }\n    return \"\";\n}\n\nstring RenderParams::_findVarEndingWithLetter(vector<string> searchVars, char letter)\n{\n    for (auto &element : searchVars) {\n        int last = element.size()-1;\n        if (element[last] == letter || element[last] == toupper(letter)) { return element; }\n    }\n    return \"\";\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RenParamsFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nRenderParams *RenParamsFactory::CreateInstance(string className, DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node)\n{\n    RenderParams *instance = NULL;\n\n    // find className in the registry and call factory method.\n    //\n    auto it = _factoryFunctionRegistry.find(className);\n    if (it != _factoryFunctionRegistry.end()) instance = it->second(dataMgr, ssave, node);\n\n    if (instance != NULL)\n        return instance;\n    else\n        return NULL;\n}\n\nvector<string> RenParamsFactory::GetFactoryNames() const\n{\n    vector<string>                                                                                       names;\n    map<string, function<RenderParams *(DataMgr *, ParamsBase::StateSave *, XmlNode *)>>::const_iterator itr;\n\n    for (itr = _factoryFunctionRegistry.begin(); itr != _factoryFunctionRegistry.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RenParamsContainer Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nRenParamsContainer::RenParamsContainer(DataMgr *dataMgr, ParamsBase::StateSave *ssave, const string &name)\n{\n    VAssert(dataMgr != NULL);\n    VAssert(ssave != NULL);\n\n    _dataMgr = dataMgr;\n    _ssave = ssave;\n    _separator = NULL;\n    _elements.clear();\n\n    _separator = new ParamsSeparator(ssave, name);\n}\n\nRenParamsContainer::RenParamsContainer(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node)\n{\n    VAssert(dataMgr != NULL);\n    VAssert(ssave != NULL);\n    VAssert(node != NULL);\n\n    _dataMgr = dataMgr;\n    _ssave = ssave;\n    _separator = new ParamsSeparator(ssave, node);\n    _elements.clear();\n\n    for (int i = 0; i < node->GetNumChildren(); i++) {\n        XmlNode *eleNameNode = node->GetChild(i);\n        if (!eleNameNode->HasChild(0)) continue;    // bad node\n\n        XmlNode *eleNode = eleNameNode->GetChild(0);\n\n        string eleName = eleNameNode->GetTag();\n        string classname = eleNode->GetTag();\n\n        RenderParams *rParams = RenParamsFactory::Instance()->CreateInstance(classname, dataMgr, ssave, eleNode);\n        if (rParams == NULL) {\n            SetDiagMsg(\"RenParamsContainer::RenParamsContainer() unrecognized class: %s\", classname.c_str());\n\n            continue;\n        }\n        _elements[eleName] = rParams;\n    }\n}\n\nRenParamsContainer::RenParamsContainer(const RenParamsContainer &rhs)\n{\n    _dataMgr = rhs._dataMgr;\n    _ssave = rhs._ssave;\n    _separator = NULL;\n    _elements.clear();\n\n    _separator = new ParamsSeparator(*(rhs._separator));\n    _separator->SetParent(NULL);\n\n    vector<string> names = rhs.GetNames();\n    for (int i = 0; i < names.size(); i++) {\n        // Make copy of RenderParams\n        //\n        RenderParams *rhspb = rhs.GetParams(names[i]);\n        XmlNode *     node = new XmlNode(*(rhspb->GetNode()));\n\n        string        classname = rhspb->GetName();\n        RenderParams *mypb = RenParamsFactory::Instance()->CreateInstance(classname, _dataMgr, _ssave, node);\n        mypb->SetParent(_separator);\n\n        _elements[names[i]] = mypb;\n    }\n}\n\nRenParamsContainer &RenParamsContainer::operator=(const RenParamsContainer &rhs)\n{\n    VAssert(_separator);\n\n    vector<string> mynames = GetNames();\n    for (int i = 0; i < mynames.size(); i++) { Remove(mynames[i]); }\n    _elements.clear();\n\n    _dataMgr = rhs._dataMgr;\n    _ssave = rhs._ssave;\n    _separator = rhs._separator;\n\n    vector<string> names = rhs.GetNames();\n    for (int i = 0; i < names.size(); i++) {\n        XmlNode *eleNameNode = _separator->GetNode()->GetChild(names[i]);\n        VAssert(eleNameNode);\n\n        ParamsSeparator mySep(_ssave, eleNameNode);\n\n        XmlNode *eleNode = eleNameNode->GetChild(0);\n\n        string eleName = eleNameNode->GetTag();\n        string classname = eleNode->GetTag();\n\n        RenderParams *mypb = RenParamsFactory::Instance()->CreateInstance(classname, _dataMgr, _ssave, eleNode);\n        mypb->SetParent(&mySep);\n\n        _elements[names[i]] = mypb;\n    }\n\n    return (*this);\n}\n\nRenParamsContainer::~RenParamsContainer()\n{\n    map<string, RenderParams *>::iterator itr;\n    for (itr = _elements.begin(); itr != _elements.end(); ++itr) {\n        if (itr->second) delete itr->second;\n    }\n\n    if (_separator) delete _separator;\n}\n\nRenderParams *RenParamsContainer::Insert(const RenderParams *pb, string name)\n{\n    VAssert(pb != NULL);\n\n    if (name.empty()) { name = \"NULL\"; }\n\n    map<string, RenderParams *>::iterator itr = _elements.find(name);\n    if (itr != _elements.end()) { delete itr->second; }\n\n    // Create a separator node\n    //\n    ParamsSeparator mySep(_ssave, name);\n    mySep.SetParent(_separator);\n\n    // Create element name node\n    //\n    string        classname = pb->GetName();\n    XmlNode *     node = new XmlNode(*(pb->GetNode()));\n    RenderParams *mypb = RenParamsFactory::Instance()->CreateInstance(classname, _dataMgr, _ssave, node);\n    VAssert(mypb != NULL);\n    mypb->SetParent(&mySep);\n\n    _elements[name] = mypb;\n\n    return (mypb);\n}\n\nRenderParams *RenParamsContainer::Create(string className, string name)\n{\n    VAssert(!className.empty());\n    VAssert(!name.empty());\n\n    map<string, RenderParams *>::iterator itr = _elements.find(name);\n    if (itr != _elements.end()) { delete itr->second; }\n\n    // Create a separator node\n    //\n    ParamsSeparator mySep(_ssave, name);\n    mySep.SetParent(_separator);\n\n    // Create the desired class\n    //\n    RenderParams *mypb = RenParamsFactory::Instance()->CreateInstance(className, _dataMgr, _ssave, NULL);\n    VAssert(mypb != NULL);\n\n    mypb->SetParent(&mySep);\n\n    _elements[name] = mypb;\n\n    return (mypb);\n}\n\nvoid RenParamsContainer::Remove(string name)\n{\n    map<string, RenderParams *>::iterator itr = _elements.find(name);\n    if (itr == _elements.end()) return;\n\n    RenderParams *mypb = itr->second;\n\n    // Set parent to root so  Xml representation will be deleted\n    //\n    mypb->SetParent(NULL);\n    delete mypb;\n\n    _elements.erase(itr);\n}\n\nRenderParams *RenParamsContainer::GetParams(string name) const\n{\n    if (name.empty()) { name = \"NULL\"; }\n\n    map<string, RenderParams *>::const_iterator itr = _elements.find(name);\n    if (itr != _elements.end()) return (itr->second);\n\n    return (NULL);\n}\n\nvector<string> RenParamsContainer::GetNames() const\n{\n    map<string, RenderParams *>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _elements.begin(); itr != _elements.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nbool RenderParams::GetOrientable() const { return false; }\n\nvector<double> RenderParams::GetSlicePlaneRotation() const\n{\n    vector<double> v;\n    v.push_back(GetValueDouble(XSlicePlaneRotationTag, 0));\n    v.push_back(GetValueDouble(YSlicePlaneRotationTag, 0));\n    v.push_back(GetValueDouble(ZSlicePlaneRotationTag, 0));\n    return v;\n}\n\nvector<double> RenderParams::GetSlicePlaneOrigin() const\n{\n    vector<double> v;\n    v.push_back(GetXSlicePlaneOrigin());\n    v.push_back(GetYSlicePlaneOrigin());\n    v.push_back(GetZSlicePlaneOrigin());\n    return v;\n}\n\nvector<double> RenderParams::GetSlicePlaneNormal() const\n{\n    vector<double> v;\n    v.push_back(GetValueDouble(SlicePlaneNormalXTag, 0));\n    v.push_back(GetValueDouble(SlicePlaneNormalYTag, 0));\n    v.push_back(GetValueDouble(SlicePlaneNormalZTag, 1));\n\n    float l = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);\n    if (abs(l) < FLT_EPSILON) l = 1;\n    v[0] /= l;\n    v[1] /= l;\n    v[2] /= l;\n\n    return v;\n}\n\nvoid RenderParams::SetXSlicePlaneOrigin(double xOrigin) { SetValueDouble(XSlicePlaneOriginTag, \"Set origin of plane on X axis\", xOrigin); }\n\nvoid RenderParams::SetYSlicePlaneOrigin(double yOrigin) { SetValueDouble(YSlicePlaneOriginTag, \"Set origin of plane on Y axis\", yOrigin); }\n\nvoid RenderParams::SetZSlicePlaneOrigin(double zOrigin) { SetValueDouble(ZSlicePlaneOriginTag, \"Set origin of plane on Z axis\", zOrigin); }\n\ndouble RenderParams::GetXSlicePlaneOrigin() const\n{\n    VAPoR::CoordType min, max;\n    GetBox()->GetExtents(min, max);\n    double defaultVal = (min[0] + max[0]) / 2.;\n    return GetValueDouble(XSlicePlaneOriginTag, defaultVal);\n}\n\ndouble RenderParams::GetYSlicePlaneOrigin() const\n{\n    VAPoR::CoordType min, max;\n    GetBox()->GetExtents(min, max);\n    double defaultVal = (min[1] + max[1]) / 2.;\n    return GetValueDouble(YSlicePlaneOriginTag, defaultVal);\n}\n\ndouble RenderParams::GetZSlicePlaneOrigin() const\n{\n    VAPoR::CoordType min, max;\n    GetBox()->GetExtents(min, max);\n    double defaultVal = (min[2] + max[2]) / 2.;\n    return GetValueDouble(ZSlicePlaneOriginTag, defaultVal);\n}\n\nvoid RenderParams::SetDrawInFront(bool drawOnTop) {\n    return SetValueLong(DrawInFrontTag, \"Set renderer whether to draw on top (no depth testing)\", drawOnTop);\n}\n\nbool RenderParams::GetDrawInFront() const {\n    return GetValueLong(DrawInFrontTag, 0);\n}\n\nbool RenderParams::InitBoxFromVariable(size_t ts, string varName)\n{\n    bool enabled = _ssave->GetEnabled();\n    _ssave->SetEnabled(false);\n\n    CoordType minExt, maxExt;\n    int       rc = _dataMgr->GetVariableExtents(ts, varName, 0, 0, minExt, maxExt);\n    if (rc < 0) {\n        _ssave->SetEnabled(enabled);\n        return (false);\n    }\n    _ssave->SetEnabled(enabled);\n\n    // Configure box as planar or volumetric.\n    //\n    // N.B.Not handling case where ndim == 1!!!\n    //\n    size_t ndim = _dataMgr->GetVarTopologyDim(varName);\n    bool   planar = ndim == 2;\n    if (planar) {\n        _Box->SetOrientation(VAPoR::Box::XY);\n    } else {\n        _Box->SetOrientation(VAPoR::Box::XYZ);\n    }\n\n    vector<double> minExtVec = {minExt[0], minExt[1], minExt[2]};\n    vector<double> maxExtVec = {maxExt[0], maxExt[1], maxExt[2]};\n    _Box->SetExtents(minExtVec, maxExtVec);\n    _Box->SetPlanar(planar);\n\n    vector<double> origin(minExt.size());\n    for (int i = 0; i < minExt.size(); i++) { origin[i] = minExt[i] + (maxExt[i] - minExt[i]) * 0.5; }\n\n    if (planar) {\n        bool ok = DataMgrUtils::GetFirstExistingVariable(_dataMgr, 0, 0, 3, varName, ts);\n        if (ok) {\n            CoordType minExt, maxExt;\n            int rc = _dataMgr->GetVariableExtents(ts, varName, 0, 0, minExt, maxExt);\n            if (rc == 0) {\n                origin[2] = minExt[2] + (maxExt[2] - minExt[2]) * 0.5;\n            }\n        }\n    }\n\n    _transform->SetOrigin(origin);\n\n    SetValueDouble(XSlicePlaneOriginTag, \"\", origin[0]);\n    SetValueDouble(YSlicePlaneOriginTag, \"\", origin[1]);\n    SetValueDouble(ZSlicePlaneOriginTag, \"\", origin[2]);\n    SetValueDouble(SampleRateTag, \"\", 200);\n    SetValueDouble(SlicePlaneNormalZTag, \"\", 0);\n    SetValueDouble(SlicePlaneNormalYTag, \"\", 0);\n    SetValueDouble(SlicePlaneNormalZTag, \"\", 1);\n    SetValueLong(SlicePlaneOrientationModeTag, \"\", (int)SlicePlaneOrientationMode::Rotation);\n\n    return (true);\n}\n"
  },
  {
    "path": "lib/params/SettingsParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2015\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tSettingsParams.cpp\n//\n//\tAuthor: Scott Pearse\n//\t\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune 2015\n//\n//\tDescription:\tImplements the SettingsParams class.\n//\t\tThis class supports parameters associted with the\n//\t\tinitial VAPOR settings settings\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n#include <ostream>\n#include <fstream>\n#include <vector>\n#include <vapor/ResourcePath.h>\n#include <vapor/FileUtils.h>\n\n#include <vapor/SettingsParams.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nconst string SettingsParams::_classType = \"SettingsParams\";\n\nconst string SettingsParams::_shortName = \"Settings\";\nconst string SettingsParams::_cacheMBTag = \"CacheMBs\";\nconst string SettingsParams::_numThreadsTag = \"NumThreads\";\nconst string SettingsParams::_texSizeTag = \"TexSize\";\nconst string SettingsParams::_texSizeEnableTag = \"TexSizeEnabled\";\nconst string SettingsParams::_sessionDirTag = \"SessionDir\";\nconst string SettingsParams::_defaultSessionDirTag = \"SessionDir\";\nconst string SettingsParams::_metadataDirTag = \"MetadataDir\";\nconst string SettingsParams::_defaultMetadataDirTag = \"MetadataDir\";\nconst string SettingsParams::_tfDirTag = \"TFDir\";\nconst string SettingsParams::_defaultTfDirTag = \"TFDir\";\nconst string SettingsParams::_flowDirTag = \"FlowDir\";\nconst string SettingsParams::_defaultFlowDirTag = \"FlowDir\";\nconst string SettingsParams::_pythonDirTag = \"PythonDir\";\nconst string SettingsParams::_defaultPythonDirTag = \"PythonDir\";\nconst string SettingsParams::_currentPrefsPathTag = \"CurrentPrefsPath\";\nconst string SettingsParams::_fidelityDefault2DTag = \"Fidelity2DDefault\";\nconst string SettingsParams::_fidelityDefault3DTag = \"Fidelity3DDefault\";\nconst string SettingsParams::_autoStretchTag = \"AutoStretch\";\nconst string SettingsParams::_jpegQualityTag = \"JpegImageQuality\";\nconst string SettingsParams::_changesPerAutoSaveTag = \"ChangesPerAutoSave\";\nconst string SettingsParams::_autoSaveFileLocationTag = \"AutoSaveFileLocation\";\nconst string SettingsParams::_defaultAutoSaveFileTag = \"DefaultAutoSaveFile\";\nconst string SettingsParams::_sessionAutoSaveEnabledTag = \"AutoSaveEnabled\";\nconst string SettingsParams::_fontFileTag = \"FontFile\";\nconst string SettingsParams::_fontSizeTag = \"FontSize\";\nconst string SettingsParams::_dontShowIntelDriverWarningTag = \"DontShowIntelDriverWarning\";\nconst string SettingsParams::_settingsNeedsWriteTag = \"SettingsNeedsWrite\";\n\nconst string SettingsParams::UseAllCoresTag = \"UseAllCoresTag\";\nconst string SettingsParams::AutoCheckForUpdatesTag = \"AutoCheckForUpdatesTag\";\nconst string SettingsParams::AutoCheckForNoticesTag = \"AutoCheckForNoticesTag\";\nconst string SettingsParams::CasperVGLCheck = \"CasperVGLCheck\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<SettingsParams> registrar(SettingsParams::GetClassType());\n\nnamespace {\nstring       SettingsFile = \".vapor3_settings\";\nconst size_t defaultCacheSize = 0;\n}    // namespace\n\nSettingsParams::SettingsParams(ParamsBase::StateSave *ssave, bool loadFromFile) : ParamsBase(ssave, _classType)\n{\n    _settingsPath = FileUtils::JoinPaths({FileUtils::HomeDir(), SettingsFile});\n\n    // Try to get settings params from .settings file\n    //\n    if (loadFromFile) {\n        bool ok = LoadFromSettingsFile();\n        if (ok) return;\n    }\n\n    Init();\n}\n\nSettingsParams::SettingsParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    _settingsPath = FileUtils::JoinPaths({FileUtils::HomeDir(), SettingsFile});\n\n    // If node isn't tagged correctly we correct the tag and reinitialize\n    // from scratch;\n    //\n    if (node->GetTag() != SettingsParams::GetClassType()) {\n        node->SetTag(SettingsParams::GetClassType());\n\n        // Try to get settings params from .settings file\n        //\n        bool ok = LoadFromSettingsFile();\n        if (ok)\n            return;\n        else\n            Init();\n    }\n}\n\nSettingsParams::SettingsParams(const SettingsParams &rhs) : ParamsBase(new ParamsBase::StateSave, _classType)\n{\n    _settingsPath = FileUtils::JoinPaths({FileUtils::HomeDir(), SettingsFile});\n    Init();\n}\n\nSettingsParams &SettingsParams::operator=(const SettingsParams &rhs)\n{\n    ParamsBase::operator=(rhs);\n\n    _settingsPath = FileUtils::JoinPaths({FileUtils::HomeDir(), SettingsFile});\n\n    return (*this);\n}\n\nvoid SettingsParams::Reinit() { Init(); }\n\nSettingsParams::~SettingsParams() {}\n\nvoid SettingsParams::_swapTildeWithHome(std::string &file) const\n{\n    size_t pos = 0;\n    while ((pos = file.find(\"~\", pos)) != std::string::npos) {\n        file.replace(pos, 1, FileUtils::HomeDir());\n        pos += FileUtils::HomeDir().length();\n    }\n}\n\nlong SettingsParams::GetCacheMB() const\n{\n    long val = GetValueLong(_cacheMBTag, 0);\n    if (val < 0) val = defaultCacheSize;\n\n    return (val);\n}\n\nvoid SettingsParams::SetCacheMB(long val)\n{\n    if (val < 0) val = defaultCacheSize;\n\n    SetValueLong(_cacheMBTag, \"Set cache size\", val);\n}\n\nlong SettingsParams::GetTextureSize() const\n{\n    long val = GetValueLong(_texSizeTag, 0);\n    if (val < 0) val = 0;\n    return (val);\n}\n\nvoid SettingsParams::SetTextureSize(long val)\n{\n    if (val < 0) val = 0;\n    SetValueLong(_texSizeTag, \"Set graphic tex size\", val);\n}\n\nvoid SettingsParams::SetTexSizeEnable(bool val) { SetValueLong(_texSizeEnableTag, \"toggle enable texture size\", (long)val); }\n\nbool SettingsParams::GetTexSizeEnable() const { return (0 != GetValueLong(_texSizeEnableTag, (long)0)); }\n\nbool SettingsParams::GetAutoStretchEnabled() const { return (0 != GetValueLong(_autoStretchTag, (long)true)); }\n\nvoid SettingsParams::SetAutoStretchEnabled(bool val) { SetValueLong(_autoStretchTag, \"Enable Auto Stretch\", val); }\n\nint SettingsParams::GetJpegQuality() const\n{\n    int quality = (int)GetValueDouble(_jpegQualityTag, 100.f);\n    return quality;\n}\n\nvoid SettingsParams::SetJpegQuality(int quality)\n{\n    string description = \"Specify the quality of JPEG screen captures\";\n    SetValueDouble(_jpegQualityTag, description, quality);\n}\n\nbool SettingsParams::GetSessionAutoSaveEnabled() const\n{\n    double enabled = GetValueLong(_sessionAutoSaveEnabledTag, 1);\n    if (enabled > 0)\n        return true;\n    else\n        return false;\n}\n\nvoid SettingsParams::SetSessionAutoSaveEnabled(bool enabled)\n{\n    string description = \"Enable/disable auto save of session files\";\n    SetValueLong(_sessionAutoSaveEnabledTag, description, (long)enabled);\n}\n\nint SettingsParams::GetChangesPerAutoSave() const\n{\n    int changes = (int)GetValueLong(_changesPerAutoSaveTag, 5);\n    return changes;\n}\n\nvoid SettingsParams::SetChangesPerAutoSave(int count)\n{\n    if (count < 0) count = 5;\n    string description = \"User changes before auto saving session file\";\n    SetValueLong(_changesPerAutoSaveTag, description, count);\n}\n\nstring SettingsParams::GetAutoSaveSessionFile() const\n{\n    string autoSaveDir = FileUtils::HomeDir();\n    string defaultFile = autoSaveDir + \"/VaporAutoSave.vs3\";\n\n    string file = GetValueString(_autoSaveFileLocationTag, defaultFile);\n\n    _swapTildeWithHome(file);\n\n    return file;\n}\n\nvoid SettingsParams::SetAutoSaveSessionFile(string file)\n{\n    string description = \"Session auto-save file location\";\n    SetValueString(_autoSaveFileLocationTag, description, file);\n}\n\nstring SettingsParams::GetSessionDir() const\n{\n    string defaultDir = GetDefaultSessionDir();\n    string dir = GetValueString(_sessionDirTag, defaultDir);\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetSessionDir(string name) { SetValueString(_sessionDirTag, \"Set session directory\", name); }\n\nstring SettingsParams::GetDefaultSessionDir() const\n{\n    string dir = GetValueString(_defaultSessionDirTag, string(\".\"));\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetDefaultAutoSaveFile(string autoSaveFile)\n{\n    string description = \"Set default auto-save session directory\";\n    SetValueString(_defaultAutoSaveFileTag, description, autoSaveFile);\n}\n\nvoid SettingsParams::SetDefaultSessionDir(string name)\n{\n    string description = \"Set default session directory\";\n    SetValueString(_defaultSessionDirTag, description, name);\n}\n\nstring SettingsParams::GetMetadataDir() const\n{\n    string defaultDir = GetDefaultMetadataDir();\n    string dir = GetValueString(_metadataDirTag, defaultDir);\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetMetadataDir(string dir) { SetValueString(_metadataDirTag, \"set metadata directory\", dir); }\n\nstring SettingsParams::GetDefaultMetadataDir() const\n{\n    string dir = GetValueString(_defaultMetadataDirTag, string(\".\"));\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetDefaultMetadataDir(string dir)\n{\n    string description = \"set default metadata directory\";\n    SetValueString(_defaultMetadataDirTag, description, dir);\n}\n\nstring SettingsParams::GetTFDir() const\n{\n    string defaultDir = GetDefaultTFDir();\n    string dir = GetValueString(_tfDirTag, defaultDir);\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetTFDir(string dir) { SetValueString(_tfDirTag, \"set trans function directory\", dir); }\n\nstring SettingsParams::GetDefaultTFDir() const\n{\n    string dir = GetValueString(_defaultTfDirTag, string(\"\"));\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetDefaultTFDir(string dir)\n{\n    string description = \"set default trans function directory\";\n    SetValueString(_defaultTfDirTag, description, dir);\n}\n\nstring SettingsParams::GetFlowDir() const\n{\n    string defaultDir = GetDefaultFlowDir();\n    string dir = GetValueString(_flowDirTag, defaultDir);\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetFlowDir(string dir) { SetValueString(_flowDirTag, \"set flow save directory\", dir); }\n\nstring SettingsParams::GetDefaultFlowDir() const\n{\n    string dir = GetValueString(_defaultFlowDirTag, string(\".\"));\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetDefaultFlowDir(string dir) { SetValueString(_defaultFlowDirTag, \"set default flow save directory\", dir); }\n\nstring SettingsParams::GetPythonDir() const\n{\n    string defaultDir = GetDefaultPythonDir();\n    string dir = GetValueString(_pythonDirTag, defaultDir);\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetPythonDir(string dir) { SetValueString(_pythonDirTag, \"set python directory\", dir); }\n\nstring SettingsParams::GetDefaultPythonDir() const\n{\n    string dir = GetValueString(_defaultPythonDirTag, string(\".\"));\n    _swapTildeWithHome(dir);\n    return (dir);\n}\n\nvoid SettingsParams::SetDefaultPythonDir(string dir) { SetValueString(_defaultPythonDirTag, \"set default python directory\", dir); }\n\nstring SettingsParams::GetCurrentPrefsPath() const\n{\n    string defaultv = \"/tmp/.vapor3_prefs\";\n    return GetValueString(_currentPrefsPathTag, defaultv);\n}\n\nvoid SettingsParams::SetCurrentPrefsPath(string pth) { SetValueString(_currentPrefsPathTag, \"set current preference path\", pth); }\n\nint SettingsParams::GetNumThreads() const\n{\n    if (GetValueLong(UseAllCoresTag, true)) { return 0; }\n    long val = GetValueLong(_numThreadsTag, 0);\n    val = val >= 0 ? val : 0;\n    return ((int)val);\n}\n\nvoid SettingsParams::SetNumThreads(int val) { SetValueLong(_numThreadsTag, \"Number of execution threads\", val); }\n\nint SettingsParams::GetFontSize() const { return 24; }\n\nvoid SettingsParams::SetFontSize(int size) {}\n\nstring SettingsParams::GetFontFile() const { return \"\"; }\n\nvoid SettingsParams::SetFontFile(string file) {}\n\nbool SettingsParams::GetDontShowIntelDriverWarning() const { return GetValueLong(_dontShowIntelDriverWarningTag, false); }\n\nvoid SettingsParams::SetDontShowIntelDriverWarning(bool b) { SetValueLong(_dontShowIntelDriverWarningTag, \"Hide Intel driver warning\", b); }\n\nvoid SettingsParams::SetFidelityDefault3D(long lodDef, long refDef)\n{\n    vector<long> val;\n    val.push_back(lodDef);\n    val.push_back(refDef);\n    SetValueLongVec(_fidelityDefault3DTag, \"Set fidelity 3D default\", val);\n}\n\nvoid SettingsParams::SetFidelityDefault2D(long lodDef, long refDef)\n{\n    vector<long> val;\n    val.push_back(lodDef);\n    val.push_back(refDef);\n    SetValueLongVec(_fidelityDefault2DTag, \"Set fidelity 2D default\", val);\n}\n\nvoid SettingsParams::SetAutoCheckForUpdates(bool b) { SetValueLong(AutoCheckForUpdatesTag, \"\", b); }\nbool SettingsParams::GetAutoCheckForUpdates() const { return GetValueLong(AutoCheckForUpdatesTag, true); }\nvoid SettingsParams::SetAutoCheckForNotices(bool b) { SetValueLong(AutoCheckForNoticesTag, \"\", b); }\nbool SettingsParams::GetAutoCheckForNotices() const { return GetValueLong(AutoCheckForNoticesTag, true); }\nvoid SettingsParams::SetCasperCheckForVGL(bool b) { SetValueLong(CasperVGLCheck, \"\", b); }\nbool SettingsParams::GetCasperCheckForVGL() const { return GetValueLong(CasperVGLCheck, true); }\n\nbool SettingsParams::LoadFromSettingsFile()\n{\n    XmlNode *node = GetNode();\n    VAssert(node != NULL);\n\n    bool enabled = MyBase::GetEnableErrMsg();\n    MyBase::EnableErrMsg(false);\n\n    XmlParser xmlparser;\n    int       rc = xmlparser.LoadFromFile(node, _settingsPath);\n    bool      status = rc >= 0;\n\n    MyBase::EnableErrMsg(enabled);\n\n    return status;\n}\n\nvoid SettingsParams::FindDefaultSettingsPath()\n{\n    string prefPath;\n    string preffile =\n#ifdef WIN32\n        \"\\\\.vapor3_prefs\";\n#else\n        \"/.vapor3_prefs\";\n#endif\n    char *pPath = getenv(\"VAPOR3_PREFS_DIR\");\n    if (!pPath) pPath = getenv(\"HOME\");\n    if (!pPath) {\n        vector<string> tpath;\n        tpath.push_back(\"examples\");\n        tpath.push_back(preffile);\n        prefPath = GetSharePath(\"examples/\" + preffile);\n    } else {\n        prefPath = string(pPath) + preffile;\n    }\n\n    SetCurrentPrefsPath(prefPath);\n}\n\nint SettingsParams::SaveSettings() const\n{\n    ofstream fileout;\n    string   s;\n\n    fileout.open(_settingsPath.c_str());\n    if (!fileout) {\n        MyBase::SetErrMsg(\"Unable to open output settings file %s : %M\", _settingsPath.c_str());\n        return (-1);\n    }\n\n    const XmlNode *node = GetNode();\n    XmlNode::streamOut(fileout, *node);\n    if (fileout.bad()) {\n        MyBase::SetErrMsg(\"Unable to open output settings file %s : %M\", _settingsPath.c_str());\n        return (-1);\n    }\n\n    fileout.close();\n    return (0);\n}\n\n// Reset settings settings to initial state\nvoid SettingsParams::Init()\n{\n    SetSessionAutoSaveEnabled(true);\n    SetChangesPerAutoSave(5);\n    std::string homeDir = FileUtils::HomeDir();\n    SetAutoSaveSessionFile(homeDir + \"/VaporAutoSave.vs3\");\n\n    SetAutoStretchEnabled(true);\n    SetValueLong(UseAllCoresTag, \"\", true);\n    SetValueLong(AutoCheckForUpdatesTag, \"\", true);\n    SetValueLong(AutoCheckForNoticesTag, \"\", true);\n    SetNumThreads(4);\n    SetCacheMB(defaultCacheSize);\n\n\n    SetDefaultSessionDir(string(homeDir));\n    SetDefaultMetadataDir(string(homeDir));\n    SetDefaultFlowDir(string(homeDir));\n\n    string palettes = GetSharePath(\"palettes\");\n    SetDefaultTFDir(string(palettes));\n\n    string python = GetPythonDir();\n    SetDefaultPythonDir(string(python));\n}\n\nstd::string SettingsParams::GetSettingsPath() const { return _settingsPath; }\n"
  },
  {
    "path": "lib/params/SliceParams.cpp",
    "content": "\n#include <string>\n#include <vapor/RenderParams.h>\n#include <vapor/SliceParams.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n#define THREED 3\n\n#define X 0\n#define Y 1\n#define Z 2\n\n#define XY 0\n#define XZ 1\n#define YZ 2\n\n#define DEFAULT_SAMPLERATE 200\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<SliceParams> registrar(SliceParams::GetClassType());\n\nSliceParams::SliceParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, SliceParams::GetClassType(), THREED)\n{\n    SetDiagMsg(\"SliceParams::SliceParams() this=%p\", this);\n\n    _cachedValues.clear();\n    _init();\n}\n\nSliceParams::SliceParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, THREED) { _initialized = true; }\n\nSliceParams::~SliceParams() { SetDiagMsg(\"SliceParams::~SliceParams() this=%p\", this); }\n\nvoid SliceParams::_init()\n{\n    SetDiagMsg(\"SliceParams::_init()\");\n\n    SetFieldVariableNames(vector<string>());\n}\n\nint SliceParams::Initialize()\n{\n    int rc = RenderParams::Initialize();\n    if (rc < 0) return (rc);\n    if (_initialized) return 0;\n    _initialized = true;\n\n    Box *box = GetBox();\n    box->SetOrientation(Box::XYZ);\n\n    std::vector<double> minExt, maxExt;\n    box->GetExtents(minExt, maxExt);\n\n    std::vector<double> sampleLocation(3);\n    for (int i = 0; i < 3; i++) sampleLocation[i] = (minExt[i] + maxExt[i]) / 2.0;\n\n    SetValueDouble(RenderParams::XSlicePlaneOriginTag, \"\", sampleLocation[0]);\n    SetValueDouble(RenderParams::YSlicePlaneOriginTag, \"\", sampleLocation[1]);\n    SetValueDouble(RenderParams::ZSlicePlaneOriginTag, \"\", sampleLocation[2]);\n    SetValueDouble(RenderParams::SampleRateTag, \"\", DEFAULT_SAMPLERATE);\n\n    return (0);\n}\n\nvoid SliceParams::SetCachedValues(std::vector<double> values)\n{\n    _cachedValues.clear();\n    _cachedValues = values;\n}\n\nstd::vector<double> SliceParams::GetCachedValues() const { return _cachedValues; }\n\nbool SliceParams::GetOrientable() const { return true; }\n"
  },
  {
    "path": "lib/params/TFInterpolator.cpp",
    "content": "//************************************************************************\n//\t\t     Copyright (C)  2004\n//     University Corporation for Atmospheric Research\n//\t\t     All Rights Reserved\n//************************************************************************/\n//\n//\tFile:\t\tTFInterpolator.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tNovember 2004\n//\n//\tDescription:\tImplements the TFInterpolator class:\n//\t\tA class to interpolate transfer function values\n//\t\tCurrently only supports linear interpolation\n//\n#include <cmath>\n#include \"vapor/VAssert.h\"\n#include <iostream>\n#include <vapor/TFInterpolator.h>\nusing namespace std;\nusing namespace VAPoR;\n\n#ifdef WIN32\n    #ifndef NAN\nstatic const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};\n        #define NAN (*(const float *)__nan)\n    #endif\n#endif\n\nfloat TFInterpolator::Xn = 95.047;\nfloat TFInterpolator::Yn = 100.0;\nfloat TFInterpolator::Zn = 108.883;\n\nfloat TFInterpolator::XYZtransferMatrix[9] = {0.4124564, 0.2126729, 0.0193339, 0.3575761, 0.7151522, 0.1191920, 0.1804375, 0.0721750, 0.9503041};\n\nfloat TFInterpolator::XYZinverseMatrix[9] = {3.2404548360214087,   -0.9692663898756537, 0.05564341960421365, -1.5371388501025751, 1.876010928842491,\n                                             -0.20402585426769812, -0.4985315468684809, 0.04155608234667354, 1.0572251624579287};\n\nfloat *TFInterpolator::colorMap = NULL;\n\nTFInterpolator::~TFInterpolator()\n{\n    if (colorMap) delete colorMap;\n}\n\n// Determine the interpolated value at intermediate value 0<=r<=1\n// where the value at left and right endpoint is known\n// This method is just a stand-in until we get more sophistication\n//\nfloat TFInterpolator::interpolate(TFInterpolator::type t, float leftVal, float rightVal, float r)\n{\n    if (t == TFInterpolator::discrete) {\n        if (r < 0.5)\n            return leftVal;\n        else\n            return rightVal;\n    }\n    float val = (float)(leftVal * (1. - r) + r * rightVal);\n    // if (val < 0.f || val > 1.f){\n    // VAssert(val <= 1.f && val >= 0.f);\n    //}\n    return val;\n}\n\nfloat TFInterpolator::interpCirc(type t, float leftVal, float rightVal, float r)\n{\n    if (t == TFInterpolator::discrete) {\n        if (r < 0.5)\n            return leftVal;\n        else\n            return rightVal;\n    }\n    if (fabs(rightVal - leftVal) <= 0.5f) return interpolate(t, leftVal, rightVal, r);\n    // replace smaller by 1+smaller, interpolate, then fit back into interval\n    //\n    float interpVal;\n    if (leftVal <= rightVal) {\n        interpVal = interpolate(t, leftVal + 1.f, rightVal, r);\n    } else\n        interpVal = interpolate(t, leftVal, rightVal + 1.f, r);\n\n    if (interpVal >= 1.f) interpVal -= 1.f;\n    if (interpVal < 0.f || interpVal > 1.f) { VAssert(interpVal <= 1.f && interpVal >= 0.f); }\n    return interpVal;\n}\n\nfloat *TFInterpolator::genDivergentMap(float rgb1[3], float rgb2[3], int numColors)\n{\n    float interp;\n    float color[3];\n\n    float *colorMap1 = new float[numColors * 3];\n\n    for (float i = 0; i < (float)numColors; i++) {\n        interp = (float)i / (float)numColors;\n        divergentInterpolation(rgb1, rgb2, color, interp);\n        colorMap1[(int)i * 3] = color[0];\n        colorMap1[(int)i * 3 + 1] = color[1];\n        colorMap1[(int)i * 3 + 2] = color[2];\n    }\n\n    return colorMap1;\n}\n\nvoid TFInterpolator::correctiveDivergentInterpolation(float rgb1[3], float rgb2[3], float output[3], float interp) { divergentInterpolation(rgb1, rgb2, output, interp, true); }\n\nint TFInterpolator::divergentInterpolation(float rgb1[3], float rgb2[3], float output[3], float interp, bool corrective)\n{\n    interp = 1 - interp;\n    static float msh1[3], msh2[3], mshMid[3];\n    float        m1, s1, h1;\n    float        m2, s2, h2;\n\n    srgb2msh(rgb1, msh1);\n    m1 = msh1[0];\n    s1 = msh1[1];\n    h1 = msh1[2];\n\n    srgb2msh(rgb2, msh2);\n    m2 = msh2[0];\n    s2 = msh2[1];\n    h2 = msh2[2];\n\n    // If pohsv[1] are saturated and distinct, place white in the middle\n    if (corrective) {\n        if ((s1 > 0.05) && (s2 > .05) && (fabs(h1 - h2) > (3.1415 / 3.0))) {\n            float Mmid;\n            if ((m1 > m2) && (m1 > 88.f))\n                Mmid = m1;\n            else if ((m2 > m1) && (m2 > 88.f))\n                Mmid = m2;\n            else\n                Mmid = 88.f;\n            if (interp < 0.5) {\n                m2 = Mmid;\n                s2 = 0.0;\n                h2 = 0.0;\n                interp = 2 * interp;\n            } else {\n                m1 = Mmid;\n                s1 = 0.0;\n                h1 = 0.0;\n                interp = 2 * interp - 1;\n            }\n        }\n    }\n\n    // Adjust hue of unsaturated colors\n    if ((s1 < 0.05) && (s2 > 0.05))\n        h1 = adjustHue(m2, s2, h2, m1);\n    else if ((s2 < 0.05) && (s1 > 0.05))\n        h2 = adjustHue(m1, s1, h1, m2);\n\n    mshMid[0] = (1 - interp) * m1 + interp * m2;\n    mshMid[1] = (1 - interp) * s1 + interp * s2;\n    mshMid[2] = (1 - interp) * h1 + interp * h2;\n\n    msh2srgb(mshMid, output);\n\n    // Clip colors that are out of bounds\n    float maxVal = output[0];\n    if (maxVal < output[1]) maxVal = output[1];\n    if (maxVal < output[2]) maxVal = output[2];\n    if (maxVal > 255.0) {\n        output[0] = output[0] * 255.0 / maxVal;\n        output[1] = output[1] * 255.0 / maxVal;\n        output[2] = output[2] * 255.0 / maxVal;\n    }\n    if (output[0] < 0) output[0] = 0.0;\n    if (output[1] < 0) output[1] = 0.0;\n    if (output[2] < 0) output[2] = 0.0;\n\n    return 0;\n}\n\nfloat TFInterpolator::adjustHue(float m, float s, float h, float mUnsat)\n{\n    if (m >= mUnsat - .1)\n        return h;    // mUnsat;\n    else {\n        float hSpin;\n        hSpin = s * sqrt(pow(mUnsat, 2.f) - pow(m, 2.f)) / (m * sin(s));\n        if (h > (-3.14159 / 3))\n            return h + hSpin;\n        else\n            return h - hSpin;\n    }\n}\n\nint TFInterpolator::msh2srgb(float msh[3], float rgb[3])\n{\n    static float lab[3];\n    msh2lab(msh, lab);\n    lab2srgb(lab, rgb);\n    return 0;\n}\n\nint TFInterpolator::msh2lab(float msh[3], float lab[3])\n{\n    float l, a, b;\n    float m = msh[0];\n    float s = msh[1];\n    float h = msh[2];\n\n    l = m * cos(s);\n    a = m * sin(s) * cos(h);\n    b = m * sin(s) * sin(h);\n    lab[0] = l;\n    lab[1] = a;\n    lab[2] = b;\n    return 0;\n}\n\nfloat lab2srgbHelper(float val)\n{\n    float xlim = 0.008856;\n    float a = 7.787;\n    float b = 16.f / 116.f;\n    float ylim = a * xlim + b;\n    if (val > ylim) {\n        return pow(val, 3);\n    } else {\n        return (val - b) / a;\n    }\n}\n\nvoid LabToXYZ(double L, double a, double b, double *x, double *y, double *z)\n{\n    // LAB to XYZ\n    double var_Y = (L + 16) / 116;\n    double var_X = a / 500 + var_Y;\n    double var_Z = var_Y - b / 200;\n\n    if (pow(var_Y, 3) > 0.008856)\n        var_Y = pow(var_Y, 3);\n    else\n        var_Y = (var_Y - 16.0 / 116.0) / 7.787;\n\n    if (pow(var_X, 3) > 0.008856)\n        var_X = pow(var_X, 3);\n    else\n        var_X = (var_X - 16.0 / 116.0) / 7.787;\n\n    if (pow(var_Z, 3) > 0.008856)\n        var_Z = pow(var_Z, 3);\n    else\n        var_Z = (var_Z - 16.0 / 116.0) / 7.787;\n    const double ref_X = 0.9505;\n    const double ref_Y = 1.000;\n    const double ref_Z = 1.089;\n    *x = ref_X * var_X;    // ref_X = 0.9505  Observer= 2 deg Illuminant= D65\n    *y = ref_Y * var_Y;    // ref_Y = 1.000\n    *z = ref_Z * var_Z;    // ref_Z = 1.089\n}\n\nint TFInterpolator::lab2srgb(float lab[3], float rgb[3])\n{\n    static float xyz[3];\n    float        x, y, z;\n    float        l = lab[0];\n    float        a = lab[1];\n    float        b = lab[2];\n\n    x = Xn * lab2srgbHelper((a / 500.f) + (l + 16.f) / (116.f));\n    y = Yn * lab2srgbHelper((l + 16.f) / 116.f);\n    z = Zn * lab2srgbHelper((l + 16.f) / 116.f - (b / 200.f));\n    xyz[0] = x;\n    xyz[1] = y;\n    xyz[2] = z;\n\n    TFInterpolator::xyz2srgb(xyz, rgb);\n    return 0;\n}\n\nint TFInterpolator::srgb2msh(float rgb[3], float msh[3])\n{\n    static float lab[3];\n    srgb2lab(rgb, lab);\n    lab2msh(lab, msh);\n    return 0;\n}\n\nint TFInterpolator::lab2msh(float lab[3], float msh[3])\n{\n    float m, s, h;\n    float l = lab[0];\n    float a = lab[1];\n    float b = lab[2];\n\n    m = sqrt(pow(l, 2) + pow(a, 2) + pow(b, 2));\n    s = acos(l / m);\n    h = atan2(b, a);\n    msh[0] = m;\n    msh[1] = s;\n    msh[2] = h;\n    return 0;\n}\n\nfloat srgb2labHelper(float val)\n{\n    float limit = 0.008856;\n    if (val > limit)\n        return pow(val, (float)(1.0 / 3.0));\n    else\n        return 7.787 * val + 16.0 / 116.0;\n}\n\nint TFInterpolator::srgb2lab(float rgb[3], float lab[3])\n{\n    float        l, a, b;\n    static float xyz[3];\n    static float srgb[3];\n\n    // Newly added!\n    rgb2srgb(rgb, srgb);\n\n    srgb2xyz(rgb, xyz);\n    // srgb2xyz(rgb,xyz);\n    float x = xyz[0];\n    float y = xyz[1];\n    float z = xyz[2];\n\n    l = 116.0 * (srgb2labHelper(y / Yn) - 16.0 / 116.0);\n    a = 500.0 * (srgb2labHelper(x / Xn) - srgb2labHelper(y / Yn));\n    b = 200.0 * (srgb2labHelper(y / Yn) - srgb2labHelper(z / Zn));\n    lab[0] = l;\n    lab[1] = a;\n    lab[2] = b;\n    return 0;\n}\n\nint TFInterpolator::xyz2srgb(float xyz[3], float srgb[3])\n{\n    float r, g, b;\n    float rgb[3];\n    float x = xyz[0];\n    float y = xyz[1];\n    float z = xyz[2];\n\n    r = x * XYZinverseMatrix[0] + y * XYZinverseMatrix[3] + z * XYZinverseMatrix[6];\n    g = x * XYZinverseMatrix[1] + y * XYZinverseMatrix[4] + z * XYZinverseMatrix[7];\n    b = x * XYZinverseMatrix[2] + y * XYZinverseMatrix[5] + z * XYZinverseMatrix[8];\n    rgb[0] = r;\n    rgb[1] = g;\n    rgb[2] = b;\n\n    rgb2srgb(rgb, srgb);\n\n    r = srgb[0];\n    g = srgb[1];\n    b = srgb[2];\n\n    return 0;\n}\n\nint TFInterpolator::rgb2srgb(float rgb[3], float srgb[3])\n{\n    float val;\n    for (int i = 0; i < 3; i++) {\n        val = rgb[i] / 100.0;\n        if (val > 0.00313080495356037152)\n            val = (1.055 * pow(val, (float)(1.0 / 2.4)) - .055);\n        else\n            val = val * 12.92;\n        val = val * 255.0;\n        //\t\tif ((val-floor(val)) > .5) val = ceil(val);\n        //\t\telse val = floor(val);\n        srgb[i] = val;\n    }\n\n    /* Clip colors that are out of bounds\n        float maxVal = srgb[0];\n        if (maxVal < srgb[1]) maxVal = srgb[1];\n        if (maxVal < srgb[2]) maxVal = srgb[2];\n        cout << maxVal << endl;\n        if (maxVal > 255.0) {\n                cout << \"Correcting by \" << maxVal << endl;\n                srgb[0] /= maxVal;\n                srgb[1] /= maxVal;\n                srgb[2] /= maxVal;\n        }\n        if (srgb[0]<0) srgb[0]=0;\n        if (srgb[1]<0) srgb[1]=0;\n        if (srgb[2]<0) srgb[2]=0;*/\n\n    return 0;\n}\n\nint TFInterpolator::srgb2rgb(float srgb[3], float rgb[3])\n{\n    float val;\n\n    for (int i = 0; i < 3; i++) {\n        val = srgb[i] / 255.0;\n        if (val > 0.04045) {\n            val = pow(((val + 0.055) / 1.055), 2.4);\n        } else {\n            val = val / 12.92;\n        }\n        rgb[i] = val * 100;\n    }\n\n    /* Clip colors that are out of bounds\n    double maxVal = rgb[0];\n    if (maxVal < rgb[1]) maxVal = rgb[1];\n    if (maxVal < rgb[2]) maxVal = rgb[2];\n    cout << maxVal << endl;\n    if (maxVal > 100.0) {\n        cout << \"Correcting by \" << maxVal << endl;\n        rgb[0] /= maxVal;\n        rgb[1] /= maxVal;\n        rgb[2] /= maxVal;\n    }\n    if (rgb[0]<0) rgb[0]=0;\n    if (rgb[1]<0) rgb[1]=0;\n    if (rgb[2]<0) rgb[2]=0;*/\n\n    return 0;\n}\n\nint TFInterpolator::srgb2xyz(float rgb[3], float xyz[3])\n{\n    float linearRGB[3];\n    float x, y, z, r, g, b;\n\n    srgb2rgb(rgb, linearRGB);\n    r = linearRGB[0];\n    g = linearRGB[1];\n    b = linearRGB[2];\n\n    x = r * XYZtransferMatrix[0] + g * XYZtransferMatrix[3] + b * XYZtransferMatrix[6];\n    y = r * XYZtransferMatrix[1] + g * XYZtransferMatrix[4] + b * XYZtransferMatrix[7];\n    z = r * XYZtransferMatrix[2] + g * XYZtransferMatrix[5] + b * XYZtransferMatrix[8];\n    xyz[0] = x;\n    xyz[1] = y;\n    xyz[2] = z;\n    return 0;\n}\n\nint TFInterpolator::rgb2hsv(float rgb[3], float hsv[3])\n{\n    // hsv         out;\n    double min, max, delta;\n\n    min = rgb[0] < rgb[1] ? rgb[0] : rgb[1];\n    min = min < rgb[2] ? min : rgb[2];\n\n    max = rgb[0] > rgb[1] ? rgb[0] : rgb[1];\n    max = max > rgb[2] ? max : rgb[2];\n\n    hsv[2] = max;    // 255.0;                                // v\n    delta = max - min;\n    if (delta < 0.00001) {\n        hsv[1] = 0;\n        hsv[0] = 0;    // undefined, maybe nan?\n        return 0;\n    }\n    if (max > 0.0) {               // NOTE: if Max is == 0, this divide would cause a crash\n        hsv[1] = (delta / max);    // s\n    } else {\n        // if max is 0, then r = g = b = 0\n        // s = 0, v is undefined\n        hsv[1] = 0.0;\n        hsv[0] = NAN;    // its now undefined\n        return 0;\n    }\n    if (rgb[0] >= max)                         // > is bogus, just keeps compilor happy\n        hsv[0] = (rgb[1] - rgb[2]) / delta;    // between yellow & magenta\n    else if (rgb[1] >= max)\n        hsv[0] = 2.0 + (rgb[2] - rgb[0]) / delta;    // between cyan & yellow\n    else\n        hsv[0] = 4.0 + (rgb[0] - rgb[1]) / delta;    // between magenta & cyan\n\n    hsv[0] *= 60.0;    // degrees\n\n    if (hsv[0] < 0.0) hsv[0] += 360.0;\n\n    // hsv[0] = hsv[0]/360.0;\n    return 0;\n}\n\nint TFInterpolator::hsv2rgb(float hsv[3], float rgb[3])\n{\n    double hh, p, q, t, ff;\n    long   i;\n    // rgb         out;\n\n    hsv[0] = hsv[0] * 360.0;    //*360.0;//2.0*3.14159;\t// scale to unit circle\n\n    if (hsv[1] <= 0.0) {    // < is bogus, just shuts up warnhsv[1]\n        rgb[0] = hsv[2];\n        rgb[1] = hsv[2];\n        rgb[2] = hsv[2];\n        return 0;\n    }\n    hh = hsv[0];\n    if (hh >= 360.0) hh = 0.0;\n    hh /= 60.0;\n    i = (long)hh;\n    ff = hh - i;\n    p = hsv[2] * (1.0 - hsv[1]);\n    q = hsv[2] * (1.0 - (hsv[1] * ff));\n    t = hsv[2] * (1.0 - (hsv[1] * (1.0 - ff)));\n\n    switch (i) {\n    case 0:\n        rgb[0] = hsv[2];\n        rgb[1] = t;\n        rgb[2] = p;\n        break;\n    case 1:\n        rgb[0] = q;\n        rgb[1] = hsv[2];\n        rgb[2] = p;\n        break;\n    case 2:\n        rgb[0] = p;\n        rgb[1] = hsv[2];\n        rgb[2] = t;\n        break;\n\n    case 3:\n        rgb[0] = p;\n        rgb[1] = q;\n        rgb[2] = hsv[2];\n        break;\n    case 4:\n        rgb[0] = t;\n        rgb[1] = p;\n        rgb[2] = hsv[2];\n        break;\n    case 5:\n    default:\n        rgb[0] = hsv[2];\n        rgb[1] = p;\n        rgb[2] = q;\n        break;\n    }\n\n    // rgb[0] = rgb[0]*255;\n    // rgb[1] = rgb[1]*255;\n    // rgb[2] = rgb[2]*255;\n\n    return 0;\n}\n"
  },
  {
    "path": "lib/params/TODO.txt",
    "content": "Is params::restart() method needed? It sets params to default state when\nno data (i.e. datamgr) are present. Why not require data to be present before\ninitializing render params? RenderParams should require a valid (non-NULL) \ndata mgr, and should not have to handle cases where one does not exist. I.e.\nthere should be no need for RenderParams::Valid(type==0)\n\nRemove deprecated constructors (or constructor arguments) from\nMapperFunction. e.g. nBits\n\nRenderParams\n------------\n\n+ Should Set* functions all be made no-fail? I.e. return void and\nadjust inputs as necessary to provide a correct value when calling\nSetValueDouble, etc.\n\n+ Move Barb specific stuff into Barb renderer (e.g. {Set,Get}Grid(), IsAlignedTo Data(), SetGridAlignStrides, etc).\n\n+ How do get{Min,Max}EditBound() differ from\nMapperFunction::get{Min,Map}Value(). Ans: These methods are used purely for\npresentation within the GUI and should be moved out of the RenderParams\nclass to one of the session state classes\n\n+ RenderParams subclass instances appear to be created at applicaiton\nstartup, and whenever a new session is created. These constructors\nare fired *before* data are loaded. However, when a new instance\nof a renderer is created (via the \"New\" button) another instance\nof the params class is created again. Destructors are also not being\ncalled properly.\n\n+ No error handing performed for Set or Get methods. E.g. Setting\nRGB color to value outside 0..1.0, setting variable to name that\ndoesn't exist, etc. How should these be handle? Ignore invalid\nvalues? Reconcile to valid value? etc.\n\n+ Move common text stuff (e.g. font size, text type, precision)\nfrom isolineparams to RenderParams\n\nMISC\n----\n\n+ Get/Set param acessors need validation has is done for isolineparams\n"
  },
  {
    "path": "lib/params/Transform.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tTransform.cpp\n//\n//\tAuthor:\t\tScott Pearse\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tMay 2017\n//\n//\tDescription:\tImplements the Transform class\n//\t\tThis class contains the translation, rotation, and scale\n//\t\tparameters associated with a loaded data set\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n#include <vapor/Transform.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nconst string Transform::_translationTag = \"Translation\";\nconst string Transform::_rotationTag = \"Rotation\";\nconst string Transform::_scaleTag = \"Scale\";\nconst string Transform::_originTag = \"Origin\";\nconst string Transform::_originInitializedTag = \"OriginInitialized\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<Transform> registrar(Transform::GetClassType());\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nTransform::Transform(ParamsBase::StateSave *ssave) : ParamsBase(ssave, Transform::GetClassType()) {}\n\nTransform::Transform(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nTransform::~Transform() { MyBase::SetDiagMsg(\"Transform::~Transform() this=%p\", this); }\n\nvoid Transform::SetScales(const vector<double> scale) { SetValueDoubleVec(_scaleTag, \"Set scale transform\", scale); }\n\nvector<double> Transform::GetOrigin() const\n{\n    vector<double> defaultv(3, 0.0);\n    vector<double> origin = GetValueDoubleVec(_originTag, defaultv);\n    return origin;\n}\n\nvoid Transform::SetOrigin(const vector<double> origin)\n{\n    SetValueDoubleVec(_originTag, \"Set origin for transforms\", origin);\n    SetOriginInitialized(true);\n}\n\nbool Transform::IsOriginInitialized() const { return GetValueLong(_originInitializedTag, false); }\n\nvoid Transform::SetOriginInitialized(bool value) { SetValueLong(_originInitializedTag, \"Set is origin initialized for transforms\", value); }\n"
  },
  {
    "path": "lib/params/TwoDDataParams.cpp",
    "content": "\n#include <string>\n#include <vapor/RenderParams.h>\n#include <vapor/TwoDDataParams.h>\n#include <vapor/DataMgrUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<TwoDDataParams> registrar(TwoDDataParams::GetClassType());\n\nTwoDDataParams::TwoDDataParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, TwoDDataParams::GetClassType(), 2)\n{\n    SetDiagMsg(\"TwoDDataParams::TwoDDataParams() this=%p\", this);\n\n    _init();\n}\n\nTwoDDataParams::TwoDDataParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 2) {}\n\nTwoDDataParams::~TwoDDataParams() { SetDiagMsg(\"TwoDDataParams::~TwoDDataParams() this=%p\", this); }\n\n// Set everything to default values\nvoid TwoDDataParams::_init()\n{\n    SetDiagMsg(\"TwoDDataParams::_init()\");\n\n    // Necessary?\n    //\n    SetFieldVariableNames(vector<string>());\n}\n"
  },
  {
    "path": "lib/params/Viewpoint.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tViewpoint.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tMay 2005\n//\n//\tDescription:\tImplements the Viewpoint class\n//\t\tThis class contains the parameters associated with one viewpoint\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n\n#include <vapor/Viewpoint.h>\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nconst string Viewpoint::_modelViewMatrixTag = \"ModelViewMatrix\";\nconst string Viewpoint::_projectionMatrixTag = \"ProjectionMatrix\";\nconst string Viewpoint::_rotationCenterTag = \"RotationCenter\";\n\ndouble Viewpoint::_defaultModelViewMatrix[] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0};\ndouble Viewpoint::_defaultProjectionMatrix[] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0};\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<Viewpoint> registrar(Viewpoint::GetClassType());\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nViewpoint::Viewpoint(ParamsBase::StateSave *ssave) : ParamsBase(ssave, Viewpoint::GetClassType()) { _init(); }\n\nViewpoint::Viewpoint(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node) {}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nViewpoint::~Viewpoint() { MyBase::SetDiagMsg(\"Viewpoint::~Viewpoint() this=%p\", this); }\n\nvoid Viewpoint::_init()\n{\n    double proj[] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0};\n\n    double modelview[] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0};\n\n    SetProjectionMatrix(proj);\n    SetModelViewMatrix(modelview);\n}\n\nvoid Viewpoint::GetModelViewMatrix(double m[16]) const\n{\n    vector<double> defaultv;\n    for (int i = 0; i < 16; i++) defaultv.push_back(_defaultModelViewMatrix[i]);\n\n    vector<double> val = GetValueDoubleVec(_modelViewMatrixTag, defaultv);\n    VAssert(val.size() == 16);\n\n    for (int i = 0; i < val.size(); i++) m[i] = val[i];\n}\n\nvoid Viewpoint::SetModelViewMatrix(const double m[16])\n{\n    vector<double> val;\n    for (int i = 0; i < 16; i++) val.push_back(m[i]);\n\n#ifdef VAPOR3_0_0_ALPHA\n    for (int j = 0; j < 4; j++) {\n        for (int i = 0; i < 4; i++) { cout << m[j * 4 + i] << \" \"; }\n        cout << endl;\n    }\n    cout << endl;\n#endif\n\n    SetValueDoubleVec(_modelViewMatrixTag, \"Model view matrix\", val);\n}\n\nvoid Viewpoint::GetProjectionMatrix(double m[16]) const\n{\n    vector<double> defaultv;\n    for (int i = 0; i < 16; i++) defaultv.push_back(_defaultProjectionMatrix[i]);\n\n    vector<double> val = GetValueDoubleVec(_projectionMatrixTag, defaultv);\n    VAssert(val.size() == 16);\n\n    for (int i = 0; i < val.size(); i++) m[i] = val[i];\n}\n\nvoid Viewpoint::SetProjectionMatrix(const double m[16])\n{\n    vector<double> val;\n    for (int i = 0; i < 16; i++) val.push_back(m[i]);\n    SetValueDoubleVec(_projectionMatrixTag, \"Projection matrix\", val);\n}\n\nbool Viewpoint::ReconstructCamera(const double m[16], double position[3], double upVec[3], double viewDir[3]) const\n{\n    double minv[16];\n\n    int rc = minvert((double *)m, minv);\n    if (rc < 0) return (false);\n\n    vscale(minv + 8, -1.0);\n\n    for (int i = 0; i < 3; i++) {\n        position[i] = minv[12 + i];    // position vector is minv[12..14]\n        upVec[i] = minv[4 + i];        // up vector is minv[4..6]\n        viewDir[i] = minv[8 + i];      // view direction is minv[8..10]\n    }\n    vnormal(upVec);\n    vnormal(viewDir);\n\n    return (true);\n}\n"
  },
  {
    "path": "lib/params/ViewpointParams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tViewpointParams.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tAugust 2004\n//\n//\tDescription:\tImplements the ViewpointParams class\n//\t\tThis class contains the parameters associated with viewpoint and lights\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n#include <algorithm>\n\n#include <vapor/ViewpointParams.h>\n\ndouble VAPoR::ViewpointParams::_defaultLightDirection[3][4] = {{0.f, 0.f, 1.f, 0.f}, {0.f, 1.f, 0.f, 0.f}, {1.f, 0.f, 0.f, 0.f}};\n\nint    VAPoR::ViewpointParams::_defaultNumLights = 1;\ndouble VAPoR::ViewpointParams::_defaultDiffuseCoeff[3] = {0.8f, 0.8f, 0.8f};\ndouble VAPoR::ViewpointParams::_defaultSpecularCoeff[3] = {0.3f, 0.3f, 0.3f};\ndouble VAPoR::ViewpointParams::_defaultAmbientCoeff = 0.1f;\ndouble VAPoR::ViewpointParams::_defaultSpecularExp = 20.f;\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nconst string ViewpointParams::UseCustomFramebufferTag = \"UseCustomFramebuffer\";\nconst string ViewpointParams::CustomFramebufferWidthTag = \"CustomFramebufferWidth\";\nconst string ViewpointParams::CustomFramebufferHeightTag = \"CustomFramebufferHeight\";\n\nconst string ViewpointParams::_viewPointsTag = \"Viewpoints\";\nconst string ViewpointParams::_transformsTag = \"Transforms\";\nconst string ViewpointParams::_currentViewTag = \"CurrentViewpoint\";\nconst string ViewpointParams::_lightDirectionsTag = \"LightDirections\";\nconst string ViewpointParams::_diffuseCoeffTag = \"DiffuseCoefficients\";\nconst string ViewpointParams::_specularCoeffTag = \"SpecularCoefficients\";\nconst string ViewpointParams::_specularExpTag = \"SpecularExponent\";\nconst string ViewpointParams::_ambientCoeffTag = \"AmbientCoefficient\";\nconst string ViewpointParams::_numLightsTag = \"NumLights\";\nconst string ViewpointParams::m_windowSizeTag = \"WindowSize\";\nconst string ViewpointParams::m_stretchFactorsTag = \"StretchFactors\";\nconst string ViewpointParams::m_fieldOfView = \"FieldOfView\";\nconst string ViewpointParams::_orthoProjectionSizeTag = \"OrthoProjectionSize\";\nconst string ViewpointParams::_projectionTypeTag = \"ProjectionType\";\n\n//----------------------------------------------------------------------------\n// Constructor\n//----------------------------------------------------------------------------\nViewpointParams::ViewpointParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, ViewpointParams::GetClassType())\n{\n    _init();\n\n    m_VPs = new ParamsContainer(ssave, _viewPointsTag);\n    m_VPs->SetParent(this);\n\n    Viewpoint currentVP(ssave);\n    m_VPs->Insert(&currentVP, _currentViewTag);\n\n    _transforms = new ParamsContainer(ssave, _transformsTag);\n    _transforms->SetParent(this);\n}\n\nViewpointParams::ViewpointParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    if (node->HasChild(_viewPointsTag)) {\n        m_VPs = new ParamsContainer(ssave, node->GetChild(_viewPointsTag));\n    } else {\n        // Node doesn't contain a viewpoint container\n        //\n        m_VPs = new ParamsContainer(ssave, _viewPointsTag);\n        m_VPs->SetParent(this);\n    }\n\n    if (node->HasChild(_transformsTag)) {\n        _transforms = new ParamsContainer(ssave, node->GetChild(_transformsTag));\n    } else {\n        // Node doesn't contain a transforms container\n        //\n        _transforms = new ParamsContainer(ssave, _transformsTag);\n        _transforms->SetParent(this);\n    }\n}\n\nViewpointParams::ViewpointParams(const ViewpointParams &rhs) : ParamsBase(rhs)\n{\n    m_VPs = new ParamsContainer(*(rhs.m_VPs));\n    _transforms = new ParamsContainer(*(rhs._transforms));\n}\n\nViewpointParams &ViewpointParams::operator=(const ViewpointParams &rhs)\n{\n    if (m_VPs) delete m_VPs;\n    if (_transforms) delete _transforms;\n\n    // Note: the following assign operation has to happen AFTER destroying\n    // _transforms 2 lines above. Otherwise, memory error will occur.\n    ParamsBase::operator=(rhs);\n\n    m_VPs = new ParamsContainer(*(rhs.m_VPs));\n    _transforms = new ParamsContainer(*(rhs._transforms));\n\n    return (*this);\n}\n\n//----------------------------------------------------------------------------\n// Destructor\n//----------------------------------------------------------------------------\nViewpointParams::~ViewpointParams()\n{\n    MyBase::SetDiagMsg(\"ViewpointParams::~ViewpointParams() this=%p\", this);\n\n    if (m_VPs) {\n        delete m_VPs;\n        m_VPs = NULL;\n    }\n\n    if (_transforms) {\n        delete _transforms;\n        _transforms = NULL;\n    }\n}\n\n// Reinitialize viewpoint settings, to center view on the center of full region.\n//(this is starting state)\nvoid ViewpointParams::_init()\n{\n    setNumLights(_defaultNumLights);\n    setExponent(_defaultSpecularExp);\n    setAmbientCoeff(_defaultAmbientCoeff);\n\n    for (int i = 0; i < 3; i++) { setDiffuseCoeff(i, _defaultDiffuseCoeff[i]); }\n\n    for (int i = 0; i < 3; i++) { setSpecularCoeff(i, _defaultSpecularCoeff[i]); }\n\n    for (int light = 0; light < 3; light++) {\n        for (int i = 0; i < 4; i++) { setLightDirection(light, i, _defaultLightDirection[light][i]); }\n    }\n\n    // SetStretchFactors(vector <double>(3,1.0));\n\n    SetWindowSize(100, 100);\n\n    SetValueLong(UseCustomFramebufferTag, UseCustomFramebufferTag, false);\n    SetValueLong(CustomFramebufferWidthTag, CustomFramebufferWidthTag, 1920);\n    SetValueLong(CustomFramebufferHeightTag, CustomFramebufferHeightTag, 1080);\n}\n\nTransform *ViewpointParams::GetTransform(string dataSetName)\n{\n    if (_transforms->GetParams(dataSetName) == NULL) {\n        bool enabled = _ssave->GetEnabled();\n        _ssave->SetEnabled(false);\n        Transform newTransform(_ssave);\n        _transforms->Insert(&newTransform, dataSetName);\n        _ssave->SetEnabled(enabled);\n    }\n    return (Transform *)_transforms->GetParams(dataSetName);\n}\n\ndouble ViewpointParams::getLightDirection(int lightNum, int dir) const\n{\n    if (lightNum < 0 || lightNum > 2) lightNum = 0;\n    if (dir < 0 || dir > 3) dir = 0;\n\n    vector<double> defaultv;\n    for (int light = 0; light < 3; light++) {\n        for (int i = 0; i < 4; i++) { defaultv.push_back(_defaultLightDirection[light][i]); }\n    }\n\n    vector<double> v = GetValueDoubleVec(_lightDirectionsTag, defaultv);\n\n    return (v[lightNum * 4 + dir]);\n}\n\nvoid ViewpointParams::setLightDirection(int lightNum, int dir, double val)\n{\n    if (lightNum < 0 || lightNum > 2) lightNum = 0;\n    if (dir < 0 || dir > 3) dir = 0;\n\n    vector<double> defaultv;\n    for (int light = 0; light < 3; light++) {\n        for (int i = 0; i < 4; i++) { defaultv.push_back(_defaultLightDirection[light][i]); }\n    }\n    vector<double> v = GetValueDoubleVec(_lightDirectionsTag, defaultv);\n\n    v[lightNum * 4 + dir] = val;\n\n    SetValueDoubleVec(_lightDirectionsTag, \"Set light direction\", v);\n}\n\ndouble ViewpointParams::getDiffuseCoeff(int lightNum) const\n{\n    if (lightNum < 0 || lightNum > 2) lightNum = 0;\n\n    vector<double> defaultv;\n    for (int i = 0; i < 3; i++) defaultv.push_back(_defaultDiffuseCoeff[i]);\n\n    double v = GetValueDoubleVec(_diffuseCoeffTag, defaultv)[lightNum];\n\n    return (v);\n}\n\ndouble ViewpointParams::getSpecularCoeff(int lightNum) const\n{\n    if (lightNum < 0 || lightNum > 2) lightNum = 0;\n\n    vector<double> defaultv;\n    for (int i = 0; i < 3; i++) defaultv.push_back(_defaultSpecularCoeff[i]);\n\n    double v = GetValueDoubleVec(_specularCoeffTag, defaultv)[lightNum];\n\n    return (v);\n}\n\nvoid ViewpointParams::setDiffuseCoeff(int lightNum, double val)\n{\n    if (lightNum < 0 || lightNum > 2) lightNum = 0;\n\n    vector<double> defaultv;\n    for (int i = 0; i < 3; i++) defaultv.push_back(_defaultDiffuseCoeff[i]);\n\n    vector<double> v = GetValueDoubleVec(_diffuseCoeffTag, defaultv);\n\n    v[lightNum] = val;\n\n    SetValueDoubleVec(_diffuseCoeffTag, \"Set diffuse coefficient\", v);\n}\n\nvoid ViewpointParams::setSpecularCoeff(int lightNum, double val)\n{\n    if (lightNum < 0 || lightNum > 2) lightNum = 0;\n\n    vector<double> defaultv;\n    for (int i = 0; i < 3; i++) defaultv.push_back(_defaultSpecularCoeff[i]);\n\n    vector<double> v = GetValueDoubleVec(_specularCoeffTag, defaultv);\n\n    v[lightNum] = val;\n\n    SetValueDoubleVec(_specularCoeffTag, \"Set specular coefficient\", v);\n}\n\nvoid ViewpointParams::SetCurrentViewpoint(Viewpoint *newVP) { m_VPs->Insert(newVP, _currentViewTag); }\n\nvoid ViewpointParams::SetWindowSize(size_t width, size_t height)\n{\n    vector<long> v;\n    v.push_back(width);\n    v.push_back(height);\n    SetValueLongVec(m_windowSizeTag, \"Set window width and height\", v);\n}\n\nvoid ViewpointParams::GetWindowSize(size_t &width, size_t &height) const\n{\n    vector<long> defaultv(2, 100);\n    vector<long> val = GetValueLongVec(m_windowSizeTag, defaultv);\n    width = val[0];\n    height = val[1];\n}\n\nvoid ViewpointParams::SetFOV(float v)\n{\n    if (v < 5) v = 5;\n    if (v > 90) v = 90;\n    SetValueDouble(m_fieldOfView, \"Set Field of View\", v);\n}\n\ndouble ViewpointParams::GetFOV() const\n{\n    double defaultv = 45.0;\n    double v = GetValueDouble(m_fieldOfView, defaultv);\n    if (v < 5) v = 5;\n    if (v > 90) v = 90;\n    return (v);\n}\n\nvoid ViewpointParams::SetOrthoProjectionSize(float f) { SetValueDouble(_orthoProjectionSizeTag, \"Set orthographic projection size\", f); }\n\ndouble ViewpointParams::GetOrthoProjectionSize() const\n{\n    double defaultv = 1.0;\n    double v = GetValueDouble(_orthoProjectionSizeTag, defaultv);\n    return v;\n}\n\nvoid ViewpointParams::SetProjectionType(ViewpointParams::ProjectionType type) { SetValueLong(_projectionTypeTag, \"Set projection type\", type); }\n\nViewpointParams::ProjectionType ViewpointParams::GetProjectionType() const\n{\n    const long defaultV = Perspective;\n    return (ViewpointParams::ProjectionType)GetValueLong(_projectionTypeTag, defaultV);\n}\n\nvector<double> ViewpointParams::GetStretchFactors() const\n{\n    vector<double> defaultvec(3, 1.);\n    vector<double> val = GetValueDoubleVec(m_stretchFactorsTag, defaultvec);\n    for (int i = 0; i < val.size(); i++) {\n        if (val[i] == 0) val[i] = 1.0;\n        if (val[i] < 0) val[i] *= -1.0;\n    }\n    return (val);\n}\n\nint ViewpointParams::SetCameraFromFile(const std::string &path) {\n    XmlParser xmlparser;\n\n    XmlNode *node = new XmlNode();\n\n    int rc = xmlparser.LoadFromFile(node, path);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Failed to read file %s : %M\", path.c_str());\n        return (-1);\n    }\n\n    Viewpoint* v     = new Viewpoint(_ssave, node);\n    SetCurrentViewpoint(v);\n\n    delete v;\n\n    _ssave->Save(_node, \"Load camera from file\");\n\n    return (0);\n}\n\nint ViewpointParams::SaveCameraToFile(const std::string &path) {\n    ofstream out(path);\n    if (!out) {\n        MyBase::SetErrMsg(\"Failed to open file %s : %M\", path.c_str());\n        return (-1);\n    }\n\n    Viewpoint *    vp = getCurrentViewpoint();\n    XmlNode *node = vp->GetNode();\n\n    out << *node;\n\n    if (out.bad()) {\n        MyBase::SetErrMsg(\"Failed to write file %s : %M\", path.c_str());\n        return (-1);\n    }\n    out.close();\n\n    return (0);\n}\n\n#ifdef VAPOR3_0_0_ALPHA\nvoid ViewpointParams::SetStretchFactors(vector<double> val)\n{\n    vector<double> defaultv(3, 1.);\n    if (val.size() != defaultv.size()) val = defaultv;\n    for (int i = 0; i < val.size(); i++) {\n        if (val[i] == 0) val[i] = 1.0;\n        if (val[i] < 0) val[i] *= -1.0;\n    }\n    SetValueDoubleVec(m_stretchFactorsTag, \"Scene scaling factors\", val);\n}\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n// Rescale viewing parameters when the scene is rescaled by factor\nvoid ViewpointParams::rescale(vector<double> scaleFac)\n{\n    double         vtemp[3], vtemph[3];\n    vector<double> vtemp2, vtemp2h;\n    Viewpoint *    vp = getCurrentViewpoint();\n    Viewpoint *    vph = getHomeViewpoint();\n    vector<double> vps = vp->getCameraPosLocal();\n    vector<double> vctr = vp->getRotationCenterLocal();\n    vector<double> vpsh = vph->getCameraPosLocal();\n    vector<double> vctrh = vph->getRotationCenterLocal();\n    for (int i = 0; i < 3; i++) {\n        vtemp[i] = vps[i] - vctr[i];\n        vtemph[i] = vpsh[i] - vctrh[i];\n    }\n\n    // Want to move the camera in or out, based on scaling in directions orthogonal to view dir.\n    for (int i = 0; i < 3; i++) {\n        vtemp[i] /= scaleFac[i];\n        vtemph[i] /= scaleFac[i];\n    }\n    for (int i = 0; i < 3; i++) {\n        vtemp2.push_back(vtemp[i] + vctr[i]);\n        vtemp2h.push_back(vtemph[i] + vctrh[i]);\n    }\n\n    vp->setCameraPosLocal(vtemp2);\n    vph->setCameraPosLocal(vtemp2h);\n\n    return;\n}\n\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\ndouble ViewpointParams::GetCurrentViewDiameter(vector<double> stretchFactors) const\n{\n    double campos[3], rotctr[3];\n    getStretchedCamPosLocal(stretchFactors, campos);\n    getStretchedRotCtrLocal(stretchFactors, rotctr);\n    return (2. * vdist(campos, rotctr) * tan(22.5 * M_PI / 180.));\n}\n#endif\n"
  },
  {
    "path": "lib/params/VolumeIsoParams.cpp",
    "content": "\n#include <string>\n#include <vapor/VolumeIsoParams.h>\n#include <vapor/STLUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<VolumeIsoParams> registrar(VolumeIsoParams::GetClassType());\n\nVolumeIsoParams::VolumeIsoParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : VolumeParams(dataMgr, ssave, VolumeIsoParams::GetClassType())\n{\n    SetDiagMsg(\"VolumeIsoParams::VolumeIsoParams() this=%p\", this);\n    _init();\n}\n\nVolumeIsoParams::VolumeIsoParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : VolumeParams(dataMgr, ssave, node) {}\n\nVolumeIsoParams::~VolumeIsoParams() { SetDiagMsg(\"VolumeIsoParams::~VolumeIsoParams() this=%p\", this); }\n\nstring VolumeIsoParams::GetDefaultAlgorithmName() const { return \"Iso Regular\"; }\n\n// Set everything to default values\nvoid VolumeIsoParams::_init()\n{\n    SetDiagMsg(\"VolumeParams::_init()\");\n    SetValueLong(UseColormapVariableTag, UseColormapVariableTag, false);\n\n    SetFieldVariableNames(vector<string>());\n\n    SetValueLong(LightingEnabledTag, \"\", GetDefaultLightingEnabled());\n    SetValueDouble(PhongAmbientTag, \"\", GetDefaultPhongAmbient());\n    SetValueDouble(PhongDiffuseTag, \"\", GetDefaultPhongDiffuse());\n    SetValueDouble(PhongSpecularTag, \"\", GetDefaultPhongSpecular());\n    SetValueDouble(PhongShininessTag, \"\", GetDefaultPhongShininess());\n}\n"
  },
  {
    "path": "lib/params/VolumeParams.cpp",
    "content": "\n#include <vapor/VolumeParams.h>\n#include <vapor/STLUtils.h>\n#include <string>\n#include <cassert>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<VolumeParams> registrar(VolumeParams::GetClassType());\n\nstd::vector<VolumeParams::AlgorithmEntry> VolumeParams::_algorithms;\n\nconst std::string VolumeParams::_algorithmTag = \"AlgorithmTag\";\nconst std::string VolumeParams::_algorithmWasManuallySetByUserTag = \"AlgorithmWasManuallySetByUserTag\";\nconst std::string VolumeParams::_isoValuesTag = \"IsoValuesTag\";\nconst std::string VolumeParams::_enabledIsoValuesTag = \"EnabledIsoValuesTag\";\nconst std::string VolumeParams::LightingEnabledTag = \"LightingEnabledTag\";\nconst std::string VolumeParams::PhongAmbientTag = \"PhongAmbientTag\";\nconst std::string VolumeParams::PhongDiffuseTag = \"PhongDiffuseTag\";\nconst std::string VolumeParams::PhongSpecularTag = \"PhongSpecularTag\";\nconst std::string VolumeParams::PhongShininessTag = \"PhongShininessTag\";\nconst std::string VolumeParams::UseColormapVariableTag = \"UseColormapVariable\";\nconst std::string VolumeParams::SamplingRateMultiplierTag = \"SamplingRateMultiplierTag\";\nconst std::string VolumeParams::VolumeDensityTag = \"VolumeDensityTag\";\nconst std::string VolumeParams::OSPDensity = \"OSPDensity\";\nconst std::string VolumeParams::OSPSampleRateScalar = \"OSPSampleRateScalar\";\nconst std::string VolumeParams::OSPAmbientLightIntensity = \"OSPAmbientLightIntensity\";\nconst std::string VolumeParams::OSPDirectionalLightIntensity = \"OSPDirectionalLightIntensity\";\n\nconst std::string VolumeParams::OSPVolmeAlgorithmName = \"OSPRay (experimental)\";\n\nVolumeParams::VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, VolumeParams::GetClassType(), 3)\n{\n    SetDiagMsg(\"VolumeParams::VolumeParams() this=%p\", this);\n    _init();\n}\n\nVolumeParams::VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, std::string classType) : RenderParams(dataMgr, ssave, classType, 3)\n{\n    SetDiagMsg(\"VolumeParams::VolumeParams() this=%p\", this);\n    _init();\n}\n\nVolumeParams::VolumeParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) {}\n\nVolumeParams::~VolumeParams() { SetDiagMsg(\"VolumeParams::~VolumeParams() this=%p\", this); }\n\nstring VolumeParams::GetDefaultAlgorithmName() const { return \"Regular\"; }\n\nstd::string VolumeParams::GetAlgorithm() const { return GetValueString(_algorithmTag, GetDefaultAlgorithmName()); }\n\nvoid VolumeParams::SetAlgorithm(std::string algorithm)\n{\n    if (!STLUtils::Contains(GetAlgorithmNames(), algorithm)) MyBase::SetErrMsg(\"Invalid volume rendering algorithm \\\"%s\\\"\", algorithm.c_str());\n    SetValueString(_algorithmTag, \"Volume rendering algorithm\", algorithm);\n}\n\nvoid VolumeParams::SetAlgorithmByUser(std::string algorithm)\n{\n    BeginGroup(\"Set Algorithm and set by user\");\n    SetAlgorithm(algorithm);\n    SetAlgorithmWasManuallySetByUser(true);\n    EndGroup();\n}\n\nbool VolumeParams::GetAlgorithmWasManuallySetByUser() const { return GetValueLong(_algorithmWasManuallySetByUserTag, false); }\n\nvoid VolumeParams::SetAlgorithmWasManuallySetByUser(bool v) { SetValueLong(_algorithmWasManuallySetByUserTag, \"User manually changed the algorithm\", v); }\n\nstd::vector<float> VolumeParams::GetSamplingRateMultiples() { return {1, 2, 4, 8, 16}; }\n\nlong VolumeParams::GetSamplingMultiplier() const { return GetValueLong(SamplingRateMultiplierTag, 1); }\n\nvoid VolumeParams::SetSamplingMultiplier(long d) { SetValueLong(SamplingRateMultiplierTag, \"Sampling Rate Multiplier\", d); }\n\nvector<double> VolumeParams::GetIsoValues(const string &variable)\n{\n    const string tag = \"IsoValues_\" + variable;\n\n    if (!GetNode()->HasElementDouble(tag)) {\n        const MapperFunction *mf = GetMapperFunc(variable);\n        const float           min = mf->getMinMapValue();\n        const float           max = mf->getMaxMapValue();\n        const float           middle = (min + max) / 2.f;\n        SetIsoValues(variable, {middle});\n    }\n\n    return GetValueDoubleVec(tag);\n}\n\nvoid VolumeParams::SetIsoValues(const string &variable, const vector<double> &values)\n{\n    assert(values.size() <= 4);\n    const string tag = \"IsoValues_\" + variable;\n    SetValueDoubleVec(tag, tag, values);\n}\n\nvoid  VolumeParams::SetLightingEnabled(bool v) { SetValueLong(LightingEnabledTag, \"Lighting enabled\", v); }\nbool  VolumeParams::GetLightingEnabled() const { return GetValueLong(LightingEnabledTag, GetDefaultLightingEnabled()); }\nvoid  VolumeParams::SetPhongAmbient(float v) { SetValueDouble(PhongAmbientTag, \"Phong ambient\", v); };\nfloat VolumeParams::GetPhongAmbient() const { return GetValueDouble(PhongAmbientTag, GetDefaultPhongAmbient()); };\nvoid  VolumeParams::SetPhongDiffuse(float v) { SetValueDouble(PhongDiffuseTag, \"Phong diffuse\", v); };\nfloat VolumeParams::GetPhongDiffuse() const { return GetValueDouble(PhongDiffuseTag, GetDefaultPhongDiffuse()); };\nvoid  VolumeParams::SetPhongSpecular(float v) { SetValueDouble(PhongSpecularTag, \"Phong specular\", v); };\nfloat VolumeParams::GetPhongSpecular() const { return GetValueDouble(PhongSpecularTag, GetDefaultPhongSpecular()); };\nvoid  VolumeParams::SetPhongShininess(float v) { SetValueDouble(PhongShininessTag, \"Phong shininess\", v); };\nfloat VolumeParams::GetPhongShininess() const { return GetValueDouble(PhongShininessTag, GetDefaultPhongShininess()); };\n\nconst std::vector<std::string> VolumeParams::GetAlgorithmNames(Type type)\n{\n    vector<string> names;\n    for (const AlgorithmEntry &entry : _algorithms) {\n        if (entry.type == type || type == Type::Any) names.push_back(entry.name);\n    }\n    return names;\n}\n\nvoid VolumeParams::Register(const std::string &name, Type type)\n{\n    AlgorithmEntry entry = {name, type};\n\n    for (const AlgorithmEntry &existing : _algorithms)\n        if (entry == existing) VAssert(!\"Algorithm already registered\");\n\n    _algorithms.push_back(entry);\n}\n\n// Set everything to default values\nvoid VolumeParams::_init()\n{\n    SetDiagMsg(\"VolumeParams::_init()\");\n\n    SetFieldVariableNames(vector<string>());\n    SetValueDouble(VolumeDensityTag, \"\", 1);\n\n    SetValueLong(LightingEnabledTag, \"\", GetDefaultLightingEnabled());\n    SetValueDouble(PhongAmbientTag, \"\", GetDefaultPhongAmbient());\n    SetValueDouble(PhongDiffuseTag, \"\", GetDefaultPhongDiffuse());\n    SetValueDouble(PhongSpecularTag, \"\", GetDefaultPhongSpecular());\n    SetValueDouble(PhongShininessTag, \"\", GetDefaultPhongShininess());\n\n    SetValueDouble(OSPDensity, \"\", 1);\n    SetValueDouble(OSPSampleRateScalar, \"\", 1);\n    SetValueDouble(OSPAmbientLightIntensity, \"\", 0.2);\n    SetValueDouble(OSPDirectionalLightIntensity, \"\", 1);\n}\n"
  },
  {
    "path": "lib/params/WireFrameParams.cpp",
    "content": "\n#include <string>\n#include <vapor/RenderParams.h>\n#include <vapor/WireFrameParams.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n// Register class with object factory!!!\n//\nstatic RenParamsRegistrar<WireFrameParams> registrar(WireFrameParams::GetClassType());\n\nWireFrameParams::WireFrameParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave) : RenderParams(dataMgr, ssave, WireFrameParams::GetClassType(), 3)\n{\n    SetDiagMsg(\"WireFrameParams::WireFrameParams() this=%p\", this);\n\n    _init();\n}\n\nWireFrameParams::WireFrameParams(DataMgr *dataMgr, ParamsBase::StateSave *ssave, XmlNode *node) : RenderParams(dataMgr, ssave, node, 3) {}\n\nWireFrameParams::~WireFrameParams() { SetDiagMsg(\"WireFrameParams::~WireFrameParams() this=%p\", this); }\n\n// Set everything to default values\nvoid WireFrameParams::_init()\n{\n    SetDiagMsg(\"WireFrameParams::_init()\");\n\n    SetFieldVariableNames(vector<string>());\n}\n"
  },
  {
    "path": "lib/params/XmlNode.cpp",
    "content": "//\n//      $Id$\n//\n//************************************************************************\n//\t\t\t\t\t\t\t\t *\n//\t\t     Copyright (C)  2004\t\t\t*\n//     University Corporation for Atmospheric Research\t\t*\n//\t\t     All Rights Reserved\t\t\t*\n//\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tXmlNode.cpp\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tThu Sep 30 14:06:17 MDT 2004\n//\n//\tDescription:\n//\n#include <iostream>\n#include <fstream>\n#include <sstream>\n#include \"vapor/VAssert.h\"\n#include <cctype>\n#include <algorithm>\n#include <expat.h>\n#include <vapor/XmlNode.h>\n#include <vapor/STLUtils.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\n// Enable memory checking\n//\n#define MEMCHECK\n\nnamespace VAPoR {\nvector<double>         XmlNode::_emptyDoubleVec;\nvector<long>           XmlNode::_emptyLongVec;\nvector<string>         XmlNode::_emptyStringVec;\nstring                 XmlNode::_emptyString;\nstd::vector<XmlNode *> XmlNode::_allocatedNodes;\n};    // namespace VAPoR\n\nnamespace {\n\nstring       TypeAttr = \"Type\";\nconst string LongType = \"Long\";\nconst string DoubleType = \"Double\";\nconst string StringType = \"String\";\n};    // namespace\n\nnamespace {\n\n\nstring escapeStr(string s)\n{\n    string eS;\n    for (int i = 0; i < s.length(); i++) {\n        if (s[i] == '<') {\n            eS += \"&lt;\";\n        } else if (s[i] == '>') {\n            eS += \"&gt;\";\n        } else if (s[i] == '\"') {\n            eS += \"&quot;\";\n        } else if (s[i] == '\\'') {\n            eS += \"&apos;\";\n        } else if (s[i] == '&') {\n            eS += \"&apos;\";\n        } else {\n            eS += s[i];\n        }\n    }\n    return (eS);\n}\n};    // namespace\n\nbool XmlNode::IsValidXMLElement(const string &s, int *badIdx)\n{\n    int _;\n    badIdx = badIdx?badIdx:&_;\n    *badIdx = 0;\n\n    if (s.empty()) return (false);\n    if (!(std::isalpha(s[0]) || s[0] == '_')) return (false);\n    for (string::const_iterator itr = s.begin(); itr != s.end(); ++itr) {\n        if (!(std::isalnum(*itr) || std::isdigit(*itr) || *itr == '-' || *itr == '_' || *itr == '.')) { return (false); }\n        if (isspace(*itr)) return (false);\n        ++*badIdx;\n    }\n\n    *badIdx = -1;\n    return (true);\n}\n\nstring XmlNode::SanitizeXMLTag(string s)\n{\n    if(s.empty())\n        return \"__empty__\";\n    int i;\n    while (!IsValidXMLElement(s, &i)) {\n        s = s.substr(0, i) + \"_\" + to_string((int)s[i]) + \"_\" + s.substr(i+1);\n    }\n    return s;\n}\n\nXmlNode::XmlNode(const string &tag, const map<string, string> &attrs, size_t numChildrenHint)\n{\n    VAssert(IsValidXMLElement(tag));\n\n    _longmap.clear();\n    _doublemap.clear();\n    _stringmap.clear();\n    _attrmap.clear();\n    _children.clear();\n    _tag.clear();\n    _asciiLimit = 1024;\n    _parent = NULL;\n\n    _tag = tag;\n    _attrmap = attrs;\n\n    if (numChildrenHint) _children.reserve(numChildrenHint);\n\n#ifdef MEMCHECK\n    _allocatedNodes.push_back(this);\n#endif\n}\n\nXmlNode::XmlNode(const string &tag, size_t numChildrenHint)\n{\n    VAssert(IsValidXMLElement(tag));\n\n    _longmap.clear();\n    _doublemap.clear();\n    _stringmap.clear();\n    _attrmap.clear();\n    _children.clear();\n    _tag.clear();\n    _asciiLimit = 1024;\n    _parent = NULL;\n\n    _tag = tag;\n\n    if (numChildrenHint) _children.reserve(numChildrenHint);\n\n#ifdef MEMCHECK\n    _allocatedNodes.push_back(this);\n#endif\n}\n\nXmlNode::XmlNode()\n{\n    _longmap.clear();\n    _doublemap.clear();\n    _stringmap.clear();\n    _attrmap.clear();\n    _children.clear();\n    _tag.clear();\n    _asciiLimit = 1024;\n    _parent = NULL;\n\n#ifdef MEMCHECK\n    _allocatedNodes.push_back(this);\n#endif\n}\n\nXmlNode::XmlNode(const XmlNode &rhs)\n: _longmap(rhs._longmap), _doublemap(rhs._doublemap), _stringmap(rhs._stringmap), _attrmap(rhs._attrmap), _children(rhs._children), _tag(rhs._tag), _asciiLimit(rhs._asciiLimit),\n  _parent(NULL)    // Set parent to NULL\n{\n    _children.clear();\n    for (int i = 0; i < rhs._children.size(); i++) { AddChild(rhs._children[i]); }\n\n#ifdef MEMCHECK\n    _allocatedNodes.push_back(this);\n#endif\n}\n\nXmlNode &XmlNode::operator=(const XmlNode &rhs)\n{\n    DeleteAll();\n    MyBase::operator=(rhs);\n\n    _children.clear();\n    _longmap = rhs._longmap;\n    _doublemap = rhs._doublemap;\n    _stringmap = rhs._stringmap;\n    _attrmap = rhs._attrmap;\n    _children = rhs._children;\n    _tag = rhs._tag;\n    _asciiLimit = rhs._asciiLimit;\n    _parent = NULL;    // Set parent to NULL\n\n    _children.clear();\n    for (int i = 0; i < rhs._children.size(); i++) { AddChild(rhs._children[i]); }\n\n    return (*this);\n}\n\nbool XmlNode::operator==(const XmlNode &rhs) const\n{\n    if (_longmap != rhs._longmap) return (false);\n    if (_doublemap != rhs._doublemap) return (false);\n    if (_stringmap != rhs._stringmap) return (false);\n    if (_attrmap != rhs._attrmap) return (false);\n    if (_tag != rhs._tag) return (false);\n\n    if (_children.size() != rhs._children.size()) return (false);\n    for (int i = 0; i < _children.size(); i++) {\n        // Recusrively call '==' operator\n        //\n        if (!(*(_children[i]) == *(rhs._children[i]))) return (false);\n    }\n\n    // Don't check parent!!!\n    //\n    // if (_parent != rhs._parent) return(false);\n\n    return (true);\n}\n\nXmlNode::~XmlNode()\n{\n    DeleteAll();\n\n#ifdef MEMCHECK\n    std::vector<XmlNode *>::iterator itr;\n    for (itr = _allocatedNodes.begin(); itr != _allocatedNodes.end(); ++itr) {\n        if (*itr == this) {\n            _allocatedNodes.erase(itr);\n            break;\n        }\n    }\n#endif\n}\n\nvoid XmlNode::SetElementLong(const string &tag, const vector<long> &values)\n{\n    VAssert(IsValidXMLElement(tag));\n    _longmap[tag] = values;\n}\n\nvoid XmlNode::SetElementLong(const vector<string> &tags, const vector<long> &values)\n{\n    VAssert(!tags.empty());\n\n    // Iterate through tags, finding associated node\n    XmlNode *currNode = this;\n    for (int i = 0; i < tags.size() - 1; i++) {\n        XmlNode *child = currNode->GetChild(tags[i]);\n        if (!child) { child = currNode->NewChild(tags[i]); }\n        currNode = child;\n    }\n\n    string tag = tags[tags.size() - 1];\n    VAssert(IsValidXMLElement(tag));\n    currNode->_longmap[tag] = values;\n}\n\nvoid XmlNode::SetElementDouble(const vector<string> &tags, const vector<double> &values)\n{\n    VAssert(!tags.empty());\n\n    // Iterate through tags, finding associated node\n    XmlNode *currNode = this;\n    for (int i = 0; i < tags.size() - 1; i++) {\n        XmlNode *child = currNode->GetChild(tags[i]);\n        if (!child) { child = currNode->NewChild(tags[i]); }\n        currNode = child;\n    }\n\n    string tag = tags[tags.size() - 1];\n    VAssert(IsValidXMLElement(tag));\n    currNode->_doublemap[tag] = values;\n}\n\nconst vector<long> &XmlNode::GetElementLong(const string &tag) const\n{\n    map<string, vector<long>>::const_iterator p = _longmap.find(tag);\n\n    // see if entry for this key (tag) already exists\n    //\n    if (p == _longmap.end()) { return (_emptyLongVec); }\n\n    return (p->second);\n}\n\nbool XmlNode::HasElementLong(const string &tag) const\n{\n    map<string, vector<long>>::const_iterator p = _longmap.find(tag);\n    return (p != _longmap.end());\n}\n\nvoid XmlNode::SetElementDouble(const string &tag, const vector<double> &values)\n{\n    VAssert(IsValidXMLElement(tag));\n    _doublemap[tag] = values;\n}\n\nconst vector<double> &XmlNode::GetElementDouble(const string &tag) const\n{\n    map<string, vector<double>>::const_iterator p = _doublemap.find(tag);\n\n    // see if entry for this key (tag) already exists\n    //\n    if (p == _doublemap.end()) { return (_emptyDoubleVec); }\n\n    return (p->second);\n}\n\nbool XmlNode::HasElementDouble(const string &tag) const\n{\n    if (_doublemap.empty()) return false;\n    map<string, vector<double>>::const_iterator p = _doublemap.find(tag);\n    return (p != _doublemap.end());\n}\n\nvoid XmlNode::SetElementString(const string &tag, const string &str)\n{\n    VAssert(IsValidXMLElement(tag));\n\n    _stringmap[tag] = str;\n}\n\nvoid XmlNode::SetElementStringVec(const string &tag, const vector<string> &strvec)\n{\n    VAssert(IsValidXMLElement(tag));\n\n    string s;\n    for (int i = 0; i < strvec.size(); i++) {\n        s.append(STLUtils::ReplaceAll(strvec[i], \" \", \"\\\\ \"));\n        if (i < strvec.size() - 1) s.append(\" \");\n    }\n\n    return (XmlNode::SetElementString(tag, s));\n}\n\nvoid XmlNode::SetElementStringVec(const vector<string> &tags, const vector<string> &strvec)\n{\n    VAssert(!tags.empty());\n\n    // Iterate through tags, finding associated node\n    XmlNode *currNode = this;\n    for (int i = 0; i < tags.size() - 1; i++) {\n        XmlNode *child = currNode->GetChild(tags[i]);\n        if (!child) { child = currNode->NewChild(tags[i]); }\n        currNode = child;\n    }\n    string tag = tags[tags.size() - 1];\n    VAssert(IsValidXMLElement(tag));\n\n    string s;\n    for (int i = 0; i < strvec.size(); i++) {\n        s.append(strvec[i]);\n        if (i < strvec.size() - 1) s.append(\" \");\n    }\n    return (currNode->SetElementString(tag, s));\n}\n\nconst string &XmlNode::GetElementString(const string &tag) const\n{\n    map<string, string>::const_iterator p = _stringmap.find(tag);\n\n    // see if entry for this key (tag) already exists\n    //\n    if (p == _stringmap.end()) { return (_emptyString); }\n\n    return (p->second);\n}\n\nvoid XmlNode::GetElementStringVec(const string &tag, vector<string> &vec) const\n{\n    string s = XmlNode::GetElementString(tag);\n    StrToWordVec(s, vec);\n    for (string &e : vec) e = STLUtils::ReplaceAll(e, \"\\\\ \", \" \");\n}\n\nbool XmlNode::HasElementString(const string &tag) const\n{\n    map<string, string>::const_iterator p = _stringmap.find(tag);\n    return (p != _stringmap.end());\n}\n\nXmlNode *XmlNode::NewChild(const string &tag, const map<string, string> &attrs, size_t numChildrenHint)\n{\n    // Delete duplicates\n    //\n    if (HasChild(tag)) { DeleteChild(tag); }\n\n    XmlNode *mychild = Construct(tag, attrs, numChildrenHint);\n\n    mychild->_parent = this;\n\n    _children.push_back(mychild);\n    return (mychild);\n}\n\nXmlNode *XmlNode::AddChild(const XmlNode *child) { return (AddChild(*child)); }\n\nXmlNode *XmlNode::AddChild(const XmlNode &child)\n{\n    XmlNode *mychild = new XmlNode(child);\n\n    // Delete duplicates\n    //\n    if (HasChild(mychild->Tag())) { DeleteChild(mychild->Tag()); }\n\n    mychild->_parent = this;\n\n    _children.push_back(mychild);\n    return (mychild);\n}\n\n#ifdef VAPOR3_0_0_ALPHA\nint XmlNode::ReplaceChild(XmlNode *prevChildNode, XmlNode *newChildNode)\n{\n    for (int index = 0; index < _children.size(); index++) {\n        XmlNode *node = _children[index];\n        if (node == prevChildNode) {\n            delete node;\n            _children[index] = new XmlNode(*newChildNode);\n            newChildNode->_parent = this;\n\n            return index;\n        }\n    }\n    SetErrMsg(\"Node not found\");\n    return (-1);\n}\n#endif\n\nint XmlNode::DeleteChild(size_t index)\n{\n    if (index >= _children.size()) {\n        SetErrMsg(\"Invalid child id : %d\", index);\n        return (-1);\n    }\n\n    XmlNode *node = _children[index];\n    VAssert(node);\n\n    // Remove from parent's list of children and\n    // recursively delete this node's children, if any\n    //\n    node->SetParent(NULL);\n    delete node;\n\n    return (0);\n}\n\nint XmlNode::DeleteChild(const string &tag)\n{\n    XmlNode *child;\n\n    for (size_t i = 0; i < _children.size(); i++) {\n        child = GetChild(i);\n        VAssert(child);\n\n        if (child->_tag == tag) { return (XmlNode::DeleteChild(i)); }\n    }\n\n    SetErrMsg(\"Invalid child name (does not exist) : %s\", tag.c_str());\n    return (-1);\n}\n\nXmlNode *XmlNode::GetChild(size_t index) const\n{\n    if (index >= _children.size()) {\n        SetErrMsg(\"Invalid child id : %d\", index);\n        return (NULL);\n    }\n\n    return (_children[index]);\n}\n\nbool XmlNode::HasChild(size_t index) const { return (index < _children.size()); }\n\nXmlNode *XmlNode::GetChild(const string &tag) const\n{\n    XmlNode *child;\n\n    for (size_t i = 0; i < _children.size(); i++) {\n        if (!(child = GetChild(i))) return (NULL);\n\n        if (child->_tag == tag) return (child);\n    }\n\n    return (NULL);\n}\n\nbool XmlNode::HasChild(const string &tag) const\n{\n    XmlNode *child = NULL;\n\n    for (size_t i = 0; i < _children.size(); i++) {\n        child = GetChild(i);\n        VAssert(child != NULL);\n\n        if (child->_tag == tag) return (true);\n    }\n    return (false);\n}\n\nXmlNode *XmlNode::GetNode(std::vector<string> path, bool absolute) const\n{\n    if (path.empty()) return (NULL);\n\n    const XmlNode *node = this;\n\n    // If absolute path find the root of the tree\n    //\n    if (absolute) {\n        while (node->GetParent() != NULL) { node = node->GetParent(); }\n        if (node->GetTag() != path[0]) return (NULL);\n        path.erase(path.begin());\n    }\n\n    // Now walk the path down to the last node in the path\n    //\n    for (int i = 0; i < path.size(); i++) {\n        if (!node->HasChild(path[i])) return (NULL);\n\n        node = node->GetChild(path[i]);\n    }\n\n    return ((XmlNode *)node);\n}\n\nXmlNode *XmlNode::GetNode(string path) const\n{\n    if (path.empty()) return (NULL);\n\n    vector<string> pathvec;\n    Wasp::SplitString(path, '/', pathvec);\n\n    // Absolute or relative path?\n    //\n    if (path[0] == '/') {\n        return (GetNode(pathvec, true));\n    } else {\n        return (GetNode(pathvec, false));\n    }\n}\n\nvoid XmlNode::SetParent(XmlNode *parent)\n{\n    // No-op case\n    //\n    if (parent == _parent) return;\n\n    // Delete duplicates on new parent\n    //\n    if (parent && parent->HasChild(Tag())) { parent->DeleteChild(Tag()); }\n\n    // Remove from current parent's list of children\n    //\n    if (_parent) {\n        vector<XmlNode *>::iterator itr = _parent->_children.begin();\n        for (; itr != _parent->_children.end(); ++itr) {\n            XmlNode *node = *itr;\n            if (node->Tag() == Tag()) {\n                _parent->_children.erase(itr);\n                break;\n            }\n        }\n    }\n\n    // If new parent is not NULL\n    //\n    if (parent) { parent->_children.push_back(this); }\n\n    _parent = parent;\n}\n\n// Recursively delete all descendants of this node\n//\nvoid XmlNode::DeleteAll()\n{\n    for (int i = 0; i < (int)_children.size(); i++) {\n        if (_children[i]) {\n            XmlNode *node = _children[i];\n            VAssert(node);\n\n            delete node;\n        }\n    }\n    _children.clear();\n}\n\nvector<string> XmlNode::GetPathVec() const\n{\n    vector<string> path;\n    path.push_back(GetTag());\n\n    const XmlNode *child = this;\n    const XmlNode *parent = NULL;\n    while ((parent = child->GetParent()) != NULL) {\n        path.push_back(parent->GetTag());\n        child = parent;\n    }\n\n    // Reverse so root is first\n    //\n    reverse(path.begin(), path.end());\n\n    return (path);\n}\n\nstring XmlNode::GetPath() const\n{\n    vector<string> tags = GetPathVec();\n    string         path;\n\n    for (int i = 0; i < tags.size(); i++) {\n        path += \"/\";\n        path += tags[i];\n    }\n    return (path);\n}\n\nXmlNode *XmlNode::GetRoot() const\n{\n    const XmlNode *node = this;    // Why must node be const?\n    while (node->GetParent()) { node = node->GetParent(); }\n    return ((XmlNode *)node);\n}\n\nostream &XmlNode::streamOut(ostream &os, const XmlNode &node)\n{\n    os << node;\n    return os;\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(ostream &os, const VAPoR::XmlNode &node)\n{\n    map<string, vector<long>>::const_iterator   plong;\n    map<string, vector<double>>::const_iterator pdouble;\n    map<string, string>::const_iterator         pstring;\n    map<string, string>::const_iterator         pattr;\n\n    int i;\n\n    //\tos.setf(ios_base::scientific, ios_base::floatfield);\n    os.precision(16);\n\n    plong = node._longmap.begin();\n    pdouble = node._doublemap.begin();\n    pstring = node._stringmap.begin();\n    pattr = node._attrmap.begin();\n\n    os << \"<\" << node._tag;\n\n    for (; pattr != node._attrmap.end(); pattr++) {\n        const string &name = pattr->first;\n        const string &value = pattr->second;\n\n        os << \" \" << name << \"=\\\"\" << value << \"\\\" \";\n    }\n    os << \">\" << endl;\n\n    for (; plong != node._longmap.end(); plong++) {\n        const string &tag = plong->first;\n\n        const vector<long> &v = plong->second;\n\n        os << \"<\" << tag << \" Type=\\\"Long\\\">\" << endl;\n\n        for (i = 0; i < (int)v.size(); i++) { os << v[i] << \" \"; }\n        os << endl;\n\n        os << \"</\" << tag << \">\" << endl;\n    }\n\n    for (; pdouble != node._doublemap.end(); pdouble++) {\n        const string &tag = pdouble->first;\n\n        os << \"<\" << tag << \" Type=\\\"Double\\\">\" << endl;\n\n        const vector<double> &v = pdouble->second;\n\n        for (i = 0; i < (int)v.size(); i++) { os << v[i] << \" \"; }\n        os << endl;\n\n        os << \"</\" << tag << \">\" << endl;\n    }\n\n    for (; pstring != node._stringmap.end(); pstring++) {\n        const string &tag = pstring->first;\n\n        os << \"<\" << tag << \" Type=\\\"String\\\">\" << endl;\n\n        string v = escapeStr(pstring->second);\n\n        os << v;\n\n        os << endl;\n\n        os << \"</\" << tag << \">\" << endl;\n    }\n\n    if (node._children.size()) {\n        for (int i = 0; i < (int)node._children.size(); i++) {\n            XmlNode *childptr;\n\n            childptr = node._children[i];\n            os << *childptr;\n        }\n    }\n\n    os << \"</\" << node._tag << \">\" << endl;\n\n    return (os);\n}\n\nvoid _StartElementHandler(void *userData, const char *tag, const char **attrs)\n{\n    XmlParser *parser = (XmlParser *)userData;\n    string     mytag(tag);\n\n    map<string, string> myattrs;\n    while (*attrs) {\n        string key = *attrs;\n        attrs++;\n        VAssert(*attrs);\n        string value = *attrs;\n        attrs++;\n        myattrs[key] = value;\n    }\n    parser->_startElementHandler(mytag, myattrs);\n}\n\nvoid _EndElementHandler(void *userData, const char *tag)\n{\n    XmlParser *parser = (XmlParser *)userData;\n    string     mytag(tag);\n\n    parser->_endElementHandler(mytag);\n}\n\nvoid _CharDataHandler(void *userData, const char *s, int len)\n{\n    XmlParser *parser = (XmlParser *)userData;\n    string     mys(s, len);\n\n    parser->_charDataHandler(mys);\n}\n\n};    // namespace VAPoR\n\nXmlParser::XmlParser()\n{\n    _root = NULL;\n    _nodeType = UNKNOWN;\n    //_nodeStack.clear(); // No stack clear! Sigh\n    _stringData.clear();\n}\n\nint XmlParser::LoadFromFile(XmlNode *node, string path)\n{\n    ifstream in(path);\n    if (!in) {\n        SetErrMsg(\"Failed to open file %s : %M\", path.c_str());\n        return (-1);\n    }\n\n    int rc = LoadFromFile(node, in);\n    in.close();\n\n    if (rc < 0 || in.bad() || !_nodeStack.empty()) {\n        SetErrMsg(\"IO Error reading XML file\");\n        return (-1);\n    }\n\n    return (0);\n}\n\nint XmlParser::LoadFromFile(XmlNode *node, istream &in)\n{\n    VAssert(node != NULL);\n\n    _root = node;\n    _nodeType = UNKNOWN;\n    _stringData.clear();\n\n    //_nodeStack.clear();\n    while (_nodeStack.size()) _nodeStack.pop();\n\n    // Delete all current children\n    //\n    _root->DeleteAll();\n\n    XML_Parser expatParser = XML_ParserCreate(NULL);\n    VAssert(expatParser != NULL);\n\n    XML_SetElementHandler(expatParser, _StartElementHandler, _EndElementHandler);\n    XML_SetCharacterDataHandler(expatParser, _CharDataHandler);\n\n    XML_SetUserData(expatParser, (void *)this);\n\n    // Parse the file until we run out of elements or a parsing error occurs\n    //\n    char line[1024];\n    while (in.good()) {\n        int rc;\n        in.read(line, sizeof(line) - 1);\n        if ((rc = in.gcount()) > 0) {\n            if (XML_Parse(expatParser, line, rc, 0) == XML_STATUS_ERROR) {\n                SetErrMsg(\"Error parsing xml file at line %d : %s\", XML_GetCurrentLineNumber(expatParser), XML_ErrorString(XML_GetErrorCode(expatParser)));\n                XML_ParserFree(expatParser);\n                return (-1);\n            }\n        }\n    }\n    XML_ParserFree(expatParser);\n\n    return 0;\n}\n\nvoid XmlParser::_startElementHandler(string tag, map<string, string> &myattrs)\n{\n    _nodeType = UNKNOWN;\n    _stringData.clear();\n\n    type dtype;\n    if (_isParentElement(tag, myattrs)) {\n        _nodeType = PARENT;\n        XmlNode *parent = NULL;\n        if (_nodeStack.empty()) {\n            parent = _root;\n            parent->Tag() = tag;\n            parent->Attrs() = myattrs;\n            _nodeStack.push(parent);\n        } else {\n            XmlNode child(tag, myattrs);\n            parent = _nodeStack.top();\n            XmlNode *childptr = parent->AddChild(&child);\n            _nodeStack.push(childptr);\n        }\n    } else if (_isDataElement(tag, myattrs, dtype)) {\n        VAssert(!_nodeStack.empty());\n        _nodeType = dtype;\n    }\n    // cout << \"_startElementHandler() tag, type \" << tag << \" \" << _nodeType << endl;\n}\n\nvoid XmlParser::_endElementHandler(string tag)\n{\n    VAssert(!_nodeStack.empty());\n\n    // cout << \"_endElementHandler() tag, type /\" << tag << \" \" << _nodeType << endl;\n\n    // remove leading and trailing white space from the XML char data\n    //\n    StrRmWhiteSpace(_stringData);\n\n    XmlNode *node = _nodeStack.top();\n\n    switch (_nodeType) {\n    case PARENT:\n        VAssert(tag == node->Tag());\n        _nodeStack.pop();\n        break;\n\n    case LONG_DATA: {\n        istringstream ist(_stringData);\n        long          v;\n        vector<long>  values;\n        while (ist >> v) values.push_back(v);\n\n        node->SetElementLong(tag, values);\n        break;\n    }\n    case DOUBLE_DATA: {\n        istringstream  ist(_stringData);\n        double         v;\n        vector<double> values;\n        while (ist >> v) values.push_back(v);\n\n        node->SetElementDouble(tag, values);\n        break;\n    }\n    case STRING_DATA: node->SetElementString(tag, _stringData); break;\n    default: VAssert(0);\n    }\n    _nodeType = PARENT;\n}\n\nvoid XmlParser::_charDataHandler(string s)\n{\n    if (!(_nodeType == LONG_DATA || _nodeType == DOUBLE_DATA || _nodeType == STRING_DATA)) return;\n\n    // cout << \"_CharDataHandler() : \" << \"\\\"\"<<s<<\"\\\"\" << endl;\n\n    _stringData.append(s);\n}\n\nbool XmlParser::_isParentElement(string tag, map<string, string> myattrs) const\n{\n    type dtype;\n\n    if (_isDataElement(tag, myattrs, dtype)) return (false);\n\n    return (true);\n}\n\nbool XmlParser::_isDataElement(string tag, map<string, string> myattrs, type &dtype) const\n{\n    dtype = UNKNOWN;\n\n    if (myattrs.size() != 1) return false;\n\n    map<string, string>::const_iterator itr = myattrs.begin();\n    if (StrCmpNoCase(itr->first, TypeAttr) != 0) return false;\n\n    if (StrCmpNoCase(itr->second, LongType) == 0) {\n        dtype = LONG_DATA;\n        return true;\n    } else if (StrCmpNoCase(itr->second, DoubleType) == 0) {\n        dtype = DOUBLE_DATA;\n        return true;\n    } else if (StrCmpNoCase(itr->second, StringType) == 0) {\n        dtype = STRING_DATA;\n        return true;\n    }\n\n    return (false);\n}\n"
  },
  {
    "path": "lib/params/regionparams.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tregionparams.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tSeptember 2004\n//\n//\tDescription:\tImplements the RegionParams class.\n//\t\tThis class supports parameters associted with the\n//\t\tregion panel\n//\n#ifdef WIN32\n    // Annoying unreferenced formal parameter warning\n    #pragma warning(disable : 4100)\n#endif\n\n#include <iostream>\n\n#include <vapor/regionparams.h>\n\nusing namespace VAPoR;\n\nconst string RegionParams::_domainVariablesTag = \"DomainVariables\";\n\n//\n// Register class with object factory!!!\n//\nstatic ParamsRegistrar<RegionParams> registrar(RegionParams::GetClassType());\n\nRegionParams::RegionParams(ParamsBase::StateSave *ssave) : ParamsBase(ssave, RegionParams::GetClassType())\n{\n    // Initialize DataMgr dependent parameters\n    //\n    _init();\n\n    m_Box = new Box(ssave);\n    m_Box->SetParent(this);\n}\n\nRegionParams::RegionParams(ParamsBase::StateSave *ssave, XmlNode *node) : ParamsBase(ssave, node)\n{\n    if (node->HasChild(Box::GetClassType())) {\n        m_Box = new Box(ssave, node->GetChild(Box::GetClassType()));\n    } else {\n        // Node doesn't contain a Box\n        //\n        m_Box = new Box(ssave);\n        m_Box->SetParent(this);\n    }\n\n    _reconcile();\n}\n\nRegionParams::RegionParams(const RegionParams &rhs) : ParamsBase(rhs) { m_Box = new Box(*(rhs.m_Box)); }\n\nRegionParams &RegionParams::operator=(const RegionParams &rhs)\n{\n    if (m_Box) delete m_Box;\n\n    ParamsBase::operator=(rhs);\n\n    m_Box = new Box(*(rhs.m_Box));\n\n    return (*this);\n}\n\nRegionParams::~RegionParams()\n{\n    if (m_Box) delete m_Box;\n}\n\n// Reset region settings to initial state\nvoid RegionParams::_init()\n{\n#ifdef VAPOR3_0_0_ALPHA\n    const double * extents = m_dataStatus->getLocalExtents();\n    vector<double> exts(3, 0.0);\n\n    for (i = 0; i < 3; i++) { exts.push_back(extents[i + 3] - extents[i]); }\n    GetBox()->SetLocalExtents(exts);\n    GetBox()->Trim();\n\n    vector<string> novars;\n    SetDomainVariables(novars);\n#endif\n}\n\nvoid RegionParams::_reconcile()\n{\n#ifdef VAPOR3_0_0_ALPHA\n    vector<long> times = GetBox()->GetTimes();\n    double       regionExtents[6];\n    for (int timenum = 0; timenum < times.size(); timenum++) {\n        int currTime = times[timenum];\n        GetBox()->GetLocalExtents(regionExtents, currTime);\n\n        // force them to fit in current volume\n        for (i = 0; i < 3; i++) {\n            if (regionExtents[i] > extents[i + 3] - extents[i]) regionExtents[i] = extents[i + 3] - extents[i];\n            if (regionExtents[i] < 0.) regionExtents[i] = 0.;\n            if (regionExtents[i + 3] > extents[i + 3] - extents[i]) regionExtents[i + 3] = extents[i + 3] - extents[i];\n            if (regionExtents[i + 3] < 0.) regionExtents[i + 3] = 0.;\n            if (regionExtents[i] > regionExtents[i + 3]) regionExtents[i + 3] = regionExtents[i];\n        }\n        exts.clear();\n        for (int j = 0; j < 6; j++) exts.push_back(regionExtents[j]);\n        GetBox()->SetLocalExtents(exts, this, currTime);\n    }\n#endif\n}\n\n#ifdef VAPOR3_0_0_ALPHA\nbool RegionParams::insertTime(int timestep) { return true; }\n\nbool RegionParams::removeTime(int timestep) { return true; }\n#endif\n"
  },
  {
    "path": "lib/render/AnnotationRenderer.cpp",
    "content": "//-- AnnotationRenderer.cpp ----------------------------------------------------------\n//\n//\t\t\t\t   Copyright (C)  2015\n//\t University Corporation for Atmospheric Research\n//\t\t\t\t   All Rights Reserved\n//\n//----------------------------------------------------------------------------\n//\n//\t  File:\t\t   AnnotationRenderer.cpp\n//\n//\t  Author:\t\t Alan Norton\n//\n//\t  Description:  Implementation of AnnotationRenderer class\n//\n//----------------------------------------------------------------------------\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <cstdlib>\n#include <cstdio>\n#include <cstring>\n#include <cfloat>\n#include <numeric>\n#include <sstream>\n#include <iomanip>\n\n#ifndef WIN32\n    #include <unistd.h>\n#endif\n\n#include <glm/glm.hpp>\n#include <glm/gtc/matrix_transform.hpp>\n#include <vapor/DataStatus.h>\n#include <vapor/AnnotationRenderer.h>\n#include <vapor/ResourcePath.h>\n#include \"vapor/LegacyGL.h\"\n#include \"vapor/TextLabel.h\"\n#include \"vapor/AnnotationParams.h\"\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n\n#define X 0\n#define Y 1\n#define Z 2\n\n#define ARROW_SCALE_FACTOR .25\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nAnnotationRenderer::AnnotationRenderer(const ParamsMgr *pm, const DataStatus *dataStatus, string winName)\n{\n    m_paramsMgr = pm;\n    m_dataStatus = dataStatus;\n    m_winName = winName;\n    _glManager = nullptr;\n\n    _currentTimestep = 0;\n\n    _fontName = \"arimo\";\n    _fontFile = GetSharePath(\"fonts/\" + _fontName + \".ttf\");\n}\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nAnnotationRenderer::~AnnotationRenderer()\n{\n#ifdef VAPOR3_0_0_ALPHA\n    if (_textObjectsValid) invalidateCache();\n#endif\n}\n\nvoid AnnotationRenderer::InitializeGL(GLManager *glManager) { _glManager = glManager; }\n\nvoid AnnotationRenderer::drawDomainFrame(std::vector<double> corners) const\n{\n    assert(corners.size() == 6);\n\n    AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName);\n\n    std::vector<double> minExts = {corners[X], corners[Y], corners[Z]};\n    std::vector<double> maxExts = {corners[X + 3], corners[Y + 3], corners[Z + 3]};\n\n    int    i;\n    int    numLines[3];\n    double fullSize[3], modMin[3], modMax[3];\n\n    // Instead:  either have 2 or 1 lines in each dimension.  2 if the size is < 1/3\n    for (i = 0; i < minExts.size(); i++) {\n        double regionSize = maxExts[i] - minExts[i];\n\n        // Stretch size by 1%\n        fullSize[i] = (maxExts[i] - minExts[i]) * 1.01;\n        double mid = 0.5f * (maxExts[i] + minExts[i]);\n        modMin[i] = mid - 0.5f * fullSize[i];\n        modMax[i] = mid + 0.5f * fullSize[i];\n        if (regionSize < fullSize[i] * .3)\n            numLines[i] = 2;\n        else\n            numLines[i] = 1;\n    }\n\n    double clr[3];\n    vfParams->GetDomainColor(clr);\n    // glLineWidth(1);\n    // Now draw the lines.  Divide each dimension into numLines[dim] sections.\n\n    int x, y, z;\n    // Do the lines in each z-plane\n    // Turn on writing to the z-buffer\n    glDepthMask(GL_TRUE);\n    glEnable(GL_DEPTH_TEST);\n\n    LegacyGL *lgl = _glManager->legacy;\n    lgl->Color3f(clr[0], clr[1], clr[2]);\n    lgl->Begin(GL_LINES);\n    for (z = 0; z <= numLines[2]; z++) {\n        float zCrd = modMin[2] + ((float)z / (float)numLines[2]) * fullSize[2];\n        // Draw lines in x-direction for each y\n        for (y = 0; y <= numLines[1]; y++) {\n            float yCrd = modMin[1] + ((float)y / (float)numLines[1]) * fullSize[1];\n\n            lgl->Vertex3f(modMin[0], yCrd, zCrd);\n            lgl->Vertex3f(modMax[0], yCrd, zCrd);\n        }\n        // Draw lines in y-direction for each x\n        for (x = 0; x <= numLines[0]; x++) {\n            float xCrd = modMin[0] + ((float)x / (float)numLines[0]) * fullSize[0];\n\n            lgl->Vertex3f(xCrd, modMin[1], zCrd);\n            lgl->Vertex3f(xCrd, modMax[1], zCrd);\n        }\n    }\n    // Do the lines in each y-plane\n\n    for (y = 0; y <= numLines[1]; y++) {\n        float yCrd = modMin[1] + ((float)y / (float)numLines[1]) * fullSize[1];\n        // Draw lines in x direction for each z\n        for (z = 0; z <= numLines[2]; z++) {\n            float zCrd = modMin[2] + ((float)z / (float)numLines[2]) * fullSize[2];\n\n            lgl->Vertex3f(modMin[0], yCrd, zCrd);\n            lgl->Vertex3f(modMax[0], yCrd, zCrd);\n        }\n        // Draw lines in z direction for each x\n        for (x = 0; x <= numLines[0]; x++) {\n            float xCrd = modMin[0] + ((float)x / (float)numLines[0]) * fullSize[0];\n\n            lgl->Vertex3f(xCrd, yCrd, modMin[2]);\n            lgl->Vertex3f(xCrd, yCrd, modMax[2]);\n        }\n    }\n\n    // Do the lines in each x-plane\n    for (x = 0; x <= numLines[0]; x++) {\n        float xCrd = modMin[0] + ((float)x / (float)numLines[0]) * fullSize[0];\n        // Draw lines in y direction for each z\n        for (z = 0; z <= numLines[2]; z++) {\n            float zCrd = modMin[2] + ((float)z / (float)numLines[2]) * fullSize[2];\n\n            lgl->Vertex3f(xCrd, modMin[1], zCrd);\n            lgl->Vertex3f(xCrd, modMax[1], zCrd);\n        }\n        // Draw lines in z direction for each y\n        // Draw lines in z direction for each y\n        for (y = 0; y <= numLines[1]; y++) {\n            float yCrd = modMin[1] + ((float)y / (float)numLines[1]) * fullSize[1];\n\n            lgl->Vertex3f(xCrd, yCrd, modMin[2]);\n            lgl->Vertex3f(xCrd, yCrd, modMax[2]);\n        }\n    }\n    lgl->End();\n\n    glEnable(GL_DEPTH_TEST);\n    glDepthMask(GL_FALSE);\n}\n\nvoid AnnotationRenderer::DrawText()\n{\n    _glManager->PixelCoordinateSystemPush();\n\n    DrawText(_miscAnnot);\n    _drawTimeAnnotation();\n    DrawText(_axisAnnot);\n\n\n    _glManager->PixelCoordinateSystemPop();\n}\n\nvoid AnnotationRenderer::_drawTimeAnnotation()\n{\n    AnnotationParams *params = m_paramsMgr->GetAnnotationParams(m_winName);\n    // size_t            ts = params->GetCurrentTimestep();\n\n    std::string timeText;\n    auto        type = params->GetValueLong(AnnotationParams::_timeTypeTag, 0);\n\n    if (type == 0) {\n        ClearText(1);\n    } else if (type == 1) {    // drawTimeStep\n        timeText = \"Timestep: \" + std::to_string(_currentTimestep);\n    } else if (type == 2) {    // drawTimeUser()\n        vector<double>     timeCoords = m_dataStatus->GetTimeCoordinates();\n        std::ostringstream ss;\n        ss << timeCoords[_currentTimestep];\n        timeText = ss.str();\n    } else if (type == 3) {    // drawTimeStamp()\n        timeText = m_dataStatus->GetTimeCoordsFormatted()[_currentTimestep];\n    }\n\n\n    billboard board;\n    board.text = timeText;\n    board.xn = params->GetValueDouble(AnnotationParams::_timeLLXTag, 0.01);\n    board.yn = params->GetValueDouble(AnnotationParams::_timeLLYTag, 0.01);\n    board.x = 0;\n    board.y = 0;\n    board.size = params->GetValueLong(AnnotationParams::_timeSizeTag, 24.);\n    std::vector<double> color = params->GetValueDoubleVec(AnnotationParams::_timeColorTag, {1.0, 1.0, 1.0});\n    board.color[0] = color[0];\n    board.color[1] = color[1];\n    board.color[2] = color[2];\n\n    DrawText({board});\n}\n\nvoid AnnotationRenderer::DrawText(vector<billboard> billboards)\n{\n    float txtColor[] = {1.f, 1.f, 1.f, 1.f};\n    float bgColor[] = {0.f, 0.f, 0.f, 0.f};\n    float coords[] = {67.5f, 31.6f, 0.f};\n\n    auto size = _glManager->GetViewportSize();\n\n    for (int i = 0; i < billboards.size(); i++) {\n        string text = billboards[i].text;\n\n        if (billboards[i].x == 0 && billboards[i].y == 0) {\n            coords[0] = billboards[i].xn * size.x;\n            coords[1] = billboards[i].yn * size.y;\n        } else {\n            coords[0] = billboards[i].x;\n            coords[1] = billboards[i].y;\n        }\n        int size = billboards[i].size;\n        txtColor[0] = billboards[i].color[0];\n        txtColor[1] = billboards[i].color[1];\n        txtColor[2] = billboards[i].color[2];\n\n        TextLabel label(_glManager, _fontName, size);\n        label.ForegroundColor = glm::make_vec4(txtColor);\n        label.BackgroundColor = glm::make_vec4(bgColor);\n        label.DrawText(glm::make_vec2(coords), text);\n    }\n}\n\nvoid AnnotationRenderer::AddText(string text, int x, int y, int size, float color[3], int type)\n{\n    //_billboards.clear();  // Temporary hack.  We eventually need separate\n    // billboard groups for time annotations, axis\n    // labels, etc.  Grouping them all in the same\n    // vector makes it hard if not impossible to\n    // make changes to any of the labels (color, size,\n    // etc)\n    billboard myBoard;\n    myBoard.text = text;\n    myBoard.x = x;\n    myBoard.y = y;\n    myBoard.xn = 0;\n    myBoard.yn = 0;\n    myBoard.size = size;\n    myBoard.color[0] = color[0];\n    myBoard.color[1] = color[1];\n    myBoard.color[2] = color[2];\n\n    if (type == 0) {    // Miscellaneous annotation\n        _miscAnnot.push_back(myBoard);\n    } else if (type == 1) {    // Time annotation\n        _timeAnnot.push_back(myBoard);\n    } else if (type == 2) {\n        _axisAnnot.push_back(myBoard);\n    }\n}\n\nvoid AnnotationRenderer::AddTextNormalizedCoords(string text, float x, float y, int size, float color[3], int type)\n{\n    billboard myBoard;\n    myBoard.text = text;\n    myBoard.x = 0;\n    myBoard.y = 0;\n    myBoard.xn = x;\n    myBoard.yn = y;\n    myBoard.size = size;\n    myBoard.color[0] = color[0];\n    myBoard.color[1] = color[1];\n    myBoard.color[2] = color[2];\n\n    if (type == 0) {    // Miscellaneous annotation\n        _miscAnnot.push_back(myBoard);\n    } else if (type == 1) {    // Time annotation\n        _timeAnnot.push_back(myBoard);\n    } else if (type == 2) {\n        _axisAnnot.push_back(myBoard);\n    }\n}\n\nvoid AnnotationRenderer::ClearText(int type)\n{\n    if (type == -1) {\n        _miscAnnot.clear();\n        _timeAnnot.clear();\n        _axisAnnot.clear();\n    }\n    if (type == 0) {\n        _miscAnnot.clear();\n    } else if (type == 1) {\n        _timeAnnot.clear();\n    } else if (type == 2) {\n        _axisAnnot.clear();\n    }\n}\n\nvoid AnnotationRenderer::applyTransform(Transform *t)\n{\n    vector<double> scale = t->GetScales();\n    vector<double> origin = t->GetOrigin();\n    vector<double> translate = t->GetTranslations();\n    vector<double> rotate = t->GetRotations();\n    VAssert(translate.size() == 3);\n    VAssert(rotate.size() == 3);\n    VAssert(scale.size() == 3);\n    VAssert(origin.size() == 3);\n\n    _glManager->matrixManager->Translate(translate[0], translate[1], translate[2]);\n\n    _glManager->matrixManager->Translate(origin[0], origin[1], origin[2]);\n\n    _glManager->matrixManager->Rotate(glm::radians(rotate[0]), 1, 0, 0);\n    _glManager->matrixManager->Rotate(glm::radians(rotate[1]), 0, 1, 0);\n    _glManager->matrixManager->Rotate(glm::radians(rotate[2]), 0, 0, 1);\n    _glManager->matrixManager->Scale(scale[0], scale[1], scale[2]);\n\n    _glManager->matrixManager->Translate(-origin[0], -origin[1], -origin[2]);\n}\n\nvoid AnnotationRenderer::_makeTransformMatrix(const Transform *transform, glm::mat4 &transformMatrix) const\n{\n    vector<double> scales = transform->GetScales();\n    vector<double> origins = transform->GetOrigin();\n    vector<double> translations = transform->GetTranslations();\n    vector<double> rotations = transform->GetRotations();\n\n    glm::mat4 m;\n\n    m = glm::translate(glm::mat4(1.f), glm::vec3(translations[X], translations[Y], translations[Z]));\n\n    m = glm::translate(m, glm::vec3(origins[X], origins[Y], origins[Z]));\n\n    m = glm::rotate(m, glm::radians((float)rotations[X]), glm::vec3(1.f, 0.f, 0.f));\n    m = glm::rotate(m, glm::radians((float)rotations[Y]), glm::vec3(0.f, 1.f, 0.f));\n    m = glm::rotate(m, glm::radians((float)rotations[Z]), glm::vec3(0.f, 0.f, 1.f));\n\n    m = glm::scale(m, glm::vec3(scales[X], scales[Y], scales[Z]));\n\n    m = glm::translate(m, glm::vec3(-origins[X], -origins[Y], -origins[Z]));\n\n    transformMatrix = m;\n}\n\nvoid AnnotationRenderer::_applyDataMgrCornerToDomain(std::vector<double> &domainExtents, const glm::vec4 &dataMgrCorner, const glm::mat4 &transformMatrix) const\n{\n    assert(domainExtents.size() == 6);\n\n    // transform our corner\n    glm::vec4 transformedCorner;\n    transformedCorner = transformMatrix * dataMgrCorner;\n\n    // See if the minimum and maximum extents of our corner exceed the\n    // the currently defined domain.\n    for (int i = 0; i < 6; i++) {\n        int transformedCornerIndex = i % 3;\n        // use this corner to define all domain corners that are uninitialized\n        if (std::isnan(domainExtents[i])) domainExtents[i] = transformedCorner[transformedCornerIndex];\n        // otherwise see if the corner exceeds our currently defined domain minima\n        else if (i < 3) {\n            if (transformedCorner[transformedCornerIndex] < domainExtents[i]) { domainExtents[i] = transformedCorner[transformedCornerIndex]; }\n        }\n        // otherwise see if the corner exceeds our currently defined domain maxima\n        else {\n            if (transformedCorner[transformedCornerIndex] > domainExtents[i]) { domainExtents[i] = transformedCorner[transformedCornerIndex]; }\n        }\n    }\n}\n\n// The lookup table below designates how the eight corners of the dataMgr are\n// defined.\n//\n// For example, corner# 3 will be comprised of the following dataMgr\n// extent values: { minX, maxY, maxZ}.  Corner#6 is { maxX, maxY, minZ}\n//\n//  X Y Z corner#\n//  0 0 0       0\n//  0 0 1       1\n//  0 1 0       2\n//  0 1 1       3\n//  1 0 0       4\n//  1 0 1       5\n//  1 1 0       6\n//  1 1 1       7\nvoid AnnotationRenderer::_getDataMgrCorner(const int cornerNumber, glm::vec4 &dataMgrCorner, const CoordType &minDataMgrExtents, const CoordType &maxDataMgrExtents) const\n{\n    assert(cornerNumber >= 0 && cornerNumber <= 7);\n\n    double xCoord, yCoord, zCoord;\n    if (cornerNumber & 0b100)\n        xCoord = maxDataMgrExtents[X];\n    else\n        xCoord = minDataMgrExtents[X];\n\n    if (cornerNumber & 0b010)\n        yCoord = maxDataMgrExtents[Y];\n    else\n        yCoord = minDataMgrExtents[Y];\n\n    if (cornerNumber & 0b001)\n        zCoord = maxDataMgrExtents[Z];\n    else\n        zCoord = minDataMgrExtents[Z];\n\n    dataMgrCorner = glm::vec4(xCoord, yCoord, zCoord, 1.f);\n}\n\nvoid AnnotationRenderer::_applyDataMgrToDomainExtents(std::vector<double> &domainExtents, const CoordType &dataMgrMinExts, const CoordType &dataMgrMaxExts, const Transform *transform) const\n{\n    assert(domainExtents.size() == 6);\n\n    glm::mat4 transformMatrix;\n    _makeTransformMatrix(transform, transformMatrix);\n\n    glm::vec4 dataMgrCorner;\n    for (int i = 0; i < 8; i++) {\n        _getDataMgrCorner(i, dataMgrCorner, dataMgrMinExts, dataMgrMaxExts);\n\n        _applyDataMgrCornerToDomain(domainExtents, dataMgrCorner, transformMatrix);\n    }\n}\n\nvoid AnnotationRenderer::_calculateDomainExtents(std::vector<double> &domainExtents) const\n{\n    domainExtents = {NAN, NAN, NAN, NAN, NAN, NAN};\n\n    vector<string> names = m_dataStatus->GetDataMgrNames();\n    for (int i = 0; i < names.size(); i++) {\n        CoordType dataMgrMinExts, dataMgrMaxExts;\n\n        m_dataStatus->GetActiveExtents(m_paramsMgr, m_winName, names[i], _currentTimestep, dataMgrMinExts, dataMgrMaxExts);\n\n        ViewpointParams *vpParams = m_paramsMgr->GetViewpointParams(m_winName);\n        Transform *      transform = vpParams->GetTransform(names[i]);\n        _applyDataMgrToDomainExtents(domainExtents, dataMgrMinExts, dataMgrMaxExts, transform);\n    }\n\n    for (int i = 0; i < 6; i++) {\n        if (std::isnan(domainExtents[i])) domainExtents[i] = 0.f;\n    }\n}\n\nvoid AnnotationRenderer::InScenePaint(size_t ts)\n{\n    AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName);\n    MatrixManager *   mm = _glManager->matrixManager;\n\n    _currentTimestep = ts;\n\n    ViewpointParams *vpParams = m_paramsMgr->GetViewpointParams(m_winName);\n\n    std::vector<double> domainExtents;\n    _calculateDomainExtents(domainExtents);\n\n    mm->MatrixModeModelView();\n    mm->PushMatrix();\n\n    if (vfParams->GetUseDomainFrame()) drawDomainFrame(domainExtents);\n\n    vector<string> names = m_dataStatus->GetDataMgrNames();\n    Transform *    t = vpParams->GetTransform(names[0]);\n    applyTransform(t);\n\n    double mvMatrix[16];\n    mm->GetDoublev(MatrixManager::Mode::ModelView, mvMatrix);\n    vpParams->SetModelViewMatrix(mvMatrix);\n\n    AxisAnnotation *aa = vfParams->GetAxisAnnotation();\n    if (aa->GetAxisAnnotationEnabled()) { drawAxisTics(aa); }\n\n    mm->MatrixModeModelView();\n    mm->PopMatrix();\n\n    mm->GetDoublev(MatrixManager::Mode::ModelView, mvMatrix);\n    vpParams->SetModelViewMatrix(mvMatrix);\n\n    CheckGLErrorMsg(m_winName.c_str());\n}\n\nvoid AnnotationRenderer::scaleNormalizedCoordinatesToWorld(std::vector<double> &coords, string dataMgrName)\n{\n    std::vector<double> extents = getDomainExtents();\n    int                 dims = extents.size() / 2;\n    for (int i = 0; i < dims; i++) {\n        double offset = coords[i] * (extents[i + dims] - extents[i]);\n        double minimum = extents[i];\n        coords[i] = offset + minimum;\n    }\n}\n\nvoid AnnotationRenderer::drawAxisTics(AxisAnnotation *aa) { drawAxisTics(aa, std::vector<double>(), std::vector<double>()); }\n\nvoid AnnotationRenderer::drawAxisTics(AxisAnnotation *aa, std::vector<double> minTic, std::vector<double> maxTic)\n{\n    if (aa == NULL) aa = getCurrentAxisAnnotation();\n\n    if (minTic.empty()) minTic = aa->GetMinTics();\n    if (maxTic.empty()) maxTic = aa->GetMaxTics();\n\n    std::vector<double> origin = aa->GetAxisOrigin();\n\n    string dmName = aa->GetDataMgrName();\n    scaleNormalizedCoordinatesToWorld(origin, dmName);\n    scaleNormalizedCoordinatesToWorld(minTic, dmName);\n    scaleNormalizedCoordinatesToWorld(maxTic, dmName);\n\n    vector<double> ticLength = aa->GetTicSize();\n    vector<double> ticDir = aa->GetTicDirs();\n    vector<double> numTics = aa->GetNumTics();\n    vector<double> axisColor = aa->GetAxisColor();\n    double         width = aa->GetTicWidth();\n    bool           latLon = aa->GetLatLonAxesEnabled();\n\n    _drawAxes(minTic, maxTic, origin, axisColor, width);\n\n    double         pointOnAxis[3];\n    double         ticVec[3];\n    double         startPosn[3], endPosn[3];\n    vector<double> extents = getDomainExtents();\n\n    // Now draw tic marks for x:\n    pointOnAxis[1] = origin[1];\n    pointOnAxis[2] = origin[2];\n    ticVec[0] = 0.f;\n    ticVec[1] = 0.f;\n    ticVec[2] = 0.f;\n    double scaleFactor;\n    if (ticDir[0] == 1) {    // Y orientation\n        scaleFactor = extents[4] - extents[1];\n        ticVec[1] = ticLength[0] * scaleFactor;\n    } else {    // Z orientation\n        scaleFactor = extents[5] - extents[2];\n        ticVec[2] = ticLength[0] * scaleFactor;\n    }\n    // ticVec[1] = ticLength[1]*scaleFactor;\n    // ticVec[2] = ticLength[2]*scaleFactor;\n    for (int i = 0; i < numTics[0]; i++) {\n        pointOnAxis[0] = minTic[0] + (float)i * (maxTic[0] - minTic[0]) / (float)(numTics[0] - 1);\n        vsub(pointOnAxis, ticVec, startPosn);\n        vadd(pointOnAxis, ticVec, endPosn);\n\n        //_drawTic(startPosn, endPosn, length, width, axisColor);\n        _drawTic(startPosn, endPosn, width, axisColor);\n\n        double xValue = pointOnAxis[0];\n        double yValue = pointOnAxis[1];\n        if (latLon) convertPointToLonLat(xValue, yValue);\n        renderText(xValue, startPosn, aa);\n    }\n\n    // Now draw tic marks for y:\n    pointOnAxis[0] = origin[0];\n    pointOnAxis[2] = origin[2];\n    ticVec[0] = 0.f;\n    ticVec[1] = 0.f;\n    ticVec[2] = 0.f;\n    if (ticDir[1] == 2) {    // Z orientation\n        scaleFactor = extents[5] - extents[2];\n        ticVec[2] = ticLength[1] * scaleFactor;\n    } else {    // X orientation\n        scaleFactor = extents[4] - extents[1];\n        ticVec[0] = ticLength[1] * scaleFactor;\n    }\n    for (int i = 0; i < numTics[1]; i++) {\n        pointOnAxis[1] = minTic[1] + (float)i * (maxTic[1] - minTic[1]) / (float)(numTics[1] - 1);\n        vsub(pointOnAxis, ticVec, startPosn);\n        vadd(pointOnAxis, ticVec, endPosn);\n\n        _drawTic(startPosn, endPosn, width, axisColor);\n\n        double xValue = pointOnAxis[0];\n        double yValue = pointOnAxis[1];\n        if (latLon) convertPointToLonLat(xValue, yValue);\n        renderText(yValue, startPosn, aa);\n    }\n\n    // Now draw tic marks for z:\n    pointOnAxis[0] = origin[0];\n    pointOnAxis[1] = origin[1];\n    ticVec[0] = 0.f;\n    ticVec[1] = 0.f;\n    ticVec[2] = 0.f;\n    if (ticDir[2] == 1) {    // Y orientation\n        scaleFactor = extents[4] - extents[1];\n        ticVec[1] = ticLength[2] * scaleFactor;\n    } else {    // X orientation\n        scaleFactor = extents[3] - extents[0];\n        ticVec[0] = ticLength[2] * scaleFactor;\n    }\n    for (int i = 0; i < numTics[2]; i++) {\n        pointOnAxis[2] = minTic[2] + (float)i * (maxTic[2] - minTic[2]) / (float)(numTics[2] - 1);\n        vsub(pointOnAxis, ticVec, startPosn);\n        vadd(pointOnAxis, ticVec, endPosn);\n        _drawTic(startPosn, endPosn, width, axisColor);\n        renderText(pointOnAxis[2], startPosn, aa);\n    }\n}\n\nvoid AnnotationRenderer::_drawAxes(std::vector<double> min, std::vector<double> max, std::vector<double> origin, std::vector<double> color, double width)\n{\n    LegacyGL *lgl = _glManager->legacy;\n\n    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n    lgl->Color4f(color[0], color[1], color[2], color[3]);\n    // glLineWidth(width);\n    glEnable(GL_LINE_SMOOTH);\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3f(min[0], origin[1], origin[2]);\n    lgl->Vertex3f(max[0], origin[1], origin[2]);\n    lgl->Vertex3f(origin[0], min[1], origin[2]);\n    lgl->Vertex3f(origin[0], max[1], origin[2]);\n    lgl->Vertex3f(origin[0], origin[1], min[2]);\n    lgl->Vertex3f(origin[0], origin[1], max[2]);\n    lgl->End();\n    glDisable(GL_LINE_SMOOTH);\n}\n\nvoid AnnotationRenderer::_drawTic(double startPosn[], double endPosn[], double width, std::vector<double> color)\n{\n    LegacyGL *lgl = _glManager->legacy;\n    lgl->Color4f(color[0], color[1], color[2], color[3]);\n    // glLineWidth(width);\n    glEnable(GL_LINE_SMOOTH);\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3dv(startPosn);\n    lgl->Vertex3dv(endPosn);\n    lgl->End();\n    glDisable(GL_LINE_SMOOTH);\n}\n\nvoid AnnotationRenderer::convertPointToLonLat(double &xCoord, double &yCoord)\n{\n    double coords[2] = {xCoord, yCoord};\n    double coordsForError[2] = {coords[0], coords[1]};\n\n    string projString = m_dataStatus->GetMapProjection();\n    int    rc = DataMgrUtils::ConvertPCSToLonLat(projString, coords, 1);\n    if (!rc) { MyBase::SetErrMsg(\"Could not convert point %f, %f to Lon/Lat\", coordsForError[0], coordsForError[1]); }\n\n    xCoord = coords[0];\n    yCoord = coords[1];\n}\n\nTransform *AnnotationRenderer::getTransform(string dataMgrName)\n{\n    if (dataMgrName == \"\") dataMgrName = getCurrentDataMgrName();\n\n    ViewpointParams *vpParams = m_paramsMgr->GetViewpointParams(m_winName);\n    vector<string>   names = m_paramsMgr->GetDataMgrNames();\n    Transform *      t = vpParams->GetTransform(names[0]);\n    return t;\n}\n\nAxisAnnotation *AnnotationRenderer::getCurrentAxisAnnotation()\n{\n    AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName);\n    string            currentAxisDataMgr = vfParams->GetCurrentAxisDataMgrName();\n    AxisAnnotation *  aa = vfParams->GetAxisAnnotation();\n    return aa;\n}\n\nstring AnnotationRenderer::getCurrentDataMgrName() const\n{\n    AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName);\n    string            currentAxisDataMgr = vfParams->GetCurrentAxisDataMgrName();\n    return currentAxisDataMgr;\n}\n\nstd::vector<double> AnnotationRenderer::getDomainExtents() const\n{\n    CoordType minExts, maxExts;\n\n    m_dataStatus->GetActiveExtents(m_paramsMgr, _currentTimestep, minExts, maxExts);\n\n    std::vector<double> extents;\n    for (int i = 0; i < minExts.size(); i++) { extents.push_back(minExts[i]); }\n    for (int i = 0; i < maxExts.size(); i++) { extents.push_back(maxExts[i]); }\n\n    return extents;\n}\n\nvoid AnnotationRenderer::renderText(double text, double coord[], AxisAnnotation *aa)\n{\n    if (aa == NULL) aa = getCurrentAxisAnnotation();\n\n    std::vector<double> axisColor = aa->GetAxisColor();\n    std::vector<double> backgroundColor = aa->GetAxisBackgroundColor();\n    int                 fontSize = aa->GetAxisFontSize();\n\n    int               precision = (int)aa->GetAxisDigits();\n    std::stringstream ss;\n    ss << fixed << setprecision(precision) << text;\n    string textString = ss.str();\n\n    TextLabel label(_glManager, _fontName, fontSize);\n    label.HorizontalAlignment = TextLabel::Center;\n    label.VerticalAlignment = TextLabel::Top;\n    label.Padding = fontSize / 4.f;\n    label.ForegroundColor = glm::vec4(axisColor[0], axisColor[1], axisColor[2], axisColor[3]);\n    label.BackgroundColor = glm::vec4(backgroundColor[0], backgroundColor[1], backgroundColor[2], 1.);\n    label.DrawText(glm::vec3(coord[0], coord[1], coord[2]), textString);\n}\n\n// Find the world corrdinates of the user-selected screen coordinates, and translate the current matrix to that point\n//\nvoid AnnotationRenderer::_configureMatrixForArrows(MatrixManager *matrixManager)\n{\n    matrixManager->MatrixModeModelView();\n    matrixManager->PushMatrix();\n\n\n    // Calculate the pixel location on the screen from the user's value, which is between 0 and 1\n    //\n    AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName);\n    double            winX = vfParams->GetAxisArrowXPos();    // X position of arrows, between 0 and 1\n    double            winY = vfParams->GetAxisArrowYPos();    // Y position of arrows, between 0 and 1\n    // Scale the Params values by the window width/height\n    std::vector<int> viewport = _glManager->GetViewport();\n    winX = winX * viewport[2];    // viewport[2] is window width\n    winY = winY * viewport[3];    // viewport[3] is window hight\n\n    // Gather parameters for glm::unProject\n    //\n    // glm::unProject requires glm::mat4 for the modelview and projection matrices, so we need to\n    // convert from vapor's array representation to glm::mat4\n    double modelview[16], projection[16];\n    _glManager->matrixManager->GetDoublev(MatrixManager::Mode::ModelView, modelview);\n    _glManager->matrixManager->GetDoublev(MatrixManager::Mode::Projection, projection);\n    glm::mat4 mat4modelview = glm::make_mat4(modelview);\n    glm::mat4 mat4projection = glm::make_mat4(projection);\n\n    // glm::unProject requres a glm::vec4 for the viewport, so we need to convert it from its std::vector<int>\n    glm::vec4 vec4viewport(viewport[0], viewport[1], viewport[2], viewport[3]);\n\n    // Now un-project to find the world coordinates of the selected pixel, and and translate to it for drawing\n    //\n    glm::vec3 win = {winX, winY, .5};\n    glm::vec3 coords = glm::unProject(win, mat4modelview, mat4projection, vec4viewport);\n    _glManager->matrixManager->Translate(coords[0], coords[1], coords[2]);\n\n    // Finally, apply an scale factor that cancels the scaling done when zooming in and out, so that the arrows\n    // retain a constant size on the screen.  This code was derived from\n    // https://gamedev.stackexchange.com/questions/24968/constant-size-geometries with the exception of using\n    // glm::unproject instead of the deprecated gluUnProject function.\n    //\n    const double fov = m_paramsMgr->GetViewpointParams(m_winName)->GetFOV();\n    double       cameraPosD[3], cameraUpD[3], cameraDirD[3];\n    m_paramsMgr->GetViewpointParams(m_winName)->ReconstructCamera(modelview, cameraPosD, cameraUpD, cameraDirD);\n    glm::vec3 cameraPos = glm::vec3(cameraPosD[0], cameraPosD[1], cameraPosD[2]);\n    float     cameraObjectDistance = sqrt(pow(cameraPos[0] - coords[0], 2) + pow(cameraPos[1] - coords[1], 2) + pow(cameraPos[2] - coords[2], 2));\n    float     worldSize = (2 * tan(fov / 2.0)) * cameraObjectDistance;\n    float     size = vfParams->GetAxisArrowSize() * worldSize * ARROW_SCALE_FACTOR;\n    matrixManager->Scale(size, size, size);\n}\n\nvoid AnnotationRenderer::DrawAxisArrows()\n{\n    AnnotationParams *vfParams = m_paramsMgr->GetAnnotationParams(m_winName);\n    if (!vfParams->GetAxisArrowEnabled()) { return; }\n\n    LegacyGL *     lgl = _glManager->legacy;\n    MatrixManager *mm = _glManager->matrixManager;\n\n    _configureMatrixForArrows(mm);\n\n    glDepthMask(GL_FALSE);\n    glDisable(GL_DEPTH_TEST);\n\n    // Begin drawing\n    //\n    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n    lgl->Color3f(1, 0, 0);\n    glEnable(GL_LINE_SMOOTH);\n\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3f(0, 0, 0);\n    lgl->Vertex3f(1, 0, 0);\n    lgl->End();\n\n    lgl->Begin(GL_TRIANGLES);\n    lgl->Vertex3f(1, 0, 0);\n    lgl->Vertex3f(.8, .1, 0);\n    lgl->Vertex3f(.8, 0, .1);\n\n    lgl->Vertex3f(1, 0, 0);\n    lgl->Vertex3f(.8, 0, .1);\n    lgl->Vertex3f(.8, -.1, 0);\n\n    lgl->Vertex3f(1, 0, 0);\n    lgl->Vertex3f(.8, -.1, 0);\n    lgl->Vertex3f(.8, 0, -.1);\n\n    lgl->Vertex3f(1, 0, 0);\n    lgl->Vertex3f(.8, 0, -.1);\n    lgl->Vertex3f(.8, .1, 0);\n    lgl->End();\n\n    lgl->Color3f(0, 1, 0);\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3f(0, 0, 0);\n    lgl->Vertex3f(0, 1, 0);\n    lgl->End();\n\n    lgl->Begin(GL_TRIANGLES);\n    lgl->Vertex3f(0, 1, 0);\n    lgl->Vertex3f(.1, .8, 0);\n    lgl->Vertex3f(0, .8, .1);\n\n    lgl->Vertex3f(0, 1, 0);\n    lgl->Vertex3f(0, .8, .1);\n    lgl->Vertex3f(-.1, .8, 0);\n\n    lgl->Vertex3f(0, 1, 0);\n    lgl->Vertex3f(-.1, .8, 0);\n    lgl->Vertex3f(0, .8, -.1);\n\n    lgl->Vertex3f(0, 1, 0);\n    lgl->Vertex3f(0, .8, -.1);\n    lgl->Vertex3f(.1, .8, 0);\n    lgl->End();\n\n    lgl->Color3f(0, 0.3, 1);\n    lgl->Begin(GL_LINES);\n    lgl->Vertex3f(0, 0, 0);\n    lgl->Vertex3f(0, 0, 1);\n    lgl->End();\n\n    lgl->Begin(GL_TRIANGLES);\n    lgl->Vertex3f(0, 0, 1);\n    lgl->Vertex3f(.1, 0, .8);\n    lgl->Vertex3f(0, .1, .8);\n\n    lgl->Vertex3f(0, 0, 1);\n    lgl->Vertex3f(0, .1, .8);\n    lgl->Vertex3f(-.1, 0, .8);\n\n    lgl->Vertex3f(0, 0, 1);\n    lgl->Vertex3f(-.1, 0, .8);\n    lgl->Vertex3f(0, -.1, .8);\n\n    lgl->Vertex3f(0, 0, 1);\n    lgl->Vertex3f(0, -.1, .8);\n    lgl->Vertex3f(.1, 0, .8);\n    lgl->End();\n\n    glDepthRange(0, 1.0);\n\n    mm->PopMatrix();\n    glDisable(GL_LINE_SMOOTH);\n}\n"
  },
  {
    "path": "lib/render/BarbRenderer.cpp",
    "content": "//*************************************************************\n//\n// Copyright (C) 2017\n// University Corporation for Atmospheric Research\n// All Rights Reserved\n//\n// ************************************************************\n\n// Specify the barbhead width compared with barb diameter:\n#define BARB_HEAD_FACTOR 3.0\n\n// Specify how long the barb tube is, in front of where the\n// barbhead is attached:\n#define BARB_LENGTH_FACTOR 0.9\n\n// Specify the maximum cylinder radius in proportion to the\n// hypotenuse of the domain, divided by 4 (the maximum barb thicness param)\n// I.E. if the user sets the thickness to 4 (the maximum), then the\n// barbs will have max radius = 4 * BARB_RADIUS_TO_HYPOTENUSE * hypotenuse\n//#define BARB_RADIUS_TO_HYPOTENUSE .00625\n#define BARB_RADIUS_TO_HYPOTENUSE .001875\n\n// Specify the maximum barb length in proportion to the\n// hypotenuse of the domain, divided by 4 (the maximum barb length param)\n// I.E. if the user sets the length to 4 (the maximum), then the longest\n// barb will have max length = 4 * BARB_LENGTH_TO_HYPOTENUSE * hypotenuse\n#define BARB_LENGTH_TO_HYPOTENUSE .0625\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <cstdlib>\n#include <cstdio>\n#include <cstring>\n#include <limits>\n\n#ifndef WIN32\n    #include <unistd.h>\n#endif\n\n#include <vapor/DataStatus.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/BarbRenderer.h>\n#include <vapor/BarbParams.h>\n\n#include <vapor/regionparams.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/MyBase.h>\n#include <vapor/errorcodes.h>\n#include <vapor/DataMgr.h>\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n#include \"vapor/LegacyGL.h\"\n#include \"vapor/GLManager.h\"\n#include <glm/gtc/type_ptr.hpp>\n\n#define X    0\n#define Y    1\n#define Z    2\n#define XMIN 0\n#define YMIN 1\n#define ZMIN 2\n#define XMAX 3\n#define YMAX 4\n#define ZMAX 5\n\nint counter = 0;\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nstatic RendererRegistrar<BarbRenderer> registrar(BarbRenderer::GetClassType(), BarbParams::GetClassType());\n\nBarbRenderer::BarbRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, BarbParams::GetClassType(), BarbRenderer::GetClassType(), instName, dataMgr)\n{\n    _fieldVariables.clear();\n    _vectorScaleFactor = .2;\n    _maxThickness = .2;\n    _maxValue = 0.f;\n}\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nBarbRenderer::~BarbRenderer() {}\n\nstd::string BarbRenderer::_getColorbarVariableName() const\n{\n    RenderParams *rParams = GetActiveParams();\n    return rParams->GetColorMapVariableName();\n}\n\n// Totally unnecessary?\n//\nint BarbRenderer::_initializeGL()\n{\n    //_initialized = true;\n    return (0);\n}\n\nvoid BarbRenderer::_saveCacheParams()\n{\n    BarbParams *p = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(p);\n    _cacheParams.fieldVarNames = p->GetFieldVariableNames();\n    _cacheParams.heightVarName = p->GetHeightVariableName();\n    _cacheParams.colorVarName = p->GetColorMapVariableName();\n    _cacheParams.ts = p->GetCurrentTimestep();\n    _cacheParams.level = p->GetRefinementLevel();\n    _cacheParams.lod = p->GetCompressionLevel();\n    _cacheParams.grid = p->GetGrid();\n    _cacheParams.needToRecalc = p->GetNeedToRecalculateScales();\n    _cacheParams.useSingleColor = p->UseSingleColor();\n    p->GetBox()->GetExtents(_cacheParams.boxMin, _cacheParams.boxMax);\n}\n\nbool BarbRenderer::_isCacheDirty() const\n{\n    BarbParams *p = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(p);\n    if (_cacheParams.fieldVarNames != p->GetFieldVariableNames()) return true;\n    if (_cacheParams.heightVarName != p->GetHeightVariableName()) return true;\n    if (_cacheParams.colorVarName != p->GetColorMapVariableName()) return true;\n    if (_cacheParams.ts != p->GetCurrentTimestep()) return true;\n    if (_cacheParams.level != p->GetRefinementLevel()) return true;\n    if (_cacheParams.lod != p->GetCompressionLevel()) return true;\n    if (_cacheParams.grid != p->GetGrid()) return true;\n    if (_cacheParams.needToRecalc != p->GetNeedToRecalculateScales()) return true;\n    if (_cacheParams.useSingleColor != p->UseSingleColor()) return true;\n\n    vector<double> min, max, contourValues;\n    p->GetBox()->GetExtents(min, max);\n\n    if (_cacheParams.boxMin != min) return true;\n    if (_cacheParams.boxMax != max) return true;\n\n    return false;\n}\n\nvoid BarbRenderer::_recalculateScales(\n    // std::vector<string> varnames,\n    std::vector<VAPoR::Grid *> &varData, int ts)\n{\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n\n    vector<string> varnames = bParams->GetFieldVariableNames();\n    bool           recalculateScales = bParams->GetNeedToRecalculateScales();\n\n    if (varnames != _fieldVariables || recalculateScales) {\n        //_setDefaultLengthAndThicknessScales(ts, varnames, bParams);\n        _setDefaultLengthAndThicknessScales(ts, varData, bParams);\n        _fieldVariables = varnames;\n        bParams->SetNeedToRecalculateScales(false);\n    }\n}\n\nint BarbRenderer::_getVectorVarGrids(int ts, int refLevel, int lod, CoordType minExts, CoordType maxExts, std::vector<VAPoR::Grid *> &varData)\n{\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n\n    vector<string> varnames = bParams->GetFieldVariableNames();\n    if (!VariableExists(ts, varnames, refLevel, lod, true)) {\n        SetErrMsg(\"One or more selected field variables does not exist\");\n        return -1;\n    }\n\n    // Get grids for our vector variables\n    //\n    int rc = DataMgrUtils::GetGrids(_dataMgr, ts, varnames, minExts, maxExts, true, &refLevel, &lod, varData);\n\n    return rc;\n}\n\nvoid BarbRenderer::_getGridRequirements(int &ts, int &refLevel, int &lod, CoordType &minExts, CoordType &maxExts) const\n{\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n\n    ts = bParams->GetCurrentTimestep();\n\n    refLevel = bParams->GetRefinementLevel();\n    lod = bParams->GetCompressionLevel();\n\n    bParams->GetBox()->GetExtents(minExts, maxExts);\n}\n\nint BarbRenderer::_getVarGrid(int ts, int refLevel, int lod, string varName, CoordType minExts, CoordType maxExts, std::vector<VAPoR::Grid *> &varData)\n{\n    Grid *sg = NULL;\n    varData.push_back(sg);\n\n    if (!varName.empty()) {\n        int rc = DataMgrUtils::GetGrids(_dataMgr, ts, varName, minExts, maxExts, true, &refLevel, &lod, &sg);\n        if (rc < 0) { return (rc); }\n        varData[varData.size() - 1] = sg;\n    }\n\n    return 0;\n}\n\nint BarbRenderer::_paintGL(bool)\n{\n    if (_isCacheDirty()) {\n        if (_generateBarbs() < 0) return -1;\n        _saveCacheParams();\n    }\n\n    glEnable(GL_DEPTH_TEST);\n    glDepthMask(GL_TRUE);\n    _setUpLightingAndColor();\n\n    float clut[1024];\n    bool  doColorMapping = _makeCLUT(clut);\n    auto  crange = GetActiveParams()->GetMapperFunc(GetActiveParams()->GetColorMapVariableName())->getMinMaxMapValue();\n    for (auto b : _barbCache) _drawBarb(b, doColorMapping, clut, crange.data());\n\n    _glManager->legacy->DisableLighting();\n\n    return 0;\n}\n\nint BarbRenderer::_generateBarbs()\n{\n    int rc;\n\n    // Set up the variable data required, while determining data\n    // extents to use in rendering\n    //\n    vector<Grid *> varData;\n\n    int            ts, refLevel, lod;\n    CoordType      minExts, maxExts;\n    _getGridRequirements(ts, refLevel, lod, minExts, maxExts);\n\n    // Get vector variables\n    rc = _getVectorVarGrids(ts, refLevel, lod, minExts, maxExts, varData);\n    if (rc < 0) {\n        SetErrMsg(\"One or more selected field variables does not exist\");\n        return -1;\n    }\n\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n\n    // Get height variable\n    string heightVar = bParams->GetHeightVariableName();\n    rc = _getVarGrid(ts, refLevel, lod, heightVar, minExts, maxExts, varData);\n    if (rc < 0) {\n        SetErrMsg(\"Height variable does not exist\");\n        return -1;\n    }\n\n    // Get color variable\n    string colorVar = bParams->GetColorMapVariableName();\n    rc = _getVarGrid(ts, refLevel, lod, colorVar, minExts, maxExts, varData);\n    if (rc < 0) {\n        SetErrMsg(\"Color variable does not exist\");\n        return -1;\n    }\n\n    _recalculateScales(varData, ts);\n\n    _barbCache.clear();\n    // Render the barbs\n    _operateOnGrid(varData);\n\n    return (rc);\n}\n\nfloat BarbRenderer::_calculateDirVec(const float start[3], const float end[3], float dirVec[3])\n{\n    vsub(end, start, dirVec);\n    float len = vlength(dirVec);\n    if (len != 0.f) vscale(dirVec, 1. / len);\n    return len;\n}\n\nvoid BarbRenderer::_drawBackOfBarb(const float dirVec[3], const float startVertex[3]) const\n{\n    // TODO GL\n    /*\n    glBegin(GL_POLYGON);\n    glNormal3fv(dirVec);\n    for (int k = 0; k<6; k++){\n        glVertex3fv(startVertex+3*k);\n    }\n    glEnd();\n     */\n}\n\nvoid BarbRenderer::_drawCylinderSides(const float nextNormal[3], const float nextVertex[3], const float startNormal[3], const float startVertex[3]) const\n{\n    LegacyGL *lgl = _glManager->legacy;\n\n    lgl->Begin(GL_TRIANGLE_STRIP);\n\n    for (int i = 0; i < 6; i++) {\n        lgl->Normal3fv(nextNormal + 3 * i);\n        lgl->Vertex3fv(nextVertex + 3 * i);\n\n        lgl->Normal3fv(startNormal + 3 * i);\n        lgl->Vertex3fv(startVertex + 3 * i);\n    }\n    // repeat first two vertices to close cylinder:\n\n    lgl->Normal3fv(nextNormal);\n    lgl->Vertex3fv(nextVertex);\n\n    lgl->Normal3fv(startNormal);\n    lgl->Vertex3fv(startVertex);\n\n    lgl->End();\n}\n\nvoid BarbRenderer::_drawBarbHead(const float dirVec[3], const float vertexPoint[3], const float startNormal[3], const float startVertex[3]) const\n{\n    LegacyGL *lgl = _glManager->legacy;\n\n    // Create a triangle fan from these 6 vertices.\n    lgl->Begin(GL_TRIANGLE_FAN);\n    lgl->Normal3fv(dirVec);\n    lgl->Vertex3fv(vertexPoint);\n    for (int i = 0; i < 6; i++) {\n        lgl->Normal3fv(startNormal + 3 * i);\n        lgl->Vertex3fv(startVertex + 3 * i);\n    }\n    // Repeat first point to close fan:\n    lgl->Normal3fv(startNormal);\n    lgl->Vertex3fv(startVertex);\n    lgl->End();\n}\n\n#ifdef DEBUG\nvoid BarbRenderer::_printBackDiameter(const float startVertex[18]) const\n{\n    float pointA[3] = {startVertex[0], startVertex[1], startVertex[2]};\n    float pointB[3] = {startVertex[3], startVertex[4], startVertex[5]};\n    float pointC[3] = {startVertex[6], startVertex[7], startVertex[8]};\n    float pointD[3] = {startVertex[9], startVertex[10], startVertex[11]};\n    float pointE[3] = {startVertex[12], startVertex[13], startVertex[14]};\n    float pointF[3] = {startVertex[15], startVertex[16], startVertex[17]};\n    cout << \"   \" << pointA[0] << \"\\t\\t\" << pointB[0] << \"\\t\\t\\t\" << pointC[0];\n    cout << \"\\t\\t\" << pointD[0] << \"\\t\\t\" << pointE[0] << \"\\t\\t\" << pointF[0] << endl;\n\n    cout << \"   \" << pointA[1] << \"\\t\\t\" << pointB[1] << \"\\t\\t\" << pointC[1];\n    cout << \"\\t\" << pointD[1] << \"\\t\" << pointE[1] << \"\\t\\t\" << pointF[1] << endl;\n\n    cout << \"   \" << pointA[2] << \"\\t\\t\" << pointB[2] << \"\\t\\t\" << pointC[2];\n    cout << \"\\t\\t\" << pointD[2] << \"\\t\\t\" << pointE[2] << \"\\t\\t\" << pointF[2] << endl;\n    cout << \"Back Diameter \" << _calculateLength(pointA, pointD) << endl;\n}\n#endif\n\n// Issue OpenGL calls to draw a cylinder with orthogonal ends from\n// one point to another.  Then put an barb head on the end\n//\nvoid BarbRenderer::_drawBarb(const std::vector<Grid *> variableData, const float startPoint_[3], bool doColorMapping, const float clut[1024])\n{\n    Barb b;\n    memcpy(b.startPoint, startPoint_, sizeof(float) * 3);\n    b.lengthScalar = ((BarbParams *)GetActiveParams())->GetLengthScale() * _vectorScaleFactor;\n\n    VAssert(variableData.size() == 5);\n\n    bool missing = _defineBarb(variableData, b.startPoint, b.endPoint, &b.value, doColorMapping, clut);\n\n    if (missing) return;\n\n    _barbCache.push_back(b);\n}\n\nvoid BarbRenderer::_setBarbColor(float value, const float clut[1024], double crange[2]) const\n{\n    float range = crange[1] - crange[0];\n    float n = (value - crange[0]) / range;\n    n = glm::clamp(n, 0.f, 1.f);\n    int i = 255 * n;\n\n    _glManager->legacy->Color4fv(&clut[i * 4]);\n}\n\nvoid BarbRenderer::_drawBarb(Barb b, bool doColorMapping, const float clut[1024], double crange[2])\n{\n    float *        startPoint = b.startPoint;\n    float *        endPoint = b.endPoint;\n    MatrixManager *mm = _glManager->matrixManager;\n    if (doColorMapping) _setBarbColor(b.value, clut, crange);\n    float     newLengthScalar = ((BarbParams *)GetActiveParams())->GetLengthScale() * _vectorScaleFactor;\n    glm::vec3 v = glm::make_vec3(b.endPoint) - glm::make_vec3(b.startPoint);\n    float     l = glm::length(v) / b.lengthScalar * newLengthScalar;\n    glm::vec3 end = glm::make_vec3(b.startPoint) + glm::normalize(v) * l;\n    memcpy(b.endPoint, glm::value_ptr(end), sizeof(float) * 3);\n\n    mm->MatrixModeModelView();\n    mm->PushMatrix();\n\n    mm->Translate(startPoint[0], startPoint[1], startPoint[2]);\n\n    endPoint[0] -= startPoint[0];\n    endPoint[1] -= startPoint[1];\n    endPoint[2] -= startPoint[2];\n\n    startPoint[0] = startPoint[1] = startPoint[2] = 0;\n\n    vector<double> scales = _getScales();\n    mm->Scale(1.f / scales[0], 1.f / scales[1], 1.f / scales[2]);\n\n    // Constants are needed for cosines and sines, at\n    // 60 degree intervals. The barb is really a hexagonal tube,\n    // but the shading makes it look round.\n    const float sines[6] = {0.f, (float)(sqrt(3.) / 2.), (float)(sqrt(3.) / 2.), 0.f, (float)(-sqrt(3.) / 2.), (float)(-sqrt(3.) / 2.)};\n    const float coses[6] = {1.f, 0.5, -0.5, -1., -.5, 0.5};\n\n    float nextPoint[3];\n    float vertexPoint[3];\n    float headCenter[3];\n    float startNormal[18];\n    float nextNormal[18];\n    float startVertex[18];\n    float nextVertex[18];\n    float testVec[3];\n    float testVec2[3];\n\n    // Calculate an orthonormal frame\n\n    // dirVec is the barb direction\n    float dirVec[3];\n    float len = _calculateDirVec(startPoint, endPoint, dirVec);\n\n    // Calculate uVec, orthogonal to dirVec\n    // Not sure what bVec is.  Up direction?\n    float uVec[3], bVec[3];\n    vset(testVec, 1., 0., 0.);\n    vcross(dirVec, testVec, uVec);\n    len = vdot(uVec, uVec);\n    if (len == 0.f) {\n        vset(testVec, 0., 1., 0.);\n        vcross(dirVec, testVec, uVec);\n        len = vdot(uVec, uVec);\n    }\n    vscale(uVec, 1.f / sqrt(len));\n    vcross(uVec, dirVec, bVec);\n\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n\n    float radius = bParams->GetLineThickness() * _maxThickness;\n\n    // calculate 6 points in plane orthog to dirVec, in plane of point\n    for (int i = 0; i < 6; i++) {\n        // testVec and testVec2 are components of point in plane\n        vmult(uVec, coses[i], testVec);\n        vmult(bVec, sines[i], testVec2);\n\n        // Calc outward normal as a sideEffect..\n        // It is the vector sum of x,y components (norm 1)\n        vadd(testVec, testVec2, startNormal + 3 * i);\n\n        // stretch by radius to get current displacement\n        vmult(startNormal + 3 * i, radius, startVertex + 3 * i);\n\n        // add to current point\n        vadd(startVertex + 3 * i, startPoint, startVertex + 3 * i);\n    }\n\n#ifdef DEBUG\n    _printBackDiameter(startVertex);\n#endif\n\n    _drawBackOfBarb(dirVec, startVertex);\n\n    // The variables are located as follows:\n    //\t\t- - - - >\n    //\t   ^       ^ ^\n    // start    next end\n\n    // Calculate nextPoint and vertexPoint, for barbhead\n    for (int i = 0; i < 3; i++) {\n        nextPoint[i] = (1. - BARB_LENGTH_FACTOR) * startPoint[i] + BARB_LENGTH_FACTOR * endPoint[i];\n        // Assume a vertex angle of 45 degrees:\n        vertexPoint[i] = nextPoint[i] + dirVec[i] * radius;\n        headCenter[i] = nextPoint[i] - dirVec[i] * (BARB_HEAD_FACTOR * radius - radius);\n    }\n\n    // calc for endpoints:\n    for (int i = 0; i < 6; i++) {\n        // testVec and testVec2 are components of point in plane\n        vmult(uVec, coses[i], testVec);\n        vmult(bVec, sines[i], testVec2);\n\n        // Calc outward normal as a sideEffect..\n        // It is the vector sum of x,y components (norm 1)\n        vadd(testVec, testVec2, nextNormal + 3 * i);\n\n        // stretch by radius to get current displacement\n        vmult(nextNormal + 3 * i, radius, nextVertex + 3 * i);\n\n        // add to current point\n        vadd(nextVertex + 3 * i, nextPoint, nextVertex + 3 * i);\n    }\n\n    _drawCylinderSides(nextNormal, nextVertex, startNormal, startVertex);\n\n    // Now draw the barb head.  First calc 6 vertices at back of barbhead\n    // Reuse startNormal and startVertex vectors\n    // calc for endpoints:\n    for (int i = 0; i < 6; i++) {\n        // testVec and testVec2 are components of point in plane\n        // Can reuse them from previous (cylinder end) calculation\n        vmult(uVec, coses[i], testVec);\n        vmult(bVec, sines[i], testVec2);\n\n        // Calc outward normal as a sideEffect..\n        // It is the vector sum of x,y components (norm 1)\n        vadd(testVec, testVec2, startNormal + 3 * i);\n\n        // stretch by radius to get current displacement\n        vmult(startNormal + 3 * i, BARB_HEAD_FACTOR * radius, startVertex + 3 * i);\n\n        // add to current point\n        vadd(startVertex + 3 * i, headCenter, startVertex + 3 * i);\n\n        // Now tilt normals in direction of barb:\n        for (int k = 0; k < 3; k++) { startNormal[3 * i + k] = 0.5 * startNormal[3 * i + k] + 0.5 * dirVec[k]; }\n    }\n\n    _drawBarbHead(dirVec, vertexPoint, startNormal, startVertex);\n\n    mm->PopMatrix();\n}\n\nvoid BarbRenderer::_setUpLightingAndColor()\n{\n    LegacyGL *       lgl = _glManager->legacy;\n    string           winName = GetVisualizer();    // GetVisualizer is not const :(\n    ViewpointParams *vpParams = _paramsMgr->GetViewpointParams(winName);\n    int              nLights = vpParams->getNumLights();\n\n    float       fcolor[3];\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n    bParams->GetConstantColor(fcolor);\n    if (nLights == 0 || !bParams->GetValueLong(RenderParams::LightingEnabledTag, 0)) {\n        lgl->DisableLighting();\n    } else {\n        // All the geometry will get a white specular color:\n        float specColor[4];\n        specColor[0] = specColor[1] = specColor[2] = 0.8f;\n        specColor[3] = 1.f;\n        lgl->EnableLighting();\n\n        double m[16];\n        double cameraPosD[3], cameraUpD[3], cameraDirD[3];\n        _paramsMgr->GetViewpointParams(_winName)->GetModelViewMatrix(m);\n        _paramsMgr->GetViewpointParams(_winName)->ReconstructCamera(m, cameraPosD, cameraUpD, cameraDirD);\n        // Why do we need to invert the lighting direction here?  Are the barb normals backwards or something?\n        float cameraDirF[3] = {(float)cameraDirD[0]*-1, (float)cameraDirD[1]*-1, (float)cameraDirD[2]*-1};\n        lgl->LightDirectionfv(cameraDirF);\n    }\n    lgl->Color3fv(fcolor);\n}\n\nvoid BarbRenderer::_reFormatExtents(vector<float> &rakeExts) const\n{\n    rakeExts.clear();\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n    vector<double> rMinExtents, rMaxExtents;\n\n    bParams->GetBox()->GetExtents(rMinExtents, rMaxExtents);\n\n    bool planar = bParams->GetBox()->IsPlanar();\n\n    rakeExts.push_back(rMinExtents[X]);\n    rakeExts.push_back(rMinExtents[Y]);\n    rakeExts.push_back(planar ? GetDefaultZ(_dataMgr, bParams->GetCurrentTimestep()) : rMinExtents[Z]);\n    rakeExts.push_back(rMaxExtents[X]);\n    rakeExts.push_back(rMaxExtents[Y]);\n    rakeExts.push_back(planar ? GetDefaultZ(_dataMgr, bParams->GetCurrentTimestep()) : rMaxExtents[Z]);\n}\n\nvoid BarbRenderer::_makeRakeGrid(vector<int> &rakeGrid) const\n{\n    rakeGrid.clear();\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n    vector<long> longGrid = bParams->GetGrid();\n\n    rakeGrid.push_back((int)longGrid[X]);\n    rakeGrid.push_back((int)longGrid[Y]);\n    rakeGrid.push_back((int)longGrid[Z]);\n}\n\nfloat BarbRenderer::_getHeightOffset(Grid *heightVar, float xCoord, float yCoord, bool &missing) const\n{\n    VAssert(heightVar);\n    float missingVal = heightVar->GetMissingValue();\n    float offset = heightVar->GetValue(xCoord, yCoord, 0.f);\n    if (offset == missingVal) {\n        missing = true;\n        offset = 0.f;\n    }\n    BarbParams* p = (BarbParams *)GetActiveParams();\n    offset -= GetDefaultZ(_dataMgr, p->GetCurrentTimestep());\n    return offset;\n}\n\nvoid BarbRenderer::_getDirection(float direction[3], vector<Grid *> variableData, float xCoord, float yCoord, float zCoord, bool &missing) const\n{\n    for (int dim = 0; dim < 3; dim++) {\n        direction[dim] = 0.f;\n        if (variableData[dim]) {\n            direction[dim] = variableData[dim]->GetValue(xCoord, yCoord, zCoord);\n\n            float missingVal = variableData[dim]->GetMissingValue();\n            if (direction[dim] == missingVal) { missing = true; }\n        }\n    }\n}\n\nbool BarbRenderer::_makeCLUT(float clut[1024]) const\n{\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n    string colorVar = bParams->GetColorMapVariableName();\n    bool   doColorMapping = !bParams->UseSingleColor() && !colorVar.empty();\n\n    if (doColorMapping) {\n        MapperFunction *tf = 0;\n        tf = (MapperFunction *)bParams->GetMapperFunc(colorVar);\n        VAssert(tf);\n        tf->makeLut(clut);\n    }\n    return doColorMapping;\n}\n\nvector<double> BarbRenderer::_getScales()\n{\n    string                  myVisName = GetVisualizer();    // Not const :(\n    VAPoR::ViewpointParams *vpp = _paramsMgr->GetViewpointParams(myVisName);\n    string                  datasetName = GetMyDatasetName();\n    Transform *             tDataset = vpp->GetTransform(datasetName);\n    Transform *             tRenderer = GetActiveParams()->GetTransform();\n\n    vector<double> scales = tDataset->GetScales();\n    vector<double> rendererScales = tRenderer->GetScales();\n\n    scales[0] *= rendererScales[0];\n    scales[1] *= rendererScales[1];\n    scales[2] *= rendererScales[2];\n\n    return scales;\n}\n\nfloat BarbRenderer::_calculateLength(float start[3], float end[3]) const\n{\n    float xDist = start[X] - end[X];\n    float yDist = start[Y] - end[Y];\n    float zDist = start[Z] - end[Z];\n    float length = sqrt(xDist * xDist + yDist * yDist + zDist * zDist);\n    return length;\n}\n\nvoid BarbRenderer::_makeStartAndEndPoint(float start[3], float end[3], float direction[3])\n{\n    BarbParams *bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n    float length = bParams->GetLengthScale() * _vectorScaleFactor;\n\n    vector<double> scales = _getScales();\n\n    end[X] = start[X] + scales[X] * direction[X] * length;\n    end[Y] = start[Y] + scales[Y] * direction[Y] * length;\n    end[Z] = start[Z] + scales[Z] * direction[Z] * length;\n}\n\nvoid BarbRenderer::_getStrides(vector<float> &strides, vector<int> &rakeGrid, vector<float> &rakeExts) const\n{\n    strides.clear();\n\n    float xStride = (rakeExts[XMAX] - rakeExts[XMIN]) / ((float)rakeGrid[X] + 1);\n    strides.push_back(xStride);\n\n    float yStride = (rakeExts[YMAX] - rakeExts[YMIN]) / ((float)rakeGrid[Y] + 1);\n    strides.push_back(yStride);\n\n    float zStride = (rakeExts[ZMAX] - rakeExts[ZMIN]) / ((float)rakeGrid[Z] + 1);\n    strides.push_back(zStride);\n}\n\nbool BarbRenderer::_defineBarb(const std::vector<Grid *> variableData, float start[3], float end[3], float *value, bool doColorMapping, const float clut[1024])\n{\n    bool missing = false;\n\n    Grid *heightVar = variableData[3];\n    if (heightVar) { start[Z] += _getHeightOffset(heightVar, start[X], start[Y], missing); }\n\n    float direction[3] = {0.f, 0.f, 0.f};\n    _getDirection(direction, variableData, start[X], start[Y], start[Z], missing);\n\n    _makeStartAndEndPoint(start, end, direction);\n\n    if (doColorMapping) {\n        float val = variableData[4]->GetValue(start[X], start[Y], start[Z]);\n        *value = val;\n\n        if (val == variableData[4]->GetMissingValue())\n            missing = true;\n        else {\n            missing = _getColorMapping(val, clut);\n        }\n    }\n    return missing;\n}\n\nvoid BarbRenderer::_operateOnGrid(vector<Grid *> variableData, bool drawBarb)\n{\n    vector<int> rakeGrid;\n    _makeRakeGrid(rakeGrid);\n\n    vector<float> rakeExts;\n    _reFormatExtents(rakeExts);\n\n    vector<float> strides;\n    _getStrides(strides, rakeGrid, rakeExts);\n\n    float clut[1024];\n    bool  doColorMapping = _makeCLUT(clut);\n\n    float start[3];\n    for (int i = 1; i <= rakeGrid[X]; i++) {\n        start[X] = strides[X] * i + rakeExts[X];    // + xStride/2.0;\n        for (int j = 1; j <= rakeGrid[Y]; j++) {\n            start[Y] = strides[Y] * j + rakeExts[Y];    // + yStride/2.0;\n            for (int k = 1; k <= rakeGrid[Z]; k++) {\n                start[Z] = strides[Z] * k + rakeExts[Z];    //+ zStride/2.0;\n\n                if (drawBarb) {\n                    _drawBarb(variableData, start, doColorMapping, clut);\n                } else {\n                    _getMagnitudeAtPoint(variableData, start);\n                }\n            }\n        }\n    }\n    return;\n}\n\nvoid BarbRenderer::_getMagnitudeAtPoint(std::vector<VAPoR::Grid *> variables, float point[3])\n{\n    VAPoR::Grid *grid;\n    double       maxValue = 0.f;\n    for (int i = 0; i < 3; i++) {\n        grid = variables[i];\n        if (grid == NULL)\n            continue;\n        else {\n            double value = grid->GetValue(point[X], point[Y], point[Z]);\n            double missingValue = grid->GetMissingValue();\n\n            if (value == missingValue) { continue; }\n            value = abs(value);\n\n            if (value > maxValue && value < std::numeric_limits<double>::max() && value > std::numeric_limits<double>::lowest() && !std::isnan(value)) maxValue = value;\n        }\n    }\n    if (maxValue > _maxValue) { _maxValue = maxValue; }\n}\n\nbool BarbRenderer::_getColorMapping(float val, const float clut[256 * 4])\n{\n    bool missing = false;\n\n    MapperFunction *tf = 0;\n    BarbParams *    bParams = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(bParams);\n    string colorVar = bParams->GetColorMapVariableName();\n    tf = (MapperFunction *)bParams->GetMapperFunc(colorVar);\n    VAssert(tf);\n\n    float mappedColor[4] = {0., 0., 0., 0.};\n    // Use the transfer function to map the data:\n    int lutIndex = tf->mapFloatToIndex(val);\n    for (int i = 0; i < 4; i++) mappedColor[i] = clut[4 * lutIndex + i];\n    _glManager->legacy->Color4fv(mappedColor);\n    return missing;\n}\n\ndouble BarbRenderer::_getDomainHypotenuse(size_t ts) const\n{\n    std::vector<int>    axes;\n    CoordType           minExts, maxExts;\n    std::vector<string> varNames;\n\n    BarbParams *p = dynamic_cast<BarbParams *>(GetActiveParams());\n    VAssert(p);\n    varNames = p->GetFieldVariableNames();\n\n    bool status = DataMgrUtils::GetExtents(_dataMgr, ts, varNames, 0, 0, minExts, maxExts, axes);\n    VAssert(status);\n\n    if (varNames[0] == \"\" && varNames[1] == \"\" && varNames[2] == \"\") return 0.0;\n\n    double xLen = maxExts[0] - minExts[0];\n\n    double yLen = maxExts[1] - minExts[1];\n\n    double zLen = maxExts[2] - minExts[2];\n\n    double diag = sqrt(xLen * xLen + yLen * yLen + zLen * zLen);\n    return diag;\n}\n\nvoid BarbRenderer::_setDefaultLengthAndThicknessScales(size_t ts, const std::vector<VAPoR::Grid *> &varData, const BarbParams *bParams)\n{\n    VAssert(varData.size() >= 3);\n\n    _maxValue = 0;\n\n    _operateOnGrid(varData, false);\n\n    double hypotenuse = _getDomainHypotenuse(ts);\n\n    if (hypotenuse == 0.f) return;\n\n    _maxThickness = hypotenuse * BARB_RADIUS_TO_HYPOTENUSE;\n    _vectorScaleFactor = hypotenuse * BARB_LENGTH_TO_HYPOTENUSE;\n    _vectorScaleFactor *= 1.0 / _maxValue;\n}\n"
  },
  {
    "path": "lib/render/CMakeLists.txt",
    "content": "set (SRC\n\tBarbRenderer.cpp\n\tControlExecutive.cpp\n\tVolumeRenderer.cpp\n\tVolumeIsoRenderer.cpp\n\tHelloRenderer.cpp\n\tRenderer.cpp\n\tShaderProgram.cpp\n\tTwoDDataRenderer.cpp\n\tTwoDRenderer.cpp\n\tWireFrameRenderer.cpp\n\tGeoTile.cpp\n\tGeoTileMercator.cpp\n\tGeoTileEquirectangular.cpp\n\tGeoImage.cpp\n\tGeoImageTMS.cpp\n\tGeoImageGeoTiff.cpp\n\tImageRenderer.cpp\n\tVisualizer.cpp\n\tAnnotationRenderer.cpp\n\tjfilewrite.cpp\n\tRayCaster.cpp\n\tFlowRenderer.cpp\n\tControlExecutive.cpp\n\tContourRenderer.cpp\n    SliceRenderer.cpp\n\tMyPython.cpp\n\tMatrixManager.cpp\n\tShader.cpp\n\tLegacyGL.cpp\n\tShaderManager.cpp\n\tGLManager.cpp\n\tFontManager.cpp\n\tFont.cpp\n\tTextLabel.cpp\n\tPyEngine.cpp\n\tCalcEngineMgr.cpp\n\tGeoTIFWriter.cpp\n\tImageWriter.cpp\n\tJPGWriter.cpp\n\tPNGWriter.cpp\n\tTIFWriter.cpp\n\tProj4StringParser.cpp\n\tglutil.cpp\n\tVolumeAlgorithm.cpp\n\tVolumeGLSL.cpp\n\tVolumeRegular.cpp\n\tVolumeRectilinear.cpp\n\t# VolumeResampled.cpp\n\t# VolumeTest.cpp\n\t# VolumeTest2.cpp\n\tVolumeCellTraversal.cpp\n\tTexture.cpp\n\tFramebuffer.cpp\n\tModelRenderer.cpp\n\tOSPRay.cpp\n    ColorbarRenderer.cpp\n    ParticleRenderer.cpp\n    TrackBall.cpp\n    NavigationUtils.cpp\n    Histo.cpp\n)\n\nset (HEADERS\n\t${PROJECT_SOURCE_DIR}/include/vapor/BarbRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ControlExecutive.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/HelloRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeIsoRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Renderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ShaderProgram.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/TwoDDataRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/TwoDRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WireFrameRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GeoTile.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GeoTileMercator.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GeoTileEquirectangular.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GeoImage.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GeoImageTMS.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GeoImageGeoTiff.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ImageRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Visualizer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/AnnotationRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ControlExecutive.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ContourRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/MyPython.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/MatrixManager.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Shader.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/LegacyGL.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ShaderManager.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GLManager.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/FontManager.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Font.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/IResourceManager.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/TextLabel.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/RayCaster.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/FlowRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/PyEngine.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/CalcEngineMgr.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GeoTIFWriter.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ImageWriter.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/JPGWriter.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/PNGWriter.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/TIFWriter.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/jpegapi.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Proj4StringParser.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/SliceRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/glutil.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeAlgorithm.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeGLSL.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeRegular.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeRectilinear.h\n\t# ${PROJECT_SOURCE_DIR}/include/vapor/VolumeResampled.h\n\t# ${PROJECT_SOURCE_DIR}/include/vapor/VolumeTest.h\n\t# ${PROJECT_SOURCE_DIR}/include/vapor/VolumeTest2.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeCellTraversal.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VolumeOSPRay.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Texture.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Framebuffer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ModelRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/OSPRay.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ColorbarRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ParticleRenderer.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/TrackBall.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/NavigationUtils.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/Histo.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/VisualizerGLContextManager.h\n)\n\nif(BUILD_OSP)\n\tset(SRC ${SRC}\n\t\tVolumeOSPRay.cpp\n\t)\nendif()\n\nadd_library (render SHARED ${SRC} ${HEADERS})\n\ntarget_link_libraries (render PUBLIC common vdc params flow osgl ${FTGL} ${FREETYPE} ${GEOTIFF} ${JPEG} ${TIFF} ${ASSIMP})\n# Omitted\n# - ${Python_LIBRARIES} \n# - ${GLEW} \n# - ${OPENGL_LIBRARIES} \n\nif (APPLE)\n    # Required to load library from python\n    # Binaries using this library need to link python\n    SET_TARGET_PROPERTIES(\n        render\n        PROPERTIES\n        LINK_FLAGS \"-undefined dynamic_lookup\"\n    )\nendif ()\n\nif (UNIX AND NOT APPLE)\n\ttarget_compile_options(render PRIVATE -Wno-conversion-null)\n#   target_link_libraries (render PUBLIC GLU)\nendif ()\n\n\nif(BUILD_OSP)\n\tfind_library (OSPRAY ospray HINTS ${OSPRAYDIR}/lib REQUIRED)\n\ttarget_link_libraries (render PUBLIC ${OSPRAY})\n\ttarget_include_directories (render PUBLIC ${OSPRAYDIR}/include)\n\ttarget_compile_definitions (render PUBLIC BUILD_OSPRAY)\nendif()\n\nadd_definitions (-DRENDER_EXPORTS)\n\nOpenMPInstall (\n\tTARGETS render\n\tDESTINATION ${INSTALL_LIB_DIR}\n\tCOMPONENT Libraries\n\t)\n\ninstall (\n\tFILES ${HEADERS}\n\tDESTINATION ${INSTALL_INCLUDE_DIR}\n\tCOMPONENT Libraries\n\t)\n"
  },
  {
    "path": "lib/render/CalcEngineMgr.cpp",
    "content": "#include <iostream>\n#include <vapor/CalcEngineMgr.h>\n#include <vapor/DataStatus.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/PyEngine.h>\n#include <vapor/STLUtils.h>\nusing namespace Wasp;\nusing namespace VAPoR;\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nint CalcEngineMgr::AddFunction(string scriptType, string dataSetName, string scriptName, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames,\n                               const vector<string> &outputVarMeshes, bool coordFlag)\n{\n    if (scriptType != \"Python\") {\n        SetErrMsg(\"Unsupported script type %s\", scriptType.c_str());\n        return (-1);\n    }\n\n    DataMgr *dataMgr = _dataStatus->GetDataMgr(dataSetName);\n    if (!dataMgr) {\n        SetErrMsg(\"Invalid data set name %s\", dataSetName.c_str());\n        return (-1);\n    }\n\n    int rc = _pyScripts[dataSetName]->AddFunction(scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag);\n    if (rc < 0) return (-1);\n\n    // If the output variable had a previous definition we need to purge\n    // the variable from the RenderParams mapper functions :-(\n    //\n    vector<RenderParams *> rParams;\n    _paramsMgr->GetRenderParams(rParams);\n    for (int j = 0; j < rParams.size(); j++) {\n        for (int i = 0; i < outputVarNames.size(); i++) { rParams[j]->RemoveMapperFunc(outputVarNames[i]); }\n    }\n\n    _paramsMgr->GetDatasetsParams()->SetScript(dataSetName, scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag);\n\n    return (0);\n}\n\nvoid CalcEngineMgr::RemoveFunction(string scriptType, string dataSetName, string scriptName)\n{\n    if (scriptType != \"Python\") return;\n\n    string script;\n    vector<string> inputVarNames, outputVarNames, inputVarMeshes;\n    bool coordFlag;\n    _paramsMgr->GetDatasetsParams()->GetScript(dataSetName, scriptName, script, inputVarNames, outputVarNames, inputVarMeshes, coordFlag);\n    _paramsMgr->GetDatasetsParams()->RemoveScript(dataSetName, scriptName);\n    SetCacheDirty();\n}\n\nvector<string> CalcEngineMgr::GetFunctionNames(string scriptType, string dataSetName)\n{\n    if (scriptType != \"Python\") return (vector<string>());\n    return _paramsMgr->GetDatasetsParams()->GetScriptNames(dataSetName);\n}\n\nbool CalcEngineMgr::GetFunctionScript(string scriptType, string dataSetName, string scriptName, string &script, vector<string> &inputVarNames, vector<string> &outputVarNames,\n                                      vector<string> &outputVarMeshes, bool &coordFlag)\n{\n    script.clear();\n    inputVarNames.clear();\n    outputVarNames.clear();\n    outputVarMeshes.clear();\n\n    if (scriptType != \"Python\") return (false);\n\n    return _paramsMgr->GetDatasetsParams()->GetScript(dataSetName, scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag);\n}\n\nstring CalcEngineMgr::GetFunctionStdout(string scriptType, string dataSetName, string scriptName)\n{\n    if (scriptType != \"Python\") return (\"\");\n\n    std::map<string, PyEngine *>::const_iterator itr;\n    itr = _pyScripts.find(dataSetName);\n    if (itr == _pyScripts.cend()) return (\"\");\n\n    PyEngine *pyEngine = itr->second;\n\n    return (pyEngine->GetFunctionStdout(scriptName));\n}\n\nCalcEngineMgr::~CalcEngineMgr() { _clean(); }\n\nvoid CalcEngineMgr::_clean()\n{\n    std::map<string, PyEngine *>::iterator itr;\n    while ((itr = _pyScripts.begin()) != _pyScripts.end()) {\n        PyEngine *pyEngine = itr->second;\n        if (pyEngine) delete pyEngine;\n\n        _pyScripts.erase(itr);\n    }\n}\n\nvoid CalcEngineMgr::ReinitFromState()\n{\n    _clean();\n    SyncWithParams();\n    SetCacheDirty();\n}\n\nvoid CalcEngineMgr::SyncWithParams()\n{\n    const vector<string> datasetNames = _dataStatus->GetDataMgrNames();\n    DatasetsParams *datasetsParams = _paramsMgr->GetDatasetsParams();\n\n    for (const auto &name : STLUtils::SyncToRemove(datasetNames, STLUtils::MapKeys(_pyScripts))) {\n        delete _pyScripts[name];\n        _pyScripts.erase(name);\n    }\n\n    for (const auto &name : STLUtils::SyncToAdd(datasetNames, STLUtils::MapKeys(_pyScripts))) {\n        _pyScripts[name] = new PyEngine(_dataStatus->GetDataMgr(name));\n        _pyScripts[name]->Initialize();\n    }\n\n    for (const auto &dataset : datasetNames) {\n        const auto funcNames = datasetsParams->GetScriptNames(dataset);\n        auto engine = _pyScripts[dataset];\n\n        for (const auto &name : STLUtils::SyncToRemove(funcNames, engine->GetFunctionNames())) {\n            engine->RemoveFunction(name);\n            SetCacheDirty();\n        }\n\n        for (const auto &name : engine->GetFunctionNames()) {\n            string script, p_script;\n            vector<string> inputVarNames, outputVarNames, outputMeshNames, p_inputVarNames, p_outputVarNames, p_outputMeshNames;\n            bool coordFlag, p_coordFlag;\n            engine->GetFunctionScript(name, script, inputVarNames, outputVarNames, outputMeshNames, coordFlag);\n            datasetsParams->GetScript(dataset, name, p_script, p_inputVarNames, p_outputVarNames, p_outputMeshNames, p_coordFlag);\n#define T(v) (v != p_##v)\n            if (T(script) || T(inputVarNames) || T(outputVarNames) || T(outputMeshNames) || T(coordFlag)) {\n                engine->RemoveFunction(name);\n                engine->AddFunction(name, p_script, p_inputVarNames, p_outputVarNames, p_outputMeshNames, p_coordFlag);\n                SetCacheDirty();\n            }\n        }\n\n        for (const auto &name : STLUtils::SyncToAdd(funcNames, engine->GetFunctionNames())) {\n            string p_script;\n            vector<string> p_inputVarNames, p_outputVarNames, p_outputMeshNames;\n            bool p_coordFlag;\n            datasetsParams->GetScript(dataset, name, p_script, p_inputVarNames, p_outputVarNames, p_outputMeshNames, p_coordFlag);\n            engine->AddFunction(name, p_script, p_inputVarNames, p_outputVarNames, p_outputMeshNames, p_coordFlag);\n        }\n    }\n\n    _wasCacheDirty = _isDataCacheDirty;\n    _isDataCacheDirty = false;\n}\n"
  },
  {
    "path": "lib/render/ColorbarRenderer.cpp",
    "content": "#include <vapor/glutil.h>\n#include <vapor/ColorbarRenderer.h>\n#include <stdio.h>\n#include <vapor/RenderParams.h>\n#include <vapor/LegacyGL.h>\n#include <vapor/MatrixManager.h>\n#include <vapor/GLManager.h>\n#include <vapor/Texture.h>\n#include <vapor/TextLabel.h>\n#include <vapor/Font.h>\n#include <assert.h>\n\nusing namespace VAPoR;\nusing glm::vec2;\nusing glm::vec3;\nusing glm::vec4;\n\nstatic vec2 D2V2(vector<double> d)\n{\n    assert(d.size() >= 2);\n    return vec2(d[0], d[1]);\n}\n\n\nstatic void DrawRect(LegacyGL *lgl, vec2 pos, vec2 size)\n{\n    lgl->Begin(LGL_QUADS);\n    lgl->TexCoord2f(0, 0);\n    lgl->Vertex2f(pos[0], pos[1]);\n    lgl->TexCoord2f(0, 1);\n    lgl->Vertex2f(pos[0], pos[1] + size[1]);\n    lgl->TexCoord2f(1, 1);\n    lgl->Vertex2f(pos[0] + size[0], pos[1] + size[1]);\n    lgl->TexCoord2f(1, 0);\n    lgl->Vertex2f(pos[0] + size[0], pos[1]);\n    lgl->End();\n}\n\n\nstatic void DrawColorBar(LegacyGL *lgl, MapperFunction *mf, vec2 pos, vec2 size)\n{\n    float lut[4 * 256];\n    mf->makeLut(lut);\n    for (int i = 0; i < 256; i++) lut[4 * i + 3] = 1;\n\n    Texture2D tex;\n    tex.Generate();\n    tex.TexImage(GL_RGB, 1, 256, 0, GL_RGBA, GL_FLOAT, lut);\n    tex.Bind();\n\n    lgl->EnableTexture();\n    lgl->Color3f(1, 1, 1);\n    DrawRect(lgl, pos, size);\n    lgl->DisableTexture();\n}\n\n\nclass Div {\npublic:\n    vec2                 Size = vec2(0);\n    function<void(void)> Draw;\n\n    void Render(GLManager *glm, vec2 pos)\n    {\n        glm->matrixManager->PushMatrix();\n        glm->matrixManager->Translate(pos.x, pos.y, 0);\n        RenderInner(glm);\n        glm->matrixManager->PopMatrix();\n    }\n\nprotected:\n    virtual void RenderInner(GLManager *glm) { Draw(); }\n};\n\ntemplate<float vec2::*primaryAxis, float vec2::*secondaryAxis> class Stack : public Div {\n    vector<Div *> _children;\n    int           _spacing;\n\npublic:\n    Stack(const vector<Div *> &c, int spacing = 5)\n    {\n        _children = c;\n        _spacing = spacing;\n        Size.*primaryAxis = -spacing;\n        for (const auto d : c) {\n            Size.*primaryAxis += d->Size.*primaryAxis;\n            Size.*secondaryAxis = std::max(Size.*secondaryAxis, d->Size.*secondaryAxis);\n            if (d->Size.*primaryAxis > 0) Size.*primaryAxis += spacing;\n        }\n    }\n\nprotected:\n    virtual void RenderInner(GLManager *glm)\n    {\n        vec2 p(0);\n        for (auto d : _children) {\n            d->Render(glm, p);\n            p.*primaryAxis += d->Size.*primaryAxis + _spacing;\n        }\n    };\n};\n\nstruct HStack : public Stack<&vec2::x, &vec2::y> {\n    using Stack::Stack;\n};\nstruct VStack : public Stack<&vec2::y, &vec2::x> {\n    using Stack::Stack;\n};\n\n\n\nvoid ColorbarRenderer::Render(GLManager *glm, RenderParams *rp)\n{\n    LegacyGL *     lgl = glm->legacy;\n    ColorbarPbase *cp = rp->GetColorbarPbase();\n\n    if (!cp->IsEnabled()) return;\n\n    auto  size = D2V2(cp->GetSize());\n    float scale = size.x;\n    size.y += (1.f - size.y) * scale;\n    size = glm::max(size, vec2(0.01, 0.01));\n    glm->PixelCoordinateSystemPush();\n    vec2 viewSize = glm->GetViewportSize();\n    size *= viewSize;\n\n    vec3   foregroundColor = [](vector<double> v){ return vec3(v[0], v[1], v[2]); }(cp->GetForegroundColor());\n    vec4   backgroundColor = [](vector<double> v){ return vec4(v[0], v[1], v[2],  v[3]); }(cp->GetBackgroundColor());\n    string fontName = \"arimo\";\n    float  border = roundf(glm::length(viewSize) * 0.001 * (1 + scale * 2));\n    float  padding = roundf(glm::length(viewSize) * 0.007 * (1 + scale * 2));\n\n    vec2 colorbarSize = glm::round(vec2(glm::length(viewSize) * 0.03 * (1 + scale), size.y - padding * 2));\n    colorbarSize = glm::max(colorbarSize, vec2(0, viewSize.y * 0.06f));\n\n    int tickCount = cp->GetNumTicks();\n    int fontSize = roundf(colorbarSize.y / tickCount * 0.8);\n    fontSize = min(fontSize, (int)(padding * 1.8f));\n\n    int manualFontSize = cp->GetFontSize();\n    if (cp->GetValueLong(\"manual_font\", false)) {\n        fontSize = manualFontSize;\n\n        padding = max(padding, fontSize / 2.f);\n        colorbarSize.y = max(roundf(fontSize * tickCount / 0.8), colorbarSize.y);\n        colorbarSize.x = roundf(max(colorbarSize.x, fontSize * 1.618f));\n        size.y = roundf(colorbarSize.y + padding * 2);\n    }\n\n    int   titleFontSize = max(fontSize * 1.3f, padding * 2.f);\n    float tickThickness = roundf(std::max(1.f, fontSize * 0.1f));\n    float tickLength = roundf(std::max(8.f, fontSize * 0.4f));\n    float tickPadding = 3;\n\n    auto            colormapVarName = rp->GetActualColorMapVariableName();\n    MapperFunction *mf = rp->GetMapperFunc(colormapVarName);\n    vec2            mfRange = D2V2(mf->getMinMaxMapValue());\n\n    Div colorbar;\n    colorbar.Size = colorbarSize;\n    colorbar.Draw = [&]() { DrawColorBar(lgl, mf, vec2(0), colorbarSize); };\n\n    Div ticks;\n    ticks.Size = vec2(tickLength, tickThickness);\n    ticks.Draw = [&]() {\n        float h = colorbarSize.y;\n        lgl->Color(foregroundColor);\n        for (int i = 0; i < tickCount; i++) {\n            vec2 tickPos = glm::round(vec2(0, (h - tickThickness) * i / (tickCount - 1.f)));\n            DrawRect(lgl, tickPos, vec2(tickLength, tickThickness));\n        }\n    };\n\n    TextLabel tickFont(glm, fontName, fontSize);\n    tickFont.ForegroundColor = glm::vec4(foregroundColor, 1);\n    tickFont.VerticalAlignment = TextLabel::Center;\n    tickFont.HorizontalAlignment = TextLabel::Left;\n\n    auto formatTick = makeFormatter(mf, cp->GetNumDigits(), cp->GetValueLong(cp->UseScientificNotationTag, false));\n    auto valueForTick = [&](int i) -> float { return mfRange.x + (mfRange.y - mfRange.x) * i / (tickCount - 1.f); };\n    auto textForTick = [&](int i) -> string { return formatTick(valueForTick(i)); };\n    auto tickTextSize = [&](int i) -> vec2 { return tickFont.GetFont()->TextDimensions(textForTick(i)); };\n    Div  tickLabels;\n    for (int i = 0; i < tickCount; i++) { tickLabels.Size = glm::max(tickLabels.Size, tickTextSize(i)); }\n    tickLabels.Draw = [&]() {\n        float h = colorbarSize.y;\n        lgl->Color(foregroundColor);\n        for (int i = 0; i < tickCount; i++) {\n            vec2 textPos = glm::round(vec2(0, tickThickness / 2.f + (h - tickThickness) * i / (tickCount - 1.f)));\n            tickFont.DrawText(textPos, textForTick(i));\n        }\n    };\n\n    HStack labledColorbar({&colorbar, &ticks, &tickLabels}, tickPadding);\n\n    TextLabel titleFont(glm, fontName, titleFontSize);\n    titleFont.ForegroundColor = glm::vec4(foregroundColor, 1);\n    titleFont.VerticalAlignment = TextLabel::Bottom;\n    titleFont.HorizontalAlignment = TextLabel::Left;\n    Div    title;\n    string titleText = cp->GetTitle();\n    title.Size = titleFont.GetFont()->TextDimensions(titleText);\n    title.Draw = [&]() { titleFont.DrawText(vec2(0), titleText); };\n\n    VStack titledColorbar({&labledColorbar, &title}, padding * 1.618);\n    size = titledColorbar.Size + vec2(padding * 2);\n\n    vec2 corner = D2V2(cp->GetCornerPosition());\n    vec2 pos = (corner * viewSize) - (size * corner);\n    vec2 colorbarPos = glm::round(pos + padding);\n\n    glDisable(GL_DEPTH_TEST);\n    glDepthMask(GL_FALSE);\n\n    glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    lgl->Color(foregroundColor);\n#if DRAW_COLORBAR_BORDER\n    if (backgroundColor.w > 0.99)\n        DrawRect(lgl, pos, size);\n#endif\n    lgl->Color(backgroundColor);\n    DrawRect(lgl, pos + vec2(border), size - vec2(border * 2));\n    titledColorbar.Render(glm, colorbarPos);\n\n    glDisable(GL_BLEND);\n\n    glm->PixelCoordinateSystemPop();\n}\n\n\nstd::function<std::string(float)> ColorbarRenderer::makeFormatter(MapperFunction *mf, int sigFigs, bool scientificNotation)\n{\n    vec2  mfRange = D2V2(mf->getMinMaxMapValue());\n    float mfDiff = mfRange[1] - mfRange[0];\n    float mfMax = max(abs(mfRange[0]), abs(mfRange[1]));\n    int   diffLog10 = ceil(log10(mfDiff));\n    int   maxLog10 = ceil(log10(mfMax));\n    int   nDecimals = max(sigFigs - max(diffLog10, maxLog10), 0);\n\n    auto formatTick = [=](float x) -> string {\n        char buf[64];\n        if (scientificNotation) {\n            snprintf(buf, 64, \"%.*e\", sigFigs - 1, x);\n        } else {\n            if (x > FLT_EPSILON) {\n                int exp = ceil(log10(x));\n                int shift = sigFigs - exp;\n                x = pow(10, -shift) * round((x * pow(10, shift)));\n            }\n\n            snprintf(buf, 64, \"%.*f\", nDecimals, x);\n        }\n        return string(buf);\n    };\n    return formatTick;\n}\n"
  },
  {
    "path": "lib/render/ContourRenderer.cpp",
    "content": "//************************************************************************\n//                                                                       *\n//                          Copyright (C)  2018                          *\n//            University Corporation for Atmospheric Research            *\n//                          All Rights Reserved                          *\n//                                                                       *\n//************************************************************************/\n//\n//  File:   ContourRenderer.cpp\n//\n//  Author: Stas Jaroszynski\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:   March 2018\n//\n//  Description:\n//          Implementation of ContourRenderer\n//\n\n#include <sstream>\n#include <string>\n#include <iterator>\n\n#include <vapor/glutil.h>    // Must be included first!!!\n\n#include <vapor/Renderer.h>\n#include <vapor/ContourRenderer.h>\n#include <vapor/ContourParams.h>\n#include <vapor/regionparams.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/DataStatus.h>\n#include <vapor/errorcodes.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/ShaderManager.h>\n#include <glm/glm.hpp>\n#include <glm/gtc/type_ptr.hpp>\n#include <vapor/GLManager.h>\n#include <vapor/LegacyGL.h>\n#include <vapor/ArbitrarilyOrientedRegularGrid.h>\n\nusing namespace VAPoR;\n\n#pragma pack(push, 4)\nstruct ContourRenderer::VertexData {\n    float x, y, z;\n    float v;\n};\n#pragma pack(pop)\n\nstatic RendererRegistrar<ContourRenderer> registrar(ContourRenderer::GetClassType(), ContourParams::GetClassType());\n\nContourRenderer::ContourRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, ContourParams::GetClassType(), ContourRenderer::GetClassType(), instName, dataMgr), _VAO(0), _VBO(0), _nVertices(0)\n{\n}\n\nContourRenderer::~ContourRenderer()\n{\n    if (_VAO) glDeleteVertexArrays(1, &_VAO);\n    if (_VBO) glDeleteBuffers(1, &_VBO);\n    _VAO = _VBO = 0;\n}\n\nvoid ContourRenderer::_saveCacheParams()\n{\n    ContourParams *p = (ContourParams *)GetActiveParams();\n    _cacheParams.varName = p->GetVariableName();\n    _cacheParams.heightVarName = p->GetHeightVariableName();\n    _cacheParams.ts = p->GetCurrentTimestep();\n    _cacheParams.level = p->GetRefinementLevel();\n    _cacheParams.lod = p->GetCompressionLevel();\n    _cacheParams.lineThickness = p->GetLineThickness();\n    p->GetBox()->GetExtents(_cacheParams.boxMin, _cacheParams.boxMax);\n    _cacheParams.contourValues = p->GetContourValues(_cacheParams.varName);\n    _cacheParams.sliceRotation = p->GetSlicePlaneRotation();\n    _cacheParams.sliceNormal = p->GetSlicePlaneNormal();\n    _cacheParams.sliceOrigin = p->GetSlicePlaneOrigin();\n    _cacheParams.sliceOffset = p->GetValueDouble(p->SliceOffsetTag, 0);\n    _cacheParams.sliceResolution = p->GetValueDouble(RenderParams::SampleRateTag, 200);\n    _cacheParams.sliceOrientationMode = p->GetValueLong(RenderParams::SlicePlaneOrientationModeTag, 0);\n}\n\nbool ContourRenderer::_isCacheDirty() const\n{\n    ContourParams *p = (ContourParams *)GetActiveParams();\n    if (_cacheParams.varName != p->GetVariableName()) return true;\n    if (_cacheParams.heightVarName != p->GetHeightVariableName()) return true;\n    if (_cacheParams.ts != p->GetCurrentTimestep()) return true;\n    if (_cacheParams.level != p->GetRefinementLevel()) return true;\n    if (_cacheParams.lod != p->GetCompressionLevel()) return true;\n    if (_cacheParams.lineThickness != p->GetLineThickness()) return true;\n    if (_cacheParams.sliceRotation != p->GetSlicePlaneRotation()) return true;\n    if (_cacheParams.sliceNormal != p->GetSlicePlaneNormal()) return true;\n    if (_cacheParams.sliceOrigin != p->GetSlicePlaneOrigin()) return true;\n    if (_cacheParams.sliceOffset != p->GetValueDouble(p->SliceOffsetTag, 0)) return true;\n    if (_cacheParams.sliceResolution != p->GetValueDouble(RenderParams::SampleRateTag, 200)) return true;\n    if (_cacheParams.sliceOrientationMode != p->GetValueLong(RenderParams::SlicePlaneOrientationModeTag, 0)) return true;\n\n    vector<double> min, max, contourValues;\n    p->GetBox()->GetExtents(min, max);\n    contourValues = p->GetContourValues(_cacheParams.varName);\n\n    if (_cacheParams.boxMin != min) return true;\n    if (_cacheParams.boxMax != max) return true;\n    if (_cacheParams.contourValues != contourValues) return true;\n\n    return false;\n}\n\nstatic CoordType ToCoordType(const vector<double> &v)\n{\n    CoordType c;\n    for (int i = 0; i < std::min(c.size(), v.size()); i++) c[i] = v[i];\n    return c;\n}\n\nstatic glm::vec3 ToVec3(const vector<double> &v)\n{\n    glm::vec3 c;\n    for (int i = 0; i < std::min(c.length(), (int)v.size()); i++) c[i] = v[i];\n    return c;\n}\n\nstatic vector<double> ToDoubleVec(const glm::vec3 &v)\n{\n    vector<double> c(v.length());\n    for (int i = 0; i < v.length(); i++) c[i] = v[i];\n    return c;\n}\n\n\nint ContourRenderer::_buildCache(bool fast)\n{\n    ContourParams *cParams = (ContourParams *)GetActiveParams();\n    _saveCacheParams();\n\n    vector<VertexData> vertices;\n\n    if (cParams->GetVariableName().empty()) {\n        MyBase::SetErrMsg(\"Missing Variable\");\n        return 1;\n    }\n    vector<double> contours = cParams->GetContourValues(_cacheParams.varName);\n\n    CoordType boxMin = {0.0, 0.0, 0.0};\n    CoordType boxMax = {0.0, 0.0, 0.0};\n    Grid::CopyToArr3(_cacheParams.boxMin, boxMin);\n    Grid::CopyToArr3(_cacheParams.boxMax, boxMax);\n\n    Grid *grid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.varName, _cacheParams.level, _cacheParams.lod, boxMin, boxMax);\n    Grid *grid2 = nullptr;\n    Grid *heightGrid = nullptr;\n    _sliceQuad.clear();\n\n    int dims = grid->GetTopologyDim();\n    if (!_cacheParams.heightVarName.empty() && dims == 2) { heightGrid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.heightVarName, _cacheParams.level, _cacheParams.lod, boxMin, boxMax); }\n    if (grid == NULL || (heightGrid == NULL && !_cacheParams.heightVarName.empty())) {\n        if (grid) delete grid;\n        if (grid2) delete grid2;\n        if (heightGrid) delete heightGrid;\n        return -1;\n    }\n\n    if (dims == 3) {\n        planeDescription pd;\n        pd.boxMin = ToCoordType(_cacheParams.boxMin);\n        pd.boxMax = ToCoordType(_cacheParams.boxMax);\n        pd.origin = _cacheParams.sliceOrigin;\n        pd.sideSize = _cacheParams.sliceResolution;\n        if (_cacheParams.sliceOrientationMode == (int)RenderParams::SlicePlaneOrientationMode::Normal)\n            pd.normal = _cacheParams.sliceNormal;\n        else\n            pd.normal = ToDoubleVec(ArbitrarilyOrientedRegularGrid::GetNormalFromRotations(_cacheParams.sliceRotation));\n\n        auto o = ToVec3(_cacheParams.sliceOrigin);\n        auto n = ToVec3(pd.normal);\n        auto offsetOrigin = o + n * (float)_cacheParams.sliceOffset;\n        pd.origin = ToDoubleVec(offsetOrigin);\n        _finalOrigin = offsetOrigin;\n\n        DimsType dims = {pd.sideSize, pd.sideSize, 1};\n\n        ArbitrarilyOrientedRegularGrid *grid2d = new ArbitrarilyOrientedRegularGrid(grid, pd, dims);\n        grid2 = grid;\n        grid = grid2d;\n\n        CoordType corner1, corner2, corner3, corner4;\n        grid2d->GetUserCoordinates({0, 0, 0}, corner1);\n        grid2d->GetUserCoordinates({0, pd.sideSize - 1, 0}, corner2);\n        grid2d->GetUserCoordinates({pd.sideSize - 1, 0, 0}, corner3);\n        grid2d->GetUserCoordinates({pd.sideSize - 1, pd.sideSize - 1, 0}, corner4);\n\n        cParams->SetSlicePlaneQuad({\n            {corner1[0], corner1[1], corner1[2]},\n            {corner3[0], corner3[1], corner3[2]},\n            {corner4[0], corner4[1], corner4[2]},\n            {corner2[0], corner2[1], corner2[2]},\n        });\n\n        if (fast) {\n            _cacheParams.varName = \"\";\n            if (grid) delete grid;\n            if (grid2) delete grid2;\n            if (heightGrid) delete heightGrid;\n            return 0;\n        }\n    }\n\n    double mv = grid->GetMissingValue();\n    float  Z0 = GetDefaultZ(_dataMgr, _cacheParams.ts);\n\n    Grid::ConstCellIterator it = grid->ConstCellBegin(boxMin, boxMax);\n\n    size_t           maxNodes = grid->GetMaxVertexPerCell();\n    vector<DimsType> nodes(maxNodes);\n\n    vector<float>     values(maxNodes);\n    vector<CoordType> coords(maxNodes);\n\n    Grid::ConstCellIterator end = grid->ConstCellEnd();\n    for (; it != end; ++it) {\n        const DimsType &cell = *it;\n        grid->GetCellNodes(cell, nodes);\n\n        bool hasMissing = false;\n        for (int i = 0; i < nodes.size(); i++) {\n            grid->GetUserCoordinates(nodes[i], coords[i]);\n            values[i] = grid->GetValueAtIndex(nodes[i]);\n            if (values[i] == mv) { hasMissing = true; }\n        }\n        if (hasMissing) continue;\n\n        for (int ci = 0; ci != contours.size(); ci++) {\n            for (int a = nodes.size() - 1, b = 0; b < nodes.size(); a++, b++) {\n                if (a == nodes.size()) a = 0;\n                float contour = contours[ci];\n\n                if ((values[a] <= contour && values[b] <= contour) || (values[a] > contour && values[b] > contour)) continue;\n\n                float t = (contour - values[a]) / (values[b] - values[a]);\n                float v[3];\n                v[0] = coords[a][0] + t * (coords[b][0] - coords[a][0]);\n                v[1] = coords[a][1] + t * (coords[b][1] - coords[a][1]);\n                v[2] = coords[a][2] + t * (coords[b][2] - coords[a][2]);\n\n                if (dims == 2) v[2] = Z0;\n\n                if (heightGrid) {\n                    float aHeight = heightGrid->GetValueAtIndex(nodes[a]);\n                    float bHeight = heightGrid->GetValueAtIndex(nodes[b]);\n                    v[2] = aHeight + t * (bHeight - aHeight);\n                }\n\n                vertices.push_back({v[0], v[1], v[2], contour});\n            }\n        }\n    }\n\n    _nVertices = vertices.size();\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_DYNAMIC_DRAW);\n    glBindVertexArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    if (grid) delete grid;\n    if (grid2) delete grid2;\n    if (heightGrid) delete heightGrid;\n\n    return 0;\n}\n\nint ContourRenderer::_paintGL(bool fast)\n{\n    int rc = 0;\n    if (_isCacheDirty()) {\n        rc = _buildCache(fast);\n    }\n    if (rc != 0) return rc;\n\n    RenderParams *  rp = GetActiveParams();\n    MapperFunction *tf = rp->GetMapperFunc(rp->GetVariableName());\n    float           lut[4 * 256];\n    tf->makeLut(lut);\n    if (rp->UseSingleColor()) {\n        float c[3];\n        rp->GetConstantColor(c);\n        for (int i = 0; i < 256; i++) {\n            lut[i * 4 + 0] = c[0];\n            lut[i * 4 + 1] = c[1];\n            lut[i * 4 + 2] = c[2];\n        }\n    }\n    _lutTexture.TexImage(GL_RGBA8, 256, 0, 0, GL_RGBA, GL_FLOAT, lut);\n\n    ShaderProgram *shader = _glManager->shaderManager->GetShader(\"Contour\");\n    if (shader == nullptr) return -1;\n    shader->Bind();\n    shader->SetUniform(\"MVP\", _glManager->matrixManager->GetModelViewProjectionMatrix());\n    shader->SetUniform(\"minLUTValue\", tf->getMinMapValue());\n    shader->SetUniform(\"maxLUTValue\", tf->getMaxMapValue());\n    shader->SetSampler(\"colormap\", _lutTexture);\n\n    // glLineWidth(_cacheParams.lineThickness);\n    glDepthMask(true);\n    glEnable(GL_DEPTH_TEST);\n    glBindVertexArray(_VAO);\n    glDrawArrays(GL_LINES, 0, _nVertices);\n\n    glBindVertexArray(0);\n    shader->UnBind();\n\n    return rc;\n}\n\nint ContourRenderer::_initializeGL()\n{\n    glGenVertexArrays(1, &_VAO);\n    glBindVertexArray(_VAO);\n    glGenBuffers(1, &_VBO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL);\n    glEnableVertexAttribArray(0);\n    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, v));\n    glEnableVertexAttribArray(1);\n    glBindVertexArray(0);\n\n    _lutTexture.Generate();\n\n    return 0;\n}\n"
  },
  {
    "path": "lib/render/ControlExecutive.cpp",
    "content": "#include <fstream>\n#include <sstream>\n#include <string>\n#include <algorithm>\n#include <cfloat>\n\n#include <vapor/STLUtils.h>\n#include <vapor/FileUtils.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/CalcEngineMgr.h>\n#include <vapor/VisualizerGLContextManager.h>\n#include <vapor/Visualizer.h>\n#include <vapor/DataStatus.h>\n#include <vapor/GUIStateParams.h>\n#include <vapor/SettingsParams.h>\n#include <vapor/NavigationUtils.h>\n\n#include <vapor/VolumeRenderer.h>\n#include <vapor/VolumeIsoRenderer.h>\n#include <vapor/OpenMPSupport.h>\n\nusing namespace VAPoR;\nusing namespace std;\n\nControlExec::ControlExec(ParamsMgr *pm, size_t cacheSizeMB, int nThreads) : MyBase()\n{\n    _paramsMgr = pm;\n    _dataStatus = new DataStatus(cacheSizeMB, nThreads);\n    _calcEngineMgr = new CalcEngineMgr(_dataStatus, _paramsMgr);\n    _visualizers.clear();\n    auto sp = pm->GetParams<SettingsParams>();\n    SetCacheSize(sp->GetCacheMB());\n    SetNumThreads(sp->GetNumThreads());\n}\n\nControlExec::~ControlExec()\n{\n#ifdef DEBUG\n    cout << \"Allocated XmlNode count before delete \" << XmlNode::GetAllocatedNodes().size() << endl;\n\n    const vector<XmlNode *> &nodes = XmlNode::GetAllocatedNodes();\n    for (int i = 0; i < nodes.size(); i++) { cout << \"   \" << nodes[i]->GetTag() << \" \" << XmlNode::streamOut(cout, nodes[i]) << endl; }\n#endif\n\n    if (_paramsMgr) delete _paramsMgr;\n    if (_dataStatus) delete _dataStatus;\n\n#ifdef DEBUG\n    cout << \"Allocated XmlNode count after delete \" << XmlNode::GetAllocatedNodes().size() << endl;\n\n    for (int i = 0; i < nodes.size(); i++) { cout << \"   \" << nodes[i]->GetTag() << \" \" << XmlNode::streamOut(cout, nodes[i]) << endl; }\n#endif\n}\n\nint ControlExec::NewVisualizer(string winName)\n{\n    // TODO Maybe remove this and RemoveVisualizer\n    winName = _paramsMgr->CreateVisualizerParamsInstance(winName);\n    if (winName.empty()) {\n        SetErrMsg(\"Failed to create Visualizer parameters\");\n        return -1;\n    }\n    return 0;\n}\n\nvoid ControlExec::RemoveVisualizer(string winName, bool hasOpenGLContext)\n{\n    _paramsMgr->RemoveVisualizer(winName);\n}\n\n\nvoid ControlExec::SyncWithParams()\n{\n    syncDatasetsWithParams();\n    syncVisualizersWithParams();\n    _calcEngineMgr->SyncWithParams();\n}\n\n\nvoid ControlExec::syncVisualizersWithParams()\n{\n    vector<string> vizNames = GetParamsMgr()->GetVisualizerNames();\n\n    for (const auto &name : STLUtils::SyncToRemove(vizNames, STLUtils::MapKeys(_visualizers)))\n        CleanupVisualizer(name, false);\n\n    for (const auto &name : STLUtils::SyncToAdd(vizNames, STLUtils::MapKeys(_visualizers)))\n        _visualizers[name] = new Visualizer(_paramsMgr, _dataStatus, name);\n}\n\n\nvoid ControlExec::syncDatasetsWithParams()\n{\n    auto gp = GetParams<GUIStateParams>();\n    auto openDatasets = gp->GetOpenDataSetNames();\n    auto toRemove = STLUtils::SyncToRemove(openDatasets, _dataStatus->GetDataMgrNames());\n    if (_dataCachedProjStr != gp->GetProjectionString()) {\n        toRemove = _dataStatus->GetDataMgrNames();\n        _dataCachedProjStr = gp->GetProjectionString();\n    }\n\n    for (const auto &name : toRemove)\n        _dataStatus->Close(name);\n\n    for (const auto &name : STLUtils::SyncToAdd(openDatasets, _dataStatus->GetDataMgrNames()))\n        OpenData(gp->GetOpenDataSetPaths(name), name, gp->GetOpenDataSetFormat(name));\n\n    _dataStatus->_wasCacheDirty = _dataStatus->_isDataCacheDirty;\n    _dataStatus->_isDataCacheDirty = false;\n}\n\n\nvoid ControlExec::EnforceDefaultAppState()\n{\n    vector<string> vizNames = _paramsMgr->GetVisualizerNames();\n    auto gsp = GetParams<GUIStateParams>();\n    if (!vizNames.empty() && !STLUtils::Contains(vizNames, gsp->GetActiveVizName())) {\n        _paramsMgr->PushSaveStateEnabled(false);\n        gsp->SetActiveVizName(vizNames[0]);\n        _paramsMgr->PopSaveStateEnabled();\n    }\n}\n\n\nvoid ControlExec::CleanupVisualizer(string winName, bool hasOpenGLContext)\n{\n    auto viz = getVisualizer(winName);\n    if (!viz) return;\n\n    if (!hasOpenGLContext)\n        _vizGLMgr->Activate(winName);\n\n    RemoveAllRenderers(winName, true, false);\n\n    _visualizers.erase(winName);\n    delete viz;\n}\n\nint ControlExec::InitializeViz(string winName, GLManager *glManager)\n{\n    Visualizer *v = getVisualizer(winName);\n    if (!v) {\n        SetErrMsg(\"Invalid Visualizer \\\"%s\\\"\", winName.c_str());\n        return -1;\n    }\n\n    if (v->InitializeGL(glManager) < 0) {\n        SetErrMsg(\"InitializeGL failure\");\n        return -1;\n    }\n\n    _cachedVendor = glManager->GetVendor();\n\n    return 0;\n}\n\nvector<string> ControlExec::GetVisualizerNames() const\n{\n    vector<string> names;\n\n    std::map<string, Visualizer *>::const_iterator itr;\n    for (itr = _visualizers.begin(); itr != _visualizers.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nint ControlExec::ResizeViz(string winName, int width, int height)\n{\n    Visualizer *v = getVisualizer(winName);\n    if (!v) {\n        SetErrMsg(\"Invalid Visualizer \\\"%s\\\"\", winName.c_str());\n        return -1;\n    }\n    if (v->resizeGL(width, height) < 0) return -1;\n\n    return 0;\n}\n\nvoid ControlExec::ClearRenderCache(const string &winName, const string &inst)\n{\n    getVisualizer(winName)->ClearRenderCache(inst);\n}\n\nvoid ControlExec::ClearAllRenderCaches()\n{\n    std::map<string, Visualizer *>::const_iterator itr;\n    for (itr = _visualizers.begin(); itr != _visualizers.end(); ++itr) { itr->second->ClearRenderCache(); }\n}\n\nGLManager::Vendor ControlExec::GetGPUVendor() const { return _cachedVendor; }\n\nint ControlExec::Paint(string winName, bool fast)\n{\n    Visualizer *v = getVisualizer(winName);\n    if (!v) {\n        SetErrMsg(\"Invalid Visualizer \\\"%s\\\"\", winName.c_str());\n        return -1;\n    }\n\n    // Disable state saving when generating the transfer function\n    //\n    bool enabled = _paramsMgr->GetSaveStateEnabled();\n    _paramsMgr->SetSaveStateEnabled(false);\n\n    int rc = v->paintEvent(fast);\n\n    _paramsMgr->SetSaveStateEnabled(enabled);\n\n    if (rc) SetErrMsg(\"Error performing paint event\");\n    return rc;\n}\n\n// TODO Replace with params-only\nint ControlExec::ActivateRender(string winName, string dataSetName, string renderType, string renderName, bool on)\n{\n    if (!_dataStatus->GetDataMgrNames().size()) {\n        SetErrMsg(\"Invalid state : no data\");\n        return -1;\n    }\n\n    if (!STLUtils::Contains(_paramsMgr->GetVisualizerNames(), winName)) {\n        SetErrMsg(\"Invalid Visualizer \\\"%s\\\"\", winName.c_str());\n        return -1;\n    }\n\n    _paramsMgr->BeginSaveStateGroup(\"Activate Renderer\");\n\n    string paramsType = RendererFactory::Instance()->GetParamsClassFromRenderClass(renderType);\n    VAssert(!paramsType.empty());\n\n    RenderParams *rp = _paramsMgr->GetRenderParams(winName, dataSetName, paramsType, renderName);\n    if (!rp) {\n        rp = _paramsMgr->CreateRenderParamsInstance(winName, dataSetName, paramsType, renderName);\n        if (!rp) {\n            SetErrMsg(\"Invalid renderer of type \\\"%s\\\"\", renderType.c_str());\n            _paramsMgr->EndSaveStateGroup();\n            return -1;\n        }\n\n        rp->SetCurrentTimestep(NavigationUtils::GetCurrentTimeStep(this));\n        int rc = rp->Initialize();\n        if (rc < 0) {\n            SetErrMsg(\"Failed to initialize of type \\\"%s\\\"\", renderType.c_str());\n            _paramsMgr->EndSaveStateGroup();\n            return (-1);\n        }\n    }\n\n    VAssert(rp);\n    rp->SetEnabled(on);\n\n    if (on) {\n        Visualizer *v = getVisualizer(winName);\n        if (v) { // TODO Replace rendering order using params\n            v->MoveRendererToFront(renderType, renderName);\n            v->MoveRenderersOfTypeToFront(VolumeRenderer::GetClassType());\n        }\n    }\n\n    _paramsMgr->EndSaveStateGroup();\n\n    return 0;\n}\n\nvoid ControlExec::_removeRendererHelper(string winName, string dataSetName, string pClassName, string renderName, bool hasOpenGLContext)\n{\n    // No-op if tuple of winName, dataSetName, renderType, and\n    // renderName is unknown\n    //\n\n    // Convert from params render type to render type. Sigh\n    //\n    string rClassName = RendererFactory::Instance()->GetRenderClassFromParamsClass(pClassName);\n\n    RenderParams *rParams = _paramsMgr->GetRenderParams(winName, dataSetName, pClassName, renderName);\n    if (!rParams) return;\n\n    Visualizer *v = getVisualizer(winName);\n    if (!v) return;\n\n    v->DestroyRenderer(rClassName, renderName, hasOpenGLContext);\n\n    _paramsMgr->RemoveRenderParamsInstance(winName, dataSetName, pClassName, renderName);\n}\n\nvoid ControlExec::RemoveRenderer(string winName, string dataSetName, string renderType, string renderName, bool hasOpenGLContext)\n{\n    string pClassName = RendererFactory::Instance()->GetParamsClassFromRenderClass(renderType);\n\n    RenderParams *rParams = _paramsMgr->GetRenderParams(winName, dataSetName, pClassName, renderName);\n    if (!rParams) return;\n\n    _removeRendererHelper(winName, dataSetName, pClassName, renderName, hasOpenGLContext);\n}\n\nvoid ControlExec::RemoveAllRenderers(string winName, bool hasOpenGLContext, bool removeFromParamsFlag)\n{\n    vector<string> dataSetNames = _paramsMgr->GetDataMgrNames();\n    for (int k = 0; k < dataSetNames.size(); k++) {\n        vector<string> pClassNames = _paramsMgr->GetRenderParamsClassNames(winName, dataSetNames[k]);\n\n        for (int j = 0; j < pClassNames.size(); j++) {\n            vector<string> instNames = _paramsMgr->GetRenderParamInstances(winName, dataSetNames[k], pClassNames[j]);\n\n            for (int i = 0; i < instNames.size(); i++) { _removeRendererHelper(winName, dataSetNames[k], pClassNames[j], instNames[i], hasOpenGLContext); }\n        }\n    }\n}\n\nvoid ControlExec::LoadState()\n{\n    _paramsMgr->LoadState();\n}\n\nvoid ControlExec::LoadState(const XmlNode *rootNode)\n{\n    _paramsMgr->LoadState(rootNode);\n}\n\nint ControlExec::LoadState(string stateFile, LoadStateRelAndAbsPathsExistAction relAndAbsPathsExistAction)\n{\n    _paramsMgr->BeginSaveStateGroup(\"Load state\");\n\n    vector<string> vizNames = GetVisualizerNames();\n    for (int i = 0; i < vizNames.size(); i++) { RemoveVisualizer(vizNames[i]); }\n\n    // Bug prevents using the real PM here\n    ParamsMgr tempPM({GUIStateParams::GetClassType()});\n    if (tempPM.LoadState(stateFile) < 0) {\n        _paramsMgr->EndSaveStateGroup();\n        return -1;\n    }\n\n    GUIStateParams *tmpGsp = (GUIStateParams *)tempPM.GetParams(GUIStateParams::GetClassType());\n    map<string, vector<string>> useRelativePaths;\n    auto sesDir = FileUtils::Dirname(stateFile);\n\n    for (auto dataset : tmpGsp->GetOpenDataSetNames()) {\n        auto paths = tmpGsp->GetOpenDataSetPaths(dataset);\n        auto relPaths = tmpGsp->GetOpenDataSetRelativePaths(dataset);\n        for (int i = 0; i < relPaths.size(); i++) relPaths[i] = FileUtils::JoinPaths({sesDir, relPaths[i]});\n        if (relPaths.empty())\n            continue;\n\n        auto absoluteExist = std::all_of(paths.begin(),    paths.end(),    [](string p){return FileUtils::Exists(p);});\n        auto relativeExist = std::all_of(relPaths.begin(), relPaths.end(), [](string p){return FileUtils::Exists(p);});\n\n        if (absoluteExist && !relativeExist) continue;\n        if (!absoluteExist && relativeExist) {\n            useRelativePaths[dataset] = relPaths;\n            continue;\n        }\n        if (absoluteExist && relativeExist) {\n            bool same = paths.size() == relPaths.size();\n            for (int i = 0; i < paths.size() && same; i++)\n                same &= FileUtils::AreSameFile(paths[i], relPaths[i]);\n\n            if (same) continue;\n\n            switch (relAndAbsPathsExistAction) {\n                case LoadStateRelAndAbsPathsExistAction::LoadAbs:\n                    continue;\n                case LoadStateRelAndAbsPathsExistAction::LoadRel:\n                    useRelativePaths[dataset] = relPaths;\n                    continue;\n                case LoadStateRelAndAbsPathsExistAction::Ask:\n                    _paramsMgr->EndSaveStateGroup();\n                    throw RelAndAbsPathsExistException(paths[0], relPaths[0]);\n            }\n        }\n    }\n\n    int rc = _paramsMgr->LoadState(stateFile);\n    if (rc < 0) {\n        _paramsMgr->EndSaveStateGroup();\n        return (-1);\n    }\n\n    auto gsp = (GUIStateParams *)_paramsMgr->GetParams(GUIStateParams::GetClassType());\n    for (const auto &it : useRelativePaths)\n        gsp->InsertOpenDataSet(it.first, gsp->GetOpenDataSetFormat(it.first), it.second);\n\n    _paramsMgr->EndSaveStateGroup();\n    return (0);\n}\n\nvoid ControlExec::SetNumThreads(size_t nthreads)\n{\n    // Set the number of PThreads to use\n    _dataStatus->SetNumThreads(nthreads);\n\n    if (nthreads > 0) { omp_set_num_threads(nthreads); }\n}\n\nsize_t ControlExec::GetNumThreads() const { return (_dataStatus->GetNumThreads()); }\n\nvoid ControlExec::SetCacheSize(size_t sizeMB) { _dataStatus->SetCacheSize(sizeMB); }\n\nint ControlExec::OpenData(const std::vector<string> &files, string dataSetName, string typ)\n{\n    _paramsMgr->BeginSaveStateGroup(\"Open Dataset\");\n\n    vector<string> options = {\"-project_to_pcs\", \"-vertical_xform\"};\n    if (GetParams<SettingsParams>()->GetAutoStretchEnabled()) options.push_back(\"-auto_stretch_z\");\n    // This is a minor bug if the first dataset has an empty proj string however this has been a bug for as long as I can tell and it is not worth fixing at the moment\n    if (!GetParams<GUIStateParams>()->GetProjectionString().empty()) STLUtils::AppendTo(options, {\"-proj4\", GetParams<GUIStateParams>()->GetProjectionString()});\n\n    SetDataCacheDirty(dataSetName);\n\n    int rc = _dataStatus->Open(files, options, dataSetName, typ);\n    if (rc < 0) {\n        SetErrMsg(\"Failure to open data set of type \\\"%s\\\"\", typ.c_str());\n        _paramsMgr->EndSaveStateGroup();\n        return -1;\n    }\n\n    _paramsMgr->AddDataMgr(dataSetName, _dataStatus->GetDataMgr(dataSetName));\n\n    // Need to call initializers for any registered application renderers\n    //\n    vector<RenderParams *> appRenderParams;\n    _paramsMgr->GetAppRenderParams(dataSetName, appRenderParams);\n    for (int i = 0; i < appRenderParams.size(); i++) {\n        int rc = appRenderParams[i]->Initialize();\n        if (rc < 0) {\n            _calcEngineMgr->Clean();\n            _dataStatus->Close(dataSetName);\n            _paramsMgr->RemoveDataMgr(dataSetName);\n            SetErrMsg(\"Failure to initialize application renderer \\\"%s\\\"\", appRenderParams[i]->GetName().c_str());\n            _paramsMgr->EndSaveStateGroup();\n            return -1;\n        }\n    }\n\n    _setDefaultOrigin(dataSetName);\n\n    if (STLUtils::Contains(options, string(\"-auto_stretch_z\"))) _autoStretchExtents(dataSetName);\n\n    // vvvv NOPs if existing used\n    _dataCachedProjStr = _dataStatus->GetMapProjection();\n    GetParams<GUIStateParams>()->SetProjectionString(_dataCachedProjStr);\n    // ^^^^\n\n    _paramsMgr->EndSaveStateGroup();\n    return rc;\n}\n\nvoid ControlExec::CloseData(string dataSetName)\n{\n    if (!_dataStatus->GetDataMgr(dataSetName)) return;\n    SetDataCacheDirty(dataSetName);\n\n    _paramsMgr->BeginSaveStateGroup(\"Close Dataset\");\n    GetParams<GUIStateParams>()->RemoveOpenDataSet(dataSetName);\n\n    for (const auto &renName : _paramsMgr->GetRenderParamNamesForDataset(dataSetName)) {\n        string vizName, className, _;\n        _paramsMgr->RenderParamsLookup(renName, vizName, _, className);\n        _paramsMgr->RemoveRenderParamsInstance(vizName, dataSetName, className, renName);\n    }\n\n    _paramsMgr->RemoveDataMgr(dataSetName);\n    _dataStatus->Close(dataSetName);\n\n    _paramsMgr->EndSaveStateGroup();\n}\n\nint ControlExec::EnableImageCapture(string filename, string winName, bool fast)\n{\n    Visualizer *v = getVisualizer(winName);\n    if (!v) {\n        SetErrMsg(\"Invalid Visualizer \\\"%s\\\"\", winName.c_str());\n        return -1;\n    }\n    if (v->SetImageCaptureEnabled(true, filename)) {\n        SetErrMsg(\"Visualizer (%s) failed to enable capturing  image.\", winName.c_str());\n        return -1;\n    }\n\n    // Disable state saving when capturing an image\n    //\n    bool enabled = _paramsMgr->GetSaveStateEnabled();\n    _paramsMgr->SetSaveStateEnabled(false);\n    int rc = v->paintEvent(fast);    // paint with image capture enabled\n    _paramsMgr->SetSaveStateEnabled(enabled);\n    if (rc != 0) {\n        SetErrMsg(\"Visualizer (%s) failed to paint and thus not capturing image.\", winName.c_str());\n        return -1;\n    }\n    return 0;\n}\n\nint ControlExec::EnableAnimationCapture(string winName, bool onOff, string filename)\n{\n    Visualizer *v = getVisualizer(winName);\n    if (!v) {\n        SetErrMsg(\"Invalid Visualizer \\\"%s\\\"\", winName.c_str());\n        return -1;\n    }\n\n    if (v->SetAnimationCaptureEnabled(onOff, filename)) return -1;\n    return 0;\n}\n\nstring ControlExec::MakeStringConformant(string s)\n{\n    if (s.empty()) s += \"_\";\n\n    if (!(isalpha(s[0]) || s[0] == '_')) { s = \"_\" + s; }\n\n    for (string::iterator itr = s.begin(); itr != s.end(); ++itr) {\n        if (!(isalnum(*itr) || isdigit(*itr) || *itr == '-' || *itr == '_' || *itr == '.')) { *itr = '_'; }\n        if (isspace(*itr)) { *itr = '_'; }\n    }\n    return (s);\n}\n\n\nint ControlExec::SaveSession(string filename)\n{\n    ofstream fileout;\n    const XmlNode *node = nullptr;\n\n    GUIStateParams *gsp = (GUIStateParams *)_paramsMgr->GetParams(GUIStateParams::GetClassType());\n    bool saveStateEnabled = _paramsMgr->GetSaveStateEnabled();\n    _paramsMgr->SetSaveStateEnabled(false);\n    auto datasets = gsp->GetOpenDataSetNames();\n    for (auto dataset : datasets) {\n        auto paths = gsp->GetOpenDataSetPaths(dataset);\n        auto format = gsp->GetOpenDataSetFormat(dataset);\n        vector<string> relpaths(paths.size());\n        for (int i = 0; i < paths.size(); i++) {\n            paths[i] = FileUtils::Realpath(paths[i]);\n            relpaths[i] = FileUtils::Relpath(paths[i], filename);\n        }\n        gsp->InsertOpenDataSet(dataset, format, paths, relpaths);\n    }\n    _paramsMgr->SetSaveStateEnabled(saveStateEnabled);\n\n    fileout.open(filename.c_str());\n    if (!fileout) {\n        SetErrMsg(\"Unable to open output session file : %M\");\n        return -1;\n    }\n\n    node = _paramsMgr->GetXMLRoot();\n    XmlNode::streamOut(fileout, *node);\n    if (fileout.bad()) {\n        SetErrMsg(\"Unable to write output session file : %M\");\n        return -1;\n    }\n\n    return 0;\n}\n\nRenderParams *ControlExec::GetRenderParams(string winName, string dataSetName, string renderType, string instName) const\n{\n    string paramsType = RendererFactory::Instance()->GetParamsClassFromRenderClass(renderType);\n\n    RenderParams *rParams = _paramsMgr->GetRenderParams(winName, dataSetName, paramsType, instName);\n\n    if (!rParams) {\n        SetErrMsg(\"Invalid window name, render type, or instance name\");\n        return (NULL);\n    }\n\n    return (rParams);\n}\n\nvector<string> ControlExec::GetRenderClassNames(string winName) const\n{\n    vector<string> v = _paramsMgr->GetRenderParamsClassNames(winName);\n\n    for (int i = 0; i < v.size(); i++) { v[i] = RendererFactory::Instance()->GetRenderClassFromParamsClass(v[i]); }\n\n    return (v);\n}\n\nvector<string> ControlExec::GetRenderInstances(string winName, string renderType) const\n{\n    string paramsType = RendererFactory::Instance()->GetParamsClassFromRenderClass(renderType);\n\n    return (_paramsMgr->GetRenderParamInstances(winName, paramsType));\n}\n\nvector<string> ControlExec::GetAllRenderClasses() { return (RendererFactory::Instance()->GetFactoryNames()); }\n\nbool ControlExec::RenderLookup(string instName, string &winName, string &dataSetName, string &renderType) const\n{\n    string paramsType;\n    bool   ok = _paramsMgr->RenderParamsLookup(instName, winName, dataSetName, paramsType);\n    if (!ok) return (ok);\n\n    renderType = RendererFactory::Instance()->GetRenderClassFromParamsClass(paramsType);\n    return (ok);\n}\n\nstring ControlExec::MakeRendererNameUnique(string name) const\n{\n    string newname = name;\n\n    ParamsMgr *pm = GetParamsMgr();\n\n    vector<string> allInstNames;\n\n    // Get ALL of the renderer instance names defined\n    //\n    vector<string> vizNames = pm->GetVisualizerNames();\n    for (int i = 0; i < vizNames.size(); i++) {\n        vector<string> classNames = GetRenderClassNames(vizNames[i]);\n\n        for (int j = 0; j < classNames.size(); j++) {\n            vector<string> rendererNames = GetRenderInstances(vizNames[i], classNames[j]);\n\n            allInstNames.insert(allInstNames.begin(), rendererNames.begin(), rendererNames.end());\n        }\n    }\n\n    while (1) {\n        bool match = false;\n        for (int i = 0; i < allInstNames.size(); i++) {\n            string usedName = allInstNames[i];\n\n            if (newname != usedName) continue;\n\n            match = true;\n\n            size_t lastnonint = newname.find_last_not_of(\"0123456789\");\n            if (lastnonint < newname.length() - 1) {\n                string endchars = newname.substr(lastnonint + 1);\n                int termInt = atoi(endchars.c_str());\n                termInt++;\n                std::stringstream ss;\n                ss << termInt;\n                endchars = ss.str();\n                newname.replace(lastnonint + 1, string::npos, endchars);\n            } else {\n                newname = newname + \"_1\";\n            }\n        }\n        if (!match) break;\n    }\n    return newname;\n}\n\nint ControlExec::AddFunction(string scriptType, string dataSetName, string scriptName, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames,\n                             const vector<string> &outputVarMeshes, bool coordFlag)\n{\n    // Ugh. Need to force each renderer to clear any cached data because\n    // if we redefine a variable the variable's data will change but\n    // the variable's name will not. Hence, if we don't clear the data\n    // the renderer may continue using old data\n    //\n//    ClearAllRenderCaches();\n\n    return (_calcEngineMgr->AddFunction(scriptType, dataSetName, scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag));\n}\n\nvoid ControlExec::RemoveFunction(string scriptType, string dataSetName, string scriptName) { return (_calcEngineMgr->RemoveFunction(scriptType, dataSetName, scriptName)); }\n\nbool ControlExec::GetFunction(string scriptType, string dataSetName, string scriptName, string &script, vector<string> &inputVarNames, vector<string> &outputVarNames, vector<string> &outputVarMeshes,\n                              bool &coordFlag) const\n{\n    script.clear();\n    inputVarNames.clear();\n    outputVarNames.clear();\n    outputVarMeshes.clear();\n\n    return (_calcEngineMgr->GetFunctionScript(scriptType, dataSetName, scriptName, script, inputVarNames, outputVarNames, outputVarMeshes, coordFlag));\n}\n\nstring ControlExec::GetFunctionStdout(string scriptType, string dataSetName, string scriptName) const { return (_calcEngineMgr->GetFunctionStdout(scriptType, dataSetName, scriptName)); }\n\nstd::vector<string> ControlExec::GetFunctionNames(string scriptType, string dataSetName) const { return (_calcEngineMgr->GetFunctionNames(scriptType, dataSetName)); }\n\n\n// Function moved from old NavigationEventRouter.cpp\nvoid ControlExec::_autoStretchExtents(string dataSetName)\n{\n    DataStatus *ds = GetDataStatus();\n\n    ParamsMgr *    paramsMgr = GetParamsMgr();\n    vector<string> winNames = paramsMgr->GetVisualizerNames();\n\n    CoordType minExt, maxExt;\n\n    for (int i = 0; i < winNames.size(); i++) {\n        ViewpointParams *   vpParams = paramsMgr->GetViewpointParams(winNames[i]);\n        Transform *         transform = vpParams->GetTransform(dataSetName);\n        std::vector<double> scales = transform->GetScales();\n        int                 xDimension = 0;\n        int                 yDimension = 1;\n        int                 zDimension = 2;\n\n        // If a dimension's scale is not 1.f, the user has saved a session with\n        // a non-default value.  Don't modify it.\n        if (scales[xDimension] != 1.f) continue;\n        if (scales[yDimension] != 1.f) continue;\n        if (scales[zDimension] != 1.f) continue;\n\n        //        size_t ts = GetCurrentTimeStep();\n        size_t ts = 0;\n        ds->GetActiveExtents(paramsMgr, winNames[i], dataSetName, ts, minExt, maxExt);\n\n        vector<float> range;\n        float         maxRange = 0.0;\n        for (int i = 0; i < minExt.size(); i++) {\n            float r = fabs(maxExt[i] - minExt[i]);\n            if (maxRange < r) { maxRange = r; }\n            range.push_back(r);\n        }\n\n        if (fabs(maxRange) <= FLT_EPSILON) maxRange = 1.0;\n\n        vector<double> scale(range.size(), 1.0);\n        for (int i = 0; i < range.size(); i++) {\n            if (range[i] < (maxRange / 10.0) && fabs(range[i]) > FLT_EPSILON) { scale[i] = maxRange / (10.0 * range[i]); }\n        }\n\n        transform->SetScales(scale);\n    }\n}\n\n\nvoid ControlExec::_setDefaultOrigin(string datasetName)\n{\n    DataStatus *ds = GetDataStatus();\n\n    ParamsMgr *    paramsMgr = GetParamsMgr();\n    vector<string> winNames = paramsMgr->GetVisualizerNames();\n\n    CoordType minExt, maxExt;\n\n    for (int i = 0; i < winNames.size(); i++) {\n        ViewpointParams *   vpParams = paramsMgr->GetViewpointParams(winNames[i]);\n        Transform *         transform = vpParams->GetTransform(datasetName);\n        std::vector<double> origin = transform->GetOrigin();\n\n        // Skip if not default\n        bool skip = false;\n        for (int i = 0; i < 3; i++)\n            if (origin[i] != 0.f) skip = true;\n        if (skip) continue;\n\n        size_t ts = 0;\n        ds->GetActiveExtents(paramsMgr, winNames[i], datasetName, ts, minExt, maxExt);\n\n        for (int i = 0; i < minExt.size(); i++) origin[i] = (maxExt[i] + minExt[i]) / 2;\n\n        transform->SetOrigin(origin);\n    }\n}\n\nbool ControlExec::WasDataCacheDirty() const {\n    return _dataStatus->WasCacheDirty() || _calcEngineMgr->_wasCacheDirty;\n}\n"
  },
  {
    "path": "lib/render/FlowRenderer.cpp",
    "content": "#include \"vapor/glutil.h\"\n#include \"vapor/FlowRenderer.h\"\n#include \"vapor/Particle.h\"\n#include \"vapor/AdvectionIO.h\"\n#include <iostream>\n#include <sstream>\n#include <cstring>\n#include <random>\n#include <algorithm>\n#include <vapor/Progress.h>\n\n#define GL_ERROR -20\n\nusing namespace VAPoR;\nusing glm::vec3;\nusing glm::vec4;\n\nstatic RendererRegistrar<FlowRenderer> registrar(FlowRenderer::GetClassType(), FlowParams::GetClassType());\n\n// Constructor\nFlowRenderer::FlowRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, FlowParams::GetClassType(), FlowRenderer::GetClassType(), instName, dataMgr),\n  _colorMapTexOffset(0)\n{\n}\n\n// Destructor\nFlowRenderer::~FlowRenderer()\n{\n    // Delete vertex arrays\n    if (_vertexArrayId) {\n        glDeleteVertexArrays(1, &_vertexArrayId);\n        _vertexArrayId = 0;\n    }\n    if (_vertexBufferId) {\n        glDeleteBuffers(1, &_vertexBufferId);\n        _vertexBufferId = 0;\n    }\n\n    if (_colorMapTexId) {\n        glDeleteTextures(1, &_colorMapTexId);\n        _colorMapTexId = 0;\n    }\n}\n\nstd::string FlowRenderer::_getColorbarVariableName() const { return GetActiveParams()->GetColorMapVariableName(); }\n\nint FlowRenderer::_initializeGL()\n{\n    _velocityField.AssignDataManager(_dataMgr);\n    _colorField.AssignDataManager(_dataMgr);\n    _timestamps = _dataMgr->GetTimeCoordinates();\n\n    // Followed by real OpenGL initializations\n    ShaderProgram *shader = nullptr;\n    if ((shader = _glManager->shaderManager->GetShader(\"FlowLine\")))\n        _shader = shader;\n    else\n        return GL_ERROR;\n\n    /* Create Vertex Array Object (VAO) */\n    glGenVertexArrays(1, &_vertexArrayId);\n    glGenBuffers(1, &_vertexBufferId);\n\n    /* Generate and configure 1D texture: _colorMapTexId */\n    glGenTextures(1, &_colorMapTexId);\n    glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTexId);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glBindTexture(GL_TEXTURE_1D, 0);\n\n    glGenVertexArrays(1, &_VAO);\n    glGenBuffers(1, &_VBO);\n\n    assert(_VAO);\n    assert(_VBO);\n\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), NULL);\n    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void *)sizeof(glm::vec3));\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n\n    return 0;\n}\n\nint FlowRenderer::_outputFlowLines()\n{\n    auto *params = dynamic_cast<FlowParams *>(GetActiveParams());\n    assert(params != nullptr);\n\n    // Retrieve additional variables that users require to sample\n    const auto addiVars = params->GetFlowOutputMoreVariables();\n\n    // Identify variables that an advection already has, but the user doesn't\n    // include in addiVars. Remove them.\n    //\n    // start by listing all variables as potentially to be removed\n    auto removeVars = _advection.GetPropertyVarNames();\n    auto containV = [&addiVars](const std::string &v) { return std::find(addiVars.cbegin(), addiVars.cend(), v) != addiVars.cend(); };\n    // remove those confirmed by the user from the \"to remove\" list\n    removeVars.erase(std::remove_if(removeVars.begin(), removeVars.end(), containV), removeVars.end());\n    for (const auto &rmV : removeVars) {\n        _advection.RemoveParticleProperty(rmV);\n\n        if (_2ndAdvection) _2ndAdvection->RemoveParticleProperty(rmV);\n    }\n\n    for (const auto &v : addiVars) {\n        // Create a VaporField with this variable\n        flow::VaporField varField;\n        varField.AssignDataManager(_dataMgr);\n        varField.UpdateParams(params);\n        varField.ScalarName = v;\n\n        // Sample values along the pathlines.\n        // Note that the advection class will do nothing if this variable already exists.\n        // Also note that the advection class will do a simple copy if this variable is\n        //   the same as particle values.\n        _advection.CalculateParticleProperties(&varField);\n        if (_2ndAdvection) _2ndAdvection->CalculateParticleProperties(&varField);\n    }\n\n    // In case of steady flow, output the number of particles that\n    // equals to the advection steps.\n    // In the case of unsteady flow, output particles that are up to\n    // the advection timestamp.\n    int rv;\n    if (params->GetIsSteady()) {\n        rv = flow::OutputFlowlinesNumSteps(&_advection, params->GetFlowlineOutputFilename().c_str(), params->GetSteadyNumOfSteps(), _dataMgr->GetMapProjection(), false);\n    } else {\n        rv = flow::OutputFlowlinesMaxTime(&_advection, params->GetFlowlineOutputFilename().c_str(), _timestamps.at(params->GetCurrentTimestep()), _dataMgr->GetMapProjection(), false);\n    }\n    if (rv != 0) {\n        MyBase::SetErrMsg(\"Output flow lines wrong!\");\n        return rv;\n    }\n\n    if (_2ndAdvection) {    // bi-directional advection\n        if (params->GetIsSteady()) {\n            rv = flow::OutputFlowlinesNumSteps(_2ndAdvection.get(), params->GetFlowlineOutputFilename().c_str(), params->GetSteadyNumOfSteps(), _dataMgr->GetMapProjection(), true);\n        } else {\n            rv = flow::OutputFlowlinesMaxTime(_2ndAdvection.get(), params->GetFlowlineOutputFilename().c_str(), _timestamps.at(params->GetCurrentTimestep()), _dataMgr->GetMapProjection(), true);\n        }\n        if (rv != 0) {\n            MyBase::SetErrMsg(\"Output flow lines wrong!\");\n            return rv;\n        }\n    }\n\n    return 0;\n}\n\nint FlowRenderer::_paintGL(bool fast)\n{\n    FlowParams *params = dynamic_cast<FlowParams *>(GetActiveParams());\n    int         rv = 0;    // return value\n\n    if (params->GetNeedFlowlineOutput()) {\n        rv = _outputFlowLines();\n        params->SetNeedFlowlineOutput(false);\n        _printNonZero(rv, __FILE__, __func__, __LINE__);\n        if (rv != 0) return rv;\n    }\n\n    rv = _updateFlowCacheAndStates(params);\n    _printNonZero(rv, __FILE__, __func__, __LINE__);\n    if (rv != 0) {\n        MyBase::SetErrMsg(\"Parameters not ready!\");\n        return flow::PARAMS_ERROR;\n    }\n\n    if (_velocityStatus != FlowStatus::UPTODATE || _colorStatus != FlowStatus::UPTODATE)\n        _renderStatus = FlowStatus::SIMPLE_OUTOFDATE;\n\n    _velocityField.UpdateParams(params);\n    _velocityField.ScalarName.clear();\n    auto vel_tmp = params->GetFieldVariableNames();\n    for (int i = 0; i < 3; i++) _velocityField.VelocityNames[i] = i < vel_tmp.size() ? vel_tmp[i] : \"\";\n\n    _colorField.UpdateParams(params);\n    for (int i = 0; i < 3; i++) _colorField.VelocityNames[i].clear();\n    _colorField.ScalarName = params->GetColorMapVariableName();\n\n    // In case there's 0 variable selected, meaning that more than 2 of the velocity\n    // variable names are empty strings, then the paint routine aborts.\n    if (_velocityField.GetNumOfEmptyVelocityNames() > 2) {\n        MyBase::SetErrMsg(\"Please provide at least 1 field variables for advection!\");\n        return flow::PARAMS_ERROR;\n    }\n\n    if (_velocityStatus == FlowStatus::SIMPLE_OUTOFDATE) {\n        // First step is to re-calculate deltaT\n        rv = _velocityField.CalcDeltaTFromCurrentTimeStep(_cache_deltaT);\n\n        _printNonZero(rv, __FILE__, __func__, __LINE__);\n        if (rv == flow::FIELD_ALL_ZERO) {\n            MyBase::SetErrMsg(\"The velocity field seems to contain only zero values!\");\n            return flow::PARAMS_ERROR;\n        } else if (rv != 0) {\n            MyBase::SetErrMsg(\"Update deltaT failed!\");\n            return rv;\n        }\n\n        // Obtain seeds for Flow Renderer.\n        std::vector<flow::Particle> seeds;\n        if (_cache_seedGenMode == FlowSeedMode::UNIFORM)\n            rv = _genSeedsRakeUniform(seeds);\n        else if (_cache_seedGenMode == FlowSeedMode::RANDOM)\n            rv = _genSeedsRakeRandom(seeds);\n        else if (_cache_seedGenMode == FlowSeedMode::RANDOM_BIAS)\n            rv = _genSeedsRakeRandomBiased(seeds);\n        else if (_cache_seedGenMode == FlowSeedMode::LIST)\n            rv = _genSeedsFromList(seeds);\n\n        _printNonZero(rv, __FILE__, __func__, __LINE__);\n        if (rv != 0) {\n            MyBase::SetErrMsg(\"Generating seeds failed!\");\n            return flow::NO_SEED_PARTICLE_YET;\n        }\n\n        // Note on UseSeedParticles(): this is the only function that resets\n        //   all the streams inside of an Advection class.\n        //   It should immediately be followed by a function to set its periodicity\n        _advection.UseSeedParticles(seeds);\n        rv = _updateAdvectionPeriodicity(&_advection);\n        _printNonZero(rv, __FILE__, __func__, __LINE__);\n        if (rv != 0) {\n            MyBase::SetErrMsg(\"Update Advection Periodicity failed!\");\n            return flow::GRID_ERROR;\n        }\n        if (_2ndAdvection)    // bi-directional advection\n        {\n            _2ndAdvection->UseSeedParticles(seeds);\n            rv = _updateAdvectionPeriodicity(_2ndAdvection.get());\n            _printNonZero(rv, __FILE__, __func__, __LINE__);\n            if (rv != 0) {\n                MyBase::SetErrMsg(\"Update Advection Periodicity failed!\");\n                return flow::GRID_ERROR;\n            }\n        }\n\n        _advectionComplete = false;\n        _velocityStatus = FlowStatus::UPTODATE;\n    } else if (_velocityStatus == FlowStatus::TIME_STEP_OOD) {\n        _advectionComplete = false;\n        _velocityStatus = FlowStatus::UPTODATE;\n    }\n\n    if (!params->UseSingleColor()) {\n        if (_colorStatus == FlowStatus::SIMPLE_OUTOFDATE) {\n            _advection.ResetParticleValues();\n            _coloringComplete = false;\n            _colorStatus = FlowStatus::UPTODATE;\n            if (_2ndAdvection)    // bi-directional advection\n                _2ndAdvection->ResetParticleValues();\n        } else if (_colorStatus == FlowStatus::TIME_STEP_OOD) {\n            _coloringComplete = false;\n            _colorStatus = FlowStatus::UPTODATE;\n        }\n    }\n\n    if (!_advectionComplete) {\n        auto deltaT = _cache_deltaT;\n        const auto fixedSteps = params->GetUseFixedAdvectionSteps();\n        if (fixedSteps && params->GetFixedAdvectionStepSize() > 0.0)\n          deltaT = params->GetFixedAdvectionStepSize();\n\n        rv = flow::ADVECT_HAPPENED;\n\n        // Advection scheme 1: advect a maximum number of steps.\n        // This scheme is used for steady flow\n        if (params->GetIsSteady()) {\n            // If the advection is single-directional\n            if (params->GetFlowDirection() == 1)    // backward integration\n                deltaT *= -1.0;\n            long numOfSteps = params->GetSteadyNumOfSteps();\n\n            Progress::StartIndefinite(\"Performing flowline calculations\");\n            Progress::Update(0);\n            rv = _advection.AdvectSteps(&_velocityField, deltaT, numOfSteps, fixedSteps);\n            _printNonZero(rv, __FILE__, __func__, __LINE__);\n\n            // If the advection is bi-directional\n            if (_2ndAdvection) {\n                Progress::Update(5);\n                assert(deltaT > 0.0);\n                auto deltaT2 = deltaT * -1.0;\n\n                rv = _2ndAdvection->AdvectSteps(&_velocityField, deltaT2, numOfSteps, fixedSteps);\n                _printNonZero(rv, __FILE__, __func__, __LINE__);\n            }\n            Progress::Finish();\n        }\n\n        // Advection scheme 2: advect to a certain timestamp.\n        // This scheme is used for unsteady flow\n        else {\n            for (int i = 1; i <= _cache_currentTS; i++) {\n                rv = _advection.AdvectTillTime(&_velocityField, _timestamps.at(i - 1), deltaT, _timestamps.at(i), fixedSteps);\n                _printNonZero(rv, __FILE__, __func__, __LINE__);\n            }\n        }\n\n        _advectionComplete = true;\n    }\n\n    if (!_coloringComplete) {\n        bool integrate = params->GetValueLong(params->_doIntegrationTag, false);\n        bool setAllToFinalValue = params->GetValueLong(params->_integrationSetAllToFinalValueTag, false);\n\n        if (integrate) {\n            vector<double> integrationVolumeMin, integrationVolumeMax;\n            params->GetIntegrationBox()->GetExtents(integrationVolumeMin, integrationVolumeMax);\n            float distScale = params->GetValueDouble(params->_integrationScalarTag, 1.f);\n            rv = _advection.CalculateParticleIntegratedValues(&_colorField, true, distScale, integrationVolumeMin, integrationVolumeMax);\n            _printNonZero(rv, __FILE__, __func__, __LINE__);\n            if (_2ndAdvection)    // bi-directional advection\n                rv = _2ndAdvection->CalculateParticleIntegratedValues(&_colorField, true, distScale, integrationVolumeMin, integrationVolumeMax);\n\n            if (setAllToFinalValue) {\n                int numSamplesPerStream;\n                if (_cache_isSteady)\n                    numSamplesPerStream = _cache_steadyNumOfSteps;\n                else\n                    numSamplesPerStream = _cache_currentTS;\n                _advection.SetAllStreamValuesToFinalValue(numSamplesPerStream);\n                if (_2ndAdvection) _2ndAdvection->SetAllStreamValuesToFinalValue(numSamplesPerStream);\n            }\n\n            vector<double> histoRange;\n            vector<long>   histo(256);\n            _advection.CalculateParticleHistogram(histoRange, histo);\n\n            params->SetValueLongVec(RenderParams::CustomHistogramDataTag, \"\", histo);\n            params->SetValueDoubleVec(RenderParams::CustomHistogramRangeTag, \"\", histoRange);\n        } else {\n            rv = _advection.CalculateParticleValues(&_colorField, true);\n            _printNonZero(rv, __FILE__, __func__, __LINE__);\n            if (_2ndAdvection)    // bi-directional advection\n                rv = _2ndAdvection->CalculateParticleValues(&_colorField, true);\n\n            if (params->GetValueDoubleVec(RenderParams::CustomHistogramRangeTag).size()) {\n                params->SetValueLongVec(RenderParams::CustomHistogramDataTag, \"\", {});\n                params->SetValueDoubleVec(RenderParams::CustomHistogramRangeTag, \"\", {});\n            }\n        }\n        _printNonZero(rv, __FILE__, __func__, __LINE__);\n        _coloringComplete = true;\n    }\n\n    glEnable(GL_DEPTH_TEST);\n    glDepthMask(true);\n\n    _prepareColormap(params);\n\n    rv = 0;\n\n    if (params->GetValueLong(\"old_render\", 0)) {\n        _renderFromAnAdvectionLegacy(&_advection, params, fast);\n        if (_2ndAdvection) {    // If the advection is bi-directional\n            _renderFromAnAdvectionLegacy(_2ndAdvection.get(), params, fast);\n        }\n    } else {\n        // Workaround for how bi-directional was implemented.\n        // The rendering caches the flow data on the GPU however it\n        // only caches one advection at a time. Since when using bidirectional\n        // flow it results in two separate advections, we need to reset the cache\n        // before each half is drawn.\n        if (_2ndAdvection) _renderStatus = FlowStatus::SIMPLE_OUTOFDATE;\n\n        rv |= _renderAdvection(&_advection);\n        _printNonZero(rv, __FILE__, __func__, __LINE__);\n        /* If the advection is bi-directional */\n        if (_2ndAdvection) {\n            _renderStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            rv |= _renderAdvection(_2ndAdvection.get());\n            _printNonZero(rv, __FILE__, __func__, __LINE__);\n        }\n    }\n\n    _restoreGLState();\n\n    // Release grids that are acquired during this paint event\n    // before their DataMgr is destroyed by others.\n    _velocityField.ReleaseLockedGrids();\n    _colorField.ReleaseLockedGrids();\n\n    return rv;\n}\n\nint FlowRenderer::_renderAdvection(const flow::Advection *adv)\n{\n    FlowParams *rp = dynamic_cast<FlowParams *>(GetActiveParams());\n\n    if (_renderStatus != FlowStatus::UPTODATE) {\n        int nStreams = adv->GetNumberOfStreams();\n\n        typedef struct {\n            vec3  p;\n            float v;\n        } Vertex;\n        vector<Vertex> vertices;\n        vector<int>    sizes;\n        vector<Vertex> sv;\n\n        // If streams are larger than this then need to skip remaining\n        size_t maxSamples = rp->GetSteadyNumOfSteps() + 1;\n\n        // First calculate the starting time stamp. Copied from legacy.\n        double startingTime = _timestamps[0];\n        if (!_cache_isSteady) {\n            startingTime = _timestamps[0];\n            // note that _cache_currentTS is cast to a signed integer.\n            if (int(_cache_currentTS) - _cache_pastNumOfTimeSteps > 0) startingTime = _timestamps[_cache_currentTS - _cache_pastNumOfTimeSteps];\n        }\n\n        for (int s = 0; s < nStreams; s++) {\n            const vector<flow::Particle> &stream = adv->GetStreamAt(s);\n            sv.clear();\n            int sn = stream.size();\n            if (_cache_isSteady) sn = std::min(sn, (int)maxSamples);\n\n            for (int i = 0; i < sn + 1; i++) {\n                // \"IsSpecial\" means don't render this sample.\n                if (i == sn || stream[i].IsSpecial()) {\n                    int svn = sv.size();\n\n                    if (svn < 2) {\n                        sv.clear();\n                        continue;\n                    }\n\n                    vec3 prep(-normalize(sv[1].p - sv[0].p) + sv[0].p);\n                    vec3 post(normalize(sv[svn - 1].p - sv[svn - 2].p) + sv[svn - 1].p);\n\n                    size_t vn = vertices.size();\n                    vertices.resize(vn + svn + 2);\n                    vertices[vn] = {prep, sv[0].v};\n                    vertices[vertices.size() - 1] = {post, sv[svn - 1].v};\n\n                    memcpy(vertices.data() + vn + 1, sv.data(), sizeof(Vertex) * svn);\n\n                    sizes.push_back(svn + 2);\n                    sv.clear();\n                } else {\n                    const flow::Particle &p = stream[i];\n\n                    if (_cache_isSteady) {\n                        sv.push_back({p.location, p.value});\n                    } else {\n                        if (p.time > _timestamps.at(_cache_currentTS)) continue;\n                        if (p.time >= startingTime) sv.push_back({p.location, p.value});\n                    }\n                }\n            }\n\n            _renderStatus = FlowStatus::UPTODATE;\n        }\n\n        assert(glIsVertexArray(_VAO) == GL_TRUE);\n        assert(glIsBuffer(_VBO) == GL_TRUE);\n\n        glBindVertexArray(_VAO);\n        glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n        glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_STREAM_DRAW);\n        glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n        _streamSizes = sizes;\n    }\n\n    bool show_dir = rp->GetValueLong(FlowParams::RenderShowStreamDirTag, false);\n\n    _renderAdvectionHelper(show_dir);\n    if (show_dir) _renderAdvectionHelper(false);\n\n    return 0;\n}\n\nint FlowRenderer::_renderAdvectionHelper(bool renderDirection)\n{\n    auto rp = GetActiveParams();\n\n    FlowParams::RenderType renderType = (FlowParams::RenderType)rp->GetValueLong(FlowParams::RenderTypeTag, FlowParams::RenderTypeStream);\n    FlowParams::GlpyhType  glyphType = (FlowParams::GlpyhType)rp->GetValueLong(FlowParams::RenderGlyphTypeTag, FlowParams::GlpyhTypeSphere);\n\n    bool  geom3d = rp->GetValueLong(FlowParams::RenderGeom3DTag, false);\n    float radiusBase = rp->GetValueDouble(FlowParams::RenderRadiusBaseTag, -1);\n    if (radiusBase == -1) {\n        CoordType mind, maxd;\n\n        // Need to find a non-empty variable from color mapping or velocity variables.\n        std::string nonEmptyVarName = rp->GetColorMapVariableName();\n        if (nonEmptyVarName.empty()) {\n            for (auto it = _velocityField.VelocityNames.cbegin(); it != _velocityField.VelocityNames.cend(); ++it) {\n                if (!it->empty()) {\n                    nonEmptyVarName = *it;\n                    break;\n                }\n            }\n        }\n        assert(!nonEmptyVarName.empty());\n\n        _dataMgr->GetVariableExtents(rp->GetCurrentTimestep(), nonEmptyVarName, rp->GetRefinementLevel(), rp->GetCompressionLevel(), mind, maxd);\n        vec3  min(mind[0], mind[1], mind[2]);\n        vec3  max(maxd[0], maxd[1], maxd[2]);\n        vec3  lens = max - min;\n        float largestDim = glm::max(lens.x, glm::max(lens.y, lens.z));\n        radiusBase = largestDim / 560.f;\n        rp->SetValueDouble(FlowParams::RenderRadiusBaseTag, \"\", radiusBase);\n    }\n    float radiusScalar = rp->GetValueDouble(FlowParams::RenderRadiusScalarTag, 1);\n    float radius = radiusBase * radiusScalar;\n    int   glyphStride = rp->GetValueLong(FlowParams::RenderGlyphStrideTag, 5);\n\n    ShaderProgram *shader = nullptr;\n\n    if (renderType == FlowParams::RenderTypeStream) {\n        if (geom3d)\n            if (renderDirection)\n                shader = _glManager->shaderManager->GetShader(\"FlowGlyphsTubeDirArrow\");\n            else\n                shader = _glManager->shaderManager->GetShader(\"FlowTubes\");\n        else if (renderDirection)\n            shader = _glManager->shaderManager->GetShader(\"FlowGlyphsLineDirArrow2D\");\n        else\n            shader = _glManager->shaderManager->GetShader(\"FlowLines\");\n    } else if (renderType == FlowParams::RenderTypeSamples) {\n        if (glyphType == FlowParams::GlpyhTypeSphere)\n            if (geom3d)\n                shader = _glManager->shaderManager->GetShader(\"FlowGlyphsSphereSplat\");\n            else\n                shader = _glManager->shaderManager->GetShader(\"FlowGlyphsSphere2D\");\n        else if (geom3d)\n            shader = _glManager->shaderManager->GetShader(\"FlowGlyphsArrow\");\n        else\n            shader = _glManager->shaderManager->GetShader(\"FlowGlyphsArrow2D\");\n    } else {\n        shader = _glManager->shaderManager->GetShader(\"FlowLines\");\n    }\n\n    if (!shader) return -1;\n\n    double m[16];\n    double cameraPosD[3], cameraUpD[3], cameraDirD[3];\n    _paramsMgr->GetViewpointParams(_winName)->GetModelViewMatrix(m);\n    _paramsMgr->GetViewpointParams(_winName)->ReconstructCamera(m, cameraPosD, cameraUpD, cameraDirD);\n    vec3 cameraDir = vec3(cameraDirD[0], cameraDirD[1], cameraDirD[2]);\n    vec3 cameraPos = vec3(cameraPosD[0], cameraPosD[1], cameraPosD[2]);\n\n    shader->Bind();\n    shader->SetUniform(\"P\", _glManager->matrixManager->GetProjectionMatrix());\n    shader->SetUniform(\"MV\", _glManager->matrixManager->GetModelViewMatrix());\n    shader->SetUniform(\"aspect\", _glManager->matrixManager->GetProjectionAspectRatio());\n    shader->SetUniform(\"radius\", radius);\n    shader->SetUniform(\"lightingEnabled\", true);\n    shader->SetUniform(\"glyphStride\", glyphStride);\n    shader->SetUniform(\"showOnlyLeadingSample\", (bool)rp->GetValueLong(FlowParams::RenderGlyphOnlyLeadingTag, false));\n    shader->SetUniform(\"scales\", _getScales());\n    shader->SetUniform(\"cameraPos\", cameraPos);\n    if (rp->GetValueLong(FlowParams::RenderLightAtCameraTag, true))\n        shader->SetUniform(\"lightDir\", cameraDir);\n    else\n        shader->SetUniform(\"lightDir\", vec3(0, 0, -1));\n    shader->SetUniform(\"phongAmbient\", (float)rp->GetValueDouble(FlowParams::PhongAmbientTag, 0));\n    shader->SetUniform(\"phongDiffuse\", (float)rp->GetValueDouble(FlowParams::PhongDiffuseTag, 0));\n    shader->SetUniform(\"phongSpecular\", (float)rp->GetValueDouble(FlowParams::PhongSpecularTag, 0));\n    shader->SetUniform(\"phongShininess\", (float)rp->GetValueDouble(FlowParams::PhongShininessTag, 0));\n\n    shader->SetUniform(\"mapRange\", glm::make_vec2(_colorMapRange));\n\n    shader->SetUniform(\"fade_tails\", (bool)rp->GetValueLong(FlowParams::RenderFadeTailTag, 0));\n    shader->SetUniform(\"fade_start\", (int)rp->GetValueLong(FlowParams::RenderFadeTailStartTag, 10));\n    shader->SetUniform(\"fade_length\", (int)rp->GetValueLong(FlowParams::RenderFadeTailLengthTag, 10));\n    shader->SetUniform(\"fade_stop\", (int)rp->GetValueLong(FlowParams::RenderFadeTailStopTag, 0));\n\n    shader->SetUniform(\"density\", renderType == FlowParams::RenderTypeDensity);\n    shader->SetUniform(\"falloff\", (float)rp->GetValueDouble(FlowParams::RenderDensityFalloffTag, 1));\n    shader->SetUniform(\"tone\", (float)rp->GetValueDouble(FlowParams::RenderDensityToneMappingTag, 1));\n\n    //    Features supported by shaders but not implemented in GUI/not finished\n    //\n    //    shader->SetUniform(\"constantColorEnabled\", false);\n    //    shader->SetUniform(\"Color\", vec3(1.0f));\n    //    shader->SetUniform(\"antiAlias\", (bool)rp->GetValueLong(\"anti_alias\", 0));\n    //    auto bcd = rp->GetValueDoubleVec(\"border_color\");\n    //    if (bcd.size())\n    //        shader->SetUniform(\"borderColor\", vec3((float)bcd[0], bcd[1], bcd[2]));\n    //    shader->SetUniform(\"border\", (float)rp->GetValueDouble(\"border\", 0));\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTexId);\n    shader->SetUniform(\"LUT\", 0);\n\n    EnableClipToBox(shader, 0.01);\n\n    glEnable(GL_CULL_FACE);\n    glFrontFace(GL_CCW);\n    glEnable(GL_BLEND);\n    glBindVertexArray(_VAO);\n\n    if (renderType == FlowParams::RenderTypeDensity) {\n        glBlendFunc(GL_SRC_ALPHA, GL_ONE);\n        if (rp->GetValueLong(\"invert\", false))\n            glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);\n        else\n            glBlendEquation(GL_FUNC_ADD);\n        glDepthMask(GL_FALSE);\n    }\n\n    size_t offset = 0;\n    for (int n : _streamSizes) {\n        shader->SetUniform(\"nVertices\", n);\n        glDrawArrays(GL_LINE_STRIP_ADJACENCY, offset, n);\n        offset += n;\n    }\n\n    glDepthMask(GL_TRUE);\n    glDisable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBindVertexArray(0);\n    glDisable(GL_CULL_FACE);\n    shader->UnBind();\n    DisableClippingPlanes();\n\n    return 0;\n}\n\nglm::vec3 FlowRenderer::_getScales()\n{\n    string                  myVisName = GetVisualizer();\n    VAPoR::ViewpointParams *vpp = _paramsMgr->GetViewpointParams(myVisName);\n    string                  datasetName = GetMyDatasetName();\n    Transform *             tDataset = vpp->GetTransform(datasetName);\n    Transform *             tRenderer = GetActiveParams()->GetTransform();\n\n    vector<double> scales = tDataset->GetScales();\n    vector<double> rendererScales = tRenderer->GetScales();\n\n    scales[0] *= rendererScales[0];\n    scales[1] *= rendererScales[1];\n    scales[2] *= rendererScales[2];\n\n    return vec3(scales[0], scales[1], scales[2]);\n}\n\nint FlowRenderer::_renderFromAnAdvectionLegacy(const flow::Advection *adv, FlowParams *params, bool fast)\n{\n    size_t numOfStreams = adv->GetNumberOfStreams();\n    auto   numOfPart = params->GetSteadyNumOfSteps() + 1;\n    bool   singleColor = params->UseSingleColor();\n\n    if (_cache_isSteady) {\n        std::vector<float> vec;\n        for (size_t s = 0; s < numOfStreams; s++) {\n            const auto &stream = adv->GetStreamAt(s);\n            for (size_t i = 0; i < stream.size() && i < numOfPart; i++) {\n                const auto &p = stream[i];\n                _particleHelper1(vec, p, singleColor);\n            }    // Finish processing a stream\n            if (!vec.empty()) {\n                _drawALineStrip(vec.data(), vec.size() / 4, singleColor);\n                vec.clear();\n            }\n        }     // Finish processing all streams\n    } else    // Unsteady flow (only occurs with forward direction)\n    {\n        // First calculate the starting time stamp\n        double startingTime = _timestamps[0];\n        if (int(_cache_currentTS) - _cache_pastNumOfTimeSteps > 0) startingTime = _timestamps[_cache_currentTS - _cache_pastNumOfTimeSteps];\n\n        std::vector<float> vec;\n        for (size_t s = 0; s < numOfStreams; s++) {\n            const auto &stream = adv->GetStreamAt(s);\n            for (const auto &p : stream) {\n                if (p.IsSpecial())    // If p is a separator, directly send it to the helper function\n                {\n                    _particleHelper1(vec, p, singleColor);\n                } else    // Otherwise, examine its timestamp to decide how to handle\n                {         // Finish this stream once we go beyond the current TS\n                    if (p.time > _timestamps.at(_cache_currentTS)) break;\n\n                    // Only start this stream if the current time stamp passes startingTime\n                    if (p.time >= startingTime) _particleHelper1(vec, p, singleColor);\n                }\n            }    // Finish processing a stream\n\n            if (!vec.empty()) {\n                _drawALineStrip(vec.data(), vec.size() / 4, singleColor);\n                vec.clear();\n            }\n        }    // Finish processing all streams\n    }\n\n    return 0;\n}\n\nvoid FlowRenderer::_particleHelper1(std::vector<float> &vec, const flow::Particle &p, bool singleColor) const\n{\n    if (!p.IsSpecial())    // p isn't a separator\n    {\n        vec.push_back(p.location.x);\n        vec.push_back(p.location.y);\n        vec.push_back(p.location.z);\n        vec.push_back(p.value);\n    } else if (vec.size() > 0)    // p is a separator and vec is non-empty\n    {\n        _drawALineStrip(vec.data(), vec.size() / 4, singleColor);\n        vec.clear();\n    }\n}\n\nint FlowRenderer::_drawALineStrip(const float *buf, size_t numOfParts, bool singleColor) const\n{\n    // Make some OpenGL function calls\n    glm::mat4 modelview = _glManager->matrixManager->GetModelViewMatrix();\n    glm::mat4 projection = _glManager->matrixManager->GetProjectionMatrix();\n    _shader->Bind();\n    _shader->SetUniform(\"MV\", modelview);\n    _shader->SetUniform(\"Projection\", projection);\n    _shader->SetUniform(\"colorMapRange\", glm::make_vec3(_colorMapRange));\n    _shader->SetUniform(\"singleColor\", int(singleColor));\n    Renderer::EnableClipToBox(_shader, 0.01);\n\n    glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTexId);\n    _shader->SetUniform(\"colorMapTexture\", _colorMapTexOffset);\n\n    glBindVertexArray(_vertexArrayId);\n    glEnableVertexAttribArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);\n    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * numOfParts, buf, GL_STREAM_DRAW);\n    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (void *)0);\n    glDrawArrays(GL_LINE_STRIP, 0, numOfParts);\n\n    // Some OpenGL cleanup\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glDisableVertexAttribArray(0);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTexId);\n    glBindVertexArray(0);\n\n    return 0;\n}\n\nint FlowRenderer::_updateFlowCacheAndStates(const FlowParams *params)\n{\n    /*\n     * This function servers two purposes:\n     * 1) update the cached parameters, and 2) determine if the advection is out of date.\n     *\n     * Strategy:\n     * First, compare parameters that if changed, they would put both steady and unsteady\n     * streams out of date.\n     * Second, branch into steady and unsteady cases, and deal with them separately.\n     */\n\n    // Check seed generation mode\n    if (_cache_seedGenMode != static_cast<FlowSeedMode>(params->GetSeedGenMode())) {\n        _cache_seedGenMode = static_cast<FlowSeedMode>(params->GetSeedGenMode());\n        _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n\n    // Check seed input filename\n    if (_cache_seedInputFilename != params->GetSeedInputFilename()) {\n        _cache_seedInputFilename = params->GetSeedInputFilename();\n        // we only update status if the current seed generation mode IS seed list.\n        if (_cache_seedGenMode == FlowSeedMode::LIST) {\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        }\n    }\n\n    // Check velocity variable names\n    // If names not the same, entire stream is out of date\n    // Note: variable names are kept in VaporFields.\n    // Note: RenderParams always returns arrays of size 3 here.\n    std::vector<std::string> varnames = params->GetFieldVariableNames();\n    if ((varnames.at(0) != _velocityField.VelocityNames[0]) || (varnames.at(1) != _velocityField.VelocityNames[1]) || (varnames.at(2) != _velocityField.VelocityNames[2])) {\n        _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        // When new velocity variables are selected, new particles will be generated,\n        // so we should declare color status out of date too.\n        _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n\n    // Check color mapping variable names\n    std::string colorVarName = params->GetColorMapVariableName();\n    if (colorVarName != _colorField.ScalarName) { _colorStatus = FlowStatus::SIMPLE_OUTOFDATE; }\n\n    // Check compression parameters\n    // If these parameters not the same, entire stream is out of date\n    if (_cache_refinementLevel != params->GetRefinementLevel()) {\n        _cache_refinementLevel = params->GetRefinementLevel();\n        _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n    if (_cache_compressionLevel != params->GetCompressionLevel()) {\n        _cache_compressionLevel = params->GetCompressionLevel();\n        _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n\n    // Check velocity multiplier\n    // If the multiplier is changed, then the entire stream is out of date\n    if (_cache_velocityMltp != params->GetVelocityMultiplier()) {\n        _cache_velocityMltp = params->GetVelocityMultiplier();\n        _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n\n    // Check first step size multiplier\n    // If the multiplier is changed, then the entire stream is out of date\n    if (_cache_firstStepSizeMltp != params->GetFirstStepSizeMultiplier()) {\n        _cache_firstStepSizeMltp = params->GetFirstStepSizeMultiplier();\n        _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n\n    // Check if using the fixed advection steps.\n    // If changed, then the entire stream is out ot date.\n    if (_cache_useFixedAdvectionSteps != params->GetUseFixedAdvectionSteps()) {\n      _cache_useFixedAdvectionSteps = params->GetUseFixedAdvectionSteps();\n      _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n      _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n\n    // Check if the fixed advection step size is out of date only when specified to use fixed steps.\n    if (_cache_useFixedAdvectionSteps && _cache_fixedAdvectionStepSize != params->GetFixedAdvectionStepSize()) {\n      _cache_fixedAdvectionStepSize = params->GetFixedAdvectionStepSize();\n      _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n      _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n    \n\n    // Check periodicity\n    // If periodicity changes along any dimension, then the entire stream is out of date\n    // Note: FlowParams return a vector of size either 2 or 3.\n    bool       diff = false;\n    const auto peri = params->GetPeriodic();\n    if (peri.size() != _cache_periodic.size())\n        diff = true;\n    else {\n        for (int i = 0; i < peri.size(); i++)\n            if (peri[i] != _cache_periodic[i]) {\n                diff = true;\n                break;\n            }\n    }\n    if (diff) {\n        _cache_periodic = peri;\n        _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n\n    // Check the rake defined by 6 or 4 extents.\n    // We update these parameters anyway, and decide if the advection is out of date in rake mode.\n    diff = false;\n    const auto rake = params->GetRake();\n    if (rake.size() != _cache_rake.size())\n        diff = true;\n    else {\n        for (int i = 0; i < rake.size(); i++)\n            if (rake[i] != _cache_rake[i]) {\n                diff = true;\n                break;\n            }\n    }\n    if (diff) {\n        _cache_rake = rake;\n        // Mark out-of-date if we're currently using any mode that involves a rake\n        if (_cache_seedGenMode != FlowSeedMode::LIST) {\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        }\n    }\n\n    // Check the gridded number of seeds in the rake\n    diff = false;\n    const auto gridNOS = params->GetGridNumOfSeeds();\n    if (gridNOS.size() != _cache_gridNumOfSeeds.size())\n        diff = true;\n    else {\n        for (int i = 0; i < gridNOS.size(); i++)\n            if (gridNOS[i] != _cache_gridNumOfSeeds[i]) {\n                diff = true;\n                break;\n            }\n    }\n    if (diff) {\n        _cache_gridNumOfSeeds = gridNOS;\n        if (_cache_seedGenMode == FlowSeedMode::UNIFORM) {\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        }\n    }\n\n    // Check the random num of seeds\n    const auto randNOS = params->GetRandomNumOfSeeds();\n    if (randNOS != _cache_randNumOfSeeds) {\n        _cache_randNumOfSeeds = randNOS;\n        if (_cache_seedGenMode == FlowSeedMode::RANDOM || _cache_seedGenMode == FlowSeedMode::RANDOM_BIAS) {\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        }\n    }\n\n    // Check the bias variable and bias strength\n    const auto rakeBiasVariable = params->GetRakeBiasVariable();\n    const auto rakeBiasStrength = params->GetRakeBiasStrength();\n    if (_cache_rakeBiasStrength != rakeBiasStrength || _cache_rakeBiasVariable.compare(rakeBiasVariable) != 0) {\n        _cache_rakeBiasVariable = rakeBiasVariable;\n        _cache_rakeBiasStrength = rakeBiasStrength;\n\n        if (_cache_seedGenMode == FlowSeedMode::RANDOM_BIAS) {\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        }\n    }\n\n    const auto doIntegration = params->GetValueLong(params->_doIntegrationTag, false);\n    const auto integrationSetAllToFinalValue = params->GetValueLong(params->_integrationSetAllToFinalValueTag, false);\n    const auto integrationDistScalar = params->GetValueDouble(params->_integrationScalarTag, false);\n    const auto integrationVolume = params->GetValueDoubleVec(params->_integrationBoxTag);\n    if (doIntegration != _cache_doIntegration || integrationSetAllToFinalValue != _cache_integrationSetAllToFinalValue || integrationDistScalar != _cache_integrationDistScalar\n        || integrationVolume != _cache_integrationVolume) {\n        _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n    }\n    _cache_doIntegration = doIntegration;\n    _cache_integrationSetAllToFinalValue = integrationSetAllToFinalValue;\n    _cache_integrationDistScalar = integrationDistScalar;\n    _cache_integrationVolume = integrationVolume;\n\n    //\n    // Now we branch into steady and unsteady cases, and treat them separately\n    //\n    if (params->GetIsSteady()) {\n        if (_cache_isSteady)    // steady state isn't changed\n        {\n            if (params->GetSteadyNumOfSteps() > _cache_steadyNumOfSteps) {\n                if (_colorStatus == FlowStatus::UPTODATE) _colorStatus = FlowStatus::TIME_STEP_OOD;\n                if (_velocityStatus == FlowStatus::UPTODATE) _velocityStatus = FlowStatus::TIME_STEP_OOD;\n            }\n            if (params->GetSteadyNumOfSteps() != _cache_steadyNumOfSteps) _renderStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            if (params->GetSteadyNumOfSteps() < _cache_steadyNumOfSteps && doIntegration) _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _cache_steadyNumOfSteps = params->GetSteadyNumOfSteps();\n\n            if (_cache_currentTS != params->GetCurrentTimestep()) {\n                _cache_currentTS = params->GetCurrentTimestep();\n                _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n                _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            }\n        } else    // switched from unsteady to steady. Everything is out of date in this case.\n        {\n            _cache_isSteady = true;\n            _cache_steadyNumOfSteps = params->GetSteadyNumOfSteps();\n            _cache_currentTS = params->GetCurrentTimestep();\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        }\n\n        if (_cache_flowDir != static_cast<FlowDir>(params->GetFlowDirection())) {\n            _cache_flowDir = static_cast<FlowDir>(params->GetFlowDirection());\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            if (_cache_flowDir == FlowDir::BI_DIR)\n                _2ndAdvection.reset(new flow::Advection());\n            else\n                _2ndAdvection.reset(nullptr);\n        }\n    } else    // in case of unsteady flow\n    {\n        if (!_cache_isSteady)    // unsteady state isn't changed\n        {\n            // First consider if the advection needs to be updated.\n            if (_cache_currentTS < params->GetCurrentTimestep()) {\n                if (_colorStatus == FlowStatus::UPTODATE) { _colorStatus = FlowStatus::TIME_STEP_OOD; }\n                if (_velocityStatus == FlowStatus::UPTODATE) { _velocityStatus = FlowStatus::TIME_STEP_OOD; }\n            }\n\n            // Second consider if the rendering needs to be updated.\n            if (_cache_currentTS != params->GetCurrentTimestep() || _cache_pastNumOfTimeSteps != params->GetPastNumOfTimeSteps()) { _renderStatus = FlowStatus::SIMPLE_OUTOFDATE; }\n            _cache_currentTS = params->GetCurrentTimestep();\n            _cache_steadyNumOfSteps = params->GetSteadyNumOfSteps();\n            _cache_pastNumOfTimeSteps = params->GetPastNumOfTimeSteps();\n        } else    // switched from steady to unsteady\n        {\n            _cache_isSteady = false;\n            _cache_steadyNumOfSteps = params->GetSteadyNumOfSteps();\n            _cache_currentTS = params->GetCurrentTimestep();\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        }\n\n        if (_cache_seedInjInterval != params->GetSeedInjInterval()) {\n            _cache_seedInjInterval = params->GetSeedInjInterval();\n            _colorStatus = FlowStatus::SIMPLE_OUTOFDATE;\n            _velocityStatus = FlowStatus::SIMPLE_OUTOFDATE;\n        }\n    }\n\n    return 0;\n}\n\nvoid FlowRenderer::_dupSeedsNewTime(std::vector<flow::Particle> &seeds, size_t firstN, double newTime) const\n{\n    VAssert(firstN <= seeds.size());\n    for (size_t i = 0; i < firstN; i++) seeds.emplace_back(seeds[i].location, newTime);\n}\n\nint FlowRenderer::_genSeedsRakeUniform(std::vector<flow::Particle> &seeds) const\n{\n    FlowParams *params = dynamic_cast<FlowParams *>(GetActiveParams());\n    VAssert(params);\n\n    // sanity check: rake extents and uniform seed numbers match dims\n    size_t dim = _cache_gridNumOfSeeds.size();\n    VAssert(dim == 2 || dim == 3);\n    VAssert(_cache_rake.size() == dim * 2);\n\n    // Populate the list of seeds\n    float start[3], step[3];\n    for (size_t i = 0; i < dim; i++) {\n        step[i] = (_cache_rake[i * 2 + 1] - _cache_rake[i * 2]) / float(_cache_gridNumOfSeeds[i]);\n        start[i] = _cache_rake[i * 2];\n    }\n    if (dim == 2) {\n        start[2] = Renderer::GetDefaultZ(_dataMgr, params->GetCurrentTimestep());\n        step[2] = 0.0f;\n    }\n    size_t seedsZ = 1;\n    if (dim == 3) { seedsZ = _cache_gridNumOfSeeds[2]; }\n\n    auto      timeVal = _timestamps.at(0);    // Default time value\n    glm::vec3 loc;\n    seeds.clear();\n    seeds.reserve(seedsZ * _cache_gridNumOfSeeds[1] * _cache_gridNumOfSeeds[0]);\n    for (long k = 0; k < seedsZ; k++) {\n        for (long j = 0; j < _cache_gridNumOfSeeds[1]; j++) {\n            for (long i = 0; i < _cache_gridNumOfSeeds[0]; i++) {\n                loc.x = start[0] + (float(i) + 0.5f) * step[0];\n                loc.y = start[1] + (float(j) + 0.5f) * step[1];\n                loc.z = start[2] + (float(k) + 0.5f) * step[2];\n                seeds.emplace_back(loc, timeVal);\n            }\n        }\n    }\n\n    // If in unsteady case and there are multiple seed injections,\n    //   we insert more seeds.\n    if (!_cache_isSteady && _cache_seedInjInterval > 0) {\n        size_t firstN = seeds.size();\n        // Check every time step available, see if we need to inject seeds at that time step\n        for (size_t ts = 1; ts < _timestamps.size(); ts++)\n            if (ts % _cache_seedInjInterval == 0) { _dupSeedsNewTime(seeds, firstN, _timestamps[ts]); }\n    }\n\n    return 0;\n}\n\nint FlowRenderer::_genSeedsFromList(std::vector<flow::Particle> &seeds) const\n{\n    FlowParams *params = dynamic_cast<FlowParams *>(GetActiveParams());\n    VAssert(params);\n\n    // Read seed locations (X, Y, Z) from a file.\n    std::vector<flow::Particle> read_from_disk = flow::InputSeedsCSV(params->GetSeedInputFilename());\n    if (read_from_disk.empty()) return flow::NO_SEED_PARTICLE_YET;\n\n    // Set seed time to be the time stamp at step 0\n    double timeVal = _timestamps.at(0);\n    for (auto &seed : read_from_disk) seed.time = timeVal;\n\n    seeds = std::move(read_from_disk);\n\n    // If in unsteady case and there are multiple seed injections, we insert more seeds.\n    if (!_cache_isSteady && _cache_seedInjInterval > 0) {\n        size_t firstN = seeds.size();\n        // Check every time step available, see if we need to inject seeds at that time step\n        for (size_t ts = 1; ts < _timestamps.size(); ts++) {\n            if (ts % _cache_seedInjInterval == 0) { _dupSeedsNewTime(seeds, firstN, _timestamps[ts]); }\n        }\n    }\n\n    return 0;\n}\n\nint FlowRenderer::_genSeedsRakeRandom(std::vector<flow::Particle> &seeds) const\n{\n    FlowParams *params = dynamic_cast<FlowParams *>(GetActiveParams());\n\n    VAssert(_cache_rake.size() == 6 || _cache_rake.size() == 4);\n    int dim = _cache_rake.size() / 2;\n    for (int i = 0; i < dim; i++) VAssert(_cache_rake[i * 2 + 1] >= _cache_rake[i * 2]);\n\n    /* Create uniform distributions along 2 or 3 dimensions */\n    /* Use a fixed value for the generator seed.          */\n    unsigned int                          randSeed = 32;\n    std::mt19937                          gen(randSeed);    // Standard mersenne_twister_engine\n    std::uniform_real_distribution<float> distX(_cache_rake[0], _cache_rake[1]);\n    std::uniform_real_distribution<float> distY(_cache_rake[2], _cache_rake[3]);\n\n    auto timeVal = _timestamps.at(0);\n    seeds.resize(_cache_randNumOfSeeds);\n    if (dim == 3) {\n        std::uniform_real_distribution<float> distZ(_cache_rake[4], _cache_rake[5]);\n        for (long i = 0; i < _cache_randNumOfSeeds; i++) {\n            seeds[i].location.x = distX(gen);\n            seeds[i].location.y = distY(gen);\n            seeds[i].location.z = distZ(gen);\n            seeds[i].time = timeVal;\n        }\n    } else {\n        const float dfz = Renderer::GetDefaultZ(_dataMgr, params->GetCurrentTimestep());\n        for (long i = 0; i < _cache_randNumOfSeeds; i++) {\n            seeds[i].location.x = distX(gen);\n            seeds[i].location.y = distY(gen);\n            seeds[i].location.z = dfz;\n            seeds[i].time = timeVal;\n        }\n    }\n\n    // If in unsteady case and there are multiple seed injections, we insert more seeds.\n    if (!_cache_isSteady && _cache_seedInjInterval > 0) {\n        size_t firstN = seeds.size();\n        // Check every time step available, see if we need to inject seeds at that time step\n        for (size_t ts = 1; ts < _timestamps.size(); ts++) {\n            if (ts % _cache_seedInjInterval == 0) { _dupSeedsNewTime(seeds, firstN, _timestamps[ts]); }\n        }\n    }\n\n    return 0;\n}\n\nint FlowRenderer::_genSeedsRakeRandomBiased(std::vector<flow::Particle> &seeds) const\n{\n    FlowParams *params = dynamic_cast<FlowParams *>(GetActiveParams());\n\n    VAssert(_cache_rake.size() == 6 || _cache_rake.size() == 4);\n    int dim = _cache_rake.size() / 2;\n    for (int i = 0; i < dim; i++) VAssert(_cache_rake[i * 2 + 1] >= _cache_rake[i * 2]);\n    CoordType rakeExtMin = {0.0, 0.0, 0.0};\n    CoordType rakeExtMax = {0.0, 0.0, 0.0};\n    for (int i = 0; i < dim; i++) {\n        rakeExtMin[i] = _cache_rake[i * 2];\n        rakeExtMax[i] = _cache_rake[i * 2 + 1];\n    }\n\n    const auto numOfSeedsNeeded = _cache_randNumOfSeeds;\n\n    /* request a grid representing the rake area */\n    Grid *grid = _dataMgr->GetVariable(params->GetCurrentTimestep(), _cache_rakeBiasVariable, params->GetRefinementLevel(), params->GetCompressionLevel(), rakeExtMin, rakeExtMax);\n    if (grid == nullptr) {\n        MyBase::SetErrMsg(\"Not able to get a grid!\");\n        return flow::GRID_ERROR;\n    }\n\n    /*\n     * The bias strategy is:\n     * We generate more random seeds than needed, and then sort them.\n     * The first batch of these seeds are used as the final seeds.\n     */\n\n    /* Create three uniform distributions in 3 dimensions */\n    unsigned int                          procID = 32;\n    std::mt19937                          gen(procID);    // Standard mersenne_twister engine\n    std::uniform_real_distribution<float> distX(_cache_rake[0], _cache_rake[1]);\n    std::uniform_real_distribution<float> distY(_cache_rake[2], _cache_rake[3]);\n\n    // Now we generate many seeds.\n    // We test missing values in case 1) the bias variable does have missing values, and 2)\n    // the rake extents are outside of the bias variable.\n    // Thus, we only keep random seeds that are falling on non-missing-value locations.\n    glm::vec3           loc;\n    std::vector<double> locD(3);\n    auto                timeVal = _timestamps.at(0);\n    // This is the total number of seeds to generate, based on the bias strength.\n    auto numOfSeedsToGen = numOfSeedsNeeded * (std::abs(_cache_rakeBiasStrength) + 1);\n    long numOfTrials = 0;\n    seeds.clear();\n    seeds.reserve(numOfSeedsToGen);    // For performance reasons\n    // Note: in the case that too many random seeds fall on missing values,\n    // we set a limit of 10 times numOfSeedsToGen.\n    long  numOfTrialLimit = 10 * numOfSeedsToGen;\n    float val, mv = grid->GetMissingValue();\n    if (dim == 3) {\n        std::uniform_real_distribution<float> distZ(_cache_rake[4], _cache_rake[5]);\n        while (numOfTrials < numOfTrialLimit && seeds.size() < numOfSeedsToGen) {\n            loc.x = distX(gen);\n            locD[0] = loc.x;\n            loc.y = distY(gen);\n            locD[1] = loc.y;\n            loc.z = distZ(gen);\n            locD[2] = loc.z;\n            val = grid->GetValue(locD);\n            if (val != mv) seeds.emplace_back(loc, timeVal, val);\n            numOfTrials++;\n        }\n    } else    // dim == 2\n    {\n        const auto dfz = Renderer::GetDefaultZ(_dataMgr, params->GetCurrentTimestep());\n        loc.z = dfz;\n        locD[2] = dfz;\n        while (numOfTrials < numOfTrialLimit && seeds.size() < numOfSeedsToGen) {\n            loc.x = distX(gen);\n            locD[0] = loc.x;\n            loc.y = distY(gen);\n            locD[1] = loc.y;\n            val = grid->GetValue(locD);\n            if (val != mv) seeds.emplace_back(loc, timeVal, val);\n            numOfTrials++;\n        }\n    }\n\n    delete grid;    // Delete the temporary grid\n\n    // If we reach numOfTrialLimit without collecting enough seeds, bail.\n    if (numOfTrials == numOfTrialLimit && seeds.size() < numOfSeedsNeeded) {\n        seeds.clear();\n        return flow::GRID_ERROR;\n    }\n\n    // How we sort all seeds based on their values\n    auto ascLambda = [](const flow::Particle &p1, const flow::Particle &p2) { return p1.value < p2.value; };\n    auto desLambda = [](const flow::Particle &p1, const flow::Particle &p2) { return p2.value < p1.value; };\n    if (_cache_rakeBiasStrength < 0) {\n        std::nth_element(seeds.begin(), seeds.begin() + numOfSeedsNeeded, seeds.end(), ascLambda);\n    } else {\n        std::nth_element(seeds.begin(), seeds.begin() + numOfSeedsNeeded, seeds.end(), desLambda);\n    }\n\n    seeds.resize(numOfSeedsNeeded);    // We only take first chunck of seeds that we need\n    seeds.shrink_to_fit();             // Free up some memory\n    for (auto &e : seeds) {            // reset the value field of each particle\n        e.value = 0.0;\n    }\n\n    // If in unsteady case and there are multiple seed injections, we insert more seeds.\n    if (!_cache_isSteady && _cache_seedInjInterval > 0) {\n        size_t firstN = seeds.size();\n        // Check every time step available, see if we need to inject seeds at that time step\n        for (size_t ts = 1; ts < _timestamps.size(); ts++) {\n            if (ts % _cache_seedInjInterval == 0) { _dupSeedsNewTime(seeds, firstN, _timestamps[ts]); }\n        }\n    }\n\n    return 0;\n}\n\nvoid FlowRenderer::_prepareColormap(FlowParams *params)\n{\n    if (params->UseSingleColor()) {\n        float singleColor[4];\n        params->GetConstantColor(singleColor);\n        singleColor[3] = 1.0f;    // 1.0 in alpha channel\n        _colorMap.resize(8);      // _colorMap will have 2 RGBA values\n        for (int i = 0; i < 8; i++) _colorMap[i] = singleColor[i % 4];\n        _colorMapRange[0] = 0.0f;     // min value of the color map\n        _colorMapRange[1] = 0.0f;     // max value of the color map\n        _colorMapRange[2] = 1e-5f;    // diff of color map. Has to be non-zero though.\n    } else {\n        // This is the line that's not const\n        VAPoR::MapperFunction *mapperFunc = params->GetMapperFunc(params->GetColorMapVariableName());\n        mapperFunc->makeLut(_colorMap);\n        assert(_colorMap.size() % 4 == 0);\n        std::vector<double> range = mapperFunc->getMinMaxMapValue();\n        _colorMapRange[0] = float(range[0]);\n        _colorMapRange[1] = float(range[1]);\n        _colorMapRange[2] = (_colorMapRange[1] - _colorMapRange[0]) > 1e-5f ? (_colorMapRange[1] - _colorMapRange[0]) : 1e-5f;\n    }\n    glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTexId);\n    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, _colorMap.size() / 4, 0, GL_RGBA, GL_FLOAT, _colorMap.data());\n}\n\nvoid FlowRenderer::_restoreGLState() const\n{\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, 0);\n}\n\nint FlowRenderer::_updateAdvectionPeriodicity(flow::Advection *advc)\n{\n    glm::vec3 minxyz, maxxyz;\n    int       rv = _velocityField.GetVelocityIntersection(_cache_currentTS, minxyz, maxxyz);\n    if (rv != 0) return rv;\n\n    if (_cache_periodic[0])\n        advc->SetXPeriodicity(true, minxyz.x, maxxyz.x);\n    else\n        advc->SetXPeriodicity(false, 0.0f, 1.0f);\n\n    if (_cache_periodic[1])\n        advc->SetYPeriodicity(true, minxyz.y, maxxyz.y);\n    else\n        advc->SetYPeriodicity(false, 0.0f, 1.0f);\n\n    if (_cache_periodic.size() == 2)\n        advc->SetZPeriodicity(false, 0.0f, 1.0f);\n    else {\n        if (_cache_periodic[2])\n            advc->SetZPeriodicity(true, minxyz.z, maxxyz.z);\n        else\n            advc->SetZPeriodicity(false, 0.0f, 1.0f);\n    }\n\n    return 0;\n}\n\nvoid FlowRenderer::_printNonZero(int rtn, const char *file, const char *func, int line) const\n{\n#ifdef VPRINT\n    if (rtn != 0) {\n        printf(\"Rtn == %d: %s:(%s):%d\\n\", rtn, file, func, line);\n    }\n#endif\n}\n"
  },
  {
    "path": "lib/render/Font.cpp",
    "content": "#include \"vapor/glutil.h\"\n#include \"vapor/Font.h\"\n#include \"vapor/VAssert.h\"\n#include \"vapor/ShaderManager.h\"\n#include <glm/glm.hpp>\n#include \"vapor/GLManager.h\"\n\nusing namespace VAPoR;\nusing glm::vec2;\nusing std::string;\n\nFont::Font(GLManager *glManager, const std::string &path, int size, FT_Library library) : _glManager(glManager), _library(nullptr), _size(size)\n{\n    if (library == nullptr) {\n        int err = FT_Init_FreeType(&_library);\n        VAssert(!err);\n        library = _library;\n    }\n    int err = FT_New_Face(library, path.c_str(), 0, &_face);\n    VAssert(!err);\n    FT_Set_Pixel_Sizes(_face, 0, _size);\n\n    glGenVertexArrays(1, &_VAO);\n    glGenBuffers(1, &_VBO);\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glBufferData(GL_ARRAY_BUFFER, 6 * 4 * sizeof(float), NULL, GL_STREAM_DRAW);\n    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);\n    glEnableVertexAttribArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nFont::~Font()\n{\n    FT_Done_Face(_face);\n    if (_library) FT_Done_FreeType(_library);\n\n    glDeleteVertexArrays(1, &_VAO);\n    glDeleteBuffers(1, &_VBO);\n    for (auto it = _glyphMap.begin(); it != _glyphMap.end(); ++it) glDeleteTextures(1, &it->second.textureID);\n}\n\nbool Font::LoadGlyph(int c)\n{\n    if (FT_Load_Char(_face, c, FT_LOAD_RENDER)) {\n        printf(\"FAILED TO LOAD CHAR\\n\");\n        return false;\n    }\n\n    unsigned int texture;\n    glGenTextures(1, &texture);\n    glBindTexture(GL_TEXTURE_2D, texture);\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, _face->glyph->bitmap.width, _face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE, _face->glyph->bitmap.buffer);\n\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);\n\n    _glyphMap[c] = {texture, (int)_face->glyph->bitmap.width, (int)_face->glyph->bitmap.rows, _face->glyph->bitmap_left, _face->glyph->bitmap_top, _face->glyph->advance.x};\n\n    return true;\n}\n\nFont::Glyph Font::GetGlyph(int c)\n{\n    auto it = _glyphMap.find(c);\n    if (it == _glyphMap.end()) {\n        LoadGlyph(c);\n        return _glyphMap[c];\n    }\n    return it->second;\n}\n\nvoid Font::DrawText(const std::string &text, const glm::vec4 &color)\n{\n    SmartShaderProgram shader = _glManager->shaderManager->GetSmartShader(\"font\");\n    shader->SetUniform(\"MVP\", _glManager->matrixManager->GetModelViewProjectionMatrix());\n    shader->SetUniform(\"color\", color);\n    glActiveTexture(GL_TEXTURE0);\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    const float xStart = 0;\n    const float yStart = 0;\n\n    float cursorX = xStart;\n    float cursorY = yStart;\n\n    for (int i = 0; i < text.size(); i++) {\n        if (text[i] == '\\n') {\n            cursorY -= LineHeight();\n            cursorX = xStart;\n            continue;\n        }\n        if (text[i] == '\\r') {\n            cursorX = xStart;\n            continue;\n        }\n\n        Glyph ch = GetGlyph(text[i]);\n\n        float x = cursorX + ch.bearingX;\n        float y = cursorY - (ch.sizeY - ch.bearingY);\n        float w = ch.sizeX;\n        float h = ch.sizeY;\n\n        float vertices[6][4] = {{x, y + h, 0, 0}, {x, y, 0, 1},     {x + w, y, 1, 1},\n\n                                {x, y + h, 0, 0}, {x + w, y, 1, 1}, {x + w, y + h, 1, 0}};\n        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);\n        glBindTexture(GL_TEXTURE_2D, ch.textureID);\n        glDrawArrays(GL_TRIANGLES, 0, 6);\n\n        cursorX += ch.advance / 64;\n    }\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glDisable(GL_BLEND);\n}\n\nglm::vec2 Font::TextDimensions(const std::string &text)\n{\n    vec2  dimensions(0.f);\n    float lineWidth = 0;\n    float maxHeightForLine = 0;\n    for (int i = 0; i < text.size(); i++) {\n        if (text[i] == '\\n') {\n            if (lineWidth > dimensions.x) dimensions.x = lineWidth;\n            dimensions.y += LineHeight();\n            maxHeightForLine = 0;\n            lineWidth = 0;\n            continue;\n        }\n        if (text[i] == '\\r') {\n            if (lineWidth > dimensions.x) dimensions.x = lineWidth;\n            lineWidth = 0;\n            continue;\n        }\n\n        Glyph ch = GetGlyph(text[i]);\n        lineWidth += ch.advance / 64;\n        if (ch.sizeY > maxHeightForLine) maxHeightForLine = ch.sizeY;\n    }\n    if (lineWidth > dimensions.x) dimensions.x = lineWidth;\n    dimensions.y += maxHeightForLine;\n    return dimensions;\n}\n\nfloat Font::LineHeight() const\n{\n    return _face->size->metrics.height / 64;\n    // return _face->height / 64;\n}\n"
  },
  {
    "path": "lib/render/FontManager.cpp",
    "content": "#include \"vapor/glutil.h\"\n#include \"vapor/FontManager.h\"\n#include <vapor/ResourcePath.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nusing std::map;\nusing std::pair;\nusing std::string;\n\nFontManager::FontManager(GLManager *glManager) : _glManager(glManager), _library(nullptr)\n{\n    VAssert(glManager);\n    VAssert(!FT_Init_FreeType(&_library));\n}\n\nFontManager::~FontManager()\n{\n    for (auto it = _map.begin(); it != _map.end(); ++it) delete it->second;\n    _map.clear();\n    if (_library) FT_Done_FreeType(_library);\n}\n\nFont *FontManager::GetFont(const std::string &name, unsigned int size) { return GetResource(pair<string, unsigned int>(name, size)); }\n\nint FontManager::LoadResourceByKey(const std::pair<std::string, unsigned int> &key)\n{\n    if (HasResource(key)) {\n        VAssert(!\"Font already loaded\");\n        return -1;\n    }\n    const string       name = key.first;\n    const unsigned int size = key.second;\n    const string       path = GetSharePath(\"fonts/\" + name + \".ttf\");\n    Font *             f = new Font(_glManager, path, size, _library);\n    AddResource(key, f);\n    return 1;\n}\n"
  },
  {
    "path": "lib/render/Framebuffer.cpp",
    "content": "#include <vapor/Framebuffer.h>\n#include <vapor/MyBase.h>\n#include <vapor/glutil.h>\n#include \"vapor/VAssert.h\"\n\nusing namespace VAPoR;\n\nFramebuffer::~Framebuffer()\n{\n    if (_id) glDeleteFramebuffers(1, &_id);\n    _id = 0;\n}\n\nint Framebuffer::Generate()\n{\n    VAssert(!Initialized());\n\n    GLint savedId;\n    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &savedId);\n\n    glGenFramebuffers(1, &_id);\n    glBindFramebuffer(GL_FRAMEBUFFER, _id);\n    VAssert(_id);\n\n    _colorBuffer.Generate();\n    _colorBuffer.TexImage(GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);\n    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _colorBuffer._id, 0);\n\n    if (_hasDepthBuffer) {\n        _depthBuffer.Generate();\n        _depthBuffer.TexImage(GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);\n        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthBuffer._id, 0);\n    }\n\n    glBindFramebuffer(GL_FRAMEBUFFER, savedId);\n    return 0;\n}\n\nbool Framebuffer::Initialized() const { return _id; }\n\nbool Framebuffer::IsComplete() const { return Initialized() && GetStatus() == GL_FRAMEBUFFER_COMPLETE; }\n\nint Framebuffer::GetStatus() const { return glCheckFramebufferStatus(GL_FRAMEBUFFER); }\n\nconst char *Framebuffer::GetStatusString() const { return GetStatusString(GetStatus()); }\n\nconst char *Framebuffer::GetStatusString(int status)\n{\n    switch (status) {\n    case GL_FRAMEBUFFER_COMPLETE: return \"GL_FRAMEBUFFER_COMPLETE\";\n    case GL_FRAMEBUFFER_UNDEFINED: return \"GL_FRAMEBUFFER_UNDEFINED\";\n    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return \"GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\";\n    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return \"GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\";\n    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: return \"GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER\";\n    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: return \"GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER\";\n    case GL_FRAMEBUFFER_UNSUPPORTED: return \"GL_FRAMEBUFFER_UNSUPPORTED\";\n    case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return \"GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE\";\n    case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: return \"GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS\";\n    case GL_INVALID_ENUM: return \"GL_INVALID_ENUM\";\n    case GL_INVALID_OPERATION: return \"GL_INVALID_OPERATION\";\n    default: return \"Unknown GL enum\";\n    }\n}\n\nvoid Framebuffer::Bind()\n{\n    VAssert(Initialized());\n    glBindFramebuffer(GL_FRAMEBUFFER, _id);\n}\n\nvoid Framebuffer::UnBind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }\n\nvoid Framebuffer::SetSize(int width, int height)\n{\n    VAssert(Initialized());\n\n    width = width <= 0 ? 1 : width;\n    height = height <= 0 ? 1 : height;\n\n    if (width != _width || height != _height) {\n        _width = width;\n        _height = height;\n\n        _colorBuffer.TexImage(GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);\n        if (_hasDepthBuffer) _depthBuffer.TexImage(GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);\n    }\n}\n\nvoid Framebuffer::GetSize(int *width, int *height) const\n{\n    *width = _width;\n    *height = _height;\n}\n\nint Framebuffer::MakeRenderTarget()\n{\n    Bind();\n    if (!IsComplete()) {\n        Wasp::MyBase::SetErrMsg(\"Incomplete framebuffer: %s\\n\", GetStatusString());\n        UnBind();\n        VAssert(false);\n        return -1;\n    }\n\n    glViewport(0, 0, _width, _height);\n    return 0;\n}\n\nvoid Framebuffer::EnableDepthBuffer()\n{\n    VAssert(!Initialized());\n    _hasDepthBuffer = true;\n}\n\nconst Texture2D *Framebuffer::GetColorTexture() const\n{\n    VAssert(Initialized());\n    return &_colorBuffer;\n}\n\nconst Texture2D *Framebuffer::GetDepthTexture() const\n{\n    VAssert(Initialized());\n    if (!_hasDepthBuffer) {\n        VAssert(!\"Depth buffer requested from Framebuffer that does not have one\");\n        return nullptr;\n    }\n    return &_depthBuffer;\n}\n"
  },
  {
    "path": "lib/render/GLManager.cpp",
    "content": "#include \"vapor/glutil.h\"\n#include \"vapor/GLManager.h\"\n#include \"vapor/LegacyGL.h\"\n#include \"vapor/FontManager.h\"\n#include \"vapor/STLUtils.h\"\n#include <chrono>\n\nusing namespace VAPoR;\nusing namespace std::chrono;\n\nGLManager::Vendor GLManager::_cachedVendor = Vendor::Unknown;\n\nGLManager::GLManager() : shaderManager(new ShaderManager), fontManager(new FontManager(this)), matrixManager(new MatrixManager), legacy(new LegacyGL(this)) { _queryVendor(); }\n\nGLManager::~GLManager()\n{\n    delete shaderManager;\n    delete fontManager;\n    delete matrixManager;\n    delete legacy;\n}\n\nstd::vector<int> GLManager::GetViewport()\n{\n    GLint v[4] = {0};\n    glGetIntegerv(GL_VIEWPORT, v);\n    return {v[0], v[1], v[2], v[3]};\n}\n\nglm::vec2 GLManager::GetViewportSize()\n{\n    const auto v = GetViewport();\n    return glm::vec2(v[2] - v[0], v[3] - v[1]);\n}\n\nvoid GLManager::PixelCoordinateSystemPush()\n{\n    MatrixManager *  mm = matrixManager;\n    std::vector<int> viewport = GLManager::GetViewport();\n\n    mm->MatrixModeProjection();\n    mm->PushMatrix();\n    mm->Ortho(viewport[0], viewport[2], viewport[1], viewport[3]);\n    mm->MatrixModeModelView();\n    mm->PushMatrix();\n    mm->LoadIdentity();\n}\n\nvoid GLManager::PixelCoordinateSystemPop()\n{\n    MatrixManager *mm = matrixManager;\n    mm->PopMatrix();\n    mm->MatrixModeProjection();\n    mm->PopMatrix();\n    mm->MatrixModeModelView();\n}\n\nGLManager::Vendor GLManager::GetVendor() { return _cachedVendor; }\n\nvoid GLManager::_queryVendor()\n{\n    string vendorString((const char *)glGetString(GL_VERSION));\n    vendorString = STLUtils::ToLower(vendorString);\n\n    if (STLUtils::Contains(vendorString, \"intel\"))\n        _cachedVendor = Vendor::Intel;\n    else if (STLUtils::Contains(vendorString, \"nvidia\"))\n        _cachedVendor = Vendor::Nvidia;\n    else if (STLUtils::Contains(vendorString, \"amd\"))\n        _cachedVendor = Vendor::AMD;\n    else if (STLUtils::Contains(vendorString, \"mesa\"))\n        _cachedVendor = Vendor::Mesa;\n    else\n        _cachedVendor = Vendor::Other;\n}\n\nvoid GLManager::GetGLVersion(int *major, int *minor)\n{\n    // Only >=3.0 guarentees glGetIntegerv\n\n    string version = string((const char *)glGetString(GL_VERSION));\n    version = version.substr(0, version.find(\" \"));\n    const string majorString = version.substr(0, version.find(\".\"));\n    *major = std::stoi(majorString);\n    if (majorString.length() < version.length()) {\n        version = version.substr(majorString.length() + 1);\n        const string minorString = version.substr(0, version.find(\".\"));\n        if (!minorString.empty())\n            *minor = std::stoi(minorString);\n        else\n            *minor = 0;\n    }\n}\n\nint GLManager::GetGLSLVersion()\n{\n    int major, minor;\n    GetGLVersion(&major, &minor);\n\n    // This does not work for < OpenGL 3.3 but we do not support it anyway\n    return 100 * major + 10 * minor;\n}\n\nbool GLManager::IsCurrentOpenGLVersionSupported()\n{\n    int major, minor;\n    GetGLVersion(&major, &minor);\n\n    int version = major * 100 + minor;\n\n    if (version >= 303) return true;\n\n    Wasp::MyBase::SetErrMsg(\"OpenGL Version \\\"%s\\\" is too low and is not supported\", glGetString(GL_VERSION));\n    return false;\n}\n\nbool GLManager::CheckError()\n{\n    int err = glGetError();\n    if (err != GL_NO_ERROR) { return false; }\n    return true;\n}\n\n#ifndef NDEBUG\nvoid GLManager::ShowDepthBuffer()\n{\n    static bool         initialized = false;\n    static unsigned int VAO = 0;\n    static unsigned int VBO = 0;\n    static unsigned int texID = 0;\n    static float        BL = 0.5;\n    static float        data[] = {BL, BL, 0, 0, 1, BL, 1, 0, BL, 1, 0, 1,\n\n                           BL, 1,  0, 1, 1, BL, 1, 0, 1,  1, 1, 1};\n    // Since this is just for debugging purposes, initialized stays false to support use in multiple contexts\n    if (!initialized) {\n        glGenVertexArrays(1, &VAO);\n        glGenBuffers(1, &VBO);\n        glBindVertexArray(VAO);\n        glBindBuffer(GL_ARRAY_BUFFER, VBO);\n        glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);\n        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL);\n        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));\n        glEnableVertexAttribArray(0);\n        glEnableVertexAttribArray(1);\n\n        glGenTextures(1, &texID);\n        glBindTexture(GL_TEXTURE_2D, texID);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    }\n\n    GLint viewport[4] = {0};\n    glGetIntegerv(GL_VIEWPORT, viewport);\n\n    glBindTexture(GL_TEXTURE_2D, texID);\n    // glReadBuffer(GL_BACK);\n    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewport[0], viewport[1], viewport[2], viewport[3], 0);\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_2D, texID);\n    glBindVertexArray(VAO);\n    SmartShaderProgram shader = shaderManager->GetSmartShader(\"DepthBuffer\");\n    shader->SetUniform(\"near\", matrixManager->Near);\n    shader->SetUniform(\"far\", matrixManager->Far);\n    shader->SetUniform(\"linearize\", true);\n    glDrawArrays(GL_TRIANGLES, 0, 6);\n    glBindVertexArray(0);\n}\n#endif\n\nvoid *GLManager::BeginTimer()\n{\n    glFinish();\n    auto start = new chrono::time_point<chrono::high_resolution_clock>;\n    *start = chrono::high_resolution_clock::now();\n    return start;\n}\n\ndouble GLManager::EndTimer(void *startTime)\n{\n    VAssert(startTime);\n    auto start = (chrono::time_point<chrono::high_resolution_clock> *)startTime;\n\n    glFinish();\n    auto stop = chrono::high_resolution_clock::now();\n    auto duration = chrono::duration_cast<chrono::microseconds>(stop - *start);\n\n    delete start;\n\n    return (double)duration.count() / 1000000.0;\n}\n"
  },
  {
    "path": "lib/render/GeoImage.cpp",
    "content": "#include <iostream>\n#include <sstream>\n#include <cstdarg>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <cstdio>\n#include <algorithm>\n#include <sys/stat.h>\n#include <vapor/Proj4API.h>\n#include <vapor/GeoUtil.h>\n\n#include \"vapor/GeoImage.h\"\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n#endif\nusing namespace VAPoR;\nusing namespace Wasp;\n\nnamespace {\n\n// Error handling for TIFF library\n//\nvoid myTiffErrHandler(const char *module, const char *fmt, va_list ap)\n{\n    char buf[1024];\n\n#ifdef WIN32\n    _vsnprintf(buf, sizeof(buf), fmt, ap);\n#else\n    vsnprintf(buf, sizeof(buf), fmt, ap);\n#endif\n\n    if (module) {\n        MyBase::SetErrMsg(\"%s : %s\", module, buf);\n    } else {\n        MyBase::SetErrMsg(\"%s\", buf);\n    }\n}\n\n};    // namespace\n\nGeoImage::GeoImage(int pixelsize, int nbands) : _pixelsize(pixelsize), _nbands(nbands)\n{\n    VAssert(pixelsize = 8);\n    VAssert(nbands = 4);\n    _tif = NULL;\n    _path.clear();\n}\n\nGeoImage::GeoImage() : _pixelsize(8), _nbands(4)\n{\n    _path.clear();\n    _tif = NULL;\n}\n\nGeoImage::~GeoImage() { GeoImage::TiffClose(); }\n\nint GeoImage::TiffOpen(string path)\n{\n    TIFFSetErrorHandler(myTiffErrHandler);\n\n    GeoImage::TiffClose();\n\n    // Check for a valid file name (this avoids Linux crash):\n    //\n    struct stat statbuf;\n    if (stat(path.c_str(), &statbuf) < 0) {\n        SetErrMsg(\"Invalid tiff file: %s\\n\", path.c_str());\n        return -1;\n    }\n\n    // Not using memory-mapped IO (m) is reputed to help plug\n    // leaks (but doesn't do any good on windows for me)\n    //\n    _tif = XTIFFOpen(path.c_str(), \"rm\");\n    if (!_tif) {\n        SetErrMsg(\"Unable to open tiff file: %s\\n\", path.c_str());\n        return -1;\n    }\n\n    char emsg[1000];\n    int  ok = TIFFRGBAImageOK(_tif, emsg);\n    if (!ok) {\n        MyBase::SetErrMsg(\"Unable to process tiff file:\\n %s\\nError message: %s\", path.c_str(), emsg);\n        return (-1);\n    }\n\n    // Check compression.  Some compressions, e.g. jpeg, cause crash on Linux\n    //\n#ifdef VAPOR3_0_0_ALPHA\n    short compr = 1;\n    ok = TIFFGetField(_tif, TIFFTAG_COMPRESSION, &compr);\n    if (ok) {\n        if (compr != COMPRESSION_NONE && compr != COMPRESSION_LZW && compr != COMPRESSION_JPEG && compr != COMPRESSION_CCITTRLE) {\n            MyBase::SetErrMsg(\"Unsupported Tiff compression\");\n            return (-1);\n        }\n    }\n#endif\n\n    return (0);\n}\n\nvoid GeoImage::TiffClose()\n{\n    if (_tif) XTIFFClose(_tif);\n    _path.clear();\n    _tif = NULL;\n}\n\n// Return dimensions of image at selected directory number\n//\nint GeoImage::TiffGetImageDimensions(int dirnum, size_t &width, size_t &height) const\n{\n    VAssert(_tif != NULL);\n    width = 0;\n    height = 0;\n\n    bool ok = (bool)TIFFSetDirectory(_tif, dirnum);\n    if (!ok) return (-1);\n\n    uint32_t w;\n    ok = (bool)TIFFGetField(_tif, TIFFTAG_IMAGEWIDTH, &w);\n    if (!ok) return (-1);\n\n    uint32_t h;\n    ok = (bool)TIFFGetField(_tif, TIFFTAG_IMAGELENGTH, &h);\n    if (!ok) return (-1);\n\n    width = (size_t)w;\n    height = (size_t)h;\n\n    return (0);\n}\n\n// Read the indicated TIFF image and return it as a 2D texture.\n//\nint GeoImage::TiffReadImage(int dirnum, unsigned char *texture) const\n{\n    VAssert(_tif != NULL);\n\n    uint32_t *texuint32_t = (uint32_t *)texture;\n\n    bool ok = (bool)TIFFSetDirectory(_tif, dirnum);\n    if (!ok) return (-1);\n\n    size_t w, h;\n    int    rc = GeoImage::TiffGetImageDimensions(dirnum, w, h);\n    if (rc < 0) return (-1);\n\n    // Check if this is a 2-component 8-bit image.  These are read\n    // by scanline since TIFFReadRGBAImage\n    // apparently does not know how to get the alpha channel\n    //\n    short nsamples, nbitspersample;\n    ok = TIFFGetField(_tif, TIFFTAG_SAMPLESPERPIXEL, &nsamples);\n    if (!ok) return (-1);\n\n    ok = TIFFGetField(_tif, TIFFTAG_BITSPERSAMPLE, &nbitspersample);\n    if (!ok) return (-1);\n\n    if (nsamples == 2 && nbitspersample == 8) {\n        tdata_t buf;\n        uint32_t  row;\n        short   config;\n        short   photometric;\n\n        TIFFGetField(_tif, TIFFTAG_PLANARCONFIG, &config);\n        if (!ok) return (-1);\n\n        TIFFGetField(_tif, TIFFTAG_PHOTOMETRIC, &photometric);\n        if (!ok) return (-1);\n\n        buf = _TIFFmalloc(TIFFScanlineSize(_tif));\n        VAssert(buf != NULL);\n\n        unsigned char *charArray = (unsigned char *)buf;\n        int            scanlength = TIFFScanlineSize(_tif) / 2;\n\n        if (config == PLANARCONFIG_CONTIG) {\n            for (row = 0; row < h; row++) {\n                int revrow = h - row - 1;    // reverse, go bottom up\n                int rc = TIFFReadScanline(_tif, buf, row);\n                if (rc < 0) {\n                    MyBase::SetErrMsg(\"Error reading tiff file:\\n %s\\n\", _path.c_str());\n                    _TIFFfree(buf);\n                    return (-1);\n                }\n                for (int k = 0; k < scanlength; k++) {\n                    unsigned char greyval = charArray[2 * k];\n                    // If white is zero, reverse it:\n                    if (!photometric) greyval = 255 - greyval;\n                    unsigned char alphaval = charArray[2 * k + 1];\n                    texuint32_t[revrow * w + k] = alphaval << 24 | greyval << 16 | greyval << 8 | greyval;\n                }\n            }\n        } else if (config == PLANARCONFIG_SEPARATE) {\n            uint16_t s;\n\n            // Note: following loop (adapted from tiff docs) has not\n            // been tested.  Are there tiff\n            // examples with separate alpha channel?\n            //\n            for (s = 0; s < nsamples; s++) {\n                for (row = 0; row < h; row++) {\n                    int rc = TIFFReadScanline(_tif, buf, row, s);\n                    if (rc < 0) {\n                        MyBase::SetErrMsg(\"Error reading tiff file:\\n %s\\n\", _path.c_str());\n                        _TIFFfree(buf);\n                        return (-1);\n                    }\n                    int revrow = h - row - 1;    // reverse, go bottom up\n                    if (!(s % 2)) {              // color\n                        for (int k = 0; k < h; k++) {\n                            unsigned char greyval = charArray[k];\n                            // If white is zero, reverse it:\n                            if (!photometric) greyval = 255 - greyval;\n                            texuint32_t[revrow * w + k] = greyval << 16 | greyval << 8 | greyval;\n                        }\n                    } else {    // alpha\n                        for (int k = 0; k < h; k++) {\n                            unsigned char alphaval = charArray[k];\n                            texuint32_t[revrow * w + k] = alphaval << 24 | (texuint32_t[revrow * w + k] & 0xffffff);\n                        }\n                    }\n                }\n            }\n        }\n        _TIFFfree(buf);\n        return (0);\n\n    } else {\n        // Read pixels, whether or not we are georeferenced:\n\n        ok = TIFFReadRGBAImage(_tif, w, h, texuint32_t, 0);\n        if (!ok) {\n            MyBase::SetErrMsg(\"Error reading tiff file:\\n %s\\n\", _path.c_str());\n            return -1;\n        }\n\n        return (0);\n    }\n}\n\n// Project extents (ll, ur) given in PCS coordinates in srccoords using the\n// specified projection in proj4src\n// into 4 corners and return the extents (ll, ur) in the projected\n// space. Because the projected space may be convex - the maximum and\n// minimum values may not occur at the corner points - we need to walk\n// around the boundaries to find the extents in the projected space.\n//\nint GeoImage::CornerExtents(const double srccoords[4], double dstcoords[4], string proj4src) const\n{\n    proj4src += \" +over\";\n\n    Proj4API proj4API;\n    int      rc = proj4API.Initialize(proj4src, \"\");\n    if (rc < 0) return (-1);\n\n    size_t              nx = 256;\n    size_t              ny = 256;\n    size_t              ntotal = nx * ny;\n    std::vector<double> xsamples(ntotal);\n    std::vector<double> ysamples(ntotal);\n\n    double deltax = (srccoords[2] - srccoords[0]) / (double)(nx - 1);\n    double deltay = (srccoords[3] - srccoords[1]) / (double)(ny - 1);\n\n    for (int j = 0; j < ny; j++) {\n        for (int i = 0; i < nx; i++) {\n            xsamples[j * nx + i] = srccoords[0] + i * deltax;\n            ysamples[j * nx + i] = srccoords[1] + j * deltay;\n        }\n    }\n\n    proj4API.Transform(xsamples.data(), ysamples.data(), ntotal, 1);\n\n    // Find the extents the extents of the\n    // entire enclosed region. The inverse Proj4 transform does not prevent\n    // wraparound\n    //\n    double minx = *(std::min_element(xsamples.begin(), xsamples.end()));\n    double maxx = *(std::max_element(xsamples.begin(), xsamples.end()));\n    double miny = *(std::min_element(ysamples.begin(), ysamples.end()));\n    double maxy = *(std::max_element(ysamples.begin(), ysamples.end()));\n\n    // still needed?\n    //\n    if ((maxx - minx) >= 359.99) { maxx = minx + 359.99; }\n\n    dstcoords[0] = minx;\n    dstcoords[1] = miny;\n    dstcoords[2] = maxx;\n    dstcoords[3] = maxy;\n\n    return (0);\n}\n"
  },
  {
    "path": "lib/render/GeoImageGeoTiff.cpp",
    "content": "#include <iostream>\n#include <sstream>\n#include <cstdarg>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <cstdio>\n#include <sys/stat.h>\n#ifdef WIN32\n    #include <geotiff/geotiff.h>\n    #include <geotiff/geo_normalize.h>\n#else\n    #include <geotiff.h>\n    #include <geo_normalize.h>\n#endif\n\n#include <vapor/Proj4API.h>\n#include <vapor/GeoUtil.h>\n#include <vapor/GeoTileEquirectangular.h>\n#include <vapor/GeoTileMercator.h>\n#include <vapor/GeoImageGeoTiff.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nGeoImageGeoTiff::GeoImageGeoTiff() : GeoImage(8, 4)\n{\n    _tiffTimes.clear();\n    _times.clear();\n    _texture = NULL;\n    _textureSize = 0;\n}\n\nGeoImageGeoTiff::~GeoImageGeoTiff()\n{\n    if (_texture) delete[] _texture;\n    _textureSize = 0;\n}\n\nint GeoImageGeoTiff::Initialize(string path, vector<double> times)\n{\n    GeoImage::TiffClose();\n    _tiffTimes.clear();\n    _times.clear();\n\n    int rc = GeoImage::TiffOpen(path);\n    if (rc < 0) return (-1);\n\n    // Set up time vector\n    //\n    _initTimeVector(GeoImage::TiffGetHandle(), times);\n\n    return (0);\n}\n\nunsigned char *GeoImageGeoTiff::GetImage(size_t ts, size_t &width, size_t &height)\n{\n    // Get tiff directory number for this time step\n    //\n    int dirnum = _getBestDirNum(ts);\n\n    // Get dimensions image at given time step\n    //\n    int rc = GeoImage::TiffGetImageDimensions(dirnum, width, height);\n    if (rc < 0) return (NULL);\n\n    //\n    // Read the image texture from a file\n    //\n    size_t size = width * height * 4;\n    if (_textureSize < size) {\n        delete[] _texture;\n        _texture = new unsigned char[size];\n        _textureSize = size;\n    }\n\n    rc = GeoImage::TiffReadImage(dirnum, _texture);\n    if (!_texture) return (NULL);\n\n    return (_texture);\n}\n\nunsigned char *GeoImageGeoTiff::GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq,    // not used\n                                         double pcsExtentsImg[4], double geoCornersImg[8], string &proj4StringImg, size_t &width, size_t &height)\n{\n    for (int i = 0; i < 4; i++) {\n        pcsExtentsImg[i] = pcsExtentsReq[i];\n        geoCornersImg[i] = 0.0;\n        geoCornersImg[i + 4] = 0.0;    // Do we need this parameter?\n    }\n    proj4StringImg.clear();\n    width = height = 0;\n\n    _texture = GeoImageGeoTiff::GetImage(ts, width, height);\n    if (!_texture) return (NULL);\n\n    //\n    // Get extents of image in both Projected Coordinates (PCS)\n    // and lat-long.\n    // N.B. if the proj4String defined a lat-long\n    // projection (proj=latlong), it's modified to be cylindrical\n    // equidistant (proj=eqc)\n    //\n    int rc = _getGTIFInfo(GeoImage::TiffGetHandle(), width, height, pcsExtentsImg, geoCornersImg, proj4StringImg);\n    if (rc < 0) return (NULL);\n\n    //\n    // If image is not geo referenced we're done. pcsExtentsImg are\n    // already initialized to pcsExtentsReq\n    //\n    if (!proj4StringImg.size()) return (_texture);\n\n    //\n    // Attempt to crop the texture to the smallest rectangle\n    // that covers the data space. Only possible if image is\n    // a global, cylindrical-equidistant or pseudo mercator projection.\n    // _extractSubtexture()\n    // modifies with, height, and pcsExtents if successful, otherwise\n    // they are unchanged.\n    //\n    (void)_extractSubtexture(_texture, width, height, pcsExtentsReq, proj4StringReq, pcsExtentsImg, geoCornersImg, proj4StringImg, proj4StringImg, width, height, pcsExtentsImg, geoCornersImg);\n\n    return (unsigned char *)_texture;\n}\n\n// Get the Proj4 projection string from a GTIF handle\n//\nstring GeoImageGeoTiff::_getProjectionFromGTIF(GTIF *gtifHandle) const\n{\n    GTIFDefn gtifDef;\n    GTIFGetDefn(gtifHandle, &gtifDef);\n\n    string proj4String = GTIFGetProj4Defn(&gtifDef);\n    if (proj4String.empty()) return (proj4String);\n\n    // If there's no \"ellps=\" in the string, force it to be spherical,\n    // This avoids a bug in the geotiff routines\n    //\n    if (std::string::npos == proj4String.find(\"ellps=\")) { proj4String += \" +ellps=sphere\"; }\n    return (proj4String);\n}\n\n// Construct a time vector, _tiffTimes, containing the time coordinates\n// for all images in the TIFF data base\n//\nvoid GeoImageGeoTiff::_initTimeVector(TIFF *tif, const vector<double> &times)\n{\n    _times = times;\n    _tiffTimes.clear();\n\n    // Check if the first time step (tiff \"directory\" has a time stamp.\n    // If it does all directories must have a time stamp. If no time\n    // stamp is present then the time stamp is taken from the data itself.\n    //\n    TIFFSetDirectory(tif, 0);\n\n    char *timePtr = NULL;\n    bool  hasTime = TIFFGetField(tif, TIFFTAG_DATETIME, &timePtr);\n\n    // build a list of the times in the tiff\n    //\n    UDUnits udunits;\n    udunits.Initialize();\n\n    do {\n        int dircount = 0;\n\n        if (hasTime) {\n            double tifftime = 0.0;\n            bool   ok = _getTiffTime(tif, &udunits, tifftime);\n            if (!ok) {\n                SetDiagMsg(\"Failed to read time stamp from TIFF image\");\n                break;\n            }\n            _tiffTimes.push_back(tifftime);\n        } else {\n            if (dircount < _times.size()) _tiffTimes.push_back(_times[dircount]);\n        }\n\n        dircount++;\n    } while (TIFFReadDirectory(tif));\n\n    return;\n}\n\n// Get the time coordinate of the current tiff directory, convert it\n// from a date to seconds since EPOCH using udunits\n//\nbool GeoImageGeoTiff::_getTiffTime(TIFF *tif, UDUnits *udunits, double &tifftime) const\n{\n    tifftime = 0.0;\n\n    char *timePtr = NULL;\n    bool  hasTime = (bool)TIFFGetField(tif, TIFFTAG_DATETIME, &timePtr);\n\n    if (!hasTime) return (false);\n\n    // determine seconds from the time stamp in the tiff\n    // convert tifftags to use WRF style date/time strings\n    //\n    int         year, mon, mday, hour, min, sec;\n    const char *format = \"%4d:%2d:%2d %2d:%2d:%2d\";\n    int         rc = sscanf(timePtr, format, &year, &mon, &mday, &hour, &min, &sec);\n\n    // For backwords compatibility check WRF-style format\n    //\n    if (rc != 6) {\n        format = \"%4d-%2d-%2d_%2d:%2d:%2d\";\n        rc = sscanf(timePtr, format, &year, &mon, &mday, &hour, &min, &sec);\n\n        if (rc != 6) return (false);\n    }\n\n    tifftime = udunits->EncodeTime(year, mon, mday, hour, min, sec);\n    return (true);\n}\n\n// Find the tiff time coordinate that best matches the time step\n// indicated by ts. Return an index into _tiffTimes for the best\n// match.\n//\nint GeoImageGeoTiff::_getBestDirNum(size_t ts) const\n{\n    VAssert(ts < _times.size());\n    VAssert(_tiffTimes.size());\n\n    double t = _times[ts];\n\n    int bestdir = 0;\n    for (int i = 0; i < _tiffTimes.size(); i++) {\n        if (fabs(_tiffTimes[i] - t) < fabs(_tiffTimes[bestdir] - t)) { bestdir = i; }\n    }\n\n    return (bestdir);\n}\n\nint GeoImageGeoTiff::_getGTIFInfo(TIFF *tif, size_t width, size_t height, double pcsExtents[4], double geoCorners[8], string &proj4String) const\n{\n    for (int i = 0; i < 4; i++) {\n        pcsExtents[i] = 0.0;\n        geoCorners[i] = geoCorners[i + 4] = 0.0;\n    }\n    proj4String.clear();\n\n    GTIF *gtifHandle = GTIFNew(tif);\n    VAssert(gtifHandle != NULL);\n\n    // Read proj4 string from geotiff file\n    //\n    proj4String = _getProjectionFromGTIF(gtifHandle);\n    if (proj4String.empty()) return (0);\n\n    //\n    // Get image extents by converting from pixel to\n    // Projection Coordinate Space (PCS). Note, if the\n    // proj4 projection is \"latlong\" the conversion will be from\n    // pixels to geographic coords (i.e. lat and long) :-(\n    //\n    // N.B. GTIF library expects Y origin at top of image, we\n    // us bottom for Y origin\n    //\n    //\tdouble extents[4] = {0.0, height-1, width-1, 0};\n    double extents[4] = {0.0, (double)height, (double)width, 0.0};\n\n    bool ok = GTIFImageToPCS(gtifHandle, &extents[0], &extents[1]);\n    if (!ok) {\n        SetErrMsg(\"GTIFImageToPCS()\");\n        GTIFFree(gtifHandle);\n        return (-1);\n    }\n    ok = GTIFImageToPCS(gtifHandle, &extents[2], &extents[3]);\n    if (!ok) {\n        SetErrMsg(\"GTIFImageToPCS()\");\n        GTIFFree(gtifHandle);\n        return (-1);\n    }\n    GTIFFree(gtifHandle);\n\n    //\n    // Set up proj4 to convert from PCS, image space to lat-long\n    //\n    Proj4API proj4API;\n    int      rc = proj4API.Initialize(proj4String, \"\");\n    if (rc < 0) return (-1);\n\n    // Make sure projection is not lat-long. If so, convert to eqc\n    //\n    if (proj4API.IsLatLonSrc()) {\n        // Oops. Projection string was lat-long. This means we have\n        // lat long coordinates in 'extents', not PCS. We need to generate\n        // a new proj4 string to find geographic (lat-lon) coordinates\n        //\n        double        lon_0 = (extents[0] + extents[2]) / 2.0;\n        double        lat_0 = (extents[1] + extents[3]) / 2.0;\n        ostringstream oss;\n        oss.precision(12);\n        oss << \" +lon_0=\" << lon_0 << \" +lat_0=\" << lat_0;\n        proj4String = \"+proj=eqc +ellps=WGS84\" + oss.str();\n        int rc = proj4API.Initialize(\"\", proj4String);\n        if (rc < 0) return (-1);\n\n        // Map geographic to PCS coordinates\n        //\n        proj4API.Transform(extents, extents + 1, 2, 2);\n\n        // Reinitialize proj4API to map from geographic to PCS coordinates\n        //\n        rc = proj4API.Initialize(proj4String, \"\");\n        if (rc < 0) return (-1);\n    }\n\n    // Clamp image bounds to range permitted by projection.\n    //\n    proj4API.Clamp(extents, extents + 1, 2, 2);\n\n    for (int i = 0; i < 4; i++) { pcsExtents[i] = extents[i]; }\n\n    //\n    // clockwise order starting with lower-left\n    //\n    geoCorners[0] = extents[0];\n    geoCorners[1] = extents[1];\n    geoCorners[2] = extents[0];\n    geoCorners[3] = extents[3];\n    geoCorners[4] = extents[2];\n    geoCorners[5] = extents[3];\n    geoCorners[6] = extents[2];\n    geoCorners[7] = extents[1];\n\n    //\n    // Transform from PCS to lat-long\n    //\n    proj4API.Transform(geoCorners, geoCorners + 1, 4, 2);\n\n    // Don't allow latlong image to go all the way to the poles\n    // Not sure why they can't to to 90. This code may no longer\n    // be necessary.\n    //\n    if (geoCorners[1] < -89.9999) geoCorners[1] = -89.9999;\n    if (geoCorners[7] < -89.9999) geoCorners[7] = -89.9999;\n    if (geoCorners[3] > 89.9999) geoCorners[3] = 89.9999;\n    if (geoCorners[5] > 89.9999) geoCorners[5] = 89.9999;\n\n    return (0);\n}\n\n// Extract a ROI from a GeoTiff texture. Only possible if image is global\n// and in either cylindrical equidistant or mercator projection. Otherwise\n// the original texture is returned unchanged.\n//\n// texture : Pointer to a 2D texture containing the geoimage\n// width, height : dimensions of texture in pixels\n// pcsExtentsReq : Extents (llx, lly, urx, ury) of desired ROI expressed\n// in PCS coordinates of the *image*\n//\n// proj4StringReq : Proj4 string associated with texture\n// pcsExtentsImg : Extents (llx, lly, urx, ury) of texture expressed\n// in PCS coordinates of the *image*\n//\n// geoCornersImg : Corner points (lat, lon) of image corners\n// in clockwise order starting from S.W. corner\n//\n// proj4StringImg : Proj4 string associated with texture (how different\n// from proj4StringReq)/\n//\n// subProj4StringImg : Proj4 string for returned image. The string\n// may be modified from the orginal if the desired ROI crosses\n// the boundary of the original image\n//\n// subWidth, subHeight : width and height of returned texture\n// subPCSExtentsImg : Extents (llx, lly, urx, ury) of returned texture\n// expressed\n// in PCS coordinates of the *image*\n//\nbool GeoImageGeoTiff::_extractSubtexture(unsigned char *texture, size_t width, size_t height, const double pcsExtentsReq[4], string proj4StringReq, const double pcsExtentsImg[4],\n                                         const double geoCornersImg[8], string proj4StringImg, string &subProj4StringImg, size_t &subWidth, size_t &subHeight, double subPCSExtentsImg[4],\n                                         double subGeoCornersImg[8]) const\n{\n    //\n    // Initialize output params to inputs in case of failure, in which\n    // case the entire image is returned unchanged (uncropped)\n    //\n    subProj4StringImg = proj4StringImg;\n    subWidth = width;\n    subHeight = height;\n    for (int i = 0; i < 4; i++) { subPCSExtentsImg[i] = pcsExtentsImg[i]; }\n    for (int i = 0; i < 8; i++) { subGeoCornersImg[i] = geoCornersImg[i]; }\n\n    //\n    // Can only extract sub-textures from georeferenced images\n    // with cylindrical equi-distant or mercator projections that cover\n    // entire globe. This is really a hack and we need a better test\n    // for global coverage.\n    //\n    bool mercator = std::string::npos != subProj4StringImg.find(\"proj=merc\");\n    bool eqc = std::string::npos != subProj4StringImg.find(\"proj=eqc\");\n\n    if (!mercator && !eqc) return (false);\n\n    // There must be a better way to determine if image is global\n    //\n    if (geoCornersImg[0] > -179.5 || geoCornersImg[4] < 179.5) { return (false); }\n    if (eqc) {\n        if (geoCornersImg[1] > -89.5 || geoCornersImg[5] < 89.5) return (false);\n        if (width != 2 * height) return (false);\n    }\n    if (mercator) {\n        if (geoCornersImg[1] > -85.0 || geoCornersImg[5] < 85.0) return (false);\n        if (width != height) return (false);\n    }\n\n    // Convert requested data extents from PCS coordinates to geographic\n    // and crop data latitude extents to image latitude extents. With Mercator\n    // projections latitudes can't extend beyond ~85 degrees\n    //\n    double myGeoExtentsData[4];\n    for (int i = 0; i < 4; i++) myGeoExtentsData[i] = pcsExtentsReq[i];\n\n    (void)CornerExtents(myGeoExtentsData, myGeoExtentsData, proj4StringReq);\n\n    // Clamp latitude to extents of image. Can't do same for longitude\n    // becuase they may be shifted\n    //\n    if (myGeoExtentsData[1] < geoCornersImg[1]) myGeoExtentsData[1] = geoCornersImg[1];\n\n    if (myGeoExtentsData[3] > geoCornersImg[5]) myGeoExtentsData[3] = geoCornersImg[5];\n\n    //\n    // Construct a GeoTile. It supports subregion extraction and handles\n    // wraparound\n    //\n    GeoTile *geotile;\n    if (eqc) {\n        geotile = new GeoTileEquirectangular(width, height, 4);\n    } else {\n        geotile = new GeoTileMercator(width, height, 4);\n    }\n    geotile->Insert(\"\", (unsigned char *)texture);\n    size_t pixelSW[2];\n    size_t pixelNE[2];\n    size_t nx, ny;\n\n    //\n    // Get GeoTile's pixel coordinates of subregion.\n    //\n    geotile->LatLongRectToPixelRect(myGeoExtentsData, myGeoExtentsData + 2, 0, pixelSW, pixelNE);\n\n    int rc = geotile->MapSize(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], 0, nx, ny);\n    if (rc != 0) {\n        delete geotile;\n        return false;\n    };\n\n    //\n    // Extract the image\n    //\n    VAssert(nx <= width);\n    VAssert(ny <= height);\n    rc = geotile->GetMap(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], 0, texture);\n    if (rc != 0) {\n        delete geotile;\n        return false;\n    };\n\n    delete geotile;\n\n    //\n    // If data crosses -180 or 180 we need to generate a new\n    // proj4 string with the correct centering\n    //\n    if (myGeoExtentsData[0] < -180 || myGeoExtentsData[2] > 180.0) {\n        double        lon_0 = (myGeoExtentsData[0] + myGeoExtentsData[2]) / 2.0;\n        ostringstream oss;\n        oss.precision(12);\n        oss << \" +lon_0=\" << lon_0;\n        string::size_type first = subProj4StringImg.find(\"+lon_0\");\n        if (first == string::npos) {\n            subProj4StringImg += oss.str();\n        } else {\n            string::size_type last = subProj4StringImg.find(\" \", first);\n            VAssert(last != string::npos);\n            subProj4StringImg.replace(first, last - first, oss.str());\n        }\n    }\n\n    //\n    // Finally, update the extents of the new image in PCS coordinates\n    // by mapping geographic coordinates of corners to PCS.\n    // Since the projection is eqc we only need south-west and north-east\n    // points.\n    //\n    Proj4API proj4API;\n    proj4API.Initialize(\"\", subProj4StringImg);\n\n    subPCSExtentsImg[0] = myGeoExtentsData[0];\n    subPCSExtentsImg[1] = myGeoExtentsData[1];\n    subPCSExtentsImg[2] = myGeoExtentsData[2];\n    subPCSExtentsImg[3] = myGeoExtentsData[3];\n\n    proj4API.Transform(subPCSExtentsImg, subPCSExtentsImg + 1, 2, 2);\n    subWidth = (int)nx;\n    subHeight = (int)ny;\n\n    // Image is rectangular so corners come directry from extents\n    //\n    subGeoCornersImg[0] = myGeoExtentsData[0];\n    subGeoCornersImg[1] = myGeoExtentsData[1];\n    subGeoCornersImg[2] = myGeoExtentsData[0];\n    subGeoCornersImg[3] = myGeoExtentsData[3];\n    subGeoCornersImg[4] = myGeoExtentsData[2];\n    subGeoCornersImg[5] = myGeoExtentsData[3];\n    subGeoCornersImg[6] = myGeoExtentsData[2];\n    subGeoCornersImg[7] = myGeoExtentsData[1];\n\n    return true;\n}\n"
  },
  {
    "path": "lib/render/GeoImageTMS.cpp",
    "content": "#include <iostream>\n#include <cstdarg>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <cstdio>\n#ifdef WIN32\n    #include <geotiff/geotiff.h>\n    #include <geotiff/geo_normalize.h>\n#else\n    #include <geotiff.h>\n    #include <geo_normalize.h>\n#endif\n\n#include <vapor/Proj4API.h>\n#include <vapor/GeoUtil.h>\n#include <vapor/GeoTileMercator.h>\n#include <vapor/TMSUtils.h>\n#include <vapor/GeoImageTMS.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nGeoImageTMS::GeoImageTMS() : GeoImage(8, 4)\n{\n    _dir.clear();\n    _currentLOD = -1;\n    _maxLOD = 0;\n    _texture = NULL;\n    _textureSize = 0;\n    _tileBuf = NULL;\n    _tileBufSize = 0;\n    _geotile = NULL;\n\n    // The default projection string for imagery centered at 0 degrees\n    // longitude. This string is modified (+lon_0 is edited) if a\n    // reconstructed contiguous image is not centered at 0 degrees longitude\n    //\n    _defaultProj4String = \"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 \"\n                          \"+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext \"\n                          \"+no_defs\";\n}\n\nGeoImageTMS::~GeoImageTMS()\n{\n    if (_texture) delete[] _texture;\n    _textureSize = 0;\n\n    if (_tileBuf) delete[] _tileBuf;\n    _tileBufSize = 0;\n\n    if (_geotile) delete _geotile;\n}\n\nint GeoImageTMS::Initialize(string dir, vector<double> times)\n{\n    SetDiagMsg(\"GeoImageTMS::Initialize(%s)\", dir.c_str());\n\n    if (_geotile) delete _geotile;\n    _geotile = NULL;\n    _dir = dir;\n    _maxLOD = 0;\n\n    // Find the maximum available LOD in the TMS database.\n    //\n    int lod = TMSUtils::GetNumTMSLODs(_dir) - 1;\n    if (lod < 0) {\n        SetErrMsg(\"Failed to initialize TMS directory %s\", _dir.c_str());\n        return (-1);\n    }\n    _maxLOD = lod;\n\n    size_t w, h;\n    int    rc = _tileSize(_dir, 0, 0, 0, w, h);\n    if (rc < 0) return (-1);\n\n    //\n    // Construct a GeoTile. It supports subregion extraction and handles\n    // wraparound. I.e. GeoTile can reconstruct contigous image for any\n    // longitudinal span\n    //\n    _geotile = new GeoTileMercator(w, h, 4);\n\n    //\n    // Allocate space to buffer a tile\n    //\n    size_t size = w * h * 4;\n    if (_tileBufSize < size) {\n        delete[] _tileBuf;\n        _tileBuf = new unsigned char[size];\n        _tileBufSize = size;\n    }\n\n    return (0);\n}\n\nvoid GeoImageTMS::SetLOD(int lod) { _currentLOD = lod; }\n\nunsigned char *GeoImageTMS::GetImage(size_t ts, size_t &width, size_t &height)\n{\n    _geotile->GetTileSize(width, height);\n\n    size_t size = width * height * 4;\n    if (_textureSize < size) {\n        delete[] _texture;\n        _texture = new unsigned char[size];\n        _textureSize = size;\n    }\n\n    //\n    // Just return the base texture\n    //\n    int rc = _tileRead(_dir, 0, 0, 0, _texture);\n    if (rc < 0) return (NULL);\n\n    return (_texture);\n}\n\nunsigned char *GeoImageTMS::GetImage(size_t ts, const double pcsExtentsReq[4], string proj4StringReq, size_t maxWidthReq, size_t maxHeightReq, double pcsExtentsImg[4], double geoCornersImg[8],\n                                     string &proj4StringImg, size_t &width, size_t &height)\n{\n    SetDiagMsg(\"GeoImageTMS::GetImage()\");\n\n    proj4StringImg = _defaultProj4String;\n    width = height = 0;\n\n    // Convert requested data extents from PCS coordinates to geographic\n    // and crop data latitude extents to image latitude extents. With Mercator\n    // projections latitudes can't extend beyond ~85 degrees\n    //\n    double myGeoExtentsData[4];\n    for (int i = 0; i < 4; i++) myGeoExtentsData[i] = pcsExtentsReq[i];\n\n    (void)CornerExtents(myGeoExtentsData, myGeoExtentsData, proj4StringReq);\n\n    // Clamp latitude to extents of image. Can't do same for longitude\n    // because they may be shifted\n    //\n    // Get the supported lat and lon extents for the GeoTile, which\n    // are guaranteed to be rectangular by the mercator projection.\n    //\n    double minlon, minlat, maxlon, maxlat;\n    _geotile->GetLatLonExtents(minlon, minlat, maxlon, maxlat);\n\n    if (myGeoExtentsData[1] < minlat) myGeoExtentsData[1] = minlat;\n    if (myGeoExtentsData[3] > maxlat) myGeoExtentsData[3] = maxlat;\n\n    // Pick a lod that won't allow the resulting image to\n    // exceed the max width and height\n    //\n    int lod;\n    if (_currentLOD == -1) {\n        lod = _getBestLOD(myGeoExtentsData, maxWidthReq, maxHeightReq);\n    } else {\n        lod = _currentLOD;\n    }\n    SetDiagMsg(\"GeoImageTMS::GetImage() LOD : %d\", lod);\n\n    //\n    // Get GeoTile's pixel coordinates of subregion at the given lod\n    //\n    size_t pixelSW[2];\n    size_t pixelNE[2];\n    size_t nx, ny;\n    _geotile->LatLongRectToPixelRect(myGeoExtentsData, myGeoExtentsData + 2, lod, pixelSW, pixelNE);\n\n    int rc = _geotile->MapSize(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], lod, nx, ny);\n\n    //\n    // Resize the buffer if needed.\n    //\n    size_t size = nx * ny * 4;\n    if (_textureSize < size) {\n        delete[] _texture;\n        _texture = new unsigned char[size];\n        _textureSize = size;\n    }\n\n    //\n    // Extract the image\n    //\n    rc = _getMap(pixelSW, pixelNE, lod, _texture);\n    if (rc < 0) return (NULL);\n\n    //\n    // If data crosses -180 or 180 we need to generate a new\n    // proj4 string with the correct centering\n    //\n    if (myGeoExtentsData[0] < -180 || myGeoExtentsData[2] > 180.0) {\n        double        lon_0 = (myGeoExtentsData[0] + myGeoExtentsData[2]) / 2.0;\n        ostringstream oss;\n        oss.precision(12);\n        oss << \" +lon_0=\" << lon_0;\n        string::size_type first = proj4StringImg.find(\"+lon_0\");\n        if (first == string::npos) {\n            proj4StringImg += oss.str();\n        } else {\n            string::size_type last = proj4StringImg.find(\" \", first);\n            VAssert(last != string::npos);\n            proj4StringImg.replace(first, last - first, oss.str());\n        }\n    }\n\n    //\n    // Finally, update the extents of the new image in PCS coordinates\n    // by mapping geographic coordinates of corners to PCS.\n    // Since the projection is eqc we only need south-west and north-east\n    // points.\n    //\n    Proj4API proj4API;\n    proj4API.Initialize(\"\", proj4StringImg);\n\n    pcsExtentsImg[0] = myGeoExtentsData[0];\n    pcsExtentsImg[1] = myGeoExtentsData[1];\n    pcsExtentsImg[2] = myGeoExtentsData[2];\n    pcsExtentsImg[3] = myGeoExtentsData[3];\n\n    proj4API.Transform(pcsExtentsImg, pcsExtentsImg + 1, 2, 2);\n    width = nx;\n    height = ny;\n\n    // Image is rectangular so corners come directry from extents\n    //\n    geoCornersImg[0] = myGeoExtentsData[0];\n    geoCornersImg[1] = myGeoExtentsData[1];\n    geoCornersImg[2] = myGeoExtentsData[0];\n    geoCornersImg[3] = myGeoExtentsData[3];\n    geoCornersImg[4] = myGeoExtentsData[2];\n    geoCornersImg[5] = myGeoExtentsData[3];\n    geoCornersImg[6] = myGeoExtentsData[2];\n    geoCornersImg[7] = myGeoExtentsData[1];\n\n    return (_texture);\n}\n\n// Get the dimensions of a single tile from the TMS database\n// N.B. This method allows the specification of the tile coordinates,\n// but all tiles in a single TMS must be the same size\n//\nint GeoImageTMS::_tileSize(string dir, size_t tileX, size_t tileY, int lod, size_t &w, size_t &h)\n{\n    string path = TMSUtils::TilePath(dir, tileX, tileY, lod);\n    if (path.empty()) {\n        SetErrMsg(\"Tile %d %d %d does not exist\", tileX, tileY, lod);\n        return (-1);\n    }\n\n    int rc = GeoImage::TiffOpen(path);\n    if (rc < 0) return (-1);\n\n    rc = GeoImage::TiffGetImageDimensions(0, w, h);\n    if (rc < 0) {\n        GeoImage::TiffClose();\n        return (-1);\n    }\n\n    GeoImage::TiffClose();\n\n    return (0);\n}\n\n// Read a single tile from the TMS database and return as a raster\n// image\n//\nint GeoImageTMS::_tileRead(string dir, size_t tileX, size_t tileY, int lod, unsigned char *tile)\n{\n    SetDiagMsg(\"GeoImageTMS::_tileRead(%s,%d,%d,%d)\", dir.c_str(), tileX, tileY, lod);\n\n    string path = TMSUtils::TilePath(dir, tileX, tileY, lod);\n    if (path.empty()) {\n        SetErrMsg(\"Tile %d %d %d does not exist\", tileX, tileY, lod);\n        return (-1);\n    }\n    SetDiagMsg(\"GeoImageTMS::_tileRead() path : %s\", path.c_str());\n\n    int rc = GeoImage::TiffOpen(path);\n    if (rc < 0) return (-1);\n\n    rc = GeoImage::TiffReadImage(0, tile);\n    if (rc < 0) {\n        GeoImage::TiffClose();\n        return (-1);\n    }\n\n    GeoImage::TiffClose();\n\n    return (0);\n}\n\n// Determine the best lod for a region specified in lat-lon\n// coordinates. I.e. the largest lod where the resulting image\n// dimensions won't exceed maxWidthReq or maxHeightReq\n//\nint GeoImageTMS::_getBestLOD(const double myGeoExtentsData[4], int maxWidthReq, int maxHeightReq) const\n{\n    size_t pixelSW[2];\n    size_t pixelNE[2];\n\n    bool done = false;\n    int  lod = 0;\n    for (; lod < _maxLOD && !done; lod++) {\n        size_t nx, ny;\n\n        //\n        // Get GeoTile's pixel coordinates of subregion.\n        //\n        _geotile->LatLongRectToPixelRect(myGeoExtentsData, myGeoExtentsData + 2, lod, pixelSW, pixelNE);\n\n        int rc = _geotile->MapSize(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], lod, nx, ny);\n        VAssert(!(rc < 0));\n\n        if (nx > maxWidthReq || ny > maxHeightReq) {\n            done = true;\n            if (lod > 0) lod--;\n        }\n    }\n\n    return (lod);\n}\n\n// Construct a contiguous map (raster image) from the TMS for the\n// specified ROI\n//\n\nint GeoImageTMS::_getMap(const size_t pixelSW[2], const size_t pixelNE[2], int lod, unsigned char *texture)\n{\n    size_t tileX0, tileX1;\n    size_t tileY0, tileY1;\n    size_t dummy;\n\n    _geotile->PixelXYToTileXY(pixelSW[0], pixelSW[1], tileX0, tileY0, dummy, dummy);\n\n    _geotile->PixelXYToTileXY(pixelNE[0], pixelNE[1], tileX1, tileY1, dummy, dummy);\n\n    // Deal with wraparound\n    //\n    size_t ntiles = 1 << lod;\n    size_t nxtiles, nytiles;\n    if (pixelSW[0] < pixelNE[0]) {\n        nxtiles = tileX1 - tileX0 + 1;\n    } else {\n        nxtiles = ntiles - ((tileX1 == tileX0) ? 0 : (tileX0 - tileX1 - 1));\n    }\n\n    if (pixelSW[1] < pixelNE[1]) {\n        nytiles = tileY1 - tileY0 + 1;\n    } else {\n        nytiles = ntiles - ((tileY1 == tileY0) ? 0 : (tileY0 - tileY1 - 1));\n    }\n\n    // Make sure tiles need for this map are loaded. If not, read\n    // and load them\n    //\n    size_t tileY = tileY0;\n    for (size_t y = 0; y < nytiles; y++) {\n        size_t tileX = tileX0;\n        for (size_t x = 0; x < nxtiles; x++) {\n            string quadkey = _geotile->TileXYToQuadKey(tileX, tileY, lod);\n            if (!_geotile->GetTile(quadkey)) {\n                int rc = _tileRead(_dir, tileX, tileY, lod, _tileBuf);\n                if (rc < 0) return (-1);\n\n                rc = _geotile->Insert(quadkey, _tileBuf);\n                VAssert(!(rc < 0));\n            }\n            tileX = (tileX + 1) % ntiles;\n        }\n\n        tileY = (tileY + 1) % ntiles;\n    }\n\n    int rc = _geotile->GetMap(pixelSW[0], pixelSW[1], pixelNE[0], pixelNE[1], lod, texture);\n    return (rc);\n}\n"
  },
  {
    "path": "lib/render/GeoTIFWriter.cpp",
    "content": "#include \"vapor/GeoTIFWriter.h\"\n#include \"vapor/Proj4StringParser.h\"\n#include \"vapor/VAssert.h\"\n\n#ifdef WIN32\n    #include <geotiff/geo_normalize.h>\n    #include <geotiff/xtiffio.h>\n#else\n    #include <geo_normalize.h>\n#endif\n\nusing namespace VAPoR;\n\nGeoTIFWriter::GeoTIFWriter(const std::string &path) : TIFWriter(path), gtif(nullptr), _hasTiePoint(false), _hasPixelScale(false), _geoTiffWasConfigured(false)\n{\n    if (opened) {\n        gtif = GTIFNew(tif);\n        if (!gtif) opened = false;\n    }\n}\n\nGeoTIFWriter::~GeoTIFWriter()\n{\n    if (gtif) GTIFFree(gtif);\n}\n\nint GeoTIFWriter::Write(const unsigned char *buffer, const unsigned int width, const unsigned int height)\n{\n    VAssert(_hasTiePoint);\n    VAssert(_hasPixelScale);\n    VAssert(_geoTiffWasConfigured);\n\n    GTIFWriteKeys(gtif);\n    return TIFWriter::Write(buffer, width, height);\n}\n\nint GeoTIFWriter::ConfigureFromProj4(const std::string proj4String)\n{\n    Proj4StringParser proj(proj4String);\n\n    if (proj.GetString(\"ellps\") == \"sphere\") {\n        SetErrMsg(\"Arbitrary sphere projections not supported\");\n        return -1;\n    }\n\n    if (proj.GetString(\"proj\") == \"lcc\" || proj.GetString(\"proj\") == \"utm\") {\n        if (GTIFSetFromProj4(gtif, proj4String.c_str()) == 0) {\n            SetErrMsg(\"Unable to configure GeoTIFF using GTIFSetFromProj4(%s)\", proj4String.c_str());\n            return -1;\n        }\n    } else {\n        if (proj.GetString(\"proj\") == \"merc\") {\n            GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_Mercator);\n            GTIFKeySet(gtif, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1, proj.GetDouble(\"k\", 1.0));\n        } else if (proj.GetString(\"proj\") == \"eqc\") {\n            GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_Equirectangular);\n        } else if (proj.GetString(\"proj\") == \"stere\") {\n            GTIFKeySet(gtif, ProjCoordTransGeoKey, TYPE_SHORT, 1, CT_Stereographic);\n            if (proj.HasKey(\"R\")) {\n                SetErrMsg(\"Arbitrary sphere projections not supporteds\");\n                return -1;\n            }\n        } else {\n            SetErrMsg(\"Unsupported projection \\\"%s\\\"\", proj.GetString(\"proj\").c_str());\n            return -1;\n        }\n\n        int ellipse = Proj4StringParser::Proj4EllipseStringToGeoTIFEnum(proj.GetString(\"ellps\", \"WGS84\"));\n        if (ellipse < 0) return -1;\n        GTIFKeySet(gtif, GeogEllipsoidGeoKey, TYPE_SHORT, 1, ellipse);\n\n        GTIFKeySet(gtif, GTModelTypeGeoKey, TYPE_SHORT, 1, ModelTypeProjected);\n        GTIFKeySet(gtif, ProjectedCSTypeGeoKey, TYPE_SHORT, 1, KvUserDefined);\n        GTIFKeySet(gtif, ProjectionGeoKey, TYPE_SHORT, 1, KvUserDefined);\n\n        // Proj4 does not support lat_0 but some of our proj4 strings have this parameter in them\n        // In the datasets I've tested, it appears to override lat_ts..?\n        if (proj.HasKey(\"lat_0\"))\n            GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, proj.GetDouble(\"lat_0\", 0.0));\n        else\n            GTIFKeySet(gtif, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1, proj.GetDouble(\"lat_ts\", 0.0));\n\n        GTIFKeySet(gtif, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1, proj.GetDouble(\"lon_0\", 0.0));\n        GTIFKeySet(gtif, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1, proj.GetDouble(\"x_0\", 0.0));\n        GTIFKeySet(gtif, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1, proj.GetDouble(\"y_0\", 0.0));\n    }\n\n    _geoTiffWasConfigured = true;\n    return 0;\n}\n\nvoid GeoTIFWriter::SetTiePoint(double worldX, double worldY, double rasterX, double rasterY)\n{\n    // http://geotiff.maptools.org/spec/geotiff2.6.html#2.6\n    double tiePoints[6] = {\n        rasterX, rasterY, 0,    // 3D I,J,K Raster coordinate space\n        worldX,  worldY,  0     // 3D X,Y,Z World coordinate space\n    };\n    TIFFSetField(tif, TIFFTAG_GEOTIEPOINTS, 6, tiePoints);\n    _hasTiePoint = true;\n}\n\nvoid GeoTIFWriter::SetPixelScale(double x, double y)\n{\n    double pixelScale[3] = {x, y, 0};\n    TIFFSetField(tif, TIFFTAG_GEOPIXELSCALE, 3, pixelScale);\n    _hasPixelScale = true;\n}\n"
  },
  {
    "path": "lib/render/GeoTile.cpp",
    "content": "#include <iostream>\n#include <cstring>\n#include <algorithm>\n#include <sstream>\n#include \"vapor/GeoTile.h\"\n#include \"vapor/MyBase.h\"\n\nusing namespace std;\nusing namespace VAPoR;\n\nGeoTile::GeoTile(size_t tile_width, size_t tile_height, size_t pixel_size, double min_lon, double min_lat, double max_lon, double max_lat)\n{\n    _tile_width = tile_width;\n    _tile_height = tile_height;\n    _pixel_size = pixel_size;\n    _tiles.clear();\n\n    _MinLongitude = min_lon;\n    _MinLatitude = min_lat;\n    _MaxLongitude = max_lon;\n    _MaxLatitude = max_lat;\n}\n\nGeoTile::~GeoTile()\n{\n    std::map<string, unsigned char *>::iterator p;\n\n    for (p = _tiles.begin(); p != _tiles.end(); ++p) {\n        if (p->second) delete[] p->second;\n    }\n}\n\nvoid GeoTile::PixelXYToTileXY(size_t pixelX, size_t pixelY, size_t &tileX, size_t &tileY, size_t &tilePixelX, size_t &tilePixelY) const\n{\n    tileX = pixelX / _tile_width;\n    tileY = pixelY / _tile_height;\n    tilePixelX = pixelX % _tile_width;\n    tilePixelY = pixelY % _tile_height;\n}\n\nvoid GeoTile::TileXYToPixelXY(size_t tileX, size_t tileY, size_t &pixelX, size_t &pixelY) const\n{\n    pixelX = tileX * _tile_width;\n    pixelY = tileY * _tile_height;\n}\n\nint GeoTile::Insert(std::string quadkey, const unsigned char *image)\n{\n    size_t tileX, tileY;\n    int    lod;\n    int    rc = QuadKeyToTileXY(quadkey, tileX, tileY, lod);\n    if (rc < 0) return (rc);    // invalid quadkey\n\n    std::map<string, unsigned char *>::iterator p = _tiles.find(quadkey);\n    unsigned char *                             imgptr;\n    if (p != _tiles.end()) {\n        imgptr = p->second;    // tile already exists;\n    } else {\n        imgptr = new unsigned char[_tile_width * _tile_height * _pixel_size];\n        _tiles[quadkey] = imgptr;\n    }\n    memcpy(imgptr, image, _tile_width * _tile_height * _pixel_size);\n    return (0);\n}\n\nconst unsigned char *GeoTile::GetTile(string quadkey) const\n{\n    map<string, unsigned char *>::const_iterator p = _tiles.find(quadkey);\n    if (p != _tiles.end()) {\n        return (p->second);    // tile already exists;\n    } else {\n        return (NULL);\n    }\n}\n\nint GeoTile::GetMap(size_t pixelX0, size_t pixelY0, size_t pixelX1, size_t pixelY1, int lod, unsigned char *map_image) const\n{\n    if (pixelX0 == pixelX1 || pixelY0 == pixelY1) {\n        Wasp::MyBase::SetErrMsg(\"Data's geographic coordinates appear to be invalid.\");\n        return -1;\n    }\n\n    //\n    // resolution of global map at requested lod\n    //\n    size_t nx_global, ny_global;\n    MapSize(lod, nx_global, ny_global);\n\n    //\n    // resolution of requested sub region (map). Need to handle periodicity.\n    //\n    size_t map_width, map_height;\n    int    rc = MapSize(pixelX0, pixelY0, pixelX1, pixelY1, lod, map_width, map_height);\n    if (rc < 0) return (rc);\n\n    // coordinates of tile containing first (north-west) , and second\n    // (south-east) pixel\n    //\n    size_t tileX0, tileY0;\n    size_t tileX1, tileY1;\n\n    // pixel coordinates in  tile coordinate system\n    //\n    size_t tilePixelX0, tilePixelY0;\n    size_t tilePixelX1, tilePixelY1;\n\n    PixelXYToTileXY(pixelX0, pixelY0, tileX0, tileY0, tilePixelX0, tilePixelY0);\n    PixelXYToTileXY(pixelX1, pixelY1, tileX1, tileY1, tilePixelX1, tilePixelY1);\n\n    // Deal with wraparound\n    //\n    size_t ntiles = 1 << lod;\n    size_t nxtiles, nytiles;\n    if (pixelX0 < pixelX1) {\n        nxtiles = tileX1 - tileX0 + 1;\n    } else {\n        nxtiles = (tileX1 == tileX0) ? ntiles + 1 : ntiles - (tileX0 - tileX1 - 1);\n    }\n\n    if (pixelY0 < pixelY1) {\n        nytiles = tileY1 - tileY0 + 1;\n    } else {\n        nytiles = (tileY1 == tileY0) ? ntiles + 1 : ntiles - (tileY0 - tileY1 - 1);\n    }\n\n    size_t tpx0 = 0, tpy0 = 0;    // pixel coord bounds in tile coordinate system\n    size_t tpx1 = 0, tpy1 = 0;\n\n    // Process tiles from north-west to south-east.\n    //\n    // N.B. because of periodicity tile{X,Y}0 may be >= tile{X,Y}1\n    //\n    size_t map_py = 0;\n    size_t map_px = 0;\n\n    //\n    // p{x,y}0 and p{x,y}1 define bounds of tile within map in global coords\n    //\n    size_t px0, py0;\n    size_t px1, py1;\n\n    size_t ty = tileY0;\n    for (int j = 0; j < nytiles; j++) {\n        map_px = 0;\n        size_t tx = tileX0;\n\n        size_t dummy;\n        TileXYToPixelXY(tx, ty, dummy, py0);\n        py1 = py0 + _tile_height - 1;\n\n        // Handle boundary tiles\n        //\n        tpy0 = 0;\n        tpy1 = _tile_height - 1;\n        if (j == 0 && py0 < pixelY0) {\n            size_t offset = pixelY0 - py0;\n            py0 += offset;\n            tpy0 += offset;\n        }\n        if (j == nytiles - 1 && py1 > pixelY1) {\n            size_t offset = py1 - pixelY1;\n            py1 -= offset;\n            tpy1 -= offset;\n        }\n\n        for (int i = 0; i < nxtiles; i++) {\n            const unsigned char *tile = GetTile(tx, ty, lod);\n            if (!tile) return (-1);    // tile doesn't exist at this lod\n\n            TileXYToPixelXY(tx, ty, px0, dummy);\n            px1 = px0 + _tile_width - 1;\n\n            // Handle boundary tiles\n            //\n            tpx0 = 0;\n            tpx1 = _tile_width - 1;\n            if (i == 0 && px0 < pixelX0) {\n                size_t offset = pixelX0 - px0;\n                px0 += offset;\n                tpx0 += offset;\n            }\n            if (i == nxtiles - 1 && px1 > pixelX1) {\n                size_t offset = px1 - pixelX1;\n                px1 -= offset;\n                tpx1 -= offset;\n            }\n\n            _CopyTileToMap(tile, tpx0, tpy0, tpx1, tpy1, map_image, map_px, map_py, map_width, map_height);\n\n            map_px += tpx1 - tpx0 + 1;\n            tx = (tx + 1) % ntiles;\n        }\n        map_py += tpy1 - tpy0 + 1;\n        ty = (ty + 1) % ntiles;\n    }\n    return (0);\n}\n\nstring GeoTile::TileXYToQuadKey(size_t tileX, size_t tileY, int lod)\n{\n    string quadKey = \"\";    // lod == 0\n    for (int i = lod; i > 0; i--) {\n        ostringstream oss;\n        char          digit = '0';\n        size_t        mask = 1 << (i - 1);\n        if ((tileX & mask) != 0) { digit++; }\n        if ((tileY & mask) != 0) {\n            digit++;\n            digit++;\n        }\n        oss << digit;\n        quadKey.append(oss.str());\n    }\n    return (quadKey);\n}\n\nint GeoTile::QuadKeyToTileXY(string quadKey, size_t &tileX, size_t &tileY, int &lod)\n{\n    tileX = tileY = 0;\n    lod = quadKey.length();\n    for (int i = lod; i > 0; i--) {\n        int mask = 1 << (i - 1);\n        switch (quadKey[lod - i]) {\n        case '0': break;\n\n        case '1': tileX |= mask; break;\n\n        case '2': tileY |= mask; break;\n\n        case '3':\n            tileX |= mask;\n            tileY |= mask;\n            break;\n\n        default: return (-1);    // Invalid QuadKey digit sequence\n        }\n    }\n    return (0);\n}\n\nvoid GeoTile::MapSize(int lod, size_t &nx, size_t &ny) const\n{\n    nx = _tile_width << lod;\n    ny = _tile_height << lod;\n}\n\nint GeoTile::MapSize(size_t pixelX0, size_t pixelY0, size_t pixelX1, size_t pixelY1, int lod, size_t &nx, size_t &ny) const\n{\n    size_t nx_global, ny_global;\n    MapSize(lod, nx_global, ny_global);\n\n    if (pixelX0 > nx_global - 1) return (-1);\n    if (pixelY0 > ny_global - 1) return (-1);\n    if (pixelX1 > nx_global - 1) return (-1);\n    if (pixelY1 > ny_global - 1) return (-1);\n\n    if (pixelY0 > pixelY1) return (-1);\n\n    //\n    // resolution of requested sub region (map). Need to handle periodicity.\n    //\n    if (pixelX1 >= pixelX0) {\n        nx = pixelX1 - pixelX0 + 1;\n    } else {\n        nx = nx_global - (pixelX0 - pixelX1 - 1);    // map wraps around lon\n    }\n    ny = pixelY1 - pixelY0 + 1;\n    return (0);\n}\n\ndouble GeoTile::_Clip(double n, double minValue, double maxValue) const { return std::min(std::max(n, minValue), maxValue); }\n\nvoid GeoTile::_CopyTileToMap(const unsigned char *tile, size_t tilePixelX0, size_t tilePixelY0, size_t tilePixelX1, size_t tilePixelY1, unsigned char *map, size_t pixelX0, size_t pixelY0, size_t nx,\n                             size_t ny) const\n{\n    size_t px = pixelX0;\n    size_t py = pixelY0;\n\n    unsigned char *      mapptr = map;\n    const unsigned char *tileptr = tile;\n    for (size_t tpy = tilePixelY0; tpy <= tilePixelY1; tpy++, py++) {\n        mapptr = map + (py * nx + pixelX0) * _pixel_size;\n        tileptr = tile + (tpy * _tile_width + tilePixelX0) * _pixel_size;\n\n        for (size_t tpx = tilePixelX0; tpx <= tilePixelX1; tpx++, px++) {\n            for (int i = 0; i < _pixel_size; i++) { mapptr[i] = tileptr[i]; }\n\n            mapptr += _pixel_size;\n            tileptr += _pixel_size;\n        }\n    }\n}\n\nvoid GeoTile::LatLongRectToPixelRect(const double geoSW[2], const double geoNE[2], int lod, size_t pixelSW[2], size_t pixelNE[2]) const\n{\n    LatLongToPixelXY(geoSW[0], geoSW[1], lod, pixelSW[0], pixelSW[1]);\n    LatLongToPixelXY(geoNE[0], geoNE[1], lod, pixelNE[0], pixelNE[1]);\n\n    // Handle wraparound for longitude. I.e. if the S.W. and N.E. longitudes map to\n    // same pixel coordinate, the region may span the entire globe, or they may simply span\n    // a small region contained within a single pixel. To determine the case we pick a longitude point\n    // between the geographic SW and NE corners, convert to pixels, and see if the midpoint is still\n    // in the same pixel.\n    //\n    if (pixelSW[0] == pixelNE[0]) {\n        // X pixel coordinate for SW and NE corners are the same. Determine if\n        // longitude wraps around, or simply defines a small region residing entirely\n        // within a single pixel.\n        //\n        double midpointGeo[2] = {(geoNE[0] + geoSW[0]) / 2.0, (geoNE[1] + geoSW[1]) / 2.0};\n        size_t midpointPixel[2];\n        LatLongToPixelXY(midpointGeo[0], midpointGeo[1], lod, midpointPixel[0], midpointPixel[1]);\n\n        // If geographic midpoint resuls in a different pixel the region wraps around.\n        // Correct the NE (or SW) pixel so we\n        // don't have identical pixel coordinates for both corners\n        //\n        size_t nx_global, ny_global;\n        MapSize(lod, nx_global, ny_global);\n        if (pixelSW[0] != midpointPixel[0]) {\n            if (pixelSW[0] == 0)\n                pixelNE[0] = nx_global - 1;\n            else\n                pixelNE[0] = pixelSW[0] - 1;\n        }\n    }\n}\n"
  },
  {
    "path": "lib/render/GeoTileEquirectangular.cpp",
    "content": "#include \"vapor/GeoTileEquirectangular.h\"\nusing namespace VAPoR;\n\nvoid GeoTileEquirectangular::LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const\n{\n    while (lon < _MinLongitude) lon += 360.0;\n    while (lon > _MaxLongitude) lon -= 360.0;\n\n    double x = (lon + 180) / 360.0;\n    double y = (lat + 90) / 180.0;\n\n    size_t nx, ny;\n    MapSize(lod, nx, ny);\n\n    pixelX = (int)_Clip(x * nx + 0.5, 0, nx - 1);\n    pixelY = (int)_Clip(y * ny + 0.5, 0, ny - 1);\n}\n\nvoid GeoTileEquirectangular::PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const\n{\n    size_t nx, ny;\n    MapSize(lod, nx, ny);\n\n    double x = (_Clip(pixelX, 0, nx - 1) / (double)nx) - 0.5;\n    double y = 0.5 - (_Clip(pixelY, 0, ny - 1) / (double)ny);\n\n    lat = 180 * y;\n    lon = 360 * x;\n}\n"
  },
  {
    "path": "lib/render/GeoTileMercator.cpp",
    "content": "#ifdef _WINDOWS\n    #define _USE_MATH_DEFINES\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <cmath>\n#include \"vapor/GeoTileMercator.h\"\nusing namespace VAPoR;\n\nvoid GeoTileMercator::LatLongToPixelXY(double lon, double lat, int lod, size_t &pixelX, size_t &pixelY) const\n{\n    while (lon < _MinLongitude) lon += 360.0;\n    while (lon > _MaxLongitude) lon -= 360.0;\n\n    lat = _Clip(lat, _MinLatitude, _MaxLatitude);\n    lon = _Clip(lon, _MinLongitude, _MaxLongitude);\n\n    double x = (lon + 180) / 360.0;\n\n    double sinLat = sin(lat * M_PI / 180.0);\n    double y = 0.5 - log((1 + sinLat) / (1 - sinLat)) / (4 * M_PI);\n\n    // Flip Y coordinate. South most point is pixel 0\n    //\n    y = 1.0 - y;\n\n    size_t nx, ny;\n    MapSize(lod, nx, ny);\n\n    pixelX = (int)_Clip(x * nx + 0.5, 0, nx - 1);\n    pixelY = (int)_Clip(y * ny + 0.5, 0, ny - 1);\n}\n\nvoid GeoTileMercator::PixelXYToLatLon(size_t pixelX, size_t pixelY, int lod, double &lon, double &lat) const\n{\n    size_t nx, ny;\n    MapSize(lod, nx, ny);\n\n    double x = (_Clip(pixelX, 0, nx - 1) / (double)nx) - 0.5;\n    double y = 0.5 - (_Clip(pixelY, 0, ny - 1) / ny);\n\n    lon = 360 * x;\n    lat = -1 * (90.0 - 360.0 * atan(exp(-y * 2 * M_PI)) / M_PI);\n}\n"
  },
  {
    "path": "lib/render/HelloRenderer.cpp",
    "content": "//-- HelloRenderer.cpp ----------------------------------------------------------\n//\n//                   Copyright (C)  2015\n//     University Corporation for Atmospheric Research\n//                   All Rights Reserved\n//\n//----------------------------------------------------------------------------\n//\n//      File:           HelloRenderer.cpp\n//\n//      Author:         Alan Norton\n//\n//      Description:  Implementation of HelloRenderer class\n//\n//----------------------------------------------------------------------------\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <cstdlib>\n#include <cstdio>\n#include <cstring>\n#include <cfloat>\n\n#ifndef WIN32\n    #include <unistd.h>\n#endif\n\n#include <vapor/ParamsMgr.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/HelloRenderer.h>\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\n//\n// Register class with object factory!!!\n//\nstatic RendererRegistrar<HelloRenderer> registrar(HelloRenderer::GetClassType(), HelloParams::GetClassType());\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nHelloRenderer::HelloRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, HelloParams::GetClassType(), HelloRenderer::GetClassType(), instName, dataMgr)\n{\n}\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nHelloRenderer::~HelloRenderer() {}\n\nint HelloRenderer::_initializeGL() { return (0); }\n\nint HelloRenderer::_paintGL(bool)\n{\n    HelloParams *rParams = (HelloParams *)GetActiveParams();\n\n    // Next we need to get a Grid for the data we are rendering.\n    Grid *helloGrid;\n\n    // To obtain the Grid, we need the refinement level, variable, LOD, and extents:\n    int actualRefLevel = rParams->GetRefinementLevel();\n    int lod = rParams->GetCompressionLevel();\n\n    // Get the variable name\n    string varname = rParams->GetVariableName();\n\n    // Determine the full vdc extents, in order to render\n    // in local user coordinates.\n\n    // Determine the data extents.\n    // The extents of data needed are determined by the end points.\n    // Get the end points from the Params:\n    vector<double> point1Vec = rParams->GetPoint1();\n    vector<double> point2Vec = rParams->GetPoint2();\n    VAssert(point1Vec.size() == point2Vec.size());\n    VAssert(point1Vec.size() >= 2 && point1Vec.size() <= 3);\n\n    CoordType point1 = {0.0, 0.0, 0.0};\n    CoordType point2 = {0.0, 0.0, 0.0};\n    Grid::CopyToArr3(point1Vec, point1);\n    Grid::CopyToArr3(point2Vec, point2);\n\n\n    cout << \"helloParams point: \" << endl;\n    cout << \"point1: \" << point1[0] << \" \" << point1[1] << \" \" << point1[2] << endl;\n    cout << \"point2: \" << point2[0] << \" \" << point2[1] << \" \" << point2[2] << endl;\n\n    // Finally, obtain the Grid of the data for the specified region, at requested refinement and lod,\n    // using Renderer::getGrids()\n    size_t timestep = rParams->GetCurrentTimestep();\n\n    int rc = DataMgrUtils::GetGrids(_dataMgr, timestep, varname, point1, point2, true, &actualRefLevel, &lod, &helloGrid);\n    if (rc < 0) { return rc; }\n\n    // Set the grid to use nearest-point interpolation, to calculate actual (uninterpolated) data max and min\n    helloGrid->SetInterpolationOrder(0);\n\n    // In order to sample the data at the user-specified refinement level, need to determine the number of voxels\n    // that the line crosses, which requires knowing the underlying grid.\n    //\n\n    size_t nsamples = 100;\n    // nsamples is the number of samples along the line.\n    // Divide the line into maxvox equal sections, sample the variable at each point along the line, to find\n    // coordinates of min and max value\n    double         maxval = -DBL_MAX;\n    double         minval = DBL_MAX;\n    vector<double> minPoint, maxPoint;\n    for (int i = 0; i < nsamples; i++) {\n        vector<double> coord;\n\n        for (int j = 0; j < point1.size(); j++) { coord.push_back(point1[j] + i * (point2[j] - point1[j]) / (double)(nsamples - 1)); }\n\n        double sampledVal = helloGrid->GetValue(coord);\n        if (sampledVal == helloGrid->GetMissingValue()) continue;\n        if (minval > sampledVal) {\n            minval = sampledVal;\n            minPoint = coord;\n        }\n        if (maxval < sampledVal) {\n            maxval = sampledVal;\n            maxPoint = coord;\n        }\n    }\n\n    // Obtain the line width\n    // float width = (float)rParams->GetLineThickness();\n\n    // Set up lighting and color.  We will use the lighting settings from the viewpoint params for rendering the lines,\n    // but lighting will be disabled for rendering the max and min points.\n\n    ViewpointParams *vpParams = _paramsMgr->GetViewpointParams(_winName);\n    int              nLights = vpParams->getNumLights();\n    float            fcolor[3];\n    rParams->GetConstantColor(fcolor);\n    if (nLights == 0) {\n//        glDisable(GL_LIGHTING);\n    } else {\n//        glShadeModel(GL_SMOOTH);\n//        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, fcolor);\n//        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, vpParams->getExponent());\n//        // The line geometry will get a white specular color:\n//        float specColor[4];\n//        specColor[0] = specColor[1] = specColor[2] = 0.8f;\n//        specColor[3] = 1.f;\n//        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);\n//        glEnable(GL_LIGHTING);\n//        glEnable(GL_COLOR_MATERIAL);\n    }\n//    glColor3fv(fcolor);\n    // glLineWidth(width);\n\n    // Calculate the normal vector as orthogonal to the line and projected to the viewer direction\n    // To do this, take the cross product of the line direction with the viewer direction,\n    // And then cross the result with the line direction.\n    // Find the direction vector along the line and the camera direction\n\n    double m[16];\n    vpParams->GetModelViewMatrix(m);\n\n    double posvec[3], upvec[3], dirvec[3];\n    bool   status = vpParams->ReconstructCamera(m, posvec, upvec, dirvec);\n    if (!status) {\n        SetErrMsg(\"Failed to get camera parameters\");\n        return (-1);\n    }\n\n    double lineDir[3], vdir[3], cross[3], normvec[3];\n    for (int i = 0; i < 3; i++) {\n        lineDir[i] = point2[i] - point1[i];\n        vdir[i] = dirvec[i];\n    }\n    float len = vlength(lineDir);\n    if (len == 0.f) len = 1.;\n    vscale(lineDir, 1. / len);\n    vcross(vdir, lineDir, cross);\n    len = vlength(cross);\n    if (len == 0.f) len = 1.;\n    vscale(cross, 1. / len);\n    vcross(cross, lineDir, normvec);\n    len = vlength(normvec);\n    if (len == 0.f) len = 1.;\n    vscale(normvec, 1. / len);\n\n    // Now render the line\n    // translate to as to render in local user coordinates\n    //\n//    glBegin(GL_LINES);\n//    glNormal3dv(normvec);\n//    glVertex3d(point1[0], point1[1], point1[2]);\n//    glNormal3dv(normvec);\n//    glVertex3d(point2[0], point2[1], point2[2]);\n//    glEnd();\n//\n//    // Then render the Max and Min points:\n//    glDisable(GL_LIGHTING);\n//    glPointSize(4. * width);\n//    // Max will be white\n//    glColor3f(1.f, 1.f, 1.f);\n//    glBegin(GL_POINTS);\n//    glVertex3d(maxPoint[0], maxPoint[1], maxPoint[2]);\n//    glEnd();\n//\n//    // Set min point to be yellow\n//    glColor3f(1.f, 1.f, 0.f);\n//    glBegin(GL_POINTS);\n//    glVertex3d(minPoint[0], minPoint[1], minPoint[2]);\n//    glEnd();\n\n    return 0;\n}\n"
  },
  {
    "path": "lib/render/Histo.cpp",
    "content": "//************************************************************************\n//                                    *\n//             Copyright (C)  2004                *\n//     University Corporation for Atmospheric Research            *\n//             All Rights Reserved                *\n//                                    *\n//************************************************************************/\n//\n//    File:        Histo.cpp\n//\n//    Author:        Alan Norton\n//            National Center for Atmospheric Research\n//            PO 3000, Boulder, Colorado\n//\n//    Date:        November 2004\n//\n//    Description:  Implementation of Histo class\n//\n#include <vapor/MyBase.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/Histo.h>\n#include <cassert>\nusing namespace VAPoR;\nusing namespace Wasp;\n\n#define SAMPLE_RATE 30\n\n#ifndef __FLT_EPSILON__\n    #define __FLT_EPSILON__ FLT_EPSILON\n#endif\n\nHisto::Histo(int numberBins, float mnData, float mxData, string var, int ts)\n{\n    setProperties(mnData, mxData, var, ts);\n    reset(numberBins);\n}\n\nHisto::Histo(int numberBins)\n{\n    autoSetProperties = true;\n    reset(numberBins);\n}\n\nHisto::Histo() : Histo(0) {}\n\nHisto::~Histo()\n{\n    if (_binArray) delete[] _binArray;\n    if (_below) delete[] _below;\n    if (_above) delete[] _above;\n}\nvoid Histo::reset(int newNumBins)\n{\n    if (newNumBins != _numBins && newNumBins != -1) {\n        _numBins = newNumBins;\n        if (_binArray) delete[] _binArray;\n        _binArray = new unsigned int[_numBins];\n        if (_below) delete[] _below;\n        if (_above) delete[] _above;\n        _below = nullptr;\n        _above = nullptr;\n        _nBinsBelow = 0;\n        _nBinsAbove = 0;\n    }\n    for (int i = 0; i < _numBins; i++) _binArray[i] = 0;\n    if (_below) memset(_below, 0, _nBinsBelow * sizeof(*_below));\n    if (_above) memset(_above, 0, _nBinsAbove * sizeof(*_above));\n    _numSamplesBelow = 0;\n    _numSamplesAbove = 0;\n    _maxBinSize = -1;\n    _populated = false;\n}\n\nvoid Histo::reset(int newNumBins, float mnData, float mxData)\n{\n    reset(newNumBins);\n    _minMapData = mnData;\n    _maxMapData = mxData;\n    if (_maxMapData < _minMapData) _maxMapData = _minMapData;\n    _range = _maxMapData - _minMapData;\n}\n\nvoid Histo::setBins(const vector<long> &bins)\n{\n    VAssert(bins.size() == _numBins);\n    for (int i = 0; i < _numBins; i++) _binArray[i] = bins[i];\n}\n\nvoid Histo::addToBin(float val)\n{\n    // The additional checks below are because\n    // 1. The data min/max are imperfect, e.g. calculated max is 1 but E value of 1.1\n    // 2. Float precision errors, e.g.\n    //    >  Range is 0 - 1, outer range is -1 - 2\n    //    >  val = -0.00000000001 so it is below\n    //    >  -0.00000000001 - -1 = -1\n    //    >  0 - -1 = 1\n    //    >  1 * array size = out of bounds\n\n    if (val < _minMapData) {\n        _numSamplesBelow++;\n        if (_below) {\n            assert(_minMapData - _minData > 0);\n            int index = (val - _minData) / (_minMapData - _minData) * _nBinsBelow;\n\n            if (index >= _nBinsBelow) index = _nBinsBelow - 1;\n            if (index >= 0) _below[index]++;\n        }\n    } else if (val > _maxMapData) {\n        _numSamplesAbove++;\n        if (_above) {\n            assert(_maxData - _maxMapData > 0);\n            int index = (val - _maxMapData) / (_maxData - _maxMapData) * _nBinsAbove;\n\n            if (index < 0) index = 0;\n            if (index < _nBinsAbove) _above[index]++;\n        }\n    } else {\n        int intVal = 0;\n        if (_range == 0.f)\n            intVal = 0;\n        else\n            intVal = (int)((val - _minMapData) / _range * (float)_numBins);\n\n        if (intVal < 0) intVal = 0;\n        if (intVal >= _numBins) intVal = _numBins - 1;\n        _binArray[intVal]++;\n    }\n}\n\nint Histo::getMaxBinSize()\n{\n    if (_maxBinSize == -1)    // For legacy purposes. Can remove with new TF Editor\n        calculateMaxBinSize();\n    if (_maxBinSize == 0)\n        return 1;\n    else\n        return _maxBinSize;\n}\n\nint Histo::getMaxBinSizeBetweenIndices(const int start, const int end) const\n{\n    int maxBin = 0;\n\n    if (start < 0 && _below)\n        for (int i = max(0, start + _nBinsBelow); i < min(end + _nBinsBelow, _nBinsBelow); i++) maxBin = maxBin < _below[i] ? _below[i] : maxBin;\n\n    for (int i = max(start, 0); i < min(end, _numBins); i++) maxBin = maxBin < _binArray[i] ? _binArray[i] : maxBin;\n\n    if (end >= _numBins && _above)\n        for (int i = max(start - _numBins, 0); i < min(end - _numBins, _nBinsAbove); i++) maxBin = maxBin < _above[i] ? _above[i] : maxBin;\n\n    if (maxBin == 0)\n        return 1;\n    else\n        return maxBin;\n}\n\nint Histo::getNumBins() const { return _numBins; }\n\nint Histo::getBinSize(int index) const\n{\n    if (index < 0) {\n        index += _nBinsBelow;\n        if (index < 0) return 0;\n        return _below[index];\n    } else if (index >= _numBins) {\n        index -= _numBins;\n        if (index >= _nBinsAbove) return 0;\n        return _above[index];\n    } else\n        return _binArray[index];\n}\n\nint Histo::getBinSize(int index, int stride) const\n{\n    int max = 0;\n    for (int i = index; i < index + stride; i++) max = std::max(max, getBinSize(i));\n    return max;\n}\n\nfloat Histo::getNormalizedBinSize(int bin) const\n{\n    if (_maxBinSize == 0) return 0;\n    return getBinSize(bin) / (float)_maxBinSize;\n}\n\nfloat Histo::getNormalizedBinSizeForValue(float v) const\n{\n    float nv = (v - _minMapData) / _range;\n    return getNormalizedBinSizeForNormalizedValue(nv);\n}\n\nfloat Histo::getNormalizedBinSizeForNormalizedValue(float v) const\n{\n    if (v < 0) {\n        float belowNormMin = 0 - (_minMapData - _minData) / _range;\n        if (v < belowNormMin || !_below) return 0;\n        int index = (v - belowNormMin) / (0 - belowNormMin) * _nBinsBelow;\n        return std::min(1.0f, _below[index] / (float)_maxBinSize);\n    } else if (v >= 1.0) {\n        float aboveNormMax = 1 + (_maxData - _maxMapData) / _range;\n        if (v >= aboveNormMax || !_above) return 0;\n        int index = (v - 1) / (aboveNormMax - 1) * _nBinsAbove;\n        return std::min(1.0f, _above[index] / (float)_maxBinSize);\n    } else\n        return getNormalizedBinSize(v * _numBins);\n}\n\nint Histo::getBinIndexForValue(float v) { return (v - _minMapData) / _range * _numBins; }\n\nint Histo::Populate(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp)\n{\n    size_t         ts = rp->GetCurrentTimestep();\n    int            refLevel = rp->GetRefinementLevel();\n    int            lod = rp->GetCompressionLevel();\n    vector<double> minExtsVec, maxExtsVec;\n    rp->GetBox()->GetExtents(minExtsVec, maxExtsVec);\n\n    CoordType minExts = {0.0, 0.0, 0.0};\n    CoordType maxExts = {0.0, 0.0, 0.0};\n    Grid::CopyToArr3(minExtsVec, minExts);\n    Grid::CopyToArr3(maxExtsVec, maxExts);\n\n    if (autoSetProperties) {\n        MapperFunction *mf = rp->GetMapperFunc(varName);\n        setProperties(mf->getMinMapValue(), mf->getMaxMapValue(), varName, ts);\n        _minExts = minExtsVec;\n        _maxExts = maxExtsVec;\n        _lod = lod;\n        _refLevel = refLevel;\n    }\n\n    if (_below) {\n        delete[] _below;\n        _below = nullptr;\n        _nBinsBelow = 0;\n    }\n    if (_above) {\n        delete[] _above;\n        _above = nullptr;\n        _nBinsAbove = 0;\n    }\n\n    _getDataRange(varName, dm, rp, &_minData, &_maxData);\n\n#ifdef WIN32\n    if (_maxMapData - _minMapData > FLT_EPSILON) {\n#else\n    if (_maxMapData - _minMapData > __FLT_EPSILON__) {\n#endif\n        _nBinsBelow = std::min(10000.0f, _numBins / (_maxMapData - _minMapData) * (_minMapData - _minData));\n        _nBinsAbove = std::min(10000.0f, _numBins / (_maxMapData - _minMapData) * (_maxData - _maxMapData));\n    } else {\n        _nBinsAbove = 0;\n        _nBinsBelow = 0;\n    }\n\n    if (_nBinsBelow > 0) _below = new unsigned int[_nBinsBelow];\n    if (_nBinsAbove > 0) _above = new unsigned int[_nBinsAbove];\n    if (_below) memset(_below, 0, _nBinsBelow * sizeof(*_below));\n    if (_above) memset(_above, 0, _nBinsAbove * sizeof(*_above));\n\n    auto samples = GetDataSamples(varName, dm, rp);\n    for (const auto &sample : samples)\n        addToBin(sample);\n\n    calculateMaxBinSize();\n    _populated = true;\n\n    return 0;\n}\n    \nvector<float> Histo::GetDataSamples(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp)\n{\n    size_t         ts = rp->GetCurrentTimestep();\n    int            refLevel = rp->GetRefinementLevel();\n    int            lod = rp->GetCompressionLevel();\n    vector<double> minExtsVec, maxExtsVec;\n    rp->GetBox()->GetExtents(minExtsVec, maxExtsVec);\n\n    CoordType minExts = {0.0, 0.0, 0.0};\n    CoordType maxExts = {0.0, 0.0, 0.0};\n    Grid::CopyToArr3(minExtsVec, minExts);\n    Grid::CopyToArr3(maxExtsVec, maxExts);\n    \n    Grid *grid;\n    int   rc = DataMgrUtils::GetGrids(dm, ts, varName, minExts, maxExts, true, &refLevel, &lod, &grid);\n\n    if (rc < 0) return vector<float>();\n\n    grid->SetInterpolationOrder(1);\n\n    vector<float> samples;\n    if (shouldUseSampling(varName, dm, rp))\n        samples = getDataSamplesSampling(grid, minExtsVec, maxExtsVec);\n    else\n        samples = getDataSamplesIterating(grid, calculateStride(varName, dm, rp));\n    \n    dm->UnlockGrid(grid);\n    delete grid;\n    \n    return samples;\n}\n\nbool Histo::NeedsUpdate(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp)\n{\n    if (!dm || !rp) return false;\n    if (!_populated) return true;\n\n    MapperFunction *mf = rp->GetMapperFunc(varName);\n    vector<double>  minExts, maxExts;\n    rp->GetBox()->GetExtents(minExts, maxExts);\n\n    if (_minMapData != mf->getMinMapValue()) return true;\n    if (_maxMapData != mf->getMaxMapValue()) return true;\n    if (_refLevel != rp->GetRefinementLevel()) return true;\n    if (_lod != rp->GetCompressionLevel()) return true;\n    if (_varnameOfUpdate != varName) return true;\n    if (_timestepOfUpdate != rp->GetCurrentTimestep()) return true;\n    if (_minExts != minExts) return true;\n    if (_maxExts != maxExts) return true;\n\n    return false;\n}\n\nint Histo::PopulateIfNeeded(const std::string &varName, VAPoR::DataMgr *dm, VAPoR::RenderParams *rp)\n{\n    if (!NeedsUpdate(varName, dm, rp)) return 0;\n\n    reset(_numBins);\n    return Populate(varName, dm, rp);\n}\n\nvector<float> Histo::getDataSamplesIterating(const Grid *grid, const int stride)\n{\n    VAssert(grid);\n    vector<float> samples;\n\n    float               missingValue = grid->GetMissingValue();\n    Grid::ConstIterator enditr = grid->cend();\n\n    for (auto itr = grid->cbegin(); itr != enditr; itr += stride) {\n        float v = *itr;\n        if (v != missingValue) samples.push_back(v);\n    }\n    \n    return samples;\n}\n\n#define X 0\n#define Y 1\n#define Z 2\n\nvector<float> Histo::getDataSamplesSampling(const Grid *grid, const vector<double> &minExts, const vector<double> &maxExts)\n{\n    VAssert(grid);\n    VAssert(minExts.size() == 3 && maxExts.size() == 3);\n    vector<float> samples;\n\n    double              dx = (maxExts[X] - minExts[X]) / SAMPLE_RATE;\n    double              dy = (maxExts[Y] - minExts[Y]) / SAMPLE_RATE;\n    double              dz = (maxExts[Z] - minExts[Z]) / SAMPLE_RATE;\n    std::vector<double> deltas = {dx, dy, dz};\n\n    float               varValue, missingValue;\n    std::vector<double> coords(3, 0.0);\n\n    double xStartPoint = minExts[X] + deltas[X] / 2.f;\n    double yStartPoint = minExts[Y] + deltas[Y] / 2.f;\n    double zStartPoint = minExts[Z] + deltas[Z] / 2.f;\n\n    coords[X] = xStartPoint;\n    coords[Y] = yStartPoint;\n    coords[Z] = zStartPoint;\n\n    int iSamples = SAMPLE_RATE;\n    int jSamples = SAMPLE_RATE;\n    int kSamples = SAMPLE_RATE;\n\n    if (deltas[X] == 0) iSamples = 1;\n    if (deltas[Y] == 0) jSamples = 1;\n    if (deltas[Z] == 0) kSamples = 1;\n\n    for (int k = 0; k < kSamples; k++) {\n        coords[Y] = yStartPoint;\n\n        for (int j = 0; j < jSamples; j++) {\n            coords[X] = xStartPoint;\n\n            for (int i = 0; i < iSamples; i++) {\n                varValue = grid->GetValue(coords);\n                missingValue = grid->GetMissingValue();\n                if (varValue != missingValue) samples.push_back(varValue);\n                coords[X] += deltas[X];\n            }\n            coords[Y] += deltas[Y];\n        }\n        coords[Z] += deltas[Z];\n    }\n    \n    return samples;\n}\n\n#undef X\n#undef Y\n#undef Z\n\nint Histo::calculateStride(const std::string &varName, VAPoR::DataMgr *dm, const VAPoR::RenderParams *rp)\n{\n    return DataMgrUtils::GetDefaultMetaInfoStride(dm, varName, rp->GetRefinementLevel());\n}\n\nbool Histo::shouldUseSampling(const std::string &varName, VAPoR::DataMgr *dm, const VAPoR::RenderParams *rp)\n{\n    // TODO how does this handle with unstructured grids?\n    int nDims = dm->GetNumDimensions(varName);\n    if (nDims == 3) return true;\n    return false;\n}\n\nvoid Histo::setProperties(float mnData, float mxData, string var, int ts)\n{\n    _minMapData = mnData;\n    _maxMapData = mxData;\n    if (_maxMapData < _minMapData) _maxMapData = _minMapData;\n    _range = _maxMapData - _minMapData;\n\n    _varnameOfUpdate = var;\n    _timestepOfUpdate = ts;\n}\n\nvoid Histo::calculateMaxBinSize()\n{\n    int maxBinSize = 0;\n    for (int i = 0; i < _numBins; i++) { maxBinSize = maxBinSize > _binArray[i] ? maxBinSize : _binArray[i]; }\n\n    _maxBinSize = maxBinSize;\n}\n\nvoid Histo::_getDataRange(const std::string &varName, VAPoR::DataMgr *d, VAPoR::RenderParams *r, float *min, float *max) const\n{\n    CoordType minExt = {0.0, 0.0, 0.0};\n    CoordType maxExt = {0.0, 0.0, 0.0};\n    r->GetBox()->GetExtents(minExt, maxExt);\n\n    std::vector<double> range;\n    d->GetDataRange(r->GetCurrentTimestep(), varName, r->GetRefinementLevel(), r->GetCompressionLevel(), minExt, maxExt, range);\n    *min = range[0];\n    *max = range[1];\n}\n"
  },
  {
    "path": "lib/render/ImageRenderer.cpp",
    "content": "//************************************************************************\n//\n//\t\t     Copyright (C)  2008\t\t\t\t\t\t\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t\t\t\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tImagerRenderer.cpp\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n#include <vapor/glutil.h>    // Must be included first!!!\n\n#include <iostream>\n#include <fstream>\n\n#include <vapor/Proj4API.h>\n#include <vapor/CFuncs.h>\n#include <vapor/GeoImageGeoTiff.h>\n#include <vapor/GeoImageTMS.h>\n#include <vapor/ImageRenderer.h>\n#include <vapor/ImageParams.h>\n#include <vapor/FileUtils.h>\n\nusing namespace VAPoR;\n\nnamespace {\n//\n// Make mesh conformant. PCS coordinates may wrap around globe at boundaries :-(\n//\nvoid conform(GLfloat *verts, int nx, int ny)\n{\n    if (nx<2 || ny<2) return;\n\n    // x values\n    //\n    for (int j = 0; j < ny; j++) {\n        // left side\n        //\n        if (verts[3 * (nx * j)] > verts[3 * (nx * j + 1)]) { verts[3 * (nx * j)] = verts[3 * (nx * j + 1)]; }\n\n        // right side\n        //\n        if (verts[3 * ((nx * j) + (nx - 1))] < verts[3 * ((nx * j) + (nx - 2))]) { verts[3 * ((nx * j) + (nx - 1))] = verts[3 * ((nx * j) + (nx - 2))]; }\n    }\n\n    // y values\n    //\n    verts++;\n    for (int i = 0; i < nx; i++) {\n        // bottom row\n        //\n        if (verts[3 * i] > verts[3 * (nx + i)]) { verts[3 * i] = verts[3 * (nx + i)]; }\n\n        // top row\n        //\n        if (verts[3 * (nx * (ny - 1) + i)] < verts[3 * (nx * (ny - 2) + i)]) { verts[3 * (nx * (ny - 1) + i)] = verts[3 * (nx * (ny - 2) + i)]; }\n    }\n}\n};    // namespace\n\n//\n// Register class with object factory!!!\n//\nstatic RendererRegistrar<ImageRenderer> registrar(ImageRenderer::GetClassType(), ImageParams::GetClassType());\n\nImageRenderer::ImageRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr)\n: TwoDRenderer(pm, winName, dataSetName, ImageParams::GetClassType(), ImageRenderer::GetClassType(), instName, dataMgr), _maxResamplingResolution(1024)\n{\n    _geoImage = NULL;\n    _cacheImgFileName.clear();\n    _twoDTex = NULL;\n    _cacheTimes.clear();\n    _pcsExtentsData.clear();\n    for (int i = 0; i < 4; i++) { _pcsExtentsImg[i] = 0; }\n    _proj4StringImg.clear();\n    _texWidth = 0;\n    _texHeight = 0;\n    _cacheTimestep = 0;\n    _cacheTMSLOD = -1;\n    _cacheRefLevel = 0;\n    _cacheLod = 0;\n    _cacheHgtVar = \"\";\n    _cacheGeoreferenced = -1;\n    _cacheTimestepTex = 0;\n    _cacheBoxExtentsTex.clear();\n    _vertsWidth = 0;\n    _vertsHeight = 0;\n    _nindices = 0;\n    _nverts = 0;\n}\n\nImageRenderer::~ImageRenderer()\n{\n    if (_geoImage) {\n        delete _geoImage;\n        _geoImage = NULL;\n    }\n}\n\nconst GLvoid *ImageRenderer::GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned)\n{\n    width = 0;\n    height = 0;\n    internalFormat = GL_RGBA;\n    format = GL_RGBA;\n    type = GL_UNSIGNED_BYTE;\n    texelSize = 4;    // RGBA * sizeof(type)\n    gridAligned = false;\n\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n\n    if (myParams->GetIgnoreTransparency()) internalFormat = GL_RGB;\n\n    GLvoid *texture = (GLvoid *)_getTexture(dataMgr);\n    if (!texture) return (NULL);\n\n    width = _texWidth;\n    height = _texHeight;\n    return (texture);\n}\n\nint ImageRenderer::GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh)\n{\n    width = 0;\n    height = 0;\n    nindices = 0;\n    nverts = 0;\n    structuredMesh = true;\n\n    // See if already in cache\n    //\n    if (!_gridStateDirty() && _sb_verts.GetBuf()) {\n        width = _vertsWidth;\n        height = _vertsHeight;\n        *verts = (GLfloat *)_sb_verts.GetBuf();\n        *normals = (GLfloat *)_sb_normals.GetBuf();\n        nverts = _nverts;\n\n        *indices = (GLuint *)_sb_indices.GetBuf();\n        nindices = _nindices;\n        return (0);\n    }\n    _gridStateClear();\n\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n\n    // Find box extents for ROI\n    //\n    vector<double> minBoxReq, maxBoxReq;\n    myParams->GetBox()->GetExtents(minBoxReq, maxBoxReq);\n\n    int rc;\n\n    // If we are terrain mapping the image or if both the image and the\n    // data are geo-referenced\n    //\n    double defaultZ = GetDefaultZ(dataMgr, myParams->GetCurrentTimestep());\n    \n    if (!myParams->GetHeightVariableName().empty() || (myParams->GetIsGeoRef() && !dataMgr->GetMapProjection().empty())) {\n        // Get the width and height of the image texture. These\n        // will be used to set the width and height of the mesh.\n        //\n        _getTexture(dataMgr);    // Ugh, this function is more than a get method...\n        _vertsWidth = min(_maxResamplingResolution, _texWidth);\n        _vertsHeight = min(_maxResamplingResolution, _texHeight);\n        rc = _getMeshDisplaced(dataMgr, _vertsWidth, _vertsHeight, minBoxReq, maxBoxReq, defaultZ);\n    } else {\n        _vertsWidth = 2;\n        _vertsHeight = 2;\n        rc = _getMeshPlane(minBoxReq, maxBoxReq, defaultZ);\n    }\n\n    if (rc < 0) {\n        _vertsWidth = 0;\n        _vertsHeight = 0;\n        return (-1);\n    }\n\n    //_transformToLocal(_vertsWidth, _vertsHeight, stretchFac);\n\n    _gridStateSet();\n\n    // Compute vertex normals\n    //\n    *verts = (GLfloat *)_sb_verts.GetBuf();\n    *normals = (GLfloat *)_sb_normals.GetBuf();\n    ComputeNormals(*verts, _vertsWidth, _vertsHeight, *normals);\n\n    // Construct indices for a triangle strip covering one row\n    // of the mesh\n    //\n    *indices = (GLuint *)_sb_indices.GetBuf();\n    for (GLuint i = 0; i < _vertsWidth; i++) (*indices)[2 * i] = i;\n    for (GLuint i = 0; i < _vertsWidth; i++) (*indices)[2 * i + 1] = i + _vertsWidth;\n\n    width = _vertsWidth;\n    height = _vertsHeight;\n\n    nindices = _nindices;\n    nverts = _nverts;\n\n    return (0);\n}\n\n// Sets _pcsExtentsImg, _pcsExtentsData,\n// _proj4StringImg, _texWidth, _texHeight\n//\nunsigned char *ImageRenderer::_getTexture(DataMgr *dataMgr)\n{\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n\n    int currentTimestep = myParams->GetCurrentTimestep();\n\n    string         imgFileName = myParams->GetImagePath();\n    vector<double> times = dataMgr->GetTimeCoordinates();\n\n    // Initialize _geoImage if image file or user times have changed\n    //\n    if (_imageStateDirty(times)) {\n        int rc = _reinit(imgFileName, times);\n        if (rc < 0) return (NULL);\n    }\n    VAssert(_geoImage);\n\n    // Get the ROI for the displayed image in PCS coordinates of\n    // the data\n    //\n    vector<double> _pcsExtentsData = _getPCSExtentsData();\n\n    // Get a new texture if any relevant parameters have changed\n    //\n    if (!_twoDTex || _imageStateDirty(times) || _texStateDirty(dataMgr)) {\n        // Get pro4 string for data if georeferencing is requested\n        //\n        string proj4StringData;\n        if (myParams->GetIsGeoRef()) { proj4StringData = dataMgr->GetMapProjection(); }\n\n        double geoCornersImg[8];    // Coordinates of image corners in geo coords\n\n        _twoDTex = _getImage(_geoImage, currentTimestep, proj4StringData, _pcsExtentsData, _pcsExtentsImg, geoCornersImg, _proj4StringImg, _texWidth, _texHeight);\n\n        if (!_twoDTex) return (NULL);\n\n        _texStateSet(dataMgr);\n\n        // Force recompute of mesh\n        //\n        _gridStateClear();\n    }\n    _imageStateSet(times);\n\n    return (_twoDTex);\n}\n\nbool ImageRenderer::_gridStateDirty() const\n{\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n\n    int            refLevel = myParams->GetRefinementLevel();\n    int            lod = myParams->GetCompressionLevel();\n    string         hgtVar = myParams->GetHeightVariableName();\n    int            ts = myParams->GetCurrentTimestep();\n    vector<double> minExt, maxExt;\n    myParams->GetBox()->GetExtents(minExt, maxExt);\n    vector<double> boxExtents(minExt);\n    boxExtents.insert(boxExtents.end(), maxExt.begin(), maxExt.end());\n\n    return (refLevel != _cacheRefLevel || lod != _cacheLod || hgtVar != _cacheHgtVar || ts != _cacheTimestep || boxExtents != _cacheBoxExtents);\n}\n\nvoid ImageRenderer::_gridStateClear()\n{\n    _cacheRefLevel = 0;\n    _cacheLod = 0;\n    _cacheHgtVar.clear();\n    _cacheTimestep = -1;\n    _cacheBoxExtents.clear();\n}\n\nvoid ImageRenderer::_gridStateSet()\n{\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n    _cacheRefLevel = myParams->GetRefinementLevel();\n    _cacheLod = myParams->GetCompressionLevel();\n    _cacheHgtVar = myParams->GetHeightVariableName();\n    _cacheTimestep = myParams->GetCurrentTimestep();\n    vector<double> minExt, maxExt;\n    myParams->GetBox()->GetExtents(minExt, maxExt);\n    _cacheBoxExtents = minExt;\n    _cacheBoxExtents.insert(_cacheBoxExtents.end(), maxExt.begin(), maxExt.end());\n}\n\nbool ImageRenderer::_imageStateDirty(const vector<double> &times) const\n{\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n    string       imgFileName = myParams->GetImagePath();\n\n    return (_cacheImgFileName != imgFileName || _cacheTimes != times);\n}\n\nvoid ImageRenderer::_imageStateSet(const vector<double> &times)\n{\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n\n    string imgFileName = myParams->GetImagePath();\n\n    _cacheImgFileName = imgFileName;\n    _cacheTimes = times;\n}\n\nvoid ImageRenderer::_imageStateClear()\n{\n    _cacheImgFileName.clear();\n    _cacheTimes.clear();\n}\n\nbool ImageRenderer::_texStateDirty(DataMgr *dataMgr) const\n{\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n\n    int            georeferenced = (int)myParams->GetIsGeoRef();\n    int            ts = myParams->GetCurrentTimestep();\n    vector<double> minExt, maxExt;\n    myParams->GetBox()->GetExtents(minExt, maxExt);\n    vector<double> boxExtents(minExt);\n    boxExtents.insert(boxExtents.end(), maxExt.begin(), maxExt.end());\n    int tmsLOD = myParams->GetTMSLOD();\n\n    return (_cacheTimestepTex != ts || _cacheTMSLOD != tmsLOD || _cacheBoxExtentsTex != boxExtents || _cacheGeoreferenced != georeferenced);\n}\n\nvoid ImageRenderer::_texStateSet(DataMgr *dataMgr)\n{\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n    int          georeferenced = (int)myParams->GetIsGeoRef();\n\n    _cacheTimestepTex = myParams->GetCurrentTimestep();\n    _cacheTMSLOD = myParams->GetTMSLOD();\n    _cacheGeoreferenced = georeferenced;\n    vector<double> minExt, maxExt;\n    myParams->GetBox()->GetExtents(minExt, maxExt);\n    _cacheBoxExtentsTex = minExt;\n    _cacheBoxExtentsTex.insert(_cacheBoxExtentsTex.end(), maxExt.begin(), maxExt.end());\n}\n\nvoid ImageRenderer::_texStateClear()\n{\n    _cacheTimestepTex = -1;\n    _cacheTMSLOD = -1;\n    _cacheBoxExtentsTex.clear();\n    _cacheGeoreferenced = -1;\n}\n\nint ImageRenderer::_reinit(string path, vector<double> times)\n{\n    // Two forms of georeferenced images are cachely supported.\n    // If path is a directory then we have a TMS database. Otherwise,\n    // path must point to a tiff file\n    //\n    bool tms_flag = false;\n    if (Wasp::TMSUtils::IsTMSFile(path)) {\n        ifstream in;\n        in.open(path.c_str());\n        if (!in) {\n            SetErrMsg(\"fopen(%s) : %M\", path.c_str());\n            return (-1);\n        }\n        string tiledir;\n        in >> tiledir;\n        in.close();\n\n        // Construct path to TMS tile directory\n        //\n        if (FileUtils::IsPathAbsolute(tiledir)) {\n            path = tiledir;\n        } else {\n            string dir = FileUtils::Dirname(path);\n            path = dir + FileUtils::Separator + tiledir;\n        }\n        tms_flag = true;\n    }\n\n    // If _geoImage already exists make sure the type matches\n    // the cache path (TMS or Tiff). If they don't match delete\n    // _geoImage\n    //\n    if (_geoImage) {\n        if ((dynamic_cast<GeoImageGeoTiff *>(_geoImage)) && tms_flag) {\n            delete _geoImage;\n            _geoImage = NULL;\n        }\n        if ((dynamic_cast<GeoImageTMS *>(_geoImage)) && !tms_flag) {\n            delete _geoImage;\n            _geoImage = NULL;\n        }\n    }\n\n    // Create an appropriate instance of _geoImage for the cache path\n    //\n    if (!_geoImage) {\n        if (tms_flag) {\n            ImageParams *myParams = dynamic_cast<ImageParams *>(GetActiveParams());\n            _geoImage = new GeoImageTMS();\n            dynamic_cast<GeoImageTMS *>(_geoImage)->SetLOD(myParams->GetTMSLOD());\n        } else\n            _geoImage = new GeoImageGeoTiff();\n    }\n\n    int rc = _geoImage->Initialize(path, times);\n    if (rc < 0) {\n        SetErrMsg(\"GeoImage::Initialize(%s,)\", path.c_str());\n        return (-1);\n    }\n\n    return (0);\n}\n\nunsigned char *ImageRenderer::_getImage(GeoImage *geoimage, size_t ts, string proj4StringData, vector<double> pcsExtentsDataVec, double pcsExtentsImg[4], double geoCornersImg[8],\n                                        string &proj4StringImg, GLsizei &width, GLsizei &height) const\n{\n    VAssert(geoimage);\n    VAssert(pcsExtentsDataVec.size() >= 4);\n\n    // Initialize out params\n    //\n    for (int i = 0; i < 4; i++) {\n        pcsExtentsImg[i] = 0.0;\n        geoCornersImg[i] = geoCornersImg[i + 4] = 0.0;\n    }\n    width = height = 0;\n\n    const int maxWidthReq = 1024;\n    const int maxHeightReq = 1024;\n\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n    GeoImageTMS *geoImageTMS = dynamic_cast<GeoImageTMS *>(geoimage);\n    if (geoImageTMS != nullptr) { dynamic_cast<GeoImageTMS *>(_geoImage)->SetLOD(myParams->GetTMSLOD()); }\n\n    double pcsExtentsData[4];\n    for (int i = 0; i < 4; i++) { pcsExtentsData[i] = pcsExtentsDataVec[i]; }\n\n    size_t         my_width, my_height;\n    unsigned char *tex;\n    if (proj4StringData.empty()) {\n        // Data aren't geo-referenced.\n        //\n        for (int i = 0; i < 4; i++) { pcsExtentsImg[i] = pcsExtentsData[i]; }\n        tex = geoimage->GetImage(ts, my_width, my_height);\n    } else {\n        tex = geoimage->GetImage(ts, pcsExtentsData, proj4StringData, maxWidthReq, maxHeightReq, pcsExtentsImg, geoCornersImg, proj4StringImg, my_width, my_height);\n    }\n    width = my_width;\n    height = my_height;\n    return (tex);\n}\n\nint ImageRenderer::_getMeshDisplaced(DataMgr *dataMgr, GLsizei width, GLsizei height, const vector<double> &minBox, const vector<double> &maxBox, double defaultZ)\n{\n    // Construct the displaced (terrain following) grid using\n    // a map projection, if specified.\n    //\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n\n    int refLevel = myParams->GetRefinementLevel();\n    int lod = myParams->GetCompressionLevel();\n\n    // Get the height variable if one specified\n    //\n    Grid * hgtGrid = NULL;\n    string hgtVar = myParams->GetHeightVariableName();\n    if (!hgtVar.empty()) {\n        int rc = DataMgrUtils::GetGrids(dataMgr, myParams->GetCurrentTimestep(), hgtVar, false, &refLevel, &lod, &hgtGrid);\n\n        if (rc < 0) {\n            MyBase::SetErrMsg(\"height data unavailable for 2D rendering at timestep %d\", myParams->GetCurrentTimestep());\n            return (rc);\n        }\n    }\n\n    // (Re)allocate space for verts\n    //\n    _nverts = width * height * 3;\n    _sb_verts.Alloc(_nverts * 3 * sizeof(GLfloat));\n    _sb_normals.Alloc(_nverts * 3 * sizeof(GLfloat));\n\n    _nindices = 2 * width;\n    _sb_indices.Alloc(_nindices * sizeof(GLuint));\n\n    int rc;\n    if (myParams->GetIsGeoRef()) {\n        rc = _getMeshDisplacedGeo(dataMgr, hgtGrid, width, height, defaultZ);\n    } else {\n        rc = _getMeshDisplacedNoGeo(dataMgr, hgtGrid, width, height, minBox, maxBox, defaultZ);\n    }\n\n    if (hgtGrid) { delete hgtGrid; }\n\n    return (rc);\n}\n\n// Compute verts  for displayed, geo-referenced image\n//\nint ImageRenderer::_getMeshDisplacedGeo(DataMgr *dataMgr, Grid *hgtGrid, GLsizei width, GLsizei height, double defaultZ)\n{\n    // Set up proj.4:\n    //\n    string proj4String = dataMgr->GetMapProjection();\n\n    // Delta between pixels in image in Image PCS coordinates\n    //\n    double deltax = (_pcsExtentsImg[2] - _pcsExtentsImg[0]) / (double)(width - 1);\n    double deltay = (_pcsExtentsImg[3] - _pcsExtentsImg[1]) / (double)(height - 1);\n\n    // Compute horizontal coordinates in Image PCS space. Ignore\n    // vertical coordinate for now.\n    //\n    GLfloat *verts = (GLfloat *)_sb_verts.GetBuf();\n    for (int j = 0; j < height; j++) {\n        for (int i = 0; i < width; i++) {\n            verts[j * width * 3 + i * 3] = _pcsExtentsImg[0] + (i * deltax);\n            verts[j * width * 3 + i * 3 + 1] = _pcsExtentsImg[1] + (j * deltay);\n            verts[j * width * 3 + i * 3 + 2] = 0.0;    // ignored\n        }\n    }\n\n    // apply proj4 to transform the points(in place), converting\n    // from Image PCS to Data PCS\n    //\n    Proj4API proj4;\n\n    int rc = proj4.Transform(_proj4StringImg, proj4String, verts, verts + 1, NULL, width * height, 3);\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Error in coordinate projection\");\n        return (-1);\n    }\n\n    // Now find vertical coordinate\n    //\n    double mv = hgtGrid ? hgtGrid->GetMissingValue() : 0.0;\n    for (int j = 0; j < height; j++) {\n        for (int i = 0; i < width; i++) {\n            float x = verts[j * width * 3 + i * 3];\n            float y = verts[j * width * 3 + i * 3 + 1];\n            float z = 0.0;\n\n            // Lookup vertical coordinate as a data element from the\n            // height variable. Note, missing values are possible if image\n            // extents are out side of extents for height variable, or if\n            // height variable itself contains missing values.\n            //\n            float deltaZ = (float)defaultZ;\n            if (hgtGrid) {\n                if (deltaZ == mv) deltaZ = defaultZ;\n                else deltaZ = hgtGrid->GetValue(x, y, 0.0);\n            }\n            z = deltaZ;\n\n            verts[j * width * 3 + i * 3 + 2] = z;\n        }\n    }\n\n    // Take care of any boundary conditions to present meshes with\n    // folds. Still needed?\n    //\n    conform(verts, width, height);\n\n    return (0);\n}\n\n// Compute verts  for displayed, non-georeferenced image\n//\nint ImageRenderer::_getMeshDisplacedNoGeo(DataMgr *dataMgr, Grid *hgtGrid, GLsizei width, GLsizei height, const vector<double> &minExt, const vector<double> &maxExt, double defaultZ)\n{\n    // Delta between pixels in image in Image PCS coordinates\n    //\n    double deltax = (maxExt[0] - minExt[0]) / (double)(width - 1);\n    double deltay = (maxExt[1] - minExt[1]) / (double)(height - 1);\n\n    // Compute horizontal coordinates in Image PCS space. Ignore\n    // vertical coordinate for now.\n    //\n    GLfloat *verts = (GLfloat *)_sb_verts.GetBuf();\n    double   mv = hgtGrid ? hgtGrid->GetMissingValue() : 0.0;\n    for (int j = 0; j < height; j++) {\n        double y = minExt[1] + (j * deltay);\n\n        for (int i = 0; i < width; i++) {\n            double x = minExt[0] + (i * deltax);\n            double z = 0.0;\n\n            verts[j * width * 3 + i * 3] = x;\n            verts[j * width * 3 + i * 3 + 1] = y;\n\n            // Lookup vertical coordinate as a data element from the\n            // height variable. Note, missing values are possible if image\n            // extents are out side of extents for height variable, or if\n            // height variable itself contains missing values.\n            //\n            float deltaZ = (float)defaultZ;\n            if (hgtGrid) {\n                if (deltaZ == mv) deltaZ = defaultZ;\n                else deltaZ = hgtGrid->GetValue(x, y, 0.0);\n            }\n            z = deltaZ;\n\n            verts[j * width * 3 + i * 3 + 2] = z;\n        }\n    }\n    return (0);\n}\n\nint ImageRenderer::_getMeshPlane(const vector<double> &minBox, const vector<double> &maxBox, double defaultZ)\n{\n    // determine the corners of the textured plane.\n    // If it's X-Y (orientation = 2)\n    // If it's X-Z (orientation = 1)\n    // If it's Y-Z (orientation = 0)\n    //\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n    int          orient = myParams->GetOrientation();\n\n    _nverts = 2 * 2;\n    GLfloat *verts = (float *)_sb_verts.Alloc(_nverts * 3 * sizeof(*verts));\n    _sb_normals.Alloc(_nverts * 3 * sizeof(GLfloat));\n\n    _nindices = 2 * 2;\n    _sb_indices.Alloc(_nindices * sizeof(GLuint));\n\n    if (orient == 2) {    // X-Y\n        verts[0] = minBox[0];\n        verts[1] = minBox[1];\n        verts[2] = defaultZ;\n\n        verts[3] = maxBox[0];\n        verts[4] = minBox[1];\n        verts[5] = defaultZ;\n\n        verts[6] = minBox[0];\n        verts[7] = maxBox[1];\n        verts[8] = defaultZ;\n\n        verts[9] = maxBox[0];\n        verts[10] = maxBox[1];\n        verts[11] = defaultZ;\n    } else {    // X-Z\n        SetErrMsg(\"Orientation == %d  not supported\", orient);\n        return (-1);\n    }\n\n    return (0);\n}\n\n// Get the selected horizontal ROI in PCS data coordinates\n//\nvector<double> ImageRenderer::_getPCSExtentsData() const\n{\n    ImageParams *myParams = (ImageParams *)GetActiveParams();\n\n    // Find box extents for ROI\n    //\n    vector<double> minBox;\n    vector<double> maxBox;\n    myParams->GetBox()->GetExtents(minBox, maxBox);\n\n    vector<double> pcsExtentsData;\n    pcsExtentsData.push_back(minBox[0]);\n    pcsExtentsData.push_back(minBox[1]);\n    pcsExtentsData.push_back(maxBox[0]);\n    pcsExtentsData.push_back(maxBox[1]);\n\n    return (pcsExtentsData);\n}\n\n#if 0\nvoid ImageRenderer::_transformToLocal(  size_t width, \n                                        size_t height, \n\t                                      const vector <double> &scaleFac) const \n{\n\tsize_t ts =  GetCurrentTimestep();\n  vector<double>minExts,maxExts;\n\n\tGLfloat *verts = (GLfloat *) _sb_verts.GetBuf();\n\n\tfor (int j = 0; j<height; j++){\n\tfor (int i = 0; i<width; i++){\n\t\t\tverts[j*width*3 + i*3] -= minExts[0];\n\t\t\tverts[j*width*3 + i*3+1] -= minExts[1];\n\t\t\tverts[j*width*3 + i*3+2] -= minExts[2];\n\n\t\t\tverts[j*width*3 + i*3] *= scaleFac[0];\n\t\t\tverts[j*width*3 + i*3+1] *= scaleFac[1];\n\t\t\tverts[j*width*3 + i*3+2] *= scaleFac[2];\n\t}\n\t}\n}\n#endif\n"
  },
  {
    "path": "lib/render/ImageWriter.cpp",
    "content": "#include \"vapor/ImageWriter.h\"\n#include \"vapor/FileUtils.h\"\n#include \"vapor/PNGWriter.h\"\n#include \"vapor/TIFWriter.h\"\n#include \"vapor/JPGWriter.h\"\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nstd::vector<ImageWriterFactory *> ImageWriter::factories;\n\nImageWriter::ImageWriter(const std::string &path) : format(Format::RGB), path(path), opened(false) {}\n\nImageWriter *ImageWriter::CreateImageWriterForFile(const std::string &path)\n{\n    std::string pathExtension = FileUtils::Extension(path);\n    for (auto factory = factories.begin(); factory != factories.end(); ++factory)\n        for (auto writerExtension = (*factory)->Extensions.begin(); writerExtension != (*factory)->Extensions.end(); ++writerExtension)\n            if (*writerExtension == pathExtension) return (*factory)->Create(path);\n\n    SetErrMsg(\"Unsupported image file type \\\"%s\\\"\", FileUtils::Extension(path).c_str());\n    return nullptr;\n}\n\nvoid ImageWriter::RegisterFactory(ImageWriterFactory *factory) { factories.push_back(factory); }\n"
  },
  {
    "path": "lib/render/JPGWriter.cpp",
    "content": "#include \"vapor/JPGWriter.h\"\n#include \"vapor/jpegapi.h\"\n\nusing namespace VAPoR;\n\nREGISTER_IMAGEWRITER(JPGWriter);\n\nint JPGWriter::DefaultQuality = 95;\n\nstd::vector<std::string> JPGWriter::GetFileExtensions() { return {\"jpg\", \"jpeg\"}; }\n\nJPGWriter::JPGWriter(const std::string &path) : ImageWriter(path), fp(nullptr), Quality(DefaultQuality)\n{\n    fp = fopen(path.c_str(), \"wb\");\n    if (fp) opened = true;\n}\n\nJPGWriter::~JPGWriter()\n{\n    if (fp) fclose(fp);\n    fp = nullptr;\n}\n\nint JPGWriter::Write(const unsigned char *buffer, const unsigned int width, const unsigned int height)\n{\n    if (!opened) {\n        MyBase::SetErrMsg(\"Unable to open JPG file for writing: \\\"%s\\\"\", path.c_str());\n        return -1;\n    }\n\n    return write_JPEG_file(fp, width, height, const_cast<unsigned char *>(buffer), Quality);\n}\n"
  },
  {
    "path": "lib/render/LegacyGL.cpp",
    "content": "#include \"vapor/glutil.h\"\n#include \"vapor/LegacyGL.h\"\n#include \"vapor/VAssert.h\"\n#include <glm/glm.hpp>\n#include \"vapor/GLManager.h\"\n#include \"vapor/ShaderProgram.h\"\n#include <glm/gtc/type_ptr.hpp>\n\nusing namespace VAPoR;\nusing std::vector;\n\nLegacyGL::LegacyGL(GLManager *glManager)\n: _glManager(glManager), _mode(0), _emulateQuads(false), _firstQuadTriangle(true), _VAO(0), _VBO(0), _nx(0), _ny(0), _nz(0), _r(1), _g(1), _b(1), _a(1), _s(0), _t(0), _initialized(false),\n  _insideBeginEndBlock(false), _lightingEnabled(false), _textureEnabled(false), _lightDir{0}\n{\n}\n\nLegacyGL::~LegacyGL()\n{\n    if (_VAO) glDeleteVertexArrays(1, &_VAO);\n    if (_VBO) glDeleteBuffers(1, &_VBO);\n}\n\nvoid LegacyGL::Initialize()\n{\n    GL_ERR_BREAK();\n    VAssert(!_initialized);\n\n    glGenVertexArrays(1, &_VAO);\n    glGenBuffers(1, &_VBO);\n\n    VAssert(_VAO);\n    VAssert(_VBO);\n\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL);\n    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, nx));\n    glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, r));\n    glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, s));\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n    glEnableVertexAttribArray(2);\n    glEnableVertexAttribArray(3);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n\n    _emptyTexture.Generate();\n    float zero = 0;\n    _emptyTexture.TexImage(GL_RGB, 1, 1, 0, GL_RGBA, GL_FLOAT, &zero);\n\n    _initialized = true;\n    GL_ERR_BREAK();\n}\n\nvoid LegacyGL::Begin(unsigned int mode)\n{\n    VAssert(!_insideBeginEndBlock);\n\n    if (mode == LGL_QUADS) {\n        _emulateQuads = true;\n        mode = GL_TRIANGLES;\n    }\n\n    _mode = mode;\n    _insideBeginEndBlock = true;\n}\n\nvoid LegacyGL::End()\n{\n    if (!_initialized) Initialize();\n    VAssert(_insideBeginEndBlock);\n\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * _vertices.size(), _vertices.data(), GL_STREAM_DRAW);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    ShaderProgram *_shader = _glManager->shaderManager->GetShader(\"Legacy\");\n    _shader->Bind();\n    _shader->SetUniform(\"P\", _glManager->matrixManager->GetProjectionMatrix());\n    _shader->SetUniform(\"MV\", _glManager->matrixManager->GetModelViewMatrix());\n    _shader->SetUniform(\"lightingEnabled\", _lightingEnabled);\n    _shader->SetUniform(\"textureEnabled\", _textureEnabled);\n    _shader->SetUniform(\"lightDir\", glm::make_vec3(_lightDir));\n\n    if (!_textureEnabled) _emptyTexture.Bind();\n\n    VAssert(glIsVertexArray(_VAO) == GL_TRUE);\n    VAssert(glIsBuffer(_VBO) == GL_TRUE);\n\n    glDrawArrays(_mode, 0, _vertices.size());\n\n    glBindVertexArray(0);\n    _shader->UnBind();\n    if (!_textureEnabled) _emptyTexture.UnBind();\n\n    _emulateQuads = false;\n    _insideBeginEndBlock = false;\n    _vertices.clear();\n}\n\nvoid LegacyGL::Vertex(glm::vec2 v) { Vertex2f(v.x, v.y); }\n\nvoid LegacyGL::Vertex(glm::vec3 v) { Vertex3f(v.x, v.y, v.z); }\n\nvoid LegacyGL::Vertex2f(float x, float y) { Vertex3f(x, y, 0); }\n\nextern bool PRINT_VERTS;\n\nvoid LegacyGL::Vertex3f(float x, float y, float z)\n{\n    VAssert(_insideBeginEndBlock);\n    _vertices.push_back({x, y, z, _nx, _ny, _nz, _r, _g, _b, _a, _s, _t});\n\n    if (_emulateQuads && _vertices.size() % 3 == 0) {\n        if (_firstQuadTriangle) {\n            VertexData v1 = _vertices[_vertices.size() - 3];\n            VertexData v3 = _vertices[_vertices.size() - 1];\n            _vertices.push_back(v1);\n            _vertices.push_back(v3);\n            _firstQuadTriangle = false;\n        } else {\n            _firstQuadTriangle = true;\n        }\n    }\n}\n\nvoid LegacyGL::Vertex3fv(const float *v) { Vertex3f(v[0], v[1], v[2]); }\n\nvoid LegacyGL::Vertex3dv(const double *v) { Vertex3f((float)v[0], (float)v[1], (float)v[2]); }\n\nvoid LegacyGL::Normal3f(float x, float y, float z)\n{\n    _nx = x;\n    _ny = y;\n    _nz = z;\n}\n\nvoid LegacyGL::Normal3fv(const float *n) { Normal3f(n[0], n[1], n[2]); }\n\nvoid LegacyGL::Color(glm::vec3 v) { Color3f(v.r, v.g, v.b); }\n\nvoid LegacyGL::Color(glm::vec4 v) { Color4f(v.r, v.g, v.b, v.a); }\n\nvoid LegacyGL::Color3f(float r, float g, float b)\n{\n    _r = r;\n    _g = g;\n    _b = b;\n    _a = 1.0f;\n}\n\nvoid LegacyGL::Color3fv(const float *f) { Color3f(f[0], f[1], f[2]); }\n\nvoid LegacyGL::Color4f(float r, float g, float b, float a)\n{\n    _r = r;\n    _g = g;\n    _b = b;\n    _a = a;\n}\n\nvoid LegacyGL::Color4fv(const float *f) { Color4f(f[0], f[1], f[2], f[3]); }\n\nvoid LegacyGL::TexCoord(glm::vec2 st) { TexCoord2f(st.s, st.t); }\n\nvoid LegacyGL::TexCoord2f(float s, float t)\n{\n    _s = s;\n    _t = t;\n}\n\nvoid LegacyGL::EnableLighting() { _lightingEnabled = true; }\nvoid LegacyGL::DisableLighting() { _lightingEnabled = false; }\n\nvoid LegacyGL::LightDirectionfv(const float *f)\n{\n    glm::vec3 dir = glm::make_vec3(f);\n    // mimic legacy setlightdirectionfv\n    //    dir = _glManager->matrixManager->GetModelViewMatrix() * glm::vec4(dir, 0.f);\n    _lightDir[0] = dir.x;\n    _lightDir[1] = dir.y;\n    _lightDir[2] = dir.z;\n}\n\nvoid LegacyGL::EnableTexture() { _textureEnabled = true; }\nvoid LegacyGL::DisableTexture() { _textureEnabled = false; }\n"
  },
  {
    "path": "lib/render/MatrixManager.cpp",
    "content": "#include <vapor/glutil.h>\n#include \"vapor/MatrixManager.h\"\n#include \"vapor/VAssert.h\"\n#include <iostream>\n#include <glm/glm.hpp>\n#include <glm/gtc/matrix_transform.hpp>\n#include <glm/gtc/type_ptr.hpp>\n\nusing namespace VAPoR;\nusing glm::mat4;\nusing glm::vec3;\nusing glm::vec4;\nusing std::pair;\n\nMatrixManager::MatrixManager()\n{\n    _modelviewStack.push(glm::mat4(1.0));\n    _projectionStack.push(glm::mat4(1.0));\n    _currentStack = &_modelviewStack;\n    _mode = Mode::ModelView;\n}\n\nglm::mat4 MatrixManager::GetCurrentMatrix() const { return top(); }\n\nmat4 MatrixManager::GetProjectionMatrix() const { return _projectionStack.top(); }\n\nmat4 MatrixManager::GetModelViewMatrix() const { return _modelviewStack.top(); }\n\nmat4 MatrixManager::GetModelViewProjectionMatrix() const { return GetProjectionMatrix() * GetModelViewMatrix(); }\n\nvoid MatrixManager::SetCurrentMatrix(const glm::mat4 m) { top() = m; }\n\nvoid MatrixManager::MatrixModeModelView()\n{\n    _currentStack = &_modelviewStack;\n    _mode = Mode::ModelView;\n}\n\nvoid MatrixManager::MatrixModeProjection()\n{\n    _currentStack = &_projectionStack;\n    _mode = Mode::Projection;\n}\n\nvoid MatrixManager::PushMatrix() { _currentStack->push(top()); }\n\nvoid MatrixManager::PopMatrix() { _currentStack->pop(); }\n\nvoid MatrixManager::LoadMatrixd(const double *m) { top() = glm::make_mat4(m); }\n\nvoid MatrixManager::GetDoublev(Mode mode, double *m) const\n{\n    const float *data = nullptr;\n    if (mode == Mode::ModelView)\n        data = glm::value_ptr(_modelviewStack.top());\n    else if (mode == Mode::Projection)\n        data = glm::value_ptr(_projectionStack.top());\n\n    if (data) {\n        for (int i = 0; i < 16; i++) m[i] = data[i];\n    }\n}\n\nvoid MatrixManager::LoadIdentity() { top() = glm::mat4(1.0); }\n\nvoid MatrixManager::Translate(float x, float y, float z) { top() = glm::translate(top(), vec3(x, y, z)); }\n\nvoid MatrixManager::Scale(float x, float y, float z) { top() = glm::scale(top(), vec3(x, y, z)); }\n\nvoid MatrixManager::Rotate(float angle, float x, float y, float z) { top() = glm::rotate(top(), angle, vec3(x, y, z)); }\n\nvoid MatrixManager::Perspective(float fovy, float aspect, float zNear, float zFar)\n{\n    top() = glm::perspective(fovy, aspect, zNear, zFar);\n    _projectionAspectRatio = aspect;\n\n    Near = zNear;\n    Far = zFar;\n    FOV = fovy;\n    Aspect = aspect;\n}\n\nvoid MatrixManager::Ortho(float left, float right, float bottom, float top)\n{\n    this->top() = glm::ortho(left, right, bottom, top);\n    _projectionAspectRatio = (right - left) / (top - bottom);\n}\n\nvoid MatrixManager::Ortho(float left, float right, float bottom, float top, float zNear, float zFar) { this->top() = glm::ortho(left, right, bottom, top, zNear, zFar); }\n\nglm::vec2 MatrixManager::ProjectToScreen(float x, float y, float z) const { return ProjectToScreen(vec3(x, y, z)); }\n\nglm::vec2 MatrixManager::ProjectToScreen(const glm::vec3 &v) const\n{\n    vec4 vs = GetModelViewProjectionMatrix() * vec4(v, 1.0f);\n    vs /= vs.w;\n    return vs;\n}\n\nfloat MatrixManager::GetProjectionAspectRatio() const\n{\n    VAssert(_projectionAspectRatio != 0);\n    return _projectionAspectRatio;\n}\n\n#ifdef LEGACY_GL_DEBUG\n\nint MatrixManager::GetGLMatrixMode()\n{\n    int mode;\n    glGetIntegerv(GL_MATRIX_MODE, &mode);\n    return mode;\n}\n\nconst char *MatrixManager::GetGLMatrixModeStr()\n{\n    int mode = GetGLMatrixMode();\n    switch (mode) {\n    case GL_MODELVIEW: return \"GL_MODELVIEW\";\n    case GL_PROJECTION: return \"GL_PROJECTION\";\n    case GL_TEXTURE: return \"GL_TEXTURE\";\n    case GL_COLOR: return \"GL_COLOR\";\n    default: return \"UNKNOWN_MODE\";\n    }\n}\n\nint MatrixManager::GetGLModelViewStackDepth()\n{\n    int depth;\n    glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);\n    return depth;\n}\n\nint MatrixManager::GetGLProjectionStackDepth()\n{\n    int depth;\n    glGetIntegerv(GL_PROJECTION_STACK_DEPTH, &depth);\n    return depth;\n}\n\nint MatrixManager::GetGLCurrentStackDepth()\n{\n    if (GetGLMatrixMode() == GL_MODELVIEW) return GetGLModelViewStackDepth();\n    if (GetGLMatrixMode() == GL_PROJECTION) return GetGLProjectionStackDepth();\n    return -1;\n}\n\nconst char *MatrixManager::GetMatrixModeStr()\n{\n    if (_mode == Mode::ModelView) return \"ModelView\";\n    return \"Projection\";\n}\n\n#endif\n\nglm::mat4 &MatrixManager::top() { return _currentStack->top(); }\n\nconst glm::mat4 &MatrixManager::top() const { return _currentStack->top(); }\n"
  },
  {
    "path": "lib/render/ModelRenderer.cpp",
    "content": "//************************************************************************\n//                                                                       *\n//                          Copyright (C)  2018                          *\n//            University Corporation for Atmospheric Research            *\n//                          All Rights Reserved                          *\n//                                                                       *\n//************************************************************************/\n//\n//  File:   ModelRenderer.cpp\n//\n//  Author: Stas Jaroszynski\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:   March 2018\n//\n//  Description:\n//          Implementation of ModelRenderer\n//\n\n#include <string>\n\n#include <vapor/glutil.h>    // Must be included first!!!\n\n#include <vapor/ModelRenderer.h>\n#include <vapor/ShaderManager.h>\n#include <glm/glm.hpp>\n#include <glm/gtc/type_ptr.hpp>\n#include <vapor/GLManager.h>\n#include <vapor/LegacyGL.h>\n#include <vapor/FileUtils.h>\n#include <vapor/STLUtils.h>\n#include <vapor/XmlNode.h>\n#include <assimp/postprocess.h>\n#include <assimp/version.h>\n#include <vapor/VAssert.h>\n\nusing namespace VAPoR;\n\nstatic RendererRegistrar<ModelRenderer> registrar(ModelRenderer::GetClassType(), ModelParams::GetClassType());\n\nModelRenderer::ModelRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, ModelParams::GetClassType(), ModelRenderer::GetClassType(), instName, dataMgr)\n{\n}\n\nint ModelRenderer::_paintGL(bool fast)\n{\n    RenderParams *    rp = GetActiveParams();\n    int               rc = 0;\n    const std::string file = rp->GetValueString(ModelParams::FileTag, \"\");\n\n    if (file != _cachedFile) {\n        rc = _scene.Load(file);\n        if (rc < 0) {\n            _cachedFile = \"\";\n            return rc;\n        }\n        _cachedFile = file;\n        glm::vec3 center = _scene.Center();\n        rp->GetTransform()->SetOrigin({center.x, center.y, center.z});\n    }\n\n    LegacyGL *lgl = _glManager->legacy;\n\n    MatrixManager *mm = _glManager->matrixManager;\n    mm->MatrixModeModelView();\n\n    lgl->EnableLighting();\n    lgl->DisableTexture();\n\n    ViewpointParams *viewpointParams = _paramsMgr->GetViewpointParams(_winName);\n    Viewpoint *      viewpoint = viewpointParams->getCurrentViewpoint();\n    double           m[16];\n    double           cameraPos[3], cameraUp[3], cameraDir[3];\n    _glManager->matrixManager->GetDoublev(MatrixManager::Mode::ModelView, m);\n    viewpoint->ReconstructCamera(m, cameraPos, cameraUp, cameraDir);\n\n    lgl->Color3f(1, 1, 1);\n    float lightDir[3] = {(float)cameraDir[0], (float)cameraDir[1], (float)cameraDir[2]};\n    lgl->LightDirectionfv(lightDir);\n    glDepthMask(GL_TRUE);\n    glEnable(GL_DEPTH_TEST);\n\n    _scene.Render(_glManager, rp->GetCurrentTimestep());\n    lgl->DisableLighting();\n\n    return rc;\n}\n\nint ModelRenderer::_initializeGL() { return 0; }\n\nvoid ModelRenderer::Model::renderNode(GLManager *gl, const aiNode *nd) const\n{\n    LegacyGL *     lgl = gl->legacy;\n    MatrixManager *mm = gl->matrixManager;\n\n    mm->PushMatrix();\n    mm->SetCurrentMatrix(mm->GetCurrentMatrix() * getMatrix(nd));\n\n    for (int m = 0; m < nd->mNumMeshes; m++) {\n        const aiMesh *mesh = _scene->mMeshes[nd->mMeshes[m]];\n        const bool    hasNormals = mesh->HasNormals();\n        const bool    hasColor = mesh->GetNumColorChannels() > 0;\n        if (mesh->HasNormals())\n            lgl->EnableLighting();\n        else\n            lgl->DisableLighting();\n\n        lgl->Begin(GL_TRIANGLES);\n        for (int f = 0; f < mesh->mNumFaces; f++) {\n            const aiFace *face = &mesh->mFaces[f];\n\n            if (face->mNumIndices != 3) continue;\n\n            for (int v = 0; v < face->mNumIndices; v++) {\n                if (hasColor) lgl->Color3fv(&mesh->mColors[0][face->mIndices[v]].r);\n                if (hasNormals) lgl->Normal3fv(&mesh->mNormals[face->mIndices[v]].x);\n                lgl->Vertex3fv(&mesh->mVertices[face->mIndices[v]].x);\n            }\n        }\n        lgl->End();\n    }\n\n    for (int c = 0; c < nd->mNumChildren; c++) renderNode(gl, nd->mChildren[c]);\n\n    mm->PopMatrix();\n}\n\nvoid ModelRenderer::Model::calculateBounds(const aiNode *nd, glm::mat4 transform)\n{\n    transform *= getMatrix(nd);\n\n    for (int m = 0; m < nd->mNumMeshes; m++) {\n        const aiMesh *mesh = _scene->mMeshes[nd->mMeshes[m]];\n\n        for (int f = 0; f < mesh->mNumFaces; f++) {\n            const aiFace *face = &mesh->mFaces[f];\n\n            if (face->mNumIndices != 3) continue;\n\n            for (int v = 0; v < face->mNumIndices; v++) {\n                glm::vec3 gv = glm::make_vec3(&mesh->mVertices[face->mIndices[v]].x);\n                gv = transform * glm::vec4(gv, 1.0f);\n                _min = glm::min(_min, gv);\n                _max = glm::max(_max, gv);\n            }\n        }\n    }\n\n    for (int c = 0; c < nd->mNumChildren; c++) calculateBounds(nd->mChildren[c], transform);\n}\n\nglm::mat4 ModelRenderer::Model::getMatrix(const aiNode *nd) const\n{\n    // Ignore root transform. This is created by assimp to change the up axis\n    if (nd == _scene->mRootNode) return glm::identity<glm::mat4>();\n\n    aiMatrix4x4 m = nd->mTransformation;\n    m.Transpose();\n    return glm::make_mat4((float *)&m);\n}\n\nvoid ModelRenderer::Model::Render(GLManager *gl) const\n{\n    gl->legacy->Color3f(1, 1, 1);\n    gl->legacy->DisableTexture();\n    VAssert(_scene);\n    renderNode(gl, _scene->mRootNode);\n}\n\nvoid ModelRenderer::Model::DrawBoundingBox(GLManager *gl) const\n{\n    LegacyGL *lgl = gl->legacy;\n    lgl->DisableLighting();\n\n    lgl->Begin(GL_LINES);\n    lgl->Color3f(1, 0, 0);\n    lgl->Vertex3f(_min.x, _min.y, _min.z);\n    lgl->Vertex3f(_max.x, _min.y, _min.z);\n\n    lgl->Color3f(0, 1, 0);\n    lgl->Vertex3f(_min.x, _min.y, _min.z);\n    lgl->Vertex3f(_min.x, _max.y, _min.z);\n\n    lgl->Color3f(0, 0, 1);\n    lgl->Vertex3f(_min.x, _min.y, _min.z);\n    lgl->Vertex3f(_min.x, _min.y, _max.z);\n    lgl->End();\n}\n\nint ModelRenderer::Model::Load(const std::string &path)\n{\n    if (!FileUtils::Exists(path)) {\n        MyBase::SetErrMsg(\"File not found \\\"%s\\\"\", path.c_str());\n        return -1;\n    }\n\n    if (_importer.GetScene()) _importer.FreeScene();\n\n    _scene = _importer.ReadFile(path, aiProcessPreset_TargetRealtime_Quality | aiProcess_Triangulate);\n\n    if (!_scene) {\n        MyBase::SetErrMsg(\"3D File Error: %s\", _importer.GetErrorString());\n        return -1;\n    }\n\n    _min = glm::vec3(FLT_MAX);\n    _max = glm::vec3(FLT_MIN);\n    calculateBounds(_scene->mRootNode);\n\n    return 0;\n}\n\nModelRenderer::Scene::~Scene()\n{\n    for (auto it : _models) delete it.second;\n}\n\nint ModelRenderer::Scene::Load(const std::string &path)\n{\n    for (auto it : _models) delete it.second;\n    _keyframes.clear();\n    _models.clear();\n    _instances.clear();\n\n    int rc;\n    if (FileUtils::Extension(path) == \"vms\")\n        rc = loadSceneFile(path);\n    else\n        rc = createSceneFromModelFile(path);\n\n    return rc;\n}\n\nvoid ModelRenderer::Scene::Render(GLManager *gl, const int ts)\n{\n    MatrixManager *              mm = gl->matrixManager;\n    const vector<ModelInstance> &keyframe = getInstances(ts);\n\n    for (const auto &instance : keyframe) {\n        mm->PushMatrix();\n        const glm::vec3 translate = instance.translate;\n        const glm::vec3 rotate = instance.rotate;\n        const glm::vec3 scale = instance.scale;\n        const glm::vec3 origin = instance.origin;\n\n        mm->Translate(translate.x, translate.y, translate.z);\n        mm->Translate(origin.x, origin.y, origin.z);\n        mm->Rotate(glm::radians(rotate.x), 1, 0, 0);\n        mm->Rotate(glm::radians(rotate.y), 0, 1, 0);\n        mm->Rotate(glm::radians(rotate.z), 0, 0, 1);\n        mm->Scale(scale.x, scale.y, scale.z);\n        mm->Translate(-origin.x, -origin.y, -origin.z);\n\n        _models[instance.file]->Render(gl);\n        mm->PopMatrix();\n    }\n}\n\nglm::vec3 ModelRenderer::Scene::Center() const\n{\n    glm::vec3 accum(0.f);\n    for (const auto &it : _models) accum += it.second->Center();\n    if (!_models.empty()) accum /= (float)_models.size();\n    return accum;\n}\n\nstd::vector<ModelRenderer::Scene::ModelInstance> ModelRenderer::Scene::getInstances(const int ts) const\n{\n    VAssert(ts >= 0);\n    int lastValidFrame = -1;\n    for (auto frame : _keyframes) {\n        const int frameTime = frame.first;\n        if (frameTime == ts) return frame.second;\n        if (frameTime < ts && frameTime > lastValidFrame) lastValidFrame = frameTime;\n    }\n    if (lastValidFrame != -1)\n        return _keyframes.at(lastValidFrame);\n    else\n        return vector<ModelInstance>();\n}\n\nint ModelRenderer::Scene::createSceneFromModelFile(const std::string &path)\n{\n    Model *model = new Model;\n    int    rc = model->Load(path);\n    if (rc < 0) return rc;\n    _models[path] = model;\n\n    ModelInstance defaultInstance;\n    defaultInstance.file = path;\n    _keyframes[0] = {defaultInstance};\n\n    return 0;\n}\n\n#define TAG_INSTANCE \"instance_\"\n#define TAG_TIME     \"time_\"\n\nint ModelRenderer::Scene::loadSceneFile(const std::string &sceneFilePath)\n{\n    XmlNode   root;\n    XmlParser xmlParser;\n    int       rc = xmlParser.LoadFromFile(&root, sceneFilePath);\n    if (rc < 0) return rc;\n\n    for (int i = 0; i < root.GetNumChildren(); i++) {\n        XmlNode *node = root.GetChild(i);\n\n        if (STLUtils::BeginsWith(node->Tag(), TAG_INSTANCE)) {\n            ModelInstance instance;\n            rc = handleInstanceNode(node, &instance);\n        } else if (STLUtils::BeginsWith(node->Tag(), TAG_TIME)) {\n            rc = handleTimeNode(node);\n        } else {\n            MyBase::SetErrMsg(\"Unknown tag \\\"%s\\\"\", node->Tag().c_str());\n            rc = -1;\n        }\n\n        if (rc < 0) {\n            MyBase::SetErrMsg(\"%s ->\", root.Tag().c_str());\n            break;\n        }\n    }\n\n    if (rc < 0) return rc;\n\n    for (const ModelInstance &instance : _instances) {\n        if (!isModelCached(instance.file)) {\n            string filePath = instance.file;\n            if (!FileUtils::IsPathAbsolute(filePath)) filePath = FileUtils::JoinPaths({FileUtils::Dirname(sceneFilePath), filePath});\n\n            Model *model = new Model;\n            int    rc = model->Load(filePath);\n            if (rc < 0) return rc;\n            _models[instance.file] = model;\n        }\n    }\n\n    return rc;\n}\n\nint ModelRenderer::Scene::handleInstanceNode(XmlNode *node, ModelInstance *instance)\n{\n    string name = node->Tag();\n    if (name == TAG_INSTANCE) {\n        MyBase::SetErrMsg(\"Invalid instance \\\"%s\\\"\", node->Tag().c_str());\n        return -1;\n    }\n\n    instance->name = name;\n    if (node->Attrs().find(\"file\") != node->Attrs().end()) instance->file = node->Attrs()[\"file\"];\n\n    if (node->HasChild(\"translate\"))\n        if (handleVectorNode(node->GetChild(\"translate\"), &instance->translate) < 0) return -1;\n    if (node->HasChild(\"rotate\"))\n        if (handleVectorNode(node->GetChild(\"rotate\"), &instance->rotate) < 0) return -1;\n    if (node->HasChild(\"scale\"))\n        if (handleVectorNode(node->GetChild(\"scale\"), &instance->scale) < 0) return -1;\n    if (node->HasChild(\"origin\")) {\n        if (handleVectorNode(node->GetChild(\"origin\"), &instance->origin) < 0) return -1;\n    } else if (doesInstanceExist(instance->name)) {\n        instance->origin = getInitInstance(instance->name).origin;\n    }\n\n    if (doesInstanceExist(instance->name)) {\n        if (!instance->file.empty()) {\n            MyBase::SetErrMsg(\"Instance \\\"%s\\\" file specified more than once\", node->Tag().c_str());\n            return -1;\n        } else {\n            instance->file = getInitInstance(instance->name).file;\n        }\n    } else {\n        if (instance->file.empty()) {\n            MyBase::SetErrMsg(\"Instance \\\"%s\\\" defined without an associated file\", node->Tag().c_str());\n            return -1;\n        }\n\n        _instances.push_back(*instance);\n    }\n\n    return 0;\n}\n\nint ModelRenderer::Scene::handleTimeNode(XmlNode *node)\n{\n    int    rc = 0;\n    int    ts;\n    string tsString = node->Tag().substr(strlen(TAG_TIME));\n\n    if (tsString.empty() || parseIntString(tsString, &ts)) {\n        MyBase::SetErrMsg(\"Invalid time tag \\\"%s\\\"\", node->Tag().c_str());\n        return -1;\n    }\n\n    vector<ModelInstance> instances;\n\n    for (int i = 0; i < node->GetNumChildren(); i++) {\n        XmlNode *child = node->GetChild(i);\n\n        if (STLUtils::BeginsWith(child->Tag(), TAG_INSTANCE)) {\n            ModelInstance instance;\n            rc = handleInstanceNode(child, &instance);\n            if (rc < 0) break;\n\n            instances.push_back(instance);\n        } else {\n            MyBase::SetErrMsg(\"Unknown tag \\\"%s\\\"\", child->Tag().c_str());\n            rc = -1;\n        }\n        if (rc < 0) {\n            MyBase::SetErrMsg(\"%s ->\", node->Tag().c_str());\n            break;\n        }\n    }\n\n    _keyframes[ts] = instances;\n    return rc;\n}\n\nint ModelRenderer::Scene::handleVectorNode(XmlNode *node, glm::vec3 *v)\n{\n    int rc = 0;\n    rc -= handleFloatAttribute(node, \"x\", &v->x);\n    rc -= handleFloatAttribute(node, \"y\", &v->y);\n    rc -= handleFloatAttribute(node, \"z\", &v->z);\n    return rc;\n}\n\nint ModelRenderer::Scene::handleFloatAttribute(XmlNode *node, const std::string &name, float *f)\n{\n    if (node->Attrs().find(name) == node->Attrs().end()) return 0;\n\n    string valueString = node->Attrs()[name];\n    size_t charsRead;\n    try {\n        *f = std::stof(valueString, &charsRead);\n    } catch (invalid_argument const&) {\n        MyBase::SetErrMsg(\"Invalid float attribute %s=\\\"%s\\\"\", name.c_str(), valueString.c_str());\n        return -1;\n    } catch (out_of_range const&) {\n        MyBase::SetErrMsg(\"Float attribute out of range %s=\\\"%s\\\"\", name.c_str(), valueString.c_str());\n        return -1;\n    }\n\n    if (charsRead != valueString.size()) {\n        MyBase::SetErrMsg(\"Invalid float attribute %s=\\\"%s\\\"\", name.c_str(), valueString.c_str());\n        return -1;\n    }\n\n    return 0;\n}\n\nint ModelRenderer::Scene::parseIntString(const std::string &str, int *i) const\n{\n    size_t charsRead;\n    try {\n        *i = std::stof(str, &charsRead);\n    } catch (invalid_argument const&) {\n        MyBase::SetErrMsg(\"Invalid integer \\\"%s\\\"\", str.c_str());\n        return -1;\n    } catch (out_of_range const&) {\n        MyBase::SetErrMsg(\"Integer out of range \\\"%s\\\"\", str.c_str());\n        return -1;\n    }\n\n    if (charsRead != str.size()) {\n        MyBase::SetErrMsg(\"Invalid integer \\\"%s\\\"\", str.c_str());\n        return -1;\n    }\n\n    return 0;\n}\n\nModelRenderer::Scene::ModelInstance ModelRenderer::Scene::getInitInstance(const std::string &name) const\n{\n    assert(doesInstanceExist(name));\n\n    for (const ModelInstance &inst : _instances)\n        if (inst.name == name) return inst;\n    return ModelInstance();\n}\n\nbool ModelRenderer::Scene::doesInstanceExist(const std::string &name) const\n{\n    for (const ModelInstance &instance : _instances)\n        if (instance.name == name) return true;\n    return false;\n}\n\nbool ModelRenderer::Scene::isModelCached(const std::string &file) const\n{\n    for (const auto &it : _models)\n        if (it.first == file) return true;\n    return false;\n}\n"
  },
  {
    "path": "lib/render/MyPython.cpp",
    "content": "//\t\t\t\t\t\t\t\t *\n//\t\t     Copyright (C)  2016\t\t\t*\n//     University Corporation for Atmospheric Research\t\t*\n//\t\t     All Rights Reserved\t\t\t*\n//\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tMyPython.cpp\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tThu Sep 29 13:29:44 MDT 2016\n//\n//\tDescription:\n//\n#include <iostream>\n#include <algorithm>\n#include <cstdlib>\n#include <csignal>\n#include <cstdlib>\n#include <csetjmp>\n#include <csignal>\n\n#ifndef WIN32\n    #include <unistd.h>\n#endif\n\n#include <vapor/ResourcePath.h>\n#include <vapor/MyPython.h>\n#include \"vapor/VAssert.h\"\n\nusing namespace Wasp;\n\n#ifdef VAPOR3_0_0\nnamespace {\n\nbool        pyIntFailed = false;\nstatic void signal_handler(int sig)\n{\n    if (sig == SIGINT) {\n        cerr << \"Caught SIGINT\\n\";\n        pyIntFailed = true;\n    }\n}\n\nvoid init_signals(void)\n{\n    struct sigaction sigact;\n\n    sigact.sa_handler = signal_handler;\n    sigemptyset(&sigact.sa_mask);\n    sigact.sa_flags = 0;\n    sigaction(SIGINT, &sigact, (struct sigaction *)NULL);\n}\n}    // namespace\n#endif\n\nMyPython *  MyPython::m_instance = NULL;\nbool        MyPython::m_isInitialized = false;\nstd::string MyPython::m_pyHome = \"\";\nbool MyPython::IsRunningFromPython = false;\n\nMyPython *MyPython::Instance()\n{\n    if (!m_instance) { m_instance = new MyPython(); }\n    return (m_instance);\n}\n\nint MyPython::Initialize()\n{\n    if (m_isInitialized) return (0);\n\n    m_pyHome.clear();\n    char *s = getenv(\"VAPOR3_HOME\");\n    if (s) m_pyHome = s;\n\n    if (m_pyHome.empty()) {\n        // On windows use VAPOR_HOME/lib/python2.7; VAPOR_HOME works\n        // on Linux and Mac\n        m_pyHome = GetPythonDir();\n    }\n\n    if (!m_pyHome.empty()) {\n#ifdef WIN32\n        std::string version = GetPythonVersion();\n        version.erase(std::remove(version.begin(), version.end(), '.'), version.end());\n        std::string pythonPath = m_pyHome + \"\\\\Python\" + version + \";\";\n        pythonPath = pythonPath + m_pyHome + \"\\\\Python\" + version + \"\\\\Lib;\";\n        pythonPath = pythonPath + m_pyHome + \"\\\\Python\" + version + \"\\\\Lib\\\\site-packages\";\n        _putenv_s(\"PYTHONPATH\", pythonPath.c_str());\n        std::wstring   widestr = std::wstring(m_pyHome.begin(), m_pyHome.end());\n        const wchar_t *widecstr = widestr.c_str();\n        Py_SetPythonHome((wchar_t *)widecstr);\n        MyBase::SetDiagMsg(\"Setting PYTHONHOME in the vaporgui app to %s\\n\", m_pyHome.c_str());\n#endif\n    }\n\n    // Prevent python from attempting to write a .pyc file on disk.\n    //\n    const char *env = \"PYTHONDONTWRITEBYTECODE=1\";\n    char        env2[256];\n    strcpy(env2, env);    // All this trouble is to eliminate a compiler warning\n    putenv(env2);\n\n#ifdef VAPOR3_0_0\n    init_signals();\n#endif\n\n    // This is dependent on the environmental variable PYTHONHOME which is\n    // set in vaporgui/main.cpp\n    Py_InitializeEx(0);\n\n#ifdef VAPOR3_0_0\n    if (pyIntFailed) {\n        SetErrMsg(\"Failed to initialize python : Py_Initialize() Failed\");\n        return (-1);\n    }\n#endif\n\n#ifdef PYTHON_API_DEBUG\n    printf(\"Vapor Linked Python Version = %s (%s)\\n\", GetPythonVersion().c_str(), GetPythonPath().c_str());\n    PyRun_SimpleString(\"import sys; print(f\\\"Vapor Runtime Python Version = {sys.version.split(' ')[0]} ({sys.prefix})\\\")\");\n#endif\n    \n    int rc;\n    \n    if (!IsRunningFromPython) {\n        MyBase::SetErrMsg(\"Redirecting Python IO\");\n        rc = rerouteSTDIO();\n        if (rc < 0) return rc;\n    }\n\n    if ((rc = pyImport(\"sys\")) < 0) return rc;\n#ifndef DISABLE_EXTRA_PYTHON_MATH_IMPORTS\n    if ((rc = pyImport(\"matplotlib\")) < 0) return rc;\n#else\n    fprintf(stderr, \"WARNING Vapor python matplotlib import disabled\\n\");\n#endif\n\n    // Add vapor modules to search path\n    //\n    std::string path = Wasp::GetSharePath(\"python\");\n    path = \"sys.path.append('\" + path + \"')\\n\";\n    rc = PyRun_SimpleString(path.c_str());\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"PyRun_SimpleString() : %s\", PyErr().c_str());\n        return (-1);\n    }\n\n    m_isInitialized = true;\n\n    return (0);\n}\n\nint MyPython::pyImport(string lib)\n{\n    std::string importMPL = string() +\n                            \"try:\\n\"\n                            \"    import \"+lib+\"\\n\"\n                            \"except: \\n\"\n                            \"    print('Failed to import \"+lib+\"', file=sys.stderr)\\n\"\n                            \"    raise\\n\";\n    int rc = PyRun_SimpleString(importMPL.c_str());\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"PyRun_SimpleString() : %s\", PyErr().c_str());\n    }\n    \n    return rc;\n}\n\nint MyPython::rerouteSTDIO()\n{\n    // Ugh. Have to define a python object to enable capturing of\n    // stderr to a string. Python API doesn't support a version of\n    // PyErr_Print() that fetches the error to a C++ string. Give me\n    // a break!\n    //\n    std::string stdErr = \"try:\\n\"\n                         \"\timport sys\\n\"\n                         \"except: \\n\"\n                         \"\tprint('Failed to import sys')\\n\"\n                         \"\traise\\n\"\n                         \"class CatchErr:\\n\"\n                         \"\tdef __init__(self):\\n\"\n                         \"\t\tself.value = 'VAPOR_PY: '\\n\"\n                         \"\tdef write(self, txt):\\n\"\n                         \"\t\tself.value += txt\\n\"\n                         \"\tdef flush(self): pass\\n\"\n                         \"catchErr = CatchErr()\\n\"\n                         \"sys.stderr = catchErr\\n\"\n                        ;\n\n    // Catch stderr from Python to a string.\n    //\n    int rc = PyRun_SimpleString(stdErr.c_str());\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"PyRun_SimpleString() : %s\", PyErr().c_str());\n        return (-1);\n    }\n\n    std::string stdOut = \"try:\\n\"\n                         \"\timport sys\\n\"\n                         \"except: \\n\"\n                         \"\tprint('Failed to import sys')\\n\"\n                         \"\traise\\n\"\n                         \"class CatchOut:\\n\"\n                         \"\tdef __init__(self):\\n\"\n                         \"\t\tself.value = ''\\n\"\n                         \"\tdef write(self, txt):\\n\"\n                         \"\t\tself.value += txt\\n\"\n                         \"\tdef flush(self): pass\\n\"\n                         \"catchOut = CatchOut()\\n\"\n                         \"sys.stdout = catchOut\\n\"\n                        ;\n\n    // Catch stdout from Python to a string.\n    //\n    rc = PyRun_SimpleString(stdOut.c_str());\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"PyRun_SimpleString() : %s\", PyErr().c_str());\n        return (-1);\n    }\n\n    return 0;\n}\n\n// Fetch an error message genereated by Python API.\n//\nstring MyPython::PyErr()\n{\n    PyErr_Print();\n\n    PyObject *pMain = PyImport_AddModule(\"__main__\");\n\n    PyObject *catcher = NULL;\n    if (pMain && PyObject_HasAttrString(pMain, \"catchErr\")) { catcher = PyObject_GetAttrString(pMain, \"catchErr\"); }\n\n    // If catcher is NULL the Python message will be written\n    // to stderr. Otherwise it is writter to the catchErr object.\n    //\n\n    if (!catcher) { return (\"Failed to initialize Python error catcher!!!\"); }\n\n    PyObject *output = PyObject_GetAttrString(catcher, \"value\");\n    const char *    s = PyUnicode_AsUTF8(output);\n\n    // Erase the string\n    //\n    PyObject *eStr = PyUnicode_FromString(\"\");\n    PyObject_SetAttrString(catcher, \"value\", eStr);\n    Py_DECREF(eStr);\n\n    return (s ? string(s) : string());\n}\n\n// Fetch an error message genereated by Python API.\n//\nstring MyPython::PyOut()\n{\n    PyObject *pMain = PyImport_AddModule(\"__main__\");\n\n    PyObject *catcher = NULL;\n    if (pMain && PyObject_HasAttrString(pMain, \"catchOut\")) { catcher = PyObject_GetAttrString(pMain, \"catchOut\"); }\n\n    if (!catcher) { return (\"\"); }\n\n    PyObject *output = PyObject_GetAttrString(catcher, \"value\");\n    const char *    s = PyUnicode_AsUTF8(output);\n\n    // Erase the string\n    //\n    PyObject *eStr = PyUnicode_FromString(\"\");\n    PyObject_SetAttrString(catcher, \"value\", eStr);\n    Py_DECREF(eStr);\n\n    return (s ? string(s) : string());\n}\n\nPyObject *MyPython::CreatePyFunc(string moduleName, string funcName, string script)\n{\n    PyObject *pMain = PyImport_AddModule(\"__main__\");\n    if (!pMain) { return (NULL); }\n\n    PyObject *pModule = PyImport_AddModule(moduleName.c_str());\n    if (!pModule) { return (NULL); }\n\n    // Get the dictionary object from my module so I can pass this\n    // to PyRun_String\n    //\n    PyObject *pLocal = PyModule_GetDict(pModule);\n    VAssert(pLocal != NULL);    // no fail\n\n    PyObject *pGlobal = PyModule_GetDict(pMain);\n    VAssert(pGlobal != NULL);    // no fail\n\n    PyObject *pValue = PyRun_String(script.c_str(), Py_file_input, pGlobal, pLocal);\n    if (!pValue) { return (NULL); }\n    Py_DECREF(pValue);\n\n    PyObject *pFunc = PyObject_GetAttrString(pModule, funcName.c_str());\n    VAssert(pFunc != NULL);\n\n    int rc = PyCallable_Check(pFunc);\n    if (rc != 1) {    // Yes, this API call returns a 1 on success.\n\n        Py_DECREF(pFunc);\n        return (NULL);\n    }\n\n    return (pFunc);\n}\n"
  },
  {
    "path": "lib/render/NavigationUtils.cpp",
    "content": "#include <vapor/NavigationUtils.h>\n#include <vapor/DataStatus.h>\n#include <vapor/ParamsMgr.h>\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n#include <vapor/AnimationParams.h>\n#include <vapor/GUIStateParams.h>\n#include <vapor/AnimationParams.h>\n#include <vapor/ParticleParams.h>\n#include <cassert>\n#include <cfloat>\n#include <glm/glm.hpp>\n\nusing namespace VAPoR;\nusing glm::vec3;\n\nvoid NavigationUtils::SetHomeViewpoint(ControlExec *ce)\n{\n    ParamsMgr *      paramsMgr = ce->GetParamsMgr();\n    ViewpointParams *vpParams = GetActiveViewpointParams(ce);\n    GUIStateParams * guiParams = GetGUIStateParams(ce);\n    assert(vpParams);\n    assert(guiParams);\n\n    // Get the current model view matrix and it home\n    //\n    vector<double> m = vpParams->GetModelViewMatrix();\n    vector<double> c = vpParams->GetRotationCenter();\n\n    paramsMgr->BeginSaveStateGroup(\"Set home viewpoint\");\n\n    guiParams->SetValueDoubleVec(\"HomeModelViewMatrix\", \"Modelview matrix\", m);\n    guiParams->SetValueDoubleVec(\"HomeRotationCenter\", \"Camera rotation center\", c);\n    paramsMgr->EndSaveStateGroup();\n}\n\n\nvoid NavigationUtils::UseHomeViewpoint(ControlExec *ce)\n{\n    GUIStateParams *guiParams = GetGUIStateParams(ce);\n\n    // Get the home matrix and make it the current model view matrix\n    //\n    vector<double> defaultV(16, 0.0);\n    defaultV[0] = defaultV[5] = defaultV[10] = defaultV[15] = 1.0;\n\n    vector<double> m = guiParams->GetValueDoubleVec(\"HomeModelViewMatrix\", defaultV);\n\n    vector<double> defaultC(3, 0.0);\n    vector<double> c = guiParams->GetValueDoubleVec(\"HomeRotationCenter\", defaultC);\n\n    SetAllCameras(ce, m, c);\n}\n\n\nvoid NavigationUtils::ViewAll(ControlExec *ce)\n{\n    DataStatus *dataStatus = ce->GetDataStatus();\n    ParamsMgr * paramsMgr = ce->GetParamsMgr();\n    size_t      ts = GetCurrentTimeStep(ce);\n\n    CoordType minExts, maxExts;\n    dataStatus->GetActiveExtents(paramsMgr, ts, minExts, maxExts);\n\n    double maxSide = max(maxExts[2] - minExts[2], max(maxExts[1] - minExts[1], maxExts[0] - minExts[0]));\n\n    // calculate the camera position: center - 1.5*dirvec*maxSide;\n    // Position the camera 1.5*maxSide units away from the center, aimed\n    // at the center.\n    //\n\n    // Make sure the dirvec is normalized:\n    double dirvec[] = {0.0, 0.0, -1.0};\n    //    vnormal(dirvec);\n\n    double upvec[] = {0.0, 1.0, 0.0};\n\n    double posvec[3], center[3];\n    for (int i = 0; i < 3; i++) {\n        center[i] = 0.5f * (maxExts[i] + minExts[i]);\n        posvec[i] = center[i] - 1.5 * maxSide * dirvec[i];\n    }\n\n    SetAllCameras(ce, posvec, dirvec, upvec, center);\n}\n\n\nvoid NavigationUtils::AlignView(ControlExec *ce, int axis)\n{\n    // This fixes a bug in this legacy function where the up dir is occationally wrong\n    if (axis != 3 && axis != 1) AlignView(ce, 3);\n\n    float axes[3][3] = {{1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f}};\n\n    double dirvec[3] = {0.0, 0.0, 0.0};\n    double upvec[3] = {0.0, 1.0, 0.0};\n    (void)(upvec);\n    ViewpointParams *vpParams = GetActiveViewpointParams(ce);\n    assert(vpParams);\n    if (!vpParams) return;\n\n    double m[16], curPosVec[3], curViewDir[3], curUpVec[3], curCenter[3];\n    vpParams->GetModelViewMatrix(m);\n    bool status = vpParams->ReconstructCamera(m, curPosVec, curUpVec, curViewDir);\n    vpParams->GetRotationCenter(curCenter);\n    if (!status) return;\n    \n#define V3S(v) (string(\"[\")+to_string(v[0])+\",\"+to_string(v[1])+\",\"+to_string(v[2])+\"]\").c_str()\n\n    if (axis == 1) {    // Special case to align to closest axis.\n        // determine the closest view direction and up vector to the current viewpoint.\n        // Check the dot product with all axes\n        float maxVDot = -1.f;\n        int   bestVDir = 0;\n        float maxUDot = -1.f;\n        int   bestUDir = 0;\n        for (int i = 0; i < 3; i++) {\n            double dotVProd = 0.;\n            double dotUProd = 0.;\n            for (int j = 0; j < 3; j++) {\n                dotUProd += (axes[i][j] * curViewDir[j]);\n                dotVProd += (axes[i][j] * curUpVec[j]);\n            }\n            if (abs(dotVProd) > maxVDot) {\n                maxVDot = abs(dotVProd);\n                bestVDir = i + 1;\n                if (dotVProd < 0.f) bestVDir = -i - 1;\n            }\n            if (abs(dotUProd) > maxUDot) {\n                maxUDot = abs(dotUProd);\n                bestUDir = i + 1;\n                if (dotUProd < 0.f) bestUDir = -i - 1;\n            }\n        }\n        for (int i = 0; i < 3; i++) {\n            if (bestUDir > 0)\n                dirvec[i] = axes[bestUDir - 1][i];\n            else\n                dirvec[i] = -axes[-1 - bestUDir][i];\n\n            if (bestVDir > 0)\n                upvec[i] = axes[bestVDir - 1][i];\n            else\n                upvec[i] = -axes[-1 - bestVDir][i];\n        }\n    } else {\n        // establish view direction, up vector:\n        switch (axis) {\n        case (2): dirvec[0] = 1.f; break;\n        case (3):\n            dirvec[1] = 1.f;\n            upvec[1] = 0.f;\n            upvec[0] = 1.f;\n            break;\n        case (4): dirvec[2] = 1.f; break;\n        case (5): dirvec[0] = -1.f; break;\n        case (6):\n            dirvec[1] = -1.f;\n            upvec[1] = 0.f;\n            upvec[0] = 1.f;\n            break;\n        case (7): dirvec[2] = -1.f; break;\n        default: return;\n        }\n    }\n\n    vector<double> stretch = vpParams->GetStretchFactors();\n\n    // Determine distance from center to camera, in stretched coordinates\n\n    // determine the relative position in stretched coords:\n    vsub(curPosVec, curCenter, curPosVec);\n    float viewDist = vlength(curPosVec);\n    // Position the camera the same distance from the center but down the -axis direction\n    for (int i = 0; i < 3; i++) {\n        dirvec[i] = dirvec[i] * viewDist;\n        curPosVec[i] = (curCenter[i] - dirvec[i]);\n    }\n\n    SetAllCameras(ce, curPosVec, dirvec, upvec, curCenter);\n}\n\n\nvoid NavigationUtils::SetAllCameras(ControlExec *ce, const double position[3], const double direction[3], const double up[3], const double origin[3])\n{\n    Trackball trackball;\n    bool      ok = trackball.setFromFrame(position, direction, up, origin, true);\n    if (!ok) {\n        MyBase::SetErrMsg(\"Invalid camera settings\");\n        return;\n    }\n\n    trackball.TrackballSetMatrix();\n    const double *m = trackball.GetModelViewMatrix();\n    SetAllCameras(ce, m, origin);\n}\n\n\nvoid NavigationUtils::SetAllCameras(ControlExec *ce, const double position[3], const double direction[3], const double up[3])\n{\n    ViewpointParams *vpParams = GetActiveViewpointParams(ce);\n    assert(vpParams);\n    if (!vpParams) return;\n\n    double curCenter[3];\n    vpParams->GetRotationCenter(curCenter);\n    \n    SetAllCameras(ce, position, direction, up, curCenter);\n}\n\n\nvoid NavigationUtils::SetAllCameras(ControlExec *ce, const vector<double> &position, const vector<double> &direction, const vector<double> &up, const vector<double> &origin)\n{\n    SetAllCameras(ce, position.data(), direction.data(), up.data(), origin.data());\n}\n\n\nvoid NavigationUtils::SetAllCameras(ControlExec *ce, const vector<double> &position, const vector<double> &direction, const vector<double> &up)\n{\n    SetAllCameras(ce, position.data(), direction.data(), up.data());\n}\n\n\nvoid NavigationUtils::SetAllCameras(ControlExec *ce, const double matrix[16], const double origin[3])\n{\n    ParamsMgr *pm = ce->GetParamsMgr();\n    auto       vizNames = pm->GetVisualizerNames();\n    pm->BeginSaveStateGroup(\"Set Camera\");\n    for (auto &viz : vizNames) {\n        ViewpointParams *vp = pm->GetViewpointParams(viz);\n        vp->SetModelViewMatrix(matrix);\n        vp->SetRotationCenter(origin);\n    }\n    pm->EndSaveStateGroup();\n}\n\n\nvoid NavigationUtils::SetAllCameras(ControlExec *ce, const vector<double> &m, const vector<double> &origin)\n{\n    assert(m.size() == 16);\n    SetAllCameras(ce, m.data(), origin.data());\n}\n\nvoid NavigationUtils::SetAllCameras(ControlExec *ce, const Trackball &trackball)\n{\n    double center[3];\n    trackball.GetCenter(center);\n    const double *m = trackball.GetModelViewMatrix();\n    NavigationUtils::SetAllCameras(ce, m, center);\n}\n\nvoid NavigationUtils::ConfigureTrackball(ControlExec *ce, Trackball &trackball)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    trackball.setFromFrame(pos, dir, up, tgt, true);\n    \n    if (ce->GetDataNames().size() == 0) return;\n\n    DataStatus *dataStatus = ce->GetDataStatus();\n    ParamsMgr  *paramsMgr  = ce->GetParamsMgr();\n    size_t ts = GetAnimationParams(ce)->GetCurrentTimestep();\n\n    VAPoR::CoordType minExts, maxExts;\n    dataStatus->GetActiveExtents(paramsMgr, ts, minExts, maxExts);\n\n    double scale[3];\n    scale[0] = scale[1] = scale[2] = max(maxExts[0] - minExts[0], (maxExts[1] - minExts[1]));\n    trackball.SetScale(scale);\n}\n\nvoid NavigationUtils::LookAt(ControlExec *ce, const vector<double> &position, const vector<double> &target, const vector<double> &up)\n{\n    vec3 pos(position[0], position[1], position[2]);\n    vec3 tar(target[0], target[1], target[2]);\n    vec3 dir = glm::normalize(tar - pos);\n    vector<double> direction = {dir.x, dir.y, dir.z};\n    SetAllCameras(ce, position, direction, up, target);\n}\n\n\nvoid NavigationUtils::SetTimestep(ControlExec *ce, size_t ts)\n{\n    AnimationParams *aParams = GetAnimationParams(ce);\n    size_t ots = aParams->GetCurrentTimestep();\n\n    propagateTimestep(ce, ts);\n\n    handleMovingDomainAdjustments(ce, ots, ts);\n}\n\nvoid NavigationUtils::propagateTimestep(ControlExec *ce, size_t ts)\n{\n    DataStatus *dataStatus = ce->GetDataStatus();\n    ParamsMgr * paramsMgr = ce->GetParamsMgr();\n\n    paramsMgr->BeginSaveStateGroup(\"Set Timestep \" + std::to_string(ts));\n\n    // First set current *global* timestep in AnimationParams\n    //\n    AnimationParams *aParams = GetAnimationParams(ce);\n    aParams->SetCurrentTimestep(ts);\n\n    // Now set *local* time step for each RenderParams instance\n    //\n    vector<string> winNames = paramsMgr->GetVisualizerNames();\n    for (int i = 0; i < winNames.size(); i++) {\n        vector<string> dataSetNames = dataStatus->GetDataMgrNames();\n        for (int j = 0; j < dataSetNames.size(); j++) {\n            vector<RenderParams *> rParams;\n            paramsMgr->GetRenderParams(winNames[i], dataSetNames[j], rParams);\n\n            if (!rParams.size()) continue;\n\n            size_t local_ts = dataStatus->MapGlobalToLocalTimeStep(dataSetNames[j], ts);\n\n            for (int k = 0; k < rParams.size(); k++) {\n                RenderParams *rp = rParams[k];\n                rp->SetCurrentTimestep(local_ts);\n\n                // If variable was not initialzed but now is, reset the TF mapping range\n                std::string varNames[2] = {rp->GetVariableName(), rp->GetActualColorMapVariableName()};\n\n                for (int l = 0; l < 2; l++) {\n                    if (varNames[i].empty()) continue;\n\n                    MapperFunction *tf = rp->GetMapperFunc(varNames[i]);\n                    vector<double>  range = tf->getMinMaxMapValue();\n                    if (abs(range[1] - range[0]) > FLT_EPSILON * max(abs(range[0]), abs(range[1]))) continue;\n\n                    DataMgr *dm = dataStatus->GetDataMgr(dataSetNames[j]);\n                    if (!dm) continue;\n\n                    if (!dm->VariableExists(local_ts, varNames[i], 0, 0)) continue;\n\n                    if (dm->GetDataRange(local_ts, varNames[i], 0, 0, range) < 0) continue;\n\n                    bool SSE = paramsMgr->GetSaveStateEnabled();\n                    paramsMgr->SetSaveStateEnabled(false);\n                    tf->setMinMaxMapValue(range[0], range[1]);\n                    paramsMgr->SetSaveStateEnabled(SSE);\n                }\n            }\n        }\n    }\n\n    paramsMgr->EndSaveStateGroup();\n}\n\n\nstatic vector<double> DoubleArr3ToVector(double a[3])\n{\n    vector<double> v(3);\n    v[0] = a[0];\n    v[1] = a[1];\n    v[2] = a[2];\n    return v;\n}\n\n\nvoid NavigationUtils::GetCameraProperties(ControlExec *ce, vector<double> *position, vector<double> *direction, vector<double> *up, vector<double> *target)\n{\n    position->resize(3, 0);\n    direction->resize(3, 0);\n    up->resize(3, 0);\n    target->resize(3, 0);\n    \n    ViewpointParams *vpParams = GetActiveViewpointParams(ce);\n    assert(vpParams);\n    if (!vpParams) return;\n    \n    double m[16], posD[3] = {0}, dirD[3] = {0}, upD[3] = {0}, targetD[3] = {0};\n    vpParams->GetModelViewMatrix(m);\n    vpParams->ReconstructCamera(m, posD, upD, dirD);\n    vpParams->GetRotationCenter(targetD);\n    \n    *position = DoubleArr3ToVector(posD);\n    *direction = DoubleArr3ToVector(dirD);\n    *up = DoubleArr3ToVector(upD);\n    *target = DoubleArr3ToVector(targetD);\n}\n\n\nvector<double> NavigationUtils::GetCameraPosition(ControlExec *ce)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    return pos;\n}\n\n\nvector<double> NavigationUtils::GetCameraDirection(ControlExec *ce)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    return dir;\n}\n\n\nvector<double> NavigationUtils::GetCameraUp(ControlExec *ce)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    return up;\n}\n\n\nvector<double> NavigationUtils::GetCameraTarget(ControlExec *ce)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    return tgt;\n}\n\n\nvoid NavigationUtils::SetCameraPosition(ControlExec *ce, const vector<double> &v)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    SetAllCameras(ce, v, dir, up, tgt);\n}\n\n\nvoid NavigationUtils::SetCameraDirection(ControlExec *ce, const vector<double> &v)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    SetAllCameras(ce, pos, v, up, tgt);\n}\n\n\nvoid NavigationUtils::SetCameraUp(ControlExec *ce, const vector<double> &v)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    SetAllCameras(ce, pos, dir, v, tgt);\n}\n\n\nvoid NavigationUtils::SetCameraTarget(ControlExec *ce, const vector<double> &v)\n{\n    vector<double> pos, dir, up, tgt;\n    GetCameraProperties(ce, &pos, &dir, &up, &tgt);\n    SetAllCameras(ce, pos, dir, up, v);\n}\n\n\nlong NavigationUtils::GetCurrentTimeStep(VAPoR::ControlExec *ce)\n{\n    AnimationParams *aParams = (AnimationParams *)ce->GetParamsMgr()->GetParams(AnimationParams::GetClassType());\n    VAssert(aParams);\n\n    return aParams->GetCurrentTimestep();\n}\n\n\nVAPoR::ViewpointParams *NavigationUtils::GetActiveViewpointParams(ControlExec *ce)\n{\n    ParamsMgr *      pm = ce->GetParamsMgr();\n    auto             activeViz = GetGUIStateParams(ce)->GetActiveVizName();\n    ViewpointParams *vp = pm->GetViewpointParams(activeViz);\n    return vp;\n}\n\n\nGUIStateParams *NavigationUtils::GetGUIStateParams(ControlExec *ce)\n{\n    ParamsMgr *pm = ce->GetParamsMgr();\n    return ((GUIStateParams *)pm->GetParams(GUIStateParams::GetClassType()));\n}\n\n\nAnimationParams *NavigationUtils::GetAnimationParams(ControlExec *ce) { return ((AnimationParams *)ce->GetParamsMgr()->GetParams(AnimationParams::GetClassType())); }\n\n\nstatic vec3 CoordTypeToVec3(const CoordType &c) { return vec3(c[0], c[1], c[2]); }\nstatic CoordType Vec3ToCoordType(const vec3 &c) { return CoordType {c[0], c[1], c[2]}; }\n\n\nvoid NavigationUtils::handleMovingDomainAdjustments(ControlExec *ce, size_t ts_from, size_t ts_to)\n{\n    auto paramsMgr = ce->GetParamsMgr();\n    auto guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n    bool trackCamera = guiParams->GetValueLong(GUIStateParams::MovingDomainTrackCameraTag, false);\n    bool trackDomain = guiParams->GetValueLong(GUIStateParams::MovingDomainTrackRenderRegionsTag, false);\n\n    if (trackCamera) movingDomainTrackCamera(ce, ts_from, ts_to);\n    if (trackDomain) movingDomainTrackRenderRegions(ce, ts_from, ts_to);\n    if (trackDomain) movingDomainTrackParticleRenderRegions(ce, ts_from, ts_to);\n}\n\n\nstd::tuple<glm::vec3, glm::vec3> NavigationUtils::getDomainExtentsAtTimestep(ControlExec *ce, const std::string &dataset, size_t ts)\n{\n    auto paramsMgr = ce->GetParamsMgr();\n    auto dataStatus = ce->GetDataStatus();\n    auto guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n    string viz = guiParams->GetActiveVizName();\n\n    CoordType minExts_, maxExts_;\n    dataStatus->GetActiveExtents(paramsMgr, viz, dataset, ts, minExts_, maxExts_);\n    vec3 minExts = CoordTypeToVec3(minExts_);\n    vec3 maxExts = CoordTypeToVec3(maxExts_);\n\n    return std::make_tuple(minExts, maxExts);\n}\n\n\nglm::vec3 NavigationUtils::getDomainMovementBetweenTimesteps(ControlExec *ce, string dataset, size_t from, size_t to)\n{\n    vec3 oldMinExts, oldMaxExts, newMinExts, newMaxExts;\n    std::tie(oldMinExts, oldMaxExts) = getDomainExtentsAtTimestep(ce, dataset, from);\n    std::tie(newMinExts, newMaxExts) = getDomainExtentsAtTimestep(ce, dataset, to);\n\n    vec3 oldDomainCenter = (oldMinExts+oldMaxExts)/2.f;\n    vec3 newDomainCenter = (newMinExts+newMaxExts)/2.f;\n    vec3 domainMove = newDomainCenter - oldDomainCenter;\n\n    return domainMove;\n}\n\n\nstd::tuple<glm::vec3, glm::vec3> NavigationUtils::getRendererExtents(const RenderParams *rp)\n{\n    CoordType minExts_, maxExts_;\n    rp->GetBox()->GetExtents(minExts_, maxExts_);\n    return std::make_tuple(CoordTypeToVec3(minExts_), CoordTypeToVec3(maxExts_));\n}\n\n\nvoid NavigationUtils::setRendererExtents(const RenderParams *rp, const glm::vec3 &minExts, const glm::vec3 &maxExts)\n{\n    rp->GetBox()->SetExtents(Vec3ToCoordType(minExts), Vec3ToCoordType(maxExts));\n}\n\n\nvoid NavigationUtils::movingDomainTrackCamera(ControlExec *ce, size_t from, size_t to)\n{\n    auto paramsMgr = ce->GetParamsMgr();\n    auto dataStatus = ce->GetDataStatus();\n    GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n    string viz = guiParams->GetActiveVizName();\n    auto viewpointParams = paramsMgr->GetViewpointParams(guiParams->GetActiveVizName());\n    auto datasets = guiParams->GetOpenDataSetNames();\n\n    vec3 domainMoveSum = vec3(0);\n    int nDomainsMoved = 0;\n\n    for (const auto &dataset : datasets) {\n        if (!dataStatus->GetDataMgr(dataset)->HasMovingDomain()) continue;\n        auto domainMove = getDomainMovementBetweenTimesteps(ce, dataset, from, to);\n        domainMoveSum += domainMove;\n        nDomainsMoved++;\n    }\n\n    if (nDomainsMoved) {\n        vec3 domainMove = domainMoveSum / (float)nDomainsMoved;\n        double camMat[16], camPos[3], camDir[3], camUp[3];\n        viewpointParams->GetModelViewMatrix(camMat);\n        viewpointParams->ReconstructCamera(camMat, camPos, camUp, camDir);\n        for (int i = 0; i < 3; i++) camPos[i] += domainMove[i];\n        NavigationUtils::SetAllCameras(ce, camPos, camDir, camUp);\n    }\n}\n\n\nvoid NavigationUtils::movingDomainTrackRenderRegions(ControlExec *ce, size_t from, size_t to)\n{\n    auto paramsMgr = ce->GetParamsMgr();\n    auto dataStatus = ce->GetDataStatus();\n    GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n    string viz = guiParams->GetActiveVizName();\n    auto datasets = guiParams->GetOpenDataSetNames();\n\n    for (const auto &dataset : datasets) {\n        if (!dataStatus->GetDataMgr(dataset)->HasMovingDomain()) continue;\n        auto domainMove = getDomainMovementBetweenTimesteps(ce, dataset, from, to);\n\n        vector<string> renderers;\n        paramsMgr->GetRenderParamNames(viz, dataset, renderers);\n        for (const auto &renderer : renderers) {\n            string _1, _2, className;\n            paramsMgr->RenderParamsLookup(renderer, _1, _2, className);\n            if (className == ParticleParams::GetClassType())\n                continue;\n            RenderParams *rp = paramsMgr->GetRenderParams(viz, dataset, className, renderer);\n\n            vec3 minExts, maxExts;\n            std::tie(minExts, maxExts) = getRendererExtents(rp);\n            setRendererExtents(rp, domainMove+minExts, domainMove+maxExts);\n        }\n    }\n}\n\n\nvoid NavigationUtils::movingDomainTrackParticleRenderRegions(ControlExec *ce, size_t from, size_t to)\n{\n    auto paramsMgr = ce->GetParamsMgr();\n    GUIStateParams *guiParams = (GUIStateParams *)paramsMgr->GetParams(GUIStateParams::GetClassType());\n    string viz = guiParams->GetActiveVizName();\n    auto datasets = guiParams->GetOpenDataSetNames();\n\n    for (const auto &dataset : datasets) {\n        vector<string> renderers;\n        paramsMgr->GetRenderParamNames(viz, dataset, renderers);\n        for (const auto &renderer : renderers) {\n            string _1, _2, className;\n            paramsMgr->RenderParamsLookup(renderer, _1, _2, className);\n            if (className != ParticleParams::GetClassType())\n                continue;\n            RenderParams *rp = paramsMgr->GetRenderParams(viz, dataset, className, renderer);\n\n            vec3 dataExtentsFromMin, dataExtentsFromMax, dataExtentsToMin, dataExtentsToMax, rendererExtentsFromMin, rendererExtentsFromMax;\n            std::tie(dataExtentsFromMin,     dataExtentsFromMax)     = getDomainExtentsAtTimestep(ce, dataset, from);\n            std::tie(dataExtentsToMin,       dataExtentsToMax)       = getDomainExtentsAtTimestep(ce, dataset, to);\n            std::tie(rendererExtentsFromMin, rendererExtentsFromMax) = getRendererExtents(rp);\n\n            vec3 rendererExtentsFromMinNorm = (rendererExtentsFromMin - dataExtentsFromMin) / (dataExtentsFromMax - dataExtentsFromMin);\n            vec3 rendererExtentsFromMaxNorm = (rendererExtentsFromMax - dataExtentsFromMin) / (dataExtentsFromMax - dataExtentsFromMin);\n            vec3 rendererExtentsToMin = (dataExtentsToMax - dataExtentsToMin) * rendererExtentsFromMinNorm + dataExtentsToMin;\n            vec3 rendererExtentsToMax = (dataExtentsToMax - dataExtentsToMin) * rendererExtentsFromMaxNorm + dataExtentsToMin;\n\n            setRendererExtents(rp, rendererExtentsToMin, rendererExtentsToMax);\n        }\n    }\n}\n\n\n// This is some code that someone decided is worth keeping for future reference.\n// It allegedly worked at some point.\n// I don't want to have to write any camera code without refactoring the entire\n// system so I am leaving it here in case the functionality is needed again.\n\n#ifdef VAPOR3_0_0_ALPHA\nvoid NavigationEventRouter::CenterSubRegion()\n{\n    cout << \"NavigationEventRouter::CenterSubRegion not implemented\" << endl;\n\n    ViewpointParams *vpParams = _getActiveParams();\n    if (!vpParams) return;\n\n    // Find the largest of the dimensions of the current region, projected orthogonal to view\n    // direction:\n    // Make sure the dirvec is normalized:\n    double dirvec[3];\n    vpParams->GetCameraViewDir(dirvec);\n\n    double upvec[3];\n    vpParams->GetCameraUpVec(upvec);\n\n    vnormal(dirvec);\n    float          regionSideVector[3], compVec[3], projvec[3];\n    float          maxProj = -1.f;\n    vector<double> stretch = vpParams->GetStretchFactors();\n\n    vector<double> minExts, maxExts;\n    rParams->GetBox()->GetExtents(minExts, maxExts);\n    for (int i = 0; i < 3; i++) {\n        // Make a vector that points along side(i) of subregion,\n\n        for (int j = 0; j < 3; j++) {\n            regionSideVector[j] = 0.f;\n            if (j == i) { regionSideVector[j] = maxExts[j] - minExts[j]; }\n        }\n        // Now find its component orthogonal to view direction:\n        double dotprod = 0.;\n\n        for (int j = 0; j < 3; j++) dotprod += (dirvec[j] * regionSideVector[j]);\n        for (int j = 0; j < 3; j++) compVec[j] = dotprod * dirvec[j];\n        // projvec is projection orthogonal to view dir:\n        vsub(regionSideVector, compVec, projvec);\n        float proj = vlength(projvec);\n        if (proj > maxProj) maxProj = proj;\n    }\n\n    // calculate the camera position: center - 1.5*dirvec*maxSide;\n    // Position the camera 1.5*maxSide units away from the center, aimed\n    // at the center\n\n    double         posvec[3], center[3];\n    vector<double> rotCtr;\n    for (int i = 0; i < 3; i++) {\n        center[i] = 0.5 * (minExts[i] + maxExts[i]);\n        posvec[i] = center[i] - (1.5 * maxProj * dirvec[i] / stretch[i]);\n    }\n\n    _setViewpointParams(center, posvec, dirvec, upvec);\n}\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n// Reset the center of view.  Leave the camera where it is\nvoid NavigationEventRouter::SetCenter(const double *coords)\n{\n    double           vdir[3];\n    vector<double>   nvdir;\n    ViewpointParams *vpParams = _getActiveParams();\n    if (!vpParams) return;\n    vector<double> stretch = _dataStatus->getStretchFactors();\n\n    // Determine the new viewDir in stretched world coords\n\n    vcopy(coords, vdir);\n    // Stretch the new view center coords\n    for (int i = 0; i < 3; i++) vdir[i] *= stretch[i];\n    double campos[3];\n    vpParams->getStretchedCamPosLocal(campos);\n    vsub(vdir, campos, vdir);\n\n    vnormal(vdir);\n    vector<double> vvdir;\n    #ifdef VAPOR3_0_0_ALPHA\n    Command *cmd = Command::CaptureStart(vpParams, \"re-center view\");\n    #endif\n    for (int i = 0; i < 3; i++) vvdir.push_back(vdir[i]);\n    vpParams->setViewDir(vvdir);\n    vector<double> rotCtr;\n    for (int i = 0; i < 3; i++) { rotCtr.push_back(coords[i]); }\n    vpParams->setRotationCenterLocal(rotCtr);\n    #ifdef VAPOR3_0_0_ALPHA\n    Command::CaptureEnd(cmd, vpParams);\n    #endif\n    updateTab();\n}\n#endif\n"
  },
  {
    "path": "lib/render/OSPRay.cpp",
    "content": "#ifdef WIN32\n    #define _USE_MATH_DEFINES\n    #include <cmath>\n#endif\n\n#include <vapor/OSPRay.h>\n#include <stdio.h>\n#include <stdlib.h>\n\nusing namespace VOSP;\n\n#ifdef BUILD_OSPRAY\nstatic int _initialized = false;\n\nvoid ospErrorCallback(OSPError error, const char *msg)\n{\n    fprintf(stderr, \"OSP error \");\n    switch (error) {\n    #define STRINGIFY(x) \\\n    case x: fprintf(stderr, #x); break;\n        STRINGIFY(OSP_NO_ERROR)\n        STRINGIFY(OSP_UNKNOWN_ERROR)\n        STRINGIFY(OSP_INVALID_ARGUMENT)\n        STRINGIFY(OSP_INVALID_OPERATION)\n        STRINGIFY(OSP_OUT_OF_MEMORY)\n        STRINGIFY(OSP_UNSUPPORTED_CPU)\n        STRINGIFY(OSP_VERSION_MISMATCH)\n    #undef STRINGIFY\n    }\n    fprintf(stderr, \": %s\\n\", msg);\n    //    exit(1);\n}\n#endif\n\nint VOSP::Initialize(int *argc, char **argv)\n{\n#ifdef BUILD_OSPRAY\n    if (_initialized) return 0;\n\n    OSPError init_error = ospInit(argc, (const char **)argv);\n    if (init_error != OSP_NO_ERROR) return init_error;\n\n    // Hide deprecated warning.\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\n    // If this is not set, OSPRay will crash upon shutdown\n    ospDeviceSetErrorFunc(ospGetCurrentDevice(), ospErrorCallback);\n    #pragma GCC diagnostic pop\n    _initialized = true;\n    return 0;\n#else\n    return 0;\n#endif\n}\n\nint VOSP::Shutdown()\n{\n    //    ospShutdown(); // Broken. Do not use.\n    return 0;\n}\n\nstd::string VOSP::Version()\n{\n#ifdef BUILD_OSPRAY\n    long major = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_MAJOR);\n    long minor = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_MINOR);\n    long patch = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_PATCH);\n    return std::to_string(major) + \".\" + std::to_string(minor) + \".\" + std::to_string(patch);\n#else\n    return \"0.0.0\";\n#endif\n}\n\nbool VOSP::IsVersionAtLeast(int testMajor, int testMinor)\n{\n#ifdef BUILD_OSPRAY\n    long major = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_MAJOR);\n    long minor = ospDeviceGetProperty(ospGetCurrentDevice(), OSP_DEVICE_VERSION_MINOR);\n\n    if (major > testMajor || (major == testMajor && minor >= testMinor)) return true;\n\n    return false;\n\n#else\n    return false;\n#endif\n}\n\n#ifdef BUILD_OSPRAY\n\nOSPData VOSP::NewCopiedData(const void *data, OSPDataType type, uint64_t numItems1, uint64_t numItems2, uint64_t numItems3)\n{\n    OSPData shared = ospNewSharedData(data, type, numItems1, 0, numItems2, 0, numItems3, 0);\n    ospCommit(shared);\n    OSPData opaque = ospNewData(type, numItems1, numItems2, numItems3);\n    ospCommit(opaque);\n    ospCopyData(shared, opaque);\n    ospCommit(opaque);\n    ospRelease(shared);\n    return opaque;\n}\n\nOSPTexture VOSP::OSPDepthFromGLPerspective(float fovy, float aspect, float zNear, float zFar, glm::vec3 cameraDir, glm::vec3 cameraUp, const float *glDepthBuffer, int width, int height)\n{\n    float *ospDepth = new float[width * height];\n\n    // transform OpenGL depth to linear depth\n    for (size_t i = 0; i < width * height; i++) {\n        const double z_n = 2.0 * glDepthBuffer[i] - 1.0;\n        ospDepth[i] = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));\n    }\n\n    // transform from orthogonal Z depth to ray distance t\n    glm::vec3 dir_du = normalize(cross(cameraDir, cameraUp));\n    glm::vec3 dir_dv = normalize(cross(dir_du, cameraDir));\n\n    const float imagePlaneSizeY = 2.f * tanf(fovy / 2.f * M_PI / 180.f);\n    const float imagePlaneSizeX = imagePlaneSizeY * aspect;\n\n    dir_du *= imagePlaneSizeX;\n    dir_dv *= imagePlaneSizeY;\n\n    const glm::vec3 dir_00 = cameraDir - .5f * dir_du - .5f * dir_dv;\n\n    for (size_t j = 0; j < height; j++) {\n        for (size_t i = 0; i < width; i++) {\n            const glm::vec3 dir_ij = normalize(dir_00 + float(i) / float(width - 1) * dir_du + float(j) / float(height - 1) * dir_dv);\n\n            const float t = ospDepth[j * width + i] / dot(cameraDir, dir_ij);\n            ospDepth[j * width + i] = t;\n        }\n    }\n\n    OSPTexture depthTexture = ospNewTexture(\"texture2d\");\n    ospSetInt(depthTexture, \"format\", OSP_TEXTURE_R32F);\n    ospSetInt(depthTexture, \"filter\", OSP_TEXTURE_FILTER_NEAREST);\n\n    OSPData data = VOSP::NewCopiedData(ospDepth, OSP_FLOAT, width, height);\n    ospCommit(data);\n    ospSetObject(depthTexture, \"data\", data);\n    ospRelease(data);\n\n    delete[] ospDepth;\n\n    ospCommit(depthTexture);\n    return depthTexture;\n}\n\n// triangle mesh data\nnamespace TriData {\nfloat   translation[] = {0, 0, 0};\nfloat   vertex[] = {-1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f};\nfloat   color[] = {0.9f, 0.5f, 0.5f, 1.0f, 0.8f, 0.8f, 0.8f, 1.0f, 0.8f, 0.8f, 0.8f, 1.0f, 0.5f, 0.9f, 0.5f, 1.0f};\nint32_t index[] = {0, 1, 2, 1, 2, 3};\n}    // namespace TriData\n\nOSPGeometricModel Test::LoadTriangle(glm::vec3 scale, const std::string &rendererType)\n{\n    // Translate Triangle\n    float pos[4 * 3];\n    for (int i = 0; i < 4 * 3; i++) { pos[i] = TriData::vertex[i] * scale[i % 3] + TriData::translation[i % 3]; }\n\n    // create and setup model and mesh\n    OSPGeometry mesh = ospNewGeometry(\"mesh\");\n\n    OSPData data = NewCopiedData(pos, OSP_VEC3F, 4);\n    // alternatively with an OSPRay managed OSPData\n    // OSPData managed = ospNewData1D(OSP_VEC3F, 4);\n    // ospCopyData1D(data, managed, 0);\n\n    ospCommit(data);\n    ospSetObject(mesh, \"vertex.position\", data);\n    ospRelease(data);    // we are done using this handle\n\n    data = ospNewSharedData1D(TriData::color, OSP_VEC4F, 4);\n    ospCommit(data);\n    ospSetObject(mesh, \"vertex.color\", data);\n    ospRelease(data);\n\n    data = ospNewSharedData1D(TriData::index, OSP_VEC3UI, 2);\n    ospCommit(data);\n    ospSetObject(mesh, \"index\", data);\n    ospRelease(data);\n\n    ospCommit(mesh);\n\n    OSPMaterial mat = ospNewMaterial(rendererType.c_str(), \"obj\");\n    ospCommit(mat);\n\n    // put the mesh into a model\n    OSPGeometricModel model = ospNewGeometricModel(mesh);\n    ospSetObject(model, \"material\", mat);\n    ospCommit(model);\n    ospRelease(mesh);\n    ospRelease(mat);\n\n    return model;\n}\n\n#endif\n"
  },
  {
    "path": "lib/render/PNGWriter.cpp",
    "content": "#include \"vapor/PNGWriter.h\"\n#include \"vapor/VAssert.h\"\n\n#define USE_PYTHON_PNG 1\n\n#if USE_PYTHON_PNG\n    #include \"vapor/MyPython.h\"\n#else\n    #include <png.h>\n#endif\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nREGISTER_IMAGEWRITER(PNGWriter);\n\nstd::vector<std::string> PNGWriter::GetFileExtensions() { return {\"png\"}; }\n\nPNGWriter::PNGWriter(const string &path) : ImageWriter(path) {}\n\nint PNGWriter::Write(const unsigned char *buffer, const unsigned int width, const unsigned int height)\n{\n#if USE_PYTHON_PNG\n\n    VAssert(format == Format::RGB);\n\n    PyObject *pName, *pModule, *pFunc, *pArgs, *pValue;\n\n    int rc = Wasp::MyPython::Instance()->Initialize();\n    if (rc < 0) {\n        MyBase::SetErrMsg(\"Failed to initialize python : %s\", MyPython::Instance()->PyErr().c_str());\n        return (-1);\n    }\n\n    pName = PyUnicode_FromString(\"imagewriter\");\n    pModule = PyImport_Import(pName);\n\n    if (pModule == NULL) {\n        PyErr_Print();\n        MyBase::SetErrMsg(\"pModule (drawpng) NULL : %s\", MyPython::Instance()->PyErr().c_str());\n        return -1;\n    }\n    pFunc = PyObject_GetAttrString(pModule, \"drawpng\");\n    if (pFunc && PyCallable_Check(pFunc)) {\n        pArgs = PyTuple_New(4);\n\n        // The 1st argument: output filename\n        pValue = PyUnicode_FromString(path.c_str());\n        PyTuple_SetItem(pArgs, 0, pValue);\n\n        // The 2nd argument: width\n        pValue = PyLong_FromLong((long)width);\n        PyTuple_SetItem(pArgs, 1, pValue);\n\n        // The 3rd argument: height\n        pValue = PyLong_FromLong((long)height);\n        PyTuple_SetItem(pArgs, 2, pValue);\n\n        // The 4th argument: RGB buffer\n        long      nChars = width * height * 3;\n        PyObject *pListOfChars = PyList_New(nChars);\n        VAssert(pListOfChars);\n        for (long i = 0; i < nChars; i++) {\n            int rt = PyList_SetItem(pListOfChars, i, PyLong_FromLong((long)buffer[i]));\n            VAssert(rt == 0);\n        }\n        PyTuple_SetItem(pArgs, 3, pListOfChars);\n\n        // Call the python routine\n        pValue = PyObject_CallObject(pFunc, pArgs);\n        if (pValue == NULL) {\n            PyErr_Print();\n            MyBase::SetErrMsg(\"pFunc (drawpng) failed to execute : %s\", MyPython::Instance()->PyErr().c_str());\n            return -1;\n        }\n    } else {\n        PyErr_Print();\n        MyBase::SetErrMsg(\"pFunc (drawpng) NULL : %s\", MyPython::Instance()->PyErr().c_str());\n        return -1;\n    }\n\n    Py_XDECREF(pName);\n    Py_XDECREF(pArgs);\n    Py_XDECREF(pValue);\n    Py_XDECREF(pFunc);\n    Py_XDECREF(pModule);\n\n    return 0;\n#else\n    int         code = 0;\n    FILE *      fp = NULL;\n    png_structp png_ptr = NULL;\n    png_infop   info_ptr = NULL;\n    png_bytep   row = NULL;\n\n    fp = fopen(file, \"wb\");\n    if (!fp) return -1;\n\n    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);\n    if (png_ptr == NULL) VAssert(0);\n\n    info_ptr = png_create_info_struct(png_ptr);\n    if (info_ptr == NULL) VAssert(0);\n\n    png_init_io(png_ptr, fp);\n\n    png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);\n\n    png_write_info(png_ptr, info_ptr);\n\n    #error Functionality Not Finished\n\n    png_write_end(png_ptr, NULL);\n    if (fp) fclose(fp);\n    if (info_ptr) png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);\n    if (png_ptr) png_destroy_write_struct(&png_ptr, (png_infopp)NULL);\n\n    return 0;\n#endif\n}\n"
  },
  {
    "path": "lib/render/ParticleRenderer.cpp",
    "content": "//************************************************************************\n//                                                                       *\n//                          Copyright (C)  2018                          *\n//            University Corporation for Atmospheric Research            *\n//                          All Rights Reserved                          *\n//                                                                       *\n//************************************************************************/\n//\n//  File:   ParticleRenderer.cpp\n//\n//  Author: Stas Jaroszynski\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:   March 2018\n//\n//  Description:\n//          Implementation of ParticleRenderer\n//\n\n#include <sstream>\n#include <string>\n#include <iterator>\n\n#include <vapor/glutil.h>    // Must be included first!!!\n\n#include <vapor/Renderer.h>\n#include <vapor/ParticleRenderer.h>\n#include <vapor/ParticleParams.h>\n#include <vapor/regionparams.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/DataStatus.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/errorcodes.h>\n#include <vapor/ControlExecutive.h>\n#include \"vapor/ShaderManager.h\"\n#include \"vapor/debug.h\"\n#include <glm/glm.hpp>\n#include <glm/gtc/type_ptr.hpp>\n#include \"vapor/GLManager.h\"\n#include <vapor/LegacyGL.h>\n\nusing namespace VAPoR;\n\n#pragma pack(push, 4)\n// struct ParticleRenderer::VertexData {\n//    float x, y, z;\n//    float v;\n//};\n#pragma pack(pop)\n\nusing glm::vec3;\nstatic inline vec3 CoordTypeToVec3(const CoordType &c) { return vec3(c[0], c[1], c[2]); }\n\nstatic RendererRegistrar<ParticleRenderer> registrar(ParticleRenderer::GetClassType(), ParticleParams::GetClassType());\n\nParticleRenderer::ParticleRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, ParticleParams::GetClassType(), ParticleRenderer::GetClassType(), instName, dataMgr),\n  _colorMapTexOffset(0)\n{\n    _cacheParams.ts=0;\n    _cacheParams.rLevel=0;\n    _cacheParams.cLevel=0;\n    _cacheParams.stride=0;\n    _cacheParams.radius=8.0;\n    _cacheParams.direction=false;\n}\n\nParticleRenderer::~ParticleRenderer() {\n    if (_vertexArrayId) {\n        glDeleteVertexArrays(1, &_vertexArrayId);\n        _vertexArrayId = 0;\n    }\n    if (_vertexBufferId) {\n        glDeleteBuffers(1, &_vertexBufferId);\n        _vertexBufferId = 0;\n    }\n\n    if (_colorMapTexId) {\n        glDeleteTextures(1, &_colorMapTexId);\n        _colorMapTexId = 0;\n    }\n}\n\nint ParticleRenderer::_paintGL(bool)\n{\n#ifdef DEBUG\n    auto start = chrono::steady_clock::now();\n#endif\n\n    glDepthMask(true);\n    glEnable(GL_DEPTH_TEST);\n\n    bool regenerateParticles = false;\n    bool recomputeBaseRadius = false;\n\n    if (_particleBaseSizeIsDirty())\n        recomputeBaseRadius = true;\n\n    if (_particleCacheIsDirty()) {\n        _resetParticleCache();\n        regenerateParticles = true;\n    }\n\n    if (_colormapCacheIsDirty()) {\n        _resetColormapCache();\n        _prepareColormap();\n    }\n\n    Grid* grid = nullptr;\n    std::vector<Grid*> vecGrids;\n    int rc = _getGrids(grid, vecGrids);\n    if (rc != 0) {\n        SetErrMsg(\"Could not get scalar and field grids for ParticleRenderer\");\n        return rc;\n    }\n\n    bool renderLegacy = GetActiveParams()->GetValueLong(ParticleParams::RenderLegacyTag, false);\n    if (renderLegacy) {\n        _renderParticlesLegacy(grid, vecGrids);\n        _cacheParams.varName = \"\";\n    }\n    else {\n        if (regenerateParticles)\n            _generateTextureData(grid, vecGrids);\n        if (recomputeBaseRadius)\n            _computeBaseRadius();\n        _renderParticlesHelper();\n    }\n\n    _dataMgr->UnlockGrid(grid);\n    delete grid;\n    for (auto g : vecGrids) {\n        _dataMgr->UnlockGrid(g);\n        delete g;\n    }\n\n#ifdef DEBUG\n    auto end = chrono::steady_clock::now();\n    cout << \"Glyph time in milliseconds: \"\n        << chrono::duration_cast<chrono::milliseconds>(end - start).count()\n        << \" ms\" << endl;\n#endif\n    return 0;\n}\n\nint ParticleRenderer::_initializeGL() { \n    glGenVertexArrays(1, &_vertexArrayId);\n    glGenBuffers(1, &_vertexBufferId);\n\n    /* Generate and configure 1D texture: _colorMapTexId */\n    glGenTextures(1, &_colorMapTexId);\n    glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTexId);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glBindTexture(GL_TEXTURE_1D, 0);\n\n    glGenVertexArrays(1, &_VAO);\n    glGenBuffers(1, &_VBO);\n\n    assert(_VAO);\n    assert(_VBO);\n\n    return 0;\n}\n\nstatic void SetupParticlePointGL(const int VAO, const int VBO, const bool dynamicSize) {\n    glBindVertexArray(VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, VBO);\n    int elSize = sizeof(glm::vec4);\n    if (dynamicSize) elSize += sizeof(float);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, elSize, NULL);\n    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec3));\n    if (dynamicSize)\n        glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec4));\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n    if (dynamicSize)\n        glEnableVertexAttribArray(2);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nstatic void SetupParticleDirectionGL(const int VAO, const int VBO, const bool dynamicSize) {\n    glBindVertexArray(VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, VBO);\n    int elSize = sizeof(float)*7;\n    if (dynamicSize) elSize += sizeof(float);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, elSize, NULL);\n    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec3));\n    glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, elSize, (void *)(2*sizeof(glm::vec3)));\n    if (dynamicSize)\n        glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, elSize, (void *)(sizeof(float)*7));\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n    glEnableVertexAttribArray(2);\n    if (dynamicSize)\n        glEnableVertexAttribArray(3);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nbool ParticleRenderer::_particleBaseSizeIsDirty() const {\n    auto p = GetActiveParams();\n    if (p->GetValueLong(ParticleParams::RecalculateRadiusBaseRequestTag, false)) {\n        p->SetValueLong(ParticleParams::RecalculateRadiusBaseRequestTag, \"\", false);\n        return true;\n    }\n    if (_cacheParams.varName != p->GetVariableName()) return true;\n    if (_cacheParams.radiusVarName != p->GetValueString( ParticleParams::RenderRadiusVariableTag, \"\")) return true;\n    if (_cacheParams.stride    != p->GetValueLong( ParticleParams::StrideTag, 1)) return true;\n    return false;\n}\n\nbool ParticleRenderer::_particleCacheIsDirty() const {\n    auto p = GetActiveParams();\n\n    if (_cacheParams.ts        != p->GetCurrentTimestep()    ) return true;\n    if (_cacheParams.rLevel    != p->GetRefinementLevel()    ) return true;\n    if (_cacheParams.cLevel    != p->GetCompressionLevel()   ) return true;\n\n    VAPoR::CoordType min, max;\n    p->GetBox()->GetExtents(min, max);\n    if (_cacheParams.boxMin != min) return true;\n    if (_cacheParams.boxMax != max) return true;\n\n    if (_cacheParams.stride    != p->GetValueLong( ParticleParams::StrideTag, 1)) return true;\n    if (_cacheParams.varName   != p->GetVariableName()       ) return true;\n    if (_cacheParams.fieldVars != p->GetFieldVariableNames() ) return true;\n    if (_cacheParams.radiusVarName != p->GetValueString( ParticleParams::RenderRadiusVariableTag, \"\")) return true;\n    if (_cacheParams.direction != (bool)p->GetValueLong( ParticleParams::ShowDirectionTag, false)) return true;\n\n    return false;\n}\n\nvoid ParticleRenderer::_resetParticleCache() {\n    auto p = GetActiveParams();\n    _cacheParams.ts      = p->GetCurrentTimestep();\n    _cacheParams.rLevel  = p->GetRefinementLevel();\n    _cacheParams.cLevel  = p->GetCompressionLevel();\n\n    VAPoR::CoordType min, max;\n    p->GetBox()->GetExtents(min, max);\n    _cacheParams.boxMin = min;\n    _cacheParams.boxMax = max;\n   \n    _cacheParams.direction = (bool)p->GetValueLong(ParticleParams::ShowDirectionTag, false); \n    _cacheParams.stride = p->GetValueLong(ParticleParams::StrideTag, 1);\n    _cacheParams.varName = p->GetVariableName();\n    _cacheParams.fieldVars = p->GetFieldVariableNames();\n    _cacheParams.radiusVarName = p->GetValueString( ParticleParams::RenderRadiusVariableTag, \"\");\n}\n\nbool ParticleRenderer::_colormapCacheIsDirty() const {\n    auto p = GetActiveParams();\n    std::vector<float> tf_lut;\n    MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName);\n    tf->makeLut(tf_lut);\n    if (_cacheParams.tf_lut    != tf_lut)                  return true;\n    if (_cacheParams.tf_minMax != tf->getMinMaxMapValue()) return true;\n    return false;\n}\n\nvoid ParticleRenderer::_resetColormapCache() {\n    auto p = GetActiveParams();\n    MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName);\n    std::vector<float> tf_lut;\n    tf->makeLut(tf_lut);\n    std::vector<double> minMax = tf->getMinMaxMapValue();\n    _cacheParams.tf_lut    = tf_lut;\n    _cacheParams.tf_minMax = minMax;\n}\n\nint ParticleRenderer::_renderParticlesHelper()\n{\n    auto rp = GetActiveParams();\n    float radiusBase = rp->GetValueDouble(ParticleParams::RenderRadiusBaseTag, -1);\n    float radius = radiusBase * rp->GetValueDouble(ParticleParams::RenderRadiusScalarTag, 1.);\n\n    string shaderKey;\n    if (_cacheParams.direction)\n        shaderKey = \"ParticleDirection\";\n    else\n        shaderKey = \"ParticlePoint\";\n\n    if (!_cacheParams.radiusVarName.empty())\n        shaderKey += \":DYNAMIC_RADIUS\";\n\n    ShaderProgram *shader = _glManager->shaderManager->GetShader(shaderKey);\n    if (!shader) return -1;\n\n    double m[16];\n    double cameraPosD[3], cameraUpD[3], cameraDirD[3];\n    _paramsMgr->GetViewpointParams(_winName)->GetModelViewMatrix(m);\n    _paramsMgr->GetViewpointParams(_winName)->ReconstructCamera(m, cameraPosD, cameraUpD, cameraDirD);\n    glm::vec3 cameraDir = glm::vec3(cameraDirD[0], cameraDirD[1], cameraDirD[2]);\n    glm::vec3 cameraPos = glm::vec3(cameraPosD[0], cameraPosD[1], cameraPosD[2]);\n\n    shader->Bind();\n    shader->SetUniform(\"P\", _glManager->matrixManager->GetProjectionMatrix());\n    shader->SetUniform(\"MV\", _glManager->matrixManager->GetModelViewMatrix());\n    shader->SetUniform(\"aspect\", _glManager->matrixManager->GetProjectionAspectRatio());\n    shader->SetUniform(\"radius\", radius);\n    shader->SetUniform(\"dirScale\", (float)rp->GetValueDouble(ParticleParams::DirectionScaleTag, 1.));\n    shader->SetUniform(\"lightingEnabled\", (bool)rp->GetValueLong(ParticleParams::LightingEnabledTag, true));\n    shader->SetUniform(\"scales\", _getScales());\n    shader->SetUniform(\"cameraPos\", cameraPos);\n    shader->SetUniform(\"lightDir\", cameraDir);\n    shader->SetUniform(\"phongAmbient\", (float)rp->GetValueDouble(ParticleParams::PhongAmbientTag, 0.4));\n    shader->SetUniform(\"phongDiffuse\", (float)rp->GetValueDouble(ParticleParams::PhongDiffuseTag, 0.8));\n    shader->SetUniform(\"phongSpecular\", (float)rp->GetValueDouble(ParticleParams::PhongSpecularTag, 0.0));\n    shader->SetUniform(\"phongShininess\", (float)(100 * powf(rp->GetValueDouble(ParticleParams::PhongShininessTag, 0.01), 2)));\n\n    shader->SetUniform(\"mapRange\", glm::make_vec2(_colorMapRange));\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTexId);\n    shader->SetUniform(\"LUT\", 0);\n\n    glEnable(GL_CULL_FACE);\n    glFrontFace(GL_CCW);\n    glEnable(GL_BLEND);\n    glBindVertexArray(_VAO);\n\n    glDrawArrays(GL_POINTS, 0, _particlesCount);\n    GL_ERR_BREAK();\n\n    glDepthMask(GL_TRUE);\n    glDisable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBindVertexArray(0);\n    glDisable(GL_CULL_FACE);\n    shader->UnBind();\n    DisableClippingPlanes();\n\n    return 0;\n}\n\nint ParticleRenderer::_getGrids(Grid*& grid, std::vector<Grid*>& vecGrids) const {\n#define PD3(v) printf(\"%s = %f, %f, %f\\n\", #v, v[0], v[1], v[2])\n    string varName = _cacheParams.varName;\n    grid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.varName, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, true);\n    if (!grid) {\n        SetErrMsg(\"Cannot acquire grid for variable \\\"%s\\\"\", _cacheParams.varName.c_str());\n        return -1;\n    }\n\n    vector<string> vecNames = _cacheParams.fieldVars;\n    vector<string> mainVarCoords;\n    _dataMgr->GetVarCoordVars(_cacheParams.varName, true, mainVarCoords);\n\n    if (_cacheParams.direction) {\n        for (auto var : vecNames) {\n            vector<string> varCoords;\n            _dataMgr->GetVarCoordVars(var, true, varCoords);\n\n            if (mainVarCoords != varCoords) {\n                if (grid) {\n                    _dataMgr->UnlockGrid(grid);\n                    delete grid;\n                }\n                for (auto g : vecGrids) {\n                    _dataMgr->UnlockGrid(g);\n                    delete g;\n                }\n                SetErrMsg(\"Variable \\\"%s\\\" on different grid from main variable\", var.c_str());\n                return -1;\n            }\n\n            Grid *ng = _dataMgr->GetVariable(_cacheParams.ts, var, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, true);\n            if (!ng) {\n                if (grid) {\n                    _dataMgr->UnlockGrid(grid);\n                    delete grid;\n                }\n                for (auto g : vecGrids) {\n                    _dataMgr->UnlockGrid(g);\n                    delete g;\n                }\n                SetErrMsg(\"Cannot read var \\\"%s\\\"\", var.c_str());\n                return -1;\n            }\n            vecGrids.push_back(ng);\n        }\n    }\n\n    if (!_cacheParams.radiusVarName.empty()) {\n        vecGrids.push_back(_dataMgr->GetVariable(_cacheParams.ts, _cacheParams.radiusVarName, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, true));\n    }\n\n    return 0;\n}\n\ntemplate<typename T> void ParticleRenderer::UploadDataBuffer(vector<T> buffer) {\n    glBufferData(GL_ARRAY_BUFFER, sizeof(T) * buffer.size(), buffer.data(), GL_STATIC_DRAW);\n    _particlesCount = buffer.size();\n}\n\nvoid ParticleRenderer::_generateTextureData(const Grid* grid, const std::vector<Grid*>& vecGrids) {\n    bool      showDir = _cacheParams.direction;\n    bool      dynamicSize = !_cacheParams.radiusVarName.empty();\n    size_t    stride = max(1L, (long)_cacheParams.stride);\n    auto      node = grid->ConstNodeBegin(_cacheParams.boxMin, _cacheParams.boxMax);\n    auto      nodeEnd = grid->ConstNodeEnd();\n    CoordType coordsBuf;\n\n    struct PointDataT {vec3 pos; float val;}; vector<PointDataT> pointData;\n    struct DirectionDataT {vec3 pos; vec3 norm; float val;}; vector<DirectionDataT> directionData;\n    struct PointDynSizeDataT {vec3 pos; float val; float radius;}; vector<PointDynSizeDataT> pointDynSizeData;\n    struct DirectionDynSizeDataT {vec3 pos; vec3 norm; float val; float radius;}; vector<DirectionDynSizeDataT> directionDynSizeData;\n\n    if (showDir) {\n        SetupParticleDirectionGL(_VAO, _VBO, dynamicSize);\n        directionData.reserve(grid->GetDimensions()[0]/stride+1);\n    } else {\n        SetupParticlePointGL(_VAO, _VBO, dynamicSize);\n        pointData.reserve(grid->GetDimensions()[0]/stride+1);\n    }\n    assert(glIsVertexArray(_VAO) == GL_TRUE);\n    assert(glIsBuffer(_VBO) == GL_TRUE);\n\n    for (size_t i = 0; node != nodeEnd;) {\n        if (i % stride) goto step;\n        {\n            const float value = grid->GetValueAtIndex(*node);\n            grid->GetUserCoordinates(*node, coordsBuf);\n            const vec3 p = CoordTypeToVec3(coordsBuf);\n\n            if (showDir){\n                const glm::vec3 norm(\n                    vecGrids[0]->GetValueAtIndex(*node),\n                    vecGrids[1]->GetValueAtIndex(*node),\n                    vecGrids[2]->GetValueAtIndex(*node)\n                );\n                if (dynamicSize)\n                    directionDynSizeData.push_back({p, norm, value, vecGrids[vecGrids.size()-1]->GetValueAtIndex(*node)});\n                else\n                    directionData.push_back({p, norm, value});\n            } else {\n                if (dynamicSize)\n//                    pointDynSizeData.push_back({p, value, *(dirs[dirs.size()-1])});\n                    pointDynSizeData.push_back({p, value, vecGrids[vecGrids.size()-1]->GetValueAtIndex(*node)});\n\n                else\n                    pointData.push_back({p, value});\n            }\n        }\n        step:\n        ++node, ++i;\n    }\n\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    if (dynamicSize) {\n        if (showDir) UploadDataBuffer(directionDynSizeData);\n        else UploadDataBuffer(pointDynSizeData);\n    } else {\n        if (showDir) UploadDataBuffer(directionData);\n        else UploadDataBuffer(pointData);\n    }\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n}\n\nvoid ParticleRenderer::_computeBaseRadius() {\n    auto rp = GetActiveParams();\n    CoordType mind, maxd;\n\n    // Need to find a non-empty variable from color mapping or velocity variables.\n    std::string nonEmptyVarName = rp->GetColorMapVariableName();\n    assert(!nonEmptyVarName.empty());\n\n    _dataMgr->GetVariableExtents(_cacheParams.ts, nonEmptyVarName, _cacheParams.rLevel, _cacheParams.cLevel, mind, maxd);\n    glm::vec3  min(mind[0], mind[1], mind[2]);\n    glm::vec3  max(maxd[0], maxd[1], maxd[2]);\n    glm::vec3  lens = max - min;\n    float largestDim = glm::max(lens.x, glm::max(lens.y, lens.z));\n    float radiusBase = largestDim / 560.f;\n\n    if (!_cacheParams.radiusVarName.empty()) {\n        vector<double> dataRange;\n        _dataMgr->GetDataRange(_cacheParams.ts, _cacheParams.radiusVarName, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, dataRange);\n        radiusBase /= (dataRange[0]+dataRange[1])/2;\n    }\n\n    rp->SetValueDouble(ParticleParams::RenderRadiusBaseTag, \"\", radiusBase);\n}\n\nvoid ParticleRenderer::_renderParticlesLegacy(const Grid* grid, const std::vector<Grid*>& vecGrids) const {\n    auto p = GetActiveParams();\n    MapperFunction* mf = p->GetMapperFunc(p->GetVariableName());\n    float LUT[256*4];\n    mf->makeLut(LUT);\n\n    float mapMin = mf->getMinMapValue();\n    float mapMax = mf->getMaxMapValue();\n    float mapDif = mapMax - mapMin;\n    bool  showDir = _cacheParams.direction;\n\n    LegacyGL* lgl = _glManager->legacy;\n    glDepthMask(true);\n    glEnable(GL_DEPTH_TEST);\n    lgl->Color3f(1, 1, 1);\n    lgl->Begin(showDir ? GL_LINES : GL_POINTS);\n\n    auto      node = grid->ConstNodeBegin(_cacheParams.boxMin, _cacheParams.boxMax);\n    auto      nodeEnd = grid->ConstNodeEnd();\n    CoordType coordsBuf;\n    vector<Grid::ConstIterator> dirs;\n    for (auto g : vecGrids) dirs.push_back(g->cbegin(_cacheParams.boxMin, _cacheParams.boxMax));\n\n    size_t stride = max(1L, (long)_cacheParams.stride);\n    float  dirScale = p->GetValueDouble(ParticleParams::DirectionScaleTag, 1.);\n\n    for (size_t i = 0; node != nodeEnd; ++node, ++i) {\n        if (i % stride) {\n            if (showDir)\n                for (auto &it : dirs) ++it;\n            continue;\n        }\n\n        const float value = grid->GetValueAtIndex(*node);\n        grid->GetUserCoordinates(*node, coordsBuf);\n        const glm::vec3 p(coordsBuf[0], coordsBuf[1], coordsBuf[2]);\n\n        lgl->Color4fv(&LUT[4 * glm::clamp((int)(255 * (value - mapMin) / mapDif), 0, 255)]);\n        lgl->Vertex3fv((float *)&p);\n\n        if (showDir) {\n            const glm::vec3 n(*(dirs[0]), *(dirs[1]), *(dirs[2]));\n            const glm::vec3 p2 = p + n * dirScale;\n            lgl->Vertex3fv((float *)&p2);\n\n            for (auto &it : dirs) ++it;\n        }\n    }\n    lgl->End();\n}\n\nvoid ParticleRenderer::_prepareColormap() {\n    assert(_cacheParams.tf_lut.size() % 4 == 0);\n    _colorMapRange[0] = _cacheParams.tf_minMax[0];\n    _colorMapRange[1] = _cacheParams.tf_minMax[1];\n    _colorMapRange[2] = (_colorMapRange[1] - _colorMapRange[0]) > 1e-5f ? (_colorMapRange[1] - _colorMapRange[0]) : 1e-5f;\n    glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTexId);\n    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, _cacheParams.tf_lut.size() / 4, 0, GL_RGBA, GL_FLOAT, _cacheParams.tf_lut.data());\n}\n\nglm::vec3 ParticleRenderer::_getScales() {\n    string                  myVisName = GetVisualizer();  // This is the line that's not const\n    VAPoR::ViewpointParams *vpp = _paramsMgr->GetViewpointParams(myVisName);\n    string                  datasetName = GetMyDatasetName();\n    Transform *             tDataset = vpp->GetTransform(datasetName);\n    Transform *             tRenderer = GetActiveParams()->GetTransform();\n\n    vector<double> scales = tDataset->GetScales();\n    vector<double> rendererScales = tRenderer->GetScales();\n\n    scales[0] *= rendererScales[0];\n    scales[1] *= rendererScales[1];\n    scales[2] *= rendererScales[2];\n\n    return glm::vec3(scales[0], scales[1], scales[2]);\n}\n"
  },
  {
    "path": "lib/render/Proj4StringParser.cpp",
    "content": "#include \"vapor/Proj4StringParser.h\"\n#ifdef WIN32\n    #include <geotiff/geotiffio.h>\n#else\n    #include <geotiffio.h>\n#endif\n\nusing namespace VAPoR;\nusing std::map;\nusing std::pair;\nusing std::string;\n\nProj4StringParser::Proj4StringParser(const std::string &projString) : _string(projString), _tokens(Proj4StringToParameterMap(projString)) {}\n\npair<string, string> Proj4StringParser::Proj4ParameterToKeyValuePair(string proj)\n{\n    if (proj[0] != '+') { return pair<string, string>(\"NULL\", \"NULL\"); }\n    proj = proj.substr(1);\n    string key = proj.substr(0, proj.find(\"=\"));\n    string value = proj.substr(proj.find(\"=\") + 1);\n    return pair<string, string>(key, value);\n}\n\nmap<string, string> Proj4StringParser::Proj4StringToParameterMap(string proj)\n{\n    const string        delimeter = \" \";\n    size_t              index;\n    string              token;\n    map<string, string> tokens;\n    while ((index = proj.find(delimeter)) != string::npos) {\n        token = proj.substr(0, index);\n        proj.erase(0, index + delimeter.length());\n        tokens.insert(Proj4ParameterToKeyValuePair(token));\n    }\n    tokens.insert(Proj4ParameterToKeyValuePair(proj));\n    return tokens;\n}\n\nbool Proj4StringParser::HasKey(const std::string &key) const { return _tokens.find(key) != _tokens.end(); }\n\nstd::string Proj4StringParser::GetString(const std::string &key, const std::string &defaultValue) const\n{\n    auto it = _tokens.find(key);\n    if (it == _tokens.end()) return defaultValue;\n    return it->second;\n}\n\ndouble Proj4StringParser::GetDouble(const std::string &key, const double defaultValue) const\n{\n    auto it = _tokens.find(key);\n    if (it == _tokens.end()) return defaultValue;\n    return std::stod(it->second);\n}\n\nint Proj4StringParser::Proj4EllipseStringToGeoTIFEnum(const std::string &proj)\n{\n    if (0)\n        ;\n    else if (proj == \"NWL9D\")\n        return Ellipse_NWL_9D;\n    else if (proj == \"WGS84\")\n        return Ellipse_WGS_84;\n    else if (proj == \"airy\")\n        return Ellipse_Airy_1830;\n    else if (proj == \"bess_nam\")\n        return Ellipse_Bessel_Namibia;\n    else if (proj == \"bessel\")\n        return Ellipse_Bessel_1841;\n    else if (proj == \"clrk66\")\n        return Ellipse_Clarke_1866;\n    else if (proj == \"clrk80\")\n        return Ellipse_Clarke_1880;\n    else if (proj == \"clrk80ign\")\n        return Ellipse_Clarke_1880_IGN;\n    else if (proj == \"helmert\")\n        return Ellipse_Helmert_1906;\n    else if (proj == \"krass\")\n        return Ellipse_Krassowsky_1940;\n    else if (proj == \"plessis\")\n        return Ellipse_Plessis_1817;\n    else if (proj == \"sphere\")\n        return Ellipse_Sphere;\n    SetErrMsg(\"Unsupported Proj4 ellipse parameter \\\"%s\\\"\", proj.c_str());\n    return -1;\n}\n"
  },
  {
    "path": "lib/render/PyEngine.cpp",
    "content": "#include <iostream>\n#include <sstream>\n#include <vector>\n#include <map>\n#include <new>\n#include <vapor/utils.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/PyEngine.h>\n#include <vapor/XmlNode.h>\nusing namespace Wasp;\nusing namespace VAPoR;\n\n#define NPY_NO_DEPRECATED_API NPY_API_VERSION\n#include <numpy/arrayobject.h>\n\nnamespace {\n\nstruct varinfo_t {\n    varinfo_t()\n    {\n        _g = NULL;\n        _name.clear();\n        _dims = {1, 1, 1};\n        _coordNames.clear();\n        _coordAxes.clear();\n        _coordDims.clear();\n    }\n\n    Grid *                 _g;\n    string                 _name;\n    DimsType               _dims;\n    vector<string>         _coordNames;\n    vector<int>            _coordAxes;\n    vector<DimsType>       _coordDims;\n};\n\nvoid free_arrays(vector<float *> &arrays)\n{\n    for (int i = 0; i < arrays.size(); i++) {\n        if (arrays[i]) { delete[] arrays[i]; }\n    }\n}\n\nvoid free_arrays(vector<float *> &inputVarArrays, vector<float *> &outputVarArrays)\n{\n    free_arrays(inputVarArrays);\n    free_arrays(outputVarArrays);\n}\n\nint alloc_arrays(const vector<DimsType> &dimsVectors, vector<float *> &arrays)\n{\n    arrays.clear();\n\n    for (int i = 0; i < dimsVectors.size(); i++) {\n        size_t nElements = VProduct(dimsVectors[i].data(), dimsVectors[i].size());\n\n        float *buf = new (nothrow) float[nElements];\n        if (!buf) {\n            free_arrays(arrays);\n            return (-1);\n        }\n        arrays.push_back(buf);\n    }\n\n    return (0);\n}\n\nint alloc_arrays(const vector<DimsType> &inputVarDims, const vector<DimsType> &outputVarDims, vector<float *> &inputVarArrays, vector<float *> &outputVarArrays)\n{\n    inputVarArrays.clear();\n    outputVarArrays.clear();\n\n    int rc = alloc_arrays(inputVarDims, inputVarArrays);\n    if (rc < 0) return (rc);\n\n    rc = alloc_arrays(outputVarDims, outputVarArrays);\n    if (rc < 0) {\n        free_arrays(inputVarArrays);\n        return (rc);\n    }\n\n    return (0);\n}\n\nvoid copy_region(const float *src, float *dst, const DimsType &min, const DimsType &max, const DimsType &dims)\n{\n    DimsType coord = min;\n    for (size_t i = 0; i < VProduct(Grid::Dims(min, max).data(), min.size()); i++) {\n        size_t offset = LinearizeCoords(coord.data(), dims.data(), coord.size());\n\n        dst[i] = src[offset];\n\n        IncrementCoords(min.data(), max.data(), coord.data(), min.size(), 0);\n    }\n}\n\nvoid copy_coord(const Grid *g, int axis, float *dst)\n{\n    DimsType dims = g->GetCoordDimensions(axis);\n\n    DimsType min = {0, 0, 0};\n    DimsType max = {dims[0] - 1, dims[1] - 1, dims[2] - 1};\n\n    // Fetch user coordinates from grid. Note: assumes that if coordinate\n    // dimensions are less than grid dimensions than the coordinate\n\n    DimsType  index = min;\n    CoordType coord;\n    for (size_t i = 0; i < VProduct(Grid::Dims(min, max).data(), min.size()); i++) {\n        g->GetUserCoordinates(index, coord);\n        dst[i] = coord[axis];\n\n        IncrementCoords(min.data(), max.data(), index.data(), index.size(), 0);\n    }\n}\n\nvoid grid2c(const vector<varinfo_t> &varInfoVec, const vector<float *> &inputVarArrays)\n{\n    int idx = 0;\n    for (int i = 0; i < varInfoVec.size(); i++) {\n        const varinfo_t &vref = varInfoVec[i];\n\n        Grid *g = vref._g;\n\n        Grid::ConstIterator itr = g->cbegin();\n        Grid::ConstIterator enditr = g->cend();\n\n        VAssert(idx < inputVarArrays.size());\n        float *bufptr = inputVarArrays[idx];\n\n        // Copy data. Missing values are always set to infinity for\n        // easier Python handling\n        //\n        float mv = g->GetMissingValue();\n        for (; itr != enditr; ++itr) {\n            if (g->HasMissingData() && *itr == mv) {\n                *bufptr = std::numeric_limits<double>::infinity();\n            } else {\n                *bufptr = *itr;\n            }\n            bufptr++;\n        }\n\n        idx++;\n        for (int j = 0; j < vref._coordNames.size(); j++) {\n            VAssert(idx < inputVarArrays.size());\n            float *bufptr = inputVarArrays[idx];\n\n            copy_coord(g, vref._coordAxes[j], bufptr);\n\n            idx++;\n        }\n    }\n}\n\nvoid get_var_info(DataMgr *dataMgr, const vector<Grid *> &gs, const vector<string> &varNames, bool coordFlag, vector<varinfo_t> &varinfoVec)\n{\n    varinfoVec.clear();\n\n    VAssert(gs.size() == varNames.size());\n\n    // Need to keep track of all coordinate variables. We generate a\n    // unique list\n    //\n    vector<string> allCoordVars;\n\n    // Build a vector of grids and *unique* coordinate variables\n    //\n    for (int i = 0; i < gs.size(); i++) {\n        varinfo_t varinfo;\n        varinfo._g = gs[i];\n        varinfo._name = varNames[i];\n        varinfo._dims = gs[i]->GetDimensions();\n\n        varinfo._coordNames.clear();\n        varinfo._coordAxes.clear();\n        varinfo._coordDims.clear();\n\n        if (!coordFlag) {\n            varinfoVec.push_back(varinfo);\n            continue;\n        }\n\n        DC::DataVar dvar;\n        bool        ok = dataMgr->GetDataVarInfo(varNames[i], dvar);\n        VAssert(ok);\n\n        DC::Mesh m;\n        ok = dataMgr->GetMesh(dvar.GetMeshName(), m);\n        VAssert(ok);\n\n        vector<string> coordNames = m.GetCoordVars();\n        for (int j = 0; j < coordNames.size(); j++) {\n            vector<string>::iterator itr;\n            itr = find(allCoordVars.begin(), allCoordVars.end(), coordNames[j]);\n\n            if (itr != allCoordVars.end()) continue;\n\n            DC::CoordVar cvar;\n            ok = dataMgr->GetCoordVarInfo(coordNames[j], cvar);\n            VAssert(ok);\n\n            varinfo._coordNames.push_back(coordNames[j]);\n            varinfo._coordAxes.push_back(cvar.GetAxis());\n            varinfo._coordDims.push_back(gs[i]->GetCoordDimensions(cvar.GetAxis()));\n        }\n        varinfoVec.push_back(varinfo);\n    }\n}\n\n// Remove trailing, degenerate unit dimensions\n//\nsize_t number_of_dims(DimsType dims)\n{\n    size_t n = dims.size();\n    while (n > 1 && dims[n - 1] <= 1) n--;\n\n    return (n);\n}\n\n};    // namespace\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nint PyEngine::Initialize()\n{\n    int rc = MyPython::Instance()->Initialize();\n    if (rc < 0) return (rc);\n\n    // Secret numpy incantation required to use NumPy's C API. Hope this\n    // crap works.\n    //\n#ifndef DISABLE_EXTRA_PYTHON_MATH_IMPORTS\n    if (PyArray_API == NULL) { import_array1(-1) }\n#else\n    fprintf(stderr, \"WARNING Vapor python array import disabled\\n\");\n#endif\n\n    return (0);\n}\n\nint PyEngine::AddFunction(string name, string script, const vector<string> &inputVarNames, const vector<string> &outputVarNames, const vector<string> &outputVarMeshes, bool coordFlag)\n{\n    VAssert(outputVarNames.size() == outputVarMeshes.size());\n\n    // cout << \"PyEngine::AddFunction() \" << name << endl;\n    // cout << \"\t\" << script << endl;\n\n    // No-op if not defined\n    //\n    RemoveFunction(name);\n\n    // Output variables can't already be defined (either derived or native vars)\n    //\n    if (_checkOutVars(outputVarNames) < 0) return (-1);\n\n    // Mesh name must be defined\n    //\n    if (_checkOutMeshes(outputVarMeshes) < 0) return (-1);\n\n    // Test the script syntatical correctness. Only way to do this\n    // with crappy Python API is to compile the string to an\n    // object :-(\n    //\n    PyObject *retObj = Py_CompileString(script.c_str(), \"\", Py_file_input);\n    if (!retObj) {\n        SetErrMsg(\"Py_CompileString() : %s\", MyPython::Instance()->PyErr().c_str());\n        return -1;\n    }\n    Py_DECREF(retObj);\n\n    const string timeCoordVarName = _getTimeCoordVarName(inputVarNames);\n\n    vector<DerivedPythonVar *> dvars;\n    for (int i = 0; i < outputVarNames.size(); i++) {\n        string            vname = outputVarNames[i];\n        DerivedPythonVar *dvar = new DerivedPythonVar(vname, \"\", DC::XType::FLOAT, outputVarMeshes[i], timeCoordVarName, true, inputVarNames, script, _dataMgr, coordFlag);\n        dvars.push_back(dvar);\n\n        if (dvar->Initialize() < 0) {\n            for (int i = 0; i < dvars.size(); i++) delete dvars[i];\n            SetErrMsg(\"Failed to initialized derived variable %s\", vname.c_str());\n            return (-1);\n        }\n        (void)_dataMgr->AddDerivedVar(dvar);\n    }\n\n    _functions[name] = func_c(name, script, inputVarNames, outputVarNames, outputVarMeshes, dvars, coordFlag);\n\n    return (0);\n}\n\nvoid PyEngine::RemoveFunction(string name)\n{\n    map<string, func_c>::iterator itr = _functions.find(name);\n\n    if (itr == _functions.end()) return;\n\n    const func_c &                    func = itr->second;\n    const vector<string> &            outputVarNames = func._outputVarNames;\n    const vector<DerivedPythonVar *> &dvars = func._derivedVars;\n    VAssert(outputVarNames.size() == dvars.size());\n\n    for (int i = 0; i < outputVarNames.size(); i++) {\n        _dataMgr->RemoveDerivedVar(outputVarNames[i]);\n        if (dvars[i]) delete dvars[i];\n    }\n\n    _functions.erase(itr);\n}\n\nvector<string> PyEngine::GetFunctionNames() const\n{\n    map<string, func_c>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _functions.cbegin(); itr != _functions.cend(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nstring PyEngine::GetFunctionScript(string name) const\n{\n    map<string, func_c>::const_iterator itr = _functions.find(name);\n\n    if (itr == _functions.cend()) return (\"\");\n\n    const func_c &func = itr->second;\n\n    return (func._script);\n}\n\nbool PyEngine::GetFunctionScript(string name, string &script, std::vector<string> &inputVarNames, std::vector<string> &outputVarNames, std::vector<string> &outputMeshNames, bool &coordFlag) const\n{\n    script.clear();\n    inputVarNames.clear();\n    outputVarNames.clear();\n    outputMeshNames.clear();\n\n    map<string, func_c>::const_iterator itr = _functions.find(name);\n\n    if (itr == _functions.cend()) return (false);\n\n    const func_c &func = itr->second;\n\n    script = func._script;\n    inputVarNames = func._inputVarNames;\n    outputVarNames = func._outputVarNames;\n    outputMeshNames = func._outputMeshNames;\n    coordFlag = func._coordFlag;\n\n    return (true);\n}\n\nstring PyEngine::GetFunctionStdout(string name) const\n{\n    map<string, func_c>::const_iterator itr = _functions.find(name);\n\n    if (itr == _functions.cend()) return (\"\");\n    const func_c &func = itr->second;\n\n    string s;\n    for (int i = 0; i < func._derivedVars.size(); i++) { s += func._derivedVars[i]->GetScriptStdout(); }\n    return (s);\n}\n\nPyEngine::~PyEngine()\n{\n    map<string, func_c>::iterator itr;\n    while ((itr = _functions.begin()) != _functions.end()) { RemoveFunction(itr->first); }\n}\n\nint PyEngine::Calculate(const string &script, vector<string> inputVarNames, vector<DimsType> inputVarDims, vector<float *> inputVarArrays, vector<string> outputVarNames,\n                        vector<DimsType> outputVarDims, vector<float *> outputVarArrays)\n{\n    VAssert(inputVarNames.size() == inputVarDims.size());\n    VAssert(inputVarNames.size() == inputVarArrays.size());\n    VAssert(outputVarNames.size() == outputVarDims.size());\n    VAssert(outputVarNames.size() == outputVarArrays.size());\n\n    vector<string> allNames = inputVarNames;\n    allNames.insert(allNames.end(), outputVarNames.begin(), outputVarNames.end());\n\n    // cout << \"PyEngine::Calculate() \" << script << endl;\n\n    // Convert the input arrays and put into dictionary:\n    //\n    PyObject *mainModule = PyImport_AddModule(\"__main__\");\n    if (!mainModule) {\n        SetErrMsg(\"PyImport_AddModule(\\\"__main__\\\") : %s\", MyPython::Instance()->PyErr().c_str());\n        return -1;\n    }\n\n    PyObject *mainDict = PyModule_GetDict(mainModule);\n    VAssert(mainDict != NULL);\n\n    // Copy arrays into python environment\n    //\n    int rc = _c2python(mainDict, inputVarNames, inputVarDims, inputVarArrays);\n    if (rc < 0) {\n        _cleanupDict(mainDict, inputVarNames);\n        return (-1);\n    }\n\n    // Run the script\n    //\n    PyObject *retObj = PyRun_String(script.c_str(), Py_file_input, mainDict, mainDict);\n\n    if (!retObj) {\n        SetErrMsg(\"PyRun_String() : %s\", MyPython::Instance()->PyErr().c_str());\n        _cleanupDict(mainDict, inputVarNames);\n        return -1;\n    }\n\n    // Retrieve calculated arrays from python environment\n    //\n    rc = _python2c(mainDict, outputVarNames, outputVarDims, outputVarArrays);\n    if (rc < 0) {\n        _cleanupDict(mainDict, allNames);\n        return (-1);\n    }\n\n    _cleanupDict(mainDict, allNames);\n\n    return (0);\n}\n\nvoid PyEngine::_cleanupDict(PyObject *mainDict, vector<string> keynames)\n{\n    for (int i = 0; i < keynames.size(); i++) {\n        PyObject *key = PyUnicode_FromString(keynames[i].c_str());\n        if (!key) continue;\n        if (PyDict_Contains(mainDict, key)) { PyObject_DelItem(mainDict, key); }\n        Py_DECREF(key);\n    }\n}\n\nint PyEngine::_c2python(PyObject *dict, vector<string> inputVarNames, vector<DimsType> inputVarDims, vector<float *> inputVarArrays)\n{\n    npy_intp pyDims[3] = {1, 1, 1};\n    for (int i = 0; i < inputVarNames.size(); i++) {\n        const DimsType &dims = inputVarDims[i];\n        for (int j = 0; j < number_of_dims(dims); j++) { pyDims[number_of_dims(dims) - j - 1] = dims[j]; }\n\n        PyObject *pyArray = PyArray_SimpleNewFromData(number_of_dims(dims), pyDims, NPY_FLOAT32, inputVarArrays[i]);\n\n        PyObject *ky = Py_BuildValue(\"s\", inputVarNames[i].c_str());\n        PyObject_SetItem(dict, ky, pyArray);\n        Py_DECREF(ky);\n        Py_DECREF(pyArray);\n    }\n\n    return (0);\n}\n\nint PyEngine::_python2c(PyObject *dict, vector<string> outputVarNames, vector<DimsType> outputVarDims, vector<float *> outputVarArrays)\n{\n    for (int i = 0; i < outputVarNames.size(); i++) {\n        const string &vname = outputVarNames[i];\n\n        PyObject *ky = Py_BuildValue(\"s\", vname.c_str());\n\n        PyObject *o = PyDict_GetItem(dict, ky);\n        if (!o || !PyArray_CheckExact(o)) {\n            SetErrMsg(\"Output variable named %s, of type numpy.ndarray expected, but not produced by script\", vname.c_str());\n            return -1;\n        }\n        PyArrayObject *varArray = (PyArrayObject *)o;\n\n        if (PyArray_TYPE(varArray) != NPY_FLOAT) {\n            ;\n            SetErrMsg(\"Variable %s is not of type float32\", vname.c_str());\n            return -1;\n        }\n\n        const DimsType &      dims = outputVarDims[i];\n        int                   nd = PyArray_NDIM(varArray);\n\n        if (nd != number_of_dims(dims)) {\n            SetErrMsg(\"Shape of %s array does not match\", vname.c_str());\n            return -1;\n        }\n\n        npy_intp *pyDims = PyArray_DIMS(varArray);\n        for (int j = 0; j < nd; j++) {\n            if (pyDims[number_of_dims(dims) - j - 1] != dims[j]) {\n                SetErrMsg(\"Shape of %s array does not match\", vname.c_str());\n                return -1;\n            }\n        }\n\n        float *dataArray = (float *)PyArray_DATA(varArray);\n        size_t nelements = VProduct(dims.data(), dims.size());\n\n        float *outArray = outputVarArrays[i];\n        for (size_t j = 0; j < nelements; j++) { outArray[j] = dataArray[j]; }\n    }\n\n    return (0);\n}\n\nPyEngine::DerivedPythonVar::DerivedPythonVar(string varName, string units, DC::XType type, string mesh, string time_coord_var, bool hasMissing, std::vector<string> inNames, string script,\n                                             DataMgr *dataMgr, bool coordFlag)\n: DerivedDataVar(varName), _varInfo(varName, units, type, \"\", std::vector<size_t>(), std::vector<bool>(), mesh, time_coord_var, DC::Mesh::NODE)\n{\n    _inNames = inNames;\n    _script = script;\n    _dataMgr = dataMgr;\n    _coordFlag = coordFlag;\n    _dims = {1, 1, 1};\n    _meshMatchFlag = false;\n    _stdoutString.clear();\n    if (hasMissing) {\n        _varInfo.SetHasMissing(true);\n        _varInfo.SetMissingValue(std::numeric_limits<double>::infinity());\n    }\n};\n\nint PyEngine::DerivedPythonVar::Initialize()\n{\n    DC::Mesh m;\n    bool     status = _dataMgr->GetMesh(_varInfo.GetMeshName(), m);\n    if (!status) {\n        SetErrMsg(\"Invalid mesh : %s\", _varInfo.GetMeshName().c_str());\n        return (-1);\n    }\n\n    vector<string> dimNames = m.GetDimNames();\n    VAssert(dimNames.size() <= _dims.size());\n    for (int i = 0; i < dimNames.size(); i++) {\n        DC::Dimension dim;\n        status = _dataMgr->GetDimension(dimNames[i], dim, -1);\n        VAssert(status);\n\n        _dims[i] = dim.GetLength();\n    }\n\n    string mesh = _varInfo.GetMeshName();\n\n    // If all of the input variables and the output (derived) variable\n    // are on the same mesh we can optimize by only calculating the\n    // derived variable over the requested ROI (min and max extents)\n    //\n    _meshMatchFlag = true;\n    for (int i = 0; i < _inNames.size(); i++) {\n        DC::DataVar dvar;\n        bool        ok = _dataMgr->GetDataVarInfo(_inNames[i], dvar);\n        if (!ok || dvar.GetMeshName() != mesh) {\n            _meshMatchFlag = false;\n            break;\n        }\n    }\n\n    if (_meshMatchFlag && _inNames.size()) {\n        DC::DataVar dvar;\n        bool        ok = _dataMgr->GetDataVarInfo(_inNames[0], dvar);\n        VAssert(ok);\n        _varInfo.SetCRatios(dvar.GetCRatios());\n    }\n\n    return (0);\n}\n\nbool PyEngine::DerivedPythonVar::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _varInfo;\n    return (true);\n}\n\nint PyEngine::DerivedPythonVar::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    if (_meshMatchFlag && _inNames.size()) {\n        int rc = _dataMgr->GetDimLensAtLevel(_inNames[0], level, dims_at_level, -1);\n        VAssert(rc >= 0);\n    } else {\n        for (int i = 0; i < number_of_dims(_dims) && i < _dims.size(); i++) { dims_at_level.push_back(_dims[i]); }\n    }\n\n    // No blocking\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nsize_t PyEngine::DerivedPythonVar::GetNumRefLevels() const\n{\n    if (_meshMatchFlag && _inNames.size()) { return (_dataMgr->GetNumRefLevels(_inNames[0])); }\n\n    return (1);\n}\n\nint PyEngine::DerivedPythonVar::OpenVariableRead(size_t ts, int level, int lod)\n{\n    if (level < 0) level = GetNumRefLevels() + level;\n\n    if (lod < 0) lod = _varInfo.GetCRatios().size() + lod;\n\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint PyEngine::DerivedPythonVar::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n    return (0);\n}\n\nint PyEngine::DerivedPythonVar::_readRegionAll(int fd, const DimsType &min, const DimsType &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    vector<Grid *> variables;\n\n    size_t ts = f->GetTS();\n    int    level = f->GetLevel();\n    int    lod = f->GetLOD();\n\n    int rc = DataMgrUtils::GetGrids(_dataMgr, ts, _inNames, false, &level, &lod, variables);\n    if (rc < 0) return (-1);\n\n    vector<varinfo_t> varInfoVec;\n    get_var_info(_dataMgr, variables, _inNames, _coordFlag, varInfoVec);\n\n    vector<DimsType>       inputVarDims;\n    vector<string>         inputNames;\n    for (int i = 0; i < varInfoVec.size(); i++) {\n        const varinfo_t &vref = varInfoVec[i];\n\n        inputNames.push_back(vref._name);\n        inputVarDims.push_back(vref._dims);\n        for (int j = 0; j < vref._coordNames.size(); j++) {\n            inputNames.push_back(vref._coordNames[j]);\n            inputVarDims.push_back(vref._coordDims[j]);\n        }\n    }\n\n    vector<size_t> dims_vec, dummy;\n    (void)GetDimLensAtLevel(level, dims_vec, dummy);\n\n    DimsType dims = {1, 1, 1};\n    Grid::CopyToArr3(dims_vec, dims);\n    vector<DimsType> outputVarDims = {dims};\n\n    vector<float *> inputVarArrays;\n    vector<float *> outputVarArrays;\n    rc = alloc_arrays(inputVarDims, outputVarDims, inputVarArrays, outputVarArrays);\n    if (rc < 0) {\n        SetErrMsg(\"Error allocating  memory\");\n        return (-1);\n    }\n\n    grid2c(varInfoVec, inputVarArrays);\n\n    //\n    // clear stdout from static class\n    //\n    (void)MyPython::Instance()->PyOut();\n\n    vector<string> outputVarNames = {_derivedVarName};\n    rc = PyEngine::Calculate(_script, inputNames, inputVarDims, inputVarArrays, outputVarNames, outputVarDims, outputVarArrays);\n\n    //\n    // Capture any stdout\n    //\n    _stdoutString = MyPython::Instance()->PyOut().c_str();\n\n    if (rc < 0) {\n        free_arrays(inputVarArrays, outputVarArrays);\n        return (-1);\n    }\n\n    copy_region(outputVarArrays[0], region, min, max, outputVarDims[0]);\n\n    free_arrays(inputVarArrays, outputVarArrays);\n\n    return (0);\n}\n\nint PyEngine::DerivedPythonVar::_readRegionSubset(int fd, const DimsType &min, const DimsType &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    vector<Grid *> variables;\n\n    size_t ts = f->GetTS();\n    int    level = f->GetLevel();\n    int    lod = f->GetLOD();\n\n    int rc = DataMgrUtils::GetGrids(_dataMgr, ts, _inNames, min, max, false, &level, &lod, variables);\n    if (rc < 0) return (-1);\n\n    vector<varinfo_t> varInfoVec;\n    get_var_info(_dataMgr, variables, _inNames, _coordFlag, varInfoVec);\n\n    vector<DimsType>       inputVarDims;\n    vector<string>         inputNames;\n    for (int i = 0; i < varInfoVec.size(); i++) {\n        const varinfo_t &vref = varInfoVec[i];\n\n        inputNames.push_back(vref._name);\n        inputVarDims.push_back(vref._dims);\n        for (int j = 0; j < vref._coordNames.size(); j++) {\n            inputNames.push_back(vref._coordNames[j]);\n            inputVarDims.push_back(vref._coordDims[j]);\n        }\n    }\n\n    // output and input variable(s) (if they exist) are all defined\n    // on the same mesh (they have same dimensions)\n    //\n    vector<DimsType>       outputVarDims;\n    DimsType               minAbs = {0, 0, 0};\n    if (inputVarDims.size()) {\n        outputVarDims.push_back(inputVarDims[0]);\n        minAbs = variables[0]->GetMinAbs();\n    } else {\n        outputVarDims.push_back(Grid::Dims(min, max));\n    }\n\n    vector<float *> inputVarArrays;\n    vector<float *> outputVarArrays;\n    rc = alloc_arrays(inputVarDims, outputVarDims, inputVarArrays, outputVarArrays);\n    if (rc < 0) {\n        SetErrMsg(\"Error allocating  memory\");\n        return (-1);\n    }\n\n    grid2c(varInfoVec, inputVarArrays);\n\n    //\n    // clear stdout from static class\n    //\n    (void)MyPython::Instance()->PyOut();\n\n    vector<string> outputVarNames = {_derivedVarName};\n    rc = PyEngine::Calculate(_script, inputNames, inputVarDims, inputVarArrays, outputVarNames, outputVarDims, outputVarArrays);\n\n    //\n    // Capture any stdout\n    //\n    _stdoutString = MyPython::Instance()->PyOut().c_str();\n\n    if (rc < 0) {\n        free_arrays(inputVarArrays, outputVarArrays);\n        return (-1);\n    }\n\n    // The min and max coordinates input to this method are relative to\n    // the entire domain. We need to correct them by substracting off the\n    // origin of the ROI contained in the Grid objects\n    //\n    DimsType min_roi, max_roi;\n    for (int i = 0; i < min.size(); i++) {\n        min_roi[i] = (min[i] - minAbs[i]);\n        max_roi[i] = (max[i] - minAbs[i]);\n    }\n    copy_region(outputVarArrays[0], region, min_roi, max_roi, outputVarDims[0]);\n\n    free_arrays(inputVarArrays, outputVarArrays);\n\n    return (0);\n}\n\nint PyEngine::DerivedPythonVar::ReadRegion(int fd, const std::vector<size_t> &minVec, const std::vector<size_t> &maxVec, float *region)\n{\n    DimsType min = {0, 0, 0};\n    Grid::CopyToArr3(minVec, min);\n\n    DimsType max = {0, 0, 0};\n    Grid::CopyToArr3(maxVec, max);\n\n    if (_meshMatchFlag) {\n        return (_readRegionSubset(fd, min, max, region));\n    } else {\n        return (_readRegionAll(fd, min, max, region));\n    }\n}\n\nbool PyEngine::DerivedPythonVar::VariableExists(size_t ts, int reflevel, int lod) const\n{\n    for (int i = 0; i < _inNames.size(); i++) {\n        if (!_dataMgr->VariableExists(ts, _inNames[i], reflevel, lod)) { return (false); }\n    }\n    return (true);\n}\n\nbool PyEngine::DerivedPythonVar::GetDataVarInfo(DC::DataVar &cvar) const\n{\n    cvar = _varInfo;\n    return (true);\n}\n\nbool PyEngine::_validOutputVar(string name) const\n{\n    vector<string> vars = _dataMgr->GetDataVarNames();\n\n    if (find(vars.begin(), vars.end(), name) != vars.end()) return (false);\n\n    vars = _dataMgr->GetCoordVarNames();\n\n    if (find(vars.begin(), vars.end(), name) != vars.end()) return (false);\n\n    return (true);\n}\n\nint PyEngine::_checkOutVars(const vector<string> &outputVarNames) const\n{\n    for (int i = 0; i < outputVarNames.size(); i++) {\n        string vname = outputVarNames[i];\n\n        if (!XmlNode::IsValidXMLElement(vname)) {\n            SetErrMsg(\"Invalid variable name: %s \", vname.c_str());\n            return (-1);\n        }\n\n        if (!_validOutputVar(outputVarNames[i])) {\n            SetErrMsg(\"Invalid derived variable name %s. Already in use.\", vname.c_str());\n            return (-1);\n        }\n    }\n    return (0);\n}\n\nbool PyEngine::_validOutputMesh(string name) const\n{\n    vector<string> meshes = _dataMgr->GetMeshNames();\n\n    return (find(meshes.begin(), meshes.end(), name) != meshes.end());\n}\n\nint PyEngine::_checkOutMeshes(const vector<string> &outputMeshNames) const\n{\n    for (int i = 0; i < outputMeshNames.size(); i++) {\n        string name = outputMeshNames[i];\n        if (!_validOutputMesh(outputMeshNames[i])) {\n            SetErrMsg(\"Invalid derived variable mesh name %s\", name.c_str());\n            return (-1);\n        }\n    }\n\n    return (0);\n}\n\nstring PyEngine::_getTimeCoordVarName(const vector<string> &varNames) const\n{\n    string timeCoordVarName = _dataMgr->GetTimeCoordVarName();\n    if (timeCoordVarName.empty()) return (\"\");\n\n    for (int i = 0; i < varNames.size(); i++) {\n        if (_dataMgr->IsTimeVarying(varNames[i])) return (timeCoordVarName);\n    }\n\n    return (\"\");\n}\n"
  },
  {
    "path": "lib/render/RayCaster.cpp",
    "content": "#include \"vapor/glutil.h\"\n#include \"vapor/RayCaster.h\"\n#include <iostream>\n#include <fstream>\n#include <sstream>\n#include <cctype>\n\n#include <glm/gtc/type_ptr.hpp>\n#include <glm/ext/matrix_relational.hpp>\n\n#ifdef WIN32\n    #include <Windows.h>\n#else\n    #include <time.h>\n#endif\n\n#define OUTOFDATE   1\n#define GLNOTREADY  2\n#define GRIDERROR   -1\n#define JUSTERROR   -2\n#define PARAMSERROR -3\n#define MEMERROR    -4\n#define GLERROR     -5\n\nusing namespace VAPoR;\n\n/*\nGLenum glCheckError_(const char *file, int line)\n{\n    GLenum errorCode;\n    while ((errorCode = glGetError()) != GL_NO_ERROR)\n    {\n        std::string error;\n        switch (errorCode)\n        {\n            case GL_INVALID_ENUM:                  error = \"INVALID_ENUM\"; break;\n            case GL_INVALID_VALUE:                 error = \"INVALID_VALUE\"; break;\n            case GL_INVALID_OPERATION:             error = \"INVALID_OPERATION\"; break;\n            case GL_STACK_OVERFLOW:                error = \"STACK_OVERFLOW\"; break;\n            case GL_STACK_UNDERFLOW:               error = \"STACK_UNDERFLOW\"; break;\n            case GL_OUT_OF_MEMORY:                 error = \"OUT_OF_MEMORY\"; break;\n            case GL_INVALID_FRAMEBUFFER_OPERATION: error = \"INVALID_FRAMEBUFFER_OPERATION\"; break;\n        }\n        std::cout << error << \" | \" << file << \" (\" << line << \")\" << std::endl;\n    }\n    return errorCode;\n}\n#define glCheckError() glCheckError_(__FILE__, __LINE__)\nvoid glCheckError() { }\n*/\n\n// Constructor\nRayCaster::RayCaster(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string paramsType, std::string classType, std::string &instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, paramsType, classType, instName, dataMgr), _backFaceTexOffset(1), _frontFaceTexOffset(2), _volumeTexOffset(3), _colorMapTexOffset(4), _missingValueTexOffset(5),\n  _vertCoordsTexOffset(6), _depthTexOffset(7), _2ndVarDataTexOffset(8), _2ndVarMaskTexOffset(9)\n{\n    _backFaceTextureId = 0;\n    _frontFaceTextureId = 0;\n    _volumeTextureId = 0;\n    _missingValueTextureId = 0;\n    _colorMapTextureId = 0;\n    _vertCoordsTextureId = 0;\n    _depthTextureId = 0;\n    _frameBufferId = 0;\n    _2ndVarDataTexId = 0;\n    _2ndVarMaskTexId = 0;\n\n    _vertexArrayId = 0;\n    _vertexBufferId = 0;\n    _indexBufferId = 0;\n    _vertexAttribId = 0;\n\n    _1stPassShader = nullptr;\n    _2ndPassShader = nullptr;\n    _3rdPassShader = nullptr;\n    _3rdPassMode1Shader = nullptr;\n    _3rdPassMode2Shader = nullptr;\n\n    for (int i = 0; i < 4; i++) _currentViewport[i] = 0;\n\n    _currentMV = glm::mat4(0.0f);\n\n    // Detect if it's INTEL graphics card. If so, give a magic value to the params\n    const unsigned char *vendorC = glGetString(GL_VENDOR);\n    std::string          vendor((char *)vendorC);\n    for (int i = 0; i < vendor.size(); i++) vendor[i] = std::tolower(vendor[i]);\n    std::string::size_type n = vendor.find(\"intel\");\n    if (n == std::string::npos)\n        _isIntel = false;\n    else\n        _isIntel = true;\n\n    // Set the default ray casting method upon creation of the RayCaster.\n    _selectDefaultCastingMethod();\n}\n\n// Destructor\nRayCaster::~RayCaster()\n{\n    // Delete framebuffers\n    if (_frameBufferId) {\n        glDeleteFramebuffers(1, &_frameBufferId);\n        _frameBufferId = 0;\n    }\n\n    // Delete textures\n    if (_backFaceTextureId) {\n        glDeleteTextures(1, &_backFaceTextureId);\n        _backFaceTextureId = 0;\n    }\n    if (_frontFaceTextureId) {\n        glDeleteTextures(1, &_frontFaceTextureId);\n        _frontFaceTextureId = 0;\n    }\n    if (_volumeTextureId) {\n        glDeleteTextures(1, &_volumeTextureId);\n        _volumeTextureId = 0;\n    }\n    if (_missingValueTextureId) {\n        glDeleteTextures(1, &_missingValueTextureId);\n        _missingValueTextureId = 0;\n    }\n    if (_colorMapTextureId) {\n        glDeleteTextures(1, &_colorMapTextureId);\n        _colorMapTextureId = 0;\n    }\n    if (_vertCoordsTextureId) {\n        glDeleteTextures(1, &_vertCoordsTextureId);\n        _vertCoordsTextureId = 0;\n    }\n    if (_depthTextureId) {\n        glDeleteTextures(1, &_depthTextureId);\n        _depthTextureId = 0;\n    }\n    if (_2ndVarDataTexId) {\n        glDeleteTextures(1, &_2ndVarDataTexId);\n        _2ndVarDataTexId = 0;\n    }\n    if (_2ndVarMaskTexId) {\n        glDeleteTextures(1, &_2ndVarMaskTexId);\n        _2ndVarMaskTexId = 0;\n    }\n\n    // Delete vertex arrays\n    if (_vertexArrayId) {\n        glDeleteVertexArrays(1, &_vertexArrayId);\n        _vertexArrayId = 0;\n    }\n    if (_vertexBufferId) {\n        glDeleteBuffers(1, &_vertexBufferId);\n        _vertexBufferId = 0;\n    }\n    if (_indexBufferId) {\n        glDeleteBuffers(1, &_indexBufferId);\n        _indexBufferId = 0;\n    }\n    if (_vertexAttribId) {\n        glDeleteBuffers(1, &_vertexAttribId);\n        _vertexAttribId = 0;\n    }\n}\n\n// Constructor\nRayCaster::UserCoordinates::UserCoordinates()\n{\n    frontFace = nullptr;\n    backFace = nullptr;\n    rightFace = nullptr;\n    leftFace = nullptr;\n    topFace = nullptr;\n    bottomFace = nullptr;\n    dataField = nullptr;\n    vertCoords = nullptr;\n    secondVarData = nullptr;\n    missingValueMask = nullptr;\n    secondVarMask = nullptr;\n    for (int i = 0; i < 3; i++) {\n        myGridMin[i] = 0;\n        myGridMax[i] = 0;\n        dims[i] = 0;\n    }\n\n    myCurrentTimeStep = 0;\n    myVariableName = \"\";\n    my2ndVarName = \"\";\n    myRefinementLevel = -1;\n    myCompressionLevel = -1;\n\n    dataFieldUpToDate = false;\n    vertCoordsUpToDate = false;\n    secondVarUpToDate = false;\n}\n\n// Destructor\nRayCaster::UserCoordinates::~UserCoordinates()\n{\n    if (frontFace) {\n        delete[] frontFace;\n        frontFace = nullptr;\n    }\n    if (backFace) {\n        delete[] backFace;\n        backFace = nullptr;\n    }\n    if (rightFace) {\n        delete[] rightFace;\n        rightFace = nullptr;\n    }\n    if (leftFace) {\n        delete[] leftFace;\n        leftFace = nullptr;\n    }\n    if (topFace) {\n        delete[] topFace;\n        topFace = nullptr;\n    }\n    if (bottomFace) {\n        delete[] bottomFace;\n        bottomFace = nullptr;\n    }\n    if (dataField) {\n        delete[] dataField;\n        dataField = nullptr;\n    }\n    if (vertCoords) {\n        delete[] vertCoords;\n        vertCoords = nullptr;\n    }\n    if (missingValueMask) {\n        delete[] missingValueMask;\n        missingValueMask = nullptr;\n    }\n    if (secondVarData) {\n        delete[] secondVarData;\n        secondVarData = nullptr;\n    }\n    if (secondVarMask) {\n        delete[] secondVarMask;\n        secondVarMask = nullptr;\n    }\n}\n\nint RayCaster::UserCoordinates::GetCurrentGrid(const RayCasterParams *params, DataMgr *dataMgr, StructuredGrid **gridpp) const\n{\n    CoordType extMin, extMax;\n    params->GetBox()->GetExtents(extMin, extMax);\n\n    StructuredGrid *grid =\n        dynamic_cast<StructuredGrid *>(dataMgr->GetVariable(params->GetCurrentTimestep(), params->GetVariableName(), params->GetRefinementLevel(), params->GetCompressionLevel(), extMin, extMax));\n    if (grid == nullptr) {\n        MyBase::SetErrMsg(\"UserCoordinates::GetCurrentGrid() isn't on a StructuredGrid; \"\n                          \"the behavior is undefined in this case.\");\n        return GRIDERROR;\n    } else {\n        *gridpp = grid;\n        return 0;\n    }\n}\n\nvoid RayCaster::UserCoordinates::CheckUpToDateStatus(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr, bool use2ndVar)\n{\n    // First, if any of the metadata is changed, all data fields are not up-to-date\n    if ((myCurrentTimeStep != params->GetCurrentTimestep()) || (myRefinementLevel != params->GetRefinementLevel()) || (myCompressionLevel != params->GetCompressionLevel())) {\n        dataFieldUpToDate = false;\n        vertCoordsUpToDate = false;\n        secondVarUpToDate = false;\n        return;\n    }\n\n    // Second, if the grid extents are changed, all data fields are not up-to-date\n    std::vector<double> newMin, newMax;\n    grid->GetUserExtents(newMin, newMax);\n    VAssert(newMin.size() == 3 || newMax.size() == 3);\n    for (int i = 0; i < 3; i++)\n        if ((myGridMin[i] != (float)newMin[i]) || (myGridMax[i] != (float)newMax[i])) {\n            dataFieldUpToDate = false;\n            vertCoordsUpToDate = false;\n            secondVarUpToDate = false;\n            return;\n        }\n\n    // Third, let's compare the primary variable name\n    if (myVariableName != params->GetVariableName()) { dataFieldUpToDate = false; }\n\n    // Fourth, let's check the vertex coordinates.\n    // Actually, the only way vertex coordinates go out of date is changing the metadata\n    //   and user extents, which is already checked. We don't need to do anything here!\n\n    // Fifth, let check if second variable data is up to date\n    if (use2ndVar && (my2ndVarName != params->GetColorMapVariableName())) { secondVarUpToDate = false; }\n}\n\nint RayCaster::UserCoordinates::UpdateFaceAndData(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr)\n{\n    /* Update meta data */\n    std::vector<double> newMin, newMax;\n    grid->GetUserExtents(newMin, newMax);\n    VAssert(newMin.size() == 3 || newMax.size() == 3);\n    for (int i = 0; i < 3; i++) {\n        myGridMin[i] = (float)newMin[i];\n        myGridMax[i] = (float)newMax[i];\n    }\n    myCurrentTimeStep = params->GetCurrentTimestep();\n    myVariableName = params->GetVariableName();\n    myRefinementLevel = params->GetRefinementLevel();\n    myCompressionLevel = params->GetCompressionLevel();\n\n    /* Update member variables */\n    auto gridDims = grid->GetDimensions();\n    dims[0] = gridDims[0];\n    dims[1] = gridDims[1];\n    dims[2] = gridDims[2];\n\n    // Save front face user coordinates ( z == dims[2] - 1 )\n    if (frontFace) delete[] frontFace;\n    frontFace = new float[dims[0] * dims[1] * 3];\n    this->FillCoordsXYPlane(grid, dims[2] - 1, frontFace);\n\n    // Save back face user coordinates ( z == 0 )\n    if (backFace) delete[] backFace;\n    backFace = new float[dims[0] * dims[1] * 3];\n    this->FillCoordsXYPlane(grid, 0, backFace);\n\n    // Save right face user coordinates ( x == dims[0] - 1 )\n    if (rightFace) delete[] rightFace;\n    rightFace = new float[dims[1] * dims[2] * 3];\n    this->FillCoordsYZPlane(grid, dims[0] - 1, rightFace);\n\n    // Save left face user coordinates ( x == 0 )\n    if (leftFace) delete[] leftFace;\n    leftFace = new float[dims[1] * dims[2] * 3];\n    this->FillCoordsYZPlane(grid, 0, leftFace);\n\n    // Save top face user coordinates ( y == dims[1] - 1 )\n    if (topFace) delete[] topFace;\n    topFace = new float[dims[0] * dims[2] * 3];\n    this->FillCoordsXZPlane(grid, dims[1] - 1, topFace);\n\n    // Save bottom face user coordinates ( y == 0 )\n    if (bottomFace) delete[] bottomFace;\n    bottomFace = new float[dims[0] * dims[2] * 3];\n    this->FillCoordsXZPlane(grid, 0, bottomFace);\n\n    // Save the data field values and missing values\n    size_t numOfVertices = dims[0] * dims[1] * dims[2];\n    if (dataField) {\n        delete[] dataField;\n        dataField = nullptr;\n    }\n    try {\n        dataField = new float[numOfVertices];\n    } catch (const std::bad_alloc &e) {\n        MyBase::SetErrMsg(e.what());\n        return MEMERROR;\n    }\n    if (missingValueMask) {\n        delete[] missingValueMask;\n        missingValueMask = nullptr;\n    }\n    if (grid->HasMissingData()) {\n        try {\n            missingValueMask = new unsigned char[numOfVertices];\n        } catch (const std::bad_alloc &e) {\n            MyBase::SetErrMsg(e.what());\n            return MEMERROR;\n        }\n    }\n\n    // Now iterate the current grid\n    this->IterateAGrid(grid, numOfVertices, dataField, missingValueMask);\n\n    dataFieldUpToDate = true;\n\n    return 0;\n}\n\nint RayCaster::UserCoordinates::Update2ndVariable(const RayCasterParams *params, DataMgr *dataMgr)\n{\n    VAssert(dataFieldUpToDate);\n\n    // Update 2nd variable name\n    my2ndVarName = params->GetColorMapVariableName();\n\n    // Retrieve grid for the 2nd variable\n    CoordType extMin, extMax;\n    params->GetBox()->GetExtents(extMin, extMax);\n\n    StructuredGrid *grid = dynamic_cast<StructuredGrid *>(dataMgr->GetVariable(myCurrentTimeStep, my2ndVarName, myRefinementLevel, myCompressionLevel, extMin, extMax));\n    if (grid == nullptr) {\n        MyBase::SetErrMsg(\"The secondary variable isn't on a StructuredGrid; \"\n                          \"the behavior is undefined in this case.\");\n        return GRIDERROR;\n    }\n\n    // Make sure the secondary grid shares the same dimention as the primary grid\n    auto seconDims = grid->GetDimensions();\n    for (int i = 0; i < 3; i++)\n        if (seconDims[i] != dims[i]) {\n            MyBase::SetErrMsg(\"The secondary and primary variable grids have different dimensions; \"\n                              \"the behavior is undefined in this case.\");\n            delete grid;\n            return GRIDERROR;\n        }\n\n    // Allocate memory\n    size_t numOfVertices = dims[0] * dims[1] * dims[2];\n    if (secondVarData) {\n        delete[] secondVarData;\n        secondVarData = nullptr;\n    }\n    try {\n        secondVarData = new float[numOfVertices];\n    } catch (const std::bad_alloc &e) {\n        MyBase::SetErrMsg(e.what());\n        delete grid;\n        return MEMERROR;\n    }\n    if (secondVarMask) {\n        delete[] secondVarMask;\n        secondVarMask = nullptr;\n    }\n    if (grid->HasMissingData()) {\n        try {\n            secondVarMask = new unsigned char[numOfVertices];\n        } catch (const std::bad_alloc &e) {\n            MyBase::SetErrMsg(e.what());\n            delete grid;\n            return MEMERROR;\n        }\n    }\n\n    // Now iterate the current grid\n    this->IterateAGrid(grid, numOfVertices, secondVarData, secondVarMask);\n\n    delete grid;\n    secondVarUpToDate = true;\n\n    return 0;\n}\n\nvoid RayCaster::UserCoordinates::IterateAGrid(const StructuredGrid *grid, size_t numOfVert, float *dataBuf, unsigned char *maskBuf)\n{\n    StructuredGrid::ConstIterator valItr = grid->cbegin();\n\n    if (grid->HasMissingData()) {\n        float missingValue = grid->GetMissingValue();\n        float dataValue;\n        for (size_t i = 0; i < numOfVert; i++) {\n            dataValue = *valItr;\n            if (dataValue == missingValue) {\n                dataBuf[i] = 0.0f;\n                maskBuf[i] = 127u;\n            } else {\n                dataBuf[i] = dataValue;\n                maskBuf[i] = 0u;\n            }\n            ++valItr;\n        }\n    } else {\n        for (size_t i = 0; i < numOfVert; i++) {\n            dataBuf[i] = *valItr;\n            ++valItr;\n        }\n    }\n}\n\nvoid RayCaster::UserCoordinates::FillCoordsXYPlane(const StructuredGrid *grid, size_t planeIdx, float *coords)\n{\n    size_t idx = 0;\n    double buf[3];\n    for (size_t y = 0; y < dims[1]; y++)\n        for (size_t x = 0; x < dims[0]; x++) {\n            grid->GetUserCoordinates(x, y, planeIdx, buf[0], buf[1], buf[2]);\n            coords[idx++] = (float)buf[0];\n            coords[idx++] = (float)buf[1];\n            coords[idx++] = (float)buf[2];\n        }\n}\n\nvoid RayCaster::UserCoordinates::FillCoordsYZPlane(const StructuredGrid *grid, size_t planeIdx, float *coords)\n{\n    size_t idx = 0;\n    double buf[3];\n    for (size_t z = 0; z < dims[2]; z++)\n        for (size_t y = 0; y < dims[1]; y++) {\n            grid->GetUserCoordinates(planeIdx, y, z, buf[0], buf[1], buf[2]);\n            coords[idx++] = (float)buf[0];\n            coords[idx++] = (float)buf[1];\n            coords[idx++] = (float)buf[2];\n        }\n}\n\nvoid RayCaster::UserCoordinates::FillCoordsXZPlane(const StructuredGrid *grid, size_t planeIdx, float *coords)\n{\n    size_t idx = 0;\n    double buf[3];\n    for (size_t z = 0; z < dims[2]; z++)\n        for (size_t x = 0; x < dims[0]; x++) {\n            grid->GetUserCoordinates(x, planeIdx, z, buf[0], buf[1], buf[2]);\n            coords[idx++] = (float)buf[0];\n            coords[idx++] = (float)buf[1];\n            coords[idx++] = (float)buf[2];\n        }\n}\n\nint RayCaster::UserCoordinates::UpdateVertCoords(const RayCasterParams *params, const StructuredGrid *grid, DataMgr *dataMgr)\n{\n    VAssert(dataFieldUpToDate);\n\n    size_t numOfVertices = dims[0] * dims[1] * dims[2];\n    if (vertCoords) delete[] vertCoords;\n    try {\n        vertCoords = new float[3 * numOfVertices];\n    } catch (const std::bad_alloc &e) {\n        MyBase::SetErrMsg(e.what());\n        return MEMERROR;\n    }\n\n    // Gather the vertex coordinates from grid\n    StructuredGrid::ConstCoordItr coordItr = grid->ConstCoordBegin();\n    for (int i = 0; i < numOfVertices; i++) {\n        vertCoords[3 * i] = float((*coordItr)[0]);\n        vertCoords[3 * i + 1] = float((*coordItr)[1]);\n        vertCoords[3 * i + 2] = float((*coordItr)[2]);\n        ++coordItr;\n    }\n\n    vertCoordsUpToDate = true;\n\n    return 0;\n}\n\nint RayCaster::_initializeGL()\n{\n    // Load 1st and 2nd pass shaders\n    ShaderProgram *shader = nullptr;\n    if ((shader = _glManager->shaderManager->GetShader(\"RayCaster1stPass\")))\n        _1stPassShader = shader;\n    else\n        return GLERROR;\n\n    if ((shader = _glManager->shaderManager->GetShader(\"RayCaster2ndPass\")))\n        _2ndPassShader = shader;\n    else\n        return GLERROR;\n\n    // Load 3rd pass shaders\n    if (_load3rdPassShaders() != 0) {\n        MyBase::SetErrMsg(\"Failed to load shaders!\");\n        return GLERROR;\n    }\n\n    // Get the current viewport\n    GLint viewport[4];\n    glGetIntegerv(GL_VIEWPORT, viewport);\n    std::memcpy(_currentViewport, viewport, 4 * sizeof(GLint));\n    //\n    // Retrieved viewport may contain zero width and height sometimes.\n    //   Need to make these dimensions positive, so the initialization routine,\n    //   including the step of attaching textures to framebuffers, could complete.\n    //   Later, paintGL() will have another chance to set the correct dimensions.\n    //   The bottom line is, the rest of the class can safely assume that\n    //   _currentViewport[4] always contains non-zero dimensions.\n    //\n    for (int i = 2; i < 4; i++)\n        if (_currentViewport[i] < 1) _currentViewport[i] = 8;\n\n    // Create any textures, framebuffers, etc.\n    if (_initializeFramebufferTextures() != 0) {\n        MyBase::SetErrMsg(\"Failed to Create Framebuffer and Textures!\");\n        return GLERROR;\n    }\n\n    return 0;    // Success\n}\n\nint RayCaster::_paintGL(bool fast)\n{\n    GLint viewport[4];\n    glGetIntegerv(GL_VIEWPORT, viewport);\n    // When viewport has zero dimensions, bail immediately.\n    //   This happens when undo/redo is issued.\n    if (viewport[2] < 1 || viewport[3] < 1) return 0;\n    _updateViewportWhenNecessary(viewport);\n\n    glDisable(GL_POLYGON_SMOOTH);\n\n    // Collect params and grid that will be used repeatedly\n    RayCasterParams *params = dynamic_cast<RayCasterParams *>(GetActiveParams());\n    if (!params) {\n        MyBase::SetErrMsg(\"Error occured during retrieving RayCaster parameters!\");\n        return PARAMSERROR;\n    }\n\n    // Return when there's no variable selected.\n    if (params->GetVariableName().empty()) {\n        MyBase::SetErrMsg(\"Please select a valid 3D variable for operation!\");\n        return PARAMSERROR;\n    }\n\n    // Do not perform any fast rendering in cell traverse mode\n    int castingMode = int(params->GetCastingMode());\n    if (castingMode == CellTraversal && fast) return 0;\n\n    // Force casting mode to be FixedStep if on Intel GPU.\n    if (_isIntel) {\n        castingMode = FixedStep;\n        params->SetCastingMode(FixedStep);\n    }\n\n    StructuredGrid *grid = nullptr;\n    if (_userCoordinates.GetCurrentGrid(params, _dataMgr, &grid) != 0) {\n        MyBase::SetErrMsg(\"Failed to retrieve a StructuredGrid\");\n        return GRIDERROR;\n    }\n\n    if (_load3rdPassShaders() != 0) {\n        MyBase::SetErrMsg(\"Failed to load shaders\");\n        delete grid;\n        return GLERROR;\n    }\n\n    // Use the correct shader for 3rd pass rendering\n    if (castingMode == FixedStep)\n        _3rdPassShader = _3rdPassMode1Shader;\n    else if (castingMode == CellTraversal)\n        _3rdPassShader = _3rdPassMode2Shader;\n    else {\n        MyBase::SetErrMsg(\"RayCasting Mode not supported!\");\n        delete grid;\n        return JUSTERROR;\n    }\n\n    // Retrieve if we're using secondary variable\n    bool use2ndVar = _use2ndVariable(params);\n\n    // Check if there is an update event\n    _userCoordinates.CheckUpToDateStatus(params, grid, _dataMgr, use2ndVar);\n\n    // Update primary variable data field\n    if (!_userCoordinates.dataFieldUpToDate) {\n        int success = _userCoordinates.UpdateFaceAndData(params, grid, _dataMgr);\n        if (success != 0) {\n            MyBase::SetErrMsg(\"Error occured during updating face and volume data!\");\n            delete grid;\n            return JUSTERROR;\n        }\n\n        // Texture for primary variable data is updated only when data changes\n        _updateDataTextures();\n    }\n\n    // Update vertex coordinates field only when using CellTraversal method.\n    glm::mat4 ModelView = Renderer::_glManager->matrixManager->GetModelViewMatrix();\n    if (castingMode == CellTraversal) {\n        if (!_userCoordinates.vertCoordsUpToDate) {\n            int success = _userCoordinates.UpdateVertCoords(params, grid, _dataMgr);\n            if (success != 0) {\n                MyBase::SetErrMsg(\"Error occured during updating curvilinear coordinates!\");\n                glActiveTexture(GL_TEXTURE0);\n                glBindTexture(GL_TEXTURE_1D, 0);\n                glBindTexture(GL_TEXTURE_2D, 0);\n                glBindTexture(GL_TEXTURE_3D, 0);\n                delete grid;\n                return JUSTERROR;\n            }\n        }\n\n        // Transform vertex coordinate data to eye space, and then send to GPU.\n        // This step takes place at every loop.\n        if (_updateVertCoordsTexture(ModelView) != 0) {\n            MyBase::SetErrMsg(\"Error occured during calculating eye coordinates!\");\n            glActiveTexture(GL_TEXTURE0);\n            glBindTexture(GL_TEXTURE_1D, 0);\n            glBindTexture(GL_TEXTURE_2D, 0);\n            glBindTexture(GL_TEXTURE_3D, 0);\n            delete grid;\n            return MEMERROR;\n        }\n    }\n\n    // Update secondary variable\n    if (use2ndVar && !_userCoordinates.secondVarUpToDate) {\n        int success = _userCoordinates.Update2ndVariable(params, _dataMgr);\n        if (success != 0) {\n            MyBase::SetErrMsg(\"Error occured during updating secondary variable!\");\n            glActiveTexture(GL_TEXTURE0);\n            glBindTexture(GL_TEXTURE_1D, 0);\n            glBindTexture(GL_TEXTURE_2D, 0);\n            glBindTexture(GL_TEXTURE_3D, 0);\n            delete grid;\n            return JUSTERROR;\n        }\n    }\n\n    // This function has no effect for DVR. It's only usable for IsoSurface\n    //   with 2nd variable enabled.\n    _update2ndVarTextures();\n\n    glBindVertexArray(_vertexArrayId);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferId);\n\n    glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferId);\n    glViewport(0, 0, _currentViewport[2], _currentViewport[3]);\n\n    // 1st pass: render back facing polygons to texture0 of the framebuffer\n    std::vector<size_t> cameraCellIdx(0);\n    _drawVolumeFaces(1, castingMode, cameraCellIdx);\n\n    // Detect if we're inside the volume\n    glm::mat4           InversedMV = glm::inverse(ModelView);\n    std::vector<double> cameraUser(4, 1.0);    // current camera position in user coordinates\n    cameraUser[0] = InversedMV[3][0];\n    cameraUser[1] = InversedMV[3][1];\n    cameraUser[2] = InversedMV[3][2];\n    bool insideACell = grid->GetIndicesCell(cameraUser, cameraCellIdx);\n    if (!insideACell) cameraCellIdx.clear();    // Make sure size 0 to indicate outside of the volume\n\n    // 2nd pass, render front facing polygons\n    _drawVolumeFaces(2, castingMode, cameraCellIdx);\n\n    // Update color map texture\n    _updateColormap(params);\n    glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTextureId);\n    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, _colorMap.size() / 4, 0, GL_RGBA, GL_FLOAT, _colorMap.data());\n\n    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n    glViewport(0, 0, _currentViewport[2], _currentViewport[3]);\n\n    // 3rd pass, perform ray casting\n    _drawVolumeFaces(3, castingMode, cameraCellIdx, InversedMV, fast);\n\n    // Restore OpenGL values changed in this function.\n    glBindVertexArray(0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, 0);\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindTexture(GL_TEXTURE_3D, 0);\n\n    delete grid;\n\n    return 0;\n}\n\nint RayCaster::_initializeFramebufferTextures()\n{\n    /* Create Vertex Array Object (VAO) */\n    glGenVertexArrays(1, &_vertexArrayId);\n    glGenBuffers(1, &_vertexBufferId);\n    glGenBuffers(1, &_indexBufferId);\n    if (!_isIntel) glGenBuffers(1, &_vertexAttribId);\n\n    /* Generate and configure 2D back-facing texture */\n    glGenTextures(1, &_backFaceTextureId);\n    glActiveTexture(GL_TEXTURE0 + _backFaceTexOffset);\n    glBindTexture(GL_TEXTURE_2D, _backFaceTextureId);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _currentViewport[2], _currentViewport[3], 0, GL_RGBA, GL_FLOAT, nullptr);\n    this->_configure2DTextureLinearInterpolation();\n\n    /* Generate and configure 2D front-facing texture */\n    glGenTextures(1, &_frontFaceTextureId);\n    glActiveTexture(GL_TEXTURE0 + _frontFaceTexOffset);\n    glBindTexture(GL_TEXTURE_2D, _frontFaceTextureId);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _currentViewport[2], _currentViewport[3], 0, GL_RGBA, GL_FLOAT, nullptr);\n    this->_configure2DTextureLinearInterpolation();\n\n    /* Create an Frame Buffer Object for the front and back side of the volume. */\n    glGenFramebuffers(1, &_frameBufferId);\n    glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferId);\n\n    /* Set \"_backFaceTextureId\"  as color attachement #0,\n       and \"_frontFaceTextureId\" as color attachement #1.  */\n    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _backFaceTextureId, 0);\n    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, _frontFaceTextureId, 0);\n    GLenum drawBuffers[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};\n    glDrawBuffers(2, drawBuffers);\n\n    /* Check if framebuffer is complete */\n    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {\n        MyBase::SetErrMsg(\"_openGLInitialization(): Framebuffer failed; \"\n                          \"the behavior is then undefined.\");\n        return GLERROR;\n    }\n\n    /* Bind the default frame buffer */\n    glBindFramebuffer(GL_FRAMEBUFFER, 0);\n\n    /* Generate and configure 3D texture: _volumeTextureId */\n    glGenTextures(1, &_volumeTextureId);\n    glActiveTexture(GL_TEXTURE0 + _volumeTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _volumeTextureId);\n    this->_configure3DTextureLinearInterpolation();\n\n    /* Generate and configure 3D texture: _2ndVarDataTexId */\n    glGenTextures(1, &_2ndVarDataTexId);\n    glActiveTexture(GL_TEXTURE0 + _2ndVarDataTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _2ndVarDataTexId);\n    this->_configure3DTextureLinearInterpolation();\n\n    /* Generate and configure 1D texture: _colorMapTextureId */\n    glGenTextures(1, &_colorMapTextureId);\n    glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTextureId);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n\n    /* Generate and configure 3D texture: _missingValueTextureId */\n    glGenTextures(1, &_missingValueTextureId);\n    glActiveTexture(GL_TEXTURE0 + _missingValueTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _missingValueTextureId);\n    this->_configure3DTextureNearestInterpolation();\n\n    /* Generate and configure 3D texture: _2ndVarMaskTexId */\n    glGenTextures(1, &_2ndVarMaskTexId);\n    glActiveTexture(GL_TEXTURE0 + _2ndVarMaskTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _2ndVarMaskTexId);\n    this->_configure3DTextureNearestInterpolation();\n\n    if (!_isIntel) {\n        /* Generate 3D texture: _vertCoordsTextureId */\n        glGenTextures(1, &_vertCoordsTextureId);\n        glActiveTexture(GL_TEXTURE0 + _vertCoordsTexOffset);\n        glBindTexture(GL_TEXTURE_3D, _vertCoordsTextureId);\n        this->_configure3DTextureNearestInterpolation();\n    }\n\n    /* Generate and configure 2D depth texture */\n    glGenTextures(1, &_depthTextureId);\n    glActiveTexture(GL_TEXTURE0 + _depthTexOffset);\n    glBindTexture(GL_TEXTURE_2D, _depthTextureId);\n    this->_configure2DTextureLinearInterpolation();\n\n    return 0;\n}\n\nvoid RayCaster::_configure3DTextureNearestInterpolation() const\n{\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);\n}\n\nvoid RayCaster::_configure3DTextureLinearInterpolation() const\n{\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);\n}\n\nvoid RayCaster::_configure2DTextureLinearInterpolation() const\n{\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n}\n\nvoid RayCaster::_drawVolumeFaces(int whichPass, int castingMode, const std::vector<size_t> &cameraCellIdx, const glm::mat4 &InversedMV, bool fast) const\n{\n    VAssert(cameraCellIdx.size() == 0 || cameraCellIdx.size() == 3);\n    bool insideVolume = (cameraCellIdx.size() == 3);\n\n    glm::mat4 modelview = _glManager->matrixManager->GetModelViewMatrix();\n    glm::mat4 projection = _glManager->matrixManager->GetProjectionMatrix();\n\n    if (whichPass == 1) {\n        _1stPassShader->Bind();\n        _1stPassShader->SetUniform(\"MV\", modelview);\n        _1stPassShader->SetUniform(\"Projection\", projection);\n\n        glEnable(GL_CULL_FACE);\n        glCullFace(GL_FRONT);\n        glEnable(GL_DEPTH_TEST);\n        glClearDepth(0.0);\n        glClear(GL_DEPTH_BUFFER_BIT);\n        glDepthFunc(GL_GEQUAL);\n        const GLfloat black[] = {0.0f, 0.0f, 0.0f, 0.0f};\n        glClearBufferfv(GL_COLOR, 0, black);    // clear GL_COLOR_ATTACHMENT0\n        glDisable(GL_BLEND);\n\n        // Render the back side of the volume.\n        _renderTriangleStrips(1, castingMode);\n    } else if (whichPass == 2) {\n        _2ndPassShader->Bind();\n        _2ndPassShader->SetUniform(\"MV\", modelview);\n        _2ndPassShader->SetUniform(\"Projection\", projection);\n\n        glEnable(GL_CULL_FACE);\n        glCullFace(GL_BACK);\n        glEnable(GL_DEPTH_TEST);\n        glClearDepth(1.0);\n        glClear(GL_DEPTH_BUFFER_BIT);\n        glDepthFunc(GL_LEQUAL);\n        const GLfloat black[] = {0.0f, 0.0f, 0.0f, 0.0f};\n        glClearBufferfv(GL_COLOR, 1, black);    // clear GL_COLOR_ATTACHMENT1\n        glDisable(GL_BLEND);\n\n        // Render the front side of the volume if not inside it.\n        // Do nothing if inside the volume.\n        if (!insideVolume) _renderTriangleStrips(2, castingMode);\n    } else    // 3rd pass\n    {\n        _3rdPassShader->Bind();\n        _3rdPassShader->SetUniform(\"MV\", modelview);\n        _3rdPassShader->SetUniform(\"Projection\", projection);\n        _3rdPassShader->SetUniform(\"inversedMV\", InversedMV);\n        if (castingMode == CellTraversal) {\n            // Upload entryCellIdx, no matter inside or outside of the volume\n            glm::ivec3 entryCellIdx(0);\n            if (insideVolume) {\n                entryCellIdx.x = int(cameraCellIdx[0]);\n                entryCellIdx.y = int(cameraCellIdx[1]);\n                entryCellIdx.z = int(cameraCellIdx[2]);\n            }\n            _3rdPassShader->SetUniform(\"entryCellIdx\", entryCellIdx);\n        }\n        _load3rdPassUniforms(castingMode, fast, insideVolume);\n        _3rdPassSpecialHandling(fast, castingMode);\n\n        glEnable(GL_CULL_FACE);\n        glCullFace(GL_BACK);\n        glEnable(GL_DEPTH_TEST);\n        glDepthMask(GL_TRUE);\n\n        // When DVR is rendered the last, it blends with previous rendering.\n        glEnable(GL_BLEND);\n        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n        // Renders the near clipping plane if inside the volume.\n        //   Otherwise, render the front side of the volume.\n        if (insideVolume) {\n            // Transform the near clipping plane to model coordinate\n            //             0---------2\n            //              |       |\n            //              |       |\n            //              |       |\n            //             1|_______|3\n            GLfloat   nearCoords[12];\n            glm::mat4 MVP = _glManager->matrixManager->GetModelViewProjectionMatrix();\n            glm::mat4 InversedMVP = glm::inverse(MVP);\n            glm::vec4 topLeftNDC(-1.0f, 1.0f, -0.999f, 1.0f);\n            glm::vec4 bottomLeftNDC(-1.0f, -1.0f, -0.999f, 1.0f);\n            glm::vec4 topRightNDC(1.0f, 1.0f, -0.999f, 1.0f);\n            glm::vec4 bottomRightNDC(1.0f, -1.0f, -0.999f, 1.0f);\n            glm::vec4 nearP[4];\n            nearP[0] = InversedMVP * topLeftNDC;\n            nearP[1] = InversedMVP * bottomLeftNDC;\n            nearP[2] = InversedMVP * topRightNDC;\n            nearP[3] = InversedMVP * bottomRightNDC;\n            for (int i = 0; i < 4; i++) {\n                nearP[i] /= nearP[i].w;\n                std::memcpy(nearCoords + i * 3, glm::value_ptr(nearP[i]), 3 * sizeof(GLfloat));\n            }\n\n            glEnableVertexAttribArray(0);    // attribute 0 is vertex coordinates\n            glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);\n            glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), nearCoords, GL_DYNAMIC_DRAW);\n            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);\n            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);\n            glBindBuffer(GL_ARRAY_BUFFER, 0);\n            glDisableVertexAttribArray(0);\n        } else {\n            _renderTriangleStrips(3, castingMode);\n        }\n    }\n\n    // Let's also do some clean up.\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glUseProgram(0);\n}\n\nvoid RayCaster::_load3rdPassUniforms(int castingMode, bool fast, bool insideVolume) const\n{\n    ShaderProgram *shader = _3rdPassShader;\n\n    shader->SetUniform(\"colorMapRange\", glm::make_vec3(_colorMapRange));\n    shader->SetUniform(\"viewportDims\", glm::ivec2(_currentViewport[2], _currentViewport[3]));\n    const size_t *cdims = _userCoordinates.dims;\n    glm::ivec3    volumeDims((int)cdims[0], (int)cdims[1], (int)cdims[2]);\n    shader->SetUniform(\"volumeDims\", volumeDims);\n    float planes[24];    // 6 planes, each with 4 elements\n    Renderer::GetClippingPlanes(planes);\n    shader->SetUniformArray(\"clipPlanes\", 6, (glm::vec4 *)planes);\n\n    glm::vec3 gridMin, gridMax;\n    for (int i = 0; i < 3; i++) {\n        gridMin[i] = _userCoordinates.myGridMin[i];\n        gridMax[i] = _userCoordinates.myGridMax[i];\n    }\n    if (castingMode == FixedStep) {\n        shader->SetUniform(\"boxMin\", gridMin);\n        shader->SetUniform(\"boxMax\", gridMax);\n    }\n\n    // Get light settings from params.\n    RayCasterParams *params = dynamic_cast<RayCasterParams *>(GetActiveParams());\n    bool             lighting = params->GetLighting();\n    if (lighting) {\n        std::vector<double> coeffsD = params->GetLightingCoeffs();\n        float               coeffsF[4] = {float(coeffsD[0]), float(coeffsD[1]), float(coeffsD[2]), float(coeffsD[3])};\n        shader->SetUniformArray(\"lightingCoeffs\", 4, coeffsF);\n    }\n\n    // Pack four booleans together, so there's one data transmission\n    //   to the GPU, instead of four.\n    int flags[4] = {int(fast), int(lighting), int(insideVolume), int(_userCoordinates.missingValueMask != nullptr)};\n    shader->SetUniformArray(\"flags\", 4, flags);\n\n    // Calculate the step size with sample rate multiplier taken into account.\n    float stepSize1D, multiplier = 1.0f;\n    if (castingMode == FixedStep) switch (params->GetSampleRateMultiplier()) {\n        case 0: multiplier = 1.0f; break;    // These values need to be in sync with\n        case 1: multiplier = 2.0f; break;    //   the multiplier values in the GUI.\n        case 2: multiplier = 4.0f; break;\n        case 3: multiplier = 0.5f; break;\n        case 4: multiplier = 0.25f; break;\n        case 5: multiplier = 0.125f; break;\n        default: multiplier = 1.0f; break;\n        }\n    glm::vec3 dimsf((float)cdims[0], (float)cdims[1], (float)cdims[2]);\n    float     numCells = glm::length(dimsf);\n    glm::mat4 modelview = _glManager->matrixManager->GetModelViewMatrix();\n    glm::vec4 tmpVec4 = modelview * glm::vec4(gridMin, 1.0);\n    glm::vec3 gridMinEye(tmpVec4.x, tmpVec4.y, tmpVec4.z);\n    tmpVec4 = modelview * glm::vec4(gridMax, 1.0);\n    glm::vec3 gridMaxEye(tmpVec4.x, tmpVec4.y, tmpVec4.z);\n    glm::vec3 diagonal = gridMaxEye - gridMinEye;\n    if (numCells < 50.0f)    // Make sure at least 100 steps\n        stepSize1D = glm::length(diagonal) / 100.0f * multiplier;\n    else    // Use Nyquist frequency\n        stepSize1D = glm::length(diagonal) / (numCells * 2.0f) * multiplier;\n\n    if (fast && castingMode == FixedStep) stepSize1D *= 8.0f;    //  Increase step size, when fast rendering\n    shader->SetUniform(\"stepSize1D\", stepSize1D);\n\n    // Pass in textures\n    glActiveTexture(GL_TEXTURE0 + _backFaceTexOffset);\n    glBindTexture(GL_TEXTURE_2D, _backFaceTextureId);\n    shader->SetUniform(\"backFaceTexture\", _backFaceTexOffset);\n\n    glActiveTexture(GL_TEXTURE0 + _frontFaceTexOffset);\n    glBindTexture(GL_TEXTURE_2D, _frontFaceTextureId);\n    shader->SetUniform(\"frontFaceTexture\", _frontFaceTexOffset);\n\n    glActiveTexture(GL_TEXTURE0 + _volumeTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _volumeTextureId);\n    shader->SetUniform(\"volumeTexture\", _volumeTexOffset);\n\n    glActiveTexture(GL_TEXTURE0 + _colorMapTexOffset);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTextureId);\n    shader->SetUniform(\"colorMapTexture\", _colorMapTexOffset);\n\n    glActiveTexture(GL_TEXTURE0 + _missingValueTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _missingValueTextureId);\n    shader->SetUniform(\"missingValueMaskTexture\", _missingValueTexOffset);\n\n    if (castingMode == CellTraversal) {\n        glActiveTexture(GL_TEXTURE0 + _vertCoordsTexOffset);\n        glBindTexture(GL_TEXTURE_3D, _vertCoordsTextureId);\n        shader->SetUniform(\"vertCoordsTexture\", _vertCoordsTexOffset);\n    }\n}\n\nvoid RayCaster::_3rdPassSpecialHandling(bool fast, int castingMode) const\n{\n    // Left empty intentially.\n    // Derived classes feel free to put stuff here.\n}\n\nvoid RayCaster::_renderTriangleStrips(int whichPass, int castingMode) const\n{\n    /* Give bx, by, bz type of \"unsigned int\" for indexBuffer */\n    unsigned int bx = (unsigned int)_userCoordinates.dims[0];\n    unsigned int by = (unsigned int)_userCoordinates.dims[1];\n    unsigned int bz = (unsigned int)_userCoordinates.dims[2];\n    size_t       idx;\n\n    // Each strip will have the same numOfVertices for the first 4 faces\n    size_t        numOfVertices = bx * 2;\n    unsigned int *indexBuffer = new unsigned int[numOfVertices];\n    std::memset(indexBuffer, 0, numOfVertices * sizeof(unsigned int));\n    // Create buffer object to keep indices\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, numOfVertices * sizeof(unsigned int), indexBuffer, GL_DYNAMIC_DRAW);\n\n    bool attrib1Enabled = false;    // Attribute to hold provoking index of each triangle.\n    int *attrib1Buffer = nullptr;\n    if (castingMode == CellTraversal && whichPass == 3) {\n        attrib1Enabled = true;\n        attrib1Buffer = new int[bx * by * 4];    // Buffer for front and back face\n        std::memset(attrib1Buffer, 0, bx * by * 4 * sizeof(int));\n        glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n        // Create buffer object to keep attributes\n        glBufferData(GL_ARRAY_BUFFER, bx * by * 4 * sizeof(int), attrib1Buffer, GL_DYNAMIC_DRAW);\n    }\n\n    //\n    // Render front face:\n    //\n    // Attribute 0 keeps all the vertex indices of the entire front face.\n    glEnableVertexAttribArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);\n    glBufferData(GL_ARRAY_BUFFER, bx * by * 3 * sizeof(float), _userCoordinates.frontFace, GL_STATIC_DRAW);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);\n    for (unsigned int y = 0; y < by - 1; y++)    // Looping over every TriangleStrip\n    {\n        idx = 0;\n        //\n        // This loop controls rendering order of the triangle strip. It\n        // provides the indices for each vertex in the current strip.\n        //\n        for (unsigned int x = 0; x < bx; x++)    // Filling indices for vertices of this TriangleStrip\n        {\n            indexBuffer[idx++] = (y + 1) * bx + x;\n            indexBuffer[idx++] = y * bx + x;\n        }\n        //\n        // In cell-traverse ray casting mode we need a cell index for the\n        // two triangles forming the face of a cell. Use the OpenGL \"provoking\"\n        // vertex to provide this information.\n        //\n        if (attrib1Enabled)    // Also specify attrib1 values\n        {\n            for (unsigned int x = 0; x < bx; x++)    // Fill attrib1 value for each vertex\n            {\n                unsigned int attribIdx = ((y + 1) * bx + x) * 4;\n                attrib1Buffer[attribIdx] = int(x) - 1;\n                attrib1Buffer[attribIdx + 1] = int(y);\n                attrib1Buffer[attribIdx + 2] = int(bz) - 2;\n                attrib1Buffer[attribIdx + 3] = 0;\n                attribIdx = (y * bx + x) * 4;\n                attrib1Buffer[attribIdx] = int(x) - 1;\n                attrib1Buffer[attribIdx + 1] = int(y);\n                attrib1Buffer[attribIdx + 2] = int(bz) - 2;\n                attrib1Buffer[attribIdx + 3] = 0;\n            }\n            // Update attribute 1\n            glEnableVertexAttribArray(1);\n            glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n            glBufferSubData(GL_ARRAY_BUFFER, y * bx * 4 * sizeof(int), 2 * bx * 4 * sizeof(int), (attrib1Buffer + y * bx * 4));\n            glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0);\n        }\n        // Update indices buffer\n        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer);\n        glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0);\n    }\n\n    //\n    // Render back face:\n    //\n    glEnableVertexAttribArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);\n    glBufferData(GL_ARRAY_BUFFER, bx * by * 3 * sizeof(float), _userCoordinates.backFace, GL_STATIC_DRAW);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);\n    for (unsigned int y = 0; y < by - 1; y++)    // strip by strip\n    {\n        idx = 0;\n        for (unsigned int x = 0; x < bx; x++) {\n            indexBuffer[idx++] = y * bx + x;\n            indexBuffer[idx++] = (y + 1) * bx + x;\n        }\n        if (attrib1Enabled) {\n            for (unsigned int x = 0; x < bx; x++) {\n                unsigned int attribIdx = (y * bx + x) * 4;\n                attrib1Buffer[attribIdx] = int(x) - 1;\n                attrib1Buffer[attribIdx + 1] = int(y);\n                attrib1Buffer[attribIdx + 2] = 0;\n                attrib1Buffer[attribIdx + 3] = 1;\n                attribIdx = ((y + 1) * bx + x) * 4;\n                attrib1Buffer[attribIdx] = int(x) - 1;\n                attrib1Buffer[attribIdx + 1] = int(y);\n                attrib1Buffer[attribIdx + 2] = 0;\n                attrib1Buffer[attribIdx + 3] = 1;\n            }\n            glEnableVertexAttribArray(1);\n            glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n            glBufferSubData(GL_ARRAY_BUFFER, y * bx * 4 * sizeof(int), 2 * bx * 4 * sizeof(int), (attrib1Buffer + y * bx * 4));\n            glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0);\n        }\n        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer);\n        glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0);\n    }\n\n    if (attrib1Enabled) {\n        delete[] attrib1Buffer;\n        attrib1Buffer = new int[bx * bz * 4];    // For top and bottom faces\n        std::memset(attrib1Buffer, 0, bx * bz * 4 * sizeof(int));\n        glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n        // Create a new buffer object with the new size.\n        glBufferData(GL_ARRAY_BUFFER, bx * bz * 4 * sizeof(int), attrib1Buffer, GL_DYNAMIC_DRAW);\n    }\n\n    //\n    // Render top face:\n    //\n    glEnableVertexAttribArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);\n    glBufferData(GL_ARRAY_BUFFER, bx * bz * 3 * sizeof(float), _userCoordinates.topFace, GL_STATIC_DRAW);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);\n    for (unsigned int z = 0; z < bz - 1; z++) {\n        idx = 0;\n        for (unsigned int x = 0; x < bx; x++) {\n            indexBuffer[idx++] = z * bx + x;\n            indexBuffer[idx++] = (z + 1) * bx + x;\n        }\n        if (attrib1Enabled) {\n            for (unsigned int x = 0; x < bx; x++) {\n                unsigned int attribIdx = (z * bx + x) * 4;\n                attrib1Buffer[attribIdx] = int(x) - 1;\n                attrib1Buffer[attribIdx + 1] = int(by) - 2;\n                attrib1Buffer[attribIdx + 2] = int(z);\n                attrib1Buffer[attribIdx + 3] = 2;\n                attribIdx = ((z + 1) * bx + x) * 4;\n                attrib1Buffer[attribIdx] = int(x) - 1;\n                attrib1Buffer[attribIdx + 1] = int(by) - 2;\n                attrib1Buffer[attribIdx + 2] = int(z);\n                attrib1Buffer[attribIdx + 3] = 2;\n            }\n            glEnableVertexAttribArray(1);\n            glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n            glBufferSubData(GL_ARRAY_BUFFER, z * bx * 4 * sizeof(int), 2 * bx * 4 * sizeof(int), (attrib1Buffer + z * bx * 4));\n            glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0);\n        }\n        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer);\n        glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0);\n    }\n\n    //\n    // Render bottom face:\n    //\n    glEnableVertexAttribArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);\n    glBufferData(GL_ARRAY_BUFFER, bx * bz * 3 * sizeof(float), _userCoordinates.bottomFace, GL_STATIC_DRAW);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);\n    for (unsigned int z = 0; z < bz - 1; z++) {\n        idx = 0;\n        for (unsigned int x = 0; x < bx; x++) {\n            indexBuffer[idx++] = (z + 1) * bx + x;\n            indexBuffer[idx++] = z * bx + x;\n        }\n        if (attrib1Enabled) {\n            for (unsigned int x = 0; x < bx; x++) {\n                unsigned int attribIdx = ((z + 1) * bx + x) * 4;\n                attrib1Buffer[attribIdx] = int(x) - 1;\n                attrib1Buffer[attribIdx + 1] = 0;\n                attrib1Buffer[attribIdx + 2] = int(z);\n                attrib1Buffer[attribIdx + 3] = 3;\n                attribIdx = (z * bx + x) * 4;\n                attrib1Buffer[attribIdx] = int(x) - 1;\n                attrib1Buffer[attribIdx + 1] = 0;\n                attrib1Buffer[attribIdx + 2] = int(z);\n                attrib1Buffer[attribIdx + 3] = 3;\n            }\n            glEnableVertexAttribArray(1);\n            glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n            glBufferSubData(GL_ARRAY_BUFFER, z * bx * 4 * sizeof(int), 2 * bx * 4 * sizeof(int), (attrib1Buffer + z * bx * 4));\n            glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0);\n        }\n        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer);\n        glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0);\n    }\n\n    // Each strip will have the same numOfVertices for the rest 2 faces.\n    numOfVertices = by * 2;\n    delete[] indexBuffer;\n    indexBuffer = new unsigned int[numOfVertices];\n    std::memset(indexBuffer, 0, numOfVertices * sizeof(unsigned int));\n    // Re-create the index buffer object with the new size.\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, numOfVertices * sizeof(unsigned int), indexBuffer, GL_DYNAMIC_DRAW);\n    if (attrib1Enabled) {\n        delete[] attrib1Buffer;\n        attrib1Buffer = new int[by * bz * 4];    // For right and left faces\n        std::memset(attrib1Buffer, 0, by * bz * 4 * sizeof(int));\n        glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n        glBufferData(GL_ARRAY_BUFFER, by * bz * 4 * sizeof(int), attrib1Buffer, GL_DYNAMIC_DRAW);\n    }\n\n    //\n    // Render right face:\n    //\n    glEnableVertexAttribArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);\n    glBufferData(GL_ARRAY_BUFFER, by * bz * 3 * sizeof(float), _userCoordinates.rightFace, GL_STATIC_DRAW);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);\n    for (unsigned int z = 0; z < bz - 1; z++) {\n        idx = 0;\n        for (unsigned int y = 0; y < by; y++) {\n            indexBuffer[idx++] = (z + 1) * by + y;\n            indexBuffer[idx++] = z * by + y;\n        }\n        if (attrib1Enabled) {\n            for (unsigned int y = 0; y < by; y++) {\n                unsigned int attribIdx = ((z + 1) * by + y) * 4;\n                attrib1Buffer[attribIdx] = int(bx) - 2;\n                attrib1Buffer[attribIdx + 1] = int(y) - 1;\n                attrib1Buffer[attribIdx + 2] = int(z);\n                attrib1Buffer[attribIdx + 3] = 4;\n                attribIdx = (z * by + y) * 4;\n                attrib1Buffer[attribIdx] = int(bx) - 2;\n                attrib1Buffer[attribIdx + 1] = int(y) - 1;\n                attrib1Buffer[attribIdx + 2] = int(z);\n                attrib1Buffer[attribIdx + 3] = 4;\n            }\n            glEnableVertexAttribArray(1);\n            glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n            glBufferSubData(GL_ARRAY_BUFFER, z * by * 4 * sizeof(int), 2 * by * 4 * sizeof(int), (attrib1Buffer + z * by * 4));\n            glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0);\n        }\n        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer);\n        glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0);\n    }\n\n    //\n    // Render left face\n    //\n    glEnableVertexAttribArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferId);\n    glBufferData(GL_ARRAY_BUFFER, by * bz * 3 * sizeof(float), _userCoordinates.leftFace, GL_STATIC_DRAW);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);\n    for (unsigned int z = 0; z < bz - 1; z++) {\n        idx = 0;\n        for (unsigned int y = 0; y < by; y++) {\n            indexBuffer[idx++] = z * by + y;\n            indexBuffer[idx++] = (z + 1) * by + y;\n        }\n        if (attrib1Enabled) {\n            for (unsigned int y = 0; y < by; y++) {\n                unsigned int attribIdx = (z * by + y) * 4;\n                attrib1Buffer[attribIdx] = 0;\n                attrib1Buffer[attribIdx + 1] = int(y) - 1;\n                attrib1Buffer[attribIdx + 2] = int(z);\n                attrib1Buffer[attribIdx + 3] = 5;\n                attribIdx = ((z + 1) * by + y) * 4;\n                attrib1Buffer[attribIdx] = 0;\n                attrib1Buffer[attribIdx + 1] = int(y) - 1;\n                attrib1Buffer[attribIdx + 2] = int(z);\n                attrib1Buffer[attribIdx + 3] = 5;\n            }\n            glEnableVertexAttribArray(1);\n            glBindBuffer(GL_ARRAY_BUFFER, _vertexAttribId);\n            glBufferSubData(GL_ARRAY_BUFFER, z * by * 4 * sizeof(int), 2 * by * 4 * sizeof(int), (attrib1Buffer + z * by * 4));\n            glVertexAttribIPointer(1, 4, GL_INT, 0, (void *)0);\n        }\n        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numOfVertices * sizeof(unsigned int), indexBuffer);\n        glDrawElements(GL_TRIANGLE_STRIP, numOfVertices, GL_UNSIGNED_INT, (void *)0);\n    }\n\n    if (attrib1Enabled) delete[] attrib1Buffer;\n    delete[] indexBuffer;\n    glDisableVertexAttribArray(0);\n    glDisableVertexAttribArray(1);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n}\n\n#ifndef WIN32\ndouble RayCaster::_getElapsedSeconds(const struct timeval *begin, const struct timeval *end) const { return (end->tv_sec - begin->tv_sec) + ((end->tv_usec - begin->tv_usec) / 1000000.0); }\n#endif\n\nvoid RayCaster::_updateViewportWhenNecessary(const GLint *viewport)\n{\n    if ((std::memcmp(viewport, _currentViewport, 4 * sizeof(GLint)) != 0)) {\n        std::memcpy(_currentViewport, viewport, 4 * sizeof(GLint));\n\n        // Re-size 1st and 2nd pass rendering 2D textures\n        glActiveTexture(GL_TEXTURE0 + _backFaceTexOffset);\n        glBindTexture(GL_TEXTURE_2D, _backFaceTextureId);\n        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _currentViewport[2], _currentViewport[3], 0, GL_RGBA, GL_FLOAT, nullptr);\n\n        glActiveTexture(GL_TEXTURE0 + _frontFaceTexOffset);\n        glBindTexture(GL_TEXTURE_2D, _frontFaceTextureId);\n        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, _currentViewport[2], _currentViewport[3], 0, GL_RGBA, GL_FLOAT, nullptr);\n    }\n}\n\nvoid RayCaster::_updateColormap(RayCasterParams *params)\n{\n    if (params->UseSingleColor()) {\n        float singleColor[4];\n        params->GetConstantColor(singleColor);\n        singleColor[3] = 1.0f;    // 1.0 in alpha channel\n        _colorMap.resize(8);      // _colorMap will have 2 RGBA values\n        for (int i = 0; i < 8; i++) _colorMap[i] = singleColor[i % 4];\n        _colorMapRange[0] = 0.0f;     // min value of the color map\n        _colorMapRange[1] = 0.0f;     // max value of the color map\n        _colorMapRange[2] = 1e-5f;    // diff of color map. Has to be non-zero though.\n    } else {\n        // Subclasses will have a chance here to use their own colormaps.\n        _colormapSpecialHandling();\n    }\n}\n\nvoid RayCaster::_colormapSpecialHandling()\n{\n    // Left empty intentionally.\n    // Subclasses, e.g., IsoSurfaceRenderer and DVRenderer, feel free to implement it.\n}\n\nbool RayCaster::_use2ndVariable(const RayCasterParams *params) const\n{\n    // By default a ray caster does not use a secondary variable.\n    // Subclasses can take advantage of it, for example, an IsoSurface Renderer.\n    return false;\n}\n\nvoid RayCaster::_update2ndVarTextures()\n{\n    // Intentionally left empty\n}\n\nvoid RayCaster::_updateDataTextures()\n{\n    const size_t *dims = _userCoordinates.dims;\n\n    glActiveTexture(GL_TEXTURE0 + _volumeTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _volumeTextureId);\n#ifdef Darwin\n    //\n    // Intel driver on MacOS seems to not able to correctly update the texture content\n    //   when the texture is moderately big. This workaround of loading a dummy texture\n    //   to force it to update seems to resolve this issue.\n    //\n    float dummyVolume[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};\n    glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, 2, 2, 2, 0, GL_RED, GL_FLOAT, dummyVolume);\n#endif\n    glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, dims[0], dims[1], dims[2], 0, GL_RED, GL_FLOAT, _userCoordinates.dataField);\n\n    // Now we HAVE TO attach a missing value mask texture, because\n    //   Intel driver on Mac doesn't like leaving the texture empty...\n    glActiveTexture(GL_TEXTURE0 + _missingValueTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _missingValueTextureId);\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);    // Alignment adjustment. Stupid OpenGL thing.\n    if (_userCoordinates.missingValueMask) {\n        glTexImage3D(GL_TEXTURE_3D, 0, GL_R8UI, dims[0], dims[1], dims[2], 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, _userCoordinates.missingValueMask);\n    } else {\n        unsigned char dummyMask[8] = {0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};\n        glTexImage3D(GL_TEXTURE_3D, 0, GL_R8UI, 2, 2, 2, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dummyMask);\n    }\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);    // Restore default alignment.\n}\n\nint RayCaster::_updateVertCoordsTexture(const glm::mat4 &MV)\n{\n    // Step zero: see if MV is the same as it was from the last iteration.\n    //   If so, return directly without updating these coordinates.\n    glm::bvec4 columeEqual = glm::equal(_currentMV, MV);\n    if (glm::all(columeEqual)) return 0;\n\n    // Now we need to calculate and upload the new vertex coordinates\n    // First, transform every vertex coordinate to the eye space\n    size_t numOfVertices = _userCoordinates.dims[0] * _userCoordinates.dims[1] * _userCoordinates.dims[2];\n    float *coordEye = nullptr;\n    try {\n        coordEye = new float[3 * numOfVertices];\n    } catch (const std::bad_alloc &e) {\n        MyBase::SetErrMsg(e.what());\n        return MEMERROR;\n    }\n\n    glm::vec4 posModel(1.0f);\n    float *   posModelPtr = glm::value_ptr(posModel);\n    for (size_t i = 0; i < numOfVertices; i++) {\n        std::memcpy(posModelPtr, _userCoordinates.vertCoords + 3 * i, 3 * sizeof(float));\n        glm::vec4 posEye = MV * posModel;\n        std::memcpy(coordEye + 3 * i, glm::value_ptr(posEye), 3 * sizeof(float));\n    }\n    posModelPtr = nullptr;\n\n    // Second, send these eye coordinates to the GPU\n    glActiveTexture(GL_TEXTURE0 + _vertCoordsTexOffset);\n    glBindTexture(GL_TEXTURE_3D, _vertCoordsTextureId);\n\n#ifdef Darwin\n    // Apply a dummy texture\n    float dummyVolume[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};\n    glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, 2, 2, 2, 0, GL_RED, GL_FLOAT, dummyVolume);\n#endif\n\n    // Test if the existing texture has the same dimensions.\n    //   If so, simply substitute its content.\n    //   If not, create a new object.\n    int width, height, depth;\n    glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &width);\n    glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &height);\n    glGetTexLevelParameteriv(GL_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &depth);\n    if ((size_t)width == _userCoordinates.dims[0] && (size_t)height == _userCoordinates.dims[1] && (size_t)depth == _userCoordinates.dims[2]) {\n        glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, width, height, depth, GL_RGB, GL_FLOAT, coordEye);\n    } else {\n        glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB32F, _userCoordinates.dims[0], _userCoordinates.dims[1], _userCoordinates.dims[2], 0, GL_RGB, GL_FLOAT, coordEye);\n    }\n\n    // Don't forget to update the cached model view matrix\n    _currentMV = MV;\n\n    delete[] coordEye;\n\n    return 0;\n}\n\nint RayCaster::_selectDefaultCastingMethod() const\n{\n    RayCasterParams *params = dynamic_cast<RayCasterParams *>(GetActiveParams());\n    if (!params) {\n        MyBase::SetErrMsg(\"Error occured during retrieving RayCaster parameters!\");\n        return PARAMSERROR;\n    }\n\n    if (_isIntel) {\n        params->SetCastingMode(FixedStep);\n        return 0;\n    }\n\n    // If params already contain a value of mode 1 or 2, then do nothing.\n    //   This case happens when loading params from a session file.\n    int castingMode = int(params->GetCastingMode());\n    if (castingMode == FixedStep || castingMode == CellTraversal) return 0;\n\n    // castingMode == 0 if not initialized before. Let's figure out what value it should have.\n    StructuredGrid *grid = nullptr;\n    if (_userCoordinates.GetCurrentGrid(params, _dataMgr, &grid) != 0) {\n        MyBase::SetErrMsg(\"Failed to retrieve a StructuredGrid\");\n        return GRIDERROR;\n    }\n\n    //\n    // In case of a regular grid, use \"fixed step\" ray casting.\n    // In other cases, use \"cell traversal\" ray casting.\n    //\n    RegularGrid *regular = dynamic_cast<RegularGrid *>(grid);\n    if (regular)\n        params->SetCastingMode(FixedStep);\n    else\n        params->SetCastingMode(CellTraversal);\n\n    delete grid;\n\n    return 0;\n}\n\nvoid RayCaster::_sleepAWhile() const\n{\n#ifdef WIN32\n    glFinish();\n    Sleep(1);    // 1 milliseconds\n#else\n    struct timespec req, rem;\n    req.tv_sec = 0;\n    req.tv_nsec = 1000000L;    // 1 milliseconds\n    glFinish();\n    nanosleep(&req, &rem);\n#endif\n}\n"
  },
  {
    "path": "lib/render/Renderer.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2004\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tRenderer.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tSeptember 2004\n//\n//\tDescription:\tImplements the Renderer class.\n//\t\tA pure virtual class that is implemented for each renderer.\n//\t\tMethods are called by the Visualizer class as needed.\n//\n#include <cfloat>\n#include <climits>\n#include <limits>\n#include <iomanip>\n#include <sstream>\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <vapor/Renderer.h>\n#include <vapor/TwoDDataRenderer.h>\n#include <vapor/DataMgrUtils.h>\n#include \"vapor/GLManager.h\"\n#include \"vapor/FontManager.h\"\n#include \"vapor/LegacyGL.h\"\n#include \"vapor/TextLabel.h\"\n#include <glm/gtc/type_ptr.hpp>\n#include <vapor/ColorbarRenderer.h>\n#include <vapor/VolumeIsoParams.h>\n\n#include <vapor/ViewpointParams.h>\n\nusing namespace VAPoR;\nconst int Renderer::_imgWid = 256;\nconst int Renderer::_imgHgt = 256;\n\nRenderer::Renderer(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr)\n: RendererBase(pm, winName, dataSetName, paramsType, classType, instName, dataMgr)\n{\n    // Establish the data sources for the rendering:\n    //\n\n    _colorbarTexture = 0;\n    _timestep = 0;\n\n    _fontName = \"arimo\";\n}\n\nRendererBase::RendererBase(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr)\n{\n    // Establish the data sources for the rendering:\n    //\n    _paramsMgr = pm;\n    _winName = winName;\n    _dataSetName = dataSetName;\n    _paramsType = paramsType;\n    _classType = classType;\n    _instName = instName;\n    _dataMgr = dataMgr;\n\n    _glManager = nullptr;\n    _glInitialized = false;\n    _flaggedForDeletion = false;\n}\n// Destructor\nRendererBase::~RendererBase() {}\n\nvoid RendererBase::FlagForDeletion() { _flaggedForDeletion = true; }\n\nbool RendererBase::IsFlaggedForDeletion() const { return _flaggedForDeletion; }\n\n// Destructor\nRenderer::~Renderer()\n{\n    if (_colorbarTexture) delete _colorbarTexture;\n}\n\nint RendererBase::initializeGL(GLManager *glManager)\n{\n    _glManager = glManager;\n    int rc = _initializeGL();\n    if (rc < 0) { return (rc); }\n\n    vector<int> status;\n    bool        ok = oglStatusOK(status);\n    if (!ok) {\n        SetErrMsg(\"OpenGL error : %s\", oglGetErrMsg(status).c_str());\n        return (-1);\n    }\n\n    _glInitialized = true;\n\n    return (0);\n}\n\ndouble Renderer::GetDefaultZ(DataMgr *dataMgr, size_t ts) const\n{\n    const RenderParams *rParams = GetActiveParams();\n    int                 refLevel = rParams->GetRefinementLevel();\n    int                 lod = rParams->GetCompressionLevel();\n\n    return DataMgrUtils::Get2DRendererDefaultZ(dataMgr, ts, refLevel, lod);\n}\n\nint Renderer::paintGL(bool fast)\n{\n    const RenderParams *rParams = GetActiveParams();\n    MatrixManager *     mm = _glManager->matrixManager;\n\n    if (!rParams->IsEnabled()) return (0);\n\n    _timestep = rParams->GetCurrentTimestep();\n\n    mm->MatrixModeModelView();\n    mm->PushMatrix();\n\n    ApplyTransform(_glManager->matrixManager);\n\n    int rc = _paintGL(fast);\n\n    mm->PopMatrix();\n\n    if (rc < 0) { return (-1); }\n\n    vector<int> status;\n    bool        ok = oglStatusOK(status);\n    if (!ok) {\n        SetErrMsg(\"%s\", oglGetErrMsg(status).c_str());\n        return (-1);\n    }\n    return (0);\n}\n\nvoid Renderer::ApplyTransform(MatrixManager *mm) const\n{\n    ApplyTransform(mm, GetDatasetTransform(), GetActiveParams()->GetTransform());\n}\n\nvoid Renderer::ApplyTransform(MatrixManager *mm, const Transform *dataset, const Transform *renderer)\n{\n    vector<double> translate = renderer->GetTranslations();\n    vector<double> rotate = renderer->GetRotations();\n    vector<double> scale = renderer->GetScales();\n    vector<double> origin = renderer->GetOrigin();\n    VAssert(translate.size() == 3);\n    VAssert(rotate.size() == 3);\n    VAssert(scale.size() == 3);\n    VAssert(origin.size() == 3);\n\n    vector<double> datasetScales = dataset->GetScales();\n\n    mm->Translate(translate[0], translate[1], translate[2]);\n\n    mm->Scale(1 / datasetScales[0], 1 / datasetScales[1], 1 / datasetScales[2]);\n\n    mm->Translate(origin[0], origin[1], origin[2]);\n    mm->Rotate(glm::radians(rotate[0]), 1, 0, 0);\n    mm->Rotate(glm::radians(rotate[1]), 0, 1, 0);\n    mm->Rotate(glm::radians(rotate[2]), 0, 0, 1);\n    mm->Scale(scale[0], scale[1], scale[2]);\n    mm->Translate(-origin[0], -origin[1], -origin[2]);\n\n    mm->Scale(datasetScales[0], datasetScales[1], datasetScales[2]);\n}\n\nvoid Renderer::ApplyDatasetTransform(GLManager *gl, const Transform *t)\n{\n    MatrixManager *mm = gl->matrixManager;\n    vector<double> scales, rotations, translations, origin;\n    VAssert(t);\n    scales = t->GetScales();\n    rotations = t->GetRotations();\n    translations = t->GetTranslations();\n    origin = t->GetOrigin();\n\n    mm->Translate(origin[0], origin[1], origin[2]);\n    mm->Rotate(glm::radians(rotations[0]), 1, 0, 0);\n    mm->Rotate(glm::radians(rotations[1]), 0, 1, 0);\n    mm->Rotate(glm::radians(rotations[2]), 0, 0, 1);\n    mm->Scale(scales[0], scales[1], scales[2]);\n    mm->Translate(-origin[0], -origin[1], -origin[2]);\n\n    mm->Translate(translations[0], translations[1], translations[2]);\n}\n\nvoid Renderer::EnableClipToBox(ShaderProgram *shader, float haloFrac) const\n{\n    shader->Bind();\n    VAssert(shader->HasUniform(\"clippingPlanes\"));\n\n    float x0Plane[] = {1.0, 0.0, 0.0, 0.0};\n    float x1Plane[] = {-1.0, 0.0, 0.0, 0.0};\n    float y0Plane[] = {0.0, 1.0, 0.0, 0.0};\n    float y1Plane[] = {0.0, -1.0, 0.0, 0.0};\n    float z0Plane[] = {0.0, 0.0, 1.0, 0.0};\n    float z1Plane[] = {0.0, 0.0, -1.0, 0.0};    // z largest\n\n    const RenderParams *rParams = GetActiveParams();\n    vector<double>      minExts, maxExts;\n    rParams->GetBox()->GetExtents(minExts, maxExts);\n    VAssert(minExts.size() == maxExts.size());\n    VAssert(minExts.size() > 0 && minExts.size() < 4);\n\n    int orientation = rParams->GetBox()->GetOrientation();\n\n    for (int i = 0; i < minExts.size(); i++) {\n        double range = maxExts[i] - minExts[i];\n        if (fabs(range) <= FLT_EPSILON) range = 1.0;\n        float halo = range * haloFrac;\n        minExts[i] -= halo;\n        maxExts[i] += halo;\n    }\n\n    if (minExts.size() == 3 || orientation != Box::YZ) {\n        x0Plane[3] = -minExts[0];\n        x1Plane[3] = maxExts[0];\n        glEnable(GL_CLIP_DISTANCE0);\n        glEnable(GL_CLIP_DISTANCE1);\n        shader->SetUniform(\"clippingPlanes[0]\", glm::make_vec4(x0Plane));\n        shader->SetUniform(\"clippingPlanes[1]\", glm::make_vec4(x1Plane));\n    }\n\n    if (minExts.size() == 3 || orientation != Box::XZ) {\n        y0Plane[3] = -minExts[1];\n        y1Plane[3] = maxExts[1];\n        glEnable(GL_CLIP_DISTANCE2);\n        glEnable(GL_CLIP_DISTANCE3);\n        shader->SetUniform(\"clippingPlanes[2]\", glm::make_vec4(y0Plane));\n        shader->SetUniform(\"clippingPlanes[3]\", glm::make_vec4(y1Plane));\n    }\n\n    if (minExts.size() == 3 || orientation != Box::XY) {\n        z0Plane[3] = -minExts[2];\n        z1Plane[3] = maxExts[2];\n        glEnable(GL_CLIP_DISTANCE4);\n        glEnable(GL_CLIP_DISTANCE5);\n        shader->SetUniform(\"clippingPlanes[4]\", glm::make_vec4(z0Plane));\n        shader->SetUniform(\"clippingPlanes[5]\", glm::make_vec4(z1Plane));\n    }\n}\n\nvoid Renderer::DisableClippingPlanes()\n{\n    glDisable(GL_CLIP_DISTANCE0);\n    glDisable(GL_CLIP_DISTANCE1);\n    glDisable(GL_CLIP_DISTANCE2);\n    glDisable(GL_CLIP_DISTANCE3);\n    glDisable(GL_CLIP_DISTANCE4);\n    glDisable(GL_CLIP_DISTANCE5);\n}\n\nbool Renderer::VariableExists(size_t ts, std::vector<string> &varnames, int level, int lod, bool zeroOK) const\n{\n    for (int i = 0; i < varnames.size(); i++) {\n        if (zeroOK && (varnames[i] == \"<no-variable>\" || varnames[i] == \"\")) { continue; }\n\n        if (!_dataMgr->VariableExists(ts, varnames[i], level, lod)) { return (false); }\n    }\n    return (true);\n}\n\n#ifdef VAPOR3_0_0_ALPHA\nvoid Renderer::buildLocal2DTransform(int dataOrientation, float a[2], float b[2], float *constVal, int mappedDims[3])\n{\n    mappedDims[2] = dataOrientation;\n    mappedDims[0] = (dataOrientation == 0) ? 1 : 0;    // x or y\n    mappedDims[1] = (dataOrientation < 2) ? 2 : 1;     // z or y\n    const RenderParams *rParams = GetActiveParams();\n\n    const vector<double> &exts = rParams->GetBox()->GetLocalExtents();\n    *constVal = exts[dataOrientation];\n    // constant terms go to middle\n    b[0] = 0.5 * (exts[mappedDims[0]] + exts[3 + mappedDims[0]]);\n    b[1] = 0.5 * (exts[mappedDims[1]] + exts[3 + mappedDims[1]]);\n    // linear terms send -1,1 to box min,max\n    a[0] = b[0] - exts[mappedDims[0]];\n    a[1] = b[1] - exts[mappedDims[1]];\n}\n\nvoid Renderer::getLocalContainingRegion(float regMin[3], float regMax[3])\n{\n    // Determine the smallest axis-aligned cube that contains the rotated box local coordinates.  This is\n    // obtained by mapping all 8 corners into the space.\n\n    double transformMatrix[12];\n    // Set up to transform from probe (coords [-1,1]) into volume:\n    GetActiveParams()->GetBox()->buildLocalCoordTransform(transformMatrix, 0.f, -1);\n    const double *sizes = _dataStatus->getFullSizes();\n\n    // Calculate the normal vector to the probe plane:\n    double zdir[3] = {0.f, 0.f, 1.f};\n    double normEnd[3];    // This will be the unit normal\n    double normBeg[3];\n    double zeroVec[3] = {0.f, 0.f, 0.f};\n    vtransform(zdir, transformMatrix, normEnd);\n    vtransform(zeroVec, transformMatrix, normBeg);\n    vsub(normEnd, normBeg, normEnd);\n    vnormal(normEnd);\n\n    // Start by initializing extents, and variables that will be min,max\n    for (int i = 0; i < 3; i++) {\n        regMin[i] = FLT_MAX;\n        regMax[i] = -FLT_MAX;\n    }\n\n    for (int corner = 0; corner < 8; corner++) {\n        int    intCoord[3];\n        double startVec[3], resultVec[3];\n        intCoord[0] = corner % 2;\n        intCoord[1] = (corner / 2) % 2;\n        intCoord[2] = (corner / 4) % 2;\n        for (int i = 0; i < 3; i++) startVec[i] = -1.f + (float)(2.f * intCoord[i]);\n        // calculate the mapping of this corner,\n        vtransform(startVec, transformMatrix, resultVec);\n        // force mapped corner to lie in the local extents\n        // and then force box to contain the corner:\n        for (int i = 0; i < 3; i++) {\n            // force to lie in domain\n            if (resultVec[i] < 0.) resultVec[i] = 0.;\n            if (resultVec[i] > sizes[i]) resultVec[i] = sizes[i];\n\n            if (resultVec[i] < regMin[i]) regMin[i] = resultVec[i];\n            if (resultVec[i] > regMax[i]) regMax[i] = resultVec[i];\n        }\n    }\n    return;\n}\n#endif\n\nstd::string Renderer::_getColorbarVariableName() const\n{\n    RenderParams *rParams = GetActiveParams();\n    return rParams->GetVariableName();\n}\n\nvoid Renderer::renderColorbar()\n{\n    RenderParams *rParams = GetActiveParams();\n    if (!rParams->IsEnabled()) return;\n\n    // If constant color, no valid colorbar\n    VolumeIsoParams *vip;\n    if ((vip = dynamic_cast<VolumeIsoParams *>(rParams)))\n        if (!vip->GetValueLong(VolumeParams::UseColormapVariableTag, 0)) return;\n\n    ColorbarRenderer::Render(_glManager, rParams);\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// RendererFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nRendererFactory *RendererFactory::Instance()\n{\n    static RendererFactory instance;\n    return &instance;\n}\n\nvoid RendererFactory::RegisterFactoryFunction(string myName, string myParamsName, function<Renderer *(const ParamsMgr *, string, string, string, string, DataMgr *)> classFactoryFunction)\n{\n    // register the class factory function\n    _factoryFunctionRegistry[myName] = classFactoryFunction;\n    _factoryMapRegistry[myName] = myParamsName;\n}\n\nRenderer *RendererFactory::CreateInstance(const ParamsMgr *pm, string winName, string dataSetName, string classType, string instName, DataMgr *dataMgr)\n{\n    Renderer *instance = NULL;\n\n    // find classType in the registry and call factory method.\n    //\n    auto it = _factoryFunctionRegistry.find(classType);\n    if (it != _factoryFunctionRegistry.end()) { instance = it->second(pm, winName, dataSetName, classType, instName, dataMgr); }\n\n    if (instance != NULL)\n        return instance;\n    else\n        return NULL;\n}\n\nstring RendererFactory::GetRenderClassFromParamsClass(string paramsClass) const\n{\n    map<string, string>::const_iterator itr;\n    for (itr = _factoryMapRegistry.begin(); itr != _factoryMapRegistry.end(); ++itr) {\n        if (itr->second == paramsClass) return (itr->first);\n    }\n    return (\"\");\n}\n\nstring RendererFactory::GetParamsClassFromRenderClass(string renderClass) const\n{\n    map<string, string>::const_iterator itr;\n    for (itr = _factoryMapRegistry.begin(); itr != _factoryMapRegistry.end(); ++itr) {\n        if (itr->first == renderClass) return (itr->second);\n    }\n    return (\"\");\n}\n\nvector<string> RendererFactory::GetFactoryNames() const\n{\n    vector<string> names;\n\n    map<string, function<Renderer *(const ParamsMgr *, string, string, string, string, DataMgr *)>>::const_iterator itr;\n\n    for (itr = _factoryFunctionRegistry.begin(); itr != _factoryFunctionRegistry.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nvoid Renderer::GetClippingPlanes(float planes[24]) const\n{\n    float x0Plane[4] = {1.0, 0.0, 0.0, 0.0};\n    float x1Plane[4] = {-1.0, 0.0, 0.0, 0.0};\n    float y0Plane[4] = {0.0, 1.0, 0.0, 0.0};\n    float y1Plane[4] = {0.0, -1.0, 0.0, 0.0};\n    float z0Plane[4] = {0.0, 0.0, 1.0, 0.0};\n    float z1Plane[4] = {0.0, 0.0, -1.0, 0.0};\n\n    const RenderParams *rParams = GetActiveParams();\n    std::vector<double> minExts, maxExts;\n    rParams->GetBox()->GetExtents(minExts, maxExts);\n    VAssert(minExts.size() == maxExts.size());\n    VAssert(minExts.size() == 2 || minExts.size() == 3);\n\n    x0Plane[3] = float(-minExts[0]);\n    x1Plane[3] = float(maxExts[0]);\n    y0Plane[3] = float(-minExts[1]);\n    y1Plane[3] = float(maxExts[1]);\n    if (minExts.size() == 3)    // Fill normal Z extents\n    {\n        z0Plane[3] = float(-minExts[2]);\n        z1Plane[3] = float(maxExts[2]);\n    } else    // Fill a thin layer around DefaultZ\n    {\n        const auto dfz = this->GetDefaultZ(_dataMgr, rParams->GetCurrentTimestep());\n        const auto z1 = dfz * 1.0001;\n        const auto z2 = dfz * 0.9999;\n        z0Plane[3] = -std::min(z1, z2);\n        z1Plane[3] = std::max(z1, z2);\n    }\n\n    size_t planeSize = sizeof(x0Plane);\n    std::memcpy(planes, x0Plane, planeSize);\n    std::memcpy(planes + 4, x1Plane, planeSize);\n    std::memcpy(planes + 8, y0Plane, planeSize);\n    std::memcpy(planes + 12, y1Plane, planeSize);\n    std::memcpy(planes + 16, z0Plane, planeSize);\n    std::memcpy(planes + 20, z1Plane, planeSize);\n}\n\nRendererFactory::RendererFactory() {}\nRendererFactory::RendererFactory(const RendererFactory &) {}\nRendererFactory &RendererFactory::operator=(const RendererFactory &) { return *this; }\n"
  },
  {
    "path": "lib/render/Shader.cpp",
    "content": "#include \"vapor/glutil.h\"\n\n#include <stdio.h>\n#include <time.h>\n#include \"vapor/VAssert.h\"\n\n#include \"vapor/Shader.h\"\n\nusing namespace VAPoR;\n\nShader::Shader(unsigned int type) : _id(0), _successStatus(0), _compiled(false), _type(type) {}\n\nShader::~Shader()\n{\n    if (_id) glDeleteShader(_id);\n}\n\nint Shader::CompileFromSource(const std::string &source_)\n{\n    string source = source_;\n#ifndef NDEBUG\n    // Prevent caching\n    source += \"\\n// \" + std::to_string(time(NULL));\n#endif\n    VAssert(!_compiled);\n    char *buffer = new char[source.length() + 1];\n    strcpy(buffer, source.c_str());\n    _id = glCreateShader(_type);\n    glShaderSource(_id, 1, &buffer, NULL);\n    glCompileShader(_id);\n    glGetShaderiv(_id, GL_COMPILE_STATUS, &_successStatus);\n    _compiled = true;\n    delete[] buffer;\n\n    if (!_successStatus) {\n        SetErrMsg(\"--------------- Shader Compilation Failed ---------------\\n\"\n                  \"%s\"\n                  \"---------------------------------------------------------\\n\",\n                  GetLog().c_str());\n        return -1;\n    }\n    return 1;\n}\n\nstd::string Shader::GetLog() const\n{\n    char buf[512];\n    glGetShaderInfoLog(_id, 512, NULL, buf);\n    return std::string(buf);\n}\n\nunsigned int Shader::GetID() const { return _id; }\nunsigned int Shader::GetType() const { return _type; }\nbool         Shader::WasCompilationSuccessful() const { return _successStatus; }\n"
  },
  {
    "path": "lib/render/ShaderManager.cpp",
    "content": "#include \"vapor/glutil.h\"\n#include \"vapor/ShaderManager.h\"\n#include <vapor/Shader.h>\n#include \"vapor/FileUtils.h\"\n#include <vapor/ResourcePath.h>\n#include <vapor/STLUtils.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\nusing namespace STLUtils;\n\nusing std::map;\nusing std::pair;\nusing std::string;\nusing std::vector;\n\n#define SHADER_AUTORELOAD 1\n\n#ifdef NDEBUG\n    #if SHADER_AUTORELOAD\n        #ifndef WIN32\n        //#warning Disabling shader autoreloading\n        #endif\n        #undef SHADER_AUTORELOAD\n    #endif\n#endif\n\nstd::vector<std::string> ShaderManager::_getSourceFilePaths(const std::string &name) const\n{\n    vector<string> paths;\n    paths.push_back(GetSharePath(\"shaders/\" + name + \".vert\"));\n    paths.push_back(GetSharePath(\"shaders/\" + name + \".frag\"));\n\n    string geomPath = GetSharePath(\"shaders/\" + name + \".geom\");\n    if (FileUtils::Exists(geomPath)) paths.push_back(geomPath);\n\n    return paths;\n}\n\nbool ShaderManager::_wasFileModified(const std::string &path) const { return false; }\n\nstd::string ShaderManager::_getNameFromKey(const std::string &key) { return Split(key, \":\")[0]; }\n\nstd::vector<std::string> ShaderManager::_getDefinesFromKey(const std::string &key)\n{\n    vector<string> defines = Split(key, \":\");\n    defines.erase(defines.begin());\n    return defines;\n}\n\nShaderProgram *ShaderManager::GetShader(const std::string &key)\n{\n#if SHADER_AUTORELOAD\n    if (!_dependencyModifiedTimes.count(key)) {\n        vector<string>    paths = _getSourceFilePaths(_getNameFromKey(key));\n        vector<string>    deps;\n        map<string, long> times;\n\n        for (const string &path : paths) STLUtils::AppendTo(deps, GetShaderDependencies(path));\n\n        for (const string &path : deps) times[path] = FileUtils::GetFileModifiedTime(path);\n\n        _dependencyModifiedTimes[key] = times;\n    }\n    bool reload = false;\n    for (auto &pair : _dependencyModifiedTimes[key]) {\n        long mtime = FileUtils::GetFileModifiedTime(pair.first);\n        if (mtime > pair.second) {\n            //            printf(\"Reload \\\"%s\\\"\\n\", pair.first.c_str());\n            pair.second = mtime;\n            reload = true;\n        }\n    }\n    if (HasResource(key)) {\n        bool rebind = false;\n        int  boundProgram;\n        glGetIntegerv(GL_CURRENT_PROGRAM, &boundProgram);\n        if (reload && GetResource(key)->GetID() == boundProgram) rebind = true;\n\n        if (reload) DeleteResource(key);\n\n        ShaderProgram *shader = GetResource(key);\n        if (rebind) shader->Bind();\n        return shader;\n    }\n#endif\n    return GetResource(key);\n}\n\nSmartShaderProgram ShaderManager::GetSmartShader(const std::string &name) { return SmartShaderProgram(GetShader(name)); }\n\n#include <vapor/GLManager.h>\n\nint ShaderManager::LoadResourceByKey(const std::string &key)\n{\n    //    printf(\"Begin Compile %s\\n\", key.c_str());\n    //    void *t = GLManager::BeginTimer();\n\n    if (HasResource(key)) {\n        VAssert(!\"Shader already loaded\");\n        return -1;\n    }\n\n    const vector<string> defines = _getDefinesFromKey(key);\n\n    ShaderProgram *      program = new ShaderProgram;\n    const vector<string> paths = _getSourceFilePaths(_getNameFromKey(key));\n    for (auto it = paths.begin(); it != paths.end(); ++it) { program->AddShader(CompileNewShaderFromFile(*it, defines)); }\n    program->Link();\n    if (!program->WasLinkingSuccessful()) {\n        SetErrMsg(\"Failed to link shader:\\n%s\", program->GetLog().c_str());\n        delete program;\n        return -1;\n    }\n    AddResource(key, program);\n    //    printf(\"End Compile %f\\n\", GLManager::EndTimer(t));\n    return 1;\n}\n\nShader *ShaderManager::CompileNewShaderFromFile(const std::string &path, const std::vector<std::string> &defines)\n{\n    unsigned int shaderType = GetShaderTypeFromPath(path);\n    if (shaderType == GL_INVALID_ENUM) {\n        SetErrMsg(\"File \\\"%s\\\" does not have a valid shader file extension\", FileUtils::Basename(path).c_str());\n        return nullptr;\n    }\n    if (!FileUtils::IsRegularFile(path)) {\n        SetErrMsg(\"Path \\\"%s\\\" is not a valid file\", path.c_str());\n        return nullptr;\n    }\n    Shader *shader = new Shader(shaderType);\n    int     compilationSuccess = shader->CompileFromSource(PreProcessShader(path, defines));\n    if (compilationSuccess < 0) {\n        SetErrMsg(\"Shader \\\"%s\\\" failed to compile\", FileUtils::Basename(path).c_str());\n        delete shader;\n        return nullptr;\n    }\n    return shader;\n}\n\nunsigned int ShaderManager::GetShaderTypeFromPath(const std::string &path)\n{\n    string ext = FileUtils::Extension(path);\n    if (ext == \"vert\") return GL_VERTEX_SHADER;\n    if (ext == \"frag\") return GL_FRAGMENT_SHADER;\n    if (ext == \"geom\") return GL_GEOMETRY_SHADER;\n    return GL_INVALID_ENUM;\n}\n\nstd::string ShaderManager::PreProcessShader(const std::string &path, const std::vector<std::string> &defines)\n{\n    string source = FileUtils::ReadFileToString(path);\n    auto   lines = Split(source, \"\\n\");\n\n    int lineNum = 1;\n    for (string &line : lines) {\n        if (BeginsWith(line, \"#\")) {\n            if (BeginsWith(line, \"#pragma auto_version\")) {\n                line = \"#version \";\n                line += std::to_string(GLManager::GetGLSLVersion());\n                line += \" core\";\n            }\n\n            if (!defines.empty() && BeginsWith(line, \"#version \")) {\n                line += \"\\n\";\n                for (const string &define : defines) { line += \"#define \" + define + \"\\n\"; }\n                line += \"#line \" + std::to_string(lineNum + 1) + \" 0\";\n            }\n\n            if (BeginsWith(line, \"#include \")) {\n                VAssert(Split(line, \" \").size() == 2);\n                line = \"#line 1 1\\n\" + PreProcessShader(GetSharePath(\"shaders/\" + Split(line, \" \")[1]));\n                // Sometimes, the reported line number for a syntax error will be incorrect.\n                // This is a bug in the glsl compiler.\n                line += \"\\n#line \" + std::to_string(lineNum + 1) + \" 0\";\n            }\n        }\n        lineNum++;\n    }\n\n    return Join(lines, \"\\n\");\n}\n\nstd::vector<std::string> ShaderManager::GetShaderDependencies(const std::string &path)\n{\n    vector<string> deps = {path};\n    string         source = FileUtils::ReadFileToString(path);\n    auto           lines = Split(source, \"\\n\");\n    for (const string &line : lines) {\n        if (BeginsWith(line, \"#include \")) {\n            auto args = Split(line, \" \");\n            VAssert(args.size() == 2);\n            string include = args[1];\n            STLUtils::AppendTo(deps, GetShaderDependencies(GetSharePath(\"shaders/\" + include)));\n        }\n    }\n    return deps;\n}\n"
  },
  {
    "path": "lib/render/ShaderProgram.cpp",
    "content": "#include \"vapor/glutil.h\"    // Must be included first!!!\n#include \"vapor/ShaderProgram.h\"\n#include \"vapor/FileUtils.h\"\n#include \"vapor/VAssert.h\"\n#include <glm/glm.hpp>\n#include <glm/gtc/type_ptr.hpp>\n#include <vapor/Shader.h>\n#include <vapor/Texture.h>\n\nusing namespace VAPoR;\nusing std::string;\nusing std::vector;\n\nShaderProgram::Policy ShaderProgram::UniformNotFoundPolicy = ShaderProgram::Policy::Relaxed;\n\nShaderProgram::ShaderProgram() : _linked(false), _successStatus(false) {}\n\nShaderProgram::~ShaderProgram()\n{\n    if (_id) glDeleteProgram(_id);\n    for (int i = 0; i < _shaders.size(); i++)\n        if (_shaders[i]) delete _shaders[i];\n}\n\nint ShaderProgram::Link()\n{\n    if (_linked) { return 1; }\n    _id = glCreateProgram();\n    VAssert(_id);\n    for (auto it = _shaders.begin(); it != _shaders.end(); it++) {\n        if (*it == nullptr || !(*it)->WasCompilationSuccessful()) { return -1; }\n        glAttachShader(_id, (*it)->GetID());\n    }\n    glLinkProgram(_id);\n    glGetProgramiv(_id, GL_LINK_STATUS, &_successStatus);\n    _linked = true;\n\n    for (int i = 0; i < _shaders.size(); i++) { delete _shaders[i]; }\n    _shaders.clear();\n\n    if (!_successStatus) return -1;\n\n    ComputeSamplerLocations();\n\n    return 1;\n}\n\nvoid ShaderProgram::Bind()\n{\n    if (WasLinkingSuccessful()) glUseProgram(_id);\n}\n\nbool ShaderProgram::IsBound() const { return _id == GetBoundProgramID(); }\n\nvoid ShaderProgram::UnBind() { glUseProgram(0); }\n\nint ShaderProgram::GetBoundProgramID()\n{\n    int currentlyBoundProgramId;\n    glGetIntegerv(GL_CURRENT_PROGRAM, &currentlyBoundProgramId);\n    return currentlyBoundProgramId;\n}\n\nvoid ShaderProgram::AddShader(Shader *s)\n{\n    if (_linked) {\n        SetErrMsg(\"Program already linked\");\n        return;\n    }\n    _shaders.push_back(s);\n}\n\nint ShaderProgram::AddShaderFromSource(unsigned int type, const char *source)\n{\n    Shader *s = new Shader(type);\n    int     ret = s->CompileFromSource(source);\n    _shaders.push_back(s);\n    return ret;\n}\n\n/*\nbool ShaderProgram::AddShaderFromFile(unsigned int type, const std::string path)\n{\n    Shader *s = new Shader(type);\n    bool ret = s->CompileFromSource(FileUtils::ReadFileToString(path));\n    _shaders.push_back(s);\n    return ret;\n}\n */\n\nunsigned int ShaderProgram::GetID() const { return _id; }\nunsigned int ShaderProgram::WasLinkingSuccessful() const { return _successStatus; }\n\nint ShaderProgram::GetAttributeLocation(const std::string &name) const { return glGetAttribLocation(_id, name.c_str()); }\n\nint ShaderProgram::GetUniformLocation(const std::string &name) const { return glGetUniformLocation(_id, name.c_str()); }\n\nbool ShaderProgram::HasUniform(const std::string &name) const { return GetUniformLocation(name) != -1; }\n\ntemplate<typename T> bool ShaderProgram::SetUniform(const std::string &name, const T &value) const\n{\n    //    if ((typeid(T) == typeid(int)) && _samplerLocations.count(name)) printf(\"%s set to %i\\n\", name.c_str(), *(int*)((void*)&value));\n\n    if (!IsBound()) {\n        VAssert(!\"Program not bound\");\n        return false;\n    }\n    const int location = glGetUniformLocation(_id, name.c_str());\n    if (location == -1) {\n        // printf(\"Uniform \\\"%s\\\" not found\\n\", name.c_str());\n        if (UniformNotFoundPolicy == Policy::Strict) VAssert(!\"Uniform name not found\");\n        return false;\n    }\n    SetUniform(location, value);\n    return true;\n}\ntemplate bool ShaderProgram::SetUniform<int>(const std::string &name, const int &value) const;\ntemplate bool ShaderProgram::SetUniform<bool>(const std::string &name, const bool &value) const;\ntemplate bool ShaderProgram::SetUniform<float>(const std::string &name, const float &value) const;\ntemplate bool ShaderProgram::SetUniform<glm::vec2>(const std::string &name, const glm::vec2 &value) const;\ntemplate bool ShaderProgram::SetUniform<glm::vec3>(const std::string &name, const glm::vec3 &value) const;\ntemplate bool ShaderProgram::SetUniform<glm::vec4>(const std::string &name, const glm::vec4 &value) const;\ntemplate bool ShaderProgram::SetUniform<glm::mat4>(const std::string &name, const glm::mat4 &value) const;\ntemplate bool ShaderProgram::SetUniform<glm::ivec2>(const std::string &name, const glm::ivec2 &value) const;\ntemplate bool ShaderProgram::SetUniform<glm::ivec3>(const std::string &name, const glm::ivec3 &value) const;\ntemplate bool ShaderProgram::SetUniform<vector<float>>(const std::string &name, const vector<float> &value) const;\n\nvoid ShaderProgram::SetUniform(int location, const int &value) const { glUniform1i(location, value); }\nvoid ShaderProgram::SetUniform(int location, const float &value) const { glUniform1f(location, value); }\nvoid ShaderProgram::SetUniform(int location, const glm::vec2 &value) const { glUniform2fv(location, 1, glm::value_ptr(value)); }\nvoid ShaderProgram::SetUniform(int location, const glm::vec3 &value) const { glUniform3fv(location, 1, glm::value_ptr(value)); }\nvoid ShaderProgram::SetUniform(int location, const glm::vec4 &value) const { glUniform4fv(location, 1, glm::value_ptr(value)); }\nvoid ShaderProgram::SetUniform(int location, const glm::mat4 &value) const { glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value)); }\nvoid ShaderProgram::SetUniform(int location, const glm::ivec2 &value) const { glUniform2iv(location, 1, glm::value_ptr(value)); }\nvoid ShaderProgram::SetUniform(int location, const glm::ivec3 &value) const { glUniform3iv(location, 1, glm::value_ptr(value)); }\nvoid ShaderProgram::SetUniform(int location, const vector<float> &value) const { glUniform1fv(location, value.size(), value.data()); }\n\ntemplate<typename T> void ShaderProgram::SetUniformArray(const std::string &name, int count, const T *values) const { SetUniformArray(GetUniformLocation(name), count, values); }\ntemplate void             ShaderProgram::SetUniformArray<int>(const std::string &name, int count, const int *values) const;\ntemplate void             ShaderProgram::SetUniformArray<float>(const std::string &name, int count, const float *values) const;\ntemplate void             ShaderProgram::SetUniformArray<glm::vec3>(const std::string &name, int count, const glm::vec3 *values) const;\ntemplate void             ShaderProgram::SetUniformArray<glm::vec4>(const std::string &name, int count, const glm::vec4 *values) const;\n\nvoid ShaderProgram::SetUniformArray(int location, int count, const int *values) const { glUniform1iv(location, count, values); }\nvoid ShaderProgram::SetUniformArray(int location, int count, const float *values) const { glUniform1fv(location, count, values); }\nvoid ShaderProgram::SetUniformArray(int location, int count, const glm::vec3 *values) const { glUniform3fv(location, count, (float *)values); }\nvoid ShaderProgram::SetUniformArray(int location, int count, const glm::vec4 *values) const { glUniform4fv(location, count, (float *)values); }\n\ntemplate<typename T> bool ShaderProgram::SetSampler(const std::string &name, const T &value) const\n{\n    auto itr = _samplerLocations.find(name);\n    if (itr == _samplerLocations.end()) return false;\n    int textureUnit = itr->second;\n\n    glActiveTexture(GL_TEXTURE0 + textureUnit);\n    value.Bind();\n    SetUniform(name, textureUnit);\n\n    glActiveTexture(GL_TEXTURE0);\n\n    return true;\n}\ntemplate bool ShaderProgram::SetSampler<Texture1D>(const std::string &name, const Texture1D &value) const;\ntemplate bool ShaderProgram::SetSampler<Texture2D>(const std::string &name, const Texture2D &value) const;\ntemplate bool ShaderProgram::SetSampler<Texture3D>(const std::string &name, const Texture3D &value) const;\ntemplate bool ShaderProgram::SetSampler<Texture2DArray>(const std::string &name, const Texture2DArray &value) const;\n\nstd::string ShaderProgram::GetLog() const\n{\n    if (_linked) {\n        char buf[512];\n        glGetProgramInfoLog(_id, 512, NULL, buf);\n        return std::string(buf);\n    } else {\n        if (_shaders.empty())\n            return \"Cannot linked because there are no shaders\";\n        else\n            return \"Cannot link because shader failed to compile\";\n    }\n}\n\nvoid ShaderProgram::PrintUniforms() const\n{\n    GLint  count;\n    GLint  size;\n    GLenum type;\n    char   name[64];\n    int    nameLength;\n\n    glGetProgramiv(_id, GL_ACTIVE_UNIFORMS, &count);\n    for (int i = 0; i < count; i++) {\n        glGetActiveUniform(_id, i, 64, &nameLength, &size, &type, name);\n        printf(\"%s %s\\n\", GLTypeToString(type), name);\n    }\n}\n\nvoid ShaderProgram::ComputeSamplerLocations()\n{\n    GLint  count;\n    GLint  size;\n    GLenum type;\n    char   name[128];\n    int    nameLength;\n    int    samplerId = 1;    // Starting at 1 fixes some super weird GL bug\n\n    glGetProgramiv(_id, GL_ACTIVE_UNIFORMS, &count);\n    for (int i = 0; i < count; i++) {\n        glGetActiveUniform(_id, i, 128, &nameLength, &size, &type, name);\n        if (IsGLTypeSampler(type)) _samplerLocations[string(name)] = samplerId++;\n    }\n    VAssert(samplerId <= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1);\n}\n\nconst char *ShaderProgram::GLTypeToString(const unsigned int type)\n{\n    switch (type) {\n    case GL_FLOAT: return \"float\";\n    case GL_FLOAT_VEC2: return \"vec2\";\n    case GL_FLOAT_VEC3: return \"vec3\";\n    case GL_FLOAT_VEC4: return \"vec4\";\n    case GL_DOUBLE: return \"double\";\n    case GL_DOUBLE_VEC2: return \"dvec2\";\n    case GL_DOUBLE_VEC3: return \"dvec3\";\n    case GL_DOUBLE_VEC4: return \"dvec4\";\n    case GL_INT: return \"int\";\n    case GL_INT_VEC2: return \"ivec2\";\n    case GL_INT_VEC3: return \"ivec3\";\n    case GL_INT_VEC4: return \"ivec4\";\n    case GL_UNSIGNED_INT: return \"unsigned int\";\n    case GL_UNSIGNED_INT_VEC2: return \"uvec2\";\n    case GL_UNSIGNED_INT_VEC3: return \"uvec3\";\n    case GL_UNSIGNED_INT_VEC4: return \"uvec4\";\n    case GL_BOOL: return \"bool\";\n    case GL_BOOL_VEC2: return \"bvec2\";\n    case GL_BOOL_VEC3: return \"bvec3\";\n    case GL_BOOL_VEC4: return \"bvec4\";\n    case GL_FLOAT_MAT2: return \"mat2\";\n    case GL_FLOAT_MAT3: return \"mat3\";\n    case GL_FLOAT_MAT4: return \"mat4\";\n    case GL_FLOAT_MAT2x3: return \"mat2x3\";\n    case GL_FLOAT_MAT2x4: return \"mat2x4\";\n    case GL_FLOAT_MAT3x2: return \"mat3x2\";\n    case GL_FLOAT_MAT3x4: return \"mat3x4\";\n    case GL_FLOAT_MAT4x2: return \"mat4x2\";\n    case GL_FLOAT_MAT4x3: return \"mat4x3\";\n    case GL_DOUBLE_MAT2: return \"dmat2\";\n    case GL_DOUBLE_MAT3: return \"dmat3\";\n    case GL_DOUBLE_MAT4: return \"dmat4\";\n    case GL_DOUBLE_MAT2x3: return \"dmat2x3\";\n    case GL_DOUBLE_MAT2x4: return \"dmat2x4\";\n    case GL_DOUBLE_MAT3x2: return \"dmat3x2\";\n    case GL_DOUBLE_MAT3x4: return \"dmat3x4\";\n    case GL_DOUBLE_MAT4x2: return \"dmat4x2\";\n    case GL_DOUBLE_MAT4x3: return \"dmat4x3\";\n    case GL_SAMPLER_1D: return \"sampler1D\";\n    case GL_SAMPLER_2D: return \"sampler2D\";\n    case GL_SAMPLER_3D: return \"sampler3D\";\n    case GL_SAMPLER_CUBE: return \"samplerCube\";\n    case GL_SAMPLER_1D_SHADOW: return \"sampler1DShadow\";\n    case GL_SAMPLER_2D_SHADOW: return \"sampler2DShadow\";\n    case GL_SAMPLER_1D_ARRAY: return \"sampler1DArray\";\n    case GL_SAMPLER_2D_ARRAY: return \"sampler2DArray\";\n    case GL_SAMPLER_1D_ARRAY_SHADOW: return \"sampler1DArrayShadow\";\n    case GL_SAMPLER_2D_ARRAY_SHADOW: return \"sampler2DArrayShadow\";\n    case GL_SAMPLER_2D_MULTISAMPLE: return \"sampler2DMS\";\n    case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return \"sampler2DMSArray\";\n    case GL_SAMPLER_CUBE_SHADOW: return \"samplerCubeShadow\";\n    case GL_SAMPLER_BUFFER: return \"samplerBuffer\";\n    case GL_SAMPLER_2D_RECT: return \"sampler2DRect\";\n    case GL_SAMPLER_2D_RECT_SHADOW: return \"sampler2DRectShadow\";\n    case GL_INT_SAMPLER_1D: return \"isampler1D\";\n    case GL_INT_SAMPLER_2D: return \"isampler2D\";\n    case GL_INT_SAMPLER_3D: return \"isampler3D\";\n    case GL_INT_SAMPLER_CUBE: return \"isamplerCube\";\n    case GL_INT_SAMPLER_1D_ARRAY: return \"isampler1DArray\";\n    case GL_INT_SAMPLER_2D_ARRAY: return \"isampler2DArray\";\n    case GL_INT_SAMPLER_2D_MULTISAMPLE: return \"isampler2DMS\";\n    case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return \"isampler2DMSArray\";\n    case GL_INT_SAMPLER_BUFFER: return \"isamplerBuffer\";\n    case GL_INT_SAMPLER_2D_RECT: return \"isampler2DRect\";\n    case GL_UNSIGNED_INT_SAMPLER_1D: return \"usampler1D\";\n    case GL_UNSIGNED_INT_SAMPLER_2D: return \"usampler2D\";\n    case GL_UNSIGNED_INT_SAMPLER_3D: return \"usampler3D\";\n    case GL_UNSIGNED_INT_SAMPLER_CUBE: return \"usamplerCube\";\n    case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return \"usampler2DArray\";\n    case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return \"usampler2DArray\";\n    case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return \"usampler2DMS\";\n    case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return \"usampler2DMSArray\";\n    case GL_UNSIGNED_INT_SAMPLER_BUFFER: return \"usamplerBuffer\";\n    case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return \"usampler2DRect\";\n#ifdef GL_IMAGE_1D\n    case GL_IMAGE_1D: return \"image1D\";\n    case GL_IMAGE_2D: return \"image2D\";\n    case GL_IMAGE_3D: return \"image3D\";\n    case GL_IMAGE_2D_RECT: return \"image2DRect\";\n    case GL_IMAGE_CUBE: return \"imageCube\";\n    case GL_IMAGE_BUFFER: return \"imageBuffer\";\n    case GL_IMAGE_1D_ARRAY: return \"image1DArray\";\n    case GL_IMAGE_2D_ARRAY: return \"image2DArray\";\n    case GL_IMAGE_2D_MULTISAMPLE: return \"image2DMS\";\n    case GL_IMAGE_2D_MULTISAMPLE_ARRAY: return \"image2DMSArray\";\n    case GL_INT_IMAGE_1D: return \"iimage1D\";\n    case GL_INT_IMAGE_2D: return \"iimage2D\";\n    case GL_INT_IMAGE_3D: return \"iimage3D\";\n    case GL_INT_IMAGE_2D_RECT: return \"iimage2DRect\";\n    case GL_INT_IMAGE_CUBE: return \"iimageCube\";\n    case GL_INT_IMAGE_BUFFER: return \"iimageBuffer\";\n    case GL_INT_IMAGE_1D_ARRAY: return \"iimage1DArray\";\n    case GL_INT_IMAGE_2D_ARRAY: return \"iimage2DArray\";\n    case GL_INT_IMAGE_2D_MULTISAMPLE: return \"iimage2DMS\";\n    case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return \"iimage2DMSArray\";\n    case GL_UNSIGNED_INT_IMAGE_1D: return \"uimage1D\";\n    case GL_UNSIGNED_INT_IMAGE_2D: return \"uimage2D\";\n    case GL_UNSIGNED_INT_IMAGE_3D: return \"uimage3D\";\n    case GL_UNSIGNED_INT_IMAGE_2D_RECT: return \"uimage2DRect\";\n    case GL_UNSIGNED_INT_IMAGE_CUBE: return \"uimageCube\";\n    case GL_UNSIGNED_INT_IMAGE_BUFFER: return \"uimageBuffer\";\n    case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: return \"uimage1DArray\";\n    case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: return \"uimage2DArray\";\n    case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: return \"uimage2DMS\";\n    case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return \"uimage2DMSArray\";\n    case GL_UNSIGNED_INT_ATOMIC_COUNTER: return \"atomic_uint\";\n#endif\n    default: return \"INVALID ENUM\";\n    }\n}\n\nbool ShaderProgram::IsGLTypeSampler(const unsigned int type)\n{\n    switch (type) {\n    case GL_SAMPLER_1D:\n    case GL_SAMPLER_2D:\n    case GL_SAMPLER_3D:\n    case GL_SAMPLER_CUBE:\n    case GL_SAMPLER_1D_SHADOW:\n    case GL_SAMPLER_2D_SHADOW:\n    case GL_SAMPLER_1D_ARRAY:\n    case GL_SAMPLER_2D_ARRAY:\n    case GL_SAMPLER_1D_ARRAY_SHADOW:\n    case GL_SAMPLER_2D_ARRAY_SHADOW:\n    case GL_SAMPLER_2D_MULTISAMPLE:\n    case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:\n    case GL_SAMPLER_CUBE_SHADOW:\n    case GL_SAMPLER_BUFFER:\n    case GL_SAMPLER_2D_RECT:\n    case GL_SAMPLER_2D_RECT_SHADOW:\n    case GL_INT_SAMPLER_1D:\n    case GL_INT_SAMPLER_2D:\n    case GL_INT_SAMPLER_3D:\n    case GL_INT_SAMPLER_CUBE:\n    case GL_INT_SAMPLER_1D_ARRAY:\n    case GL_INT_SAMPLER_2D_ARRAY:\n    case GL_INT_SAMPLER_2D_MULTISAMPLE:\n    case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:\n    case GL_INT_SAMPLER_BUFFER:\n    case GL_INT_SAMPLER_2D_RECT:\n    case GL_UNSIGNED_INT_SAMPLER_1D:\n    case GL_UNSIGNED_INT_SAMPLER_2D:\n    case GL_UNSIGNED_INT_SAMPLER_3D:\n    case GL_UNSIGNED_INT_SAMPLER_CUBE:\n    case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:\n    case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:\n    case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:\n    case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:\n    case GL_UNSIGNED_INT_SAMPLER_BUFFER:\n    case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return true;\n    default: return false;\n    }\n}\n\nSmartShaderProgram::SmartShaderProgram(ShaderProgram *program) : _program(program)\n{\n    if (_program) _program->Bind();\n}\n\nSmartShaderProgram::~SmartShaderProgram()\n{\n    if (_program) _program->UnBind();\n}\n\nbool SmartShaderProgram::IsValid() const { return _program; }\n"
  },
  {
    "path": "lib/render/SliceRenderer.cpp",
    "content": "#include <sstream>\n#include <string>\n#include <limits>\n#include <ctime>\n#include <iomanip>\n\n#include <vapor/SliceRenderer.h>\n#include <vapor/SliceParams.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/LegacyGL.h>\n#include <vapor/GLManager.h>\n#include <vapor/ResourcePath.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/ArbitrarilyOrientedRegularGrid.h>\n\n#define X  0\n#define Y  1\n#define Z  2\n#define XY 0\n#define XZ 1\n#define YZ 2\n\nusing namespace VAPoR;\n\nstatic vector<double> ToDoubleVec(const glm::vec3 &v)\n{\n    vector<double> c(v.length());\n    for (int i = 0; i < v.length(); i++) c[i] = v[i];\n    return c;\n}\n\nstatic RendererRegistrar<SliceRenderer> registrar(SliceRenderer::GetClassType(), SliceParams::GetClassType());\n\nSliceRenderer::SliceRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instanceName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, SliceParams::GetClassType(), SliceRenderer::GetClassType(), instanceName, dataMgr)\n{\n    _initialized = false;\n\n    _windingOrder = {0.0f, 0.0f, 0.f, 1.0f, 0.0f, 0.f, 0.0f, 1.0f, 0.f, 1.0f, 0.0f, 0.f, 1.0f, 1.0f, 0.f, 0.0f, 1.0f, 0.f};\n    _rectangle3D = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};\n\n    _VAO = 0;\n    _vertexVBO = 0;\n    _texCoordVBO = 0;\n    _colorMapTextureID = 0;\n    _dataValueTextureID = 0;\n\n    _cacheParams.textureSampleRate = 200;\n\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    VAssert(p);\n    MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName);\n    _colorMapSize = tf->getNumEntries();\n}\n\nSliceRenderer::~SliceRenderer()\n{\n    if (_VAO != 0) {\n        glDeleteVertexArrays(1, &_VAO);\n        _VAO = 0;\n    }\n\n    if (_vertexVBO != 0) {\n        glDeleteBuffers(1, &_vertexVBO);\n        _vertexVBO = 0;\n    }\n\n    if (_texCoordVBO != 0) {\n        glDeleteBuffers(1, &_texCoordVBO);\n        _texCoordVBO = 0;\n    }\n\n    if (_colorMapTextureID != 0) {\n        glDeleteTextures(1, &_colorMapTextureID);\n        _colorMapTextureID = 0;\n    }\n\n    if (_dataValueTextureID != 0) {\n        glDeleteTextures(1, &_dataValueTextureID);\n        _dataValueTextureID = 0;\n    }\n}\n\nint SliceRenderer::_initializeGL()\n{\n    _initVAO();\n    _initTexCoordVBO();\n    _initVertexVBO();\n\n    _initialized = true;\n\n    return 0;\n}\n\nvoid SliceRenderer::_initVAO()\n{\n    glGenVertexArrays(1, &_VAO);\n    glBindVertexArray(_VAO);\n}\n\nvoid SliceRenderer::_initTexCoordVBO()\n{\n    if (_texCoordVBO != 0) glDeleteBuffers(1, &_texCoordVBO);\n\n    glGenBuffers(1, &_texCoordVBO);\n    glBindBuffer(GL_ARRAY_BUFFER, _texCoordVBO);\n    glVertexAttribPointer(1, 2, GL_DOUBLE, GL_FALSE, 0, (void *)0);\n    glEnableVertexAttribArray(1);\n    glBufferData(GL_ARRAY_BUFFER, sizeof(double) * _rectangle3D.size(), _rectangle3D.data(), GL_DYNAMIC_DRAW);\n}\n\nvoid SliceRenderer::_initVertexVBO()\n{\n    if (_vertexVBO != 0) glDeleteBuffers(1, &_vertexVBO);\n\n    glGenBuffers(1, &_vertexVBO);\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexVBO);\n    glVertexAttribPointer(0, 3, GL_DOUBLE, GL_FALSE, 0, (void *)0);\n    glEnableVertexAttribArray(0);\n    glBufferData(GL_ARRAY_BUFFER, 6 * 3 * sizeof(double), _windingOrder.data(), GL_STATIC_DRAW);\n}\n\nvoid SliceRenderer::_resetCache()\n{\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    VAssert(p);\n\n    _cacheParams.varName = p->GetVariableName();\n    _cacheParams.heightVarName = p->GetHeightVariableName();\n    _cacheParams.ts = p->GetCurrentTimestep();\n    _cacheParams.refinementLevel = p->GetRefinementLevel();\n    _cacheParams.compressionLevel = p->GetCompressionLevel();\n    _cacheParams.orientation = p->GetBox()->GetOrientation();\n\n    _cacheParams.xRotation = p->GetValueDouble(RenderParams::XSlicePlaneRotationTag, 0);\n    _cacheParams.yRotation = p->GetValueDouble(RenderParams::YSlicePlaneRotationTag, 0);\n    _cacheParams.zRotation = p->GetValueDouble(RenderParams::ZSlicePlaneRotationTag, 0);\n\n    _cacheParams.xOrigin = p->GetXSlicePlaneOrigin();\n    _cacheParams.yOrigin = p->GetYSlicePlaneOrigin();\n    _cacheParams.zOrigin = p->GetZSlicePlaneOrigin();\n\n\n    _cacheParams.textureSampleRate = p->GetValueDouble(RenderParams::SampleRateTag, 200);\n    _cacheParams.sliceOrientationMode = p->GetValueLong(RenderParams::SlicePlaneOrientationModeTag, 0);\n\n    _cacheParams.sliceRotation = p->GetSlicePlaneRotation();\n    _cacheParams.sliceNormal = p->GetSlicePlaneNormal();\n    _cacheParams.sliceOffset = p->GetValueDouble(p->SliceOffsetTag, 0);\n\n    _getExtents(_cacheParams.boxMin, _cacheParams.boxMax);\n\n    // clang-format off\n    _dataMgr->GetVariableExtents(_cacheParams.ts, \n                                 _cacheParams.varName, \n                                 _cacheParams.refinementLevel, \n                                 _cacheParams.compressionLevel, \n                                 _cacheParams.domainMin, \n                                 _cacheParams.domainMax\n    );\n    // clang-format on\n}\n\nvoid SliceRenderer::_resetColormapCache()\n{\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    VAssert(p);\n\n    MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName);\n    tf->makeLut(_cacheParams.tf_lut);\n    _cacheParams.tf_minMax = tf->getMinMaxMapValue();\n\n    if (_colorMapTextureID != 0) glDeleteTextures(1, &_colorMapTextureID);\n\n    glGenTextures(1, &_colorMapTextureID);\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTextureID);\n#ifdef DEBUG\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n#else\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n#endif\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA8, _colorMapSize, 0, GL_RGBA, GL_FLOAT, &_cacheParams.tf_lut[0]);\n}\n\n// clang-format off\n\nint SliceRenderer::_regenerateSlice()\n{\n    Grid *grid3d = nullptr;\n    int   rc = _getGrid3D(grid3d);\n    if (rc < 0) return -1;\n\n    // Get data values from a slice\n    std::shared_ptr<float> dataValues(new float[_textureSideSize * _textureSideSize]);\n    planeDescription       pd;\n    pd.sideSize = _textureSideSize;\n\n    if (_cacheParams.sliceOrientationMode == (int)RenderParams::SlicePlaneOrientationMode::Normal)\n        pd.normal = _cacheParams.sliceNormal;\n    else\n        pd.normal = ToDoubleVec(ArbitrarilyOrientedRegularGrid::GetNormalFromRotations(_cacheParams.sliceRotation));\n\n    glm::vec3 o = {_cacheParams.xOrigin, _cacheParams.yOrigin, _cacheParams.zOrigin};\n    glm::vec3 n = {pd.normal[0], pd.normal[1], pd.normal[2]};\n    glm::vec3 offsetOrigin = o + n * (float)_cacheParams.sliceOffset;\n    pd.origin = ToDoubleVec(offsetOrigin);\n\n    pd.boxMin = _cacheParams.boxMin;\n    pd.boxMax = _cacheParams.boxMax;\n\n    VAPoR::DimsType dims = { (size_t)_textureSideSize, (size_t)_textureSideSize, 1 };\n\n    ArbitrarilyOrientedRegularGrid* slice = new ArbitrarilyOrientedRegularGrid(\n        grid3d,\n        pd,\n        dims\n    );\n\n    CoordType corner1, corner2, corner3, corner4;\n    slice->GetUserCoordinates( {0,                  0,                  0}, corner1);\n    slice->GetUserCoordinates( {0,                  _textureSideSize-1, 0}, corner2);\n    slice->GetUserCoordinates( {_textureSideSize-1, 0,                  0}, corner3);\n    slice->GetUserCoordinates( {_textureSideSize-1, _textureSideSize-1, 0}, corner4);\n\n    _windingOrder = {corner1[0], corner1[1], corner1[2],\n                     corner3[0], corner3[1], corner3[2],\n                     corner2[0], corner2[1], corner2[2],\n                     corner3[0], corner3[1], corner3[2],\n                     corner4[0], corner4[1], corner4[2],\n                     corner2[0], corner2[1], corner2[2]};\n\n    _rectangle3D  = {corner1[0], corner1[1], corner1[2],\n                     corner3[0], corner3[1], corner3[2],\n                     corner4[0], corner4[1], corner4[2],\n                     corner2[0], corner2[1], corner2[2]};\n\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    std::vector<CoordType> sliceQuad = { {corner1[0], corner1[1], corner1[2]},\n                                         {corner3[0], corner3[1], corner3[2]},\n                                         {corner4[0], corner4[1], corner4[2]},\n                                         {corner2[0], corner2[1], corner2[2]}};\n    p->SetSlicePlaneQuad(sliceQuad);\n\n    delete grid3d;\n    if (slice == nullptr) {\n        Wasp::MyBase::SetErrMsg(\"Unable to perform SliceGridAlongPlane() with current Grid\");\n        return -1;\n    }\n\n    // Apply opacity to missing values\n    float missingValue = slice->GetMissingValue();\n    int                    textureSize = 2 * _textureSideSize * _textureSideSize;\n    std::unique_ptr<float> textureValues(new float[textureSize]);\n    for (size_t i = 0; i < textureSize / 2; i++) {\n        DimsType dim = {i%_textureSideSize, i/_textureSideSize, 0};\n        float dataValue = slice->GetValueAtIndex( dim );\n        if (dataValue == missingValue)\n            textureValues.get()[i * 2 + 1] = 1.f;\n        else\n            textureValues.get()[i * 2 + 1] = 0.f;\n\n        textureValues.get()[i * 2] = dataValue;\n    }\n\n    _createDataTexture(textureValues);\n\n    delete slice;\n\n    return 0;\n}\n\n// clang-format on\n\nint SliceRenderer::_getGrid3D(Grid *&grid3d) const\n{\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    int          rLevel = p->GetRefinementLevel();\n    int          cLevel = p->GetCompressionLevel();\n    int          rc = DataMgrUtils::GetGrids(_dataMgr, p->GetCurrentTimestep(), p->GetVariableName(), _cacheParams.boxMin, _cacheParams.boxMax, true, &rLevel, &cLevel, &grid3d);\n    if (rc < 0) {\n        Wasp::MyBase::SetErrMsg(\"Unable to acquire Grid for Slice texture\");\n        return rc;\n    }\n    VAssert(grid3d);\n    grid3d->SetInterpolationOrder(1);\n\n    return 0;\n}\n\nvoid SliceRenderer::_createDataTexture(std::unique_ptr<float> &dataValues)\n{\n    if (_dataValueTextureID != 0) glDeleteTextures(1, &_dataValueTextureID);\n\n    glGenTextures(1, &_dataValueTextureID);\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, _dataValueTextureID);\n#ifdef DEBUG\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n#else\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n#endif\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, _textureSideSize, _textureSideSize, 0, GL_RG, GL_FLOAT, dataValues.get());\n\n    glBindBuffer(GL_ARRAY_BUFFER, _vertexVBO);\n    glBufferSubData(GL_ARRAY_BUFFER, 0, 6 * 3 * sizeof(double), _windingOrder.data());\n}\n\nbool SliceRenderer::_isDataCacheDirty() const\n{\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    VAssert(p);\n\n    if (_cacheParams.varName != p->GetVariableName()) return true;\n    if (_cacheParams.heightVarName != p->GetHeightVariableName()) return true;\n    if (_cacheParams.ts != p->GetCurrentTimestep()) return true;\n    if (_cacheParams.refinementLevel != p->GetRefinementLevel()) return true;\n    if (_cacheParams.compressionLevel != p->GetCompressionLevel()) return true;\n\n    if (_cacheParams.xRotation != p->GetValueDouble(RenderParams::XSlicePlaneRotationTag, 0)) return true;\n    if (_cacheParams.yRotation != p->GetValueDouble(RenderParams::YSlicePlaneRotationTag, 0)) return true;\n    if (_cacheParams.zRotation != p->GetValueDouble(RenderParams::ZSlicePlaneRotationTag, 0)) return true;\n\n    if (_cacheParams.xOrigin != p->GetXSlicePlaneOrigin()) return true;\n    if (_cacheParams.yOrigin != p->GetYSlicePlaneOrigin()) return true;\n    if (_cacheParams.zOrigin != p->GetZSlicePlaneOrigin()) return true;\n\n    if (_cacheParams.sliceOffset != p->GetValueDouble(p->SliceOffsetTag, 0)) return true;\n    if (_cacheParams.sliceNormal != p->GetSlicePlaneNormal()) return true;\n    if (_cacheParams.sliceOrientationMode != p->GetValueLong(RenderParams::SlicePlaneOrientationModeTag, 0)) return true;\n\n    if (_cacheParams.textureSampleRate != p->GetValueDouble(RenderParams::SampleRateTag, 200)) return true;\n\n    return false;\n}\n\nbool SliceRenderer::_isColormapCacheDirty() const\n{\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    VAssert(p);\n\n    MapperFunction *tf = p->GetMapperFunc(_cacheParams.varName);\n    vector<float>   tf_lut;\n    tf->makeLut(tf_lut);\n    if (_cacheParams.tf_lut != tf_lut) return true;\n    if (_cacheParams.tf_minMax != tf->getMinMaxMapValue()) return true;\n    return false;\n}\n\nbool SliceRenderer::_isBoxCacheDirty() const\n{\n    VAPoR::CoordType min, max;\n    _getExtents(min, max);\n\n    if (_cacheParams.boxMin != min) return true;\n    if (_cacheParams.boxMax != max) return true;\n    return false;\n}\n\nvoid SliceRenderer::_getExtents(VAPoR::CoordType &min, VAPoR::CoordType &max) const\n{\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    VAssert(p);\n    Box *box = p->GetBox();\n\n    box->GetExtents(min, max);\n    VAssert(min.size() == 3);\n    VAssert(max.size() == 3);\n}\n\nint SliceRenderer::_paintGL(bool fast)\n{\n    int rc = 0;\n\n    glDepthMask(GL_TRUE);\n    glEnable(GL_DEPTH_TEST);\n\n\n#ifdef DEBUG\n    _drawDebugPolygons();\n#endif\n\n    glEnable(GL_DEPTH_TEST);\n    glDepthMask(GL_FALSE);\n\n    _initializeState();\n\n    if (_isDataCacheDirty() || _isBoxCacheDirty()) {\n        _resetCache();\n\n        // If we're in fast mode, degrade the quality of the slice for better interactivity\n        if (fast) {\n            _textureSideSize = 50;\n        } else {\n            _textureSideSize = _cacheParams.textureSampleRate;\n        }\n\n        int rc = _regenerateSlice();\n        if (rc < 0) return -1;\n    }\n\n    if (_isColormapCacheDirty()) _resetColormapCache();\n\n    _configureShader();\n    if (CheckGLError() != 0) {\n        _resetState();\n        return -1;\n    }\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, _colorMapTextureID);\n\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, _dataValueTextureID);\n\n    glBindVertexArray(_VAO);\n    glDrawArrays(GL_TRIANGLES, 0, 6);\n\n    _resetState();\n\n    if (CheckGLError() != 0) { return -1; }\n\n    return rc;\n}\n\n#ifdef DEBUG\nvoid SliceRenderer::_drawDebugPolygons()\n{\n    // 3D yellow enclosing rectangle that defines the perimeter of our texture\n    // This can and often will extend beyond the Box\n    // std::vector<glm::vec3> rectangle = _slicer->GetRectangle();\n    LegacyGL *lgl = _glManager->legacy;\n    lgl->Begin(GL_LINES);\n    lgl->Color4f(1., 1., 0., 1.);\n    lgl->Vertex3f(_rectangle3D[0], _rectangle3D[1], _rectangle3D[2]);\n    lgl->Vertex3f(_rectangle3D[3], _rectangle3D[4], _rectangle3D[5]);\n\n    lgl->Vertex3f(_rectangle3D[3], _rectangle3D[4], _rectangle3D[5]);\n    lgl->Vertex3f(_rectangle3D[6], _rectangle3D[7], _rectangle3D[8]);\n\n    lgl->Vertex3f(_rectangle3D[6], _rectangle3D[7], _rectangle3D[8]);\n    lgl->Vertex3f(_rectangle3D[9], _rectangle3D[10], _rectangle3D[11]);\n\n    lgl->Vertex3f(_rectangle3D[9], _rectangle3D[10], _rectangle3D[11]);\n    lgl->Vertex3f(_rectangle3D[0], _rectangle3D[1], _rectangle3D[2]);\n    lgl->End();\n\n\n    // Winding order\n    double *wo = _windingOrder.data();\n    lgl = _glManager->legacy;\n    lgl->Begin(GL_LINES);\n    lgl->Color4f(0., 1., 0., 1.);    // green\n    lgl->Vertex3f(wo[0], wo[1], wo[2]);\n    lgl->Vertex3f(wo[3], wo[4], wo[5]);\n    lgl->Color4f(0., 1., 1., 1.);    // teal\n    lgl->Vertex3f(wo[3], wo[4], wo[5]);\n    lgl->Vertex3f(wo[6], wo[7], wo[8]);\n    lgl->Color4f(1., 1., 1., 1.);    // white\n    lgl->Vertex3f(wo[6], wo[7], wo[8]);\n    lgl->Vertex3f(wo[0], wo[1], wo[2]);\n\n    lgl->Color4f(.9, .9, 1., 1.);    // purple\n    lgl->Vertex3f(wo[9], wo[10], wo[11]);\n    lgl->Vertex3f(wo[12], wo[13], wo[14]);\n    lgl->Color4f(1., 0., 0., 1.);    // red\n    lgl->Vertex3f(wo[12], wo[13], wo[14]);\n    lgl->Vertex3f(wo[15], wo[16], wo[17]);\n    lgl->Color4f(0., 1., 1., 1.);    // yellow\n    lgl->Vertex3f(wo[15], wo[16], wo[17]);\n    lgl->Vertex3f(wo[9], wo[10], wo[11]);\n    lgl->End();\n}\n#endif\n\nvoid SliceRenderer::_configureShader()\n{\n    ShaderProgram *s = _glManager->shaderManager->GetShader(\"Slice\");\n    s->Bind();\n\n    // One vertex shader uniform vec4\n    s->SetUniform(\"MVP\", _glManager->matrixManager->GetModelViewProjectionMatrix());\n\n    // Remaining fragment shader uniform floats\n    SliceParams *p = dynamic_cast<SliceParams *>(GetActiveParams());\n    VAssert(p);\n    float opacity = p->GetConstantOpacity();\n    s->SetUniform(\"constantOpacity\", opacity);\n    s->SetUniform(\"minLUTValue\", (float)_cacheParams.tf_minMax[0]);\n    s->SetUniform(\"maxLUTValue\", (float)_cacheParams.tf_minMax[1]);\n\n    // And finally our uniform samplers\n    GLint colormapLocation;\n    colormapLocation = s->GetUniformLocation(\"colormap\");\n    glUniform1i(colormapLocation, 0);\n\n    GLint dataValuesLocation;\n    dataValuesLocation = s->GetUniformLocation(\"dataValues\");\n    glUniform1i(dataValuesLocation, 1);\n}\n\nvoid SliceRenderer::_initializeState()\n{\n    _glManager->matrixManager->MatrixModeModelView();\n    glEnable(GL_BLEND);\n    glEnable(GL_DEPTH_TEST);\n    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDepthMask(GL_TRUE);\n}\n\nvoid SliceRenderer::_resetState()\n{\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_2D, 0);\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, 0);\n\n    glBindVertexArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    ShaderProgram::UnBind();\n\n    glDisable(GL_BLEND);\n    glDisable(GL_DEPTH_TEST);\n    glDepthMask(GL_FALSE);\n}\n"
  },
  {
    "path": "lib/render/TIFWriter.cpp",
    "content": "#include \"vapor/TIFWriter.h\"\n#ifdef WIN32\n    #include <tiff/xtiffio.h>\n#endif\n\nusing namespace VAPoR;\n\nREGISTER_IMAGEWRITER(TIFWriter);\n\nstd::vector<std::string> TIFWriter::GetFileExtensions() { return {\"tif\", \"tiff\"}; }\n\nint TIFWriter::ConfigureWithFormat(ImageWriter::Format f)\n{\n    TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);\n\n    switch (f) {\n    case Format::RGB:\n        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);\n        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);\n        return 0;\n\n    default: MyBase::SetErrMsg(\"Unsupported format\"); return -1;\n    }\n}\n\nTIFWriter::TIFWriter(const std::string &path) : ImageWriter(path), tif(nullptr)\n{\n    tif = XTIFFOpen(path.c_str(), \"w\");\n    if (tif) opened = true;\n}\n\nTIFWriter::~TIFWriter()\n{\n    if (tif) XTIFFClose(tif);\n    tif = nullptr;\n}\n\nint TIFWriter::Write(const unsigned char *buffer, const unsigned int width, const unsigned int height)\n{\n    if (!opened) {\n        MyBase::SetErrMsg(\"Unable to open TIF file for writing: \\\"%s\\\"\", path.c_str());\n        return -1;\n    }\n\n    ConfigureWithFormat(format);\n\n    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);\n    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);\n    TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);\n    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);\n\n    int writeSuccess = TIFFWriteRawStrip(tif, 0, const_cast<unsigned char *>(buffer), width * height * 3);\n    if (writeSuccess < 0) {\n        SetErrMsg(\"TIFF write routine failed\");\n        return -1;\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "lib/render/TODO.txt",
    "content": "TwoDDataRender\n--------------\n\n+ add support for lighting, currently hard-coded to disabled\n\n\nControlExec\n-----------\n\nGetDataMgr() should return const \n"
  },
  {
    "path": "lib/render/TextLabel.cpp",
    "content": "#include \"vapor/glutil.h\"\n#include \"vapor/TextLabel.h\"\n#include \"vapor/GLManager.h\"\n#include <vapor/FontManager.h>\n#include \"vapor/LegacyGL.h\"\n\nusing namespace VAPoR;\nusing glm::vec2;\nusing glm::vec3;\nusing glm::vec4;\nusing std::string;\n\nTextLabel::TextLabel(GLManager *glManager, const std::string &fontName, unsigned int fontSize)\n: _glManager(glManager), FontName(fontName), FontSize(fontSize), BackgroundColor(0.f), ForegroundColor(1.f), HorizontalAlignment(Left), VerticalAlignment(Bottom), Padding(0)\n{\n}\n\nvoid TextLabel::DrawText(const glm::vec2 &position, const std::string &text) { DrawText(vec3(position, 0.f), text); }\n\nvoid TextLabel::DrawText(const glm::vec3 &position, const std::string &text)\n{\n    Font *         font = _glManager->fontManager->GetFont(FontName, FontSize);\n    MatrixManager *mm = _glManager->matrixManager;\n    LegacyGL *     lgl = _glManager->legacy;\n    glm::vec2      p = mm->ProjectToScreen(position);\n\n    GLint viewport[4] = {0};\n    glGetIntegerv(GL_VIEWPORT, viewport);\n\n    vec4  ndc = mm->GetModelViewProjectionMatrix() * vec4(position, 1.f);\n    float z = ndc.z / ndc.w;\n\n    mm->MatrixModeProjection();\n    mm->PushMatrix();\n    mm->Ortho(0, viewport[2], 0, viewport[3]);\n    mm->MatrixModeModelView();\n    mm->PushMatrix();\n    mm->LoadIdentity();\n\n    float x = (p.x + 1) / 2 * viewport[2];\n    float y = (p.y + 1) / 2 * viewport[3];\n\n    vec2 textDimensions = font->TextDimensions(text);\n\n    switch (HorizontalAlignment) {\n    case Alignment::Left: break;\n    case Alignment::Center: x -= textDimensions.x / 2.f; break;\n    case Alignment::Right: x -= textDimensions.x; break;\n    default: break;\n    }\n    switch (VerticalAlignment) {\n    case Alignment::Bottom: break;\n    case Alignment::Center: y -= textDimensions.y / 2.f; break;\n    case Alignment::Top: y -= textDimensions.y; break;\n    default: break;\n    }\n\n    glDepthMask(true);\n    glEnable(GL_DEPTH_TEST);\n    glDepthFunc(GL_LEQUAL);\n\n    mm->Translate((int)x, (int)y, -z);\n\n    if (BackgroundColor.a > 0) {\n        lgl->Color(BackgroundColor);\n        lgl->Begin(LGL_QUADS);\n        lgl->Vertex2f(-Padding, -Padding);\n        lgl->Vertex2f(textDimensions.x + Padding, -Padding);\n        lgl->Vertex2f(textDimensions.x + Padding, textDimensions.y + Padding);\n        lgl->Vertex2f(-Padding, textDimensions.y + Padding);\n        lgl->End();\n    }\n\n    font->DrawText(text, ForegroundColor);\n\n    glDepthFunc(GL_LESS);\n\n    mm->PopMatrix();\n    mm->MatrixModeProjection();\n    mm->PopMatrix();\n    mm->MatrixModeModelView();\n}\n\nFont *TextLabel::GetFont() const { return _glManager->fontManager->GetFont(FontName, FontSize); }\n"
  },
  {
    "path": "lib/render/Texture.cpp",
    "content": "#include <vapor/Texture.h>\n#include <vapor/glutil.h>\n#include <vapor/MyBase.h>\n#include <vapor/VAssert.h>\n\nusing namespace VAPoR;\n\nTexture::Texture(unsigned int type) : _type(type), _nDims(GetDimsCount(type)) {}\n\nTexture::~Texture() { Delete(); }\n\nint Texture::Generate() { return Generate(GL_LINEAR); }\n\nint Texture::Generate(int filter)\n{\n    VAssert(!Initialized());\n    glGenTextures(1, &_id);\n    glBindTexture(_type, _id);\n\n    glTexParameteri(_type, GL_TEXTURE_MIN_FILTER, filter);\n    glTexParameteri(_type, GL_TEXTURE_MAG_FILTER, filter);\n\n    if (_nDims >= 1) glTexParameteri(_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    if (_nDims >= 2) glTexParameteri(_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    if (_nDims >= 3) glTexParameteri(_type, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);\n\n    glBindTexture(_type, 0);\n    return 0;\n}\n\nvoid Texture::Delete()\n{\n    if (_id) glDeleteTextures(1, &_id);\n    _id = 0;\n    _width = 0;\n    _height = 0;\n    _depth = 0;\n}\n\nbool Texture::Initialized() const { return _id; }\n\nvoid Texture::Bind() const\n{\n    VAssert(Initialized());\n    glBindTexture(_type, _id);\n}\n\nvoid Texture::UnBind() const { glBindTexture(_type, 0); }\n\n// glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, dims[0], dims[1], dims[2], 0, GL_RED, GL_FLOAT, data);\nint Texture::TexImage(int internalFormat, int width, int height, int depth, unsigned int format, unsigned int type, const void *data, int level)\n{\n    VAssert(Initialized());\n    VAssert(_nDims >= 2 || height == 0);\n    VAssert(_nDims >= 3 || depth == 0);\n\n    if (_nDims == 3) {\n        GLint max3DTexDim;\n        glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTexDim);\n        if (width > max3DTexDim || height > max3DTexDim || depth > max3DTexDim) {\n            Wasp::MyBase::SetErrMsg(\"Texture size (%lix%lix%li) not supported by GPU (max supported size per dim is %i)\\n\", width, height, depth, max3DTexDim);\n            return -1;\n        }\n    } else {\n        GLint max2DTexDim;\n        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max2DTexDim);\n        if (width > max2DTexDim || height > max2DTexDim) {\n            Wasp::MyBase::SetErrMsg(\"Texture size (%lix%li) not supported by GPU (max supported size per dim is %i)\\n\", width, height, max2DTexDim);\n            return -1;\n        }\n    }\n\n    _width = width;\n    _height = height;\n    _depth = depth;\n\n    Bind();\n\n    if (_nDims == 1)\n        glTexImage1D(_type, level, internalFormat, width, 0, format, type, data);\n    else if (_nDims == 2)\n        glTexImage2D(_type, level, internalFormat, width, height, 0, format, type, data);\n    else if (_nDims == 3) {\n        glTexImage3D(_type, level, internalFormat, 0, 0, 0, 0, format, type, NULL);    // Fix driver bug with re-uploading large textures\n        glTexImage3D(_type, level, internalFormat, width, height, depth, 0, format, type, data);\n    }\n\n    UnBind();\n    return 0;\n}\n\nunsigned int Texture::GetDimsCount(unsigned int glTextureEnum)\n{\n    switch (glTextureEnum) {\n    case GL_TEXTURE_1D: return 1;\n    case GL_TEXTURE_2D: return 2;\n    case GL_TEXTURE_3D: return 3;\n    case GL_TEXTURE_2D_ARRAY: return 3;\n\n    default: VAssert(0); return -1;\n    }\n}\n\nTexture1D::Texture1D() : Texture(GL_TEXTURE_1D) {}\nTexture2D::Texture2D() : Texture(GL_TEXTURE_2D) {}\nTexture3D::Texture3D() : Texture(GL_TEXTURE_3D) {}\nTexture2DArray::Texture2DArray() : Texture(GL_TEXTURE_2D_ARRAY) {}\n\nvoid Texture2D::CopyDepthBuffer()\n{\n    GLint viewport[4] = {0};\n    glGetIntegerv(GL_VIEWPORT, viewport);\n\n    Bind();\n    glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, viewport[0], viewport[1], viewport[2], viewport[3], 0);\n\n    _width = viewport[2] - viewport[0];\n    _height = viewport[3] - viewport[1];\n\n    UnBind();\n}\n"
  },
  {
    "path": "lib/render/TrackBall.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tTrackBall.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJuly 2004\n//\n//\tDescription:\tImplements the Trackball class:\n//\t\tThis was implemented from Ken Purcell's TrackBall\n//\t\tmethods.  Additional methods provided to set the TrackBall\n//\t\tbased on a viewing frame\n//\n/* Copyright (C) 1992  AHPCRC, Univeristy of Minnesota\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program in a file named 'Copying'; if not, write to\n * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139.\n */\n\n/* Author:\n *\tKen Chin-Purcell (ken@ahpcrc.umn.edu)\n *\tArmy High Performance Computing Research Center (AHPCRC)\n *\tUniveristy of Minnesota\n *\n * This class was extracted from glutil.c  See glutil.cpp for the revision history */\n\n/* Trackball interface for 3D rotation:\n *\n * The TrackBall is simualted as a globe rotating about its center.\n * Mouse movement is mapped to a spot on the globe, which when moved\n * effects a rotation.\n *\n * In addition, this Trackball also keeps track of translation,\n * in the form of panning and zooming.\n *\n * To use:\n *\tAt the start of the program, call Trackball constructor to\n *\t\tcreate a Trackball object.  You will want a separate\n *\t\tTrackball for each rotatable scene.\n *\tOn a Button or Motion event, call\n *\t\tMouseOnTrackball\n *\tWhen you want to draw, call\n *\t\tTrackballSetMatrix to modify the matrix.\n *\tMisc. functions:\n *\t\tTrackballReset to come to home position\n *\t\tTrackballFlip to flip about an axis\n *\t\tTrackballSpin to keep rotating by last increment\n *\t\tTrackballStopSpinning to set increment to zero\n *\n * To change how TrackBall feels:\n *\ttball->_scale[0]\t: modify translation (pan) in x direction\n *\ttball->_scale[1]\t: modify translation (pan) in y direction\n *\ttball->_scale[2]\t: modify translation (zoom) in z direction\n *\ttball->_ballsize : a bigger ball gives finer rotations\n *\t\t\t  (default = 0.65)\n */\n\n#include <cmath>\n#include <iostream>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n#include <glm/gtc/matrix_transform.hpp>\n#include <glm/gtc/type_ptr.hpp>\n#include <glm/gtc/quaternion.hpp>\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n#include <vapor/VAssert.h>\n\n#include <vapor/TrackBall.h>\n\nusing namespace VAPoR;\nvoid Trackball::TrackballReset()\n{\n    /* Bring trackball to home position, no translation, zero rotation.\n     */\n    qzero(_qrot);\n    qzero(_qinc);\n    vzero(_trans);\n    vset(_scale, 1000000.0, 1000000.0, 1000000.0);\n    // Default center of rotation:\n    _center[0] = 0.5f;\n    _center[1] = 0.5f;\n    _center[2] = 0.5f;\n}\n\nTrackball::Trackball(void)\n{\n    _ballsize = 0.65f;\n    vset(_scale, 1.0, 1.0, 1.0);\n    TrackballReset();\n}\n\nTrackball::Trackball(float scale[3])\n{\n    _ballsize = 0.65f;\n    vset(_scale, scale[0], scale[1], scale[2]);\n    TrackballReset();\n}\n\nvoid Trackball::TrackballSetMatrix()\n// Note perspective must be set previously in setFromFrame.\n{\n    /* Modify the modelview matrix by the trackball\n     * rotation and translation.\n     */\n\n    if (_perspective) {\n        glm::mat4 m(1.0);\n        m = glm::translate(m, glm::vec3(_center[0], _center[1], _center[2]));\n        m = glm::translate(m, glm::vec3(_trans[0], _trans[1], _trans[2]));\n\n        // Copying over because qmatrix is row major (it should be column major).\n        // I have no idea why this works because the surrounding functions that\n        // were here originaly were column major too. If I replace the current\n        // quat functions with the correct column major ones the rotations are correct\n        // every other rotation.\n        //\n        // Also for future reference since qmatrix has no documentation:\n        // qmatrix parameters are x,y,z,w while glm parameters are w,x,y,z\n        double m3[16];\n        qmatrix(_qrot, m3);\n        glm::mat4 mrot_row_major;\n        for (int i = 0; i < 16; i++) glm::value_ptr(mrot_row_major)[i] = m3[i];\n        m *= mrot_row_major;\n\n        m = glm::translate(m, -glm::vec3(_center[0], _center[1], _center[2]));\n\n        for (int i = 0; i < 16; i++) _modelViewMatrix[i] = glm::value_ptr(m)[i];\n    } else {\n        glm::mat4 m(1.0);\n\n        m = glm::translate(m, glm::vec3(_center[0], _center[1], _center[2]));\n        m = glm::translate(m, glm::vec3(_trans[0], _trans[1], _trans[2]));\n\n        double m3[16];\n        qmatrix(_qrot, m3);\n        glm::mat4 mrot_row_major;\n        for (int i = 0; i < 16; i++) glm::value_ptr(mrot_row_major)[i] = m3[i];\n        m *= mrot_row_major;\n\n        // Cannot scale due to how camera params are extracted from final matrix\n        // m = glm::scale(m, glm::vec3(scale_factor, scale_factor, scale_factor));\n        // SetFloat(\"Scale\", scale_factor);\n\n        m = glm::translate(m, -glm::vec3(_center[0], _center[1], _center[2]));\n\n        for (int i = 0; i < 16; i++) _modelViewMatrix[i] = glm::value_ptr(m)[i];\n    }\n}\n\ndouble Trackball::GetOrthoSize() const\n{\n    double scale_factor = 1.0;\n\n    if (_trans[2] < 0.0) {\n        scale_factor = 5.0 / (1 - _trans[2]);\n    } else {\n        scale_factor = 5.0 + _trans[2];\n    }\n    return 1 / scale_factor * 2.9;\n}\n\n#ifndef M_SQRT1_2\n    #define M_SQRT1_2 0.707106781186547524401f\n#endif\nstatic double q90[3][4] = {\n    {M_SQRT1_2, 0.0, 0.0, M_SQRT1_2},\n    {0.0, M_SQRT1_2, 0.0, M_SQRT1_2},\n    {0.0, 0.0, -M_SQRT1_2, M_SQRT1_2},\n};\n\nvoid Trackball::TrackballFlip(int axis)\n{\n    /* Rotate by 90 deg about the given axis.\n     */\n    if (axis >= 0 && axis < 3) qmult(q90[axis], _qrot, _qrot);\n}\n\nvoid Trackball::TrackballSpin()\n{\n    /* Rotationaly spin the trackball by the current increment.\n     * Use this to implement rotational glide.\n     */\n    qmult(_qinc, _qrot, _qrot);\n}\n\nvoid Trackball::TrackballStopSpinning()\n{\n    /* Cease any rotational glide by zeroing the increment.\n     */\n    qzero(_qinc);\n}\n\nint Trackball::TrackballSpinning()\n{\n    /* If the trackball is gliding then the increment's angle\n     * will be non-zero, and cos(theta) != 1, hence q[3] != 1.\n     */\n    return (_qinc[3] != 1);\n}\n\nvoid Trackball::TrackballSetPosition(double newx, double newy)\n{\n    /* Call this when the user does a mouse down.\n     * Stop the trackball glide, then remember the mouse\n     * down point (for a future rotate, pan or zoom).\n     */\n    TrackballStopSpinning();\n    _lastx = newx;\n    _lasty = newy;\n}\n\nvoid Trackball::TrackballRotate(double newx, double newy)\n{\n    CalcRotation(_qinc, newx, newy, _lastx, _lasty, _ballsize);\n    TrackballSpin();\n\n    _lastx = newx; /* remember for next time */\n    _lasty = newy;\n}\n\nvoid Trackball::TrackballPan(double newx, double newy)\n{\n    _trans[0] += (newx - _lastx) * _scale[0];\n    _trans[1] += (newy - _lasty) * _scale[1];\n\n    _lastx = newx; /* remember for next time */\n    _lasty = newy;\n}\n\nvoid Trackball::TrackballZoom(double newx, double newy)\n{\n    _trans[2] += (newy - _lasty) * _scale[2];\n\n    _lastx = newx; /* remember for next time */\n    _lasty = newy;\n}\n\nvoid Trackball::TrackballCopyTo(Trackball *dst)\n{\n    /* Copy the current roation of the trackball\n     */\n    qcopy(_qrot, dst->_qrot);\n}\n\n/*\n * eventNum is 0, 1, or 2 for press, move, or release\n * thisButton is Qt:LeftButton, RightButton, or MidButton\n */\n\nvoid Trackball::MouseOnTrackball(int eventNum, int thisButton, int xcrd, int ycrd, int width, int height)\n{\n    /* Alter a Trackball structure given  mouse event.\n     *   This routine *assumes* button 1 rotates, button 2 pans,\n     *   and button 3 zooms!\n     *\n     * event\t\t: ButtonPress, MotionNotify or ButtonRelease\n     * width, height\t: of event window\n     * tball\t\t: trackball to modify\n     */\n    double     x, y;\n    static int button;\n    // Ignore time: Qt doesn't provide time with events (may need to revisit this later????)\n    // static Time\tdownTime;\n\n    switch (eventNum) {\n    case 0:    // ButtonPress:\n        x = ScalePoint(xcrd, 0, width);\n        y = ScalePoint(ycrd, height, -((long)height));\n        TrackballSetPosition(x, y);\n        // Remember the last button pressed:\n        button = thisButton;\n        // downTime = event->xbutton.time;\n        break;\n\n    case 1:    // MotionNotify:\n        x = ScalePoint(xcrd, 0, width);\n        y = ScalePoint(ycrd, height, -((long)height));\n        switch (button) {\n        case 1:    // left button\n            TrackballRotate(x, y);\n            break;\n        case 2:    // middle button\n            TrackballPan(x, y);\n            break;\n        case 3:    // right button\n            TrackballZoom(x, y);\n            break;\n        default: break;\n        }\n        // downTime = event->xmotion.time;\n        break;\n\n    case 2:            // ButtonRelease:\n        button = 1;    // left\n                       //\tif (event->xbutton.time - downTime > 250)\n        //??? if (event->xbutton.time - downTime > 100)\n        //???\tTrackballStopSpinning(tball);\n        break;\n    }\n}\n\nbool Trackball::ReconstructCamera(double position[3], double upVec[3], double viewDir[3]) const\n{\n    double minv[16];\n\n    int rc = minvert(_modelViewMatrix, minv);\n    if (rc < 0) return (false);\n\n    vscale(minv + 8, -1.0);\n\n    for (int i = 0; i < 3; i++) {\n        position[i] = minv[12 + i];    // position vector is minv[12..14]\n        upVec[i] = minv[4 + i];        // up vector is minv[4..6]\n        viewDir[i] = minv[8 + i];      // view direction is minv[8..10]\n    }\n    vnormal(upVec);\n    vnormal(viewDir);\n\n    return (true);\n}\n\n// Set the quaternion and translation from a viewer frame\n// Also happens to construct modelview matrix, but we don't use its translation\nbool Trackball::setFromFrame(const std::vector<double> &posvec, const std::vector<double> &dirvec, const std::vector<double> &upvec, const std::vector<double> &centerRot, bool persp)\n{\n    VAssert(posvec.size() == 3);\n    VAssert(dirvec.size() == 3);\n    VAssert(upvec.size() == 3);\n    VAssert(centerRot.size() == 3);\n\n    // Check for valid up vector and view direction\n    if (upvec[0] == 0 && upvec[1] == 0 && upvec[2] == 0) { return false; }\n    if (dirvec[0] == 0 && dirvec[1] == 0 && dirvec[2] == 0) { return false; }\n\n    // First construct the rotation matrix:\n    double mtrx1[16];\n    double trnsMtrx[16];\n    double mtrx[16];\n    setCenter(centerRot);\n    makeTransMatrix(centerRot, trnsMtrx);\n    makeModelviewMatrixD(posvec, dirvec, upvec, mtrx);\n\n    // Translate on both sides by translation\n    // first on left,\n    mmult(trnsMtrx, mtrx, mtrx1);\n    // then on right by negative:\n    trnsMtrx[12] = -trnsMtrx[12];\n    trnsMtrx[13] = -trnsMtrx[13];\n    trnsMtrx[14] = -trnsMtrx[14];\n    mmult(mtrx1, trnsMtrx, mtrx);\n    double qrotd[4];\n    // convert rotation part to quaternion:\n    rotmatrix2q(mtrx, qrotd);\n    for (int i = 0; i < 4; i++) _qrot[i] = (double)qrotd[i];\n    // set the translation?\n    // If parallel (ortho) transform, z used for translation\n    _perspective = persp;\n    // vcopy(posvec, trans);\n    for (int i = 0; i < 3; i++) _trans[i] = (double)mtrx[i + 12];\n\n    return true;\n}\n"
  },
  {
    "path": "lib/render/TwoDDataRenderer.cpp",
    "content": "//************************************************************************\n\n//\t\t     Copyright (C)  2008\t\t\t\t\t\t\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t\t\t\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tTwoDDataRenderer.cpp\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tMarch 2016\n//\n//\tDescription:\tImplementation of the twoDImageRenderer class\n//\n\n#include <vapor/glutil.h>    // Must be included first!!!\n\n#include <iostream>\n#include <fstream>\n#include <numeric>\n\n#include <vapor/Proj4API.h>\n#include <vapor/CFuncs.h>\n#include <vapor/utils.h>\n#include <vapor/DataMgrUtils.h>\n#include <vapor/TwoDDataRenderer.h>\n#include <vapor/TwoDDataParams.h>\n#include \"vapor/GLManager.h\"\n\nusing namespace VAPoR;\n\n//\n// Register class with object factory!!!\n//\nstatic RendererRegistrar<TwoDDataRenderer> registrar(TwoDDataRenderer::GetClassType(), TwoDDataParams::GetClassType());\n\nnamespace {\n\n// Set to true to force structured grids to be renderered as\n// unstructured grids.\n//\nconst bool ForceUnstructured = false;\n\n// GLSL shader constants\n//\nconst string EffectBaseName = \"2DData\";\nconst string EffectName = \"2DData\";\nconst string EffectNameAttr = \"2DDataAttr\";\nconst string VertexDataAttr = \"vertexDataAttr\";\n\n// Rendering primitives will be aligned with grid points\n//\nconst bool GridAligned = true;\n\n// Texture units. Only use data texture if GridAligned is false\n//\n// const int dataTexUnit = 0; // GL_TEXTURE0\n// const int colormapTexUnit = 1;          // GL_TEXTURE1\n\n// Return name of GLSL shader instance to use\n//\nstring getEffectInstance(bool useVertAttr)\n{\n    if (useVertAttr)\n        return (EffectNameAttr);\n    else\n        return (EffectName);\n}\n\n// Compute surface normal (gradient) for point (x,y) using 1st order\n// central differences. 'hgtGrid' is a displacement map for Z coordinate.\n//\nvoid computeNormal(const Grid *hgtGrid, float x, float y, float dx, float dy, float mv, float &nx, float &ny, float &nz)\n{\n    nx = ny = 0.0;\n    nz = 1.0;\n    if (!hgtGrid) return;\n\n    // Missing value?\n    //\n    if ((hgtGrid->GetValue(x, y)) == mv) return;\n\n    float z_xpdx = hgtGrid->GetValue(x + dx, y);\n    if (z_xpdx == mv) { z_xpdx = x; }\n\n    float z_xmdx = hgtGrid->GetValue(x - dx, y);\n    if (z_xmdx == mv) { z_xmdx = x; }\n\n    float z_ypdy = hgtGrid->GetValue(x, y + dy);\n    if (z_ypdy == mv) { z_ypdy = y; }\n\n    float z_ymdy = hgtGrid->GetValue(x, y - dy);\n    if (z_ymdy == mv) { z_ymdy = x; }\n\n    float dzx = z_xpdx - z_xmdx;\n    float dzy = z_ypdy - z_ymdy;\n\n    nx = dy * dzx;\n    ny = dx * dzy;\n    nz = 1.0;\n}\n}    // namespace\n\nTwoDDataRenderer::TwoDDataRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr)\n: TwoDRenderer(pm, winName, dataSetName, TwoDDataParams::GetClassType(), TwoDDataRenderer::GetClassType(), instName, dataMgr)\n{\n    _grid_state.clear();\n    _tex_state.clear();\n\n    _texWidth = 0;\n    _texHeight = 0;\n    _texelSize = 8;\n    _vertsWidth = 0;\n    _vertsHeight = 0;\n    _nindices = 0;\n    _nverts = 0;\n    _colormap = NULL;\n    _colormapsize = 0;\n\n    _cMapTexID = 0;\n\n    TwoDDataParams *rp = (TwoDDataParams *)GetActiveParams();\n    MapperFunction *tf = rp->GetMapperFunc(rp->GetVariableName());\n\n    _colormapsize = tf->getNumEntries();\n    _colormap = new GLfloat[_colormapsize * 4];\n\n    for (int i = 0; i < _colormapsize; i++) {\n        _colormap[i * 4 + 0] = (float)i / (float)(_colormapsize - 1);\n        _colormap[i * 4 + 1] = (float)i / (float)(_colormapsize - 1);\n        _colormap[i * 4 + 2] = (float)i / (float)(_colormapsize - 1);\n        _colormap[i * 4 + 3] = 1.0;\n    }\n}\n\nTwoDDataRenderer::~TwoDDataRenderer()\n{\n    if (_cMapTexID) glDeleteTextures(1, &_cMapTexID);\n    if (_colormap) delete[] _colormap;\n}\n\nint TwoDDataRenderer::_initializeGL()\n{\n    glGenTextures(1, &_cMapTexID);\n\n    //\n    // Standard colormap\n    //\n    glActiveTexture(GL_TEXTURE1);\n    glBindTexture(GL_TEXTURE_1D, _cMapTexID);\n\n    glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, _colormapsize, 0, GL_RGBA, GL_FLOAT, _colormap);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, 0);\n    return (TwoDRenderer::_initializeGL());\n}\n\nint TwoDDataRenderer::_paintGL(bool fast)\n{\n    if (CheckGLError() != 0) return (-1);\n\n    TwoDDataParams *rp = (TwoDDataParams *)GetActiveParams();\n\n    MapperFunction *tf = rp->GetMapperFunc(rp->GetVariableName());\n    tf->makeLut(_colormap);\n    vector<double> crange = tf->getMinMaxMapValue();\n\n    int rc;\n#ifndef NOSHADER\n\n    string effect = getEffectInstance(GridAligned);\n\n    // 2D Data LIGHT parameters hard coded\n    //\n    // _shaderMgr->UploadEffectData(effect, \"lightingEnabled\", (int) false);\n    // _shaderMgr->UploadEffectData(effect, \"kd\", (float) 0.6);\n    // _shaderMgr->UploadEffectData(effect, \"ka\", (float) 0.3);\n    // _shaderMgr->UploadEffectData(effect, \"ks\", (float) 0.1);\n    // _shaderMgr->UploadEffectData(effect, \"expS\", (float) 16.0);\n    // _shaderMgr->UploadEffectData( effect, \"lightDirection\", (float) 0.0, (float) 0.0, (float) 1.0);\n\n#endif\n\n    ShaderProgram *s = _glManager->shaderManager->GetShader(\"2DData\");\n    if (s == nullptr) return -1;\n    s->Bind();\n    s->SetUniform(\"minLUTValue\", (float)crange[0]);\n    s->SetUniform(\"maxLUTValue\", (float)crange[1]);\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, _cMapTexID);\n\n    // Really only need to reload colormap texture if it changes\n    //\n    glTexSubImage1D(GL_TEXTURE_1D, 0, 0, _colormapsize, GL_RGBA, GL_FLOAT, _colormap);\n\n    glActiveTexture(GL_TEXTURE0);\n    rc = TwoDRenderer::_paintGL(fast);\n\n    glActiveTexture(GL_TEXTURE0);\n    glBindTexture(GL_TEXTURE_1D, 0);\n\n    return (rc);\n}\n\nconst GLvoid *TwoDDataRenderer::GetTexture(DataMgr *dataMgr, GLsizei &width, GLsizei &height, GLint &internalFormat, GLenum &format, GLenum &type, size_t &texelSize, bool &gridAligned)\n{\n    internalFormat = GL_RG32F;\n    format = GL_RG;\n    type = GL_FLOAT;\n    texelSize = _texelSize;\n    gridAligned = GridAligned;\n\n    GLvoid *texture = (GLvoid *)_getTexture(dataMgr);\n    if (!texture) return (NULL);\n\n    width = _texWidth;\n    height = _texHeight;\n    return (texture);\n}\n\nint TwoDDataRenderer::GetMesh(DataMgr *dataMgr, GLfloat **verts, GLfloat **normals, GLsizei &nverts, GLsizei &width, GLsizei &height, GLuint **indices, GLsizei &nindices, bool &structuredMesh)\n{\n    width = 0;\n    height = 0;\n    nindices = 0;\n    nverts = 0;\n\n    // See if already in cache\n    //\n    if (!_gridStateDirty() && _sb_verts.GetBuf()) {\n        width = _vertsWidth;\n        height = _vertsHeight;\n        *verts = (GLfloat *)_sb_verts.GetBuf();\n        *normals = (GLfloat *)_sb_normals.GetBuf();\n        nverts = _nverts;\n\n        nindices = _nindices;\n        *indices = (GLuint *)_sb_indices.GetBuf();\n        return (0);\n    }\n\n    _gridStateClear();\n\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n    int             refLevel = rParams->GetRefinementLevel();\n    int             lod = rParams->GetCompressionLevel();\n\n    // Find box extents for ROI\n    //\n    size_t         ts = rParams->GetCurrentTimestep();\n    CoordType      minBoxReq = {0.0, 0.0, 0.0};\n    CoordType      maxBoxReq = {0.0, 0.0, 0.0};\n    rParams->GetBox()->GetExtents(minBoxReq, maxBoxReq);\n\n    string varname = rParams->GetVariableName();\n    int    orientation = _getOrientation(dataMgr, varname);\n    if (orientation != 2) {\n        SetErrMsg(\"Only XY plane orientations currently supported\");\n        return (-1);\n    }\n\n    Grid *g = NULL;\n    int   rc = DataMgrUtils::GetGrids(dataMgr, ts, varname, minBoxReq, maxBoxReq, true, &refLevel, &lod, &g);\n    if (rc < 0) return (-1);\n\n    VAssert(g);\n\n    double defaultZ = GetDefaultZ(dataMgr, rParams->GetCurrentTimestep());\n\n    if (dynamic_cast<StructuredGrid *>(g) && !ForceUnstructured) {\n        rc = _getMeshStructured(dataMgr, dynamic_cast<StructuredGrid *>(g), defaultZ);\n        structuredMesh = true;\n    } else {\n        rc = _getMeshUnStructured(dataMgr, g, defaultZ);\n        structuredMesh = false;\n    }\n\n    delete g;\n\n    if (rc < 0) return (-1);\n\n    _gridStateSet();\n\n    *verts = (GLfloat *)_sb_verts.GetBuf();\n    *normals = (GLfloat *)_sb_normals.GetBuf();\n    nverts = _nverts;\n    *indices = (GLuint *)_sb_indices.GetBuf();\n\n    width = _vertsWidth;\n    height = _vertsHeight;\n    nindices = _nindices;\n\n    return (0);\n}\n\nbool TwoDDataRenderer::_gridStateDirty() const\n{\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n\n    DC::DataVar dvar;\n    _dataMgr->GetDataVarInfo(rParams->GetVariableName(), dvar);\n\n    vector<double> minExts, maxExts;\n    rParams->GetBox()->GetExtents(minExts, maxExts);\n\n    _grid_state_c current_state(_dataMgr->GetNumRefLevels(rParams->GetVariableName()), rParams->GetRefinementLevel(), rParams->GetCompressionLevel(), rParams->GetHeightVariableName(),\n                                dvar.GetMeshName(), rParams->GetCurrentTimestep(), minExts, maxExts);\n\n    return (_grid_state != current_state);\n}\n\nvoid TwoDDataRenderer::_gridStateClear() { _grid_state.clear(); }\n\nvoid TwoDDataRenderer::_gridStateSet()\n{\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n\n    DC::DataVar dvar;\n    _dataMgr->GetDataVarInfo(rParams->GetVariableName(), dvar);\n\n    vector<double> minExts, maxExts;\n    rParams->GetBox()->GetExtents(minExts, maxExts);\n    string meshName;\n\n    _grid_state = _grid_state_c(_dataMgr->GetNumRefLevels(rParams->GetVariableName()), rParams->GetRefinementLevel(), rParams->GetCompressionLevel(), rParams->GetHeightVariableName(),\n                                dvar.GetMeshName(), rParams->GetCurrentTimestep(), minExts, maxExts);\n}\n\nbool TwoDDataRenderer::_texStateDirty(DataMgr *dataMgr) const\n{\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n\n    vector<double> minExts, maxExts;\n    rParams->GetBox()->GetExtents(minExts, maxExts);\n\n    _tex_state_c current_state(rParams->GetRefinementLevel(), rParams->GetCompressionLevel(), rParams->GetVariableName(), rParams->GetCurrentTimestep(), minExts, maxExts);\n\n    return (_tex_state != current_state);\n}\n\nvoid TwoDDataRenderer::_texStateSet(DataMgr *dataMgr)\n{\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n\n    vector<double> minExts, maxExts;\n    rParams->GetBox()->GetExtents(minExts, maxExts);\n\n    _tex_state = _tex_state_c(rParams->GetRefinementLevel(), rParams->GetCompressionLevel(), rParams->GetVariableName(), rParams->GetCurrentTimestep(), minExts, maxExts);\n}\n\nvoid TwoDDataRenderer::_texStateClear() { _tex_state.clear(); }\n\n// Get mesh for a structured grid\n//\nint TwoDDataRenderer::_getMeshStructured(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ)\n{\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n\n    auto dims = g->GetDimensions();\n    VAssert(dims[2] == 1);\n\n    _vertsWidth = dims[0];\n    _vertsHeight = dims[1];\n    _nindices = _vertsWidth * 2;\n\n    // (Re)allocate space for verts\n    //\n    _nverts = _vertsWidth * _vertsHeight;\n    _sb_verts.Alloc(_nverts * 3 * sizeof(GLfloat));\n    _sb_normals.Alloc(_nverts * 3 * sizeof(GLfloat));\n    _sb_indices.Alloc(2 * _vertsWidth * sizeof(GLuint));\n\n    int rc;\n    if (!rParams->GetHeightVariableName().empty()) {\n        rc = _getMeshStructuredDisplaced(dataMgr, g, defaultZ);\n    } else {\n        rc = _getMeshStructuredPlane(dataMgr, g, defaultZ);\n    }\n    if (rc < 0) return (rc);\n\n    // Compute vertex normals\n    //\n    GLfloat *verts = (GLfloat *)_sb_verts.GetBuf();\n    GLfloat *normals = (GLfloat *)_sb_normals.GetBuf();\n    ComputeNormals(verts, _vertsWidth, _vertsHeight, normals);\n\n    // Construct indices for a triangle strip covering one row\n    // of the mesh\n    //\n    GLuint *indices = (GLuint *)_sb_indices.GetBuf();\n    for (GLuint i = 0; i < _vertsWidth; i++) indices[2 * i] = i;\n    for (GLuint i = 0; i < _vertsWidth; i++) indices[2 * i + 1] = i + _vertsWidth;\n\n    return (0);\n}\n\n// Get mesh for an unstructured grid\n//\nint TwoDDataRenderer::_getMeshUnStructured(DataMgr *dataMgr, const Grid *g, double defaultZ)\n{\n    VAssert(g->GetTopologyDim() == 2);\n    auto dims = g->GetDimensions();\n\n    // Unstructured 2d grids are stored in 1d\n    //\n    _vertsWidth = std::accumulate(dims.begin(), dims.end(), 1ul, std::multiplies<size_t>());\n    _vertsHeight = 1;\n\n    // Count the number of triangle vertex indices needed\n    //\n    size_t           maxVertexPerCell = g->GetMaxVertexPerCell();\n    vector<DimsType> nodes(maxVertexPerCell);\n    _nindices = 0;\n    Grid::ConstCellIterator citr;\n    Grid::ConstCellIterator endcitr = g->ConstCellEnd();\n    for (citr = g->ConstCellBegin(); citr != endcitr; ++citr) {\n        const DimsType &cell = *citr;\n        g->GetCellNodes(DimsType{cell[0], 0, 0}, nodes);\n\n        if (nodes.size() < 3) continue;    // degenerate\n        _nindices += 3 * (nodes.size() - 2);\n    }\n\n    // (Re)allocate space for verts\n    //\n    _nverts = _vertsWidth;\n    _sb_verts.Alloc(_nverts * 3 * sizeof(GLfloat));\n    _sb_normals.Alloc(_nverts * 3 * sizeof(GLfloat));\n    _sb_indices.Alloc(_nindices * sizeof(GLuint));\n\n    return (_getMeshUnStructuredHelper(dataMgr, g, defaultZ));\n    return 0;\n}\n\nint TwoDDataRenderer::_getMeshUnStructuredHelper(DataMgr *dataMgr, const Grid *g, double defaultZ)\n{\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n    // Construct the displaced (terrain following) grid using\n    // a map projection, if specified.\n    //\n    size_t ts = rParams->GetCurrentTimestep();\n    int    refLevel = rParams->GetRefinementLevel();\n    int    lod = rParams->GetCompressionLevel();\n\n    // Find box extents for ROI\n    //\n    CoordType minExts, maxExts;\n    g->GetUserExtents(minExts, maxExts);\n\n    // Try to get requested refinement level or the nearest acceptable level:\n    //\n    string hgtvar = rParams->GetHeightVariableName();\n\n    Grid *hgtGrid = NULL;\n\n    if (!hgtvar.empty()) {\n        int rc = DataMgrUtils::GetGrids(dataMgr, ts, hgtvar, minExts, maxExts, true, &refLevel, &lod, &hgtGrid);\n\n        if (rc < 0) return (rc);\n        VAssert(hgtGrid);\n    }\n\n    VAssert(g->GetTopologyDim() == 2);\n\n    GLfloat *verts = (GLfloat *)_sb_verts.GetBuf();\n    GLfloat *normals = (GLfloat *)_sb_normals.GetBuf();\n    GLuint * indices = (GLuint *)_sb_indices.GetBuf();\n\n    double mv = hgtGrid ? hgtGrid->GetMissingValue() : 0.0;\n\n    // Hard-code dx and dy for gradient calculation :-(\n    //\n    float dx = (maxExts[0] - minExts[0]) / 1000.0;\n    float dy = (maxExts[1] - minExts[1]) / 1000.0;\n\n    //\n    // Visit each node in the grid, build a list of vertices\n    //\n    Grid::ConstNodeIterator nitr;\n    Grid::ConstNodeIterator endnitr = g->ConstNodeEnd();\n    size_t                  voffset = 0;\n    for (nitr = g->ConstNodeBegin(); nitr != endnitr; ++nitr) {\n        CoordType coords;\n\n        g->GetUserCoordinates(*nitr, coords);\n\n        // Lookup vertical coordinate displacement as a data element\n        // from the\n        // height variable. Note, missing values are possible if image\n        // extents are out side of extents for height variable, or if\n        // height variable itself contains missing values.\n        //\n        double deltaZ = hgtGrid ? hgtGrid->GetValue(coords) : 0.0;\n        if (deltaZ == mv) deltaZ = 0.0;\n\n        verts[voffset + 0] = coords[0];\n        verts[voffset + 1] = coords[1];\n        verts[voffset + 2] = deltaZ - defaultZ;\n\n        // Compute the surface normal using central differences\n        //\n        computeNormal(hgtGrid, coords[0], coords[1], dx, dy, mv, normals[voffset + 0], normals[voffset + 1], normals[voffset + 2]);\n\n        voffset += 3;\n    }\n\n    //\n    // Visit each cell in the grid. For each cell triangulate it and\n    // and compute an index\n    // array for the triangle list\n    //\n    size_t                  maxVertexPerCell = g->GetMaxVertexPerCell();\n    vector<DimsType>        nodes(maxVertexPerCell);\n    Grid::ConstCellIterator citr;\n    Grid::ConstCellIterator endcitr = g->ConstCellEnd();\n    size_t                  index = 0;\n    for (citr = g->ConstCellBegin(); citr != endcitr; ++citr) {\n        const DimsType &cell = *citr;\n        g->GetCellNodes(DimsType{cell[0], 0, 0}, nodes);\n\n        if (nodes.size() < 3) continue;    // degenerate\n\n        // Compute triangle node indices, with common vertex at\n        // nodes[0]\n        //\n        for (int i = 0; i < nodes.size() - 2; i++) {\n            indices[index++] = nodes[0][0];\n            indices[index++] = nodes[i + 1][0];\n            indices[index++] = nodes[i + 2][0];\n        }\n    }\n\n    if (hgtGrid) { delete hgtGrid; }\n\n    return (0);\n}\n\n// Get mesh for a structured grid displaced by a height field\n//\nint TwoDDataRenderer::_getMeshStructuredDisplaced(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ)\n{\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n    // Construct the displaced (terrain following) grid using\n    // a map projection, if specified.\n    //\n    size_t ts = rParams->GetCurrentTimestep();\n    int    refLevel = rParams->GetRefinementLevel();\n    int    lod = rParams->GetCompressionLevel();\n\n    // Find box extents for ROI\n    //\n    CoordType minExtsReq = {0.0, 0.0, 0.0};\n    CoordType maxExtsReq = {0.0, 0.0, 0.0};\n    rParams->GetBox()->GetExtents(minExtsReq, maxExtsReq);\n\n    // Try to get requested refinement level or the nearest acceptable level:\n    //\n    string hgtvar = rParams->GetHeightVariableName();\n    VAssert(!hgtvar.empty());\n\n    Grid *hgtGrid = NULL;\n    int   rc = DataMgrUtils::GetGrids(dataMgr, ts, hgtvar, minExtsReq, maxExtsReq, true, &refLevel, &lod, &hgtGrid);\n    if (rc < 0) return (rc);\n    VAssert(hgtGrid);\n\n    auto dims = g->GetDimensions();\n    VAssert(dims[2] == 1);\n\n    size_t   width = dims[0];\n    size_t   height = dims[1];\n    GLfloat *verts = (GLfloat *)_sb_verts.GetBuf();\n    double   mv = hgtGrid->GetMissingValue();\n    for (int j = 0; j < height; j++) {\n        for (int i = 0; i < width; i++) {\n            double x, y, zdummy;\n            g->GetUserCoordinates(i, j, x, y, zdummy);\n\n            // Lookup vertical coordinate displacement as a data element from the\n            // height variable. Note, missing values are possible if image\n            // extents are out side of extents for height variable, or if\n            // height variable itself contains missing values.\n            //\n            double deltaZ = hgtGrid->GetValue(x, y, 0.0);\n            if (deltaZ == mv) deltaZ = 0.0;\n\n            double z = deltaZ - defaultZ;\n\n            verts[j * width * 3 + i * 3] = x;\n            verts[j * width * 3 + i * 3 + 1] = y;\n            verts[j * width * 3 + i * 3 + 2] = z;\n        }\n    }\n\n    delete hgtGrid;\n\n    return (rc);\n}\n\n// Get mesh for a structured grid that is NOT displaced by a height field.\n// I.e. it's planar.\n//\nint TwoDDataRenderer::_getMeshStructuredPlane(DataMgr *dataMgr, const StructuredGrid *g, double defaultZ)\n{\n    auto dims = g->GetDimensions();\n    VAssert(dims[2] == 1);\n\n    size_t   width = dims[0];\n    size_t   height = dims[1];\n    GLfloat *verts = (GLfloat *)_sb_verts.GetBuf();\n    for (int j = 0; j < height; j++) {\n        for (int i = 0; i < width; i++) {\n            double x, y, zdummy;\n            g->GetUserCoordinates(i, j, x, y, zdummy);\n\n            double z = defaultZ;\n\n            verts[j * width * 3 + i * 3] = x;\n            verts[j * width * 3 + i * 3 + 1] = y;\n            verts[j * width * 3 + i * 3 + 2] = z;\n        }\n    }\n\n    return (0);\n}\n\nint TwoDDataRenderer::_getOrientation(DataMgr *dataMgr, string varname)\n{\n    vector<string> coordvars;\n    bool ok = dataMgr->GetVarCoordVars(varname, true, coordvars);\n    if (!ok) return -1;\n    VAssert(coordvars.size() == 2);\n\n    vector<int> axes;    // order list of coordinate axes\n    for (int i = 0; i < coordvars.size(); i++) {\n        DC::CoordVar cvar;\n        dataMgr->GetCoordVarInfo(coordvars[i], cvar);\n\n        axes.push_back(cvar.GetAxis());\n    }\n\n    if (axes[0] == 0) {\n        if (axes[1] == 1)\n            return (2);    // X-Y\n        else\n            return (1);    // X-Z\n    }\n\n    VAssert(axes[0] == 1 && axes[2] == 2);\n    return (0);    // Y-Z\n}\n\n// Sets _texWidth, _texHeight, _sb_texture\n//\nconst GLvoid *TwoDDataRenderer::_getTexture(DataMgr *dataMgr)\n{\n    // See if already in cache\n    //\n    if (!_texStateDirty(dataMgr) && _sb_texture.GetBuf()) { return ((const GLvoid *)_sb_texture.GetBuf()); }\n    _texStateClear();\n\n    TwoDDataParams *rParams = (TwoDDataParams *)GetActiveParams();\n    size_t          ts = rParams->GetCurrentTimestep();\n\n    int refLevel = rParams->GetRefinementLevel();\n    int lod = rParams->GetCompressionLevel();\n\n    string varname = rParams->GetVariableName();\n    if (varname.empty()) {\n        SetErrMsg(\"No variable name specified\");\n        return (NULL);\n    }\n\n    // Find box extents for ROI\n    //\n    CoordType minBoxReq = {0.0, 0.0, 0.0};\n    CoordType maxBoxReq = {0.0, 0.0, 0.0};\n    rParams->GetBox()->GetExtents(minBoxReq, maxBoxReq);\n\n    Grid *g = NULL;\n    int   rc = DataMgrUtils::GetGrids(dataMgr, ts, varname, minBoxReq, maxBoxReq, true, &refLevel, &lod, &g);\n    if (rc < 0) return (NULL);\n\n    if (g->GetTopologyDim() != 2) {\n        SetErrMsg(\"Invalid variable: %s \", varname.c_str());\n        return (NULL);\n    }\n\n    // For structured grid variable data are stored in a 2D array.\n    // For structured grid variable data are stored in a 1D array.\n    //\n    auto dims = g->GetDimensions();\n    if (dynamic_cast<StructuredGrid *>(g) && !ForceUnstructured) {\n        _texWidth = dims[0];\n        _texHeight = dims[1];\n    } else {\n        _texWidth = std::accumulate(dims.begin(), dims.end(), 1, std::multiplies<size_t>());\n        _texHeight = 1;\n    }\n\n    size_t         texSize = _texWidth * _texHeight;\n    GLfloat *      texture = (float *)_sb_texture.Alloc(texSize * _texelSize);\n    GLfloat *      texptr = texture;\n    Grid::Iterator itr;\n    Grid::Iterator enditr = g->end();\n    //\tfor (itr = g->begin(minBoxReq, maxBoxReq); itr != enditr; ++itr) {\n    for (itr = g->begin(); itr != enditr; ++itr) {\n        float v = *itr;\n\n        if (v == g->GetMissingValue()) {\n            *texptr++ = 0.0;    // Data value\n            *texptr++ = 1.0;    // Missing value flag\n        } else {\n            *texptr++ = v;\n            *texptr++ = 0;\n        }\n    }\n\n    _texStateSet(dataMgr);\n\n    return (texture);\n}\n"
  },
  {
    "path": "lib/render/TwoDRenderer.cpp",
    "content": "//---------------------------------------------------------------------------\n//\n//                   Copyright (C)  2011\n//     University Corporation for Atmospheric Research\n//                   All Rights Reserved\n//\n//----------------------------------------------------------------------------\n\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <cstdlib>\n#include <cstdio>\n\n#include <vapor/ViewpointParams.h>\n#include <vapor/MyBase.h>\n#include <vapor/TwoDRenderer.h>\n#include \"vapor/GLManager.h\"\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nTwoDRenderer::TwoDRenderer(const ParamsMgr *pm, string winName, string dataSetName, string paramsType, string classType, string instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, paramsType, classType, instName, dataMgr)\n{\n    _textureID = 0;\n    _texture = NULL;\n    _texCoords = NULL;\n    _texWidth = 0;\n    _texHeight = 0;\n    _texInternalFormat = 0;\n    _texFormat = GL_RGBA;\n    _texType = GL_UNSIGNED_BYTE;\n    _texelSize = 0;\n    _gridAligned = false;\n    _structuredMesh = false;\n    _verts = NULL;\n    _normals = NULL;\n    _meshWidth = 0;\n    _meshHeight = 0;\n    _VAO = (int)NULL;\n    _VBO = (int)NULL;\n    _dataVBO = (int)NULL;\n    _EBO = (int)NULL;\n}\n\n//----------------------------------------------------------------------------\n//\n//----------------------------------------------------------------------------\nTwoDRenderer::~TwoDRenderer()\n{\n    if (_textureID) glDeleteTextures(1, &_textureID);\n    if (_VAO) glDeleteVertexArrays(1, &_VAO);\n    if (_VBO) glDeleteBuffers(1, &_VBO);\n    if (_dataVBO) glDeleteBuffers(1, &_dataVBO);\n    if (_EBO) glDeleteBuffers(1, &_EBO);\n}\n\nint TwoDRenderer::_initializeGL()\n{\n    glGenTextures(1, &_textureID);\n    glGenVertexArrays(1, &_VAO);\n    glGenBuffers(1, &_VBO);\n    glGenBuffers(1, &_dataVBO);\n    glGenBuffers(1, &_EBO);\n\n    glBindVertexArray(_VAO);\n\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), NULL);\n    glEnableVertexAttribArray(0);\n\n    glBindBuffer(GL_ARRAY_BUFFER, _dataVBO);\n    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), NULL);\n    glEnableVertexAttribArray(1);\n\n    glBindVertexArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    return (0);\n}\n\nint TwoDRenderer::_paintGL(bool)\n{\n    // Get the 2D texture\n    //\n    _texture = GetTexture(_dataMgr, _texWidth, _texHeight, _texInternalFormat, _texFormat, _texType, _texelSize, _gridAligned);\n    if (!_texture) { return (-1); }\n    VAssert(_texWidth >= 1);\n    VAssert(_texHeight >= 1);\n\n    // Get the proxy geometry used to render the 2D surface (vertices and\n    // normals)\n    //\n    int rc = GetMesh(_dataMgr, &_verts, &_normals, _nverts, _meshWidth, _meshHeight, &_indices, _nindices, _structuredMesh);\n    if (rc < 0) { return (-1); }\n\n    if (!_gridAligned) {\n        VAssert(_structuredMesh);\n        if (_meshWidth<2 || _meshHeight<2) return 0; // If mesh with or height is too small for a texture, harmlessly return\n\n        _texCoords = (GLfloat *)_sb_texCoords.Alloc(_meshWidth * _meshHeight * 2 * sizeof(*_texCoords));\n        _computeTexCoords(_texCoords, _meshWidth, _meshHeight);\n        _renderMeshUnAligned();\n    } else {\n        VAssert(_meshWidth == _texWidth);\n        VAssert(_meshHeight == _texHeight);\n\n        _renderMeshAligned();\n    }\n\n    GL_ERR_BREAK();\n\n    return (0);\n}\n\nvoid TwoDRenderer::_openGLInit()\n{\n    if (!_gridAligned) {\n        glActiveTexture(GL_TEXTURE0);\n        glBindTexture(GL_TEXTURE_2D, _textureID);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n        glTexImage2D(GL_TEXTURE_2D, 0, _texInternalFormat, _texWidth, _texHeight, 0, _texFormat, _texType, _texture);\n    }\n\n    _glManager->matrixManager->MatrixModeModelView();\n\n    glEnable(GL_BLEND);\n    glEnable(GL_DEPTH_TEST);\n\n    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    glDepthMask(GL_TRUE);\n}\n\nvoid TwoDRenderer::_openGLRestore()\n{\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glDisable(GL_BLEND);\n    glDisable(GL_DEPTH_TEST);\n    glDepthMask(GL_FALSE);\n}\n\nvoid TwoDRenderer::_renderMeshUnAligned()\n{\n    // This appears to be pretty much the Image Renderer code\n\n    RenderParams *myParams = (RenderParams *)GetActiveParams();\n    float         opacity = myParams->GetConstantOpacity();\n\n    ShaderProgram *shader = _glManager->shaderManager->GetShader(\"Image\");\n    if (shader == nullptr) return;\n    shader->Bind();\n    shader->SetUniform(\"MVP\", _glManager->matrixManager->GetModelViewProjectionMatrix());\n    shader->SetUniform(\"constantOpacity\", opacity);\n\n    EnableClipToBox(shader);\n    _openGLInit();\n\n    int W = _meshWidth;\n    int H = _meshHeight;\n\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * W * sizeof(GLuint), _indices, GL_DYNAMIC_DRAW);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glBufferData(GL_ARRAY_BUFFER, H * W * 3 * sizeof(float), _verts, GL_DYNAMIC_DRAW);\n    glBindBuffer(GL_ARRAY_BUFFER, _dataVBO);\n    glBufferData(GL_ARRAY_BUFFER, H * W * 2 * sizeof(float), _texCoords, GL_DYNAMIC_DRAW);\n\n    for (int j = 0; j < H - 1; j++) glDrawElementsBaseVertex(GL_TRIANGLE_STRIP, 2 * W, GL_UNSIGNED_INT, 0, j * W);\n\n    glBindVertexArray(0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    _openGLRestore();\n    DisableClippingPlanes();\n}\n\nvoid TwoDRenderer::_renderMeshAligned()\n{\n    RenderParams *myParams = (RenderParams *)GetActiveParams();\n    float         opacity = myParams->GetConstantOpacity();\n\n    ShaderProgram *shader = _glManager->shaderManager->GetShader(\"2DData\");\n    if (shader == nullptr) return;\n    shader->Bind();\n    shader->SetUniform(\"MVP\", _glManager->matrixManager->GetModelViewProjectionMatrix());\n    shader->SetUniform(\"constantOpacity\", opacity);\n\n    EnableClipToBox(shader);\n    _openGLInit();\n\n    // Ugh. For aligned data the type must be GLfloat.\n    //\n    VAssert(_texType == GL_FLOAT);\n    VAssert(_texelSize == 8);\n    const GLfloat *data = (GLfloat *)_texture;\n\n    if (_structuredMesh) {\n        // Draw triangle strips one row at a time\n        //\n        glBindVertexArray(_VAO);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * _meshWidth * sizeof(GLuint), _indices, GL_DYNAMIC_DRAW);\n        for (int j = 0; j < _meshHeight - 1; j++) {\n            glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n            glBufferData(GL_ARRAY_BUFFER, _meshWidth * 6 * sizeof(float), &_verts[j * _meshWidth * 3], GL_STREAM_DRAW);\n            glBindBuffer(GL_ARRAY_BUFFER, _dataVBO);\n            glBufferData(GL_ARRAY_BUFFER, _meshWidth * 4 * sizeof(float), &data[j * _meshWidth * 2], GL_STREAM_DRAW);\n            glDrawElements(GL_TRIANGLE_STRIP, 2 * _meshWidth, GL_UNSIGNED_INT, 0);\n        }\n    } else {\n        VAssert(_meshWidth >= 3);\n        VAssert(_meshHeight == 1);\n        VAssert((_nindices % 3) == 0);\n\n        glBindVertexArray(_VAO);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, _nindices * sizeof(GLsizei), _indices, GL_STREAM_DRAW);\n        glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n        glBufferData(GL_ARRAY_BUFFER, _nverts * 3 * sizeof(float), _verts, GL_STREAM_DRAW);\n        glBindBuffer(GL_ARRAY_BUFFER, _dataVBO);\n        glBufferData(GL_ARRAY_BUFFER, _nverts * 2 * sizeof(float), data, GL_STREAM_DRAW);\n        // glNormalPointer(GL_FLOAT, 0, _normals);\n        glDrawElements(GL_TRIANGLES, _nindices, GL_UNSIGNED_INT, 0);\n    }\n    glBindVertexArray(0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n\n    _openGLRestore();\n    DisableClippingPlanes();\n}\n\nvoid TwoDRenderer::ComputeNormals(const GLfloat *verts, GLsizei w, GLsizei h, GLfloat *normals)\n{\n    // Go over the grid of vertices, calculating normals\n    // by looking at adjacent x,y,z coords.\n    //\n    for (int j = 0; j < h; j++) {\n        for (int i = 0; i < w; i++) {\n            const GLfloat *point = verts + 3 * (i + w * j);\n            GLfloat *      norm = normals + 3 * (i + w * j);\n            // do differences of right point vs left point,\n            // except at edges of grid just do differences\n            // between current point and adjacent point:\n            float dx = 0.f, dy = 0.f, dzx = 0.f, dzy = 0.f;\n            if (i > 0 && i < w - 1) {\n                dx = *(point + 3) - *(point - 3);\n                dzx = *(point + 5) - *(point - 1);\n            } else if (i == 0) {\n                dx = *(point + 3) - *(point);\n                dzx = *(point + 5) - *(point + 2);\n            } else if (i == w - 1) {\n                dx = *(point) - *(point - 3);\n                dzx = *(point + 2) - *(point - 1);\n            }\n            if (j > 0 && j < h - 1) {\n                dy = *(point + 1 + 3 * w) - *(point + 1 - 3 * w);\n                dzy = *(point + 2 + 3 * w) - *(point + 2 - 3 * w);\n            } else if (j == 0) {\n                dy = *(point + 1 + 3 * w) - *(point + 1);\n                dzy = *(point + 2 + 3 * w) - *(point + 2);\n            } else if (j == h - 1) {\n                dy = *(point + 1) - *(point + 1 - 3 * w);\n                dzy = *(point + 2) - *(point + 2 - 3 * w);\n            }\n            norm[0] = dy * dzx;\n            norm[1] = dx * dzy;\n            norm[2] = 1.0;\n\n            // vnormal(norm);\n        }\n    }\n}\n\nvoid TwoDRenderer::_computeTexCoords(GLfloat *tcoords, size_t w, size_t h) const\n{\n    if (_meshWidth<2 || _meshHeight<2) return;\n\n    double deltax = 1.0 / (_meshWidth - 1);\n    double deltay = 1.0 / (_meshHeight - 1);\n\n    for (int j = 0; j < h; j++) {\n        for (int i = 0; i < w; i++) {\n            tcoords[(2 * j * w) + (2 * i + 0)] = i * deltax;\n            tcoords[(2 * j * w) + (2 * i + 1)] = j * deltay;\n        }\n    }\n}\n"
  },
  {
    "path": "lib/render/Visualizer.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tVisualizer.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tSeptember, 2013\n//\n#include <vapor/glutil.h>    // Must be included first!!!\n#include <limits>\n#include <algorithm>\n#include <vector>\n#include <cmath>\n#include \"vapor/VAssert.h\"\n#ifdef WIN32\n    #include <tiff/tiffio.h>\n#else\n    #include <tiffio.h>\n    #include <xtiffio.h>\n#endif\n\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n#endif\n\n#include \"vapor/ContourRenderer.h\"\n\n\n#include <vapor/RenderParams.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/regionparams.h>\n#include <vapor/Renderer.h>\n#include <vapor/DataStatus.h>\n#include <vapor/Visualizer.h>\n#include <vapor/FileUtils.h>\n#include <vapor/STLUtils.h>\n\n#include <vapor/common.h>\n#include \"vapor/GLManager.h\"\n#include \"vapor/LegacyGL.h\"\n#include <vapor/ShaderManager.h>\n\n#include \"vapor/ImageWriter.h\"\n#include \"vapor/GeoTIFWriter.h\"\n#include \"vapor/ImageRenderer.h\"\n#include \"vapor/VolumeRenderer.h\"\n#include \"vapor/WireFrameRenderer.h\"\n\nusing namespace VAPoR;\n\nVisualizer::Visualizer(const ParamsMgr *pm, const DataStatus *dataStatus, string winName)\n{\n    MyBase::SetDiagMsg(\"Visualizer::Visualizer() begin\");\n\n    _paramsMgr = pm;\n    _dataStatus = dataStatus;\n    _winName = winName;\n    _glManager = nullptr;\n    _vizFeatures = new AnnotationRenderer(_paramsMgr, _dataStatus, _winName);\n    _insideGLContext = false;\n    _imageCaptureEnabled = false;\n    _animationCaptureEnabled = false;\n\n    _renderers.clear();\n    _renderersToDestroy.clear();\n\n    MyBase::SetDiagMsg(\"Visualizer::Visualizer() end\");\n}\n\nVisualizer::~Visualizer()\n{\n#ifdef VAPOR_3_1_0\n    // Can't call renderer destructors because these free OpenGL resources that\n    // may require the OpenGL context to be current :-(\n    //\n    for (int i = 0; i < _renderers.size(); i++) delete _renderers[i];\n    _renderers.clear();\n#endif\n\n    if (_vizFeatures) delete _vizFeatures;\n\n    if (_screenQuadVAO) glDeleteVertexArrays(1, &_screenQuadVAO);\n    if (_screenQuadVBO) glDeleteBuffers(1, &_screenQuadVBO);\n}\n\nint Visualizer::resizeGL(int wid, int ht) { return 0; }\n\nint Visualizer::_getCurrentTimestep() const\n{\n    vector<string> dataSetNames = _dataStatus->GetDataMgrNames();\n\n    bool   first = true;\n    size_t min_ts = 0;\n    size_t max_ts = 0;\n    for (int i = 0; i < dataSetNames.size(); i++) {\n        vector<RenderParams *> rParams;\n        _paramsMgr->GetRenderParams(_winName, dataSetNames[i], rParams);\n\n        if (rParams.size()) {\n            // Use local time of first RenderParams instance on window\n            // for current data set. I.e. it is assumed that every\n            // RenderParams instance for a data set has same current\n            // time step.\n            //\n            size_t local_ts = rParams[0]->GetCurrentTimestep();\n            size_t my_min_ts, my_max_ts;\n            _dataStatus->MapLocalToGlobalTimeRange(dataSetNames[i], local_ts, my_min_ts, my_max_ts);\n            if (first) {\n                min_ts = my_min_ts;\n                max_ts = my_max_ts;\n                first = false;\n            } else {\n                if (my_min_ts > min_ts) min_ts = my_min_ts;\n                if (my_max_ts < max_ts) max_ts = my_max_ts;\n            }\n        }\n    }\n    if (min_ts > max_ts) return (-1);\n\n    return (min_ts);\n}\n\nvoid Visualizer::_applyDatasetTransformsForRenderer(Renderer *r)\n{\n    string     datasetName = r->GetMyDatasetName();\n    Transform *t = getActiveViewpointParams()->GetTransform(datasetName);\n    VAssert(t);\n    Renderer::ApplyDatasetTransform(_glManager, t);\n}\n\nvoid Visualizer::syncWithParams()\n{\n    _deleteFlaggedRenderers();\n\n    vector<Renderer*> toRemove;\n    for (const auto &r : _renderers)\n        if (r->GetActiveParams() == nullptr)\n            toRemove.push_back(r);\n\n    if (_dataStatus->WasCacheDirty())\n        toRemove = _renderers;\n\n    for (const auto &r : toRemove) {\n        _renderers.erase(std::find(_renderers.begin(), _renderers.end(), r));\n        delete r;\n    }\n\n    vector<RenderParams*> populatedRenderParams;\n    for (const auto &r : _renderers)\n        populatedRenderParams.push_back(r->GetActiveParams());\n\n    vector<RenderParams*> rendererParams;\n    _paramsMgr->GetRenderParams(_winName, rendererParams);\n    for (const auto &rp : rendererParams) {\n        if (!STLUtils::Contains(populatedRenderParams, rp)) {\n            string win, dataset, Class, name;\n            _paramsMgr->RenderParamsLookup(rp, name, win, dataset, Class);\n            CreateRenderer(dataset, RendererFactory::Instance()->GetRenderClassFromParamsClass(Class), name);\n        }\n    }\n}\n\nint Visualizer::renderRenderer(Renderer* renderer, bool fast) {\n    _glManager->matrixManager->MatrixModeModelView();\n    _glManager->matrixManager->PushMatrix();\n\n    if (renderer->IsGLInitialized()) {\n        _applyDatasetTransformsForRenderer(renderer);\n\n        // void *t = _glManager->BeginTimer();\n        int myrc = renderer->paintGL(fast);\n        // printf(\"%s: %f\\n\", _renderers[i]->GetMyName().c_str(), _glManager->EndTimer(t));\n        GL_ERR_BREAK();\n        if (myrc < 0) myrc = -1;\n    }\n    MatrixManager *mm = _glManager->matrixManager;\n    mm->MatrixModeModelView();\n    mm->PopMatrix();\n    int myrc = CheckGLErrorMsg(renderer->GetMyName().c_str());\n    if (myrc < 0) myrc = -1;\n    return myrc;\n}\n\nglm::vec3 box_min(const Box* b)\n{\n    CoordType min, max;\n    b->GetExtents(min, max);\n    return glm::make_vec3(min.data());\n}\n\nglm::vec3 box_max(const Box* b)\n{\n    CoordType min, max;\n    b->GetExtents(min, max);\n    return glm::make_vec3(max.data());\n}\n\nstruct AABB {\n    glm::vec3 min, max;\n    AABB() : min(0.f), max(0.f) {}\n    AABB(const glm::vec3 &min, const glm::vec3 &max) : min(min), max(max) {}\n    AABB(const Box *b) : AABB(box_min(b), box_max(b)) {}\n    AABB(const vector<glm::vec3> &pts)\n        : min(pts[0]), max(pts[0])\n    {\n        for (const auto &p : pts) add(p);\n    }\n    void add(const glm::vec3 p)\n    {\n        min = glm::min(min, p);\n        max = glm::max(max, p);\n    }\n    glm::vec3 center() const { return (min+max)*0.5f; }\n    bool intersects(const AABB &b) const { return intersects(*this, b); }\n    static bool intersects(const AABB &a, const AABB &b)\n    {\n        auto al = a.min;\n        auto ah = a.max;\n        auto bl = b.min;\n        auto bh = b.max;\n        return !(\n               bl.x > ah.x\n            || bh.x < al.x\n            || bl.y > ah.y\n            || bh.y < al.y\n            || bl.z > ah.z\n            || bh.z < al.z\n        );\n    }\n    string str() const\n    {\n        return \"{ \"\n        + std::to_string(min.x) + \"->\" + std::to_string(max.x) + \" \"\n        + std::to_string(min.y) + \"->\" + std::to_string(max.y) + \" \"\n        + std::to_string(min.z) + \"->\" + std::to_string(max.z) + \" }\";\n    }\n};\n\nAABB operator*(const glm::mat4 &m, const AABB &b)\n{\n    vector<glm::vec3> pts = {\n        {b.min.x, b.min.y, b.min.z},\n        {b.max.x, b.min.y, b.min.z},\n        {b.min.x, b.max.y, b.min.z},\n        {b.max.x, b.max.y, b.min.z},\n        {b.min.x, b.min.y, b.max.z},\n        {b.max.x, b.min.y, b.max.z},\n        {b.min.x, b.max.y, b.max.z},\n        {b.max.x, b.max.y, b.max.z},\n    };\n\n    for (int i = 0; i < pts.size(); i++)\n        pts[i] = m * glm::vec4(pts[i], 1.0f);\n\n    return {pts};\n}\n\nAABB rendererTransformedBB(const Renderer *r)\n{\n    MatrixManager mm;\n    AABB b = r->GetActiveParams()->GetBox();\n    r->ApplyTransform(&mm);\n    return mm.GetModelViewMatrix() * b;\n}\n\nglm::vec3 rendererTransformedCenter(const Renderer *r)\n{\n    MatrixManager mm;\n    AABB b = r->GetActiveParams()->GetBox();\n    r->ApplyTransform(&mm);\n    return mm.GetModelViewMatrix() * glm::vec4(b.center(), 1.0f);\n}\n\ndouble rendererDistanceToCamera(const Renderer *r)\n{\n    const auto vp = r->GetViewpointParams();\n    glm::vec3 cameraPos;\n    {\n        double cameraPosD[3], _[3];\n        vp->ReconstructCamera(vp->GetModelViewMatrix().data(), cameraPosD, _, _);\n        cameraPos = glm::make_vec3(cameraPosD);\n    }\n    glm::vec3 c = rendererTransformedCenter(r);\n    return glm::length(cameraPos - c);\n}\n\ntemplate <typename T> bool approxEqual(T a, T b)\n{\n    return abs(b-a) <= max(a,b) * std::numeric_limits<T>::epsilon();\n}\n\nauto rankRendererTypeOrder(const Renderer *r) {\n    if (dynamic_cast<const ImageRenderer*>(r)) return 0;\n    if (dynamic_cast<const TwoDRenderer*>(r)) return 1;\n    auto w = dynamic_cast<const WireFrameRenderer*>(r);\n    if (w && w->GetActiveParams()->GetRenderDim() == 2) return 2;\n    if (dynamic_cast<const ContourRenderer*>(r)) return 3;\n    return 4;\n};\n\nstd::pair<map<Renderer*, vector<double>>, vector<Renderer*>> autoOrder2DRenderers(const vector<Renderer*> &in)\n{\n    if (in.empty()) return {};\n    auto ret = in;\n\n    std::sort(ret.begin(), ret.end(), [](const Renderer *a, const Renderer *b) {\n        float az = rendererTransformedCenter(a).z;\n        float bz = rendererTransformedCenter(b).z;\n        if (!approxEqual(az, bz))\n            return az < bz;\n\n        if (!rendererTransformedBB(a).intersects(rendererTransformedBB(b)))\n            return rendererTransformedCenter(a).x < rendererTransformedCenter(b).x;\n\n        if (rankRendererTypeOrder(a) != rankRendererTypeOrder(b))\n            return rankRendererTypeOrder(a) < rankRendererTypeOrder(b);\n\n        return a->GetInstanceName() < b->GetInstanceName();\n    });\n\n    map<Renderer*, vector<double>> ogTrans;\n\n    int starti = 0;\n    // string startData = in[0]->GetMyDatasetName();\n    double offsetCum = 0;\n    for (int i = 0; i <= ret.size(); i++) {\n        if (i == ret.size() || ret[i]->GetActiveParams()->GetTransform()->GetTranslations()[2] != 0) {\n            for (int j = starti; j < i && i-starti>1; j++) {\n                ogTrans[ret[j]] = ret[j]->GetActiveParams()->GetTransform()->GetTranslations();\n                double offset = rendererDistanceToCamera(ret[j]) / ret[j]->GetDatasetTransform()->GetScales()[2] * 0.0003;\n                ret[j]->GetActiveParams()->GetTransform()->SetTranslations({ogTrans[ret[j]][0], ogTrans[ret[j]][1], offsetCum + offset});\n                offsetCum += offset;\n            }\n            starti = i;\n            // startData = i==ret.size() ? \"\" : in[i]->GetMyDatasetName();\n        }\n    }\n\n    return std::make_pair(ogTrans, ret);\n}\n\nvector<Renderer*> getRenderOrder(const vector<Renderer*> &in)\n{\n    if (in.empty()) return {};\n    const auto vp = in[0]->GetViewpointParams();\n    glm::vec3 cameraPos;\n    {\n        double cameraPosD[3], _[3];\n        vp->ReconstructCamera(vp->GetModelViewMatrix().data(), cameraPosD, _, _);\n        cameraPos = glm::make_vec3(cameraPosD);\n    }\n\n    // Not accounting for slice planes since those are currently not considered planar by the code\n\n    list<tuple<Renderer*, glm::vec3, AABB>> order;\n\n    auto transformedRenderer = [](Renderer *r) {\n        MatrixManager mm;\n        AABB b = r->GetActiveParams()->GetBox();\n        r->ApplyTransform(&mm);\n        glm::vec3 c = mm.GetModelViewMatrix() * glm::vec4(b.center(), 1.0f);\n        b = mm.GetModelViewMatrix() * b;\n        return make_tuple(r, c, b);\n    };\n\n    for (auto r : in) {\n        if (dynamic_cast<VolumeRenderer *>(r)) continue;\n        const auto tr = transformedRenderer(r);\n        float cameraDist = glm::length(cameraPos - std::get<1>(tr));\n\n        for (auto it = order.begin();; ++it) {\n            if (it == order.end()) {\n                order.insert(it, tr);\n                break;\n            }\n\n            float itCameraDist = glm::length(cameraPos - std::get<1>(*it));\n            if (cameraDist > itCameraDist) {\n                order.insert(it, tr);\n                break;\n            }\n        }\n    }\n\n    for (auto r : in) {\n        if (!dynamic_cast<VolumeRenderer *>(r)) continue;\n        const auto tr = transformedRenderer(r);\n        float cameraDist = glm::length(cameraPos - std::get<1>(tr));\n\n        for (auto it = order.begin();; ++it) {\n            if (it == order.end()) {\n                order.insert(it, tr);\n                break;\n            }\n\n            float itCameraDist = glm::length(cameraPos - std::get<1>(*it));\n            if (cameraDist > itCameraDist && !std::get<2>(tr).intersects(std::get<2>(*it))) {\n                order.insert(it, tr);\n                break;\n            }\n        }\n    }\n\n    vector<Renderer*> ret;\n    for (auto tr : order)\n        ret.push_back(std::get<0>(tr));\n\n    return ret;\n}\n\nint Visualizer::paintEvent(bool fast)\n{\n    _insideGLContext = true;\n    MyBase::SetDiagMsg(\"Visualizer::paintGL()\");\n    GL_ERR_BREAK();\n\n    // Do not proceed if there is no DataMgr\n    if (!_paramsMgr->GetDataMgrNames().size()) return (0);\n\n    syncWithParams();\n    if (_initializeNewRenderers() < 0) return -1;\n\n    // Do not proceed with invalid viewport\n    // This can occur sometimes on Qt startup\n    int viewport[4];\n    glGetIntegerv(GL_VIEWPORT, viewport);\n    if (viewport[2] <= 0) return 0;\n    if (viewport[3] <= 0) return 0;\n\n    assert(_framebuffer.IsComplete());\n    _clearActiveFramebuffer(0.3, 0.3, 0.3);\n    GL_ERR_BREAK();\n\n    int fbWidth = viewport[2];\n    int fbHeight = viewport[3];\n\n    ViewpointParams *vp = getActiveViewpointParams();\n    if (vp->GetValueLong(ViewpointParams::UseCustomFramebufferTag, 0)) {\n        fbWidth = vp->GetValueLong(ViewpointParams::CustomFramebufferWidthTag, 0);\n        fbHeight = vp->GetValueLong(ViewpointParams::CustomFramebufferHeightTag, 0);\n    }\n    _framebuffer.SetSize(fbWidth, fbHeight);\n\n    GLint destFbId;\n    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &destFbId);\n    _framebuffer.MakeRenderTarget();\n    GL_ERR_BREAK();\n\n    double clr[3];\n    getActiveAnnotationParams()->GetBackgroundColor(clr);\n    _clearActiveFramebuffer(clr[0], clr[1], clr[2]);\n\n    _loadMatricesFromViewpointParams();\n    if (_configureLighting()) return -1;\n\n    glDepthMask(GL_TRUE);\n    glEnable(GL_DEPTH_TEST);\n    glEnable(GL_BLEND);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    // Draw the domain frame and other in-scene features\n    _vizFeatures->InScenePaint(_getCurrentTimestep());\n    GL_ERR_BREAK();\n\n    auto ret = autoOrder2DRenderers(_renderers);\n    auto rendererTransOg = ret.first;\n    auto renderersOrdered = ret.second;\n    renderersOrdered = getRenderOrder(renderersOrdered);\n\n    std::vector<Renderer*> topRenderers;\n    int rc = 0;\n    for (int i = 0; i < renderersOrdered.size(); i++) {\n        RenderParams* rp = _paramsMgr->GetRenderParams(_winName, renderersOrdered[i]->GetMyDatasetName(), renderersOrdered[i]->GetMyParamsType(), renderersOrdered[i]->GetMyName());\n        if (rp != nullptr && rp->GetDrawInFront()) {\n            topRenderers.push_back(renderersOrdered[i]);\n            continue;\n        }\n        rc = renderRenderer(renderersOrdered[i], fast);\n    }\n\n    glDepthFunc(GL_ALWAYS);\n    glDisable(GL_DEPTH_TEST);\n    for (int i=0; i<topRenderers.size(); i++) {\n        renderRenderer(topRenderers[i], fast);\n    }\n    glDepthFunc(GL_LESS);\n    glDepthMask(GL_TRUE);\n\n    for (auto it : rendererTransOg) {\n        it.first->GetActiveParams()->GetTransform()->SetTranslations(it.second);\n    }\n\n    _vizFeatures->DrawText();\n    GL_ERR_BREAK();\n    _renderColorbars(_getCurrentTimestep());\n    GL_ERR_BREAK();\n    _vizFeatures->DrawAxisArrows();\n    GL_ERR_BREAK();\n\n    // _glManager->ShowDepthBuffer();\n\n    glFlush();\n\n    int captureImageSuccess = 0;\n    if (_imageCaptureEnabled) {\n        captureImageSuccess = _captureImage(_captureImageFile);\n    } else if (_animationCaptureEnabled) {\n        captureImageSuccess = _captureImage(_captureImageFile);\n        _incrementPath(_captureImageFile);\n    }\n    if (captureImageSuccess < 0) {\n        SetErrMsg(\"Failed to save image\");\n        return -1;\n    }\n\n    GL_ERR_BREAK();\n    if (CheckGLError()) return -1;\n\n    _framebuffer.UnBind();\n    glBindFramebuffer(GL_FRAMEBUFFER, destFbId);\n    glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);\n    glBindVertexArray(_screenQuadVAO);\n    SmartShaderProgram shader = _glManager->shaderManager->GetSmartShader(\"Framebuffer\");\n    if (!shader.IsValid()) return -1;\n    shader->SetSampler(\"colorBuffer\", *_framebuffer.GetColorTexture());\n    shader->SetSampler(\"depthBuffer\", *_framebuffer.GetDepthTexture());\n\n    glDepthFunc(GL_LEQUAL);\n    glDepthMask(true);\n    glEnable(GL_DEPTH_TEST);\n\n    glDrawArrays(GL_TRIANGLES, 0, 6);\n    glBindVertexArray(0);\n    glDepthFunc(GL_LESS);\n\n    _insideGLContext = false;\n    return rc;\n}\n\nvoid Visualizer::_loadMatricesFromViewpointParams()\n{\n    ViewpointParams *const vpParams = getActiveViewpointParams();\n    MatrixManager *const   mm = _glManager->matrixManager;\n\n    double m[16];\n    vpParams->GetProjectionMatrix(m);\n    mm->MatrixModeProjection();\n    mm->LoadMatrixd(m);\n\n    vpParams->GetModelViewMatrix(m);\n    mm->MatrixModeModelView();\n    mm->LoadMatrixd(m);\n}\n\nint Visualizer::InitializeGL(GLManager *glManager)\n{\n    if (!glManager->IsCurrentOpenGLVersionSupported()) return -1;\n\n    _glManager = glManager;\n    _vizFeatures->InitializeGL(glManager);\n\n    if (GetVendor() == MESA) {\n        SetErrMsg(\n            \"Your device appears to either not have hardware graphics support, or not have graphics drivers configured correctly for your device.\\n\"\n            \"Rendering performance may be significantly diminished, or in the case of some renderers, may not function at all.\"\n            );\n    }\n\n    _framebuffer.EnableDepthBuffer();\n    _framebuffer.Generate();\n\n    static float data[] = {-1, -1, 0, 0, 1, -1, 1, 0, -1, 1, 0, 1,\n\n                           -1, 1,  0, 1, 1, -1, 1, 0, 1,  1, 1, 1};\n    glGenVertexArrays(1, &_screenQuadVAO);\n    glGenBuffers(1, &_screenQuadVBO);\n    glBindVertexArray(_screenQuadVAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _screenQuadVBO);\n    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);\n    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL);\n    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n\n    return 0;\n}\n\n// Move to back of rendering list\nvoid Visualizer::MoveRendererToFront(string renderType, string renderName)\n{\n    Renderer *ren = _getRenderer(renderType, renderName);\n    if (!ren) return;\n\n    auto it = std::find(_renderers.begin(), _renderers.end(), ren);\n    VAssert(it != _renderers.end());\n    _renderers.erase(it);\n    _renderers.push_back(ren);\n}\n\nvoid Visualizer::MoveRenderersOfTypeToFront(const std::string &type)\n{\n    Renderer *firstRendererMoved = nullptr;\n    auto      rendererPointersCopy = _renderers;\n    for (auto it = rendererPointersCopy.rbegin(); it != rendererPointersCopy.rend(); ++it) {\n        if (*it == firstRendererMoved) break;\n        if ((*it)->GetMyType() == type) {\n            MoveRendererToFront((*it)->GetMyType(), (*it)->GetMyName());\n            if (firstRendererMoved == nullptr) firstRendererMoved = *it;\n        }\n    }\n}\n\nint Visualizer::CreateRenderer(string dataSetName, string renderType, string renderName)\n{\n    if (HasRenderer(renderType, renderName)) return (0);\n\n    Renderer *ren = RendererFactory::Instance()->CreateInstance(_paramsMgr, _winName, dataSetName, renderType, renderName, _dataStatus->GetDataMgr(dataSetName));\n\n    if (!ren) {\n        SetErrMsg(\"Invalid renderer of type \\\"%s\\\"\", renderType.c_str());\n        return (-1);\n    }\n\n    _renderers.push_back(ren);\n    return (0);\n}\n\nvoid Visualizer::DestroyRenderer(string renderType, string renderName, bool haveOpenGLContext)\n{\n    Renderer *ren = _getRenderer(renderType, renderName);\n    if (!ren) return;\n\n    _renderers.erase(std::find(_renderers.begin(), _renderers.end(), ren));\n\n    // If we have an active OpenGL context destroy the renderer immediately. Else\n    // queue for later destruction\n    //\n    if (haveOpenGLContext) {\n        delete ren;\n        return;\n    }\n\n    // Don't add to queue if already there\n    //\n    for (auto it = _renderersToDestroy.begin(); it != _renderersToDestroy.end(); ++it) {\n        if (*it == ren) return;\n    }\n\n    _renderersToDestroy.push_back(ren);\n}\n\nvoid Visualizer::DestroyAllRenderers(bool hasOpenGLContext)\n{\n    vector<Renderer *> renderersCopy = _renderers;\n\n    for (auto it = renderersCopy.begin(); it != renderersCopy.end(); ++it) {\n        Renderer *ren = *it;\n        DestroyRenderer(ren->GetMyType(), ren->GetMyName(), hasOpenGLContext);\n    }\n}\n\nbool Visualizer::HasRenderer(string renderType, string renderName) const { return (_getRenderer(renderType, renderName) != nullptr); }\n\nvoid Visualizer::ClearRenderCache()\n{\n    for (int i = 0; i < _renderers.size(); i++) { _renderers[i]->ClearCache(); }\n}\n\nvoid Visualizer::ClearRenderCache(const string &inst)\n{\n    for (int i = 0; i < _renderers.size(); i++)\n        if (_renderers[i]->GetInstanceName() == inst)\n            _renderers[i]->ClearCache();\n}\n\nRenderer *Visualizer::_getRenderer(string type, string instance) const\n{\n    for (auto it = _renderers.begin(); it != _renderers.end(); ++it) {\n        Renderer *ren = *it;\n        if (ren->GetMyType() == type && ren->GetMyName() == instance) { return (ren); }\n    }\n    return (NULL);\n}\n\nint Visualizer::_configureLighting()\n{\n    const ViewpointParams *vpParams = getActiveViewpointParams();\n    size_t                 nLights = vpParams->getNumLights();\n    VAssert(nLights <= 1);\n    LegacyGL *lgl = _glManager->legacy;\n\n    float lightDir[4];\n    for (int i = 0; i < 4; i++) { lightDir[i] = vpParams->getLightDirection(0, i); }\n\n    if (nLights > 0) {\n        // TODO GL\n        // GL_SHININESS = vpParams->getExponent())\n        // vpParams->getSpecularCoeff(0)\n        // vpParams->getDiffuseCoeff(0)\n        // vpParams->getAmbientCoeff()\n        // All the geometry will get a white specular color:\n\n        lgl->LightDirectionfv(lightDir);\n    }\n    if (CheckGLError()) return -1;\n    return 0;\n}\n\nVisualizer::GLVendorType Visualizer::GetVendor()\n{\n    string ven_str((const char *)glGetString(GL_VENDOR));\n    string ren_str((const char *)glGetString(GL_RENDERER));\n\n    for (int i = 0; i < ven_str.size(); i++) {\n        if (isupper(ven_str[i])) ven_str[i] = tolower(ven_str[i]);\n    }\n    for (int i = 0; i < ren_str.size(); i++) {\n        if (isupper(ren_str[i])) ren_str[i] = tolower(ren_str[i]);\n    }\n\n    if ((ven_str.find(\"mesa\") != string::npos) || (ren_str.find(\"mesa\") != string::npos)) {\n        return (MESA);\n    } else if ((ven_str.find(\"nvidia\") != string::npos) || (ren_str.find(\"nvidia\") != string::npos)) {\n        return (NVIDIA);\n    } else if ((ven_str.find(\"ati\") != string::npos) || (ren_str.find(\"ati\") != string::npos)) {\n        return (ATI);\n    } else if ((ven_str.find(\"intel\") != string::npos) || (ren_str.find(\"intel\") != string::npos)) {\n        return (INTEL);\n    }\n    return (UNKNOWN);\n}\n\ndouble Visualizer::getPixelSize() const\n{\n#ifdef VAPOR3_0_0_ALPHA\n    double temp[3];\n\n    // Window height is subtended by viewing angle (45 degrees),\n    // at viewer distance (dist from camera to view center)\n    const AnnotationParams *vfParams = getActiveAnnotationParams();\n    const ViewpointParams * vpParams = getActiveViewpointParams();\n\n    size_t width, height;\n    vpParams->GetWindowSize(width, height);\n\n    double center[3], pos[3];\n    vpParams->GetRotationCenter(center);\n    vpParams->GetCameraPos(pos);\n\n    vsub(center, pos, temp);\n\n    // Apply stretch factor:\n\n    vector<double> stretch = vpParams->GetStretchFactors();\n    for (int i = 0; i < 3; i++) temp[i] = stretch[i] * temp[i];\n    float distToScene = vlength(temp);\n    // tan(45 deg *0.5) is ratio between half-height and dist to scene\n    double halfHeight = tan(M_PI * 0.125) * distToScene;\n    return (2.f * halfHeight / (double)height);\n\n#endif\n    return (0.0);\n}\n\nViewpointParams *Visualizer::getActiveViewpointParams() const { return _paramsMgr->GetViewpointParams(_winName); }\n\nRegionParams *Visualizer::getActiveRegionParams() const { return _paramsMgr->GetRegionParams(_winName); }\n\nAnnotationParams *Visualizer::getActiveAnnotationParams() const { return _paramsMgr->GetAnnotationParams(_winName); }\n\n#include <vapor/STLUtils.h>\n\nint Visualizer::_captureImage(std::string path)\n{\n    // Turn off the single capture flag\n    _imageCaptureEnabled = false;\n\n    ViewpointParams *vpParams = getActiveViewpointParams();\n    int              width, height;\n    //\tvpParams->GetWindowSize(width, height);\n    _framebuffer.GetSize(&width, &height);\n\n    vector<unsigned char> framebuffer(3 * width * height);\n    int                   writeReturn = -1;\n    _getPixelData(framebuffer.data());\n\n    if (STLUtils::BeginsWith(path, \":RAM:\")) {\n        void *ptr;\n        sscanf(path.c_str(), \":RAM:%p\", &ptr);\n\n        memcpy(ptr, framebuffer.data(), sizeof(framebuffer[0]) * 3 * width * height);\n\n        return 0;\n    }\n\n    if (FileUtils::Extension(path) == \"\") path += \".png\";\n    bool         geoTiffOutput = vpParams->GetProjectionType() == ViewpointParams::MapOrthographic && (FileUtils::Extension(path) == \"tif\" || FileUtils::Extension(path) == \"tiff\");\n    ImageWriter *writer = nullptr;\n\n    if (geoTiffOutput)\n        writer = new GeoTIFWriter(path);\n    else\n        writer = ImageWriter::CreateImageWriterForFile(path);\n    if (writer == nullptr) goto captureImageEnd;\n\n    if (geoTiffOutput) {\n        VAssert(_dataStatus->GetDataMgrNames().size());\n        string projString = _dataStatus->GetDataMgr(_dataStatus->GetDataMgrNames()[0])->GetMapProjection();\n\n        CoordType dataMinExtents, dataMaxExtents;\n        _dataStatus->GetActiveExtents(_paramsMgr, _winName, _getCurrentTimestep(), dataMinExtents, dataMaxExtents);\n\n        double m[16];\n        vpParams->GetModelViewMatrix(m);\n        double posvec[3], upvec[3], dirvec[3];\n        vpParams->ReconstructCamera(m, posvec, upvec, dirvec);\n\n        float s = vpParams->GetOrthoProjectionSize();\n        float x = posvec[0];\n        float y = posvec[1];\n        float aspect = width / (float)height;\n\n        float pixelScale[2] = {s * aspect * 2 / (float)width, s * 2 / (float)height};\n\n        // Crop to data extents\n\n        double cameraMinExtents[2] = {x - s * aspect, y - s};\n        double cameraMaxExtents[2] = {x + s * aspect, y + s};\n\n        int    cropMin[2] = {0, 0};\n        double newCameraMinExtents[2] = {cameraMinExtents[0], cameraMinExtents[1]};\n        for (int i = 0; i < 2; i++) {\n            if (cameraMinExtents[i] < dataMinExtents[i]) {\n                newCameraMinExtents[i] = dataMinExtents[i];\n                cropMin[i] = (dataMinExtents[i] - cameraMinExtents[i]) / pixelScale[i];\n            }\n        }\n\n        int    cropMax[2] = {(int)width, (int)height};\n        double newCameraMaxExtents[2] = {cameraMaxExtents[0], cameraMaxExtents[1]};\n        for (int i = 0; i < 2; i++) {\n            if (cameraMaxExtents[i] > dataMaxExtents[i]) {\n                newCameraMaxExtents[i] = dataMaxExtents[i];\n                cropMax[i] = cropMax[i] - (cameraMaxExtents[i] - dataMaxExtents[i]) / pixelScale[i];\n            }\n        }\n\n        int croppedWidth = cropMax[0] - cropMin[0];\n        int croppedHeight = cropMax[1] - cropMin[1];\n\n        if (croppedWidth <= 0 || croppedHeight <= 0) {\n            MyBase::SetErrMsg(\"Dataset not visible\");\n            writeReturn = -1;\n            goto captureImageEnd;\n        }\n\n        // flip Y\n        int temp = cropMin[1];\n        cropMin[1] = height - cropMax[1];\n        cropMax[1] = height - temp;\n\n        vector<unsigned char> croppedFB(3 * croppedWidth * croppedHeight);\n        for (int y = 0; y < croppedHeight; y++) memcpy(&croppedFB[3 * y * croppedWidth], &framebuffer[3 * ((y + cropMin[1]) * width + cropMin[0])], 3 * croppedWidth);\n\n        framebuffer = croppedFB;\n\n        s *= croppedHeight / (float)height;\n\n        x = (newCameraMaxExtents[0] - newCameraMinExtents[0]) / 2 + newCameraMinExtents[0];\n        y = (newCameraMaxExtents[1] - newCameraMinExtents[1]) / 2 + newCameraMinExtents[1];\n\n        width = croppedWidth;\n        height = croppedHeight;\n        aspect = width / (float)height;\n\n        GeoTIFWriter *geo = (GeoTIFWriter *)writer;\n        geo->SetTiePoint(x, y, width / 2.f, height / 2.f);\n        geo->SetPixelScale(s * aspect * 2 / (float)width, s * 2 / (float)height);\n        if (geo->ConfigureFromProj4(projString) < 0) {\n            writeReturn = -1;\n            goto captureImageEnd;\n        }\n    }\n\n    writeReturn = writer->Write(framebuffer.data(), width, height);\n\ncaptureImageEnd:\n    if (writer) delete writer;\n\n    return writeReturn;\n}\n\nbool Visualizer::_getPixelData(unsigned char *data) const\n{\n    int width, height;\n    //\tvpParams->GetWindowSize(width, height);\n    _framebuffer.GetSize(&width, &height);\n\n    // Must clear previous errors first.\n    while (glGetError() != GL_NO_ERROR)\n        ;\n\n    //\tglReadBuffer(GL_BACK);\n    //\tglDisable(GL_SCISSOR_TEST);\n\n    // Calling pack alignment ensures that we can grab the any size window\n    glPixelStorei(GL_PACK_ALIGNMENT, 1);\n    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);\n    if (glGetError() != GL_NO_ERROR) {\n        SetErrMsg(\"Error obtaining GL framebuffer data\");\n        return false;\n    }\n    // Unfortunately gl reads these in the reverse order that jpeg expects, so\n    // Now we need to swap top and bottom!\n    unsigned char val;\n    for (int j = 0; j < height / 2; j++) {\n        for (int i = 0; i < width * 3; i++) {\n            val = data[i + width * 3 * j];\n            data[i + width * 3 * j] = data[i + width * 3 * (height - j - 1)];\n            data[i + width * 3 * (height - j - 1)] = val;\n        }\n    }\n\n    return true;\n}\n\nvoid Visualizer::_deleteFlaggedRenderers()\n{\n    VAssert(_insideGLContext);\n\n    for (auto it = _renderersToDestroy.begin(); it != _renderersToDestroy.end(); ++it) {\n        Renderer *ren = *it;\n        if (ren) delete ren;\n    }\n    _renderersToDestroy.clear();\n}\n\nint Visualizer::_initializeNewRenderers()\n{\n    VAssert(_insideGLContext);\n    for (Renderer *r : _renderers) {\n        if (!r->IsGLInitialized() && r->initializeGL(_glManager) < 0) {\n            MyBase::SetErrMsg(\"Failed to initialize renderer %s\", r->GetInstanceName().c_str());\n            return -1;\n        }\n        GL_ERR_BREAK();\n    }\n    return 0;\n}\n\nvoid Visualizer::_clearActiveFramebuffer(float r, float g, float b) const\n{\n    VAssert(_insideGLContext);\n\n    glDepthMask(GL_TRUE);\n    glClearColor(r, g, b, 1.f);\n    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);\n}\n\nvoid Visualizer::_renderColorbars(int timeStep)\n{\n    MatrixManager *mm = _glManager->matrixManager;\n    mm->MatrixModeModelView();\n    mm->PushMatrix();\n    mm->LoadIdentity();\n    mm->MatrixModeProjection();\n    mm->PushMatrix();\n    mm->LoadIdentity();\n    for (int i = 0; i < _renderers.size(); i++) {\n        // If a renderer is not initialized, or if its bypass flag is set, then don't render.\n        // Otherwise push and pop the GL matrix stack, and all attribs\n        _renderers[i]->renderColorbar();\n    }\n    mm->MatrixModeProjection();\n    mm->PopMatrix();\n    mm->MatrixModeModelView();\n    mm->PopMatrix();\n}\n\nvoid Visualizer::_incrementPath(string &s)\n{\n    // truncate the last 4 characters (remove .tif or .jpg)\n    string s1 = s.substr(0, s.length() - 4);\n    string s_end = s.substr(s.length() - 4);\n    if (s_end == \"jpeg\" || s_end == \"tiff\") {\n        s1 = s.substr(0, s.length() - 5);\n        s_end = s.substr(s.length() - 5);\n    }\n    // Find digits (before .tif or .jpg)\n    size_t lastpos = s1.find_last_not_of(\"0123456789\");\n    VAssert(lastpos < s1.length());\n    string s2 = s1.substr(lastpos + 1);\n    int    val = stol(s2);\n    // Convert val+1 to a string, with leading zeroes, of same length as s2.\n    // Except, if val+1 has more digits than s2, increase it.\n    int numDigits = 1 + (int)log10((float)(val + 1));\n    int len = s2.length();\n    if (len < numDigits) len = numDigits;\n    if (len > 9) len = 9;\n    char format[5] = {\"%04d\"};\n    char result[100];\n    char c = '0' + len;\n    format[2] = c;\n    snprintf(result, 100, format, val + 1);\n    string sval = string(result);\n    string newbody = s.substr(0, lastpos + 1);\n    s = newbody + sval + s_end;\n}\n"
  },
  {
    "path": "lib/render/VolumeAlgorithm.cpp",
    "content": "#include <vapor/VolumeAlgorithm.h>\n#include <vapor/VolumeParams.h>\n#include <vapor/VolumeRenderer.h>\n#include <glm/glm.hpp>\n\nusing namespace VAPoR;\nusing std::string;\nusing std::vector;\n\nVolumeAlgorithm::VolumeAlgorithm(GLManager *gl, VolumeRenderer *renderer) : _glManager(gl), _renderer(renderer) {}\n\nVolumeAlgorithm *VolumeAlgorithm::NewAlgorithm(const std::string &name, GLManager *gl, VolumeRenderer *renderer)\n{\n    if (factories.count(name)) { return factories[name]->Create(gl, renderer); }\n    Wasp::MyBase::SetErrMsg(\"Invalid volume rendering algorithm: \\\"%s\\\"\\n\", name.c_str());\n    return nullptr;\n}\n\nVolumeParams *VolumeAlgorithm::GetParams() const { return (VolumeParams *)_renderer->GetActiveParams(); }\n\nViewpointParams *VolumeAlgorithm::GetViewpointParams() const { return _renderer->GetViewpointParams(); }\n\nAnnotationParams *VolumeAlgorithm::GetAnnotationParams() const { return _renderer->GetAnnotationParams(); }\n\nTransform *VolumeAlgorithm::GetDatasetTransform() const { return _renderer->GetDatasetTransform(); }\n\nvoid VolumeAlgorithm::GetExtents(glm::vec3 *dataMin_, glm::vec3 *dataMax_, glm::vec3 *userMin_, glm::vec3 *userMax_) const\n{\n    vector<double> minRendererExtents, maxRendererExtents;\n    GetParams()->GetBox()->GetExtents(minRendererExtents, maxRendererExtents);\n\n    CoordType      minDataExtents, maxDataExtents;\n    auto           p = GetParams();\n    _renderer->_dataMgr->GetVariableExtents(p->GetCurrentTimestep(), p->GetVariableName(), p->GetRefinementLevel(), p->GetCompressionLevel(), minDataExtents, maxDataExtents);\n\n    glm::vec3 userMin = glm::vec3(minRendererExtents[0], minRendererExtents[1], minRendererExtents[2]);\n    glm::vec3 userMax = glm::vec3(maxRendererExtents[0], maxRendererExtents[1], maxRendererExtents[2]);\n    glm::vec3 dataMin = glm::vec3(minDataExtents[0], minDataExtents[1], minDataExtents[2]);\n    glm::vec3 dataMax = glm::vec3(maxDataExtents[0], maxDataExtents[1], maxDataExtents[2]);\n\n    if (dataMin_) *dataMin_ = dataMin;\n    if (dataMax_) *dataMax_ = dataMax;\n\n    // Moving domain allows area outside of data to be selected\n    if (userMin_) *userMin_ = glm::max(userMin, dataMin);\n    if (userMax_) *userMax_ = glm::min(userMax, dataMax);\n}\n\nstd::map<std::string, VolumeAlgorithmFactory *> VolumeAlgorithm::factories;\nvoid                                            VolumeAlgorithm::Register(VolumeAlgorithmFactory *f)\n{\n    VolumeParams::Type type = VolumeParams::Type::Any;\n    if (f->type == Type::Iso)\n        type = VolumeParams::Type::Iso;\n    else if (f->type == Type::DVR)\n        type = VolumeParams::Type::DVR;\n\n    factories[f->name] = f;\n    VolumeParams::Register(f->name, type);\n}\n\nstatic VolumeAlgorithmRegistrar<VolumeAlgorithmNull> registration;\n"
  },
  {
    "path": "lib/render/VolumeCellTraversal.cpp",
    "content": "#include <vapor/VolumeCellTraversal.h>\n#include <vector>\n#include <array>\n#include <algorithm>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n#include <vapor/GLManager.h>\n#include <vapor/ShaderManager.h>\n#include <vapor/Progress.h>\n\n#ifndef FLT16_MAX\n    #define FLT16_MAX 6.55E4\n#endif\n\nusing glm::ivec2;\nusing glm::ivec3;\nusing glm::vec3;\nusing std::array;\nusing std::vector;\n\nusing namespace VAPoR;\n\nstatic VolumeAlgorithmRegistrar<VolumeCellTraversal>    registration;\nstatic VolumeAlgorithmRegistrar<VolumeCellTraversalIso> registration2;\n\n#define MAX_LEVELS 12\n\n#define FI_LEFT  0\n#define FI_RIGHT 1\n#define FI_UP    2\n#define FI_DOWN  3\n#define FI_FRONT 4\n#define FI_BACK  5\n\n#define F_LEFT  ivec3(-1, 0, 0)\n#define F_RIGHT ivec3(1, 0, 0)\n#define F_UP    ivec3(0, 0, 1)\n#define F_DOWN  ivec3(0, 0, -1)\n#define F_FRONT ivec3(0, -1, 0)\n#define F_BACK  ivec3(0, 1, 0)\n\nstatic int GetFaceIndexFromFace(const ivec3 &face)\n{\n    if (face == F_LEFT) return FI_LEFT;\n    if (face == F_RIGHT) return FI_RIGHT;\n    if (face == F_UP) return FI_UP;\n    if (face == F_DOWN) return FI_DOWN;\n    if (face == F_FRONT) return FI_FRONT;\n    if (face == F_BACK) return FI_BACK;\n    VAssert(0);\n    return 0;\n}\n\nstatic void GetFaceCoordinateIndices(const ivec3 &cell, const ivec3 &face, ivec3 &i0, ivec3 &i1, ivec3 &i2, ivec3 &i3)\n{\n    // CCW\n    if (face == F_DOWN) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(0, 1, 0);\n        i2 = cell + ivec3(1, 1, 0);\n        i3 = cell + ivec3(1, 0, 0);\n    } else if (face == F_UP) {\n        i0 = cell + ivec3(0, 0, 1);\n        i1 = cell + ivec3(1, 0, 1);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(0, 1, 1);\n    } else if (face == F_LEFT) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(0, 0, 1);\n        i2 = cell + ivec3(0, 1, 1);\n        i3 = cell + ivec3(0, 1, 0);\n    } else if (face == F_RIGHT) {\n        i0 = cell + ivec3(1, 0, 0);\n        i1 = cell + ivec3(1, 1, 0);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(1, 0, 1);\n    } else if (face == F_FRONT) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(1, 0, 0);\n        i2 = cell + ivec3(1, 0, 1);\n        i3 = cell + ivec3(0, 0, 1);\n    } else if (face == F_BACK) {\n        i0 = cell + ivec3(0, 1, 0);\n        i1 = cell + ivec3(0, 1, 1);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(1, 1, 0);\n    } else {\n        VAssert(!\"Invalid face enum\");\n        i0 = ivec3(0);\n        i1 = ivec3(0);\n        i2 = ivec3(0);\n        i3 = ivec3(0);\n    }\n}\n\nstatic vec3 GetCoordAtIndex(const ivec3 &index, const float *data, const ivec3 &dims)\n{\n    const int w = dims.x;\n    const int h = dims.y;\n    const int d = dims.z;\n    const int x = index.x;\n    const int y = index.y;\n    const int z = index.z;\n    VAssert(x >= 0 && x < w && y >= 0 && y < h && z >= 0 && z < d);\n    return vec3(\n        data[3 * ((long)z * w * h + y * w + x)],\n        data[3 * ((long)z * w * h + y * w + x) + 1],\n        data[3 * ((long)z * w * h + y * w + x) + 2]\n    );\n}\n\nstatic void GetFaceVertices(const ivec3 &cellIndex, const ivec3 &face, const float *data, const ivec3 &dims, vec3 &v0, vec3 &v1, vec3 &v2, vec3 &v3)\n{\n    ivec3 i0, i1, i2, i3;\n    GetFaceCoordinateIndices(cellIndex, face, i0, i1, i2, i3);\n    v0 = GetCoordAtIndex(i0, data, dims);\n    v1 = GetCoordAtIndex(i1, data, dims);\n    v2 = GetCoordAtIndex(i2, data, dims);\n    v3 = GetCoordAtIndex(i3, data, dims);\n}\n\nstatic bool ComputeSideBBoxes(ivec3 side, int fastDim, int slowDim, vec3 *boxMins, vec3 *boxMaxs, float *coordData, const ivec3 &cellDims, const ivec3 &coordDims, const int bd, const int sd)\n{\n    ivec3 index = (side + 1) / 2 * (cellDims - 1);\n    int   sideID = GetFaceIndexFromFace(side);\n\n    for (index[slowDim] = 0; index[slowDim] < cellDims[slowDim]; index[slowDim]++) {\n        for (index[fastDim] = 0; index[fastDim] < cellDims[fastDim]; index[fastDim]++) {\n            vec3 v0, v1, v2, v3;\n            GetFaceVertices(index, side, coordData, coordDims, v0, v1, v2, v3);\n\n            boxMins[sideID * bd * sd + index[slowDim] * sd + index[fastDim]] = glm::min(v0, glm::min(v1, glm::min(v2, v3)));\n            boxMaxs[sideID * bd * sd + index[slowDim] * sd + index[fastDim]] = glm::max(v0, glm::max(v1, glm::max(v2, v3)));\n        }\n    }\n    return false;\n}\n\nVolumeCellTraversal::VolumeCellTraversal(GLManager *gl, VolumeRenderer *renderer) : VolumeRegular(gl, renderer), _useHighPrecisionTriangleRoutine(false)\n{\n    _coordTexture.Generate(GL_NEAREST);\n    _minTexture.Generate(GL_NEAREST);\n    _maxTexture.Generate(GL_NEAREST);\n    _BBLevelDimTexture.Generate(GL_NEAREST);\n}\n\nVolumeCellTraversal::~VolumeCellTraversal() {}\n\nint VolumeCellTraversal::LoadData(const Grid *grid)\n{\n    if (VolumeRegular::LoadData(grid) < 0) return -1;\n\n    _useHighPrecisionTriangleRoutine = _needsHighPrecisionTriangleRoutine(grid);\n    _gridHasInvertedCoordinateSystemHandiness = !grid->HasInvertedCoordinateSystemHandiness();\n\n    const auto dims = grid->GetDimensions();\n    const auto w = dims[0], h = dims[1], d = dims[2];\n    const auto nCoords = w * h * d;\n    _coordDims[0] = w;\n    _coordDims[1] = h;\n    _coordDims[2] = d;\n\n    float *data = new float[nCoords * 3];\n    if (!data) {\n        Wasp::MyBase::SetErrMsg(\"Could not allocate enough RAM to load data coordinates\");\n        return -1;\n    }\n\n    Progress::Start(\"Load coord data\", nCoords);\n    auto coord = grid->ConstCoordBegin();\n    for (size_t i = 0; i < nCoords; ++i, ++coord) {\n        Progress::Update(i);\n        data[i * 3] = (*coord)[0];\n        data[i * 3 + 1] = (*coord)[1];\n        data[i * 3 + 2] = (*coord)[2];\n    }\n    Progress::Finish();\n\n    _coordTexture.TexImage(GL_RGB32F, dims[0], dims[1], dims[2], GL_RGB, GL_FLOAT, data);\n\n    // ---------------------------------------\n    // Compute bounding boxes for outside faces\n    // ---------------------------------------\n\n    vector<size_t> cellDims = {dims[0] - 1, dims[1] - 1, dims[2] - 1};\n    vector<size_t> cellDimsSorted = cellDims;\n    std::sort(cellDimsSorted.begin(), cellDimsSorted.end());\n    int bbDim = cellDimsSorted[2];\n    int bd = bbDim;\n    int sd = bbDim;\n\n    vec3 *boxMins = new vec3[bd * sd * 6];\n    vec3 *boxMaxs = new vec3[bd * sd * 6];\n    memset(boxMins, 0, sizeof(vec3) * bd * sd * 6);\n    memset(boxMaxs, 0, sizeof(vec3) * bd * sd * 6);\n\n    int cw = w - 1;\n    int ch = h - 1;\n    int cd = d - 1;\n\n    Progress::Start(\"Compute acceleration data\", 6);\n    ComputeSideBBoxes(F_LEFT, 1, 2, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd);\n    Progress::Update(1);\n    ComputeSideBBoxes(F_RIGHT, 1, 2, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd);\n    Progress::Update(2);\n    ComputeSideBBoxes(F_UP, 0, 1, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd);\n    Progress::Update(3);\n    ComputeSideBBoxes(F_DOWN, 0, 1, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd);\n    Progress::Update(4);\n    ComputeSideBBoxes(F_FRONT, 0, 2, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd);\n    Progress::Update(5);\n    ComputeSideBBoxes(F_BACK, 0, 2, boxMins, boxMaxs, data, ivec3(cw, ch, cd), ivec3(w, h, d), bd, sd);\n    Progress::Finish();\n\n    int levels = 1;\n    int size = bd;\n    while ((size = size >> 1)) levels++;\n    levels = min(levels, MAX_LEVELS);\n    _BBLevels = levels;\n\n    _minTexture.TexImage(GL_RGB32F, sd, bd, 6, GL_RGB, GL_FLOAT, boxMins);\n    _maxTexture.TexImage(GL_RGB32F, sd, bd, 6, GL_RGB, GL_FLOAT, boxMaxs);\n\n    // ---------------------------------------\n    // Compute mipmap for acceleration tree\n    //\n    // Each subsequent mipmip level contains outermost bounds of all the bounding\n    // boxes it encompases from the previous level.\n    // ---------------------------------------\n\n    vector<int>             sizes(levels);\n    vector<array<ivec2, 6>> mipDims(levels);\n    vector<vec3 *>          minMip(levels);\n    vector<vec3 *>          maxMip(levels);\n    sizes[0] = bd;\n    minMip[0] = boxMins;\n    maxMip[0] = boxMaxs;\n\n    mipDims[0][FI_LEFT] = ivec2(ch, cd);\n    mipDims[0][FI_RIGHT] = ivec2(ch, cd);\n    mipDims[0][FI_UP] = ivec2(cw, ch);\n    mipDims[0][FI_DOWN] = ivec2(cw, ch);\n    mipDims[0][FI_FRONT] = ivec2(cw, cd);\n    mipDims[0][FI_BACK] = ivec2(cw, cd);\n\n    Progress::Start(\"Generate tree\", levels);\n    for (int level = 1; level < levels; level++) {\n        Progress::Update(level);\n        int ms = bd >> level;\n        int mUpS = sizes[level - 1];\n\n        sizes[level] = ms;\n        minMip[level] = new vec3[ms * ms * 6];\n        maxMip[level] = new vec3[ms * ms * 6];\n\n        for (int z = 0; z < 6; z++) {\n            int mUpW = mipDims[level - 1][z][0];\n            int mUpH = mipDims[level - 1][z][1];\n\n            int mW = std::max(1, mUpW >> 1);\n            int mH = std::max(1, mUpH >> 1);\n            mipDims[level][z][0] = mW;\n            mipDims[level][z][1] = mH;\n\n            // At each higher mipmap, the dimensions halve. So each pixel maps to at least 4\n            // pixels at the previous level. However if the previous level dim was 1, it\n            // no longer halves so we set the increment to 0. This resamples the same pixel twice\n            // for simplicities sake.\n            int ix = 1, iy = 1;\n            if (mUpW == 1) ix = 0;\n            if (mUpH == 1) iy = 0;\n\n            for (int y = 0; y < mH; y++) {\n                for (int x = 0; x < mW; x++) {\n                    vec3 v0 = minMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + x * 2];\n                    vec3 v1 = minMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + x * 2 + ix];\n                    vec3 v2 = minMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + x * 2 + ix];\n                    vec3 v3 = minMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + x * 2];\n\n                    // glm::min and glm::max are component-wise\n                    minMip[level][z * ms * ms + y * ms + x] = glm::min(v0, glm::min(v1, glm::min(v2, v3)));\n\n                    v0 = maxMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + x * 2];\n                    v1 = maxMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + x * 2 + ix];\n                    v2 = maxMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + x * 2 + ix];\n                    v3 = maxMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + x * 2];\n\n                    maxMip[level][z * ms * ms + y * ms + x] = glm::max(v0, glm::max(v1, glm::max(v2, v3)));\n                }\n            }\n            // If the upper level is odd, the top and right border pixels map to 6 pixels in the previous\n            // level which are accounted for here.\n            if (mUpW % 2 == 1) {\n                for (int y = 0; y < mH; y++) {\n                    vec3 v0 = minMip[level][z * ms * ms + y * ms + mW - 1];\n                    vec3 v1 = minMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + mUpW - 1];\n                    vec3 v2 = minMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + mUpW - 1];\n                    minMip[level][z * ms * ms + y * ms + mW - 1] = glm::min(v0, glm::min(v1, v2));\n\n                    v0 = maxMip[level][z * ms * ms + y * ms + mW - 1];\n                    v1 = maxMip[level - 1][z * mUpS * mUpS + (y * 2) * mUpS + mUpW - 1];\n                    v2 = maxMip[level - 1][z * mUpS * mUpS + (y * 2 + iy) * mUpS + mUpW - 1];\n                    maxMip[level][z * ms * ms + y * ms + mW - 1] = glm::max(v0, glm::max(v1, v2));\n                }\n            }\n            if (mUpH % 2 == 1) {\n                for (int x = 0; x < mW; x++) {\n                    vec3 v0 = minMip[level][z * ms * ms + (mH - 1) * ms + x];\n                    vec3 v1 = minMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + x * 2];\n                    vec3 v2 = minMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + x * 2 + ix];\n                    minMip[level][z * ms * ms + (mH - 1) * ms + x] = glm::min(v0, glm::min(v1, v2));\n\n                    v0 = maxMip[level][z * ms * ms + (mH - 1) * ms + x];\n                    v1 = maxMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + x * 2];\n                    v2 = maxMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + x * 2 + ix];\n                    maxMip[level][z * ms * ms + (mH - 1) * ms + x] = glm::max(v0, glm::max(v1, v2));\n                }\n            }\n            // If the both upper dims are odd, the top-right pixel maps to 9 pixels in the previous level.\n            // 8 of these were already accounted for. This accounts for the last pixel in the corner\n            if (mUpW % 2 == 1 && mUpH % 2 == 1) {\n                vec3 v0 = minMip[level][z * ms * ms + (mH - 1) * ms + mW - 1];\n                vec3 v1 = minMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + mUpW - 1];\n                minMip[level][z * ms * ms + (mH - 1) * ms + mW - 1] = glm::min(v0, v1);\n\n                v0 = maxMip[level][z * ms * ms + (mH - 1) * ms + mW - 1];\n                v1 = maxMip[level - 1][z * mUpS * mUpS + (mUpH - 1) * mUpS + mUpW - 1];\n                maxMip[level][z * ms * ms + (mH - 1) * ms + mW - 1] = glm::max(v0, v1);\n            }\n        }\n\n        _minTexture.TexImage(GL_RGB32F, ms, ms, 6, GL_RGB, GL_FLOAT, minMip[level], level);\n        _maxTexture.TexImage(GL_RGB32F, ms, ms, 6, GL_RGB, GL_FLOAT, maxMip[level], level);\n    }\n    Progress::Finish();\n\n    _BBLevelDimTexture.TexImage(GL_RG32I, 6, levels, 0, GL_RG_INTEGER, GL_INT, mipDims.data());\n\n    for (int level = 1; level < levels; level++) {\n        delete[] minMip[level];\n        delete[] maxMip[level];\n    }\n\n    delete[] data;\n    delete[] boxMins;\n    delete[] boxMaxs;\n    return 0;\n}\n\n// System: CISL-VAPOR\n// Vendor: NVIDIA\n// Dataset: Lee Orf tornado Max/Min resolutions\n//\n//                  Render Times\n// Levels  Compile   Max    Min\n//   9        64     0.05    -\n//   8        24     0.05    -\n//   7        9.5    0.04    -\n//   6        4      0.05   0.01\n//   5        1.8    0.067  0.01\n//   4        0.9    0.22   0.012\n//   3        0.56    -     0.022\n\nint VolumeCellTraversal::_getHeuristicBBLevels() const\n{\n    int levels = _BBLevels;\n\n    if (levels == 12)\n        levels -= 4;\n    else if (levels >= 9)\n        levels -= 3;\n    else if (levels >= 7)\n        levels -= 2;\n    else if (levels >= 2)\n        levels -= 1;\n\n    // Nvidia's loop optimizer has an exponential Big-O complexity in\n    // relation to nesting and anything over 6 takes too long to compile.\n    GLManager::Vendor vendor = GLManager::GetVendor();\n    if (vendor == GLManager::Vendor::Nvidia)\n        if (levels > 6) levels = 6;\n\n    return levels;\n}\n\nstd::string VolumeCellTraversal::_addDefinitionsToShader(std::string shaderName) const\n{\n    shaderName = VolumeRegular::_addDefinitionsToShader(shaderName);\n\n    if (_useHighPrecisionTriangleRoutine) shaderName += \":USE_INTEL_TRI_ISECT\";\n\n    if (_gridHasInvertedCoordinateSystemHandiness) shaderName += \":INVERT_GRID_COORD_SYS_HAND\";\n\n    GLManager::Vendor vendor = GLManager::GetVendor();\n\n    if (vendor == GLManager::Vendor::Nvidia || vendor == GLManager::Vendor::AMD || vendor == GLManager::Vendor::Mesa) shaderName += \":NVIDIA\";\n\n    shaderName += \":BB_LEVELS \" + std::to_string(_getHeuristicBBLevels());\n\n    return shaderName;\n}\n\nShaderProgram *VolumeCellTraversal::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader(\"VolumeCellDVR\")); }\n\nvoid VolumeCellTraversal::SetUniforms(const ShaderProgram *s) const\n{\n    VolumeRegular::SetUniforms(s);\n\n    s->SetUniform(\"coordDims\", *(glm::ivec3 *)&_coordDims);\n\n    s->SetSampler(\"coords\", _coordTexture);\n    s->SetSampler(\"boxMins\", _minTexture);\n    s->SetSampler(\"boxMaxs\", _maxTexture);\n    s->SetSampler(\"levelDims\", _BBLevelDimTexture);\n}\n\nfloat VolumeCellTraversal::GuestimateFastModeSpeedupFactor() const { return 2; }\n\nint VolumeCellTraversal::CheckHardwareSupport(const Grid *grid) const\n{\n    int ret = VolumeRegular::CheckHardwareSupport(grid);\n    if (ret < 0)\n        return ret;\n\n    long freeKB = oglGetFreeMemory();\n    if (freeKB >= 0) {\n        auto dims = grid->GetDimensions();\n        long estimatedMinimumB = dims[0]*dims[1]*dims[2] * sizeof(float) * 4;\n        long estimatedMinimumKB = estimatedMinimumB/1024;\n        if (freeKB < estimatedMinimumKB) {\n            Wasp::MyBase::SetErrMsg(\"Not enough GPU RAM free (%liMB free, need at least %liMB)\\n\", freeKB/1024, estimatedMinimumKB/1024);\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\nbool VolumeCellTraversal::_needsHighPrecisionTriangleRoutine(const Grid *grid)\n{\n    vector<double> extentsMin, extentsMax;\n    grid->GetUserExtents(extentsMin, extentsMax);\n    vector<double> lengths = {\n        extentsMax[0] - extentsMin[0],\n        extentsMax[1] - extentsMin[1],\n        extentsMax[2] - extentsMin[2],\n    };\n    double minLength = min(lengths[0], min(lengths[1], lengths[2]));\n    double maxLength = max(lengths[0], max(lengths[1], lengths[2]));\n    double ratio = maxLength / minLength;\n\n    if (ratio > 10000)\n        return true;\n    else\n        return false;\n}\n\n// Needs more consideration for frequency\nbool VolumeCellTraversal::_need32BitForCoordinates(const Grid *grid)\n{\n    vector<double> minExts, maxExts;\n    grid->GetUserExtents(minExts, maxExts);\n    double minExt = min(minExts[0], min(minExts[1], minExts[2]));\n    double maxExt = max(maxExts[0], max(maxExts[1], maxExts[2]));\n    if (minExt <= -FLT16_MAX || maxExt >= FLT16_MAX) return true;\n    return false;\n}\n\nShaderProgram *VolumeCellTraversalIso::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader(\"VolumeCellIso\")); }\n\nvoid VolumeCellTraversalIso::SetUniforms(const ShaderProgram *shader) const { VolumeCellTraversal::SetUniforms(shader); }\n"
  },
  {
    "path": "lib/render/VolumeGLSL.cpp",
    "content": "#include <vapor/VolumeGLSL.h>\n#include <vector>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n#include <vapor/GLManager.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/VolumeParams.h>\n\nusing glm::vec3;\nusing std::vector;\n\nusing namespace VAPoR;\n\n// static VolumeAlgorithmRegistrar<VolumeGLSL> registration;\n\nVolumeGLSL::VolumeGLSL(GLManager *gl, VolumeRenderer *renderer) : VolumeAlgorithm(gl, renderer)\n{\n    _LUTTexture.Generate();\n    _LUT2Texture.Generate();\n    _depthTexture.Generate();\n}\n\nVolumeGLSL::~VolumeGLSL() {}\n\nvoid VolumeGLSL::SaveDepthBuffer(bool fast) { _depthTexture.CopyDepthBuffer(); }\n\nint VolumeGLSL::Render(bool fast)\n{\n    _loadTF();\n\n    ShaderProgram *shader = GetShader();\n    if (!shader) return -1;\n    shader->Bind();\n    _setShaderUniforms(shader, fast);\n\n    return 0;\n}\n\nint VolumeGLSL::LoadData(const Grid *grid)\n{\n    grid->GetUserExtents(_minDataExtents, _maxDataExtents);\n    return 0;\n}\n\nvoid VolumeGLSL::GetFinalBlendingMode(int *src, int *dst)\n{\n    *src = GL_ONE;\n    *dst = GL_ONE_MINUS_SRC_ALPHA;\n}\n\nvoid VolumeGLSL::_loadTF()\n{\n    VolumeParams *vp = GetParams();\n\n    vector<float> constantColor = vp->GetConstantColor();\n    constantColor.push_back(vp->GetMapperFunc(vp->GetVariableName())->getOpacityScale());\n    _constantColor = constantColor;\n\n    _loadTF(&_LUTTexture, vp->GetMapperFunc(vp->GetVariableName()), &_tf);\n\n    if (_usingColorMapData()) { _loadTF(&_LUT2Texture, vp->GetMapperFunc(vp->GetColorMapVariableName()), &_tf2); }\n}\n\nvoid VolumeGLSL::_loadTF(Texture1D *texture, MapperFunction *tf, MapperFunction **cacheTF)\n{\n    if (*cacheTF) delete *cacheTF;\n    *cacheTF = new MapperFunction(*tf);\n\n    vector<float> LUT(4 * 256);\n    _getLUTFromTF(tf, LUT.data());\n    texture->TexImage(GL_RGBA8, 256, 0, 0, GL_RGBA, GL_FLOAT, LUT.data());\n}\n\nvoid VolumeGLSL::_getLUTFromTF(const MapperFunction *tf, float *LUT) const\n{\n    // Constant opacity needs to be removed here and applied in the shader\n    // because otherwise we run out of precision in the LUT\n    MapperFunction tfSansConstantOpacity(*tf);\n    tfSansConstantOpacity.setOpacityScale(1);\n\n    tfSansConstantOpacity.makeLut(LUT);\n    for (int i = 0; i < 256; i++) { LUT[4 * i + 3] = powf(LUT[4 * i + 3], 2); }\n}\n\nvoid VolumeGLSL::_setShaderUniforms(const ShaderProgram *shader, const bool fast) const\n{\n    VolumeParams *   vp = GetParams();\n    ViewpointParams *viewpointParams = GetViewpointParams();\n    Viewpoint *      viewpoint = viewpointParams->getCurrentViewpoint();\n    double           m[16];\n    double           cameraPos[3], cameraUp[3], cameraDir[3];\n    _glManager->matrixManager->GetDoublev(MatrixManager::Mode::ModelView, m);\n    viewpoint->ReconstructCamera(m, cameraPos, cameraUp, cameraDir);\n\n    shader->SetUniform(\"MVP\", _glManager->matrixManager->GetModelViewProjectionMatrix());\n    shader->SetUniform(\"cameraPos\", vec3(cameraPos[0], cameraPos[1], cameraPos[2]));\n    shader->SetUniform(\"samplingRateMultiplier\", (float)vp->GetSamplingMultiplier());\n    shader->SetUniform(\"lightingEnabled\", vp->GetLightingEnabled());\n    shader->SetUniform(\"phongAmbient\", vp->GetPhongAmbient());\n    shader->SetUniform(\"phongDiffuse\", vp->GetPhongDiffuse());\n    shader->SetUniform(\"phongSpecular\", vp->GetPhongSpecular());\n    shader->SetUniform(\"phongShininess\", powf(vp->GetPhongShininess(), 2) * 100);\n\n    glm::vec3 dataMin, dataMax, userMin, userMax;\n    _getExtents(&dataMin, &dataMax, &userMin, &userMax);\n    vec3  extLengths = dataMax - dataMin;\n    vec3  extScales = _getVolumeScales();\n    vec3  extLengthsScaled = extLengths * extScales;\n    float smallestDimension = min(extLengthsScaled[0], min(extLengthsScaled[1], extLengthsScaled[2]));\n    float largestDimension = max(extLengthsScaled[0], max(extLengthsScaled[1], extLengthsScaled[2]));\n\n    shader->SetUniform(\"dataBoundsMin\", dataMin);\n    shader->SetUniform(\"dataBoundsMax\", dataMax);\n    shader->SetUniform(\"userExtsMin\", userMin);\n    shader->SetUniform(\"userExtsMax\", userMax);\n    shader->SetUniform(\"unitDistance\", largestDimension / 100.f);\n    shader->SetUniform(\"unitOpacityScalar\", largestDimension / smallestDimension);\n    shader->SetUniform(\"scales\", extScales);\n\n    float density = vp->GetValueDouble(VolumeParams::VolumeDensityTag, 1);\n    density = powf(density, 4);\n\n    shader->SetUniform(\"density\", (float)density);\n    shader->SetUniform(\"LUTMin\", (float)_tf->getMinMapValue());\n    shader->SetUniform(\"LUTMax\", (float)_tf->getMaxMapValue());\n    shader->SetUniform(\"mapOrthoMode\", viewpointParams->GetProjectionType() == ViewpointParams::MapOrthographic);\n\n    shader->SetSampler(\"LUT\", _LUTTexture);\n    shader->SetSampler(\"sceneDepth\", _depthTexture);\n\n    if (_usingColorMapData()) {\n        shader->SetUniform(\"LUTMin2\", (float)_tf2->getMinMapValue());\n        shader->SetUniform(\"LUTMax2\", (float)_tf2->getMaxMapValue());\n        shader->SetSampler(\"LUT2\", _LUT2Texture);\n    }\n\n    shader->SetUniform(\"fast\", fast);\n\n    vector<double> isoValuesD = GetParams()->GetIsoValues();\n    vector<float>  isoValues(isoValuesD.begin(), isoValuesD.end());\n    vector<bool>   enabledIsoValues(4, false);\n    for (int i = 0; i < isoValues.size(); i++) enabledIsoValues[i] = true;\n    shader->SetUniformArray(\"isoValue\", isoValues.size(), isoValues.data());\n    shader->SetUniform(\"isoEnabled[0]\", (bool)enabledIsoValues[0]);\n    shader->SetUniform(\"isoEnabled[1]\", (bool)enabledIsoValues[1]);\n    shader->SetUniform(\"isoEnabled[2]\", (bool)enabledIsoValues[2]);\n    shader->SetUniform(\"isoEnabled[3]\", (bool)enabledIsoValues[3]);\n    if (_constantColor.size() == 4) shader->SetUniform(\"constantColor\", *(glm::vec4 *)_constantColor.data());\n\n    SetUniforms(shader);\n}\n\nglm::vec3 VolumeGLSL::_getVolumeScales() const\n{\n    Transform *datasetTransform = GetDatasetTransform();\n    Transform *rendererTransform = GetParams()->GetTransform();\n    VAssert(datasetTransform && rendererTransform);\n\n    vector<double> datasetScales, rendererScales;\n    datasetScales = datasetTransform->GetScales();\n    rendererScales = rendererTransform->GetScales();\n\n    return glm::vec3(datasetScales[0] * rendererScales[0], datasetScales[1] * rendererScales[1], datasetScales[2] * rendererScales[2]);\n}\n\nvoid VolumeGLSL::_getExtents(glm::vec3 *dataMin, glm::vec3 *dataMax, glm::vec3 *userMin, glm::vec3 *userMax) const\n{\n    vector<double> minRendererExtents, maxRendererExtents;\n    GetParams()->GetBox()->GetExtents(minRendererExtents, maxRendererExtents);\n    *userMin = vec3(minRendererExtents[0], minRendererExtents[1], minRendererExtents[2]);\n    *userMax = vec3(maxRendererExtents[0], maxRendererExtents[1], maxRendererExtents[2]);\n    *dataMin = vec3(_minDataExtents[0], _minDataExtents[1], _minDataExtents[2]);\n    *dataMax = vec3(_maxDataExtents[0], _maxDataExtents[1], _maxDataExtents[2]);\n\n    // Moving domain allows area outside of data to be selected\n    *userMin = glm::max(*userMin, *dataMin);\n    *userMax = glm::min(*userMax, *dataMax);\n}\n\nbool VolumeGLSL::_usingColorMapData() const\n{\n    // Overriden by VolumeIsoRenderer\n    return GetParams()->GetValueLong(VAPoR::VolumeParams::UseColormapVariableTag, false);\n}\n"
  },
  {
    "path": "lib/render/VolumeIsoRenderer.cpp",
    "content": "#include \"vapor/VolumeIsoRenderer.h\"\n#include <vapor/VolumeIsoParams.h>\n\n#include <vapor/MatrixManager.h>\n#include <vapor/GLManager.h>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n\n#include <vapor/VolumeRegular.h>\n#include <vapor/VolumeRectilinear.h>\n#include <vapor/VolumeCellTraversal.h>\n#include <vapor/VolumeOSPRay.h>\n\nusing glm::mat4;\nusing glm::vec2;\nusing glm::vec3;\nusing glm::vec4;\n\nusing namespace VAPoR;\n\nstatic RendererRegistrar<VolumeIsoRenderer> registrar(VolumeIsoRenderer::GetClassType(), VolumeIsoParams::GetClassType());\n\nVolumeIsoRenderer::VolumeIsoRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr)\n: VolumeRenderer(pm, winName, dataSetName, VolumeIsoParams::GetClassType(), VolumeIsoRenderer::GetClassType(), instName, dataMgr)\n{\n    // An ugly fix but I don't think we have a mechanism for this\n    if (_needToSetDefaultAlgorithm()) {\n        VolumeParams * vp = (VolumeParams *)GetActiveParams();\n        CoordType      minExt, maxExt;\n        vp->GetBox()->GetExtents(minExt, maxExt);\n\n        Grid *grid = _dataMgr->GetVariable(vp->GetCurrentTimestep(), vp->GetVariableName(), vp->GetRefinementLevel(), vp->GetCompressionLevel(), minExt, maxExt);\n        if (grid) {\n            string algorithmName = _getDefaultAlgorithmForGrid(grid);\n            vp->SetAlgorithm(algorithmName);\n            delete grid;\n        } else {\n            vp->SetAlgorithm(VolumeRegularIso::GetName());\n        }\n    }\n}\n\nVolumeIsoRenderer::~VolumeIsoRenderer() {}\n\nbool VolumeIsoRenderer::_usingColorMapData() const { return GetActiveParams()->GetValueLong(VolumeIsoParams::UseColormapVariableTag, false); }\n\nvoid VolumeIsoRenderer::_setShaderUniforms(const ShaderProgram *shader, const bool fast) const\n{\n    //    VolumeRenderer::_setShaderUniforms(shader, fast);\n\n    vector<double> isoValuesD = GetActiveParams()->GetIsoValues();\n    vector<float>  isoValues(isoValuesD.begin(), isoValuesD.end());\n    vector<bool>   enabledIsoValues(4, false);\n    for (int i = 0; i < isoValues.size(); i++) enabledIsoValues[i] = true;\n    shader->SetUniformArray(\"isoValue\", isoValues.size(), isoValues.data());\n    shader->SetUniform(\"isoEnabled[0]\", (bool)enabledIsoValues[0]);\n    shader->SetUniform(\"isoEnabled[1]\", (bool)enabledIsoValues[1]);\n    shader->SetUniform(\"isoEnabled[2]\", (bool)enabledIsoValues[2]);\n    shader->SetUniform(\"isoEnabled[3]\", (bool)enabledIsoValues[3]);\n    if (_cache.constantColor.size() == 4) shader->SetUniform(\"constantColor\", *(vec4 *)_cache.constantColor.data());\n}\n\nstd::string VolumeIsoRenderer::_getDefaultAlgorithmForGrid(const Grid *grid) const\n{\n    bool intel = GLManager::GetVendor() == GLManager::Vendor::Intel;\n\n    if (dynamic_cast<const RegularGrid *>(grid)) return VolumeRegularIso::GetName();\n    if (dynamic_cast<const StretchedGrid *>(grid)) return VolumeRectilinearIso::GetName();\n    if (dynamic_cast<const StructuredGrid *>(grid)) return intel ? VolumeRegularIso::GetName() : VolumeCellTraversalIso::GetName();\n    if (dynamic_cast<const UnstructuredGrid *>(grid)) return VolumeOSPRayIso ::GetName();\n    MyBase::SetErrMsg(\"Unsupported grid type: %s\", grid->GetType().c_str());\n    return \"\";\n}\n\nvoid VolumeIsoRenderer::_getLUTFromTF(const MapperFunction *tf, float *LUT) const { tf->makeLut(LUT); }\n"
  },
  {
    "path": "lib/render/VolumeOSPRay.cpp",
    "content": "#include <vapor/VolumeOSPRay.h>\n#include <vector>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n#include <vapor/GLManager.h>\n#include <vapor/RegularGrid.h>\n#include <vapor/StructuredGrid.h>\n#include <vapor/UnstructuredGrid.h>\n#include <vapor/VolumeParams.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/AnnotationParams.h>\n#include <vapor/Progress.h>\n\nusing glm::mat4;\nusing glm::vec3;\nusing glm::vec4;\nusing std::vector;\n\nstatic vec3 D2V(const vector<double> &dv)\n{\n    VAssert(dv.size() == 3);\n    return vec3(dv[0], dv[1], dv[2]);\n}\n\n#define PrintVec3(v) printf(\"%s = (%f, %f, %f)\\n\", #v, (v).x, (v).y, (v).z)\n\nusing namespace VAPoR;\n\nstatic VolumeAlgorithmRegistrar<VolumeOSPRay> registration;\n\nstd::string VolumeOSPRay::GetName() { return VolumeParams::OSPVolmeAlgorithmName; }\n\nVolumeOSPRay::VolumeOSPRay(GLManager *gl, VolumeRenderer *renderer) : VolumeAlgorithm(gl, renderer)\n{\n    _ospCamera = ospNewCamera(\"perspective\");\n    _ospWorld = ospNewWorld();\n\n    OSPLight lightAmbient = ospNewLight(\"ambient\");\n    ospSetFloat(lightAmbient, \"intensity\", 0.8);\n    ospCommit(lightAmbient);\n    //    ospSetObjectAsData(_ospWorld, \"light\", OSP_LIGHT, lightAmbient);\n    //    ospRelease(lightAmbient);\n\n    OSPLight lightDistant = ospNewLight(\"distant\");\n    ospSetVec3f(lightDistant, \"direction\", 0, 0, -1);\n    ospSetFloat(lightDistant, \"angularDiameter\", 1);\n    ospSetFloat(lightDistant, \"intensity\", 4);\n    ospCommit(lightDistant);\n\n    vector<OSPLight> lights = {lightAmbient, lightDistant};\n    OSPData          lightsData = VOSP::NewCopiedData(lights.data(), OSP_LIGHT, lights.size());\n    ospCommit(lightsData);\n\n    // Although these are already pointers, unlike every other function,\n    // in the case of this function you need to reference here otherwise\n    // it will crash.\n    ospSetParam(_ospWorld, \"light\", OSP_LIGHT, &lightsData);\n\n    ospRelease(lightsData);\n    _ospLightDistant = lightDistant;    // Not released therefore retained\n    _ospLightAmbient = lightAmbient;\n\n    _ospRenderTexture.Generate();\n    _ospWriteDepthTexture.Generate();\n}\n\nVolumeOSPRay::~VolumeOSPRay()\n{\n    if (_ospRenderer) ospRelease(_ospRenderer);\n    if (_ospWorld) ospRelease(_ospWorld);\n    if (_ospCamera) ospRelease(_ospCamera);\n    if (_ospTF) ospRelease(_ospTF);\n    if (_ospInstance) ospRelease(_ospInstance);\n    if (_ospVolumeModel) ospRelease(_ospVolumeModel);\n    if (_ospLightAmbient) ospRelease(_ospLightAmbient);\n    if (_ospLightDistant) ospRelease(_ospLightDistant);\n    if (_ospIso) ospRelease(_ospIso);\n    if (_ospIsoModel) ospRelease(_ospIsoModel);\n}\n\nvoid VolumeOSPRay::SaveDepthBuffer(bool fast)\n{\n    if (!fast) {\n        _copyDepth();\n\n        if (GetParams()->GetValueLong(\"osp_useBackplate\", false)) _copyBackplate();\n    }\n}\n\nint VolumeOSPRay::Render(bool fast)\n{\n    auto           viewport = GLManager::GetViewport();\n    glm::ivec2     fbSize(viewport[2], viewport[3]);\n    OSPFrameBuffer framebuffer = ospNewFrameBuffer(fbSize.x, fbSize.y, OSP_FB_SRGBA, OSP_FB_COLOR | OSP_FB_DEPTH | OSP_FB_ACCUM);\n    ospResetAccumulation(framebuffer);\n\n    _setupCamera();\n    _loadTF();\n    _applyTransform();\n    _setupRenderer(fast);\n    GetExtents(nullptr, nullptr, &_clipBox.min, &_clipBox.max);\n    if (_isIso()) _setupIso();\n\n    ospSetFloat(_ospVolumeModel, \"densityScale\", GetParams()->GetValueDouble(VolumeParams::OSPDensity, 1));\n    ospCommit(_ospVolumeModel);\n\n    ospRenderFrameBlocking(framebuffer, _ospRenderer, _ospCamera, _ospWorld);\n\n    const uint32_t *fb = (uint32_t *)ospMapFrameBuffer(framebuffer, OSP_FB_COLOR);\n    //    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, windowSize.x, windowSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, fb);\n    _ospRenderTexture.TexImage(GL_RGBA, fbSize.x, fbSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, fb);\n    ospUnmapFrameBuffer(fb, framebuffer);\n\n    const float *db = (float *)ospMapFrameBuffer(framebuffer, OSP_FB_DEPTH);\n    _ospWriteDepthTexture.TexImage(GL_R32F, fbSize.x, fbSize.y, 0, GL_RED, GL_FLOAT, db);\n    ospUnmapFrameBuffer(db, framebuffer);\n\n    ospRelease(framebuffer);\n\n    ShaderProgram *framebufferShader = _glManager->shaderManager->GetShader(\"FramebufferND\");\n    framebufferShader->Bind();\n    if (!framebufferShader) return -1;\n    framebufferShader->SetSampler(\"colorBuffer\", _ospRenderTexture);\n    framebufferShader->SetSampler(\"depthBuffer\", _ospWriteDepthTexture);\n    framebufferShader->SetUniform(\"MVP\", _glManager->matrixManager->GetModelViewProjectionMatrix());\n\n    auto   vp = GetViewpointParams();\n    double matrix[16], dpos[3], dup[3], ddir[3];\n    vp->GetModelViewMatrix(matrix);\n    vp->ReconstructCamera(matrix, dpos, dup, ddir);\n    vec3 pos(dpos[0], dpos[1], dpos[2]);\n    vec3 dir(ddir[0], ddir[1], ddir[2]);\n    framebufferShader->SetUniform(\"camPos\", pos);\n    framebufferShader->SetUniform(\"camDir\", dir);\n\n    return 0;\n}\n\nint VolumeOSPRay::LoadData(const Grid *grid)\n{\n    auto      p = GetParams();\n    OSPVolume volume;\n\n    if (p->GetValueLong(\"osp_test_volume\", false))\n        volume = _loadVolumeTest(grid);\n    else if (p->GetValueLong(\"osp_force_regular\", false))\n        volume = _loadVolumeRegular(grid);\n    else if (dynamic_cast<const RegularGrid *>(grid))\n        volume = _loadVolumeRegular(grid);\n    else if (dynamic_cast<const StructuredGrid *>(grid))\n        volume = _loadVolumeStructured(grid);\n    else if (dynamic_cast<const UnstructuredGrid *>(grid))\n        volume = _loadVolumeUnstructured(grid);\n    else\n        volume = 0, VAssert(!\"Unknown grid type\");\n\n    if (volume == nullptr) return -1;\n\n    ospRelease(_ospVolumeModel);\n    _ospVolumeModel = ospNewVolumetricModel(volume);\n    ospRelease(volume);\n\n    ospRelease(_ospTF);\n    _ospTF = ospNewTransferFunction(\"piecewiseLinear\");\n    float   temp[] = {0, 0, 0, 1, 1, 1};\n    OSPData data = VOSP::NewCopiedData(temp, OSP_VEC3F, 2);\n    ospCommit(data);\n    ospSetObject(_ospTF, \"color\", data);\n    ospRelease(data);\n    float temp2[] = {0, 1};\n    data = VOSP::NewCopiedData(temp2, OSP_FLOAT, 2);\n    ospCommit(data);\n    ospSetObject(_ospTF, \"opacity\", data);\n    ospRelease(data);\n    ospSetVec2f(_ospTF, \"valueRange\", -FLT_MAX, 0);    // These initial values are necessary to work around bugs.\n    ospCommit(_ospTF);\n    ospSetObject(_ospVolumeModel, \"transferFunction\", _ospTF);\n    ospCommit(_ospVolumeModel);\n\n    if (_isIso()) {\n        ospRelease(_ospIso);\n        ospRelease(_ospIsoModel);\n\n        _ospIso = ospNewGeometry(\"isosurface\");\n        ospSetObject(_ospIso, \"volume\", _ospVolumeModel);\n        ospSetFloat(_ospIso, \"isovalue\", 0);\n        ospCommit(_ospIso);\n\n        _ospIsoModel = ospNewGeometricModel(_ospIso);\n        ospSetVec4f(_ospIsoModel, \"color\", 1, 1, 1, 1);\n        ospCommit(_ospIsoModel);\n    }\n\n    OSPGeometry clip = ospNewGeometry(\"box\");\n    data = ospNewSharedData(&_clipBox, OSP_BOX3F, 1);\n    ospCommit(data);\n    ospSetObject(clip, \"box\", data);\n    ospRelease(data);\n    ospCommit(clip);\n\n    OSPGeometricModel clipModel = ospNewGeometricModel(clip);\n    ospSetBool(clipModel, \"invertNormals\", true);\n    ospRelease(clip);\n    ospCommit(clipModel);\n\n    OSPGroup group = ospNewGroup();\n    if (_isIso())\n        ospSetObjectAsData(group, \"geometry\", OSP_GEOMETRIC_MODEL, _ospIsoModel);\n    else\n        ospSetObjectAsData(group, \"volume\", OSP_VOLUMETRIC_MODEL, _ospVolumeModel);\n    if (p->GetValueLong(\"osp_enable_clipping\", true)) ospSetObjectAsData(group, \"clippingGeometry\", OSP_GEOMETRIC_MODEL, clipModel);\n    //    ospSetObjectAsData(group, \"geometry\", OSP_GEOMETRIC_MODEL, clipModel);\n    ospCommit(group);\n    ospRelease(clipModel);\n\n    ospRelease(_ospInstance);\n    _ospInstance = ospNewInstance(group);\n    ospCommit(_ospInstance);\n    ospRelease(group);\n\n    ospSetObjectAsData(_ospWorld, \"instance\", OSP_INSTANCE, _ospInstance);\n    ospCommit(_ospWorld);\n\n    if (dynamic_cast<const RegularGrid *>(grid))\n        _ospSampleRateScalar = 1.f;\n    else if (VOSP::IsVersionAtLeast(2, 5))\n        _ospSampleRateScalar = 1.f;\n    else\n        _ospSampleRateScalar = _guessSamplingRateScalar(grid);\n\n    return 0;\n}\n\nShaderProgram *VolumeOSPRay::GetShader() const { return _glManager->shaderManager->GetShader(\"VolumeDVR\"); }\n\nvoid VolumeOSPRay::SetUniforms(const ShaderProgram *s) const {}\n\nfloat VolumeOSPRay::GuestimateFastModeSpeedupFactor() const { return 5; }\n\nvoid VolumeOSPRay::GetFinalBlendingMode(int *src, int *dst)\n{\n    *src = GL_SRC_ALPHA;\n    *dst = GL_ONE_MINUS_SRC_ALPHA;\n}\n\nvoid VolumeOSPRay::_setupRenderer(bool fast)\n{\n    auto p = GetParams();\n    bool usePT = p->GetValueLong(\"osp_usePT\", 0);\n\n    if (!_ospRenderer || _cache.usePT != usePT) {\n        ospRelease(_ospRenderer);\n        _ospRenderer = ospNewRenderer(usePT ? \"pathtracer\" : \"scivis\");\n        _cache.usePT = usePT;\n    }\n\n    vector<double> bgColor;\n    int            spp = p->GetValueLong(\"osp_spp\", 1);\n    bool           opaqueBG = p->GetValueLong(\"osp_opaque_bg\", false);\n    GetAnnotationParams()->GetBackgroundColor(bgColor);\n    ospSetVec4f(_ospRenderer, \"backgroundColor\", bgColor[0], bgColor[1], bgColor[2], opaqueBG ? 1 : 0);\n    ospSetFloat(_ospRenderer, \"volumeSamplingRate\", _ospSampleRateScalar * (fast ? 0.1 : 1) * p->GetValueDouble(VolumeParams::OSPSampleRateScalar, 1));\n    ospSetInt(_ospRenderer, \"pixelSamples\", fast ? 1 : spp);\n    ospSetInt(_ospRenderer, \"aoSamples\", 0);\n\n    ViewpointParams *vp = GetViewpointParams();\n    auto             viewport = GLManager::GetViewport();\n    glm::ivec2       fbSize(viewport[2], viewport[3]);\n\n    if (fast) {\n        ospRemoveParam(_ospRenderer, \"map_maxDepth\");\n    } else {\n        auto   mm = _glManager->matrixManager;\n        double matrix[16], dpos[3], dup[3], ddir[3];\n        vp->GetModelViewMatrix(matrix);\n        vp->ReconstructCamera(matrix, dpos, dup, ddir);\n        vec3       pos(dpos[0], dpos[1], dpos[2]);\n        vec3       up(dup[0], dup[1], dup[2]);\n        vec3       dir(ddir[0], ddir[1], ddir[2]);\n        OSPTexture depthMap = VOSP::OSPDepthFromGLPerspective(glm::degrees(mm->FOV), mm->Aspect, mm->Near, mm->Far, dir, up, _depthData.data(), fbSize.x, fbSize.y);\n        ospSetObject(_ospRenderer, \"map_maxDepth\", depthMap);\n        ospRelease(depthMap);\n    }\n\n    if (fast || !p->GetValueLong(\"osp_useBackplate\", false)) {\n        ospRemoveParam(_ospRenderer, \"map_backplate\");\n    } else {\n        OSPTexture backplate = ospNewTexture(\"texture2d\");\n        ospSetInt(backplate, \"format\", OSP_TEXTURE_R32F);\n        ospSetInt(backplate, \"filter\", OSP_TEXTURE_FILTER_NEAREST);\n\n        OSPData data = VOSP::NewCopiedData(_backplateData.data(), OSP_VEC3UC, fbSize.x, fbSize.y);\n        ospCommit(data);\n        ospSetObject(backplate, \"data\", data);\n        ospRelease(data);\n\n        ospSetObject(_ospRenderer, \"map_backplate\", backplate);\n        ospRelease(backplate);\n    }\n\n    ospCommit(_ospRenderer);\n}\n\nvoid VolumeOSPRay::_setupCamera()\n{\n    ViewpointParams *vp = GetViewpointParams();\n    auto             viewport = GLManager::GetViewport();\n    glm::ivec2       fbSize(viewport[2], viewport[3]);\n\n    double matrix[16], dpos[3], dup[3], ddir[3];\n    vp->GetModelViewMatrix(matrix);\n    vp->ReconstructCamera(matrix, dpos, dup, ddir);\n    vec3 pos(dpos[0], dpos[1], dpos[2]);\n    vec3 up(dup[0], dup[1], dup[2]);\n    vec3 dir(ddir[0], ddir[1], ddir[2]);\n\n    //    printf(\"Camera Pos = (%f, %f, %f)\\n\", pos.x, pos.y, pos.z);\n    //    printf(\"Camera Up  = (%f, %f, %f)\\n\", up.x,  up.y,  up.z);\n    //    printf(\"Camera Dir = (%f, %f, %f)\\n\", dir.x, dir.y, dir.z);\n\n    ospSetFloat(_ospCamera, \"aspect\", fbSize.x / (float)fbSize.y);\n    ospSetFloat(_ospCamera, \"fovy\", vp->GetFOV());\n    ospSetParam(_ospCamera, \"position\", OSP_VEC3F, &pos);\n    ospSetParam(_ospCamera, \"direction\", OSP_VEC3F, &dir);\n    ospSetParam(_ospCamera, \"up\", OSP_VEC3F, &up);\n    ospCommit(_ospCamera);\n\n    float ambientIntensity = GetParams()->GetValueDouble(VolumeParams::OSPAmbientLightIntensity, 0.2);\n    ospSetFloat(_ospLightAmbient, \"intensity\", ambientIntensity);\n    ospCommit(_ospLightAmbient);\n\n    float dirIntensity = GetParams()->GetValueDouble(VolumeParams::OSPDirectionalLightIntensity, 1);\n    ospSetFloat(_ospLightDistant, \"intensity\", dirIntensity);\n    ospSetVec3f(_ospLightDistant, \"direction\", dir.x, dir.y, dir.z);\n    ospSetVec3f(_ospLightDistant, \"color\", 1, 1, 1);\n    ospCommit(_ospLightDistant);\n}\n\nvoid VolumeOSPRay::_setupIso()\n{\n    auto *         p = GetParams();\n    vector<double> isoValuesD = p->GetIsoValues();\n    vector<float>  isoValues(isoValuesD.begin(), isoValuesD.end());\n\n    OSPData data = VOSP::NewCopiedData(isoValues.data(), OSP_FLOAT, isoValues.size());\n    ospSetObject(_ospIso, \"isovalue\", data);\n    ospRelease(data);\n    ospCommit(_ospIso);\n\n    vector<float> c = p->GetConstantColor();\n    c.push_back(p->GetMapperFunc(p->GetVariableName())->getOpacityScale());\n    ospSetVec4f(_ospIsoModel, \"color\", c[0], c[1], c[2], c[3]);\n    ospCommit(_ospIsoModel);\n}\n\nvoid VolumeOSPRay::_loadTF()\n{\n    if (!_ospTF) {\n        fprintf(stderr, \"Warning: _ospTF = NULL\\n\");\n        return;\n    }\n    auto p = GetParams();\n    auto vtf = p->GetMapperFunc(p->GetVariableName());\n    auto range = vtf->getMinMaxMapValue();\n\n    float *LUT = new float[4 * 256];\n    vtf->makeLut(LUT);\n    for (int i = 0; i < 256; i++) { LUT[4 * i + 3] = powf(LUT[4 * i + 3], 2); }\n\n    vec3 * cLUT = new vec3[256];\n    float *oLUT = new float[256];\n    for (int i = 0; i < 256; i++) {\n        cLUT[i].r = LUT[4 * i + 0];\n        cLUT[i].g = LUT[4 * i + 1];\n        cLUT[i].b = LUT[4 * i + 2];\n        oLUT[i] = LUT[4 * i + 3];\n    }\n\n    OSPData data = VOSP::NewCopiedData(oLUT, OSP_FLOAT, 256);\n    ospCommit(data);\n    ospSetObject(_ospTF, \"opacity\", data);\n    ospRelease(data);\n    data = VOSP::NewCopiedData(cLUT, OSP_VEC3F, 256);\n    ospCommit(data);\n    ospSetObject(_ospTF, \"color\", data);\n    ospRelease(data);\n    ospSetVec2f(_ospTF, \"valueRange\", range[0], range[1]);\n    ospCommit(_ospTF);\n\n    delete[] LUT;\n    delete[] cLUT;\n    delete[] oLUT;\n}\n\nvoid VolumeOSPRay::_applyTransform()\n{\n    auto       p = GetParams();\n    vec3       translate = D2V(p->GetTransform()->GetTranslations());\n    vec3       rotate = D2V(p->GetTransform()->GetRotations());\n    vec3       scale = D2V(p->GetTransform()->GetScales());\n    vec3       origin = D2V(p->GetTransform()->GetOrigin());\n    Transform *datasetTransform = GetDatasetTransform();\n    vec3       datasetScales = D2V(datasetTransform->GetScales());\n    vec3       datasetRotation = D2V(datasetTransform->GetRotations());\n    vec3       datasetTranslation = D2V(datasetTransform->GetTranslations());\n    vec3       datasetOrigin = D2V(datasetTransform->GetOrigin());\n\n    mat4 m(1.f);\n\n    m = glm::translate(m, datasetTranslation);\n    m = glm::translate(m, datasetOrigin);\n    m = glm::rotate(m, glm::radians(datasetRotation.x), vec3(1, 0, 0));\n    m = glm::rotate(m, glm::radians(datasetRotation.y), vec3(0, 1, 0));\n    m = glm::rotate(m, glm::radians(datasetRotation.z), vec3(0, 0, 1));\n    m = glm::scale(m, datasetScales);\n    m = glm::translate(m, -datasetOrigin);\n\n    m = glm::scale(m, 1.f / datasetScales);\n    m = glm::translate(m, translate);\n    m = glm::translate(m, origin);\n    m = glm::rotate(m, glm::radians((float)rotate[0]), vec3(1, 0, 0));\n    m = glm::rotate(m, glm::radians((float)rotate[1]), vec3(0, 1, 0));\n    m = glm::rotate(m, glm::radians((float)rotate[2]), vec3(0, 0, 1));\n    m = glm::scale(m, scale);\n    m = glm::translate(m, -origin);\n    m = glm::scale(m, datasetScales);\n\n    struct {\n        vec3 x, y, z, o;\n    } affine;\n\n    affine.x = m * vec4(vec3(1, 0, 0), 0);\n    affine.y = m * vec4(vec3(0, 1, 0), 0);\n    affine.z = m * vec4(vec3(0, 0, 1), 0);\n    affine.o = m * vec4(vec3(0, 0, 0), 1);\n\n    ospSetParam(_ospInstance, \"xfm\", OSP_AFFINE3F, &affine);\n    ospCommit(_ospInstance);\n    ospCommit(_ospWorld);\n}\n\nvoid VolumeOSPRay::_copyDepth()\n{\n    GLint viewport[4] = {0};\n    glGetIntegerv(GL_VIEWPORT, viewport);\n    int width = viewport[2];\n    int height = viewport[3];\n\n    _depthData.resize(width * height);\n    glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, (GLvoid *)_depthData.data());\n}\n\nvoid VolumeOSPRay::_copyBackplate()\n{\n    GLint viewport[4] = {0};\n    glGetIntegerv(GL_VIEWPORT, viewport);\n    int width = viewport[2];\n    int height = viewport[3];\n\n    _backplateData.resize(width * height * 3);\n    glPixelStorei(GL_PACK_ALIGNMENT, 1);\n    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid *)_backplateData.data());\n}\n\nfloat VolumeOSPRay::_guessSamplingRateScalar(const Grid *grid) const\n{\n    std::vector<double> dataMinExtD, dataMaxExtD;\n    grid->GetUserExtents(dataMinExtD, dataMaxExtD);\n    vec3  dataMinExt(dataMinExtD[0], dataMinExtD[1], dataMinExtD[2]);\n    vec3  dataMaxExt(dataMaxExtD[0], dataMaxExtD[1], dataMaxExtD[2]);\n    vec3  lens = dataMaxExt - dataMinExt;\n    float longest = max(lens.x, max(lens.y, lens.z));\n\n    // I was going to try to come up with a continuous equation but I'm\n    // not sure how the original sample rate is determined so I'm just\n    // going off the following two samples of resonable performance vs\n    // quality:\n    //\n    // 4E7 = 0.001\n    // 3E6 = 0.1\n\n    return longest < 3E6f ? glm::mix(1.f, 0.1f, longest / 3E6f) : glm::mix(0.1f, 0.001f, (longest - 3E6f) / (4.05E7f - 3E6f));\n}\n\nOSPVolume VolumeOSPRay::_loadVolumeRegular(const Grid *grid)\n{\n    const auto          dims = grid->GetDimensions();\n    const size_t        nVerts = dims[0] * dims[1] * dims[2];\n    std::vector<double> dataMinExtD, dataMaxExtD;\n    grid->GetUserExtents(dataMinExtD, dataMaxExtD);\n    vec3  dataMinExt(dataMinExtD[0], dataMinExtD[1], dataMinExtD[2]);\n    vec3  dataMaxExt(dataMaxExtD[0], dataMaxExtD[1], dataMaxExtD[2]);\n    vec3  dimsf(dims[0], dims[1], dims[2]);\n    vec3  gridSpacing = (dataMaxExt - dataMinExt) / (dimsf - 1.f);\n    float missingValue = grid->HasMissingData() ? grid->GetMissingValue() : NAN;\n\n    float *fdata = new float[nVerts];\n    if (!fdata) {\n        Wasp::MyBase::SetErrMsg(\"Could not allocate enough RAM to load data\");\n        return nullptr;\n    }\n    auto dataIt = grid->cbegin();\n    for (size_t i = 0; i < nVerts; ++i, ++dataIt) { fdata[i] = *dataIt == missingValue ? NAN : *dataIt; }\n\n    OSPData data = VOSP::NewCopiedData(fdata, OSP_FLOAT, dims[0], dims[1], dims[2]);\n    ospCommit(data);\n    delete[] fdata;\n\n    OSPVolume volume = ospNewVolume(\"structuredRegular\");\n\n    ospSetObject(volume, \"data\", data);\n    ospRelease(data);\n\n    ospSetVec3f(volume, \"gridOrigin\", dataMinExt.x, dataMinExt.y, dataMinExt.z);\n    ospSetVec3f(volume, \"gridSpacing\", gridSpacing.x, gridSpacing.y, gridSpacing.z);\n\n    ospCommit(volume);\n    return volume;\n}\n\nVolumeOSPRay::WindingOrder VolumeOSPRay::getWindingOrderRespectToZ(const vec3 &a, const vec3 &b, const vec3 &c) { return glm::cross(b - a, c - b).z > 0 ? CCW : CW; }\n\nVolumeOSPRay::WindingOrder VolumeOSPRay::getWindingOrderTetra(const vec3 &a, const vec3 &b, const vec3 &c, const vec3 &d)\n{\n    vec3  n = glm::cross(b - a, c - a);\n    float s = glm::dot(d - a, n);\n    if (fabsf(s) < FLT_EPSILON) return INVALID;\n    return s < 0 ? CCW : CW;\n}\n\nconst char *VolumeOSPRay::windingOrderToString(WindingOrder o) { return o == CCW ? \"CCW\" : o == CW ? \"CW\" : \"INVALID\"; }\n\nbool VolumeOSPRay::isQuadCoPlanar(const vec3 &a, const vec3 &b, const vec3 &c, const vec3 &d)\n{\n    vec3  n = glm::normalize(glm::cross(b - a, c - a));\n    float s = glm::dot(d - a, n);\n    return fabsf(s) <= FLT_EPSILON;\n}\n\nOSPVolume VolumeOSPRay::_loadVolumeStructured(const Grid *grid)\n{\n    const auto   dims = grid->GetDimensions();\n    const size_t nVerts = dims[0] * dims[1] * dims[2];\n    float        missingValue = grid->HasMissingData() ? grid->GetMissingValue() : NAN;\n\n    Progress::Start(\"Loading Grid\", 2, false);\n    float *vdata = new float[nVerts];\n    auto   dataIt = grid->cbegin();\n    for (size_t i = 0; i < nVerts; ++i, ++dataIt) vdata[i] = *dataIt == missingValue ? NAN : *dataIt;\n    Progress::Update(1);\n\n    float *cdata = new float[nVerts * 3];\n    auto   coord = grid->ConstCoordBegin();\n    for (size_t i = 0; i < nVerts; ++i, ++coord) {\n        cdata[i * 3] = (*coord)[0];\n        cdata[i * 3 + 1] = (*coord)[1];\n        cdata[i * 3 + 2] = (*coord)[2];\n    }\n    Progress::Finish();\n\n    int xd = dims[0];\n    int yd = dims[1];\n    int zd = dims[2];\n    int cxd = xd - 1;\n    int cyd = yd - 1;\n    int czd = zd - 1;\n\n    if (cxd * cyd * czd == 0) {\n        MyBase::SetErrMsg(\"Volume rendering a flat grid not supported with this method\");\n        return nullptr;\n    }\n\n    // \"indexPrefixed\" is broken\n\n    typedef struct {\n        union {\n            struct {\n                unsigned int i0, i1, i2, i3, i4, i5, i6, i7;\n            };\n            unsigned int i[8];\n        };\n    } Cell;\n    vector<Cell> indices(cxd * cyd * czd);\n\n#define I(x, y, z) (unsigned int)((z)*yd * xd + (y)*xd + (x))\n\n    Progress::Start(\"Convert Grid\", czd, true);\n    for (int z = 0; z < czd; z++) {\n        Progress::Update(z);\n        if (Progress::Cancelled()) {\n            delete[] vdata;\n            delete[] cdata;\n            return nullptr;\n        }\n        for (int y = 0; y < cyd; y++) {\n            for (int x = 0; x < cxd; x++) {\n                indices[z * cyd * cxd + y * cxd + x] = {{{\n                    I(x, y, z),\n                    I(x + 1, y, z),\n                    I(x + 1, y + 1, z),\n                    I(x, y + 1, z),\n                    I(x, y, z + 1),\n                    I(x + 1, y, z + 1),\n                    I(x + 1, y + 1, z + 1),\n                    I(x, y + 1, z + 1),\n                }}};\n            }\n        }\n    }\n    Progress::Finish();\n#undef I\n\n    const int maxCells = INT_MAX;\n    const int nCells = min(maxCells, czd * cyd * cxd);\n    vec3 *    coords = (vec3 *)cdata;\n\n    //    for (int i = 0; i < 8; i++) {\n    //        int ci = indices[nCells-1].i[i];\n    //        printf(\"cells[%i][%i] = (%f, %f, %f)\\n\", nCells-1, i, coords[ci].x, coords[ci].y, coords[ci].z);\n    //    }\n\n    //    for (int i = 0; i < 4; i++) {\n    //        int bi = indices[nCells-1].i[i];\n    //        int ti = indices[nCells-1].i[i+4];\n    //        auto &b = coords[bi];\n    //        auto &t = coords[ti];\n    //        float zdiff = (t-b).z;\n    //        printf(\"ZDiff[%i] = %f%s\\n\", i, zdiff, zdiff < FLT_EPSILON ? \" (< EPSILON)\" : \"\");\n    //    }\n\n    //    bool decompose = GetActiveParams()->GetValueLong(\"osp_decompose\", false);\n    const bool decompose = true;\n    unsigned   nDecomposed = 0;\n    unsigned   nDiscarded = 0;\n\n    Progress::Start(\"Preprocess Grid\", nCells, true);\n    vector<unsigned int>  startIndex;\n    vector<unsigned char> cellType;\n    for (int i = 0; i < nCells; i++) {\n        Progress::Update(i);\n        if (Progress::Cancelled()) {\n            delete[] vdata;\n            delete[] cdata;\n            return nullptr;\n        }\n        bool discard = false;\n        for (int j = 0; j < 4; j++) {\n            if (fabsf((coords[indices[i].i[j + 4]] - coords[indices[i].i[j]]).z) < FLT_EPSILON) {\n                discard = true;\n                break;\n            }\n        }\n        if (discard) {\n            nDiscarded++;\n            continue;\n        }\n\n        if (decompose\n            && (!isQuadCoPlanar(coords[indices[i].i0], coords[indices[i].i1], coords[indices[i].i2], coords[indices[i].i3])\n                || !isQuadCoPlanar(coords[indices[i].i4], coords[indices[i].i5], coords[indices[i].i6], coords[indices[i].i7]))) {\n            Cell c = indices[i];\n            Cell w1 = {{{c.i0, c.i1, c.i3, c.i4, c.i5, c.i7, 0, 0}}};\n            Cell w2 = {{{c.i1, c.i2, c.i3, c.i5, c.i6, c.i7, 0, 0}}};\n\n            if (CW == getWindingOrderRespectToZ(coords[w1.i0], coords[w1.i1], coords[w1.i2])) {\n                std::swap(w1.i1, w1.i2);\n                std::swap(w1.i4, w1.i5);\n            }\n            if (CW == getWindingOrderRespectToZ(coords[w2.i0], coords[w2.i1], coords[w2.i2])) {\n                std::swap(w2.i1, w2.i2);\n                std::swap(w2.i4, w2.i5);\n            }\n\n            startIndex.push_back(indices.size() * 8);\n            cellType.push_back(OSP_WEDGE);\n            indices.push_back(w1);\n            startIndex.push_back(indices.size() * 8);\n            cellType.push_back(OSP_WEDGE);\n            indices.push_back(w2);\n            nDecomposed++;\n            continue;\n        }\n\n        startIndex.push_back(i * 8);\n        cellType.push_back(OSP_HEXAHEDRON);\n    }\n    Progress::Finish();\n\n    //    printf(\"Discarded %i cells\\n\", nDiscarded);\n    //    printf(\"Decomposed %i cells\\n\", nDecomposed);\n    VAssert(cellType.size() == startIndex.size());\n\n    OSPVolume volume = ospNewVolume(\"unstructured\");\n    OSPData   data;\n    Progress::Start(\"Copy data to OSPRay\", 5, false);\n\n    data = VOSP::NewCopiedData(vdata, OSP_FLOAT, nVerts);\n    ospCommit(data);\n    ospSetObject(volume, \"vertex.data\", data);\n    ospRelease(data);\n    delete[] vdata;\n    Progress::Update(1);\n\n    data = VOSP::NewCopiedData(cdata, OSP_VEC3F, nVerts);\n    ospCommit(data);\n    ospSetObject(volume, \"vertex.position\", data);\n    ospRelease(data);\n    delete[] cdata;\n    Progress::Update(2);\n\n    // Was cxd*cyd*czd*8\n    // need to potentially modify when replacing non-parallelpiped cells.\n    data = VOSP::NewCopiedData(indices.data(), OSP_UINT, indices.size() * 8);\n    ospCommit(data);\n    ospSetObject(volume, \"index\", data);\n    ospRelease(data);\n    indices.clear();\n    Progress::Update(3);\n\n    data = VOSP::NewCopiedData(startIndex.data(), OSP_UINT, startIndex.size());\n    ospCommit(data);\n    ospSetObject(volume, \"cell.index\", data);\n    ospRelease(data);\n    startIndex.clear();\n    Progress::Update(4);\n\n    data = VOSP::NewCopiedData(cellType.data(), OSP_UCHAR, cellType.size());\n    ospCommit(data);\n    ospSetObject(volume, \"cell.type\", data);\n    ospRelease(data);\n    cellType.clear();\n    Progress::Update(5);\n    Progress::Finish();\n\n    Progress::StartIndefinite(\"Commit OSPRay\");\n    ospSetBool(volume, \"hexIterative\", true);\n    ospCommit(volume);\n    Progress::Finish();\n\n    return volume;\n}\n\nOSPVolume VolumeOSPRay::_loadVolumeUnstructured(const Grid *grid)\n{\n    const auto      nodeDims = grid->GetDimensions();\n    size_t          nodeDim = grid->GetNumDimensions();\n    const size_t    nVerts = nodeDims[0] * nodeDims[1];\n    const DimsType &cellDims = grid->GetCellDimensions();\n    const size_t    nCells = cellDims[0] * cellDims[1];\n    VAssert(nodeDim == 2);\n\n    float  missingValue = grid->HasMissingData() ? grid->GetMissingValue() : NAN;\n    size_t maxNodes = grid->GetMaxVertexPerCell();\n    //    size_t *nodes = (size_t*)alloca(sizeof(size_t) * maxNodes * nodeDim);\n    std::vector<DimsType> nodes(maxNodes * nodeDim);\n\n    Progress::Start(\"Loading Grid Data\", 2, false);\n    float *vdata = new float[nVerts];\n    auto   dataIt = grid->cbegin();\n    for (size_t i = 0; i < nVerts; ++i, ++dataIt) vdata[i] = *dataIt == missingValue ? NAN : *dataIt;\n    Progress::Update(1);\n\n    float *cdata = new float[nVerts * 3];\n    auto   coord = grid->ConstCoordBegin();\n    for (size_t i = 0; i < nVerts; ++i, ++coord) {\n        cdata[i * 3] = (*coord)[0];\n        cdata[i * 3 + 1] = (*coord)[1];\n        cdata[i * 3 + 2] = (*coord)[2];\n    }\n    Progress::Update(2);\n    Progress::Finish();\n\n    vector<unsigned int>  cellIndices;\n    vector<unsigned int>  cellStarts;\n    vector<unsigned char> cellTypes;\n\n    long added[32] = {0};\n    long skipped[32] = {0};\n\n#ifdef VAPOR_3_5_0\n    int maxCells = std::max(5, std::min((int)nCells, (int)GetParams()->GetValueLong(\"osp_max_cells\", 1)));\n#endif\n\n    auto cellIt = grid->ConstCellBegin();\n    Progress::Start(\"Loading Grid\", nCells, true);\n    for (size_t cellCounter = 0; cellCounter < nCells; ++cellIt, ++cellCounter) {\n        Progress::Update(cellCounter);\n        if (Progress::Cancelled()) {\n            delete[] vdata;\n            delete[] cdata;\n            return nullptr;\n        }\n        const DimsType &cell = *cellIt;\n        grid->GetCellNodes(cell, nodes);\n        int numNodes = nodes.size();\n\n        if (numNodes == 4) {\n            cellStarts.push_back(cellIndices.size());\n            cellTypes.push_back(OSP_TETRAHEDRON);\n            added[numNodes]++;\n\n            for (int i = 0; i < 4; i++) cellIndices.push_back(nodes[i][0] + nodes[i][1] * nodeDims[0]);\n        } else if (numNodes == 6) {\n            cellStarts.push_back(cellIndices.size());\n            cellTypes.push_back(OSP_WEDGE);\n            added[numNodes]++;\n\n            for (int i = 0; i < 6; i++) cellIndices.push_back(nodes[i][0] + nodes[i][1] * nodeDims[0]);\n        } else if (numNodes == 8) {\n            cellStarts.push_back(cellIndices.size());\n            cellTypes.push_back(OSP_HEXAHEDRON);\n            added[numNodes]++;\n\n            for (int i = 0; i < 8; i++) cellIndices.push_back(nodes[i][0] + nodes[i][1] * nodeDims[0]);\n        } else if (numNodes == 12) {    // Hexagonal Prism\n#define add(i) cellIndices.push_back(nodes[i][0] + nodes[i][1] * nodeDims[0]);\n            for (int i = 0; i < 4; i++) {\n                cellStarts.push_back(cellIndices.size());\n                cellTypes.push_back(OSP_WEDGE);\n                add(0);\n                add(i + 1);\n                add(i + 2);\n                add(6);\n                add(6 + i + 1);\n                add(6 + i + 2);\n            }\n#undef add\n            added[numNodes]++;\n        } else {\n            skipped[numNodes]++;\n        }\n\n#ifdef VAPOR_3_5_0\n        if (cellCounter >= maxCells - 1) {\n            printf(\"WARNING BREAKING EARLY\\n\");\n            break;\n        }\n#endif\n    }\n    Progress::Finish();\n\n#ifdef VAPOR_3_5_0\n    long totalAdded = 0, totalSkipped = 0;\n    for (int i = 0; i < 32; i++) {\n        if (added[i] > 0) printf(\"\\tAdded[%i] = %li\\n\", i, added[i]);\n        if (skipped[i] > 0) printf(\"\\tSkipped[%i] = %li\\n\", i, skipped[i]);\n        totalAdded += added[i];\n        totalSkipped += skipped[i];\n    }\n    printf(\"\\tTotal Added = %li\\n\", totalAdded);\n    printf(\"\\tTotal Skipped = %li\\n\", totalSkipped);\n    printf(\"# Coords = %li\\n\", nVerts);\n#endif\n\n    vec3 *       coords = (vec3 *)cdata;\n    vector<bool> erase(cellStarts.size(), false);\n\n    Progress::Start(\"Preprocessing Cells\", cellStarts.size(), true);\n    for (unsigned i = 0; i < cellStarts.size(); i++) {\n        Progress::Update(i);\n        if (Progress::Cancelled()) {\n            delete[] vdata;\n            delete[] cdata;\n            return nullptr;\n        }\n        unsigned start = cellStarts[i];\n        unsigned type = cellTypes[i];\n\n        if (type == OSP_WEDGE) {\n            if (CW == getWindingOrderRespectToZ(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]])) {\n                std::swap(cellIndices[start + 1], cellIndices[start + 2]);\n                std::swap(cellIndices[start + 1 + 3], cellIndices[start + 2 + 3]);\n            }\n            WindingOrder w1 = getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]]);\n            WindingOrder w2 = getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 4]]);\n            WindingOrder w3 = getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 5]]);\n            if (w1 == INVALID || w2 == INVALID || w3 == INVALID) {\n                erase[i] = true;\n                continue;\n            }\n        } else if (type == OSP_TETRAHEDRON) {\n            WindingOrder w = getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]]);\n            if (w == CW) std::swap(cellIndices[start + 1], cellIndices[start + 2]);\n            if (w == INVALID) {\n                erase[i] = true;\n                continue;\n            }\n            VAssert(CCW == getWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]]));\n#ifdef VAPOR_3_5_0\n            if (CCW != GetWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]])) {\n                PrintVec3(coords[cellIndices[start + 0]]);\n                PrintVec3(coords[cellIndices[start + 1]]);\n                PrintVec3(coords[cellIndices[start + 2]]);\n                PrintVec3(coords[cellIndices[start + 3]]);\n                printf(\"Winding = %s\\n\",\n                       to_string(GetWindingOrderTetra(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]], coords[cellIndices[start + 3]])));\n                assert(0);\n            }\n#endif\n        } else if (type == OSP_HEXAHEDRON) {\n            auto windingBottom = getWindingOrderRespectToZ(coords[cellIndices[start + 0]], coords[cellIndices[start + 1]], coords[cellIndices[start + 2]]);\n            auto windingTop = getWindingOrderRespectToZ(coords[cellIndices[start + 4]], coords[cellIndices[start + 5]], coords[cellIndices[start + 6]]);\n            if (INVALID == windingBottom || INVALID == windingTop || windingTop != windingBottom) {\n                erase[i] = true;\n                continue;\n            }\n            if (windingTop == CW) {\n                std::swap(cellIndices[start + 0 + 1], cellIndices[start + 0 + 3]);\n                std::swap(cellIndices[start + 4 + 1], cellIndices[start + 4 + 3]);\n            }\n\n            vec3 min = coords[cellIndices[start]];\n            vec3 max = coords[cellIndices[start]];\n            for (int i = 1; i < 8; i++) {\n                min = glm::min(min, coords[cellIndices[start + i]]);\n                max = glm::max(max, coords[cellIndices[start + i]]);\n            }\n            vec3  bbSizes = max - min;\n            float bbVolume = bbSizes.x * bbSizes.y * bbSizes.z;\n            if (bbVolume <= FLT_EPSILON) {\n                erase[i] = true;\n                continue;\n            }\n        }\n    }\n    Progress::Finish();\n    {\n        vector<unsigned int>  cellStartsNew;\n        vector<unsigned char> cellTypesNew;\n\n        for (int i = 0; i < cellStarts.size(); i++) {\n            if (!erase[i]) {\n                cellStartsNew.push_back(cellStarts[i]);\n                cellTypesNew.push_back(cellTypes[i]);\n            }\n        }\n\n        cellStarts = cellStartsNew;\n        cellTypes = cellTypesNew;\n    }\n\n#ifdef VAPOR_3_5_0\n    int testCell = std::min(cellStarts.size() - 1, (size_t)maxCells - 1);\n    if (testCell >= 0) {\n        int testCellNodes = cellTypes[testCell] == OSP_TETRAHEDRON ? 4 : cellTypes[testCell] == OSP_HEXAHEDRON ? 8 : 6;\n        printf(\"Test Cell[%i].nodes = %i\\n\", testCell, testCellNodes);\n        vec3 testCellCoords[testCellNodes];\n        for (int i = 0; i < testCellNodes; i++) {\n            int idx = cellIndices[cellStarts[testCell] + i];\n            testCellCoords[i] = coords[idx];\n            printf(\"\\tCells[%i].vert[%i] = coords[%i] = (%f, %f, %f)\\n\", testCell, i, idx, coords[idx].x, coords[idx].y, coords[idx].z);\n        }\n        printf(\"\\tWinding bottom = %s\\n\", C(getWindingOrderRespectToZ(testCellCoords[0], testCellCoords[1], testCellCoords[2])));\n        if (testCellNodes == 6) printf(\"\\tWinding top = %s\\n\", C(getWindingOrderRespectToZ(testCellCoords[3], testCellCoords[4], testCellCoords[5])));\n        if (testCellNodes == 8) printf(\"\\tWinding top = %s\\n\", C(getWindingOrderRespectToZ(testCellCoords[4], testCellCoords[5], testCellCoords[6])));\n    }\n#endif\n\n    Progress::Start(\"Sanity Checks\", 5, false);\n    for (auto i : cellIndices) VAssert(i < nVerts);\n    Progress::Update(1);\n    for (auto i : cellStarts) VAssert(i < cellIndices.size());\n    Progress::Update(2);\n    for (auto i : cellTypes) VAssert(i == OSP_WEDGE || i == OSP_TETRAHEDRON || i == OSP_HEXAHEDRON);\n    Progress::Update(3);\n    VAssert(cellStarts[cellStarts.size() - 1] + (cellTypes[cellTypes.size() - 1] == OSP_WEDGE ? 6 : 4) <= cellIndices.size());\n    Progress::Update(4);\n    VAssert(cellStarts.size() == cellTypes.size());\n    Progress::Update(5);\n    Progress::Finish();\n\n    Progress::Start(\"Copy data to OSPRay\", 5, false);\n    OSPVolume volume = ospNewVolume(\"unstructured\");\n    OSPData   data;\n\n    data = VOSP::NewCopiedData(vdata, OSP_FLOAT, nVerts);\n    ospCommit(data);\n    ospSetObject(volume, \"vertex.data\", data);\n    ospRelease(data);\n    delete[] vdata;\n    Progress::Update(1);\n\n    data = VOSP::NewCopiedData(cdata, OSP_VEC3F, nVerts);\n    ospCommit(data);\n    ospSetObject(volume, \"vertex.position\", data);\n    ospRelease(data);\n    delete[] cdata;\n    Progress::Update(2);\n\n    data = VOSP::NewCopiedData(cellIndices.data(), OSP_UINT, cellIndices.size());\n    ospCommit(data);\n    ospSetObject(volume, \"index\", data);\n    ospRelease(data);\n    cellIndices.clear();\n    Progress::Update(3);\n\n    data = VOSP::NewCopiedData(cellStarts.data(), OSP_UINT, cellStarts.size());\n    ospCommit(data);\n    ospSetObject(volume, \"cell.index\", data);\n    ospRelease(data);\n    cellStarts.clear();\n    Progress::Update(4);\n\n    data = VOSP::NewCopiedData(cellTypes.data(), OSP_UCHAR, cellTypes.size());\n    ospCommit(data);\n    ospSetObject(volume, \"cell.type\", data);\n    ospRelease(data);\n    cellTypes.clear();\n    Progress::Update(5);\n    Progress::Finish();\n\n    Progress::Start(\"Commit OSPRay\", 1, false);\n    ospCommit(volume);\n    Progress::Finish();\n\n    return volume;\n}\n\nOSPVolume VolumeOSPRay::_loadVolumeTest(const Grid *grid)\n{\n    std::vector<double> dataMinExtD, dataMaxExtD;\n    grid->GetUserExtents(dataMinExtD, dataMaxExtD);\n    vec3 dataMinExt(dataMinExtD[0], dataMinExtD[1], dataMinExtD[2]);\n    vec3 dataMaxExt(dataMaxExtD[0], dataMaxExtD[1], dataMaxExtD[2]);\n    int  nVerts = 8;\n\n    vector<float> values(nVerts);\n    for (int i = 0; i < nVerts; i++) values[i] = 0;\n\n    vector<vec3> coords(nVerts);\n    float        s = 1;\n    vec3         l = s * dataMinExt;\n    vec3         h = s * dataMaxExt;\n    coords[0] = vec3(0, 0, 0);\n    coords[1] = vec3(1, 0, 0);\n    coords[2] = vec3(1, 1, 0);\n    coords[3] = vec3(0, 1, 0);\n    coords[4] = vec3(0, 0, 1);\n    coords[5] = vec3(1, 0, 1);\n    coords[6] = vec3(1, 1, 1);\n    coords[7] = vec3(0, 1, 1);\n\n    for (int i = 0; i < 8; i++) coords[i] = coords[i] * (h - l) + l;\n\n    OSPVolume volume = ospNewVolume(\"unstructured\");\n    OSPData   data;\n\n    data = VOSP::NewCopiedData(values.data(), OSP_FLOAT, nVerts);\n    ospCommit(data);\n    ospSetObject(volume, \"vertex.data\", data);\n    ospRelease(data);\n\n    data = VOSP::NewCopiedData(coords.data(), OSP_VEC3F, nVerts);\n    ospCommit(data);\n    ospSetObject(volume, \"vertex.position\", data);\n    ospRelease(data);\n\n    vector<unsigned int>  cellIndices;\n    vector<unsigned int>  cellStarts;\n    vector<unsigned char> cellTypes;\n\n#if 1\n    cellStarts.push_back(cellIndices.size());\n    cellTypes.push_back(OSP_HEXAHEDRON);\n    cellIndices.push_back(0);\n    cellIndices.push_back(1);\n    cellIndices.push_back(2);\n    cellIndices.push_back(3);\n    cellIndices.push_back(4);\n    cellIndices.push_back(5);\n    cellIndices.push_back(6);\n    cellIndices.push_back(7);\n#else\n    cellStarts.push_back(cellIndices.size());\n    cellTypes.push_back(OSP_WEDGE);\n    cellIndices.push_back(0);\n    cellIndices.push_back(1);\n    cellIndices.push_back(3);\n    cellIndices.push_back(4);\n    cellIndices.push_back(5);\n    cellIndices.push_back(7);\n    cellStarts.push_back(cellIndices.size());\n    cellTypes.push_back(OSP_WEDGE);\n    cellIndices.push_back(1);\n    cellIndices.push_back(2);\n    cellIndices.push_back(3);\n    cellIndices.push_back(5);\n    cellIndices.push_back(6);\n    cellIndices.push_back(7);\n    cellStarts.push_back(cellIndices.size());\n    cellTypes.push_back(OSP_TETRAHEDRON);\n    cellIndices.push_back(0);\n    cellIndices.push_back(1);\n    cellIndices.push_back(2);\n    cellIndices.push_back(3);\n#endif\n\n    data = VOSP::NewCopiedData(cellIndices.data(), OSP_UINT, cellIndices.size());\n    ospCommit(data);\n    ospSetObject(volume, \"index\", data);\n    ospRelease(data);\n\n    data = VOSP::NewCopiedData(cellStarts.data(), OSP_UINT, cellStarts.size());\n    ospCommit(data);\n    ospSetObject(volume, \"cell.index\", data);\n    ospRelease(data);\n\n    data = VOSP::NewCopiedData(cellTypes.data(), OSP_UCHAR, cellTypes.size());\n    ospCommit(data);\n    ospSetObject(volume, \"cell.type\", data);\n    ospRelease(data);\n\n    ospSetBool(volume, \"hexIterative\", true);\n    ospCommit(volume);\n    return volume;\n}\n\n/*\n#include <vapor/LegacyGL.h>\nvoid VolumeRenderer::drawTestCellOutline()\n{\n    if (!GetActiveParams()->GetValueLong(\"osp_test_volume\", false))\n    return;\n\n    LegacyGL *lgl = _glManager->legacy;\n    lgl->Begin(GL_LINE_STRIP);\n    lgl->Color3f(1, 0, 0);\n    lgl->Vertex(testCell[0]);\n    lgl->Color3f(0, 1, 0);\n    lgl->Vertex(testCell[1]);\n    lgl->Color3f(0, 0, 1);\n    lgl->Vertex(testCell[2]);\n    lgl->Color3f(0, 1, 1);\n    lgl->Vertex(testCell[3]);\n    lgl->Color3f(1, 0, 0);\n    lgl->Vertex(testCell[0]);\n    lgl->Color3f(1, 1, 1);\n    lgl->Vertex(testCell[4]);\n//    lgl->Color3f(0, 1, 0);\n    lgl->Vertex(testCell[5]);\n//    lgl->Color3f(0, 0, 1);\n    lgl->Vertex(testCell[6]);\n//    lgl->Color3f(0, 1, 1);\n    lgl->Vertex(testCell[7]);\n//    lgl->Color3f(1, 0, 0);\n    lgl->Vertex(testCell[4]);\n    lgl->End();\n    lgl->Begin(GL_LINES);\n    lgl->Color3f(0, 1, 0);\n    lgl->Vertex(testCell[1]);\n    lgl->Vertex(testCell[5]);\n    lgl->Color3f(0, 0, 1);\n    lgl->Vertex(testCell[2]);\n    lgl->Vertex(testCell[6]);\n    lgl->Color3f(0, 1, 1);\n    lgl->Vertex(testCell[3]);\n    lgl->Vertex(testCell[7]);\n    lgl->End();\n\n    if (!GetActiveParams()->GetValueLong(\"osp_draw_test_cell_faces\", false))\n        return;\n\n    lgl->Color3f(1, 1, 1);\n    lgl->EnableLighting();\n    ViewpointParams* vp = _paramsMgr->GetViewpointParams(_winName);\n    double matrix[16], dpos[3], dup[3], ddir[3];\n    vp->GetModelViewMatrix(matrix);\n    vp->ReconstructCamera(matrix, dpos, dup, ddir);\n    vec3 dir(ddir[0], ddir[1], ddir[2]);\n    lgl->LightDirectionfv((float*)&dir);\n    glDepthFunc(GL_LESS);\n\n#define FACE(a, b, c) { vec3 n = glm::normalize(glm::cross(testCell[b]-testCell[a], testCell[c]-testCell[a])); lgl->Normal3fv((float*)&n); lgl->Vertex(testCell[a]); lgl->Vertex(testCell[b]);\nlgl->Vertex(testCell[c]); } #define QUAD(a, b, c, d) { FACE(a, b, d); FACE(d, b, c); } lgl->Begin(GL_TRIANGLES); QUAD(0, 1, 2, 3); QUAD(4, 5, 6, 7); QUAD(0, 1, 5, 4); QUAD(1, 2, 6, 5); QUAD(2, 3, 7,\n6); QUAD(3, 0, 4, 7); lgl->End(); #undef FACE\n\n    glDepthFunc(GL_ALWAYS);\n    lgl->DisableLighting();\n}\n*/\n\nstatic VolumeAlgorithmRegistrar<VolumeOSPRayIso> registrationIso;\n"
  },
  {
    "path": "lib/render/VolumeRectilinear.cpp",
    "content": "#include \"vapor/RegularGrid.h\"\n\n\n#include <vapor/VolumeRectilinear.h>\n#include <vector>\n#include <array>\n#include <algorithm>\n#include <vapor/StretchedGrid.h>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n#include <vapor/GLManager.h>\n#include <vapor/ShaderManager.h>\n#include <vapor/Progress.h>\n\n#ifndef FLT16_MAX\n    #define FLT16_MAX 6.55E4\n#endif\n\nusing glm::ivec2;\nusing glm::ivec3;\nusing glm::vec3;\nusing std::array;\nusing std::vector;\n\nusing namespace VAPoR;\n\nstatic VolumeAlgorithmRegistrar<VolumeRectilinear>    registration;\nstatic VolumeAlgorithmRegistrar<VolumeRectilinearIso> registration2;\n\nVolumeRectilinear::VolumeRectilinear(GLManager *gl, VolumeRenderer *renderer) : VolumeRegular(gl, renderer), _useHighPrecisionTriangleRoutine(false)\n{\n    _coordLUTTexture.Generate(GL_LINEAR);\n    _minTexture.Generate(GL_NEAREST);\n    _maxTexture.Generate(GL_NEAREST);\n    _BBLevelDimTexture.Generate(GL_NEAREST);\n}\n\nVolumeRectilinear::~VolumeRectilinear() {}\n\nint VolumeRectilinear::LoadData(const Grid *grid)\n{\n    if (VolumeRegular::LoadData(grid) < 0) return -1;\n\n    _useHighPrecisionTriangleRoutine = false;\n    _gridHasInvertedCoordinateSystemHandiness = !grid->HasInvertedCoordinateSystemHandiness();\n\n    const auto dims = grid->GetDimensions();\n    const auto w = dims[0], h = dims[1], d = dims[2];\n    _coordDims[0] = w;\n    _coordDims[1] = h;\n    _coordDims[2] = d;\n\n    vec3 dataMin, dataMax, userMin, userMax;\n    _getExtents(&dataMin, &dataMax, &userMin, &userMax);\n    vec3  extLengths = dataMax - dataMin;\n\n    Progress::Start(\"Load coord data\", 6);\n\n    GLint max2DTexDim;\n    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max2DTexDim);\n    max2DTexDim /= 100;\n    vector<float> coordLUTData(max2DTexDim * 3);\n\n    auto coords = array<vector<float>, 3>();\n    array<vector<double>, 3> srcCoords;\n\n    auto rgrid = dynamic_cast<const StretchedGrid*>(grid);\n    if (rgrid) {\n        srcCoords = {\n            rgrid->GetXCoords(),\n            rgrid->GetYCoords(),\n            rgrid->GetZCoords(),\n        };\n    } else {\n        for (int i = 0; i < 3; i++) {\n            srcCoords[i] = vector<double>(dims[i]);\n            for (int j = 0; j < dims[i]; j++) {\n                auto idx = DimsType();\n                auto coord = CoordType();\n                idx[i] = j;\n                grid->GetUserCoordinates(idx, coord);\n                srcCoords[i][j] = coord[i];\n            }\n        }\n    }\n\n    for (int i = 0; i < 3; i++) {\n        Progress::Update(1+i);\n        coords[i].resize(dims[i]);\n        _coordSigns[i] = coords[i][0] < coords[i][dims[i]-1] ? 1 : -1;\n        for (int j = 0; j < dims[i]; j++) {\n            coords[i][j] = (srcCoords[i][j] - dataMin[i]) / extLengths[i];\n        }\n\n        for (int j = 0; j < dims[i]-1; j++) {\n            int start = coords[i][j]*max2DTexDim;\n            int end = coords[i][j+1]*max2DTexDim;\n            if (end < start) {\n                int t = start;\n                start = end;\n                end = t;\n            }\n            for (int k = start; k < end; k++)\n                coordLUTData[i*max2DTexDim + k] = (j + (k-start)/(float)(end-start))/(float)(dims[i]-1);\n        }\n    }\n\n    Progress::Update(4);\n    _coordLUTTexture.TexImage(GL_R32F, max2DTexDim, 3, 0, GL_RED, GL_FLOAT, coordLUTData.data());\n    Progress::Finish();\n\n    return 0;\n}\n\nstd::string VolumeRectilinear::_addDefinitionsToShader(std::string shaderName) const\n{\n    shaderName = VolumeRegular::_addDefinitionsToShader(shaderName);\n\n    if (_useHighPrecisionTriangleRoutine) shaderName += \":USE_INTEL_TRI_ISECT\";\n\n    if (_gridHasInvertedCoordinateSystemHandiness) shaderName += \":INVERT_GRID_COORD_SYS_HAND\";\n\n    GLManager::Vendor vendor = GLManager::GetVendor();\n\n    if (vendor == GLManager::Vendor::Nvidia || vendor == GLManager::Vendor::AMD || vendor == GLManager::Vendor::Mesa) shaderName += \":NVIDIA\";\n\n    shaderName += \":BB_LEVELS \" + std::to_string(3);\n\n    return shaderName;\n}\n\nShaderProgram *VolumeRectilinear::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader(\"VolumeRectilinearDVR\")); }\n\nvoid VolumeRectilinear::SetUniforms(const ShaderProgram *s) const\n{\n    VolumeRegular::SetUniforms(s);\n\n    s->SetUniform(\"coordDims\", *(glm::ivec3 *)&_coordDims);\n    s->SetUniform(\"coordSigns\", *(glm::ivec3 *)&_coordSigns);\n\n    s->SetSampler(\"coordLUT\", _coordLUTTexture);\n    s->SetSampler(\"boxMins\", _minTexture);\n    s->SetSampler(\"boxMaxs\", _maxTexture);\n    s->SetSampler(\"levelDims\", _BBLevelDimTexture);\n}\n\nfloat VolumeRectilinear::GuestimateFastModeSpeedupFactor() const { return 2; }\n\nint VolumeRectilinear::CheckHardwareSupport(const Grid *grid) const\n{\n    int ret = VolumeRegular::CheckHardwareSupport(grid);\n    if (ret < 0)\n        return ret;\n\n    long freeKB = oglGetFreeMemory();\n    if (freeKB >= 0) {\n        auto dims = grid->GetDimensions();\n        long estimatedMinimumB = dims[0]*dims[1]*dims[2] * sizeof(float) * 4;\n        long estimatedMinimumKB = estimatedMinimumB/1024;\n        if (freeKB < estimatedMinimumKB) {\n            Wasp::MyBase::SetErrMsg(\"Not enough GPU RAM free (%liMB free, need at least %liMB)\\n\", freeKB/1024, estimatedMinimumKB/1024);\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\nShaderProgram *VolumeRectilinearIso::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader(\"VolumeRectilinearIso\")); }\n\nvoid VolumeRectilinearIso::SetUniforms(const ShaderProgram *shader) const { VolumeRectilinear::SetUniforms(shader); }\n"
  },
  {
    "path": "lib/render/VolumeRegular.cpp",
    "content": "#include <vapor/VolumeRegular.h>\n#include <vector>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n#include <vapor/GLManager.h>\n#include <vapor/Progress.h>\n\nusing std::vector;\n\nusing namespace VAPoR;\n\nstatic VolumeAlgorithmRegistrar<VolumeRegular> registration;\n\nVolumeRegular::VolumeRegular(GLManager *gl, VolumeRenderer *renderer) : VolumeGLSL(gl, renderer), _hasSecondData(false)\n{\n    _data.Generate();\n    _missing.Generate();\n}\n\nVolumeRegular::~VolumeRegular() {}\n\nint VolumeRegular::LoadData(const Grid *grid)\n{\n    VolumeGLSL::LoadData(grid);\n    if (grid->GetNumDimensions() != 3) {\n        Wasp::MyBase::SetErrMsg(\"Variable has a volume of 0\");\n        return -1;\n    }\n    auto tmp = grid->GetDimensions();\n    _dataDimensions = {tmp[0], tmp[1], tmp[2]};\n    _hasSecondData = false;\n    return _loadDataDirect(grid, &_data, &_missing, &_hasMissingData);\n}\n\nint VolumeRegular::LoadSecondaryData(const Grid *grid)\n{\n    _hasSecondData = false;\n    auto tmp = grid->GetDimensions();\n    auto dims = std::vector<size_t>{tmp[0], tmp[1], tmp[2]};\n    if (_dataDimensions != dims) {\n        Wasp::MyBase::SetErrMsg(\"Secondary (color mapped) variable has different grid from primary variable\");\n        return -1;\n    }\n    if (!_data2.Initialized()) _data2.Generate();\n    if (!_missing2.Initialized()) _missing2.Generate();\n    int ret = _loadDataDirect(grid, &_data2, &_missing2, &_hasMissingData2);\n    if (ret >= 0) _hasSecondData = true;\n    return ret;\n}\n\nvoid VolumeRegular::DeleteSecondaryData()\n{\n    _hasSecondData = false;\n    _data2.Delete();\n    _missing2.Delete();\n}\n\nint VolumeRegular::_loadDataDirect(const Grid *grid, Texture3D *dataTexture, Texture3D *missingTexture, bool *hasMissingData)\n{\n    auto         dims = grid->GetDimensions();\n    const size_t nVerts = dims[0] * dims[1] * dims[2];\n    float *      data = new float[nVerts];\n    if (!data) {\n        Wasp::MyBase::SetErrMsg(\"Could not allocate enough RAM to load data\");\n        return -1;\n    }\n\n    Progress::Start(\"Load volume data\", nVerts, true);\n    auto dataIt = grid->cbegin();\n    for (size_t i = 0; i < nVerts; ++i, ++dataIt) {\n        Progress::Update(i);\n        if (Progress::Cancelled()) {\n            delete[] data;\n            return -1;\n        }\n        data[i] = *dataIt;\n    }\n    Progress::Finish();\n\n    int ret = dataTexture->TexImage(GL_R32F, dims[0], dims[1], dims[2], GL_RED, GL_FLOAT, data);\n\n    *hasMissingData = grid->HasMissingData();\n    if (ret == 0 && *hasMissingData) {\n        const float    missingValue = grid->GetMissingValue();\n        unsigned char *missingMask = new unsigned char[nVerts];\n        memset(missingMask, 0, nVerts);\n\n        for (size_t i = 0; i < nVerts; i++)\n            if (data[i] == missingValue) missingMask[i] = 255;\n\n        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n        ret = missingTexture->TexImage(GL_R8, dims[0], dims[1], dims[2], GL_RED, GL_UNSIGNED_BYTE, missingMask);\n        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);\n\n        delete[] missingMask;\n    }\n\n    delete[] data;\n    return ret;\n}\n\nShaderProgram *VolumeRegular::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader(\"VolumeDVR\")); }\n\nvoid VolumeRegular::SetUniforms(const ShaderProgram *s) const\n{\n    s->SetUniform(\"hasMissingData\", _hasMissingData);\n\n    s->SetSampler(\"data\", _data);\n    s->SetSampler(\"missingMask\", _missing);\n\n    s->SetUniform(\"useColormapData\", _hasSecondData);\n    if (_hasSecondData) {\n        s->SetUniform(\"hasMissingData2\", _hasMissingData2);\n\n        s->SetSampler(\"data2\", _data2);\n        s->SetSampler(\"missing2\", _missing2);\n    }\n}\n\nfloat VolumeRegular::GuestimateFastModeSpeedupFactor() const { return 5; }\n\nint VolumeRegular::CheckHardwareSupport(const Grid *grid) const\n{\n    int maxTexDim;\n    glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &maxTexDim);\n\n    auto dims = grid->GetDimensions();\n    for (auto d : dims) {\n        if (d > maxTexDim) {\n            Wasp::MyBase::SetErrMsg(\"Grid size (%lix%lix%li) not supported by GPU (max supported size per dim is %i)\\n\", dims[0], dims[1], dims[2], maxTexDim);\n            return -1;\n        }\n    }\n\n    long freeKB = oglGetFreeMemory();\n    if (freeKB >= 0) {\n        long estimatedMinimumB = dims[0]*dims[1]*dims[2] * sizeof(float);\n        long estimatedMinimumKB = estimatedMinimumB/1024;\n        if (freeKB < estimatedMinimumKB) {\n            Wasp::MyBase::SetErrMsg(\"Not enough GPU RAM free (%liMB free, need at least %liMB)\\n\", freeKB/1024, estimatedMinimumKB/1024);\n            return -1;\n        }\n    }\n\n    return 0;\n}\n\n\nstd::string VolumeRegular::_addDefinitionsToShader(std::string shaderName) const\n{\n    if (_hasSecondData) shaderName += \":USE_SECOND_DATA\";\n\n    return shaderName;\n}\n\nstatic VolumeAlgorithmRegistrar<VolumeRegularIso> registrationIso;\n\nShaderProgram *VolumeRegularIso::GetShader() const { return _glManager->shaderManager->GetShader(_addDefinitionsToShader(\"VolumeIso\")); }\n\nvoid VolumeRegularIso::SetUniforms(const ShaderProgram *shader) const { VolumeRegular::SetUniforms(shader); }\n"
  },
  {
    "path": "lib/render/VolumeRenderer.cpp",
    "content": "#include \"vapor/VolumeRenderer.h\"\n#include <vapor/VolumeParams.h>\n#include <vapor/MatrixManager.h>\n#include <vapor/GLManager.h>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n#include <vapor/VolumeRegular.h>\n#include \"vapor/VolumeRectilinear.h\"\n#include <vapor/VolumeCellTraversal.h>\n#include <vapor/VolumeOSPRay.h>\n\nusing glm::ivec2;\nusing glm::mat4;\nusing glm::vec2;\nusing glm::vec3;\nusing glm::vec4;\nusing std::string;\nusing std::vector;\n\n#define CheckCache(cVar, pVar)     \\\n    if (cVar != pVar) {            \\\n        _cache.needsUpdate = true; \\\n        cVar = pVar;               \\\n    }\n\nusing namespace VAPoR;\n\nstatic RendererRegistrar<VolumeRenderer> registrar(VolumeRenderer::GetClassType(), VolumeParams::GetClassType());\n\nVolumeRenderer::VolumeRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string &instName, DataMgr *dataMgr)\n: VolumeRenderer(pm, winName, dataSetName, VolumeParams::GetClassType(), VolumeRenderer::GetClassType(), instName, dataMgr)\n{\n}\n\nVolumeRenderer::VolumeRenderer(const ParamsMgr *pm, std::string &winName, std::string &dataSetName, std::string paramsType, std::string classType, std::string &instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, paramsType, classType, instName, dataMgr)\n{\n    _lastRenderTime = 10000;\n    _lastRenderWasFast = false;\n    _framebufferRatio = 1;\n    _previousFramebufferRatio = 1;\n\n    if (_needToSetDefaultAlgorithm()) {\n        VolumeParams * vp = (VolumeParams *)GetActiveParams();\n        CoordType      minExt, maxExt;\n        vp->GetBox()->GetExtents(minExt, maxExt);\n\n        Grid *grid = _dataMgr->GetVariable(vp->GetCurrentTimestep(), vp->GetVariableName(), vp->GetRefinementLevel(), vp->GetCompressionLevel(), minExt, maxExt);\n        if (grid) {\n            string algorithmName = _getDefaultAlgorithmForGrid(grid);\n            vp->SetAlgorithm(algorithmName);\n            delete grid;\n        } else {\n            vp->SetAlgorithm(VolumeRegular::GetName());\n        }\n    }\n}\n\nVolumeRenderer::~VolumeRenderer()\n{\n    if (_VAO) glDeleteVertexArrays(1, &_VAO);\n    if (_VBO) glDeleteBuffers(1, &_VBO);\n    if (_VAOChunked) glDeleteVertexArrays(1, &_VAOChunked);\n    if (_VBOChunked) glDeleteBuffers(1, &_VBOChunked);\n    if (_cache.tf) delete _cache.tf;\n    if (_algorithm) delete _algorithm;\n}\n\nint VolumeRenderer::_initializeGL()\n{\n    const float BL = -1;\n    const float data[] = {BL, BL, 0, 0, 1, BL, 1, 0, BL, 1, 0, 1,\n\n                          BL, 1,  0, 1, 1, BL, 1, 0, 1,  1, 1, 1};\n\n    glGenVertexArrays(1, &_VAO);\n    glGenBuffers(1, &_VBO);\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);\n    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL);\n    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n\n    glGenVertexArrays(1, &_VAOChunked);\n    glGenBuffers(1, &_VBOChunked);\n    glBindVertexArray(_VAOChunked);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBOChunked);\n    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL);\n    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float)));\n    glEnableVertexAttribArray(0);\n    glEnableVertexAttribArray(1);\n\n    _framebufferSize[0] = -1;\n    _framebufferSize[1] = -1;\n\n    _framebuffer.EnableDepthBuffer();\n    _framebuffer.Generate();\n\n    return 0;\n}\n\nint VolumeRenderer::_paintGL(bool fast)\n{\n    if (fast && _wasTooSlowForFastRender()) return 0;\n\n    auto p = GetActiveParams();\n    CheckCache(_cache.ospMaxCells, p->GetValueLong(\"osp_max_cells\", 1));\n    CheckCache(_cache.ospTestCellId, p->GetValueLong(\"osp_test_cells\", 1));\n    CheckCache(_cache.osp_force_regular, p->GetValueLong(\"osp_force_regular\", 0));\n    CheckCache(_cache.osp_test_volume, p->GetValueLong(\"osp_test_volume\", 0));\n    CheckCache(_cache.osp_decompose, p->GetValueLong(\"osp_decompose\", 0));\n    CheckCache(_cache.osp_enable_clipping, p->GetValueLong(\"osp_enable_clipping\", 1));\n\n    if (_initializeAlgorithm() < 0) return -1;\n    if (_loadData() < 0) return -1;\n    if (_loadSecondaryData() < 0) return -1;\n    _cache.needsUpdate = false;\n\n    _algorithm->SaveDepthBuffer(fast);\n    _initializeFramebuffer(fast);\n\n    glEnable(GL_BLEND);\n    int src, dst;\n    _algorithm->GetFinalBlendingMode(&src, &dst);\n    glBlendFunc(src, dst);\n    glDepthMask(GL_TRUE);\n    glEnable(GL_DEPTH_TEST);\n    glDepthFunc(GL_ALWAYS);\n\n    void *start = GLManager::BeginTimer();\n\n    _algorithm->Render(fast);\n    if (_shouldUseChunkedRender(fast))\n        _drawScreenQuadChuncked();\n    else\n        _drawScreenQuad();\n    double renderTime = GLManager::EndTimer(start);\n    _lastRenderTime = renderTime;\n    _lastRenderWasFast = fast;\n\n    int ret = _renderFramebufferToDisplay();\n\n    glDepthFunc(GL_LESS);\n    glDisable(GL_BLEND);\n    glBindVertexArray(0);\n    ShaderProgram::UnBind();\n\n    return ret;\n}\n\nstd::string VolumeRenderer::_getColorbarVariableName() const\n{\n    VolumeParams *vp = dynamic_cast<VolumeParams *>(GetActiveParams());\n    if (vp->GetValueLong(VolumeParams::UseColormapVariableTag, 0))\n        return vp->GetColorMapVariableName();\n    else\n        return vp->GetVariableName();\n}\n\nvoid VolumeRenderer::_drawScreenQuad()\n{\n    glBindVertexArray(_VAO);\n    glDrawArrays(GL_TRIANGLES, 0, 6);\n}\n\nvoid VolumeRenderer::_drawScreenQuadChuncked()\n{\n    // This constant is not correctly parenthesized because of precision issues\n#define CHUNKS_PER_DIM_CONSTANT 64 / (1000 * 1000)\n\n    int   width = _originalViewport[2] - _originalViewport[0];\n    int   height = _originalViewport[3] - _originalViewport[1];\n    float nPixels = width * height;\n\n    double chunksPerDim = sqrt(nPixels * CHUNKS_PER_DIM_CONSTANT);\n\n    int framebufferChunksPerDim = ceil(chunksPerDim / _framebufferRatio);\n    _generateChunkedRenderMesh(framebufferChunksPerDim);\n\n    glBindVertexArray(_VAOChunked);\n    for (int i = 0; i < _nChunks; i++) {\n        glDrawArrays(GL_TRIANGLES, i * 6, 6);\n        glFinish();\n    }\n}\n\nvoid VolumeRenderer::_generateChunkedRenderMesh(const float C)\n{\n    vector<vec4> d;\n    _nChunks = powf(ceil(C), 2);\n    d.reserve(powf(ceil(C), 2) * 6);\n    float ts = 1 / (float)C;\n    for (int yi = 0; yi < C; yi++) {\n        float y = 2.f * yi / (float)C - 1.f;\n        float ty = yi / (float)C;\n        float y2 = 2.f * (yi + 1) / (float)C - 1.f;\n        float ty2 = min(ty + ts, 1.0f);\n        for (int xi = 0; xi < C; xi++) {\n            float x = 2.f * xi / (float)C - 1.f;\n            float tx = xi / (float)C;\n            float x2 = 2.f * (xi + 1) / (float)C - 1.f;\n            float tx2 = min(tx + ts, 1.0f);\n\n            d.push_back(vec4(x, y, tx, ty));\n            d.push_back(vec4(x2, y, tx2, ty));\n            d.push_back(vec4(x, y2, tx, ty2));\n\n            d.push_back(vec4(x, y2, tx, ty2));\n            d.push_back(vec4(x2, y, tx2, ty));\n            d.push_back(vec4(x2, y2, tx2, ty2));\n        }\n    }\n    glBindBuffer(GL_ARRAY_BUFFER, _VBOChunked);\n    glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4 * d.size(), d.data(), GL_STATIC_DRAW);\n}\n\n#define MAX_FRAMEBUFFER_RATIO 15.0f\n\nbool VolumeRenderer::_wasTooSlowForFastRender() const\n{\n    float prevFPS = 1 / _lastRenderTime;\n\n    if (_lastRenderWasFast && prevFPS < 10 && _framebufferRatio == MAX_FRAMEBUFFER_RATIO) return true;\n    return false;\n}\n\nvoid VolumeRenderer::_computeNewFramebufferRatio()\n{\n    float prevFPS = 1 / _lastRenderTime;\n    if (!_lastRenderWasFast) prevFPS *= _algorithm->GuestimateFastModeSpeedupFactor();\n\n    if (prevFPS < 24 || (prevFPS > 40 && _framebufferRatio > 3) || prevFPS > 60) {\n        float ratioTo30FPS = 30 / prevFPS;\n        float perDimRatio = sqrtf(ratioTo30FPS);\n        _framebufferRatio *= perDimRatio;\n        _framebufferRatio = min(_framebufferRatio, MAX_FRAMEBUFFER_RATIO);\n        _framebufferRatio = max(_framebufferRatio, 1.0f);\n    }\n}\n\nbool VolumeRenderer::_shouldUseChunkedRender(bool fast) const\n{\n    if (_algorithm) {\n        if (_algorithm->RequiresChunkedRendering()) return true;\n\n        float estimatedTime = _lastRenderTime;\n        if (_lastRenderWasFast && !fast) {\n            estimatedTime *= powf(_previousFramebufferRatio, 2);\n            estimatedTime *= _algorithm->GuestimateFastModeSpeedupFactor();\n        }\n\n        if (estimatedTime > 1.0f) return true;\n    }\n    return false;\n}\n\nbool VolumeRenderer::_usingColorMapData() const\n{\n    // Overriden by VolumeIsoRenderer\n    return GetActiveParams()->GetValueLong(VAPoR::VolumeParams::UseColormapVariableTag, false);\n}\n\nvoid VolumeRenderer::_saveOriginalViewport() { glGetIntegerv(GL_VIEWPORT, _originalViewport); }\n\nvoid VolumeRenderer::_restoreOriginalViewport() { glViewport(_originalViewport[0], _originalViewport[1], _originalViewport[2], _originalViewport[3]); }\n\nvoid VolumeRenderer::_initializeFramebuffer(bool fast)\n{\n    _previousFramebufferRatio = _framebufferRatio;\n\n    if (fast)\n        _computeNewFramebufferRatio();\n    else\n        _framebufferRatio = 1;\n\n    _saveOriginalViewport();\n    ivec2 fbSize(_originalViewport[2], _originalViewport[3]);\n    fbSize /= _framebufferRatio;\n    _framebuffer.SetSize(fbSize.x, fbSize.y);\n\n    glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &_originalFramebuffer);\n    _framebuffer.MakeRenderTarget();\n    glClearColor(0, 0, 0, 0);\n    glDepthMask(true);\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n}\n\nint VolumeRenderer::_renderFramebufferToDisplay()\n{\n    _framebuffer.UnBind();\n    glBindFramebuffer(GL_FRAMEBUFFER, _originalFramebuffer);\n    _restoreOriginalViewport();\n    SmartShaderProgram framebufferShader = _glManager->shaderManager->GetShader(\"Framebuffer\");\n    if (!framebufferShader.IsValid()) return -1;\n    framebufferShader->SetSampler(\"colorBuffer\", *_framebuffer.GetColorTexture());\n    framebufferShader->SetSampler(\"depthBuffer\", *_framebuffer.GetDepthTexture());\n    _drawScreenQuad();\n\n    return 0;\n}\n\nint VolumeRenderer::_initializeAlgorithm()\n{\n    VolumeParams *vp = (VolumeParams *)GetActiveParams();\n\n    if (_cache.algorithmName != vp->GetAlgorithm()) {\n        _cache.algorithmName = vp->GetAlgorithm();\n        if (_cache.algorithmName == \"\") _cache.algorithmName = \"NULL\";\n        if (_algorithm) delete _algorithm;\n        _algorithm = VolumeAlgorithm::NewAlgorithm(_cache.algorithmName, _glManager, this);\n        _cache.needsUpdate = true;\n    }\n    if (_algorithm)\n        return 0;\n    else\n        return -1;\n}\n\nint VolumeRenderer::_loadData()\n{\n    VolumeParams * RP = (VolumeParams *)GetActiveParams();\n    vector<double> minExtVec, maxExtVec;\n    RP->GetBox()->GetExtents(minExtVec, maxExtVec);\n\n    CheckCache(_cache.var, RP->GetVariableName());\n    CheckCache(_cache.ts, RP->GetCurrentTimestep());\n    CheckCache(_cache.refinement, RP->GetRefinementLevel());\n    CheckCache(_cache.compression, RP->GetCompressionLevel());\n    CheckCache(_cache.minExt, minExtVec);\n    CheckCache(_cache.maxExt, maxExtVec);\n    CheckCache(_cache.ospMaxCells, RP->GetValueLong(\"osp_max_cells\", 1));\n    if (!_cache.needsUpdate) return 0;\n\n    CoordType minExt, maxExt;\n    Grid::CopyToArr3(_cache.minExt, minExt);\n    Grid::CopyToArr3(_cache.maxExt, maxExt);\n\n    Grid *grid = _dataMgr->GetVariable(_cache.ts, _cache.var, _cache.refinement, _cache.compression, minExt, maxExt);\n    if (!grid) return -1;\n\n    if (dynamic_cast<const UnstructuredGrid *>(grid) && !dynamic_cast<VolumeOSPRay *>(_algorithm)) {\n        MyBase::SetErrMsg(\"Unstructured grids are not supported by the GPU renderer\");\n        return -1;\n    }\n\n    // Actual min and max extents of returned grid, which are in general\n    // larger than requested extents.\n    //\n    grid->GetUserExtents(_dataMinExt, _dataMaxExt);\n\n    if (_needToSetDefaultAlgorithm()) {\n        RP->SetAlgorithm(_getDefaultAlgorithmForGrid(grid));\n        if (_initializeAlgorithm() < 0) {\n            delete grid;\n            return -1;\n        }\n    }\n\n    int ret = _algorithm->CheckHardwareSupport(grid);\n    if (ret == 0) {\n        ret = _algorithm->LoadData(grid);\n        _lastRenderTime = 10000;\n    }\n    delete grid;\n    return ret;\n}\n\nint VolumeRenderer::_loadSecondaryData()\n{\n    VolumeParams *vp = (VolumeParams *)GetActiveParams();\n    CheckCache(_cache.useColorMapVar, _usingColorMapData());\n    CheckCache(_cache.colorMapVar, vp->GetColorMapVariableName());\n    if (!_cache.needsUpdate) return 0;\n\n    if (_cache.useColorMapVar) {\n        CoordType minExt, maxExt;\n        Grid::CopyToArr3(_cache.minExt, minExt);\n        Grid::CopyToArr3(_cache.maxExt, maxExt);\n\n        Grid *grid = _dataMgr->GetVariable(_cache.ts, _cache.colorMapVar, _cache.refinement, _cache.compression, minExt, maxExt);\n        if (!grid) return -1;\n        int ret = _algorithm->LoadSecondaryData(grid);\n        delete grid;\n        return ret;\n    } else {\n        _algorithm->DeleteSecondaryData();\n        return 0;\n    }\n}\n\nstd::string VolumeRenderer::_getDefaultAlgorithmForGrid(const Grid *grid) const\n{\n    bool intel = GLManager::GetVendor() == GLManager::Vendor::Intel;\n\n    if (dynamic_cast<const RegularGrid *>(grid)) return VolumeRegular::GetName();\n    if (dynamic_cast<const StretchedGrid *>(grid)) return VolumeRectilinear::GetName();\n    if (dynamic_cast<const StructuredGrid *>(grid)) return intel ? VolumeRegular::GetName() : VolumeCellTraversal::GetName();\n    if (dynamic_cast<const UnstructuredGrid *>(grid)) return VolumeOSPRay::GetName();\n    MyBase::SetErrMsg(\"Unsupported grid type: %s\", grid->GetType().c_str());\n    return \"\";\n}\n\nbool VolumeRenderer::_needToSetDefaultAlgorithm() const { return !((VolumeParams *)GetActiveParams())->GetAlgorithmWasManuallySetByUser(); }\n"
  },
  {
    "path": "lib/render/VolumeResampled.cpp",
    "content": "#include <vapor/VolumeResampled.h>\n#include <vector>\n#include <vapor/glutil.h>\n#include <glm/glm.hpp>\n\nusing std::vector;\n\nusing namespace VAPoR;\n\n// static VolumeAlgorithmRegistrar<VolumeResampled> registration;\n\nint VolumeResampled::LoadData(const Grid *grid)\n{\n    VolumeRegular::LoadData(grid);\n#define S 1\n    const vector<size_t> dims = grid->GetDimensions();\n    const size_t         w = dims[0] * S, h = dims[1] * S, d = dims[2] * S;\n    float *              data = new float[w * h * d];\n\n    vector<double> min, max;\n    grid->GetUserExtents(min, max);\n\n    for (int z = 0; z < d; z++) {\n        printf(\"Resampling... %i/%li\\n\", z, d);\n        const float zSamplePos = (z + 0.5f) / (float)d * (max[2] - min[2]) + min[2];\n        for (int y = 0; y < h; y++) {\n            const float ySamplePos = (y + 0.5f) / (float)h * (max[1] - min[1]) + min[1];\n            for (int x = 0; x < w; x++) {\n                const float xSamplePos = (x + 0.5f) / (float)w * (max[0] - min[0]) + min[0];\n                data[z * w * h + y * w + x] = grid->GetValue(xSamplePos, ySamplePos, zSamplePos);\n            }\n        }\n    }\n\n    _data.TexImage(GL_R32F, w, h, d, GL_RED, GL_FLOAT, data);\n\n    _hasMissingData = grid->HasMissingData();\n    if (_hasMissingData) {\n        printf(\"Loading missing data...\\n\");\n        const float    missingValue = grid->GetMissingValue();\n        unsigned char *missingMask = new unsigned char[w * h * d];\n        memset(missingMask, 0, w * h * d);\n\n        for (size_t i = 0; i < w * h * d; i++)\n            if (data[i] == missingValue) missingMask[i] = 255;\n\n        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n        _missing.TexImage(GL_R8, dims[0], dims[1], dims[2], GL_RED, GL_UNSIGNED_BYTE, missingMask);\n        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);\n\n        delete[] missingMask;\n    }\n\n    delete[] data;\n    return 0;\n}\n"
  },
  {
    "path": "lib/render/VolumeTest.cpp",
    "content": "#include <vapor/VolumeTest.h>\n#include <vector>\n#include <vapor/glutil.h>\n#include <vapor/GLManager.h>\n#include <glm/glm.hpp>\n\nusing std::vector;\n\nusing namespace VAPoR;\n\nstatic VolumeAlgorithmRegistrar<VolumeTest> registration;\n\nVolumeTest::VolumeTest(GLManager *gl) : VolumeRegular(gl)\n{\n    glGenTextures(1, &zCoordTexture);\n    glBindTexture(GL_TEXTURE_3D, zCoordTexture);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);\n\n    glGenTextures(1, &xyCoordTexture);\n    glBindTexture(GL_TEXTURE_2D, xyCoordTexture);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n}\n\nVolumeTest::~VolumeTest()\n{\n    if (zCoordTexture) glDeleteTextures(1, &zCoordTexture);\n    if (xyCoordTexture) glDeleteTextures(1, &xyCoordTexture);\n}\n\nint VolumeTest::LoadData(const Grid *grid)\n{\n    if (VolumeRegular::LoadData(grid) < 0) return -1;\n\n    vector<size_t> dims = grid->GetDimensions();\n    const int      w = dims[0], h = dims[1], d = dims[2];\n    vector<double> minExt, maxExt;\n    grid->GetUserExtents(minExt, maxExt);\n    const float minX = minExt[0];\n    const float minY = minExt[1];\n    const float minZ = minExt[2];\n    const float maxX = maxExt[0];\n    const float maxY = maxExt[1];\n    const float maxZ = maxExt[2];\n\n    // float *xy = new float[dims[0]*dims[1]];\n    float *data = new float[w * h * d * 3];\n    for (int i = 0; i < w * h * d * 3; i++) data[i] = -1;\n\n    // auto coord = grid->ConstCoordBegin(); // broken\n    // auto end = grid->ConstCoordEnd();\n\n    vector<size_t> indices = {0, 0, 0};\n    vector<double> coords;\n\n    for (int z = 0; z < d; z++) {\n        printf(\"%i/%i\\n\", z, d);\n        for (int y = 0; y < h; y++) {\n            for (int x = 0; x < w; x++) {\n                // data[coord] = x,y,z;\n\n                // float cx = (*coord)[0];\n                // float cy = (*coord)[1];\n                // float cz = (*coord)[2];\n                double dcx, dcy, dcz;\n                float  cx, cy, cz;\n                // grid->GetUserCoordinates(x, y, z, dcx, dcy, dcz);\n                // cx = dcx;\n                // cy = dcy;\n                // cz = dcz;\n                // printf(\"[%i, %i, %i] = %.2f\\t%.2f\\t%.2f\\n\", x, y, z, dcx, dcy, dcz);\n\n                indices[0] = x;\n                indices[1] = y;\n                indices[2] = z;\n                grid->GetUserCoordinates(indices, coords);\n                cx = coords[0];\n                cy = coords[1];\n                cz = coords[2];\n\n                int dx = (cx - minX) / (maxX - minX) * (w - 1);\n                int dy = (cy - minY) / (maxY - minY) * (h - 1);\n                int dz = (cz - minZ) / (maxZ - minZ) * (d - 1);\n\n                // VAssert(dx>=0 && dx<w);\n                // VAssert(dy>=0 && dy<h);\n                // VAssert(dz>=0 && dz<d);\n\n                data[3 * (dz * w * h + dy * w + dx)] = x / (float)w;\n                data[3 * (dz * w * h + dy * w + dx) + 1] = y / (float)h;\n                data[3 * (dz * w * h + dy * w + dx) + 2] = z / (float)d;\n                // printf(\"Set data[%i, %i, %i] = %i, %i, %i\\n\", dx, dy, dz, x,y,z);\n\n                // VAssert(coord != end);\n                // ++coord;\n            }\n        }\n    }\n\n    glBindTexture(GL_TEXTURE_3D, zCoordTexture);\n    glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F, dims[0], dims[1], dims[2], 0, GL_RGB, GL_FLOAT, data);\n\n    delete[] data;\n    return 0;\n}\n\nShaderProgram *VolumeTest::GetShader() const\n{\n    ShaderProgram *s = _glManager->shaderManager->GetShader(\"ray2\");\n    if (!s) return nullptr;\n    s->Bind();\n\n    glActiveTexture(GL_TEXTURE2);\n    glBindTexture(GL_TEXTURE_3D, zCoordTexture);\n\n    s->SetUniform(\"coordLUT\", 2);\n\n    return s;\n}\n"
  },
  {
    "path": "lib/render/VolumeTest2.cpp",
    "content": "#include <vapor/VolumeTest2.h>\n#include <vector>\n#include <vapor/glutil.h>\n#include <vapor/GLManager.h>\n#include <glm/glm.hpp>\n\nusing glm::ivec3;\nusing glm::vec3;\nusing std::vector;\n\nusing namespace VAPoR;\n\nstatic VolumeAlgorithmRegistrar<VolumeTest2> registration;\n\n#define FI_LEFT  0\n#define FI_RIGHT 1\n#define FI_UP    2\n#define FI_DOWN  3\n#define FI_FRONT 4\n#define FI_BACK  5\n\n#define F_LEFT  ivec3(-1, 0, 0)\n#define F_RIGHT ivec3(1, 0, 0)\n#define F_UP    ivec3(0, 0, 1)\n#define F_DOWN  ivec3(0, 0, -1)\n#define F_FRONT ivec3(0, -1, 0)\n#define F_BACK  ivec3(0, 1, 0)\n\nstatic ivec3 GetFaceFromFaceIndex(int i)\n{\n    if (i == FI_LEFT) return F_LEFT;\n    if (i == FI_RIGHT) return F_RIGHT;\n    if (i == FI_UP) return F_UP;\n    if (i == FI_DOWN) return F_DOWN;\n    if (i == FI_FRONT) return F_FRONT;\n    if (i == FI_BACK) return F_BACK;\n    VAssert(0);\n    return F_LEFT;\n}\n\nstatic int GetFaceIndexFromFace(const ivec3 face)\n{\n    if (face == F_LEFT) return FI_LEFT;\n    if (face == F_RIGHT) return FI_RIGHT;\n    if (face == F_UP) return FI_UP;\n    if (face == F_DOWN) return FI_DOWN;\n    if (face == F_FRONT) return FI_FRONT;\n    if (face == F_BACK) return FI_BACK;\n    VAssert(0);\n    return 0;\n}\n\nstatic void GetFaceCoordinateIndices(const ivec3 &cell, const ivec3 &face, ivec3 &i0, ivec3 &i1, ivec3 &i2, ivec3 &i3)\n{\n    // CCW\n    if (face == F_DOWN) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(0, 1, 0);\n        i2 = cell + ivec3(1, 1, 0);\n        i3 = cell + ivec3(1, 0, 0);\n    } else if (face == F_UP) {\n        i0 = cell + ivec3(0, 0, 1);\n        i1 = cell + ivec3(1, 0, 1);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(0, 1, 1);\n    } else if (face == F_LEFT) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(0, 0, 1);\n        i2 = cell + ivec3(0, 1, 1);\n        i3 = cell + ivec3(0, 1, 0);\n    } else if (face == F_RIGHT) {\n        i0 = cell + ivec3(1, 0, 0);\n        i1 = cell + ivec3(1, 1, 0);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(1, 0, 1);\n    } else if (face == F_FRONT) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(1, 0, 0);\n        i2 = cell + ivec3(1, 0, 1);\n        i3 = cell + ivec3(0, 0, 1);\n    } else if (face == F_BACK) {\n        i0 = cell + ivec3(0, 1, 0);\n        i1 = cell + ivec3(0, 1, 1);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(1, 1, 0);\n    }\n}\n\nstatic vec3 GetCoordAtIndex(const ivec3 &index, const vec3 *data, const ivec3 &dims)\n{\n    const int w = dims.x;\n    const int h = dims.y;\n    const int d = dims.z;\n    const int x = index.x;\n    const int y = index.y;\n    const int z = index.z;\n    VAssert(x >= 0 && x < w && y >= 0 && y < h && z >= 0 && z < d);\n    return data[(z * w * h + y * w + x)];\n}\n\nstatic void GetFaceVertices(const ivec3 &cellIndex, const ivec3 &face, const vec3 *data, const ivec3 &dims, vec3 &v0, vec3 &v1, vec3 &v2, vec3 &v3)\n{\n    ivec3 i0, i1, i2, i3;\n    GetFaceCoordinateIndices(cellIndex, face, i0, i1, i2, i3);\n    v0 = GetCoordAtIndex(i0, data, dims);\n    v1 = GetCoordAtIndex(i1, data, dims);\n    v2 = GetCoordAtIndex(i2, data, dims);\n    v3 = GetCoordAtIndex(i3, data, dims);\n}\n\nstatic void GetFaceVertices(const ivec3 &cellIndex, int face, const vec3 *data, const ivec3 &dims, vec3 &v0, vec3 &v1, vec3 &v2, vec3 &v3)\n{\n    GetFaceVertices(cellIndex, GetFaceFromFaceIndex(face), data, dims, v0, v1, v2, v3);\n}\n\nVolumeTest2::VolumeTest2(GLManager *gl) : VolumeRegular(gl)\n{\n    glGenTextures(1, &zCoordTexture);\n    glBindTexture(GL_TEXTURE_3D, zCoordTexture);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);\n\n    glGenTextures(1, &xyCoordTexture);\n    glBindTexture(GL_TEXTURE_2D, xyCoordTexture);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n}\n\nVolumeTest2::~VolumeTest2()\n{\n    if (zCoordTexture) glDeleteTextures(1, &zCoordTexture);\n    if (xyCoordTexture) glDeleteTextures(1, &xyCoordTexture);\n}\n\n#define EPSILON 1.19e-07\n\nstatic bool IsInsideCell(const vec3 &p, const ivec3 &cellIndex, const vec3 *coords, const ivec3 dims)\n{\n    for (int face = 0; face < 6; face++) {\n        vec3 v0, v1, v2, v3;\n        GetFaceVertices(cellIndex, face, coords, dims, v0, v1, v2, v3);\n        vec3 n = cross(v1 - v0, v2 - v0);\n        if (glm::length(n) < EPSILON) {\n            if (glm::dot(n, p - v0) > 0) return false;\n        }\n    }\n    return true;\n}\n\nint VolumeTest2::LoadData(const Grid *grid)\n{\n    if (VolumeRegular::LoadData(grid) < 0) return -1;\n\n    vector<size_t> dims = grid->GetDimensions();\n    const int      w = dims[0], h = dims[1], d = dims[2];\n    const size_t   nCoords = (size_t)w * h * d;\n    vector<double> minExt, maxExt;\n    grid->GetUserExtents(minExt, maxExt);\n    const float minX = minExt[0];\n    const float minY = minExt[1];\n    const float minZ = minExt[2];\n    const float maxX = maxExt[0];\n    const float maxY = maxExt[1];\n    const float maxZ = maxExt[2];\n\n    // float *xy = new float[dims[0]*dims[1]];\n    float *data = new float[w * h * d * 3];\n    for (int i = 0; i < w * h * d * 3; i++) data[i] = -1;\n\n    vec3 *coords = new vec3[nCoords];\n\n    auto coord = grid->ConstCoordBegin();\n    for (size_t i = 0; i < nCoords; ++i, ++coord) {\n        coords[i][0] = (*coord)[0];\n        coords[i][1] = (*coord)[1];\n        coords[i][2] = (*coord)[2];\n    }\n\n    for (int z = 0; z < d; z++) {\n        for (int y = 0; y < h; y++) {\n            for (int x = 0; x < w; x++) {}\n        }\n    }\n\n    glBindTexture(GL_TEXTURE_3D, zCoordTexture);\n    glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F, dims[0], dims[1], dims[2], 0, GL_RGB, GL_FLOAT, data);\n\n    delete[] data;\n    return 0;\n}\n\nShaderProgram *VolumeTest2::GetShader() const\n{\n    ShaderProgram *s = _glManager->shaderManager->GetShader(\"ray2\");\n    if (!s) return nullptr;\n    s->Bind();\n\n    glActiveTexture(GL_TEXTURE2);\n    glBindTexture(GL_TEXTURE_3D, zCoordTexture);\n\n    s->SetUniform(\"coordLUT\", 2);\n\n    return s;\n}\n"
  },
  {
    "path": "lib/render/WireFrameRenderer.cpp",
    "content": "//************************************************************************\n//                                                                       *\n//                          Copyright (C)  2018                          *\n//            University Corporation for Atmospheric Research            *\n//                          All Rights Reserved                          *\n//                                                                       *\n//************************************************************************/\n//\n//  File:   WireFrameRenderer.cpp\n//\n//  Author: John Clyne\n//          National Center for Atmospheric Research\n//          PO 3000, Boulder, Colorado\n//\n//  Date:   June 2018\n//\n//  Description:\n//          Implementation of WireFrameRenderer\n//\n\n#include <sstream>\n#include <string>\n#include <iterator>\n\n#include <vapor/glutil.h>    // Must be included first!!!\n\n#include <vapor/Renderer.h>\n#include <vapor/WireFrameParams.h>\n#include <vapor/WireFrameRenderer.h>\n#include <vapor/regionparams.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/DataStatus.h>\n#include <vapor/errorcodes.h>\n#include <vapor/ControlExecutive.h>\n#include \"vapor/GLManager.h\"\n#include \"vapor/debug.h\"\n#include <vapor/Progress.h>\n\nusing namespace VAPoR;\n\n#pragma pack(push, 4)\nstruct WireFrameRenderer::VertexData {\n    float x, y, z;\n    float v;\n    float missing;\n};\n#pragma pack(pop)\n\nstatic RendererRegistrar<WireFrameRenderer> registrar(WireFrameRenderer::GetClassType(), WireFrameParams::GetClassType());\n\nWireFrameRenderer::WireFrameRenderer(const ParamsMgr *pm, string winName, string dataSetName, string instName, DataMgr *dataMgr)\n: Renderer(pm, winName, dataSetName, WireFrameParams::GetClassType(), WireFrameRenderer::GetClassType(), instName, dataMgr), _VAO(0), _VBO(0), _EBO(0)\n{\n}\n\nWireFrameRenderer::~WireFrameRenderer()\n{\n    if (_VAO) glDeleteVertexArrays(1, &_VAO);\n    if (_VBO) glDeleteBuffers(1, &_VBO);\n    if (_EBO) glDeleteBuffers(1, &_EBO);\n    _VAO = _VBO = _EBO = 0;\n}\n\nvoid WireFrameRenderer::_saveCacheParams()\n{\n    WireFrameParams *p = (WireFrameParams *)GetActiveParams();\n    _cacheParams.varName = p->GetVariableName();\n    _cacheParams.heightVarName = p->GetHeightVariableName();\n    _cacheParams.ts = p->GetCurrentTimestep();\n    _cacheParams.level = p->GetRefinementLevel();\n    _cacheParams.lod = p->GetCompressionLevel();\n    p->GetBox()->GetExtents(_cacheParams.boxMin, _cacheParams.boxMax);\n}\n\nbool WireFrameRenderer::_isCacheDirty() const\n{\n    WireFrameParams *p = (WireFrameParams *)GetActiveParams();\n    if (_cacheParams.varName != p->GetVariableName()) return true;\n    if (_cacheParams.heightVarName != p->GetHeightVariableName()) return true;\n    if (_cacheParams.ts != p->GetCurrentTimestep()) return true;\n    if (_cacheParams.level != p->GetRefinementLevel()) return true;\n    if (_cacheParams.lod != p->GetCompressionLevel()) return true;\n\n    vector<double> min, max;\n    p->GetBox()->GetExtents(min, max);\n\n    if (_cacheParams.boxMin != min) return true;\n    if (_cacheParams.boxMax != max) return true;\n\n    return false;\n}\n\n//\n// Generate wireframe line drawing list of line segments for a single\n// cell. Make use of drawList to avoid drawing line segments shared\n// by multiple cells\n//\nvoid WireFrameRenderer::_drawCell(const GLuint *cellNodeIndices, int n, bool layered, const vector<GLuint> &nodeMap, GLuint invalidIndex, vector<unsigned int> &indices, DrawList &drawList) const\n{\n    int count = layered ? n / 2 : n;\n    for (int i = 0; i < count; i++) {\n        GLuint idx0 = nodeMap[cellNodeIndices[i]];\n        VAssert(idx0 != invalidIndex);\n\n        GLuint idx1 = nodeMap[cellNodeIndices[(i + 1) % count]];\n        VAssert(idx1 != invalidIndex);\n\n        // Don't draw line segment if it's already been drawn\n        //\n        if (drawList.InList(idx0, idx1)) continue;\n\n        indices.push_back(idx0);\n        indices.push_back(idx1);\n    }\n\n    if (!layered) return;\n\n    // if layered the coordinates are ordered bottom face first, then top face\n    //\n    for (int i = 0; i < count; i++) {\n        GLuint idx0 = nodeMap[cellNodeIndices[i + count]];\n        VAssert(idx0 != invalidIndex);\n\n        GLuint idx1 = nodeMap[cellNodeIndices[((i + 1) % count) + count]];\n        VAssert(idx1 != invalidIndex);\n\n        if (drawList.InList(idx0, idx1)) continue;\n\n        indices.push_back(idx0);\n        indices.push_back(idx1);\n    }\n\n    // Now draw edges between top and bottom face\n    //\n    for (int i = 0; i < count; i++) {\n        GLuint idx0 = nodeMap[cellNodeIndices[i]];\n        VAssert(idx0 != invalidIndex);\n\n        GLuint idx1 = nodeMap[cellNodeIndices[i + count]];\n        VAssert(idx1 != invalidIndex);\n\n        if (drawList.InList(idx0, idx1)) continue;\n\n        indices.push_back(idx0);\n        indices.push_back(idx1);\n    }\n}\n\n// Generate list of vertices shared by all line segments, and populate\n// 'nodeMap': a map from a node's Grid index to its offset in the\n// list of vertices.\n//\nvoid WireFrameRenderer::_buildCacheVertices(const Grid *grid, const Grid *heightGrid, vector<GLuint> &nodeMap, bool *GPUOutOfMemory) const\n{\n    double mv = grid->GetMissingValue();\n    auto   tmp = grid->GetDimensions();\n    auto   dims = std::vector<size_t>{tmp[0], tmp[1], tmp[2]};\n    size_t numNodes = Wasp::VProduct(dims);\n\n    // Pre-allocate vertices vector upfront for better performance\n    //\n    vector<VertexData> vertices;\n    vertices.reserve(numNodes);\n\n    // Visit each grid node. For each node store node's coordinates and\n    // assigned color in 'vertices'. Create 'nodeMap': mapping from a\n    // grid node's index to its offset in 'vertices'\n    //\n    Grid::ConstNodeIterator nodeItr = grid->ConstNodeBegin();\n    Grid::ConstNodeIterator nodeEnd = grid->ConstNodeEnd();\n    Grid::ConstCoordItr     coordItr = grid->ConstCoordBegin();\n    Grid::ConstCoordItr     coordEnd = grid->ConstCoordEnd();\n    Progress::Start(\"Load Grid\", numNodes);\n    long done = 0;\n    for (; nodeItr != nodeEnd; ++nodeItr, ++coordItr, ++done) {\n        Progress::Update(done);\n\n        // Get current node's coordinates\n        //\n        double coord[3];\n        coord[0] = (*coordItr)[0];\n        coord[1] = (*coordItr)[1];\n\n        if (grid->GetGeometryDim() > 2) {\n            coord[2] = (*coordItr)[2];\n        } else {\n            double z;\n            if (heightGrid) {\n                z = heightGrid->GetValueAtIndex(*nodeItr);\n            } else {\n                z = 0;\n            }\n            coord[2] = z;\n        }\n\n        float dataValue = grid->GetValueAtIndex(*nodeItr);\n\n        // Create an entry in nodeMap\n        //\n        size_t index = Wasp::LinearizeCoords((*nodeItr).data(), dims.data(), dims.size());\n\n        if (vertices.size() > std::numeric_limits<GLuint>::max()) {\n#ifndef NDEBUG\n            MyBase::SetDiagMsg(\"WireFrameRenderer() : exceeded numeric limits\");\n#endif\n            continue;\n        }\n        nodeMap[index] = vertices.size();\n\n        vertices.push_back({(float)coord[0], (float)coord[1], (float)coord[2], dataValue, mv == dataValue ? 1.f : 0.f});\n    }\n\n    glBindVertexArray(_VAO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_DYNAMIC_DRAW);\n\n    GLenum err;\n    while ((err = glGetError()) != GL_NO_ERROR)\n        if (err == GL_OUT_OF_MEMORY) *GPUOutOfMemory = true;\n}\n\n//\n// Generate connectivity list for line segments joining cell nodes.\n//\nsize_t WireFrameRenderer::_buildCacheConnectivity(const Grid *grid, const vector<GLuint> &nodeMap, bool *GPUOutOfMemory) const\n{\n    auto             tmp = grid->GetDimensions();\n    auto             dims = std::vector<size_t>{tmp[0], tmp[1], tmp[2]};\n    size_t           invalidIndex = std::numeric_limits<size_t>::max();\n    size_t           numNodes = Wasp::VProduct(dims);\n    bool             layered = grid->GetTopologyDim() == 3;\n    size_t           maxVertsPerCell = grid->GetMaxVertexPerCell();\n    vector<DimsType> cellNodeIndices(maxVertsPerCell);\n    vector<GLuint>   cellNodeIndicesLinear(maxVertsPerCell);\n\n    size_t numCells = Wasp::VProduct(grid->GetCellDimensions().data(), grid->GetNumCellDimensions());\n    size_t maxLineIndices = numCells * (layered ? maxVertsPerCell / 2 * 3 : maxVertsPerCell * 2);\n\n    // Pre-allocate memory for (much) better performance.\n    //\n    vector<unsigned int> indices;\n    indices.reserve(maxLineIndices);\n\n    {\n        // drawList keeps track of line segments that have already been\n        // drawn so that we can avoid duplicates. Avoiding duplicates\n        // reduces the memory requirements substantially\n        //\n        DrawList drawList(numNodes, 10);\n\n        // Loop over cells, drawing edges of each cell\n        //\n        Grid::ConstCellIterator cellItr = grid->ConstCellBegin();\n        Grid::ConstCellIterator cellEnd = grid->ConstCellEnd();\n        Progress::Start(\"Generate Connectivity\", numCells, true);\n        for (int done = 0; cellItr != cellEnd; ++cellItr, ++done) {\n            Progress::Update(done);\n            if (Progress::Cancelled()) return 0;\n\n            grid->GetCellNodes((*cellItr).data(), cellNodeIndices);\n\n            for (int i = 0; i < cellNodeIndices.size(); i++) {\n                int    ndim = grid->GetDimensions().size();\n                size_t idx = Wasp::LinearizeCoords(cellNodeIndices[i].data(), grid->GetDimensions().data(), ndim);\n\n                if (idx > std::numeric_limits<GLuint>::max()) {\n#ifndef NDEBUG\n                    MyBase::SetDiagMsg(\"WireFrameRenderer() : exceeded numeric limits\");\n#endif\n                    continue;\n                }\n                cellNodeIndicesLinear[i] = idx;\n            }\n\n            _drawCell(cellNodeIndicesLinear.data(), cellNodeIndices.size(), layered, nodeMap, invalidIndex, indices, drawList);\n        }\n    }\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO);\n    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_DYNAMIC_DRAW);\n    glBindVertexArray(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    GLenum err;\n    while ((err = glGetError()) != GL_NO_ERROR) {\n        if (err == GL_OUT_OF_MEMORY) *GPUOutOfMemory = true;\n    }\n\n    return (indices.size());\n}\n\nint WireFrameRenderer::_buildCache()\n{\n    WireFrameParams *rParams = (WireFrameParams *)GetActiveParams();\n    _saveCacheParams();\n\n    if (rParams->GetVariableName().empty()) { return 0; }\n\n    CoordType boxMin = {0.0, 0.0, 0.0};\n    CoordType boxMax = {0.0, 0.0, 0.0};\n    Grid::CopyToArr3(_cacheParams.boxMin, boxMin);\n    Grid::CopyToArr3(_cacheParams.boxMax, boxMax);\n\n    Grid *grid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.varName, _cacheParams.level, _cacheParams.lod, boxMin, boxMax);\n    if (!grid) return (-1);\n\n    Grid *heightGrid = NULL;\n    if (!_cacheParams.heightVarName.empty()) {\n        heightGrid = _dataMgr->GetVariable(_cacheParams.ts, _cacheParams.heightVarName, _cacheParams.level, _cacheParams.lod, boxMin, boxMax);\n        if (!heightGrid) {\n            delete grid;\n            return (-1);\n        }\n    }\n\n    auto           tmp = grid->GetDimensions();\n    auto           dims = std::vector<size_t>{tmp[0], tmp[1], tmp[2]};\n    size_t         numNodes = Wasp::VProduct(dims);\n    GLuint         invalidIndex = std::numeric_limits<GLuint>::max();\n    vector<GLuint> nodeMap(numNodes, invalidIndex);\n    _GPUOutOfMemory = false;\n\n    _buildCacheVertices(grid, heightGrid, nodeMap, &_GPUOutOfMemory);\n\n    _nIndices = _buildCacheConnectivity(grid, nodeMap, &_GPUOutOfMemory);\n\n    if (grid) delete grid;\n    if (heightGrid) delete heightGrid;\n\n    Progress::Finish();\n    return 0;\n}\n\nint WireFrameRenderer::_paintGL(bool fast)\n{\n    int rc = 0;\n    if (_isCacheDirty()) { rc = _buildCache(); }\n    if (rc != 0) return rc;\n\n    if (Progress::Cancelled()) {\n        _cacheParams.varName = \"\";\n        return 0;\n    }\n\n    if (_GPUOutOfMemory) {\n        SetErrMsg(\"GPU out of memory\");\n        return -1;\n    }\n\n    RenderParams *  rp = GetActiveParams();\n    MapperFunction *tf = rp->GetMapperFunc(rp->GetVariableName());\n    if (!tf) return -1;\n    float           lut[4 * 256];\n    tf->makeLut(lut);\n    if (rp->UseSingleColor()) {\n        float c[3];\n        rp->GetConstantColor(c);\n        for (int i = 0; i < 256; i++) {\n            lut[i * 4 + 0] = c[0];\n            lut[i * 4 + 1] = c[1];\n            lut[i * 4 + 2] = c[2];\n        }\n    }\n    _lutTexture.TexImage(GL_RGBA8, 256, 0, 0, GL_RGBA, GL_FLOAT, lut);\n    \n    if (rp->GetRenderDim() == 2) {\n        float zOffset = GetDefaultZ(_dataMgr, GetActiveParams()->GetCurrentTimestep());\n        _glManager->matrixManager->Translate(0, 0, zOffset);\n    }\n\n    SmartShaderProgram shader = _glManager->shaderManager->GetSmartShader(\"Wireframe\");\n    if (!shader.IsValid()) return -1;\n\n    EnableClipToBox(_glManager->shaderManager->GetShader(\"Wireframe\"));\n    shader->SetUniform(\"MVP\", _glManager->matrixManager->GetModelViewProjectionMatrix());\n    shader->SetUniform(\"minLUTValue\", tf->getMinMapValue());\n    shader->SetUniform(\"maxLUTValue\", tf->getMaxMapValue());\n    shader->SetSampler(\"colormap\", _lutTexture);\n    glBindVertexArray(_VAO);\n\n    glEnable(GL_DEPTH_TEST);\n    glDepthMask(GL_TRUE);\n\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _EBO);\n    glDrawElements(GL_LINES, _nIndices, GL_UNSIGNED_INT, 0);\n\n    DisableClippingPlanes();\n    glBindVertexArray(0);\n\n    return rc;\n}\n\nint WireFrameRenderer::_initializeGL()\n{\n    glGenVertexArrays(1, &_VAO);\n    glBindVertexArray(_VAO);\n    glGenBuffers(1, &_VBO);\n    glGenBuffers(1, &_EBO);\n    glBindBuffer(GL_ARRAY_BUFFER, _VBO);\n    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), NULL);\n    glEnableVertexAttribArray(0);\n    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, v));\n    glEnableVertexAttribArray(1);\n    glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void *)offsetof(struct VertexData, missing));\n    glEnableVertexAttribArray(2);\n    glBindVertexArray(0);\n\n    _lutTexture.Generate();\n\n    return 0;\n}\n"
  },
  {
    "path": "lib/render/glutil.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2004\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tglutil.cpp\n//\n//\tAdaptor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJuly 2004\n//\n//\tDescription:  Methods to facilitate use of trackball navigation,\n//\t\tadapted from Ken Purcell's code to work in QT window\n//\n// Copyright (C) 1992  AHPCRC, Univeristy of Minnesota\n//\n// This program is free software; you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation; either version 2 of the License, or\n// (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program in a file named 'Copying'; if not, write to\n// the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139.\n//\n\n// Original Author:\n//\tKen Chin-Purcell (ken@ahpcrc.umn.edu)\n//\tArmy High Performance Computing Research Center (AHPCRC)\n//\tUniveristy of Minnesota\n//\n\n#include \"vapor/VAssert.h\"\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <vector>\n#include <cmath>\n#include <iostream>\n#include <cfloat>\n#include <vapor/MyBase.h>\n#include <vapor/errorcodes.h>\n#include <vapor/glutil.h>\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n\n/* Most of the 'v' routines are in the form vsomething(src1, src2, dst),\n * dst can be one of the source vectors.\n */\nnamespace VAPoR {\n\nbool oglStatusOK(vector<int> &status)\n{\n    GLenum glErr;\n\n    while ((glErr = glGetError()) != GL_NO_ERROR) { status.push_back((int)glErr); }\n    if (status.size()) return (false);\n\n    return (true);\n}\n\nstatic const char *_glErrorStr(int err)\n{\n    switch (err) {\n#define ERR_TO_STR(E) case E: return #E\n        ERR_TO_STR(GL_NO_ERROR);\n        ERR_TO_STR(GL_INVALID_ENUM);\n        ERR_TO_STR(GL_INVALID_VALUE);\n        ERR_TO_STR(GL_INVALID_OPERATION);\n        ERR_TO_STR(GL_INVALID_FRAMEBUFFER_OPERATION);\n        ERR_TO_STR(GL_OUT_OF_MEMORY);\n//        ERR_TO_STR(GL_STACK_UNDERFLOW);\n//        ERR_TO_STR(GL_STACK_OVERFLOW);\n    default: return \"GL_UNKNOWN_ERROR\";\n    }\n}\n\nstring oglGetErrMsg(vector<int> status)\n{\n    string msg;\n    for (auto e : status) {\n        msg += \"OpenGL Error: \";\n        msg += _glErrorStr(e);\n        msg += \" (#\" + std::to_string(e) + \")\\n\";\n    }\n    return msg;\n}\n\nint oglGetFreeMemory()\n{\n#define TEXTURE_FREE_MEMORY_ATI 0x87FC\n#define GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX 0x9049\n    GLint buf[4];\n    vector<int> _;\n\n#if AMD_MEM_QUERY_ENABLED\n    // On some systems returns incorrect values\n    memset(buf, 0, sizeof(buf));\n    glGetIntegerv(TEXTURE_FREE_MEMORY_ATI, buf);\n    if (buf[0] > 0)\n        return buf[0];\n\n    oglStatusOK(_);\n#endif\n\n    memset(buf, 0, sizeof(buf));\n    glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, buf);\n    if (buf[0] > 0)\n        return buf[0];\n\n    oglStatusOK(_);\n\n    return -1;\n}\n\nint __CheckGLError(const char *file, int line, const char *msg)\n{\n    //\n    // Returns -1 if an OpenGL error occurred, 0 otherwise.\n    //\n    GLenum glErr;\n    int    retCode = 0;\n\n    glErr = glGetError();\n\n    while (glErr != GL_NO_ERROR) {\n#ifndef NDEBUG\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\n//        std::cout << \"glError: \" << gluErrorString(glErr) << std::endl << \"         \" << file << \" : \" << line << std::endl;\n    #pragma GCC diagnostic pop\n#endif\n        if (msg) {\n            Wasp::MyBase::SetErrMsg(\"glError: %s\\n\", msg);\n            msg = NULL;\n        }\n        Wasp::MyBase::SetErrMsg(\"glError: %i\\n\\t%s : %d\", glErr, file, line);\n\n        retCode = -1;\n\n        glErr = glGetError();\n    }\n\n    return retCode;\n}\n\nbool FrameBufferReady()\n{\n    GLuint fbstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);\n    if (fbstatus != GL_FRAMEBUFFER_COMPLETE) { return (false); }\n\n    // Not sure if this is necessary\n    //\n    vector<int> errcodes;\n    bool        status = oglStatusOK(errcodes);\n\n    if (status) return true;\n\n    // If error, check for invalid frame buffer\n    //\n    for (int i = 0; i < errcodes.size(); i++) {\n        if (errcodes[i] == GL_INVALID_FRAMEBUFFER_OPERATION) return false;\n    }\n\n    return (true);\n}\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/render/jfilewrite.cpp",
    "content": "/*\n * example.c\n *\n * This file illustrates how to use the IJG code as a subroutine library\n * to read or write JPEG image files.  You should look at this code in\n * conjunction with the documentation file libjpeg.doc.\n *\n * This code will not do anything useful as-is, but it may be helpful as a\n * skeleton for constructing routines that call the JPEG library.\n *\n * We present these routines in the same coding style used in the JPEG code\n * (ANSI function definitions, etc); but you are of course free to code your\n * routines in a different style if you prefer.\n */\n\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n/*\n * Include file for users of JPEG library.\n * You will need to have included system headers that define at least\n * the typedefs FILE and size_t before you can include jpeglib.h.\n * (stdio.h is sufficient on ANSI-conforming systems.)\n * You may also wish to include \"jerror.h\".\n */\n\n#ifdef WIN32\n    #include <jpeg/jpeglib.h>\n#else\n    #include <jpeglib.h>\n#endif\n#include <vapor/jpegapi.h>\n\n/*\n * <setjmp.h> is used for the optional error recovery mechanism shown in\n * the second part of the example.\n */\n\n#include <setjmp.h>\n\n#ifdef WIN32\n    #pragma warning(disable : 4996)\n#endif\n\n/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/\n\n/* This half of the example shows how to feed data into the JPEG compressor.\n * We present a minimal version that does not worry about refinements such\n * as error recovery (the JPEG code will just exit() if it gets an error).\n */\n\n/*\n * IMAGE DATA FORMATS:\n *\n * The standard input image format is a rectangular array of pixels, with\n * each pixel having the same number of \"component\" values (color channels).\n * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars).\n * If you are working with color data, then the color values for each pixel\n * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit\n * RGB color.\n *\n * For this example, we'll assume that this data structure matches the way\n * our application has stored the image in memory, so we can just pass a\n * pointer to our image buffer.  In particular, let's say that the image is\n * RGB color and is described by:\n */\n/*\n * ERROR HANDLING:\n *\n * The JPEG library's standard error handler (jerror.c) is divided into\n * several \"methods\" which you can override individually.  This lets you\n * adjust the behavior without duplicating a lot of code, which you might\n * have to update with each future release.\n *\n * Our example here shows how to override the \"error_exit\" method so that\n * control is returned to the library's caller when a fatal error occurs,\n * rather than calling exit() as the standard error_exit method does.\n *\n * We use C's setjmp/longjmp facility to return control.  This means that the\n * routine which calls the JPEG library must first execute a setjmp() call to\n * establish the return point.  We want the replacement error_exit to do a\n * longjmp().  But we need to make the setjmp buffer accessible to the\n * error_exit routine.  To do this, we make a private extension of the\n * standard JPEG error handler object.  (If we were using C++, we'd say we\n * were making a subclass of the regular error handler.)\n *\n * Here's the extended error handler struct:\n */\n\nstruct my_error_mgr {\n    struct jpeg_error_mgr pub; /* \"public\" fields */\n\n    jmp_buf setjmp_buffer; /* for return to caller */\n};\n\ntypedef struct my_error_mgr *my_error_ptr;\n\n/*\n * Here's the routine that will replace the standard error_exit method:\n */\n\nnamespace {\n\nMETHODDEF(void)\nmy_error_exit(j_common_ptr cinfo)\n{\n    /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */\n    my_error_ptr myerr = (my_error_ptr)cinfo->err;\n\n    /* Always display the message. */\n    /* We could postpone this until after returning, if we chose. */\n    (*cinfo->err->output_message)(cinfo);\n\n    /* Return control to the setjmp point */\n    longjmp(myerr->setjmp_buffer, 1);\n}\n\n/* method to resample rgb image to smaller image,\n    needed to handle OpenGL power-of-two limitations.\n    */\n\nvoid resampleImage(unsigned char *image1, int xin, int yin, unsigned char *image2, int xout, int yout)\n{\n    /*Simplest approach:  Just sample one pixel for each:*/\n    int i, j, k;\n    for (j = 0; j < yout; j++) {\n        float ycrd = (float)j / (float)(yout - 1);    // Normalize to 0..1\n        int   ysample = (int)(ycrd * (float)(yin - 1) + 0.5f);\n        for (i = 0; i < xout; i++) {\n            float xcrd = (float)i / (float)(xout - 1);    // Normalize to 0..1\n            int   xsample = (int)(xcrd * (float)(xin - 1) + 0.5f);\n            for (k = 0; k < 3; k++) { image2[k + 3 * (i + xout * j)] = image1[k + 3 * (xsample + ysample * xin)]; }\n        }\n    }\n}\n\n/*\n * Sample routine for JPEG compression.  We assume that the target file\n * and a compression quality factor are passed in.\n * Returns 0 if OK, 1 for file I/O errors, 2 for other errors\n */\n\n};    // namespace\n\nint VAPoR::write_JPEG_file(FILE *outfile, int image_width, int image_height, unsigned char *image_buffer, int quality)\n{\n    /* This struct contains the JPEG compression parameters and pointers to\n     * working space (which is allocated as needed by the JPEG library).\n     * It is possible to have several such structures, representing multiple\n     * compression/decompression processes, in existence at once.  We refer\n     * to any one struct (and its associated working data) as a \"JPEG object\".\n     */\n    struct jpeg_compress_struct cinfo;\n    /* This struct represents a JPEG error handler.  It is declared separately\n     * because applications often want to supply a specialized error handler\n     * (see the second half of this file for an example).  But here we just\n     * take the easy way out and use the standard error handler, which will\n     * print a message on stderr and call exit() if compression fails.\n     * Note that this struct must live as long as the main JPEG parameter\n     * struct, to avoid dangling-pointer problems.\n     */\n    // struct jpeg_error_mgr jerr;\n    struct my_error_mgr jerr;\n    /* More stuff */\n    JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */\n    int      row_stride;     /* physical row width in image buffer */\n\n    /* Step 1: allocate and initialize JPEG compression object */\n\n    /* We have to set up the error handler first, in case the initialization\n     * step fails.  (Unlikely, but it could happen if you are out of memory.)\n     * This routine fills in the contents of struct jerr, and returns jerr's\n     * address which we place into the link field in cinfo.\n     */\n    // cinfo.err = jpeg_std_error(&jerr);\n    /* We set up the normal JPEG error routines, then override error_exit. */\n    cinfo.err = jpeg_std_error(&jerr.pub);\n    jerr.pub.error_exit = my_error_exit;\n    /* Establish the setjmp return context for my_error_exit to use. */\n    if (setjmp(jerr.setjmp_buffer)) {\n        /* If we get here, the JPEG code has signaled an error.\n         * We need to clean up the JPEG object, close the input file, and return.\n         */\n        jpeg_destroy_compress(&cinfo);\n        /*\n         * !!WRONG!! You should NOT close a file that does not belong to you!!\n         */\n        // fclose(outfile);\n        return 1;\n    }\n    /* Now we can initialize the JPEG compression object. */\n    jpeg_create_compress(&cinfo);\n\n    /* Step 2: specify data destination (eg, a file) */\n    /* Note: steps 2 and 3 can be done in either order. */\n\n    /* Here we use the library-supplied code to send compressed data to a\n     * stdio stream.  You can also write your own code to do something else.\n     * VERY IMPORTANT: use \"b\" option to fopen() if you are on a machine that\n     * requires it in order to write binary files.\n     */\n\n    jpeg_stdio_dest(&cinfo, outfile);\n\n    /* Step 3: set parameters for compression */\n\n    /* First we supply a description of the input image.\n     * Four fields of the cinfo struct must be filled in:\n     */\n    cinfo.image_width = image_width; /* image width and height, in pixels */\n    cinfo.image_height = image_height;\n    cinfo.input_components = 3;     /* # of color components per pixel */\n    cinfo.in_color_space = JCS_RGB; /* colorspace of input image */\n    /* Now use the library's routine to set default compression parameters.\n     * (You must set at least cinfo.in_color_space before calling this,\n     * since the defaults depend on the source color space.)\n     */\n    jpeg_set_defaults(&cinfo);\n    /* Now you can set any non-default parameters you wish to.\n     * Here we just illustrate the use of quality (quantization table) scaling:\n     */\n    jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);\n\n    /* Step 4: Start compressor */\n\n    /* TRUE ensures that we will write a complete interchange-JPEG file.\n     * Pass TRUE unless you are very sure of what you're doing.\n     */\n    jpeg_start_compress(&cinfo, TRUE);\n\n    /* Step 5: while (scan lines remain to be written) */\n    /*           jpeg_write_scanlines(...); */\n\n    /* Here we use the library's state variable cinfo.next_scanline as the\n     * loop counter, so that we don't have to keep track ourselves.\n     * To keep things simple, we pass one scanline per call; you can pass\n     * more if you wish, though.\n     */\n    row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */\n\n    while (cinfo.next_scanline < cinfo.image_height) {\n        /* jpeg_write_scanlines expects an array of pointers to scanlines.\n         * Here the array is only one element long, but you could pass\n         * more than one scanline at a time if that's more convenient.\n         */\n        row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];\n        (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);\n    }\n\n    /* Step 6: Finish compression */\n\n    jpeg_finish_compress(&cinfo);\n    /* After finish_compress, we can close the output file. */\n    /*\n     * !!WRONG!! You should NOT close a file that does not belong to you!!\n     */\n    // fclose(outfile);\n\n    /* Step 7: release JPEG compression object */\n\n    /* This is an important step since it will release a good deal of memory. */\n    jpeg_destroy_compress(&cinfo);\n\n    /* And we're done! */\n    return 0;\n}\n\n/*\n * SOME FINE POINTS:\n *\n * In the above loop, we ignored the return value of jpeg_write_scanlines,\n * which is the number of scanlines actually written.  We could get away\n * with this because we were only relying on the value of cinfo.next_scanline,\n * which will be incremented correctly.  If you maintain additional loop\n * variables then you should be careful to increment them properly.\n * Actually, for output to a stdio stream you needn't worry, because\n * then jpeg_write_scanlines will write all the lines passed (or else exit\n * with a fatal error).  Partial writes can only occur if you use a data\n * destination module that can demand suspension of the compressor.\n * (If you don't know what that's for, you don't need it.)\n *\n * If the compressor requires full-image buffers (for entropy-coding\n * optimization or a multi-scan JPEG file), it will create temporary\n * files for anything that doesn't fit within the maximum-memory setting.\n * (Note that temp files are NOT needed if you use the default parameters.)\n * On some systems you may need to set up a signal handler to ensure that\n * temporary files are deleted if the program is interrupted.  See libjpeg.doc.\n *\n * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG\n * files to be compatible with everyone else's.  If you cannot readily read\n * your data in that order, you'll need an intermediate array to hold the\n * image.  See rdtarga.c or rdbmp.c for examples of handling bottom-to-top\n * source data using the JPEG code's internal virtual-array mechanisms.\n */\n\n/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/\n\n/* This half of the example shows how to read data from the JPEG decompressor.\n * It's a bit more refined than the above, in that we show:\n *   (a) how to modify the JPEG library's standard error-reporting behavior;\n *   (b) how to allocate workspace using the library's memory manager.\n *\n * Just to make this example a little different from the first one, we'll\n * assume that we do not intend to put the whole image into an in-memory\n * buffer, but to send it line-by-line someplace else.  We need a one-\n * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG\n * memory manager allocate it for us.  This approach is actually quite useful\n * because we don't need to remember to deallocate the buffer separately: it\n * will go away automatically when the JPEG object is cleaned up.\n */\n\n// JPEG_GLOBAL(void) free_image (unsigned char* image){\n//\tfree(image);\n//}\n/*\n * Sample routine for JPEG decompression.  We assume that the source file name\n * is passed in.  We want to return 1 on success, 0 on error.\n */\n\nint VAPoR::read_JPEG_file(const char *filename, unsigned char **imageBuffer, int *width, int *height)\n{\n    /* This struct contains the JPEG decompression parameters and pointers to\n     * working space (which is allocated as needed by the JPEG library).\n     */\n    struct jpeg_decompress_struct cinfo;\n    /* We use our private extension JPEG error handler.\n     * Note that this struct must live as long as the main JPEG parameter\n     * struct, to avoid dangling-pointer problems.\n     */\n    struct my_error_mgr jerr;\n    /* More stuff */\n    FILE *         infile;           /* source file */\n    JSAMPARRAY     buffer;           /* Output row buffer */\n    int            row_stride;       /* physical row width in output buffer */\n    int            newXDim, newYDim; /* dimensions for resampling*/\n    int            k, testval;\n    unsigned char *firstImage;\n\n    /* In this example we want to open the input file before doing anything else,\n     * so that the setjmp() error recovery below can assume the file is open.\n     * VERY IMPORTANT: use \"b\" option to fopen() if you are on a machine that\n     * requires it in order to read binary files.\n     */\n\n    if ((infile = fopen(filename, \"rb\")) == NULL) {\n        fprintf(stderr, \"can't open %s\\n\", filename);\n        return 0;\n    }\n\n    /* Step 1: allocate and initialize JPEG decompression object */\n\n    /* We set up the normal JPEG error routines, then override error_exit. */\n    cinfo.err = jpeg_std_error(&jerr.pub);\n    jerr.pub.error_exit = my_error_exit;\n    /* Establish the setjmp return context for my_error_exit to use. */\n    if (setjmp(jerr.setjmp_buffer)) {\n        /* If we get here, the JPEG code has signaled an error.\n         * We need to clean up the JPEG object, close the input file, and return.\n         */\n        jpeg_destroy_decompress(&cinfo);\n        fclose(infile);\n        return 0;\n    }\n    /* Now we can initialize the JPEG decompression object. */\n    jpeg_create_decompress(&cinfo);\n\n    /* Step 2: specify data source (eg, a file) */\n\n    jpeg_stdio_src(&cinfo, infile);\n\n    /* Step 3: read file parameters with jpeg_read_header() */\n\n    (void)jpeg_read_header(&cinfo, TRUE);\n    /* We can ignore the return value from jpeg_read_header since\n     *   (a) suspension is not possible with the stdio data source, and\n     *   (b) we passed TRUE to reject a tables-only JPEG file as an error.\n     * See libjpeg.doc for more info.\n     */\n\n    /* Step 4: set parameters for decompression */\n\n    /* In this example, we don't need to change any of the defaults set by\n     * jpeg_read_header(), so we do nothing here.\n     */\n\n    /* Step 5: Start decompressor */\n\n    (void)jpeg_start_decompress(&cinfo);\n    /* We can ignore the return value since suspension is not possible\n     * with the stdio data source.\n     */\n\n    /* We may need to do some setup of our own at this point before reading\n     * the data.  After jpeg_start_decompress() we have the correct scaled\n     * output image dimensions available, as well as the output colormap\n     * if we asked for color quantization.\n     * In this example, we need to make an output work buffer of the right size.\n     */\n    /* JSAMPLEs per row in output buffer */\n    row_stride = cinfo.output_width * cinfo.output_components;\n    /* Make a one-row-high sample array that will go away when done with image */\n    buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);\n\n    firstImage = (unsigned char *)malloc((size_t)(row_stride * cinfo.output_height));\n\n    /* Step 6: while (scan lines remain to be read) */\n    /*           jpeg_read_scanlines(...); */\n\n    /* Here we use the library's state variable cinfo.output_scanline as the\n     * loop counter, so that we don't have to keep track ourselves.\n     */\n    while (cinfo.output_scanline < cinfo.output_height) {\n        /* jpeg_read_scanlines expects an array of pointers to scanlines.\n         * Here the array is only one element long, but you could ask for\n         * more than one scanline at a time if that's more convenient.\n         */\n        (void)jpeg_read_scanlines(&cinfo, buffer, 1);\n        /* Assume put_scanline_someplace wants a pointer and sample count. */\n        /* actually put the scanline in the image in reverse order, so that openGL will\n    scan it in the correct order*/\n        memcpy((void *)(firstImage + (cinfo.output_height - cinfo.output_scanline) * (cinfo.output_width) * 3), buffer[0], (size_t)cinfo.output_width * 3);\n        // put_scanline_someplace(buffer[0], row_stride);\n    }\n    // Find first power of two no greater than image dimensions:\n    newXDim = cinfo.output_width;\n    newYDim = cinfo.output_height;\n    for (k = 0; k < 30; k++) {\n        testval = newXDim >> k;\n        if (testval == 0) {\n            newXDim = (newXDim >> (k - 1)) << (k - 1);\n            break;\n        }\n    }\n    for (k = 0; k < 30; k++) {\n        testval = newYDim >> k;\n        if (testval == 0) {\n            newYDim = (newYDim >> (k - 1)) << (k - 1);\n            break;\n        }\n    }\n\n    *width = newXDim;\n    *height = newYDim;\n    if (newXDim == cinfo.output_width && newYDim == cinfo.output_height) {\n        *imageBuffer = firstImage;\n    } else {\n        *imageBuffer = (unsigned char *)malloc((size_t)(3 * newXDim * newYDim));\n        resampleImage(firstImage, cinfo.output_width, cinfo.output_height, *imageBuffer, newXDim, newYDim);\n        free(firstImage);\n    }\n\n    /* Step 7: Finish decompression */\n\n    (void)jpeg_finish_decompress(&cinfo);\n    /* We can ignore the return value since suspension is not possible\n     * with the stdio data source.\n     */\n\n    /* Step 8: Release JPEG decompression object */\n\n    /* This is an important step since it will release a good deal of memory. */\n    jpeg_destroy_decompress(&cinfo);\n\n    /* After finish_decompress, we can close the input file.\n     * Here we postpone it until after no more JPEG errors are possible,\n     * so as to simplify the setjmp error logic above.  (Actually, I don't\n     * think that jpeg_destroy can do an error exit, but why assume anything...)\n     */\n    fclose(infile);\n\n    /* At this point you may want to check to see whether any corrupt-data\n     * warnings occurred (test whether jerr.pub.num_warnings is nonzero).\n     */\n\n    /* And we're done! */\n    return 1;\n}\n\n/*\n * SOME FINE POINTS:\n *\n * In the above code, we ignored the return value of jpeg_read_scanlines,\n * which is the number of scanlines actually read.  We could get away with\n * this because we asked for only one line at a time and we weren't using\n * a suspending data source.  See libjpeg.doc for more info.\n *\n * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();\n * we should have done it beforehand to ensure that the space would be\n * counted against the JPEG max_memory setting.  In some systems the above\n * code would risk an out-of-memory error.  However, in general we don't\n * know the output image dimensions before jpeg_start_decompress(), unless we\n * call jpeg_calc_output_dimensions().  See libjpeg.doc for more about this.\n *\n * Scanlines are returned in the same order as they appear in the JPEG file,\n * which is standardly top-to-bottom.  If you must emit data bottom-to-top,\n * you can use one of the virtual arrays provided by the JPEG memory manager\n * to invert the data.  See wrbmp.c for an example.\n *\n * As with compression, some operating modes may require temporary files.\n * On some systems you may need to set up a signal handler to ensure that\n * temporary files are deleted if the program is interrupted.  See libjpeg.doc.\n */\n"
  },
  {
    "path": "lib/vapi/CMakeLists.txt",
    "content": "if (NOT PROJECT_NAME)\n\tcmake_minimum_required (VERSION 3.10)\n    project (VAPI)\n\tset (CMAKE_CXX_STANDARD 11)\nendif ()\n\nfile (GLOB HDRS ./*.h)\nfile (GLOB SRCS ./*.cpp)\nif (APPLE)\n\tfile (GLOB OBJC_SRCS ./*.mm)\n\tlist (APPEND SRCS ${OBJC_SRCS})\nendif ()\n\nlist(FILTER SRCS EXCLUDE REGEX \".*main\\\\.cpp$\")\n\nadd_library (vapi SHARED ${SRCS} ${HDRS})\n\ntarget_link_libraries (\n    vapi\n\trender\n    osgl\n)\n\nif (APPLE)\n\tfind_library (APPKIT AppKit)\n\ttarget_link_libraries (vapi ${APPKIT})\nendif ()\n\n# if (UNIX AND NOT APPLE)\n# \ttarget_link_libraries (vapi OSMesa EGL)\n# endif ()\n\nfile (GLOB GLContextLibFiles ./GLContext*.cpp ./GLContext*.h ./GLContext*.mm)\nsource_group (GLContextLib FILES ${GLContextLibFiles})\n\n# add_executable (vapitest main.cpp)\n# target_link_libraries (vapitest vapi ${Python_LIBRARIES})\n\n\nfile (\n    COPY ${HDRS}\n    DESTINATION ${CMAKE_BINARY_DIR}/include/vapor\n    )\ntarget_include_directories (vapi PUBLIC ${CMAKE_BINARY_DIR}/include)\n\n\ninstall (\n\tTARGETS vapi\n\tDESTINATION ${INSTALL_LIB_DIR}\n\tCOMPONENT Libraries\n\t)\n\ninstall (\n\tFILES ${HDRS}\n\tDESTINATION ${INSTALL_INCLUDE_DIR}\n\tCOMPONENT Libraries\n\t)\n\n"
  },
  {
    "path": "lib/vapi/RenderManager.cpp",
    "content": "#include \"RenderManager.h\"\n\n#include <vapor/GUIStateParams.h>\n#include <vapor/AnimationParams.h>\n#include <vapor/TrackBall.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/GLManager.h>\n#include <vapor/Framebuffer.h>\n\n#include <vapor/GLInclude.h>\n#include <vapor/GLContextProvider.h>\n\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include <vapor/LegacyVectorMath.h>\n\n\nusing namespace VAPoR;\n\nGLContext *RenderManager::_glContext = nullptr;\n\n\nRenderManager::RenderManager(ControlExec *ce, bool useOSGLContext) : _controlExec(ce), _useOSGLContext(useOSGLContext) {}\n\nRenderManager::~RenderManager()\n{\n    if (_glManager) delete _glManager;\n}\n\nvoid RenderManager::getNearFarDist(const double posVec[3], const double dirVec[3], double &boxNear, double &boxFar)\n{\n    String _winName = GetWinName();\n\n    // First check full box\n    double wrk[3], cor[3], boxcor[3];\n    double camPosBox[3], dvdir[3];\n#ifdef WIN32\n    double maxProj = -DBL_MAX;\n    double minProj = DBL_MAX;\n#else\n    double maxProj = -std::numeric_limits<double>::max();\n    double minProj = std::numeric_limits<double>::max();\n#endif\n\n    DataStatus *dataStatus = _controlExec->GetDataStatus();\n    ParamsMgr * paramsMgr = _controlExec->GetParamsMgr();\n\n    AnimationParams *ap = ((AnimationParams *)paramsMgr->GetParams(AnimationParams::GetClassType()));\n    size_t           ts = ap->GetCurrentTimestep();\n\n    CoordType minExts, maxExts;\n    dataStatus->GetActiveExtents(paramsMgr, _winName, ts, minExts, maxExts);\n\n    for (int i = 0; i < 3; i++) camPosBox[i] = posVec[i];\n\n    for (int i = 0; i < 3; i++) dvdir[i] = dirVec[i];\n    vnormal(dvdir);\n\n    // For each box corner,\n    //   convert to box coords, then project to line of view\n    for (int i = 0; i < 8; i++) {\n        for (int j = 0; j < 3; j++) { cor[j] = ((i >> j) & 1) ? maxExts[j] : minExts[j]; }\n        for (int k = 0; k < 3; k++) boxcor[k] = cor[k];\n\n        vsub(boxcor, camPosBox, wrk);\n\n        float mdist = abs(vdot(wrk, dvdir));\n        if (minProj > mdist) { minProj = mdist; }\n        if (maxProj < mdist) { maxProj = mdist; }\n    }\n\n    if (maxProj < 1.e-10) maxProj = 1.e-10;\n    if (minProj > 0.03 * maxProj) minProj = 0.03 * maxProj;\n\n    // minProj will be < 0 if either the camera is in the box, or\n    // if some of the region is behind the camera plane.  In that case, just\n    // set the nearDist a reasonable multiple of the fardist\n    //\n    if (minProj <= 0.0) minProj = 0.0002 * maxProj;\n    boxFar = (float)maxProj;\n    boxNear = (float)minProj;\n\n    return;\n}\n\nvoid RenderManager::setUpProjMatrix()\n{\n    assert(not _controlExec->GetVisualizerNames().empty());\n    ParamsMgr *      paramsMgr = _controlExec->GetParamsMgr();\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(GetWinName());\n    MatrixManager *  mm = _glManager->matrixManager;\n\n    double m[16];\n    vParams->GetModelViewMatrix(m);\n\n    double posvec[3], upvec[3], dirvec[3];\n    bool   status = vParams->ReconstructCamera(m, posvec, upvec, dirvec);\n    if (!status) {\n        LogFatal(\"Failed to get camera parameters\");\n        return;\n    }\n\n    double nearDist, farDist;\n    getNearFarDist(posvec, dirvec, nearDist, farDist);\n    nearDist *= 0.25;\n    farDist *= 4.0;\n\n    size_t width, height;\n    vParams->GetWindowSize(width, height);\n    //    width *= QApplication::desktop()->devicePixelRatio();\n    //    height *= QApplication::desktop()->devicePixelRatio();\n    int wWidth = width;\n    int wHeight = height;\n\n    if (vParams->GetValueLong(ViewpointParams::UseCustomFramebufferTag, 0)) {\n//        printf(\"USE CUSTOM FRAMEBUFFER\\n\");\n        width = vParams->GetValueLong(ViewpointParams::CustomFramebufferWidthTag, 0);\n        height = vParams->GetValueLong(ViewpointParams::CustomFramebufferHeightTag, 0);\n        if (width == 0) width = 1;\n        if (height == 0) height = 1;\n\n        int maxSize;\n        glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize);\n        if (width > maxSize) {\n            width = maxSize;\n            vParams->SetValueLong(ViewpointParams::CustomFramebufferWidthTag, ViewpointParams::CustomFramebufferWidthTag, width);\n            LogFatal(\"Selected width is larger than your OpenGL implementation supports\");\n        }\n        if (height > maxSize) {\n            height = maxSize;\n            vParams->SetValueLong(ViewpointParams::CustomFramebufferHeightTag, ViewpointParams::CustomFramebufferHeightTag, height);\n            LogFatal(\"Selected height is larger than your OpenGL implementation supports\");\n        }\n\n        float fa = width / (float)height;\n        float wa = wWidth / (float)wHeight;\n\n        if (fa >= wa) {\n            int x = 0;\n            int y = (wHeight / 2) - (wHeight / fa * wa / 2);\n            int w = wWidth;\n            int h = wHeight / fa * wa;\n            glViewport(x, y, w, h);\n        } else {\n            int x = (wWidth / 2) - (wWidth * fa / wa / 2);\n            int y = 0;\n            int w = wWidth * fa / wa;\n            int h = wHeight;\n            glViewport(x, y, w, h);\n        }\n    } else {\n        glViewport(0, 0, width, height);\n    }\n\n    mm->MatrixModeProjection();\n    mm->LoadIdentity();\n\n    float w = (float)width / (float)height;\n\n    if (vParams->GetProjectionType() == ViewpointParams::MapOrthographic) {\n        Trackball trackball;\n        double    center[3];\n        vParams->GetRotationCenter(center);\n        trackball.setFromFrame(posvec, dirvec, upvec, center, true);\n        float s = trackball.GetOrthoSize();\n        mm->Ortho(-s * w, s * w, -s, s, nearDist, farDist);\n        vParams->SetOrthoProjectionSize(trackball.GetOrthoSize());\n    } else {\n        double fov = vParams->GetFOV();\n        mm->Perspective(glm::radians(fov), w, nearDist, farDist);\n    }\n\n    double pMatrix[16];\n    mm->GetDoublev(MatrixManager::Mode::Projection, pMatrix);\n\n    bool enabled = _controlExec->GetSaveStateEnabled();\n    _controlExec->SetSaveStateEnabled(false);\n\n    vParams->SetProjectionMatrix(pMatrix);\n\n    _controlExec->SetSaveStateEnabled(enabled);\n\n    mm->MatrixModeModelView();\n}\n\nvoid RenderManager::setUpModelViewMatrix()\n{\n    ParamsMgr *      paramsMgr = _controlExec->GetParamsMgr();\n    ViewpointParams *vParams = paramsMgr->GetViewpointParams(GetWinName());\n\n    double m[16];\n    vParams->GetModelViewMatrix(m);\n    _glManager->matrixManager->LoadMatrixd(m);\n}\n\n\n\nint RenderManager::Render(String imagePath, bool fast)\n{\n    if (_useOSGLContext)\n        GetOSGLContext()->MakeCurrent();\n\n    _controlExec->SyncWithParams();\n\n    //    GL_ERR_BREAK();\n    if (!_glManager) {\n        _glManager = new GLManager;\n        _controlExec->InitializeViz(GetWinName(), _glManager);\n    }\n    \n    auto res = GetResolution();\n    int width = res[0];\n    int height = res[1];\n\n    Framebuffer defaultFB;\n    defaultFB.Generate();\n    defaultFB.SetSize(width, height);\n    defaultFB.MakeRenderTarget();\n\n    getViewpointParams()->SetWindowSize(width, height);\n\n    _glManager->matrixManager->MatrixModeProjection();\n    _glManager->matrixManager->PushMatrix();\n    setUpProjMatrix();\n\n    _glManager->matrixManager->MatrixModeModelView();\n    _glManager->matrixManager->PushMatrix();\n    setUpModelViewMatrix();\n\n    int rc = _controlExec->EnableImageCapture(imagePath, GetWinName(), fast);\n    if (rc < 0) { LogWarning(\"Paint Failed\"); }\n\n    _glManager->matrixManager->MatrixModeProjection();\n    _glManager->matrixManager->PopMatrix();\n    _glManager->matrixManager->MatrixModeModelView();\n    _glManager->matrixManager->PopMatrix();\n\n    return rc;\n}\n\nvoid RenderManager::SetResolution(int width, int height)\n{\n    width = std::max(width, 1);\n    height = std::max(height, 1);\n    auto vp = getViewpointParams();\n    vp->BeginGroup(\"res\");\n    vp->SetValueLong(ViewpointParams::UseCustomFramebufferTag, \"\", true);\n    vp->SetValueLong(ViewpointParams::CustomFramebufferWidthTag, \"\", width);\n    vp->SetValueLong(ViewpointParams::CustomFramebufferHeightTag, \"\", height);\n    vp->EndGroup();\n}\n\nvector<int> RenderManager::GetResolution() const\n{\n    vector<int> res = {600, 480};\n    \n    auto vp = getViewpointParams();\n    if (vp->GetValueLong(vp->UseCustomFramebufferTag, false)) {\n        res[0] = getViewpointParams()->GetValueLong(ViewpointParams::CustomFramebufferWidthTag, 600);\n        res[1] = getViewpointParams()->GetValueLong(ViewpointParams::CustomFramebufferHeightTag, 480);\n    }\n    \n    return res;\n}\n\nString RenderManager::GetWinName() const\n{\n    const auto names = _controlExec->GetParamsMgr()->GetVisualizerNames();\n    assert(not names.empty());\n    return names[0];\n}\n\nGLContext *RenderManager::GetOSGLContext()\n{\n    if (_glContext == nullptr)\n        _glContext = GLContextProvider::CreateContext();\n    return _glContext;\n}\n\n\nVAPoR::ViewpointParams *RenderManager::getViewpointParams() const { return _controlExec->GetParamsMgr()->GetViewpointParams(GetWinName()); }\n"
  },
  {
    "path": "lib/vapi/RenderManager.h",
    "content": "#pragma once\n\n#include <vapor/VPCommon.h>\n#include <vapor/GLContext.h>\n\n//! \\class RenderManager\n//! \\ingroup VAPI\n//! \\brief Manages rendering visualizers\n\nclass RenderManager {\n    ControlExec *_controlExec;\n    GLManager *  _glManager = nullptr;\n    bool         _useOSGLContext = false;\n    static GLContext * _glContext;\n\npublic:\n    RenderManager(ControlExec *ce, bool useOSGLContext = false);\n    ~RenderManager();\n    int Render(String imagePath, bool fast=false);\n    void SetResolution(int width, int height);\n    vector<int> GetResolution() const;\n    String GetWinName() const;\n    static GLContext *GetOSGLContext();\n\nprivate:\n    void             getNearFarDist(const double posVec[3], const double dirVec[3], double &boxNear, double &boxFar);\n    void             setUpProjMatrix();\n    void             setUpModelViewMatrix();\n    ViewpointParams *getViewpointParams() const;\n};\n"
  },
  {
    "path": "lib/vapi/Session.cpp",
    "content": "#include \"Session.h\"\n\n#include <vapor/GUIStateParams.h>\n#include <vapor/AnimationParams.h>\n#include <vapor/SettingsParams.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/NavigationUtils.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/FileUtils.h>\n#include <vapor/STLUtils.h>\n#include <vapor/PythonDataMgr.h>\n\n#include <vapor/RenderManager.h>\n\nusing namespace VAPoR;\n\nSession::Session(bool useOSGLContext)\n: _useOSGLContext(useOSGLContext)\n{\n    vector<string> myParams;\n    myParams.push_back(GUIStateParams::GetClassType());\n    myParams.push_back(AnimationParams::GetClassType());\n    myParams.push_back(SettingsParams::GetClassType());\n    vector<string> myRenParams;\n    _controlExec = new ControlExec(new ParamsMgr(myParams, myRenParams));\n\n    Reset();\n}\n\nSession::~Session()\n{\n    delete _renderManager;\n    delete _controlExec;\n}\n\nvoid Session::CloseDataset(String datasetName)\n{\n    _controlExec->CloseData(datasetName);\n}\n\nvoid Session::CloseAllDatasets()\n{\n    auto datasetNames = _controlExec->GetDataNames();\n    for (auto &name : datasetNames) { CloseDataset(name); }\n}\n\nint Session::OpenDataset(String name, String format, const vector<String> &files, const vector<String> &options)\n{\n    _controlExec->GetParamsMgr()->BeginSaveStateGroup(\"Import Dataset\");\n    int rc = _controlExec->OpenData(files, name, format);\n    if (rc < 0) {\n        _controlExec->GetParamsMgr()->EndSaveStateGroup();\n        LogWarning(\"Failed to load data '%s'\", files.empty() ? name.c_str() : files[0].c_str());\n        return rc;\n    }\n\n    GUIStateParams *p = getGUIStateParams();\n    DataStatus *    ds = _controlExec->GetDataStatus();\n    bool            isFirstDataset = p->GetOpenDataSetNames().empty();\n    p->InsertOpenDataSet(name, format, files);\n    getAnimationParams()->SetEndTimestep(ds->GetTimeCoordinates().size() - 1);\n\n    if (isFirstDataset) {\n        NavigationUtils::ViewAll(_controlExec);\n        NavigationUtils::SetHomeViewpoint(_controlExec);\n        p->SetProjectionString(ds->GetMapProjection());\n    }\n\n    _controlExec->GetParamsMgr()->EndSaveStateGroup();\n    return 0;\n}\n\nint Session::OpenDataset(String format, const vector<String> &files, String name)\n{\n    VAssert(!name.empty());\n    \n    GUIStateParams *p = getGUIStateParams();\n    vector<String>  options = {\"-project_to_pcs\", \"-vertical_xform\"};\n    if (getSettingsParams()->GetAutoStretchEnabled()) options.push_back(\"-auto_stretch_z\");\n\n    if (!p->GetProjectionString().empty()) {\n        options.push_back(\"-proj4\");\n        options.push_back(p->GetProjectionString());\n    }\n\n    return OpenDataset(name, format, files, options);\n}\n\nString Session::OpenDataset(String format, vector<String> files)\n{\n    if (files.empty())\n        return \"\";\n\n    String name = ControlExec::MakeStringConformant(FileUtils::Basename(files[0]));\n    \n    if (OpenDataset(format, files, name) < 0)\n        return \"\";\n    return name;\n}\n\nint Session::Load(String path)\n{\n    Reset();\n\n    int rc = _controlExec->LoadState(path);\n    if (rc < 0) {\n        LogWarning(\"Session '%s' failed to load\", path.c_str());\n        return rc;\n    }\n\n    auto dataSetNames = _controlExec->GetParamsMgr()->GetDataMgrNames();\n    for (auto d : dataSetNames) { printf(\"Dataset: '%s'\\n\", d.c_str()); }\n\n    loadAllParamsDatasets();\n    \n    getGUIStateParams()->SetActiveVizName(getWinName());\n\n    _controlExec->GetParamsMgr()->UndoRedoClear();\n    return 0;\n}\n\nint Session::Save(String path)\n{\n    for (auto name : _controlExec->GetDataNames()) {\n        if (dynamic_cast<PythonDataMgr*>(_controlExec->GetDataStatus()->GetDataMgr(name))) {\n            LogWarning(\"Cannot save session that contains data dynamically loaded from python (dataset.PYTHON)\");\n            return -1;\n        }\n    }\n            \n    \n    if (_controlExec->SaveSession(path) < 0) {\n        LogWarning(\"Failed to save session \\\"%s\\\"\", path.c_str());\n        return -1;\n    }\n    \n    getGUIStateParams()->SetCurrentSessionFile(path);\n    return 0;\n}\n\nvoid Session::Reset()\n{\n    CloseAllDatasets();\n    _controlExec->LoadState();\n    _controlExec->SetCacheSize(getSettingsParams()->GetCacheMB());\n\n    _controlExec->NewVisualizer(\"viz_1\");\n    getGUIStateParams()->SetActiveVizName(\"viz_1\");\n\n    \n    if (_renderManager) delete _renderManager;\n    _renderManager = new RenderManager(_controlExec, _useOSGLContext);\n    \n    _controlExec->GetParamsMgr()->UndoRedoClear();\n}\n\nint Session::Render(String imagePath, bool fast)\n{\n    if (!_controlExec->GetParamsMgr()->GetDataMgrNames().size()) {\n        LogWarning(\"Nothing to render\");\n        return -1;\n    }\n    if (_controlExec->GetParamsMgr()->GetDataMgrNames() != getGUIStateParams()->GetOpenDataSetNames()) {\n        LogWarning(\"Cannot render: There are missing datasets\");\n        return -1;\n    }\n\n    return _renderManager->Render(imagePath, fast);\n}\n\nvoid Session::SetTimestep(int ts) { NavigationUtils::SetTimestep(_controlExec, ts); }\nint Session::GetTimesteps() const { return _controlExec->GetDataStatus()->getMaxTimestep() + 1; }\n\n\nvoid Session::SetWaspMyBaseErrMsgFilePtrToSTDERR()\n{\n    Wasp::MyBase::SetErrMsgFilePtr(stderr);\n}\n\nvector<String> Session::GetDatasetNames() const\n{\n    return _controlExec->GetDataNames();\n}\n\nvector<String> Session::GetRendererNames() const\n{\n    vector<String> names;\n    for (auto cls : _controlExec->GetAllRenderClasses())\n        for (auto inst : _controlExec->GetRenderInstances(getWinName(), cls))\n            names.push_back(inst);\n    return names;\n}\n\nString Session::NewRenderer(String type, String dataset)\n{\n    auto all = _controlExec->GetAllRenderClasses();\n    VAssert(STLUtils::Contains(all, type));\n    VAssert(!_controlExec->GetDataNames().empty());\n    \n    if (dataset.empty())\n        dataset = _controlExec->GetDataNames()[0];\n    \n    String rendererName = _controlExec->MakeRendererNameUnique(type);\n\n    _controlExec->GetParamsMgr()->BeginSaveStateGroup(\"New Renderer\");\n\n    int rc = _controlExec->ActivateRender(getWinName(), dataset, type, rendererName, false);\n    if (rc < 0) {\n        _controlExec->GetParamsMgr()->EndSaveStateGroup();\n        return \"\";\n    }\n\n    getGUIStateParams()->SetActiveRenderer(getWinName(), type, rendererName);\n    _controlExec->GetParamsMgr()->EndSaveStateGroup();\n    \n    // ControlExec::RenderLookup\n    string _win, _data, _type;\n    _controlExec->RenderLookup(rendererName, _win, _data, _type);\n    return rendererName;\n}\n\n\nvoid Session::DeleteRenderer(String name)\n{\n    string win, data, type;\n    _controlExec->RenderLookup(name, win, data, type);\n    _controlExec->RemoveRenderer(win, data, type, name, false);\n}\n\n\nString Session::GetPythonWinName() const\n{\n    return getWinName();\n}\n\n\nvoid Session::loadAllParamsDatasets()\n{\n    auto dataSetNames = _controlExec->GetParamsMgr()->GetDataMgrNames();\n\n    for (int i = 0; i < dataSetNames.size(); i++) {\n        string         name = dataSetNames[i];\n        string         format;\n        vector<string> paths;\n        getParamsDatasetInfo(name, &format, &paths);\n        if (std::all_of(paths.begin(), paths.end(), FileUtils::Exists)) {\n            if (OpenDataset(format, paths, name) < 0) getGUIStateParams()->RemoveOpenDataSet(name);\n        } else {\n            getGUIStateParams()->RemoveOpenDataSet(name);\n\n            string details = \"This session links to the dataset \" + name + \" which was not found. Please open this dataset if it is in a different location\\n\";\n\n            for (const auto &path : paths)\n                if (!FileUtils::Exists(path)) details += \"\\\"\" + path + \"\\\" not found.\\n\";\n\n            LogWarning(\"%s\", details.c_str());\n        }\n    }\n}\n\nvoid Session::getParamsDatasetInfo(String name, String *type, vector<String> *files)\n{\n    auto gsp = getGUIStateParams();\n    *type = gsp->GetOpenDataSetFormat(name);\n    *files = gsp->GetOpenDataSetPaths(name);\n}\n\nGUIStateParams *Session::getGUIStateParams() const { return ((GUIStateParams *)_controlExec->GetParamsMgr()->GetParams(GUIStateParams::GetClassType())); }\n\nAnimationParams *Session::getAnimationParams() const { return ((AnimationParams *)_controlExec->GetParamsMgr()->GetParams(AnimationParams::GetClassType())); }\n\nSettingsParams *Session::getSettingsParams() const { return ((SettingsParams *)_controlExec->GetParamsMgr()->GetParams(SettingsParams::GetClassType())); }\n\nString Session::getWinName() const\n{\n    return _renderManager->GetWinName();\n}\n"
  },
  {
    "path": "lib/vapi/Session.h",
    "content": "#pragma once\n\n#include <vapor/VPCommon.h>\n\nclass RenderManager;\n\n//! \\class Session\n//! \\ingroup VAPI\n//! \\brief Manages a Vapor Session\n//! \\author Stas Jaroszynski\n\nclass Session {\npublic:\n    ControlExec *  _controlExec = nullptr;\n    RenderManager *_renderManager = nullptr;\n    bool _useOSGLContext = false;\n\n    Session(bool useOSGLContext = false);\n    virtual ~Session();\n    void CloseDataset(String name);\n    void CloseAllDatasets();\n    int  OpenDataset(String name, String format, const vector<String> &files, const vector<String> &options);\n    int  OpenDataset(String format, const vector<String> &files, String name);\n    String OpenDataset(String format, vector<String> files);\n    int  Load(String path);\n    int  Save(String path);\n    void Reset();\n    \n    vector<String> GetDatasetNames() const;\n    vector<String> GetRendererNames() const;\n\n    String NewRenderer(String type, String dataset=\"\");\n    void DeleteRenderer(String name);\n\n    int  Render(String imagePath, bool fast=false);\n    void SetTimestep(int ts);\n    int GetTimesteps() const;\n    \n    static void SetWaspMyBaseErrMsgFilePtrToSTDERR();\n    \n    String GetPythonWinName() const;\n\nprotected:\n    void             loadAllParamsDatasets();\n    void             getParamsDatasetInfo(String name, String *type, vector<String> *files);\n    GUIStateParams * getGUIStateParams() const;\n    AnimationParams *getAnimationParams() const;\n    SettingsParams * getSettingsParams() const;\n    String getWinName() const;\n};\n"
  },
  {
    "path": "lib/vapi/VPCommon.h",
    "content": "#pragma once\n\n#include <vapor/GLContextProviderCommon.h>\n\nnamespace VAPoR {\nclass ControlExec;\nclass ParamsMgr;\nstruct GLManager;\nclass Framebuffer;\nclass ViewpointParams;\nclass RenderParams;\n}    // namespace VAPoR\nusing namespace VAPoR;\nclass GUIStateParams;\nclass AnimationParams;\nclass SettingsParams;\n"
  },
  {
    "path": "lib/vapi/main.cpp",
    "content": "//#include <vapor/glutil.h>\n\n#include <stdio.h>\n#include <vapor/GLContextProvider.h>\n#include <vapor/GLInclude.h>\n#include <vapor/Log.h>\n#include <vapor/Session.h>\n#include <vapor/VAssert.h>\n#include <vapor/MyBase.h>\n\nusing namespace VAPoR;\nSession *_session;\n\nint main(int argc, char **argv)\n{\n    const char *sessionPath;\n    if (argc == 2)\n        sessionPath = argv[1];\n    else \n        sessionPath = \"/Users/stasj/Work/sessions/time.vs3\";\n\n\n    Wasp::MyBase::SetErrMsgFilePtr(stderr);\n\n    auto ctx = GLContextProvider::CreateContext();\n    VAssert(ctx);\n    ctx->MakeCurrent();\n    LogMessage(\"Context: %s\", glGetString(GL_VERSION));\n\n    _session = new Session;\n\n    _session->Load(sessionPath);\n    \n    // _session->NewRenderer(\"Contour\");\n    \n    _session->Render(\"out-vapi-test.png\");\n\n    return 0;\n}\n"
  },
  {
    "path": "lib/vdc/ArbitrarilyOrientedRegularGrid.cpp",
    "content": "#include <limits>\n#include <iomanip>\n\n#include <vapor/utils.h>\n\n#include <glm/gtc/type_ptr.hpp>\n#include <GTE/MinimumAreaBox2.h>\n#include <vapor/RegularGrid.h>\n#include <vapor/ArbitrarilyOrientedRegularGrid.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\n// clang-format off\n\nArbitrarilyOrientedRegularGrid::ArbitrarilyOrientedRegularGrid(\n    const VAPoR::Grid *grid3d,\n    planeDescription& pd,\n    const DimsType& dims\n) : RegularGrid(\n        dims, \n        {{pd.sideSize, pd.sideSize, 1}}, \n        {(_myBlks = new float[dims[0]*dims[1]*dims[2]])}, \n        {{0.,0.,0.}}, \n        {{1.,1.,1.}}\n) {\n    SetMissingValue( grid3d->GetMissingValue() );\n\n    glm::vec3 n(pd.normal[0], pd.normal[1], pd.normal[2]);\n    n = glm::normalize(n);\n    if (glm::any(glm::isnan(n)) || abs(glm::length(n)) < 0.5)\n        n = glm::vec3(0,0,1);\n    \n    _sideSize = pd.sideSize;\n    _normal = {n[0], n[1], n[2]};\n\n    CoordType gridMin, gridMax;\n    grid3d->GetUserExtents(gridMin, gridMax);\n\n    _origin = {pd.origin[0], pd.origin[1], pd.origin[2]};\n\n    // Rotate the plane via quaternion method\n    _rotate();\n\n    // Find the vertices where our plane intercepts the edges of the Box\n    std::vector<glm::tvec3<double, glm::highp>> vertices;\n    _findIntercepts(gridMin, gridMax, vertices);\n\n    // If there are no vertices to define our quad, make a grid of empty values\n    if (!vertices.size()) {\n        _makeEmptyGrid();\n        return;\n    }\n\n    // Find the minimum-area-rectangle that encloses the vertices that are along the edges\n    // of the Box.  Define this rectangle in 3D space, and in a newly projecteed 2D space.\n    std::vector<glm::tvec3<double, glm::highp>> tmpRectangle3D;\n    _getMinimumAreaRectangle( vertices );\n\n    // Pick sample points along our 2D rectangle, and project those points back into 3D space\n    // to query our 3D grid for data values.\n    _populateData( grid3d, pd );\n}\n\nArbitrarilyOrientedRegularGrid::~ArbitrarilyOrientedRegularGrid() {\n    if (_myBlks != nullptr)\n        delete [] _myBlks;\n}\n\nvoid ArbitrarilyOrientedRegularGrid::_makeEmptyGrid() {\n    _rectangle2D.clear();\n    _rectangle2D.resize(4);\n    _rectangle2D[0] = glm::vec2(0., 0.);\n    _rectangle2D[1] = glm::vec2(0., 0.);\n    _rectangle2D[2] = glm::vec2(0., 0.);\n    _rectangle2D[3] = glm::vec2(0., 0.);\n\n    size_t numSamples = _sideSize*_sideSize;\n    for (size_t i = 0; i < numSamples; i++) {\n        _myBlks[i] = GetMissingValue();\n    }\n}\n\n// Huges-Moller algorithm to get an orthogonal vector\n// https://blog.selfshadow.com/2011/10/17/perp-vectors\nglm::tvec3<double, glm::highp> ArbitrarilyOrientedRegularGrid::_getOrthogonal(const glm::tvec3<double, glm::highp>& u) \n{\n    glm::tvec3<double, glm::highp> a = abs(u);\n    glm::tvec3<double, glm::highp> v;\n    if (a.x <= a.y && a.x <= a.z)\n        v = glm::tvec3<double, glm::highp>(0, -u.z, u.y);\n    else if (a.y <= a.x && a.y <= a.z)\n        v = glm::tvec3<double, glm::highp>(-u.z, 0, u.x);\n    else\n        v = glm::tvec3<double, glm::highp>(-u.y, u.x, 0);\n    v = glm::normalize(v);\n    return v;\n}\n\nvoid ArbitrarilyOrientedRegularGrid::_rotate() {\n    // We will sample the slice in 2D coordinates.\n    // So we first define a basis function of three orthogonal vectors (normal, _axis1, _axis2).\n    _axis1 = _getOrthogonal(_normal);\n    _axis2 = glm::cross(_normal, _axis1);\n}\n\nvoid ArbitrarilyOrientedRegularGrid::_findIntercepts(\n    const VAPoR::CoordType& boxMin,\n    const VAPoR::CoordType& boxMax,\n    std::vector<glm::tvec3<double, glm::highp>> &vertices\n)  {\n    // Lambdas for finding intercepts on the XYZ edges of the Box\n    // Plane equation:\n    //     normal.x*(x-origin.x) + normal.y*(y-origin.y) + normal.z*(z-origin.z) = 0\n\n    auto zIntercept = [&](double x, double y) {\n        if (_normal.z == 0) return;\n        double z = (_normal.x * _origin.x + _normal.y * _origin.y + _normal.z * _origin.z - _normal.x * x - _normal.y * y) / _normal.z;\n        if (z >= boxMin[2] && z <= boxMax[2]) {\n            glm::tvec3<double, glm::highp> p(x, y, z);\n            vertices.push_back(p);\n        }\n    };\n    auto yIntercept = [&](double x, double z) {\n        if (_normal.y == 0) return;\n        double y = (_normal.x * _origin.x + _normal.y * _origin.y + _normal.z * _origin.z - _normal.x * x - _normal.z * z) / _normal.y;\n        if (y >= boxMin[1] && y <= boxMax[1]) {\n            glm::tvec3<double, glm::highp> p(x, y, z);\n            vertices.push_back(p);\n        }\n    };\n    auto xIntercept = [&](double y, double z) {\n        if (_normal.x == 0) return;\n        double x = (_normal.x * _origin.x + _normal.y * _origin.y + _normal.z * _origin.z - _normal.y * y - _normal.z * z) / _normal.x;\n        if (x >= boxMin[0] && x <= boxMax[0]) {\n            glm::tvec3<double, glm::highp> p(x, y, z);\n            vertices.push_back(p);\n        }\n    };\n\n    // Find vertices that exist on the Z edges of the Box\n    zIntercept(boxMin[0], boxMin[1]);\n    zIntercept(boxMax[0], boxMax[1]);\n    zIntercept(boxMin[0], boxMax[1]);\n    zIntercept(boxMax[0], boxMin[1]);\n    // Find any vertices that exist on the Y edges of the Box\n    yIntercept(boxMin[0], boxMin[2]);\n    yIntercept(boxMax[0], boxMax[2]);\n    yIntercept(boxMin[0], boxMax[2]);\n    yIntercept(boxMax[0], boxMin[2]);\n    // Find any vertices that exist on the X edges of the Box\n    xIntercept(boxMin[1], boxMin[2]);\n    xIntercept(boxMax[1], boxMax[2]);\n    xIntercept(boxMin[1], boxMax[2]);\n    xIntercept(boxMax[1], boxMin[2]);\n}\n\nvoid ArbitrarilyOrientedRegularGrid::_getMinimumAreaRectangle(\n    const std::vector<glm::tvec3<double, glm::highp>>& vertices\n) {\n\n    std::vector<gte::Vector2<double>> gteVertices;\n    for (int i=0; i<vertices.size(); i++) {\n        glm::tvec3<double, glm::highp> v3d = vertices[i];\n        double x = glm::dot(_axis1, v3d-_origin);\n        double y = glm::dot(_axis2, v3d-_origin);\n        gte::Vector2<double> v{x,y};\n        gteVertices.push_back(v);\n    }\n\n    typedef gte::BSRational<gte::UIntegerAP32> MABRational;\n    gte::MinimumAreaBox2<double, MABRational> mab2;\n    gte::OrientedBox2<double> minimalBox = mab2(vertices.size(), &gteVertices[0]);\n    std::array<gte::Vector2<double>, 4> rectangle;\n    minimalBox.GetVertices(rectangle);\n\n    // _rectangle2D\n    _rectangle2D.clear();\n    _rectangle2D.resize(4);\n    _rectangle2D[0] = glm::vec2(rectangle[0][0], rectangle[0][1]);\n    _rectangle2D[1] = glm::vec2(rectangle[1][0], rectangle[1][1]);\n    _rectangle2D[2] = glm::vec2(rectangle[3][0], rectangle[3][1]);\n    _rectangle2D[3] = glm::vec2(rectangle[2][0], rectangle[2][1]);\n}\n\nvoid ArbitrarilyOrientedRegularGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const\n{\n    // For now, we ignore rotated grids that have greater than 3 dimensions\n    // Therefore we only index on i an j, but not k\n    //\n    size_t i = indices[0];\n    size_t j = indices[1];\n\n    glm::tvec2<double, glm::highp> delta( (_rectangle2D[1].x-_rectangle2D[0].x)/_sideSize, (_rectangle2D[1].y-_rectangle2D[0].y)/_sideSize );\n\n    double xScanlineIncrement = (_rectangle2D[3].x-_rectangle2D[0].x)/_sideSize;\n    double yScanlineIncrement = (_rectangle2D[3].y-_rectangle2D[0].y)/_sideSize;\n\n    double x = _rectangle2D[0].x + j*xScanlineIncrement + i*delta.x;\n    double y = _rectangle2D[0].y + j*yScanlineIncrement + i*delta.y;\n\n    glm::tvec3<double, glm::highp> samplePoint = _origin + x*_axis1 + y*_axis2;\n    coords = {samplePoint.x, samplePoint.y, samplePoint.z};\n}\n\nvoid ArbitrarilyOrientedRegularGrid::_populateData(\n    const VAPoR::Grid *grid, \n    const planeDescription& description\n) {\n    VAPoR::CoordType min = description.boxMin;\n    VAPoR::CoordType max = description.boxMax;\n    float missingValue = grid->GetMissingValue();\n    size_t index = 0;\n\n    for (size_t j = 0; j < _sideSize; j++) {\n        for (size_t i = 0; i < _sideSize; i++) {\n            VAPoR::CoordType p;\n            GetUserCoordinates({i,j,1}, p);\n\n            if ( p[0] < min[0] || p[0] > max[0] ||\n                 p[1] < min[1] || p[1] > max[1] ||\n                 p[2] < min[2] || p[2] > max[2] ) {\n                _myBlks[index] = missingValue;\n            }\n            else {\n                _myBlks[index] = grid->GetValue(p);\n            }\n            index++;\n        }\n    }\n}\n\n// clang-format on\n\nglm::vec3 ArbitrarilyOrientedRegularGrid::GetNormalFromRotations(const std::vector<double> &rotations)\n{\n    glm::vec3 r(rotations[0], rotations[1], rotations[2]);\n    r = r * (float)M_PI / 180.f;\n    auto q = glm::quat(r);\n    auto n = q * glm::vec3(0, 0, 1);\n    return n;\n}\n\nstd::pair<float, float> ArbitrarilyOrientedRegularGrid::GetOffsetRange(const planeDescription &pd)\n{\n    glm::vec3 n(pd.normal[0], pd.normal[1], pd.normal[2]);\n    glm::vec3 dataMin(pd.boxMin[0], pd.boxMin[1], pd.boxMin[2]);\n    glm::vec3 dataMax(pd.boxMax[0], pd.boxMax[1], pd.boxMax[2]);\n    glm::vec3 o(pd.origin[0], pd.origin[1], pd.origin[2]);\n    float     t0, t1;\n    glm::vec3 tMin = (dataMin - o) / n;\n    glm::vec3 tMax = (dataMax - o) / n;\n    glm::vec3 bt1 = min(tMin, tMax);\n    glm::vec3 bt2 = max(tMin, tMax);\n    t0 = max(max(bt1.x, bt1.y), bt1.z);\n    t1 = min(min(bt2.x, bt2.y), bt2.z);\n    return std::pair<float, float>(t0, t1);\n}\n"
  },
  {
    "path": "lib/vdc/BOVCollection.cpp",
    "content": "#include <memory>\n#include <vector>\n#include <algorithm>\n#include <map>\n#include <sstream>\n#include <iomanip>\n#include <iostream>\n#include <fstream>\n#include <type_traits>\n#include <float.h>\n#include \"vapor/VAssert.h\"\n#include \"vapor/utils.h\"\n#include \"vapor/FileUtils.h\"\n#include <cstdio>\n#include <climits>\n#include <cmath>\n\n#include <vapor/BOVCollection.h>\n\nusing namespace VAPoR;\n\nconst std::string BOVCollection::TIME_TOKEN = \"TIME\";\nconst std::string BOVCollection::DATA_FILE_TOKEN = \"DATA_FILE\";\nconst std::string BOVCollection::GRID_SIZE_TOKEN = \"DATA_SIZE\";\nconst std::string BOVCollection::FORMAT_TOKEN = \"DATA_FORMAT\";\nconst std::string BOVCollection::VARIABLE_TOKEN = \"VARIABLE\";\nconst std::string BOVCollection::ORIGIN_TOKEN = \"BRICK_ORIGIN\";\nconst std::string BOVCollection::BRICK_SIZE_TOKEN = \"BRICK_SIZE\";\nconst std::string BOVCollection::OFFSET_TOKEN = \"BYTE_OFFSET\";\n\n// These tokens are parsed, but not used in ReadRegion() logic\nconst std::string BOVCollection::ENDIAN_TOKEN = \"DATA_ENDIAN\";\nconst std::string BOVCollection::CENTERING_TOKEN = \"CENTERING\";\nconst std::string BOVCollection::DIVIDE_BRICK_TOKEN = \"DIVIDE_BRICK\";\nconst std::string BOVCollection::DATA_BRICKLETS_TOKEN = \"DATA_BRICKLETS\";\nconst std::string BOVCollection::DATA_COMPONENTS_TOKEN = \"DATA_COMPONENTS\";\n\nconst std::array<double, 3> BOVCollection::_defaultOrigin = {0., 0., 0.};\nconst std::array<double, 3> BOVCollection::_defaultBrickSize = {1., 1., 1.};\nconst std::array<size_t, 3> BOVCollection::_defaultGridSize = {0, 0, 0};\nconst DC::XType             BOVCollection::_defaultFormat = DC::XType::INVALID;\nconst std::string           BOVCollection::_defaultFile = \"\";\nconst std::string           BOVCollection::_defaultVar = \"brickVar\";\nconst double                BOVCollection::_defaultTime = FLT_MIN;\nconst size_t                BOVCollection::_defaultByteOffset = 0;\n\n// Currently unused in ReadRegion() logic\nconst std::string           BOVCollection::_defaultEndian = \"LITTLE\";\nconst std::string           BOVCollection::_defaultCentering = \"ZONAL\";\nconst bool                  BOVCollection::_defaultDivBrick = false;\nconst std::array<size_t, 3> BOVCollection::_defaultBricklets = {0, 0, 0};\nconst size_t                BOVCollection::_defaultComponents = 1;\n\nconst std::string BOVCollection::_xDim = \"x\";\nconst std::string BOVCollection::_yDim = \"y\";\nconst std::string BOVCollection::_zDim = \"z\";\nconst std::string BOVCollection::_timeDim = \"t\";\n\nconst std::string BOVCollection::_byteFormatString = \"BYTE\";\nconst std::string BOVCollection::_shortFormatString = \"SHORT\";\nconst std::string BOVCollection::_intFormatString = \"INT\";\nconst std::string BOVCollection::_floatFormatString = \"FLOAT\";\nconst std::string BOVCollection::_doubleFormatString = \"DOUBLE\";\n\nnamespace {\nsize_t getFileSize(std::string filename)    // path to file\n{\n    FILE *p_file = NULL;\n    p_file = fopen(filename.c_str(), \"rb\");\n    fseek(p_file, 0, SEEK_END);\n    size_t size = ftell(p_file);\n    fclose(p_file);\n    return size;\n}\n}    // namespace\n\nBOVCollection::BOVCollection()\n: _time(_defaultTime), _dataFile(_defaultFile), _dataFormat(_defaultFormat), _variable(_defaultVar), _byteOffset(_defaultByteOffset), _divideBrick(_defaultDivBrick), _dataEndian(_defaultEndian),\n  _centering(_defaultCentering), _dataComponents(_defaultComponents), _tmpDataFormat(_defaultFormat), _tmpByteOffset(_defaultByteOffset), _gridSizeAssigned(false), _formatAssigned(false),\n  _brickOriginAssigned(false), _brickSizeAssigned(false), _byteOffsetAssigned(false), _timeDimension(_timeDim)\n{\n    // Note: the following variables are unused in the ReadRegion() logic\n    // _defaultEndian\n    // _defaultCentering\n    // _defaultDivBrick\n    // _defaultBricklets\n    // _defaultComponents\n\n    _dataFiles.clear();\n    _times.clear();\n    _gridSize = _defaultGridSize;\n    _tmpGridSize[0] = (int)_defaultGridSize[0];\n    _tmpGridSize[1] = (int)_defaultGridSize[1];\n    _tmpGridSize[2] = (int)_defaultGridSize[2];\n    _brickOrigin = _defaultOrigin;\n    _tmpBrickOrigin = _defaultOrigin;\n    _brickSize = _defaultBrickSize;\n    _tmpBrickSize = _defaultBrickSize;\n    _dataBricklets = _defaultBricklets;\n    _spatialDimensions = {_xDim, _yDim, _zDim};\n}\n\nint BOVCollection::Initialize(const std::vector<std::string> &paths)\n{\n    VAssert(paths.size() > 0);\n\n    int           rc;\n    std::ifstream header;\n    for (int i = 0; i < paths.size(); i++) {\n        _dataFile = _defaultFile;\n\n        // Save the path to the BOV header so we can add it\n        // to data files given with a relative path\n        _currentFilePath = Wasp::FileUtils::Dirname(paths[i]);\n\n        header.open(paths[i]);\n        if (header.is_open()) {\n            if (getFileSize(paths[i]) > 1000000) {\n                SetErrMsg((\"BOV header file larger than 1MB.  This text file shouldn't need to be larger than a few KB.\" + paths[0]).c_str());\n                return -1;\n            }\n\n            rc = _parseHeader(header);\n            if (rc < 0) {\n                SetErrMsg((\"Error parsing BOV file \" + paths[0]).c_str());\n                return -1;\n            }\n\n            // If _dataFile is not an absolute path, prepend with the BOV header's path\n            if (!Wasp::FileUtils::IsPathAbsolute(_dataFile)) {\n                auto dirAndPath = {_currentFilePath, _dataFile};\n                _dataFile = Wasp::FileUtils::JoinPaths(dirAndPath);\n            }\n\n            rc = _validateParsedValues();\n            if (rc < 0) {\n                SetErrMsg(\"Validating BOV tokens failed\");\n                return -1;\n            }\n\n            // Ensure we have the required tokens in the header\n            //\n            if (_dataFile == _defaultFile) { return _missingValueError(DATA_FILE_TOKEN); }\n            if (_dataFormat == _defaultFormat) { return _missingValueError(FORMAT_TOKEN); }\n            if (_gridSize == _defaultGridSize) { return _missingValueError(GRID_SIZE_TOKEN); }\n            if (_time == _defaultTime) { return _missingValueError(TIME_TOKEN); }\n\n            rc = _populateDataFileMap();\n            if (rc < 0) {\n                SetErrMsg(\"Problem indexing data files.\");\n                return -1;\n            }\n        } else {\n            SetErrMsg((\"Failed to open BOV file \" + paths[0]).c_str());\n            return -1;\n        }\n        header.close();\n    }\n\n    return 0;\n}\n\nint BOVCollection::_parseHeader(std::ifstream &header)\n{\n    int         rc;\n    std::string line;\n    std::string dataFile;\n    while (getline(header, line)) {\n        // The _dataFile, _gridSize, and _dataFormat variables are all required to process\n        // the BOV.  Try to find them, and report errors if we can't.\n        //\n        rc = _findToken(DATA_FILE_TOKEN, line, dataFile);\n        if (rc == (int)parseCodes::PARSE_ERROR)\n            return _failureToReadError(DATA_FILE_TOKEN);\n        else if (rc == (int)parseCodes::FOUND) {\n            _dataFile = dataFile;\n            continue;\n        }\n\n        double time;\n        rc = _findToken(TIME_TOKEN, line, time);\n        if (rc == (int)parseCodes::PARSE_ERROR)\n            return _failureToReadError(TIME_TOKEN);\n        else if (rc == (int)parseCodes::FOUND) {\n            _time = time;\n            continue;\n        }\n\n        std::string variable;\n        rc = _findToken(VARIABLE_TOKEN, line, variable);\n        if (rc == (int)parseCodes::PARSE_ERROR)\n            return _invalidValueError(VARIABLE_TOKEN);\n        else if (rc == (int)parseCodes::FOUND) {\n            _variable = variable;\n            continue;\n        }\n\n        rc = _findToken(GRID_SIZE_TOKEN, line, _tmpGridSize);\n        if (rc == (int)parseCodes::PARSE_ERROR)\n            return _failureToReadError(GRID_SIZE_TOKEN);\n        else if (rc == (int)parseCodes::FOUND)\n            continue;\n\n        rc = _findToken(FORMAT_TOKEN, line, _tmpDataFormat);\n        if (rc == (int)parseCodes::PARSE_ERROR)\n            return _failureToReadError(FORMAT_TOKEN);\n        else if (rc == (int)parseCodes::FOUND)\n            continue;\n\n        // Optional tokens.  If their values are invalid, SetErrMsg, and return -1.\n        //\n        rc = _findToken(ORIGIN_TOKEN, line, _tmpBrickOrigin);\n        if (rc == (int)parseCodes::PARSE_ERROR)\n            return _invalidValueError(ORIGIN_TOKEN);\n        else if (rc == (int)parseCodes::FOUND)\n            continue;\n\n        rc = _findToken(BRICK_SIZE_TOKEN, line, _tmpBrickSize);\n        if (rc == (int)parseCodes::PARSE_ERROR)\n            return _invalidValueError(BRICK_SIZE_TOKEN);\n        else if (rc == (int)parseCodes::FOUND)\n            continue;\n\n        rc = _findToken(OFFSET_TOKEN, line, _tmpByteOffset);\n        if (rc == (int)parseCodes::PARSE_ERROR)\n            return _invalidValueError(OFFSET_TOKEN);\n        else if (rc == (int)parseCodes::FOUND)\n            continue;\n\n        // All other variables are currently unused.\n        //\n        _findToken(ENDIAN_TOKEN, line, _dataEndian);\n        _findToken(CENTERING_TOKEN, line, _centering);\n        _findToken(DIVIDE_BRICK_TOKEN, line, _divideBrick);\n        _findToken(DATA_BRICKLETS_TOKEN, line, _dataBricklets);\n        _findToken(DATA_COMPONENTS_TOKEN, line, _dataComponents);\n    }\n    return 0;\n}\n\nint BOVCollection::_validateParsedValues()\n{\n    // Validate grid dimensions\n    if (_tmpGridSize[0] < 2 || _tmpGridSize[1] < 2 || _tmpGridSize[2] < 2)\n        return _invalidDimensionError(GRID_SIZE_TOKEN);\n    else if ((_tmpGridSize[0] != _gridSize[0] || _tmpGridSize[1] != _gridSize[1] || _tmpGridSize[2] != _gridSize[2]) && _gridSizeAssigned == true)\n        return _inconsistentValueError(GRID_SIZE_TOKEN);\n    else {\n        _gridSize[0] = (size_t)_tmpGridSize[0];\n        _gridSize[1] = (size_t)_tmpGridSize[1];\n        _gridSize[2] = (size_t)_tmpGridSize[2];\n        _gridSizeAssigned = true;\n    }\n\n\n    // Validate data format\n    if (_tmpDataFormat == DC::INVALID)\n        return _invalidFormatError(FORMAT_TOKEN);\n    else if (_tmpDataFormat != _dataFormat && _formatAssigned == true) {\n        return _inconsistentValueError(FORMAT_TOKEN);\n    } else {\n        _dataFormat = _tmpDataFormat;\n        _formatAssigned = true;\n    }\n\n    // Validate brick origin\n    if (_tmpBrickOrigin != _brickOrigin && _brickOriginAssigned == true)\n        return _inconsistentValueError(ORIGIN_TOKEN);\n    else {\n        _brickOrigin = _tmpBrickOrigin;\n        _brickOriginAssigned = true;\n    }\n\n    // Validate brick size\n    if (_tmpBrickSize != _brickSize && _brickSizeAssigned == true)\n        return _inconsistentValueError(BRICK_SIZE_TOKEN);\n    else {\n        for (size_t i = 0; i < _tmpBrickSize.size(); i++) {\n            if (_tmpBrickSize[i] < 0.) return _invalidValueError(BRICK_SIZE_TOKEN);\n        }\n        _brickSize = _tmpBrickSize;\n        _brickSizeAssigned = true;\n    }\n\n    // Validate byte offest\n    if (_tmpByteOffset != _byteOffset && _byteOffsetAssigned == true)\n        return _inconsistentValueError(OFFSET_TOKEN);\n    else {\n        _byteOffset = _tmpByteOffset;\n        _byteOffsetAssigned = true;\n    }\n\n    if (_variable.find_first_not_of(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_-\") != std::string::npos) return _invalidVarNameError();\n\n    return 0;\n}\n\nint BOVCollection::_populateDataFileMap()\n{\n    if (_dataFileMap[_variable].count(_time)) {\n        SetErrMsg(\"Duplicate time entries found in BOV files.  Each file must uniquely describe one variable, at one timestep.\");\n        return -1;\n    }\n\n    _variables.push_back(_variable);\n\n    if (std::find(_times.begin(), _times.end(), _time) == _times.end()) _times.push_back(_time);\n\n    std::sort(_times.begin(), _times.end());\n\n    _dataFileMap[_variable][_time] = _dataFile;\n    return 0;\n}\n\nint BOVCollection::_invalidVarNameError() const\n{\n    SetErrMsg(\"Invalid variable name.  (Must be alphanumeric)\");\n    return -1;\n}\n\n\nint BOVCollection::_invalidFileSizeError(size_t numElements) const\n{\n    SetErrMsg((\"Data file \" + _dataFile + \", which has \" + to_string(numElements)\n               + \" values, does not match the size of the the data and offset \"\n                 \"specified in BOV header.\")\n                  .c_str());\n    return -1;\n}\n\nint BOVCollection::_invalidFileError() const\n{\n    SetErrMsg((\"Reading \" + _dataFile + \" failed with error: \" + strerror(errno)).c_str());\n    return -1;\n}\n\nint BOVCollection::_missingValueError(const std::string &token) const\n{\n    SetErrMsg((\"BOV file must contain token: \" + token).c_str());\n    return -1;\n}\n\nint BOVCollection::_invalidDimensionError(const std::string &token) const\n{\n    SetErrMsg((token + \" must have all dimensions > 1\").c_str());\n    return -1;\n}\n\nint BOVCollection::_invalidFormatError(const std::string &token) const\n{\n    std::string message = token + \" must be either INT, FLOAT, or DOUBLE.\";\n    SetErrMsg(message.c_str());\n    return -1;\n}\n\nint BOVCollection::_failureToReadError(const std::string &token) const\n{\n    SetErrMsg((\"Failure reading BOV token: \" + token).c_str());\n    return -1;\n}\n\nint BOVCollection::_inconsistentValueError(const std::string &token) const\n{\n    SetErrMsg((token + \" must be consistent in all BOV files\").c_str());\n    return -1;\n}\n\nint BOVCollection::_invalidValueError(const std::string &token) const\n{\n    SetErrMsg((\"Invalid value for token: \" + token).c_str());\n    return -1;\n}\n\nstd::vector<std::string> BOVCollection::GetDataVariableNames() const { return _variables; }\n\nstd::array<std::string, 3> BOVCollection::GetSpatialDimensions() const { return _spatialDimensions; }\n\nstd::string BOVCollection::GetTimeDimension() const { return _timeDimension; }\n\nstd::vector<float> BOVCollection::GetUserTimes() const { return _times; }\n\nstd::array<size_t, 3> BOVCollection::GetDataSize() const { return _gridSize; }\n\nDC::XType BOVCollection::GetDataFormat() const { return _dataFormat; }\n\nstd::array<double, 3> BOVCollection::GetBrickOrigin() const { return _brickOrigin; }\n\nstd::array<double, 3> BOVCollection::GetBrickSize() const { return _brickSize; }\n\n// Template specialization for reading data of type DC::XType\ntemplate<> int BOVCollection::_findToken<DC::XType>(const std::string &token, std::string &line, DC::XType &value, bool verbose)\n{\n    // Skip comments\n    for (size_t i = 0; i < line.length(); i++) {\n        if (line[i] == '#') {\n            line.erase(line.begin() + i, line.end());\n            break;\n        }\n    }\n\n    if (line.length() == 0) return (int)parseCodes::NOT_FOUND;\n\n    while (line.length() > 0) {\n        if (line[line.length() - 1] == ' ')    // If last char is a space, pop it\n            line.pop_back();\n        else\n            break;\n    }\n\n    size_t pos = line.find(token);\n    if (pos != std::string::npos) {    // We found the token\n        std::string format = line;\n        _findTokenValue(format);\n        if (format == _intFormatString)\n            value = DC::INT32;\n        else if (format == _floatFormatString)\n            value = DC::FLOAT;\n        else if (format == _doubleFormatString)\n            value = DC::DOUBLE;\n        else {\n            value = DC::INVALID;\n            _invalidFormatError(token);\n            return (int)parseCodes::PARSE_ERROR;\n        }\n\n        if (verbose) { std::cout << std::setw(20) << token << \" \" << value << std::endl; }\n        return (int)parseCodes::FOUND;\n    }\n    return (int)parseCodes::NOT_FOUND;\n}\n\n// Template specialization for reading data of types bool or string\ntemplate<typename T> int BOVCollection::_findToken(const std::string &token, std::string &line, T &value, bool verbose)\n{\n    // Skip comments\n    for (size_t i = 0; i < line.length(); i++) {\n        if (line[i] == '#') {\n            line.erase(line.begin() + i, line.end());\n            break;\n        }\n    }\n\n    if (line.length() == 0) return (int)parseCodes::NOT_FOUND;\n\n    while (line.length() > 0) {\n        if (line[line.length() - 1] == ' ')    // If last char is a space, pop it\n            line.pop_back();\n        else\n            break;\n    }\n\n    size_t pos = line.find(token);\n    if (pos != std::string::npos) {    // We found the token\n        _findTokenValue(line);\n        stringstream ss(line);\n        if (std::is_same<T, bool>::value) {\n            ss >> std::boolalpha >> value;\n        } else {\n            ss >> value;\n        }\n\n        if (verbose) { std::cout << std::setw(20) << token << \" \" << value << std::endl; }\n\n        if (ss.fail()) { return (int)parseCodes::PARSE_ERROR; }\n        // If there is more than one value, throw error\n        if (ss.eof() == false) return (int)parseCodes::PARSE_ERROR;\n\n        return (int)parseCodes::FOUND;\n    }\n    return (int)parseCodes::NOT_FOUND;\n}\n\n// Template specialization for reading data of type std::array<size_t, 3> or std::array<float, 3>\ntemplate<typename T> int BOVCollection::_findToken(const std::string &token, std::string &line, std::array<T, 3> &value, bool verbose)\n{\n    // Skip comments\n    for (size_t i = 0; i < line.length(); i++) {\n        if (line[i] == '#') {\n            line.erase(line.begin() + i, line.end());\n            break;\n        }\n    }\n\n    if (line.length() == 0) return (int)parseCodes::NOT_FOUND;\n\n    while (line.length() > 0) {\n        if (line[line.length() - 1] == ' ')    // If last char is a space, pop it\n            line.pop_back();\n        else\n            break;\n    }\n\n    size_t pos = line.find(token);\n    if (pos != std::string::npos) {    // We found the token\n        T lineValue;\n        _findTokenValue(line);\n        std::stringstream lineStream(line);\n\n        for (int i = 0; i < value.size(); i++) {\n            lineStream >> lineValue;\n            if (lineStream.fail()) return (int)parseCodes::PARSE_ERROR;\n\n            value[i] = lineValue;\n        }\n\n        // If there are more than 3 values, throw error\n        if (!lineStream.eof()) return (int)parseCodes::PARSE_ERROR;\n\n        if (verbose) {\n            std::cout << std::setw(20) << token << \" \";\n            for (int i = 0; i < value.size(); i++) std::cout << value[i] << \" \";\n            std::cout << std::endl;\n        }\n        return (int)parseCodes::FOUND;\n    }\n    return (int)parseCodes::NOT_FOUND;\n}\n\nvoid BOVCollection::_findTokenValue(std::string &line) const\n{\n    std::string delimiter = \": \";\n\n    size_t      pos = 0;\n    std::string token;\n    while ((pos = line.find(delimiter)) != std::string::npos) {\n        token = line.substr(0, pos);\n        line.erase(0, pos + delimiter.length());\n    }\n}\n\nint BOVCollection::_sizeOfFormat(DC::XType type) const\n{\n    switch (type) {\n    case DC::XType::INT32: return 4;\n    case DC::XType::FLOAT: return 4;\n    case DC::XType::DOUBLE: return 8;\n    default: return -1;\n    }\n}\n\ntemplate<class T> int BOVCollection::ReadRegion(std::string varname, size_t ts, const std::vector<size_t> &min, const std::vector<size_t> &max, T region)\n{\n    float       time = _times[ts];\n    std::string dataFile = _dataFileMap[varname][time];\n\n    FILE *fp = fopen(dataFile.c_str(), \"rb\");\n    if (!fp) {\n        if (dataFile == \"\")\n            SetErrMsg(\"No data file associated with variable '%s' at timestep %d\", varname.c_str(), time);\n        else\n            SetErrMsg(\"Invalid file: %s : %M\", dataFile.c_str());\n        return -1;\n    }\n\n    int formatSize = _sizeOfFormat(_dataFormat);\n    if (formatSize < 0) {\n        SetErrMsg(\"Unspecified data format\");\n        fclose(fp);\n        return -1;\n    }\n\n    // Read a \"pencil\" of data along the X axis, one row at a time\n    size_t count = max[0] - min[0] + 1;\n    // Note: allocate buffer once and reuse for many times, so repeated allocation is avoided.\n    std::vector<unsigned char> vReadBuffer(count * formatSize);\n    unsigned char *            readBuffer = vReadBuffer.data();\n\n    for (size_t k = min[2]; k <= max[2]; k++) {\n        size_t zOffset = _gridSize[0] * _gridSize[1] * k;\n        for (size_t j = min[1]; j <= max[1]; j++) {\n            size_t xOffset = min[0];\n            size_t yOffset = _gridSize[0] * j;\n            size_t offset = formatSize * (xOffset + yOffset + zOffset) + _byteOffset;\n\n            int rc = fseek(fp, offset, SEEK_SET);\n            if (rc != 0) {\n                MyBase::SetErrMsg(\"Unable to seek on file: %M\");\n                return -1;\n            }\n\n            size_t fread_rc = fread(readBuffer, formatSize, count, fp);\n            if (fread_rc != count) {\n                if (ferror(fp) != 0) {\n                    MyBase::SetErrMsg(\"Error reading input file: %M\");\n                } else {\n                    MyBase::SetErrMsg(\"Short read on input file: %M\");\n                }\n                fclose(fp);\n                return -1;\n            }\n\n            if (_dataFormat == DC::XType::INT32) {\n                int *castBuffer = (int *)readBuffer;\n                for (size_t i = 0; i < count; i++) { *region++ = (typename std::remove_pointer<T>::type)castBuffer[i]; }\n            } else if (_dataFormat == DC::XType::FLOAT) {\n                float *castBuffer = (float *)readBuffer;\n                for (size_t i = 0; i < count; i++) { *region++ = (typename std::remove_pointer<T>::type)castBuffer[i]; }\n            } else if (_dataFormat == DC::XType::DOUBLE) {\n                double *castBuffer = (double *)readBuffer;\n                for (size_t i = 0; i < count; i++) { *region++ = (typename std::remove_pointer<T>::type)castBuffer[i]; }\n            }\n        }\n    }\n\n    fclose(fp);\n\n    return 0;\n}\n\n// ReadRegion can only be used with int* float* and double*\ntemplate int BOVCollection::ReadRegion<int *>(std::string varname, size_t ts, const std::vector<size_t> &, const std::vector<size_t> &, int *);\ntemplate int BOVCollection::ReadRegion<float *>(std::string varname, size_t ts, const std::vector<size_t> &, const std::vector<size_t> &, float *);\ntemplate int BOVCollection::ReadRegion<double *>(std::string varname, size_t ts, const std::vector<size_t> &, const std::vector<size_t> &, double *);\n"
  },
  {
    "path": "lib/vdc/BlkMemMgr.cpp",
    "content": "#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <cerrno>\n#include <iostream>\n#include <new>\n#ifndef WIN32\n    #include <unistd.h>\n#endif\n\n#include <vapor/BlkMemMgr.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n//\tStatic member initialization\n//\nbool   BlkMemMgr::_page_aligned_req = true;\nsize_t BlkMemMgr::_mem_size_max_req = 32768;\nsize_t BlkMemMgr::_blk_size_req = 32 * 32 * 32;\n\nbool   BlkMemMgr::_page_aligned = false;\nsize_t BlkMemMgr::_mem_size_max = 0;\nsize_t BlkMemMgr::_blk_size = 0;\n\nvector<size_t>                               BlkMemMgr::_mem_region_sizes;\nvector<unsigned char *>                      BlkMemMgr::_blks;\nvector<vector<BlkMemMgr::_mem_allocation_t>> BlkMemMgr::_mem_regions;\n#ifdef VAPOR3_0_0_ALPHA\n#endif\n\nint BlkMemMgr::_ref_count = 0;\n\nint BlkMemMgr::_Reinit(size_t n)\n{\n    long   page_size = 0;\n    size_t size = 0;\n\n    if (_mem_size_max_req == 0 || _blk_size_req == 0) return (false);\n\n    _page_aligned = _page_aligned_req;\n    _mem_size_max = _mem_size_max_req;\n    _blk_size = _blk_size_req;\n\n    //\n    // Calculate starting region size\n    //\n    size_t mem_size = n;\n\n    //\n    // How much total memory already allocated\n    //\n    size_t total_size = 0;\n    int    r;\n    for (r = 0; r < _mem_regions.size(); r++) total_size += _mem_region_sizes[r];\n\n    //\n    // New region size is double preceding one\n    //\n    if (r > 0) mem_size = _mem_region_sizes[r - 1] << 1;\n\n    // Make sure region size will be large enough, and not too large\n    //\n    if (mem_size < n) mem_size = n;\n    if ((mem_size + total_size) > _mem_size_max) mem_size = _mem_size_max - total_size;\n\n    if (mem_size < n) return (false);\n\n    if (_page_aligned) {\n#ifdef WIN32\n        page_size = 4096;\n#else\n        page_size = sysconf(_SC_PAGESIZE);\n        if (page_size < 0) page_size = 0;\n#endif\n    }\n\n    unsigned char *blks;\n    do {\n        size = (size_t)_blk_size * (size_t)mem_size;\n        size += (size_t)page_size;\n\n        blks = new (nothrow) unsigned char[size];\n        if (!blks) {\n            SetDiagMsg(\"BlkMemMgr::_Reinit() : failed to allocate %d blocks, retrying\", mem_size);\n            mem_size = mem_size >> 1;\n        }\n    } while (blks == NULL && mem_size > 0 && _blk_size > 0);\n\n    if (!blks && mem_size > 0 && _blk_size > 0) {\n        SetDiagMsg(\"Memory allocation of %lu bytes failed\", size);\n        return (false);\n    } else {\n        SetDiagMsg(\"BlkMemMgr() : allocated %lu bytes\", size);\n    }\n\n    unsigned char *blkptr = blks;\n\n    if (page_size) { blkptr += page_size - (((size_t)blks) % page_size); }\n\n    _mem_allocation_t         m;\n    vector<_mem_allocation_t> mem_region;\n    m._nfree = mem_size;\n    m._nused = 0;\n    m._blk = blkptr;\n    mem_region.push_back(m);\n\n    _mem_regions.push_back(mem_region);\n    _blks.push_back(blks);\n    _mem_region_sizes.push_back(mem_size);\n\n    return (true);\n}\n\nint BlkMemMgr::RequestMemSize(size_t blk_size, size_t num_blks, bool page_aligned)\n{\n    SetDiagMsg(\"BlkMemMgr::RequestMemSize(%u,%u,%d)\", blk_size, num_blks, page_aligned);\n\n    //\n    // If there are no instances of this object, re-initialized\n    // the static memory pool if needed\n    //\n    if (blk_size == 0 || num_blks == 0) {\n        SetErrMsg(\"Invalid request\");\n        return (-1);\n    }\n\n    _blk_size_req = blk_size;\n    _mem_size_max_req = num_blks;\n    _page_aligned_req = page_aligned;\n\n    return (0);\n}\n\nBlkMemMgr::BlkMemMgr()\n{\n    SetDiagMsg(\"BlkMemMgr::BlkMemMgr()\");\n\n    //\n    // If there are no other instances of this object, re-initialized\n    // the static memory pool if needed\n    //\n    if (_ref_count != 0) {\n        _ref_count++;\n        return;\n    }\n\n    for (int i = 0; i < _blks.size(); i++) {\n        if (_blks[i]) delete[] _blks[i];\n    }\n    _mem_regions.clear();\n    _mem_region_sizes.clear();\n    _blks.clear();\n\n    _page_aligned = _page_aligned_req;\n    _mem_size_max = _mem_size_max_req;\n    _blk_size = _blk_size_req;\n\n    _ref_count = 1;\n}\n\nBlkMemMgr::~BlkMemMgr()\n{\n    SetDiagMsg(\"BlkMemMgr::~BlkMemMgr()\");\n\n    if (_ref_count > 0) _ref_count--;\n\n    if (_ref_count != 0) return;\n\n    for (int i = 0; i < _blks.size(); i++) {\n        if (_blks[i]) delete[] _blks[i];\n    }\n    _blks.clear();\n    _mem_regions.clear();\n    _mem_region_sizes.clear();\n}\n\nvoid *BlkMemMgr::Alloc(size_t n, bool fill)\n{\n    SetDiagMsg(\"BlkMemMgr::Alloc(%d)\", n);\n\n    //\n    // Check each region, find the first run of blocks large enough\n    // to satisfy the request\n    //\n    void *blk = NULL;\n    for (int r = 0; r < _mem_regions.size() && !blk; r++) {\n        vector<_mem_allocation_t> &mem_region = _mem_regions[r];\n        for (int i = 0; i < mem_region.size() && !blk; i++) {\n            if (n <= mem_region[i]._nfree) {    // Found a run of blocks\n                blk = mem_region[i]._blk;\n                mem_region[i]._nused = n;\n\n                //\n                // If run is strictly larger than request split it\n                //\n                if (n < mem_region[i]._nfree) {\n                    _mem_allocation_t m;\n                    m._nfree = mem_region[i]._nfree - n;\n                    m._nused = 0;\n                    m._blk = (unsigned char *)mem_region[i]._blk + (_blk_size * n);\n                    mem_region.insert(mem_region.begin() + i + 1, m);\n                }\n                mem_region[i]._nfree = 0;\n            }\n        }\n    }\n\n    if (!blk) {\n        // Couldn't find space in existing memory pool.\n        // Try to allocate more memory.\n        //\n        if (!BlkMemMgr::_Reinit(n)) return (NULL);\n\n        return (Alloc(n, fill));\n    }\n\n    if (fill) {\n        unsigned char *ptr = (unsigned char *)blk;\n        for (size_t i = 0; i < n * _blk_size; i++) ptr[i] = 0;\n    }\n\n    return (blk);\n}\n\nvoid BlkMemMgr::FreeMem(void *ptr)\n{\n    SetDiagMsg(\"BlkMemMgr::FreeMem()\");\n\n    bool found = false;\n    for (int r = 0; r < _mem_regions.size() && !found; r++) {\n        vector<_mem_allocation_t> &mem_region = _mem_regions[r];\n        for (int i = 0; i < mem_region.size() && !found; i++) {\n            if (ptr == mem_region[i]._blk) {\n                found = true;\n                mem_region[i]._nfree = mem_region[i]._nused;\n                mem_region[i]._nused = 0;\n            }\n        }\n    }\n    if (!found) cerr << \"Failed to free block \" << ptr << endl;\n\n    //\n    // Collapse any two adjacent runs of they're both free\n    //\n    bool collapse;\n    do {\n        collapse = false;\n        for (int r = 0; r < _mem_regions.size(); r++) {\n            vector<_mem_allocation_t> &mem_region = _mem_regions[r];\n            for (int i = 0; i < mem_region.size() - 1; i++) {\n                if (mem_region[i]._nfree && mem_region[i + 1]._nfree) {\n                    mem_region[i]._nfree += mem_region[i + 1]._nfree;\n                    mem_region.erase(mem_region.begin() + i + 1);\n                    collapse = true;\n                    break;\n                }\n            }\n        }\n    } while (collapse);\n}\n"
  },
  {
    "path": "lib/vdc/CMakeLists.txt",
    "content": "set (SRC\n\tBlkMemMgr.cpp\n\tGrid.cpp\n\tConstantGrid.cpp\n\tStructuredGrid.cpp\n\tRegularGrid.cpp\n\tStretchedGrid.cpp\n\tLayeredGrid.cpp\n\tCurvilinearGrid.cpp\n\tUnstructuredGrid.cpp\n\tUnstructuredGrid2D.cpp\n\tUnstructuredGrid3D.cpp\n\tUnstructuredGridLayered.cpp\n\tArbitrarilyOrientedRegularGrid.cpp\n\tNetCDFSimple.cpp\n\tNetCDFCollection.cpp\n\tNetCDFCFCollection.cpp\n    BOVCollection.cpp\n\tUDUnitsClass.cpp\n\tProj4API.cpp\n\tDC.cpp\n\tDCWRF.cpp\n\tDCCF.cpp\n\tDCBOV.cpp\n\tDCMPAS.cpp\n\tDCP.cpp\n    DCRAM.cpp\n    DCMelanie.cpp\n\tVDC.cpp\n\tVDCNetCDF.cpp\n\tDerivedVar.cpp\n    DerivedParticleDensity.cpp\n\tDerivedVarMgr.cpp\n\tDataMgr.cpp\n\tPythonDataMgr.cpp\n\tGridHelper.cpp\n\tDataMgrUtils.cpp\n\tGeoUtil.cpp\n\tvizutil.cpp\n\tKDTreeRG.cpp\n\tkdtree.c\n\tVDC_c.cpp\n\tDCUtils.cpp\n\tQuadTreeRectangleP.cpp\n    DCUGRID.cpp\n)\n\nset (HEADERS\n\t${PROJECT_SOURCE_DIR}/include/vapor/BlkMemMgr.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Grid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GridHelper.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ConstantGrid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/StructuredGrid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/RegularGrid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/StretchedGrid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/LayeredGrid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/CurvilinearGrid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGrid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGrid2D.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGrid3D.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGridLayered.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/ArbitrarilyOrientedRegularGrid.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/NetCDFSimple.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/NetCDFCollection.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/NetCDFCFCollection.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/BOVCollection.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/UDUnitsClass.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/Proj4API.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DC.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DCWRF.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DCCF.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DCBOV.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DCMPAS.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DCP.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/DCRAM.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DCMelanie.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VDC.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VDCNetCDF.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DataMgr.h\n    ${PROJECT_SOURCE_DIR}/include/vapor/PythonDataMgr.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DataMgrUtils.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/GeoUtil.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/vizutil.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/KDTreeRG.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/VDC_c.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DerivedVar.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DerivedParticleDensity.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DerivedVarMgr.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DCUtils.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/QuadTreeRectangle.hpp\n\t${PROJECT_SOURCE_DIR}/include/vapor/QuadTreeRectangleP.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/OpenMPSupport.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/DCUGRID.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/UnstructuredGridCoordless.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/SetHDF5PluginPath.h\n)\n\nadd_library (vdc SHARED ${SRC} ${HEADERS})\n\nif( USE_OMP )\n  target_compile_options( vdc PUBLIC ${OpenMP_CXX_FLAGS} )\n  target_compile_definitions (vdc PUBLIC USE_OMP)\n  target_link_libraries (vdc PUBLIC OpenMP::OpenMP_CXX)\nelseif( NOT WIN32 )\n  target_compile_options( vdc PUBLIC \"-Wno-unknown-pragmas\" )\nendif()\n\ntarget_link_libraries (vdc PUBLIC common wasp ${UDUNITS2} ${PROJ})\n\nadd_definitions (-DVDF_EXPORTS)\n\nOpenMPInstall (\n    TARGETS vdc\n    DESTINATION ${INSTALL_LIB_DIR}\n    COMPONENT Libraries\n)\n\n\ninstall (\n\tFILES ${HEADERS}\n\tDESTINATION ${INSTALL_INCLUDE_DIR}\n\tCOMPONENT Libraries\n\t)\n"
  },
  {
    "path": "lib/vdc/ConstantGrid.cpp",
    "content": "#include <limits>\n\n#include \"vapor/ConstantGrid.h\"\n\nusing VAPoR::ConstantGrid;\n\nConstantGrid::ConstantGrid(float v, size_t d) : _value(v), _topologyDim(d) {}\n\nfloat ConstantGrid::GetConstantValue() const { return _value; }\n\nfloat ConstantGrid::GetValue(const VAPoR::CoordType &coords) const { return _value; }\nfloat ConstantGrid::GetValueNearestNeighbor(const VAPoR::CoordType &coords) const { return _value; }\n\nfloat ConstantGrid::GetValueLinear(const VAPoR::CoordType &coords) const { return _value; }\n\nstd::string ConstantGrid::GetType() const\n{\n    std::string type(\"ConstantGrid\");\n    return type;\n}\n\nsize_t ConstantGrid::GetTopologyDim() const { return _topologyDim; }\n\nvoid ConstantGrid::GetUserExtentsHelper(VAPoR::CoordType &minu, VAPoR::CoordType &maxu) const\n{\n    for (int i = 0; i < minu.size(); i++) {\n        minu[i] = std::numeric_limits<double>::lowest();\n        maxu[i] = std::numeric_limits<double>::max();\n    }\n}\n\nbool ConstantGrid::InsideGrid(const VAPoR::CoordType &coords) const { return true; }\n\nVAPoR::DimsType ConstantGrid::GetCoordDimensions(size_t) const { return (VAPoR::DimsType{1, 1, 1}); }\n\nsize_t ConstantGrid::GetGeometryDim() const { return 3; }\n\nconst VAPoR::DimsType &ConstantGrid::GetNodeDimensions() const { return (GetDimensions()); }\n\nconst size_t ConstantGrid::GetNumNodeDimensions() const { return (GetNumDimensions()); }\n\nconst VAPoR::DimsType &ConstantGrid::GetCellDimensions() const\n{\n    _duplicate = GetDimensions();\n    return _duplicate;\n}\n\nconst size_t ConstantGrid::GetNumCellDimensions() const { return (GetNumDimensions()); }\n\nbool ConstantGrid::GetIndicesCell(const VAPoR::CoordType &coords, VAPoR::DimsType &indices) const { return false; }\n\nbool ConstantGrid::GetCellNodes(const VAPoR::DimsType &cindices, std::vector<VAPoR::DimsType> &nodes) const { return false; }\n\nbool ConstantGrid::GetCellNeighbors(const VAPoR::DimsType &cindices, std::vector<VAPoR::DimsType> &cells) const { return false; }\n\nbool ConstantGrid::GetNodeCells(const VAPoR::DimsType &cindices, std::vector<VAPoR::DimsType> &cells) const { return false; }\n\nsize_t ConstantGrid::GetMaxVertexPerFace() const { return 0; }\n\nsize_t ConstantGrid::GetMaxVertexPerCell() const { return 0; }\n\nVAPoR::Grid::ConstCoordItr ConstantGrid::ConstCoordBegin() const { return VAPoR::Grid::ConstCoordItr(); }\n\nVAPoR::Grid::ConstCoordItr ConstantGrid::ConstCoordEnd() const { return VAPoR::Grid::ConstCoordItr(); }\n"
  },
  {
    "path": "lib/vdc/CurvilinearGrid.cpp",
    "content": "#include <stdio.h>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <cfloat>\n#include <limits>\n#include <vapor/utils.h>\n#include <vapor/CurvilinearGrid.h>\n#include <vapor/QuadTreeRectangleP.h>\n#include <vapor/vizutil.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nvoid CurvilinearGrid::_curvilinearGrid(const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg, const vector<double> &zcoords, std::shared_ptr<const QuadTreeRectangleP> qtr)\n{\n    _zcoords.clear();\n    _xrg = xrg;\n    _yrg = yrg;\n    _zrg = zrg;\n\n    _zcoords = zcoords;\n\n    GetUserExtentsHelper(_minu, _maxu);\n\n    _qtr = qtr;\n    if (!_qtr) { _qtr = _makeQuadTreeRectangle(); }\n}\n\nCurvilinearGrid::CurvilinearGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, const vector<double> &zcoords,\n                                 std::shared_ptr<const QuadTreeRectangleP> qtr)\n: StructuredGrid(dims, bs, blks)\n{\n    // Only support 2D X & Y coordinates currently. I.e. only support\n    // \"layered\" curvilinear grids\n    //\n    VAssert(xrg.GetNumDimensions() == 2);\n    VAssert(yrg.GetNumDimensions() == 2);\n    VAssert(zcoords.size() == 0 || zcoords.size() == dims[2]);\n\n    _terrainFollowing = false;\n    _curvilinearGrid(xrg, yrg, RegularGrid(), zcoords, qtr);\n}\n\nCurvilinearGrid::CurvilinearGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg,\n                                 std::shared_ptr<const QuadTreeRectangleP> qtr)\n: StructuredGrid(dims, bs, blks)\n{\n    // Only support 2D X & Y coordinates currently. I.e. only support\n    // \"layered\" curvilinear grids\n    //\n    VAssert(xrg.GetNumDimensions() == 2);\n    VAssert(yrg.GetNumDimensions() == 2);\n    VAssert(zrg.GetNumDimensions() == 3);\n\n    _terrainFollowing = true;\n    _curvilinearGrid(xrg, yrg, zrg, vector<double>(), qtr);\n}\n\nCurvilinearGrid::CurvilinearGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, std::shared_ptr<const QuadTreeRectangleP> qtr)\n: StructuredGrid(dims, bs, blks)\n{\n    // Only support 2D X & Y coordinates currently. I.e. only support\n    // \"layered\" curvilinear grids\n    //\n    VAssert(xrg.GetNumDimensions() == 2);\n    VAssert(yrg.GetNumDimensions() == 2);\n\n    _terrainFollowing = false;\n    _curvilinearGrid(xrg, yrg, RegularGrid(), vector<double>(), qtr);\n}\n\nCurvilinearGrid::CurvilinearGrid(const vector<size_t> &dimsv, const vector<size_t> &bsv, const vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, const vector<double> &zcoords,\n                                 std::shared_ptr<const QuadTreeRectangleP> qtr)\n: StructuredGrid(dimsv, bsv, blks)\n{\n    VAssert(dimsv.size() == 2 || dimsv.size() == 3);\n    VAssert(bsv.size() == dimsv.size());\n\n    // Only support 2D X & Y coordinates currently. I.e. only support\n    // \"layered\" curvilinear grids\n    //\n    VAssert(xrg.GetNumDimensions() == 2);\n    VAssert(yrg.GetNumDimensions() == 2);\n    VAssert(zcoords.size() == 0 || zcoords.size() == dimsv[2]);\n\n    _terrainFollowing = false;\n\n    DimsType dims = {1, 1, 1};\n    DimsType bs = {1, 1, 1};\n    CopyToArr3(dimsv, dims);\n    CopyToArr3(bsv, bs);\n    _curvilinearGrid(xrg, yrg, RegularGrid(), zcoords, qtr);\n}\n\nCurvilinearGrid::CurvilinearGrid(const vector<size_t> &dimsv, const vector<size_t> &bsv, const vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg, const RegularGrid &zrg,\n                                 std::shared_ptr<const QuadTreeRectangleP> qtr)\n: StructuredGrid(dimsv, bsv, blks)\n{\n    VAssert(dimsv.size() == 3);\n    VAssert(bsv.size() == dimsv.size());\n\n    _terrainFollowing = true;\n\n    DimsType dims = {1, 1, 1};\n    DimsType bs = {1, 1, 1};\n    CopyToArr3(dimsv, dims);\n    CopyToArr3(bsv, bs);\n    _curvilinearGrid(xrg, yrg, zrg, vector<double>(), qtr);\n}\n\nCurvilinearGrid::CurvilinearGrid(const vector<size_t> &dimsv, const vector<size_t> &bsv, const vector<float *> &blks, const RegularGrid &xrg, const RegularGrid &yrg,\n                                 std::shared_ptr<const QuadTreeRectangleP> qtr)\n: StructuredGrid(dimsv, bsv, blks)\n{\n    VAssert(dimsv.size() == 2);\n    VAssert(bsv.size() == dimsv.size());\n\n    // Only support 2D X & Y coordinates currently. I.e. only support\n    // \"layered\" curvilinear grids\n    //\n    VAssert(xrg.GetNumDimensions() == 2);\n    VAssert(yrg.GetNumDimensions() == 2);\n\n    _terrainFollowing = false;\n\n    DimsType dims = {1, 1, 1};\n    DimsType bs = {1, 1, 1};\n    CopyToArr3(dimsv, dims);\n    CopyToArr3(bsv, bs);\n    _curvilinearGrid(xrg, yrg, RegularGrid(), vector<double>(), qtr);\n}\n\nDimsType CurvilinearGrid::GetCoordDimensions(size_t dim) const\n{\n    DimsType dims = {1, 1, 1};\n\n    if (dim == 0) {\n        dims = _xrg.GetDimensions();\n    } else if (dim == 1) {\n        dims = _yrg.GetDimensions();\n    } else if (dim == 2) {\n        if (_terrainFollowing) { dims = _zrg.GetDimensions(); }\n    }\n\n    return (dims);\n}\n\nvoid CurvilinearGrid::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const\n{\n    DimsType cMin;\n    ClampIndex(min, cMin);\n\n    DimsType cMax;\n    ClampIndex(max, cMax);\n\n    for (int i = 0; i < GetGeometryDim(); i++) { VAssert(cMin[i] <= cMax[i]); }\n\n    for (int i = 0; i < minu.size(); i++) {\n        minu[i] = 0.0;\n        maxu[i] = 0.0;\n    }\n\n    // Get the horiztonal (X & Y) extents by visiting every point\n    // on a single plane (horizontal coordinates are constant over Z).\n    //\n    vector<size_t> min2d = {cMin[0], cMin[1]};\n    vector<size_t> max2d = {cMax[0], cMax[1]};\n    float          xrange[2], yrange[2];\n    _xrg.GetRange(min2d, max2d, xrange);\n    _yrg.GetRange(min2d, max2d, yrange);\n\n    minu[0] = xrange[0];\n    minu[1] = yrange[0];\n    maxu[0] = xrange[1];\n    maxu[1] = yrange[1];\n\n    // We're done if 2D grid\n    //\n    if (GetGeometryDim() == 2) return;\n\n    if (_terrainFollowing) {\n        float zrange[2];\n        _zrg.GetRange(cMin, cMax, zrange);\n\n        minu[2] = zrange[0];\n        maxu[2] = zrange[1];\n    } else {\n        minu[2] = _zcoords[cMin[2]];\n        maxu[2] = _zcoords[cMax[2]];\n    }\n}\n\nvoid CurvilinearGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const\n{\n    DimsType cIndices;\n    ClampIndex(indices, cIndices);\n\n    coords[0] = _xrg.AccessIJK(cIndices[0], cIndices[1]);\n    coords[1] = _yrg.AccessIJK(cIndices[0], cIndices[1]);\n\n    if (GetGeometryDim() < 3) return;\n\n    if (_terrainFollowing) {\n        coords[2] = _zrg.AccessIJK(cIndices[0], cIndices[1], cIndices[2]);\n    } else {\n        coords[2] = _zcoords[cIndices[2]];\n    }\n}\n\nbool CurvilinearGrid::GetIndicesCell(const CoordType &coords, DimsType &indices) const\n{\n    // Clamp coordinates on periodic boundaries to grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    double x = cCoords[0];\n    double y = cCoords[1];\n    double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0;\n\n    double lambda[4], zwgt[2];\n    size_t i, j, k;\n    bool   inside = _insideGrid(x, y, z, i, j, k, lambda, zwgt);\n\n    if (!inside) return (false);\n\n    indices[0] = i;\n    indices[1] = j;\n\n    if (GetGeometryDim() == 2) return (true);\n\n    indices[2] = k;\n\n    return (true);\n}\n\nbool CurvilinearGrid::InsideGrid(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to reside within the\n    // grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    // Do a quick check to see if the point is completely outside of\n    // the grid bounds.\n    //\n    VAssert(GetGeometryDim() <= 3);\n    for (int i = 0; i < GetGeometryDim(); i++) {\n        if (cCoords[i] < _minu[i] || cCoords[i] > _maxu[i]) return (false);\n    }\n\n    double lambda[4], zwgt[2];\n    size_t i, j, k;    // not used\n    double x = cCoords[0];\n    double y = cCoords[1];\n    double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0;\n\n    bool inside = _insideGrid(x, y, z, i, j, k, lambda, zwgt);\n\n    return (inside);\n}\n\nCurvilinearGrid::ConstCoordItrCG::ConstCoordItrCG(const CurvilinearGrid *cg, bool begin) : ConstCoordItrAbstract()\n{\n    _cg = cg;\n    auto dims = _cg->GetDimensions();\n    _index = {0, 0, 0};\n    _coords = {0.0, 0.0, 0.0};\n    _terrainFollowing = _cg->_terrainFollowing;\n    if (begin) {\n        _xCoordItr = _cg->_xrg.cbegin();\n        _yCoordItr = _cg->_yrg.cbegin();\n        if (_terrainFollowing) { _zCoordItr = _cg->_zrg.cbegin(); }\n    } else {\n        _xCoordItr = _cg->_xrg.cend();\n        _yCoordItr = _cg->_yrg.cend();\n        if (_terrainFollowing) { _zCoordItr = _cg->_zrg.cend(); }\n\n        _index = {0, 0, dims[dims.size() - 1]};\n\n        return;\n    }\n    _coords[0] = *_xCoordItr;\n    _coords[1] = *_yCoordItr;\n\n    if (_terrainFollowing) {\n        _coords[2] = *_zCoordItr;\n    } else {\n        if (_cg->_zcoords.size()) _coords[2] = _cg->_zcoords[0];\n    }\n}\n\nCurvilinearGrid::ConstCoordItrCG::ConstCoordItrCG(const ConstCoordItrCG &rhs) : ConstCoordItrAbstract()\n{\n    _cg = rhs._cg;\n    _index = rhs._index;\n    _coords = rhs._coords;\n    _xCoordItr = rhs._xCoordItr;\n    _yCoordItr = rhs._yCoordItr;\n    if (rhs._terrainFollowing) { _zCoordItr = rhs._zCoordItr; }\n    _terrainFollowing = rhs._terrainFollowing;\n}\n\nCurvilinearGrid::ConstCoordItrCG::ConstCoordItrCG() : ConstCoordItrAbstract()\n{\n    _cg = NULL;\n    _index = {0, 0, 0};\n    _coords = {0.0, 0.0, 0.0};\n}\n\nvoid CurvilinearGrid::ConstCoordItrCG::next()\n{\n    auto dims = _cg->GetDimensions();\n\n    _index[0]++;\n    ++_xCoordItr;\n    ++_yCoordItr;\n    if (_terrainFollowing) { ++_zCoordItr; }\n\n    if (_index[0] < dims[0]) {\n        _coords[0] = *_xCoordItr;\n        _coords[1] = *_yCoordItr;\n        if (_terrainFollowing) { _coords[2] = *_zCoordItr; }\n        return;\n    }\n\n    _index[0] = 0;\n    _index[1]++;\n\n    if (_index[1] < dims[1]) {\n        _coords[0] = *_xCoordItr;\n        _coords[1] = *_yCoordItr;\n        if (_terrainFollowing) { _coords[2] = *_zCoordItr; }\n        return;\n    }\n\n    _index[1] = 0;\n    _index[2]++;\n    if (_index[2] < dims[2]) {\n        _xCoordItr = _cg->_xrg.cbegin();\n        _yCoordItr = _cg->_yrg.cbegin();\n\n        _coords[0] = *_xCoordItr;\n        _coords[1] = *_yCoordItr;\n        if (_terrainFollowing) {\n            _coords[2] = *_zCoordItr;\n        } else {\n            _coords[2] = _cg->_zcoords[_index[2]];\n        }\n        return;\n    }\n\n    _index = {0, 0, dims[dims.size() - 1]};    // last index\n}\n\nvoid CurvilinearGrid::ConstCoordItrCG::next(const long &offset)\n{\n    auto dims = _cg->GetDimensions();\n    auto ndims = _cg->GetNumDimensions();\n\n    if (!ndims) return;\n\n    long maxIndexL = Wasp::VProduct(dims.data(), dims.size()) - 1;\n    long newIndexL = Wasp::LinearizeCoords(_index.data(), dims.data(), dims.size()) + offset;\n    if (newIndexL < 0) { newIndexL = 0; }\n    if (newIndexL > maxIndexL) {\n        _index = {0, 0, dims[dims.size() - 1]};\n        return;\n    }\n\n    size_t index2DL = _index[1] * dims[0] + _index[0];\n\n    _index = {0, 0, 0};\n    Wasp::VectorizeCoords(newIndexL, dims.data(), _index.data(), dims.size());\n\n    VAssert(_index[1] * dims[0] + _index[0] >= index2DL);\n    size_t offset2D = (_index[1] * dims[0] + _index[0]) - index2DL;\n\n    _xCoordItr += offset2D;\n    _yCoordItr += offset2D;\n\n    _coords[0] = *_xCoordItr;\n    _coords[1] = *_yCoordItr;\n\n    if (_terrainFollowing) {\n        _zCoordItr += offset;\n        _coords[2] = *_zCoordItr;\n    } else {\n        _coords[2] = _cg->_zcoords[_index[2]];\n    }\n}\n\nfloat CurvilinearGrid::GetValueNearestNeighbor(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    double lambda[4], zwgt[2];\n    size_t i, j, k;\n    double x = cCoords[0];\n    double y = cCoords[1];\n    double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0;\n    bool   inside = _insideGrid(x, y, z, i, j, k, lambda, zwgt);\n\n    if (!inside) return (GetMissingValue());\n\n    // Find closest point within face\n    //\n    double maxl = lambda[0];\n    int    maxidx = 0;\n    for (int idx = 1; idx < 4; idx++) {\n        if (lambda[idx] > maxl) {\n            maxl = lambda[idx];\n            maxidx = idx;\n        }\n    }\n    if (maxidx == 1) {\n        i++;\n    } else if (maxidx == 2) {\n        i++;\n        j++;\n    } else if (maxidx == 3) {\n        j++;\n    }\n\n    if (zwgt[1] > zwgt[0]) k++;\n\n    return (AccessIJK(i, j, k));\n}\n\nnamespace {\n\nfloat interpolateQuad(const float values[4], const double lambda[4], float mv)\n{\n    // Special handling for any missing values\n    //\n    if (std::any_of(values, values + 4, [&mv](float v) { return (mv == v); })) {\n        double lambda0[] = {lambda[0], lambda[1], lambda[2], lambda[3]};\n        float  values0[] = {values[0], values[1], values[2], values[3]};\n\n        // Find missing values. Zero out weight\n        //\n        double wTotal = 0.0;\n        int    nMissing = 0;\n        for (int i = 0; i < 4; i++) {\n            if (values0[i] == mv) {\n                lambda0[i] = 0.0;\n                values0[i] = 0.0;\n                nMissing++;\n            } else {\n                wTotal += lambda0[i];\n            }\n        }\n\n        if (nMissing == 4) return (mv);\n        if (wTotal == 0.0) return (mv);\n\n        // Re-normalize weights if we have missing values\n        //\n        if (nMissing) {\n            wTotal = 1.0 / wTotal;\n            for (int i = 0; i < 4; i++) { lambda0[i] *= wTotal; }\n        }\n        float v = 0.0;\n        for (int i = 0; i < 4; i++) { v += values0[i] * lambda0[i]; }\n        return (v);\n    } else {\n        float v = 0.0;\n        for (int i = 0; i < 4; i++) { v += values[i] * lambda[i]; }\n        return (v);\n    }\n}\n};    // namespace\n\nfloat CurvilinearGrid::GetValueLinear(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    // Get Wachspress coordinates for horizontal weights, and\n    // simple linear interpolation weights for vertical axis. _insideGrid\n    // handlese case where grid is 2D. I.e. if 2d then zwgt[0] == 1 &&\n    // zwgt[1] = 0.0\n    //\n    double lambda[4], zwgt[2];\n    size_t i, j, k;\n    double x = cCoords[0];\n    double y = cCoords[1];\n    double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0;\n    bool   inside = _insideGrid(x, y, z, i, j, k, lambda, zwgt);\n\n    float mv = GetMissingValue();\n\n    if (!inside) return (mv);\n\n    // Use Wachspress coordinates as weights to do linear interpolation\n    // along XY plane\n    //\n    auto dims = GetDimensions();\n    VAssert(i < dims[0] - 1);\n    VAssert(j < dims[1] - 1);\n    if (GetNumDimensions() > 2) VAssert(k < dims[2]);\n\n    float v0s[] = {AccessIJK(i, j, k), AccessIJK(i + 1, j, k), AccessIJK(i + 1, j + 1, k), AccessIJK(i, j + 1, k)};\n\n    float v0 = interpolateQuad(v0s, lambda, mv);\n\n    if (GetGeometryDim() == 2 || dims[2] < 2) return (v0);\n\n    if (v0 == mv && zwgt[0] != 0.0) return (mv);\n\n    float v1s[] = {AccessIJK(i, j, k + 1), AccessIJK(i + 1, j, k + 1), AccessIJK(i + 1, j + 1, k + 1), AccessIJK(i, j + 1, k + 1)};\n\n    float v1 = interpolateQuad(v1s, lambda, mv);\n\n    if (v1 == mv && zwgt[1] != 0.0) return (mv);\n\n    // Linearly interpolate along Z axis\n    //\n    if (zwgt[0] == 0.0)\n        return (v1);\n    else if (zwgt[1] == 0.0)\n        return (v0);\n    else\n        return (v0 * zwgt[0] + v1 * zwgt[1]);\n}\n\nvoid CurvilinearGrid::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const\n{\n    // Get the horiztonal (X & Y) extents by visiting every point\n    // on a single plane (horizontal coordinates are constant over Z).\n    //\n    float xrange[2], yrange[2];\n    _xrg.GetRange(xrange);\n    _yrg.GetRange(yrange);\n\n    minu[0] = xrange[0];\n    minu[1] = yrange[0];\n    maxu[0] = xrange[1];\n    maxu[1] = yrange[1];\n\n    // We're done if 2D grid\n    //\n    if (GetGeometryDim() == 2) return;\n\n    if (_terrainFollowing) {\n        float zrange[2];\n        _zrg.GetRange(zrange);\n\n        minu[2] = zrange[0];\n        maxu[2] = zrange[1];\n    } else {\n        minu[2] = _zcoords[0];\n        maxu[2] = _zcoords[_zcoords.size() - 1];\n    }\n}\n\nbool CurvilinearGrid::_insideGridHelperStretched(double z, size_t &k, double zwgt[2]) const\n{\n    // Now verify that Z coordinate of point is in grid, and find\n    // its interpolation weights if so.\n    //\n    size_t kFound = 0;\n\n    if (!Wasp::BinarySearchRange(_zcoords, z, kFound)) return (false);\n\n    k = kFound;\n    zwgt[0] = 1.0 - (z - _zcoords[k]) / (_zcoords[k + 1] - _zcoords[k]);\n    zwgt[1] = 1.0 - zwgt[0];\n\n    return (true);\n}\n\nbool CurvilinearGrid::_insideGridHelperTerrain(double x, double y, double z, const size_t &i, const size_t &j, size_t &k, double zwgt[2]) const\n{\n    // XZ and YZ cell sides are planar, but XY sides may not be. We divide\n    // the XY faces into two triangles (changing hexahedrals into prims)\n    // and figure out which triangle (prism) the point is in (first or\n    // second). Then we search the stack of first (or second) prism in Z\n    //\n    //\n\n    // Check if point is in \"first\" triangle (0,0), (1,0), (1,1)\n    //\n    double   lambda[3];\n    double   pt[] = {x, y};\n    DimsType iv = {i, i + 1, i + 1};\n    DimsType jv = {j, j, j + 1};\n    double   tverts0[] = {_xrg.AccessIJK(iv[0], jv[0], 0), _yrg.AccessIJK(iv[0], jv[0], 0), _xrg.AccessIJK(iv[1], jv[1], 0),\n                        _yrg.AccessIJK(iv[1], jv[1], 0), _xrg.AccessIJK(iv[2], jv[2], 0), _yrg.AccessIJK(iv[2], jv[2], 0)};\n\n    bool inside = VAPoR::BarycentricCoordsTri(tverts0, pt, lambda);\n    if (!inside) {\n        // Not in first triangle.\n        // Now check if point is in \"second\" triangle (0,0), (1,1), (0,1)\n        //\n        iv = {i, i + 1, i};\n        jv = {j, j + 1, j + 1};\n        double tverts1[] = {_xrg.AccessIJK(iv[0], jv[0], 0), _yrg.AccessIJK(iv[0], jv[0], 0), _xrg.AccessIJK(iv[1], jv[1], 0),\n                            _yrg.AccessIJK(iv[1], jv[1], 0), _xrg.AccessIJK(iv[2], jv[2], 0), _yrg.AccessIJK(iv[2], jv[2], 0)};\n\n        inside = VAPoR::BarycentricCoordsTri(tverts1, pt, lambda);\n        if (!inside) return (false);\n    }\n\n    float z0, z1;\n\n    // Find k index of cell containing z. Already know i and j indices\n    //\n    size_t         nz = GetDimensions()[2];\n    vector<double> zcoords(nz);\n    for (int kk = 0; kk < nz; kk++) {\n        // Interpolate Z coordinate across triangle\n        //\n        float zk = _zrg.AccessIJK(iv[0], jv[0], kk) * lambda[0] + _zrg.AccessIJK(iv[1], jv[1], kk) * lambda[1] + _zrg.AccessIJK(iv[2], jv[2], kk) * lambda[2];\n\n        zcoords[kk] = zk;\n    }\n\n    if (!Wasp::BinarySearchRange(zcoords, z, k)) return (false);\n\n    z0 = zcoords[k];\n    z1 = k < nz - 1 ? zcoords[k + 1] : z0;\n\n    zwgt[0] = 1.0 - (z - z0) / (z1 - z0);\n    zwgt[1] = 1.0 - zwgt[0];\n\n    return (true);\n}\n\nbool CurvilinearGrid::_insideFace(const DimsType &face, double pt[2], double lambda[4], vector<DimsType> &nodes) const\n{\n    CoordType verts[4];    // space for 4 vertices with 3D user coordinates\n\n    size_t gDim = GetGeometryDim();\n\n    bool ok = GetCellNodes(face, nodes);\n    VAssert(ok);\n\n    // For 3D data GetCellNodes returns 3D cells. We only need the 2D\n    // bottom face (all cells in a vertical column have same horizontal\n    // coordinates\n    // for layered 3D data)\n    //\n    size_t n = nodes.size();\n    if (gDim > 2 && n == 8) n /= 2;\n    VAssert(n == 4);\n\n    // Get X and Y coordinates for each vertex making up the face\n    //\n    for (int i = 0; i < n; i++) { GetUserCoordinates(nodes[i], verts[i]); }\n\n    // The following functions operate on packed, raw arrays\n    //\n    double verts2d[] = {verts[0][0], verts[0][1], verts[1][0], verts[1][1], verts[2][0], verts[2][1], verts[3][0], verts[3][1]};\n    if (!Grid::PointInsideBoundingRectangle(pt, verts2d, 4)) { return (false); }\n\n    bool ret = WachspressCoords2D(verts2d, pt, 4, lambda);\n\n    return ret;\n}\n\n// Search for a point inside the grid. If the point is inside return true,\n// and provide the Wachspress weights/coordinates for the point within\n// the XY quadrilateral cell containing the point in XY, and the linear\n// interpolation weights/coordinates along Z. If the grid is 2D then\n// zwgt[0] == 1.0, and zwgt[1] == 0.0. If the point is outside of the\n// grid the values of 'lambda', and 'zwgt' are not defined\n//\nbool CurvilinearGrid::_insideGrid(double x, double y, double z, size_t &i, size_t &j, size_t &k, double lambda[4], double zwgt[2]) const\n{\n    for (int l = 0; l < 4; l++) lambda[l] = 0.0;\n    for (int l = 0; l < 2; l++) zwgt[l] = 0.0;\n    i = j = k = 0;\n\n    // Find the indices for the faces that might contain the point\n    //\n    vector<DimsType> face_indices;\n    _qtr->GetPayloadContained(x, y, face_indices);\n\n    bool             inside = false;\n    double           pt[] = {x, y};\n    vector<DimsType> nodes(8);\n    for (int ii = 0; ii < face_indices.size(); ii++) {\n        if (_insideFace(face_indices[ii], pt, lambda, nodes)) {\n            i = face_indices[ii][0];\n            j = face_indices[ii][1];\n\n            inside = true;\n            break;\n        }\n    }\n\n    if (!inside) return (false);\n\n    if (GetGeometryDim() == 2) {\n        zwgt[0] = 1.0;\n        zwgt[1] = 0.0;\n        return (true);\n    }\n\n    if (_terrainFollowing) {\n        return (_insideGridHelperTerrain(x, y, z, i, j, k, zwgt));\n    } else {\n        return (_insideGridHelperStretched(z, k, zwgt));\n    }\n}\n\nstd::shared_ptr<QuadTreeRectangleP> CurvilinearGrid::_makeQuadTreeRectangle() const\n{\n    const DimsType &dims = GetCellDimensions();\n    size_t          reserve_size = dims[0] * dims[1];\n\n    CoordType minu, maxu;\n    GetUserExtents(minu, maxu);\n\n    std::shared_ptr<QuadTreeRectangleP> qtr = std::make_shared<QuadTreeRectangleP>((float)minu[0], (float)minu[1], (float)maxu[0], (float)maxu[1], 12, reserve_size);\n\n    qtr->Insert(this, dims[0] * dims[1]);\n    return (qtr);\n}\n"
  },
  {
    "path": "lib/vdc/DC.cpp",
    "content": "#include \"vapor/VAssert.h\"\n#include <sstream>\n#include \"vapor/DC.h\"\n\nusing namespace VAPoR;\n\nnamespace {\n\nstring join(const vector<string> &v, string separator)\n{\n    string s;\n\n    for (int i = 0; i < (int)v.size() - 1; i++) {\n        s += v[i];\n        s += separator;\n    }\n\n    if (v.size()) { s += v[v.size() - 1]; }\n\n    return (s);\n}\n\n#ifdef UNUSED_FUNCTION\n// Product of elements in a vector\n//\nsize_t vproduct(vector<size_t> a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n#endif\n\n};    // namespace\n\nDC::Attribute::Attribute(string name, XType type, const vector<float> &values)\n{\n    _name = name;\n    _type = type;\n    _values.clear();\n    Attribute::SetValues(values);\n}\n\nvoid DC::Attribute::SetValues(const vector<float> &values)\n{\n    _values.clear();\n    vector<double> dvec;\n    for (int i = 0; i < values.size(); i++) { dvec.push_back((double)values[i]); }\n    DC::Attribute::SetValues(dvec);\n}\n\nDC::Attribute::Attribute(string name, XType type, const vector<double> &values)\n{\n    _name = name;\n    _type = type;\n    _values.clear();\n    Attribute::SetValues(values);\n}\n\nvoid DC::Attribute::SetValues(const vector<double> &values)\n{\n    _values.clear();\n    for (int i = 0; i < values.size(); i++) {\n        podunion pod;\n        if (_type == FLOAT) {\n            pod.f = (float)values[i];\n        } else if (_type == DOUBLE) {\n            pod.d = (double)values[i];\n        } else if (_type == INT32) {\n            pod.i = (int)values[i];\n        } else if (_type == INT64) {\n            pod.l = (int)values[i];\n        } else if (_type == TEXT) {\n            pod.c = (char)values[i];\n        }\n        _values.push_back(pod);\n    }\n}\n\nDC::Attribute::Attribute(string name, XType type, const vector<int> &values)\n{\n    _name = name;\n    _type = type;\n    _values.clear();\n    Attribute::SetValues(values);\n}\n\nvoid DC::Attribute::SetValues(const vector<int> &values)\n{\n    _values.clear();\n    vector<long> lvec;\n    for (int i = 0; i < values.size(); i++) { lvec.push_back((long)values[i]); }\n    DC::Attribute::SetValues(lvec);\n}\n\nDC::Attribute::Attribute(string name, XType type, const vector<long> &values)\n{\n    _name = name;\n    _type = type;\n    _values.clear();\n    Attribute::SetValues(values);\n}\n\nvoid DC::Attribute::SetValues(const vector<long> &values)\n{\n    _values.clear();\n\n    for (int i = 0; i < values.size(); i++) {\n        podunion pod;\n        if (_type == FLOAT) {\n            pod.f = (float)values[i];\n        } else if (_type == DOUBLE) {\n            pod.d = (double)values[i];\n        } else if (_type == INT32) {\n            pod.i = (int)values[i];\n        } else if (_type == INT64) {\n            pod.l = (long)values[i];\n        } else if (_type == TEXT) {\n            pod.c = (char)values[i];\n        }\n        _values.push_back(pod);\n    }\n}\n\nDC::Attribute::Attribute(string name, XType type, const string &values)\n{\n    _name = name;\n    _type = type;\n    _values.clear();\n    Attribute::SetValues(values);\n}\n\nvoid DC::Attribute::SetValues(const string &values)\n{\n    _values.clear();\n    for (int i = 0; i < values.size(); i++) {\n        podunion pod;\n        if (_type == FLOAT) {\n            pod.f = (float)values[i];\n        } else if (_type == DOUBLE) {\n            pod.d = (double)values[i];\n        } else if (_type == INT32) {\n            pod.i = (int)values[i];\n        } else if (_type == INT64) {\n            pod.l = (long)values[i];\n        } else if (_type == TEXT) {\n            pod.c = (char)values[i];\n        }\n        _values.push_back(pod);\n    }\n}\n\nvoid DC::Attribute::GetValues(vector<float> &values) const\n{\n    values.clear();\n\n    vector<double> dvec;\n    DC::Attribute::GetValues(dvec);\n    for (int i = 0; i < dvec.size(); i++) { values.push_back((float)dvec[i]); }\n}\n\nvoid DC::Attribute::GetValues(vector<double> &values) const\n{\n    values.clear();\n\n    for (int i = 0; i < _values.size(); i++) {\n        podunion pod = _values[i];\n        if (_type == FLOAT) {\n            values.push_back((double)pod.f);\n        } else if (_type == DOUBLE) {\n            values.push_back((double)pod.d);\n        } else if (_type == INT32) {\n            values.push_back((double)pod.i);\n        } else if (_type == INT64) {\n            values.push_back((double)pod.l);\n        } else if (_type == TEXT) {\n            values.push_back((double)pod.c);\n        }\n    }\n}\n\nvoid DC::Attribute::GetValues(vector<int> &values) const\n{\n    values.clear();\n\n    vector<long> lvec;\n    DC::Attribute::GetValues(lvec);\n    for (int i = 0; i < lvec.size(); i++) { values.push_back((int)lvec[i]); }\n}\n\nvoid DC::Attribute::GetValues(vector<long> &values) const\n{\n    values.clear();\n\n    for (int i = 0; i < _values.size(); i++) {\n        podunion pod = _values[i];\n        if (_type == FLOAT) {\n            values.push_back((long)pod.f);\n        } else if (_type == DOUBLE) {\n            values.push_back((long)pod.d);\n        } else if (_type == INT32) {\n            values.push_back((long)pod.i);\n        } else if (_type == INT64) {\n            values.push_back((long)pod.l);\n        } else if (_type == TEXT) {\n            values.push_back((long)pod.c);\n        }\n    }\n}\n\nvoid DC::Attribute::GetValues(string &values) const\n{\n    values.clear();\n\n    for (int i = 0; i < _values.size(); i++) {\n        podunion pod = _values[i];\n        if (_type == FLOAT) {\n            values += (char)pod.f;\n        } else if (_type == DOUBLE) {\n            values += (char)pod.d;\n        } else if (_type == INT32) {\n            values += (char)pod.i;\n        } else if (_type == INT64) {\n            values += (char)pod.l;\n        } else if (_type == TEXT) {\n            values += (char)pod.c;\n        }\n    }\n}\n\nDC::BaseVar::BaseVar(string name, string units, XType type, std::vector<bool> periodic) : _name(name), _units(units), _type(type), _periodic(periodic)\n{\n    _wname = \"\";\n    _cratios.push_back(1);\n}\n\nvoid DC::Mesh::_Mesh(string name, std::vector<string> coord_vars, int max_nodes_per_face, int max_faces_per_node, Mesh::Type mtype)\n{\n    _name.clear();\n    _dim_names.clear();\n    _coord_vars.clear();\n    _max_nodes_per_face = 1;\n    _max_faces_per_node = 1;\n    _node_dim_name.clear();\n    _face_dim_name.clear();\n    _layers_dim_name.clear();\n    _face_node_var.clear();\n    _node_face_var.clear();\n    _node_face_var.clear();\n    _face_edge_var.clear();\n    _face_face_var.clear();\n    _edge_dim_name.clear();\n    _edge_node_var.clear();\n    _edge_face_var.clear();\n    _mtype = STRUCTURED;\n\n    _name = name;\n    _coord_vars = coord_vars;\n    _max_nodes_per_face = max_nodes_per_face;\n    _max_faces_per_node = max_faces_per_node;\n    _mtype = mtype;\n}\n\nDC::Mesh::Mesh(std::string name, std::vector<string> dim_names, std::vector<string> coord_vars)\n{\n    VAssert(coord_vars.size() >= dim_names.size());\n\n    _Mesh(name, coord_vars, 4, 4, STRUCTURED);\n\n    if (_name.empty()) { _name = MakeMeshName(dim_names); }\n\n    _dim_names = dim_names;\n}\n\nDC::Mesh::Mesh(std::string name, size_t max_nodes_per_face, size_t max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::vector<std::string> coord_vars,\n               std::string face_node_var, std::string node_face_var)\n{\n    VAssert(coord_vars.size() >= 2);\n\n    _Mesh(name, coord_vars, max_nodes_per_face, max_faces_per_node, UNSTRUC_2D);\n\n    _node_dim_name = node_dim_name;\n    _face_dim_name = face_dim_name;\n    _face_node_var = face_node_var;\n    _node_face_var = node_face_var;\n\n    _dim_names.push_back(node_dim_name);\n}\n\nDC::Mesh::Mesh(std::string name, size_t max_nodes_per_face, size_t max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::string layers_dim_name,\n               std::vector<std::string> coord_vars, std::string face_node_var, std::string node_face_var)\n{\n    VAssert(coord_vars.size() == 3);\n\n    _Mesh(name, coord_vars, max_nodes_per_face, max_faces_per_node, UNSTRUC_LAYERED);\n\n    _node_dim_name = node_dim_name;\n    _face_dim_name = face_dim_name;\n    _layers_dim_name = layers_dim_name;\n    _face_node_var = face_node_var;\n    _node_face_var = node_face_var;\n\n    _dim_names.push_back(node_dim_name);\n    _dim_names.push_back(layers_dim_name);\n}\n\nDC::Mesh::Mesh(std::string name, int max_nodes_per_face, int max_faces_per_node, std::string node_dim_name, std::string face_dim_name, std::vector<string> coord_vars)\n{\n    _Mesh(name, coord_vars, max_nodes_per_face, max_faces_per_node, UNSTRUC_3D);\n\n    _node_dim_name = node_dim_name;\n    _face_dim_name = face_dim_name;\n\n    _dim_names.push_back(node_dim_name);\n}\n\nsize_t DC::Mesh::GetTopologyDim() const\n{\n    switch (_mtype) {\n    case STRUCTURED: return (_dim_names.size()); break;\n    case UNSTRUC_2D: return (2); break;\n    case UNSTRUC_LAYERED: return (3); break;\n    case UNSTRUC_3D: return (0); break;\n    default:\n        VAssert(false);\n        return (0);\n        break;\n    }\n}\n\nstring DC::Mesh::MakeMeshName(std::vector<string> s) { return (join(s, \"x\")); }\n\nDC::DC() {}\n\nint DC::GetHyperSliceInfo(string varname, int level, std::vector<size_t> &hslice_dims, size_t &nslice, long ts)\n{\n    hslice_dims.clear();\n    nslice = 0;\n\n    vector<size_t> dims_at_level;\n    vector<size_t> dummy;\n\n    int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts);\n    if (rc < 0) return (-1);\n\n    if (dims_at_level.size() == 0) return (0);\n\n    hslice_dims = dims_at_level;\n\n    if (dims_at_level.size() == 1) {\n        nslice = 1;\n        return (0);\n    }\n\n    int dim = hslice_dims.size() - 1;\n\n    hslice_dims[dim] = 1;\n    nslice = dims_at_level[dim] / hslice_dims[dim];\n\n    return (0);\n}\n\nvector<string> DC::GetDataVarNames(int ndim) const\n{\n    vector<string> names, allnames;\n\n    allnames = GetDataVarNames();\n\n    for (int i = 0; i < allnames.size(); i++) {\n        DataVar dvar;\n        bool    ok = GetDataVarInfo(allnames[i], dvar);\n        if (!ok) continue;\n\n        string mesh_name;\n        mesh_name = dvar.GetMeshName();\n\n        Mesh mesh;\n        ok = GetMesh(mesh_name, mesh);\n        if (!ok) continue;\n\n        size_t d = mesh.GetGeometryDim();\n\n        if (d == ndim) { names.push_back(allnames[i]); }\n    }\n    return (names);\n}\n\nbool DC::_getDataVarDimensions(string varname, bool spatial, vector<DC::Dimension> &dimensions, long ts) const\n{\n    dimensions.clear();\n\n    DataVar var;\n    bool    status = GetDataVarInfo(varname, var);\n    if (!status) return (false);\n\n    string mname = var.GetMeshName();\n\n    if (!mname.empty()) {\n        ;    // 0-d variable\n        Mesh mesh;\n        status = GetMesh(mname, mesh);\n        if (!status) return (false);\n\n        vector<string> dimnames;\n        if (mesh.GetMeshType() == Mesh::STRUCTURED) {\n            dimnames = mesh.GetDimNames();\n        } else {\n            switch (var.GetSamplingLocation()) {\n            case Mesh::NODE: dimnames.push_back(mesh.GetNodeDimName()); break;\n            case Mesh::EDGE: dimnames.push_back(mesh.GetEdgeDimName()); break;\n            case Mesh::FACE: dimnames.push_back(mesh.GetFaceDimName()); break;\n            case Mesh::VOLUME: VAssert(0 && \"VOLUME cells not supported\"); break;\n            }\n            if (mesh.GetMeshType() == Mesh::UNSTRUC_LAYERED) { dimnames.push_back(mesh.GetLayersDimName()); }\n        }\n\n        for (int i = 0; i < dimnames.size(); i++) {\n            Dimension dim;\n\n            status = GetDimension(dimnames[i], dim, ts);\n            if (!status) return (false);\n\n            dimensions.push_back(dim);\n        }\n    }\n\n    // we're done if time dim isn't wanted\n    //\n    if (spatial) return (true);\n\n    string tvar = var.GetTimeCoordVar();\n    if (!tvar.empty()) {\n        vector<DC::Dimension> timedims;\n        status = _getCoordVarDimensions(tvar, false, timedims, ts);\n        if (!status) return (false);\n\n        VAssert(timedims.size() == 1);\n        dimensions.push_back(timedims[0]);\n    }\n\n    return (true);\n}\n\nbool DC::_getCoordVarDimensions(string varname, bool spatial, vector<DC::Dimension> &dimensions, long ts) const\n{\n    dimensions.clear();\n\n    CoordVar var;\n    bool     status = GetCoordVarInfo(varname, var);\n    if (!status) return (false);\n\n    vector<string> dimnames = var.GetDimNames();\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        Dimension dim;\n        status = GetDimension(dimnames[i], dim, ts);\n        if (!status) return (false);\n\n        dimensions.push_back(dim);\n    }\n\n    // we're done if time dim isn't wanted\n    //\n    if (spatial) return (true);\n\n    string timedim = var.GetTimeDimName();\n    if (!timedim.empty()) {\n        Dimension dim;\n        status = GetDimension(timedim, dim, ts);\n        if (!status) return (false);\n\n        dimensions.push_back(dim);\n    }\n    return (true);\n}\n\nbool DC::_getAuxVarDimensions(string varname, vector<DC::Dimension> &dimensions, long ts) const\n{\n    dimensions.clear();\n\n    AuxVar var;\n    bool   status = GetAuxVarInfo(varname, var);\n    if (!status) return (false);\n\n    vector<string> dimnames = var.GetDimNames();\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        Dimension dim;\n        status = GetDimension(dimnames[i], dim, ts);\n        if (!status) return (false);\n\n        dimensions.push_back(dim);\n    }\n    return (true);\n}\n\nvector<size_t> DC::_getBlockSize() const\n{\n    vector<size_t> bs = getBlockSize();\n    while (bs.size() > 3) { bs.pop_back(); }\n    return (bs);\n}\n\nint DC::_openVariableRead(size_t ts, string varname, int level, int lod) { return (openVariableRead(ts, varname, level, lod)); }\n\nint DC::_closeVariable(int fd) { return (closeVariable(fd)); }\n\ntemplate<class T> int DC::_readSliceTemplate(int fd, T *slice)\n{\n    vector<size_t> dims_at_level;\n    vector<size_t> dummy;\n\n    FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor: %d\", fd);\n        return (-1);\n    }\n\n    string varname = f->GetVarname();\n    int    level = f->GetLevel();\n    int    sliceNum = f->GetSlice();\n\n    int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, f->GetTS());\n    if (rc < 0) return (rc);\n\n    vector<size_t> hslice_dims;\n    size_t         nslice;\n    rc = GetHyperSliceInfo(varname, level, hslice_dims, nslice);\n    if (rc < 0) return (rc);\n    VAssert(hslice_dims.size() == dims_at_level.size());\n\n    if (sliceNum >= nslice) return (0);    // Done reading;\n\n    vector<size_t> min;\n    vector<size_t> max;\n    int            dim = 0;\n    for (; dim < hslice_dims.size() - 1; dim++) {\n        min.push_back(0);\n        max.push_back(hslice_dims[dim] - 1);\n    };\n    min.push_back(sliceNum * hslice_dims[dim]);\n    max.push_back(min[dim] + hslice_dims[dim] - 1);\n\n    // Last slice is a partial read if not block-aligned\n    //\n    if (max[dim] >= dims_at_level[dim]) { max[dim] = dims_at_level[dim] - 1; }\n\n    rc = ReadRegion(fd, min, max, slice);\n    if (rc < 0) return (rc);\n\n    sliceNum++;\n    f->SetSlice(sliceNum);\n\n    return (rc);\n}\n\ntemplate<class T> int DC::_readTemplate(int fd, T *data)\n{\n    vector<size_t> dims_at_level;\n    vector<size_t> dummy;\n\n    FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor: %d\", fd);\n        return (-1);\n    }\n    string varname = f->GetVarname();\n    int    level = f->GetLevel();\n\n    int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, f->GetTS());\n    if (rc < 0) return (rc);\n\n    vector<size_t> min, max;\n    for (int i = 0; i < dims_at_level.size(); i++) {\n        min.push_back(0);\n        max.push_back(dims_at_level[i] - 1);\n    }\n\n    return (ReadRegion(fd, min, max, data));\n}\n\ntemplate<class T> int DC::_getVarTemplate(string varname, int level, int lod, T *data)\n{\n    vector<size_t> dims_at_level;\n    vector<size_t> dummy;\n\n    size_t numts = GetNumTimeSteps(varname);\n\n    T *ptr = data;\n    for (size_t ts = 0; ts < numts; ts++) {\n        int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts);\n        if (rc < 0) return (-1);\n        size_t var_size = 1;\n        for (int i = 0; i < dims_at_level.size(); i++) { var_size *= dims_at_level[i]; }\n\n        rc = GetVar(ts, varname, level, lod, ptr);\n        if (rc < 0) return (-1);\n\n        ptr += var_size;\n    }\n\n    return (0);\n}\n\ntemplate int DC::_getVarTemplate<double>(string varname, int level, int lod, double *data);\ntemplate int DC::_getVarTemplate<float>(string varname, int level, int lod, float *data);\ntemplate int DC::_getVarTemplate<int>(string varname, int level, int lod, int *data);\n\ntemplate<class T> int DC::_getVarTemplate(size_t ts, string varname, int level, int lod, T *data)\n{\n    int fd = OpenVariableRead(ts, varname, level, lod);\n    if (fd < 0) return (-1);\n\n    int rc = Read(fd, data);\n    if (rc < 0) {\n        CloseVariable(fd);\n        return (-1);\n    }\n\n    rc = CloseVariable(fd);\n\n    return (rc);\n}\n\ntemplate int DC::_getVarTemplate<double>(size_t ts, string varname, int level, int lod, double *data);\ntemplate int DC::_getVarTemplate<float>(size_t ts, string varname, int level, int lod, float *data);\ntemplate int DC::_getVarTemplate<int>(size_t ts, string varname, int level, int lod, int *data);\n\nbool DC::GetVarDimensions(string varname, bool spatial, vector<DC::Dimension> &dimensions, long ts) const\n{\n    dimensions.clear();\n\n    if (IsDataVar(varname)) {\n        return (_getDataVarDimensions(varname, spatial, dimensions, ts));\n    } else if (IsCoordVar(varname)) {\n        return (_getCoordVarDimensions(varname, spatial, dimensions, ts));\n    } else if (IsAuxVar(varname)) {\n        return (_getAuxVarDimensions(varname, dimensions, ts));\n    } else {\n        return (false);\n    }\n}\n\nbool DC::GetVarDimLens(string varname, bool spatial, vector<size_t> &dimlens, long ts) const\n{\n    dimlens.clear();\n\n    vector<DC::Dimension> dims;\n\n    bool status = DC::GetVarDimensions(varname, spatial, dims, ts);\n    if (!status) return (status);\n\n    for (int i = 0; i < dims.size(); i++) { dimlens.push_back(dims[i].GetLength()); }\n\n    return (true);\n}\n\nbool DC::GetVarDimLens(string varname, vector<size_t> &sdimlens, size_t &time_dimlen, long ts) const\n{\n    sdimlens.clear();\n    time_dimlen = 0;\n\n    vector<DC::Dimension> dims;\n\n    bool status = DC::GetVarDimensions(varname, false, dims, ts);\n    if (!status) return (status);\n\n    if (DC::IsTimeVarying(varname)) {\n        time_dimlen = dims[dims.size() - 1].GetLength();\n        dims.pop_back();\n    }\n\n    for (int i = 0; i < dims.size(); i++) { sdimlens.push_back(dims[i].GetLength()); }\n\n    return (true);\n}\n\nbool DC::GetVarDimNames(string varname, bool spatial, vector<string> &dimnames) const\n{\n    dimnames.clear();\n\n    vector<DC::Dimension> dims;\n\n    bool status = DC::GetVarDimensions(varname, spatial, dims, 0);\n    if (!status) return (status);\n\n    for (int i = 0; i < dims.size(); i++) { dimnames.push_back(dims[i].GetName()); }\n\n    return (true);\n}\n\nbool DC::GetVarDimNames(string varname, vector<string> &sdimnames, string &time_dimname) const\n{\n    sdimnames.clear();\n    time_dimname = \"\";\n\n    vector<DC::Dimension> dims;\n\n    bool status = DC::GetVarDimensions(varname, false, dims, 0);\n    if (!status) return (status);\n\n    if (DC::IsTimeVarying(varname)) {\n        time_dimname = dims[dims.size() - 1].GetName();\n        dims.pop_back();\n    }\n\n    for (int i = 0; i < dims.size(); i++) { sdimnames.push_back(dims[i].GetName()); }\n\n    return (true);\n}\n\nsize_t DC::GetVarTopologyDim(string varname) const\n{\n    DataVar var;\n    bool    status = GetDataVarInfo(varname, var);\n    if (!status) return (0);\n\n    string mname = var.GetMeshName();\n\n    Mesh mesh;\n    status = GetMesh(mname, mesh);\n    if (!status) return (0);\n\n    return (mesh.GetTopologyDim());\n}\n\nsize_t DC::GetVarGeometryDim(string varname) const\n{\n    DataVar var;\n    bool    status = GetDataVarInfo(varname, var);\n    if (!status) return (0);\n\n    string mname = var.GetMeshName();\n\n    Mesh mesh;\n    status = GetMesh(mname, mesh);\n    if (!status) return (0);\n\n    return (mesh.GetGeometryDim());\n}\n\nbool DC::IsTimeVarying(string varname) const\n{\n    if (IsAuxVar(varname)) return (false);\n\n    // If var is a data variable and has a time coordinate variable defined\n    //\n    if (IsDataVar(varname)) {\n        DataVar var;\n        bool    ok = GetDataVarInfo(varname, var);\n        if (!ok) return (false);\n        return (!var.GetTimeCoordVar().empty());\n    }\n\n    // If var is a coordinate variable and it has a time dimension\n    //\n    if (IsCoordVar(varname)) {\n        CoordVar var;\n        bool     ok = GetCoordVarInfo(varname, var);\n        if (!ok) return (false);\n        return (!var.GetTimeDimName().empty());\n    }\n\n    return (false);\n}\n\nbool DC::IsCompressed(string varname) const\n{\n    BaseVar var;\n\n    bool ok = GetBaseVarInfo(varname, var);\n    if (!ok) return (false);\n\n    return (var.IsCompressed());\n}\n\nint DC::GetNumTimeSteps(string varname) const\n{\n    if (IsAuxVar(varname)) return (1);\n\n    // If data variable get it's time coordinate variable if it exists\n    //\n    if (IsDataVar(varname)) {\n        DataVar var;\n        bool    ok = GetDataVarInfo(varname, var);\n        if (!ok) return (0);\n\n        string time_coord_var = var.GetTimeCoordVar();\n        if (time_coord_var.empty()) return (1);\n        varname = time_coord_var;\n    }\n\n    CoordVar var;\n    bool     ok = GetCoordVarInfo(varname, var);\n    if (!ok) return (0);\n\n    string time_dim_name = var.GetTimeDimName();\n    if (time_dim_name.empty()) return (1);\n\n    DC::Dimension dim;\n    ok = GetDimension(time_dim_name, dim, 0);\n    if (!ok) return (0);\n\n    return (dim.GetLength());\n}\n\nvector<size_t> DC::GetCRatios(string varname) const\n{\n    DC::BaseVar var;\n    bool        status = GetBaseVarInfo(varname, var);\n    if (!status) { return (vector<size_t>(1, 1)); }\n    return (var.GetCRatios());\n}\n\nbool DC::GetVarCoordVars(string varname, bool spatial, std::vector<string> &coord_vars) const\n{\n    coord_vars.clear();\n\n    DataVar dvar;\n    bool    status = GetDataVarInfo(varname, dvar);\n    if (!status) return (false);\n\n    Mesh m;\n    status = GetMesh(dvar.GetMeshName(), m);\n    if (!status) return (false);\n\n    coord_vars = m.GetCoordVars();\n\n    if (spatial) return (true);\n\n    if (!dvar.GetTimeCoordVar().empty()) { coord_vars.push_back(dvar.GetTimeCoordVar()); }\n\n    return (true);\n}\n\nbool DC::GetVarConnVars(string varname, string &face_node_var, string &node_face_var, string &face_edge_var, string &face_face_var, string &edge_node_var, string &edge_face_var) const\n{\n    face_node_var.clear();\n    node_face_var.clear();\n    face_edge_var.clear();\n    face_face_var.clear();\n    edge_node_var.clear();\n    edge_face_var.clear();\n\n    DataVar dvar;\n    bool    status = GetDataVarInfo(varname, dvar);\n    if (!status) return (false);\n\n    Mesh m;\n    status = GetMesh(dvar.GetMeshName(), m);\n    if (!status) return (false);\n\n    face_node_var = m.GetFaceNodeVar();\n    node_face_var = m.GetNodeFaceVar();\n    face_edge_var = m.GetFaceEdgeVar();\n    face_face_var = m.GetFaceFaceVar();\n    edge_node_var = m.GetEdgeNodeVar();\n    edge_face_var = m.GetEdgeFaceVar();\n\n    return (true);\n}\n\nsize_t DC::GetNumDimensions(string varname) const\n{\n    DataVar dvar;\n    bool    status = GetDataVarInfo(varname, dvar);\n\n    if (status) {\n        Mesh m;\n        status = GetMesh(dvar.GetMeshName(), m);\n        if (!status) return (0);\n\n        return (m.GetDimNames().size());\n    }\n\n    CoordVar cvar;\n    status = GetCoordVarInfo(varname, cvar);\n    if (status) return (cvar.GetDimNames().size());\n\n    AuxVar avar;\n    status = GetAuxVarInfo(varname, avar);\n    if (status) return (avar.GetDimNames().size());\n\n    return (0);\n}\n\nstd::vector<string> DC::GetTimeCoordVarNames() const\n{\n    vector<string> cvars = GetCoordVarNames();\n\n    vector<string> timeCoordVars;\n\n    for (int i = 0; i < cvars.size(); i++) {\n        CoordVar cvar;\n        bool     status = GetCoordVarInfo(cvars[i], cvar);\n        VAssert(status);\n\n        if (cvar.GetAxis() == 3) { timeCoordVars.push_back(cvars[i]); }\n    }\n    return (timeCoordVars);\n}\n\nDC::FileTable::FileTable() { _table.clear(); }\n\nDC::FileTable::~FileTable()\n{\n    for (int i = 0; i < _table.size(); i++) {\n        if (_table[i]) delete _table[i];\n        _table[i] = NULL;\n    }\n}\n\nint DC::FileTable::AddEntry(DC::FileTable::FileObject *obj)\n{\n    // Try to re-use an existing entry;\n    //\n    for (int i = 0; i < _table.size(); i++) {\n        if (!_table[i]) {\n            _table[i] = obj;\n            return (i);\n        }\n    }\n\n    // Create new entry\n    //\n    _table.push_back(obj);\n    return (_table.size() - 1);\n}\n\nDC::FileTable::FileObject *DC::FileTable::GetEntry(int fd) const\n{\n    if (fd < 0) return (NULL);\n\n    if (fd < _table.size()) return (_table[fd]);\n\n    return (NULL);\n}\n\nvoid DC::FileTable::RemoveEntry(int fd)\n{\n    if (fd < 0 || fd >= _table.size()) return;\n\n    _table[fd] = NULL;\n}\n\nvector<int> DC::FileTable::GetEntries() const\n{\n    vector<int> fds;\n\n    for (int i = 0; i < _table.size(); i++) {\n        if (_table[i]) { fds.push_back(i); }\n    }\n    return (fds);\n}\n\nbool DC::GetMeshDimLens(const string &mesh_name, std::vector<size_t> &dims, long ts) const\n{\n    dims.clear();\n\n    DC::Mesh mesh;\n    bool     status = GetMesh(mesh_name, mesh);\n    if (!status) return (false);\n\n    vector<string> dimNames = mesh.GetDimNames();\n    for (int i = 0; i < dimNames.size(); i++) {\n        DC::Dimension dimension;\n\n        status = GetDimension(dimNames[i], dimension, ts);\n        if (!status) return (false);\n\n        dims.push_back(dimension.GetLength());\n    }\n    return (true);\n}\n\nbool DC::GetMeshDimNames(const string &mesh_name, std::vector<string> &dimnames) const\n{\n    dimnames.clear();\n\n    DC::Mesh mesh;\n    bool     status = GetMesh(mesh_name, mesh);\n    if (!status) return (false);\n\n    dimnames = mesh.GetDimNames();\n\n    return (true);\n}\n\nnamespace VAPoR {\n\nstd::ostream &operator<<(std::ostream &o, const DC::Dimension &d)\n{\n    o << \"  Dimension\" << endl;\n    o << \"   Name: \" << d._name << endl;\n    o << \"   Lengths:\";\n    for (int i = 0; i < d._lengths.size(); i++) { o << \" \" << d._lengths[i]; }\n    o << endl;\n\n    return (o);\n}\n\nstd::ostream &operator<<(std::ostream &o, const DC::Mesh &m)\n{\n    o << \"  Mesh\" << endl;\n    o << \"   Name: \" << m._name << endl;\n\n    o << \"   DimNames:\";\n    for (int i = 0; i < m._dim_names.size(); i++) { o << \" \" << m._dim_names[i]; }\n    o << endl;\n\n    o << \"   CoordVars:\";\n    for (int i = 0; i < m._coord_vars.size(); i++) { o << \" \" << m._coord_vars[i]; }\n    o << endl;\n\n    o << \"   MaxNodesPerFace: \" << m._max_nodes_per_face << endl;\n    o << \"   MaxFacesPerNode: \" << m._max_faces_per_node << endl;\n    o << \"   NodeDimName: \" << m._node_dim_name << endl;\n    o << \"   FaceDimName: \" << m._face_dim_name << endl;\n    o << \"   LayersDimName: \" << m._layers_dim_name << endl;\n    o << \"   FaceNodeVar: \" << m._face_node_var << endl;\n    o << \"   NodeFaceVar: \" << m._node_face_var << endl;\n    o << \"   FaceEdgeVar: \" << m._face_edge_var << endl;\n    o << \"   FaceFaceVar: \" << m._face_face_var << endl;\n    o << \"   EdgeDimName: \" << m._edge_dim_name << endl;\n    o << \"   EdgeNodeVar: \" << m._edge_node_var << endl;\n    o << \"   EdgeFaceVar: \" << m._edge_face_var << endl;\n    o << \"   Mtype: \" << m._mtype << endl;\n\n    return (o);\n}\n\nstd::ostream &operator<<(std::ostream &o, const DC::Attribute &a)\n{\n    o << \"  Attribute:\" << endl;\n    o << \"   Name: \" << a._name << endl;\n    o << \"   Type: \" << a._type << endl;\n\n    o << \"   Values: \";\n    for (int i = 0; i < a._values.size(); i++) {\n        DC::Attribute::podunion p = a._values[i];\n        if (a._type == DC::FLOAT) {\n            o << p.f;\n        } else if (a._type == DC::DOUBLE) {\n            o << p.d;\n        } else if (a._type == DC::INT32) {\n            o << p.i;\n        } else if (a._type == DC::INT64) {\n            o << p.l;\n        }\n        if (a._type == DC::TEXT) { o << p.c; }\n        o << \" \";\n    }\n    o << endl;\n    return (o);\n}\n\nstd::ostream &operator<<(std::ostream &o, const DC::BaseVar &var)\n{\n    o << \"  BaseVar\" << endl;\n    o << \"   Name: \" << var._name << endl;\n    o << \"   Units: \" << var._units << endl;\n    o << \"   XType: \" << var._type << endl;\n    o << \"   Compressed: \" << (var._cratios.size() > 0) << endl;\n    o << \"   WName: \" << var._wname << endl;\n    o << \"   CRatios: \";\n    for (int i = 0; i < var._cratios.size(); i++) { o << var._cratios[i] << \" \"; }\n    o << endl;\n    o << endl;\n    o << \"   Periodic: \";\n    for (int i = 0; i < var._periodic.size(); i++) { o << var._periodic[i] << \" \"; }\n    o << endl;\n\n    std::map<string, DC::Attribute>::const_iterator itr;\n    for (itr = var._atts.begin(); itr != var._atts.end(); ++itr) { o << itr->second; }\n\n    return (o);\n}\n\nstd::ostream &operator<<(std::ostream &o, const DC::CoordVar &var)\n{\n    o << \"  CoordVar\" << endl;\n    o << \"   Axis: \" << var._axis << endl;\n    o << \"   Uniform: \" << var._uniform << endl;\n\n    o << (DC::BaseVar)var;\n\n    return (o);\n}\n\nstd::ostream &operator<<(std::ostream &o, const DC::DataVar &var)\n{\n    o << \"  DataVar\" << endl;\n    o << \"   Mesh: \" << var._mesh << endl;\n    o << \"   TimeCoordVar: \" << var._time_coord_var << endl;\n    o << \"   Location: \" << var._location << endl;\n    o << \"   MaskVar: \" << var._maskvar << endl;\n    o << \"   HasMissing: \" << var._has_missing << endl;\n    o << \"   MissingValue: \" << var._missing_value << endl;\n\n    o << (DC::BaseVar)var;\n\n    return (o);\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/DCBOV.cpp",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <fstream>\n#include \"vapor/VAssert.h\"\n#include <stdio.h>\n\n#ifdef _WINDOWS\n    #define _USE_MATH_DEFINES\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <cmath>\n\n#include <vapor/GeoUtil.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/DCBOV.h>\n#include <vapor/DCUtils.h>\n\nusing namespace VAPoR;\nusing namespace std;\n\nDCBOV::DCBOV() : _bovCollection(nullptr)\n{\n    _dimsMap.clear();\n    _coordVarsMap.clear();\n    _dataVarsMap.clear();\n    _meshMap.clear();\n    _coordVarKeys.clear();\n}\n\nDCBOV::~DCBOV()\n{\n    if (_bovCollection != nullptr) { delete _bovCollection; }\n}\n\nint DCBOV::initialize(const vector<string> &paths, const std::vector<string> &options)\n{\n    if (_bovCollection != nullptr) delete _bovCollection;\n    _bovCollection = new BOVCollection();\n    int rc = _bovCollection->Initialize(paths);\n    if (rc < 0) {\n        SetErrMsg(\"Failure reading .bov file\");\n        return (-1);\n    }\n\n    //\n    //  Get the dimensions of the grid.\n    //\tInitializes members: _dimsMap\n    //\n    _InitDimensions();\n\n    // Set up the coordinate variables\n    //\n    _InitCoordinates();\n\n    // Identify data and coordinate variables. Sets up members:\n    // Initializes members: _dataVarsMap, _meshMap\n    //\n    _InitVars();\n\n    return (0);\n}\n\nvoid DCBOV::_InitDimensions()\n{\n    _dimsMap.clear();\n    std::array<std::string, 3> dimnames = _bovCollection->GetSpatialDimensions();\n    std::array<size_t, 3>      dimlens = _bovCollection->GetDataSize();\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        Dimension dim(dimnames[i], dimlens[i]);\n        _dimsMap[dimnames[i]] = dim;\n    }\n\n    string    timeDim = _bovCollection->GetTimeDimension();\n    size_t    numTimes = _bovCollection->GetUserTimes().size();\n    Dimension dim(timeDim, numTimes);\n    _dimsMap[timeDim] = dim;\n}\n\nvoid DCBOV::_InitCoordinates()\n{\n    bool                       uniformHint = true;\n    vector<bool>               periodic(1, false);\n    std::string                units = \"m\";\n    std::array<std::string, 3> dims = _bovCollection->GetSpatialDimensions();\n\n    _coordVarsMap[dims[0]] = CoordVar(dims[0], units, DC::FLOAT, periodic, 0, uniformHint, {dims[0]}, \"\");\n    _coordVarsMap[dims[1]] = CoordVar(dims[1], units, DC::FLOAT, periodic, 1, uniformHint, {dims[1]}, \"\");\n    _coordVarsMap[dims[2]] = CoordVar(dims[2], units, DC::FLOAT, periodic, 2, uniformHint, {dims[2]}, \"\");\n\n    std::string timeDim = _bovCollection->GetTimeDimension();\n    _coordVarsMap[timeDim] = CoordVar(timeDim, \"seconds\", DC::FLOAT, vector<bool>(), 3, false, vector<string>(), timeDim);\n}\n\n// Collect metadata for all data variables found in the CF data\n// set. Initialize the _dataVarsMap member\n//\nvoid DCBOV::_InitVars()\n{\n    _dataVarsMap.clear();\n    _meshMap.clear();\n\n    vector<bool> periodic(3, false);\n\n    std::array<std::string, 3> dimnames = _bovCollection->GetSpatialDimensions();\n    std::vector<std::string>   vars = _bovCollection->GetDataVariableNames();\n    DC::XType                  format = _bovCollection->GetDataFormat();\n    std::string                timeCoordVar = _bovCollection->GetTimeDimension();\n    string                     units = \"m\";\n\n    std::vector<std::string> vDimNames = {dimnames[0], dimnames[1], dimnames[2]};\n    Mesh                     mesh(\"BOV\", vDimNames, vDimNames);\n\n    // Create new mesh. We're being lazy here and probably should only\n    // createone if it doesn't ready exist\n    //\n    _meshMap[mesh.GetName()] = mesh;\n\n    for (auto var : vars) { _dataVarsMap[var] = DataVar(var, units, format, periodic, mesh.GetName(), timeCoordVar, DC::Mesh::NODE); }\n}\n\nbool DCBOV::getDimension(string dimname, DC::Dimension &dimension) const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    itr = _dimsMap.find(dimname);\n    if (itr == _dimsMap.end()) return (false);\n\n    dimension = itr->second;\n    return (true);\n}\n\nstd::vector<string> DCBOV::getDimensionNames() const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    vector<string> names;\n\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nvector<string> DCBOV::getMeshNames() const\n{\n    vector<string>                         mesh_names;\n    std::map<string, Mesh>::const_iterator itr = _meshMap.begin();\n    for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); }\n    return (mesh_names);\n}\n\nbool DCBOV::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    map<string, Mesh>::const_iterator itr = _meshMap.find(mesh_name);\n    if (itr == _meshMap.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nbool DCBOV::getCoordVarInfo(string varname, DC::CoordVar &cvar) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr == _coordVarsMap.end()) { return (false); }\n\n    cvar = itr->second;\n    return (true);\n}\n\nbool DCBOV::getDataVarInfo(string varname, DC::DataVar &datavar) const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    itr = _dataVarsMap.find(varname);\n    if (itr == _dataVarsMap.end()) { return (false); }\n\n    datavar = itr->second;\n    return (true);\n}\n\nbool DCBOV::getBaseVarInfo(string varname, DC::BaseVar &var) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr != _coordVarsMap.end()) {\n        var = itr->second;\n        return (true);\n    }\n\n    map<string, DC::DataVar>::const_iterator itr1 = _dataVarsMap.find(varname);\n    if (itr1 != _dataVarsMap.end()) {\n        var = itr1->second;\n        return (true);\n    }\n\n    return (false);\n}\n\nstd::vector<string> DCBOV::getDataVarNames() const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nstd::vector<string> DCBOV::getCoordVarNames() const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nbool DCBOV::getAtt(string varname, string attname, vector<double> &values) const { return false; }\n\nbool DCBOV::getAtt(string varname, string attname, vector<long> &values) const { return false; }\n\nbool DCBOV::getAtt(string varname, string attname, string &values) const { return false; }\n\nstd::vector<string> DCBOV::getAttNames(string varname) const { return {}; }\n\nDC::XType DCBOV::getAttType(string varname, string attname) const { return INVALID; }\n\nint DCBOV::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    bool ok = GetVarDimLens(varname, true, dims_at_level);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DCBOV::openVariableRead(size_t ts, string varname)\n{\n    FileTable::FileObject *f = new FileTable::FileObject(ts, varname, 0, 0, 0);\n    return (_fileTable.AddEntry(f));\n}\n\nint DCBOV::closeVariable(int fd)\n{\n    DC::FileTable::FileObject *w = _fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    if (w != nullptr) delete w;\n\n    return 0;\n}\n\nint DCBOV::_isCoordinateVariable(std::string varname) const\n{\n    int                        dim = -1;\n    std::array<std::string, 3> spatialDims = _bovCollection->GetSpatialDimensions();\n\n    for (int i = 0; i < spatialDims.size(); i++) {\n        if (varname == spatialDims[i]) dim = i;\n    }\n\n    return dim;\n}\n\ntemplate<class T> void DCBOV::_generateCoordinates(int dim, const vector<size_t> &min, const vector<size_t> &max, T *region) const\n{\n    std::array<size_t, 3> dataSize = _bovCollection->GetDataSize();\n    std::array<double, 3> origin = _bovCollection->GetBrickOrigin();\n    std::array<double, 3> brickSize = _bovCollection->GetBrickSize();\n\n    double denom = (dataSize[dim] - 1);\n    double increment = denom == 0. ? 0. : brickSize[dim] / denom;\n    double start = origin[dim] + min[0] * increment;\n    size_t steps = max[0] - min[0];\n\n    for (int i = 0; i <= steps; i++) { region[i] = start + i * increment; }\n}\n\ntemplate<class T> int DCBOV::_readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region)\n{\n    FileTable::FileObject *w = (FileTable::FileObject *)_fileTable.GetEntry(fd);\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    std::string varname = w->GetVarname();\n\n    int dim = _isCoordinateVariable(varname);\n    if (dim >= 0) {\n        _generateCoordinates(dim, min, max, region);\n        return 0;\n    }\n\n    size_t ts = w->GetTS();\n\n    // If a data variable is requested, read it with ReadRegion\n    std::vector<std::string> varnames = _bovCollection->GetDataVariableNames();\n    if (std::find(varnames.begin(), varnames.end(), varname) != varnames.end()) {\n        int rc = _bovCollection->ReadRegion(varname, ts, min, max, region);\n        if (rc < 0) {\n            SetErrMsg(\"DCBOV::_readRegionTemplate error\");\n            return -1;\n        }\n    }\n    // Otherwise return time values\n    else if (varname == _bovCollection->GetTimeDimension()) {\n        *region = _bovCollection->GetUserTimes()[ts];\n    }\n    return 0;\n}\n\nbool DCBOV::variableExists(size_t ts, string varname, int, int) const\n{\n    if (_coordVarsMap.find(varname) != _coordVarsMap.end()) return true;\n    if (_dataVarsMap.find(varname) != _dataVarsMap.end()) return true;\n    return false;\n}\n"
  },
  {
    "path": "lib/vdc/DCCF.cpp",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <stdio.h>\n\n#ifdef _WINDOWS\n    #define _USE_MATH_DEFINES\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <cmath>\n\n#include <vapor/GeoUtil.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/DCCF.h>\n#include <vapor/DCUtils.h>\n\nusing namespace VAPoR;\nusing namespace std;\n\nnamespace {\n\nDC::XType netcdf_to_dc_xtype(int t)\n{\n    switch (t) {\n    case NC_DOUBLE: return (DC::XType::DOUBLE);\n    case NC_INT64: return (DC::XType::INT64);\n    case NC_CHAR: return (DC::XType::TEXT);\n    default: return (DC::XType::INVALID);\n    }\n}\n\n#ifdef UNUSED_FUNCTION\n// Product of elements in a vector\n//\nsize_t vproduct(vector<size_t> a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n#endif\n\n};    // namespace\n\nDCCF::DCCF()\n{\n    _ncdfc = NULL;\n\n    _dimsMap.clear();\n    _coordVarsMap.clear();\n    _dataVarsMap.clear();\n    _auxVarsMap.clear();\n    _meshMap.clear();\n}\n\nDCCF::~DCCF()\n{\n    if (_ncdfc) delete _ncdfc;\n}\n\nint DCCF::initialize(const vector<string> &paths, const std::vector<string> &options)\n{\n    auto ncdf = std::unique_ptr<NetCDFCFCollection>(new NetCDFCFCollection());\n    return initialize_impl(paths, options, std::move(ncdf));\n}\n\nint DCCF::initialize_impl(const vector<string> &paths, const std::vector<string> &options,\n                          std::unique_ptr<NetCDFCFCollection> ncdfc)\n{\n    // Initialize the NetCDFCFCollection class.\n    //\n    int rc = ncdfc->Initialize(paths);\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize netCDF data collection for reading\");\n        return (-1);\n    }\n\n    // Use UDUnits for unit conversion\n    //\n    rc = _udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", _udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n    //\n    // To provide a more detailed message in the case described by issue 3626:\n    // https://github.com/NCAR/VAPOR/issues/3626\n    // add a test if there's any 2D or 3D variables detected. If not, we raise an error.\n    //\n    // Update on 8/15/2024:\n    // It turns out that this error message is also raised with UGRID 2D data sets, when it\n    // shouldn't be raised (see issue 3650). Thus, Sam is commenting out this logic for\n    // release 3.9.3, and will come back to design a more robust method to address both\n    // issues 3626 and 3650.\n    //\n    // auto vars2d = ncdfc->GetDataVariableNames(2, true);\n    // if (vars2d.empty()) {\n    //   auto vars3d = ncdfc->GetDataVariableNames(3, true);\n    //   if (vars3d.empty()) {\n    //     SetErrMsg(\"Failed to detect any 2D or 3D variables.\\n\"\n    //               \"Did you forget any coordinate files?\\n\");\n    //     return (-1);\n    //   }\n    // }\n\n    if (_ncdfc) {\n      delete _ncdfc;\n    }\n    _ncdfc = ncdfc.release();\n    _paths = paths;\n\n    return BuildCache();\n}\n\nint DCCF::Reinitialize()\n{\n    return Initialize(_paths, {});\n}\n\nint DCCF::BuildCache()\n{\n    auto ncdfc = _ncdfc;\n    int rc;\n    \n    //\n    //  Get the dimensions of the grid.\n    //    Initializes members: _dimsMap\n    //\n    rc = initDimensions(ncdfc, _dimsMap);\n    if (rc < 0) {\n        SetErrMsg(\"No valid dimensions\");\n        return (-1);\n    }\n\n    rc = initCoordinates(ncdfc, _coordVarsMap);\n    if (rc < 0) {\n        SetErrMsg(\"No valid dimensions\");\n        return (-1);\n    }\n\n    //\n    // Identify auxilliary variables.\n    //\n    rc = initAuxilliaryVars(ncdfc, _auxVarsMap);\n    if (rc < 0) return (-1);\n\n    //\n    // Identify meshes.\n    //\n    rc = initMesh(ncdfc, _meshMap);\n    if (rc < 0) return (-1);\n\n\n    //\n    // Identify data variables.\n    //\n    rc = initDataVars(ncdfc, _dataVarsMap);\n    if (rc < 0) return (-1);\n    \n    return 0;\n}\n\nbool DCCF::getDimension(string dimname, DC::Dimension &dimension) const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    itr = _dimsMap.find(dimname);\n    if (itr == _dimsMap.end()) return (false);\n\n    dimension = itr->second;\n    return (true);\n}\n\nstd::vector<string> DCCF::getDimensionNames() const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    vector<string> names;\n\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nvector<string> DCCF::getMeshNames() const\n{\n    vector<string>                         mesh_names;\n    std::map<string, Mesh>::const_iterator itr = _meshMap.begin();\n    for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); }\n    return (mesh_names);\n}\n\nbool DCCF::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    map<string, Mesh>::const_iterator itr = _meshMap.find(mesh_name);\n    if (itr == _meshMap.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nbool DCCF::getCoordVarInfo(string varname, DC::CoordVar &cvar) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr == _coordVarsMap.end()) { return (false); }\n\n    cvar = itr->second;\n    return (true);\n}\n\nbool DCCF::getDataVarInfo(string varname, DC::DataVar &datavar) const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    itr = _dataVarsMap.find(varname);\n    if (itr == _dataVarsMap.end()) { return (false); }\n\n    datavar = itr->second;\n    return (true);\n}\n\nbool DCCF::getAuxVarInfo(string varName, DC::AuxVar &auxVar) const\n{\n    map<string, DC::AuxVar>::const_iterator itr;\n\n    itr = _auxVarsMap.find(varName);\n    if (itr == _auxVarsMap.end()) { return (false); }\n\n    auxVar = itr->second;\n    return (true);\n}\n\nbool DCCF::getBaseVarInfo(string varname, DC::BaseVar &var) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr != _coordVarsMap.end()) {\n        var = itr->second;\n        return (true);\n    }\n\n    map<string, DC::DataVar>::const_iterator itr1 = _dataVarsMap.find(varname);\n    if (itr1 != _dataVarsMap.end()) {\n        var = itr1->second;\n        return (true);\n    }\n\n    return (false);\n}\n\nstd::vector<string> DCCF::getDataVarNames() const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nstd::vector<string> DCCF::getCoordVarNames() const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nstd::vector<string> DCCF::getAuxVarNames() const\n{\n    map<string, DC::AuxVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _auxVarsMap.begin(); itr != _auxVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\ntemplate<class T> bool DCCF::_getAttTemplate(string varname, string attname, T &values) const\n{\n    if (varname.empty()) {\n        _ncdfc->GetAtt(\"\", attname, values);\n        return (true);\n    }\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (status);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (status);\n\n    att.GetValues(values);\n\n    return (true);\n}\n\nbool DCCF::getAtt(string varname, string attname, vector<double> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCCF::getAtt(string varname, string attname, vector<long> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCCF::getAtt(string varname, string attname, string &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nstd::vector<string> DCCF::getAttNames(string varname) const\n{\n    if (varname.empty()) return (_ncdfc->GetAttNames(\"\"));\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (vector<string>());\n\n    vector<string> names;\n\n    const std::map<string, Attribute> &         atts = var.GetAttributes();\n    std::map<string, Attribute>::const_iterator itr;\n    for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nDC::XType DCCF::getAttType(string varname, string attname) const\n{\n    if (varname.empty()) { return (netcdf_to_dc_xtype(_ncdfc->GetAttType(\"\", attname))); }\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (DC::INVALID);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (DC::INVALID);\n\n    return (att.GetXType());\n}\n\nint DCCF::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    bool ok = GetVarDimLens(varname, true, dims_at_level, 0);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DCCF::openVariableRead(size_t ts, string varname)\n{\n    int aux = _ncdfc->OpenRead(ts, varname);\n    if (aux < 0) return (aux);\n\n    FileTable::FileObject *f = new FileTable::FileObject(ts, varname, 0, 0, aux);\n    return (_fileTable.AddEntry(f));\n}\n\nint DCCF::closeVariable(int fd)\n{\n    DC::FileTable::FileObject *w = _fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    int rc = _ncdfc->Close(aux);\n\n    _fileTable.RemoveEntry(fd);\n\n    return (rc);\n}\n\ntemplate<class T> int DCCF::_readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region)\n{\n    FileTable::FileObject *w = (FileTable::FileObject *)_fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    vector<size_t> ncdf_start = min;\n    reverse(ncdf_start.begin(), ncdf_start.end());\n\n    vector<size_t> ncdf_max = max;\n    reverse(ncdf_max.begin(), ncdf_max.end());\n\n    vector<size_t> ncdf_count;\n    for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); }\n\n    return (_ncdfc->Read(ncdf_start, ncdf_count, region, aux));\n}\n\nbool DCCF::variableExists(size_t ts, string varname, int, int) const { return (_ncdfc->VariableExists(ts, varname)); }\n\nbool DCCF::_isUniform(NetCDFCFCollection *ncdfc, string varname)\n{\n    vector<size_t> dims = ncdfc->GetDims(varname);\n\n    if (dims.size() != 1) return (false);\n\n    if (dims[0] < 2) return (true);\n\n    vector<float> buf(dims[0]);\n\n    bool enabled = EnableErrMsg(false);\n    int  fd = ncdfc->OpenRead(0, varname);\n    if (fd < 0) {\n        EnableErrMsg(enabled);\n        return (false);\n    }\n    int rc = ncdfc->Read(buf.data(), fd);\n    if (rc < 0) {\n        EnableErrMsg(enabled);\n        return (false);\n    }\n    ncdfc->Close(fd);\n    EnableErrMsg(enabled);\n\n    VAssert(buf.size() >= 2);\n\n    float epsilon = 0.0001;\n    float delta = buf[1] - buf[0];\n    for (int i = 1; i < buf.size() - 1; i++) {\n        if (!Wasp::NearlyEqual((buf[i + 1] - buf[i]), delta, epsilon)) { return (false); }\n    }\n\n    return (true);\n}\n\nint DCCF::addCoordvars(NetCDFCFCollection *ncdfc, const vector<string> &cvars, std::map<string, DC::CoordVar> &coordVarsMap)\n{\n    for (int i = 0; i < cvars.size(); i++) {\n        // Get dimension names\n        //\n        vector<string> dimnames = ncdfc->GetDimNames(cvars[i]);\n        reverse(dimnames.begin(), dimnames.end());    // DC order\n\n        string time_dim_name;\n        if (ncdfc->IsTimeVarying(cvars[i])) {\n            time_dim_name = dimnames.back();\n            dimnames.pop_back();\n        }\n\n        int axis = 0;\n        if (ncdfc->IsLonCoordVar(cvars[i])) {\n            axis = 0;\n        } else if (ncdfc->IsLatCoordVar(cvars[i])) {\n            axis = 1;\n        } else if (ncdfc->IsVertCoordVar(cvars[i])) {\n            axis = 2;\n        } else if (ncdfc->IsTimeCoordVar(cvars[i])) {\n            axis = 3;\n        } else {\n            continue;    // should this be a error condition?\n        }\n\n        string units;\n        ncdfc->GetAtt(cvars[i], \"units\", units);\n        if (!_udunits.ValidUnit(units)) { units = \"\"; }\n\n        // See if the variable has uniform spacing. If so, set the uniform hint\n        //\n        bool uniformHint = _isUniform(ncdfc, cvars[i]);\n\n        // Finally, add the variable to coordVarsMap.\n        //\n        vector<bool> periodic(false);\n        coordVarsMap[cvars[i]] = CoordVar(cvars[i], units, DC::FLOAT, periodic, axis, uniformHint, dimnames, time_dim_name);\n\n        int rc = DCUtils::CopyAtt(*ncdfc, cvars[i], coordVarsMap[cvars[i]]);\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\nint DCCF::initCoordinates(NetCDFCFCollection *ncdfc, std::map<string, DC::CoordVar> &coordVarsMap)\n{\n    coordVarsMap.clear();\n\n    // Set up the horizontal coordinate variables\n    //\n    int rc = _initHorizontalCoordinates(ncdfc, coordVarsMap);\n    if (rc < 0) { return (-1); }\n\n    // Set up the vertical coordinate variables.\n    //\n    rc = _initVerticalCoordinates(ncdfc, coordVarsMap);\n    if (rc < 0) { return (-1); }\n\n    // Set up user time coordinate variable.\n    //\n    rc = _initTimeCoordinates(ncdfc, coordVarsMap);\n    if (rc < 0) { return (-1); }\n\n    return (0);\n}\n\nint DCCF::_initHorizontalCoordinates(NetCDFCFCollection *ncdfc, std::map<string, DC::CoordVar> &coordVarsMap)\n{\n    vector<string> latVars = ncdfc->GetLatCoordVars();\n    int            rc = addCoordvars(ncdfc, latVars, coordVarsMap);\n    if (rc < 0) return (-1);\n\n    vector<string> lonVars = ncdfc->GetLonCoordVars();\n    rc = addCoordvars(ncdfc, lonVars, coordVarsMap);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\n//\n//\nint DCCF::_initVerticalCoordinates(NetCDFCFCollection *ncdfc, std::map<string, DC::CoordVar> &coordVarsMap)\n{\n    vector<string> vertVars = ncdfc->GetVertCoordVars();\n    int            rc = addCoordvars(ncdfc, vertVars, coordVarsMap);\n\n    return (rc);\n}\n\nint DCCF::_initTimeCoordinates(NetCDFCFCollection *ncdfc, std::map<string, DC::CoordVar> &coordVarsMap)\n{\n    // add native time coordinate variables\n    //\n    int rc = addCoordvars(ncdfc, ncdfc->GetTimeCoordVars(), coordVarsMap);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\n// Get Space and time dimensions from CF data set. Initialize\n// _dimsMap\n//\nint DCCF::initDimensions(NetCDFCFCollection *ncdfc, std::map<string, DC::Dimension> &dimsMap)\n{\n    dimsMap.clear();\n\n    // Get dimension names and lengths for all dimensions in the\n    // CF data set.\n    //\n    vector<string> dimnames = ncdfc->GetDimNames();\n    vector<size_t> dimlens = ncdfc->GetDims();\n    VAssert(dimnames.size() == dimlens.size());\n\n    //\n    // Find all dimensions and their associated axis (X,Y,Z,T). From\n    // CF 1.6:\n    //\n    // All of a variable's dimensions that are latitude, longitude, vertical,\n    // or time dimensions (see Section 1.2, “Terminology”) must have\n    // corresponding coordinate variables, i.e., one-dimensional variables\n    // with the same name as the dimension (see examples in Chapter 4,\n    // Coordinate Types ). This is the only method of associating dimensions\n    // with coordinates that is supported by COARDS.\n    //\n    for (int i = 0; i < dimnames.size(); i++) {\n        Dimension dim(dimnames[i], dimlens[i]);\n        dimsMap[dimnames[i]] = dim;\n    }\n\n    return (0);\n}\n\n// Given a data variable name return the variable's dimensions and\n// associated coordinate variables. The coordinate variable names\n// returned is for the derived coordinate variables expressed in\n// Cartographic coordinates, not the native geographic coordinates\n// found in the CF file.\n//\n// The order of the returned vectors\n// is significant.\n//\nint DCCF::getVarCoordinates(NetCDFCFCollection *ncdfc, string varname, vector<string> &sdimnames, vector<string> &scoordvars, string &time_dim_name, string &time_coordvar) const\n{\n    sdimnames.clear();\n    scoordvars.clear();\n    time_dim_name.clear();\n    time_coordvar.clear();\n\n    int rc = ncdfc->GetVarCoordVarNames(varname, scoordvars);\n    if (rc < 0) return (-1);\n\n    reverse(scoordvars.begin(), scoordvars.end());    // DC dimension order\n\n    sdimnames = ncdfc->GetDimNames(varname);\n    reverse(sdimnames.begin(), sdimnames.end());    // DC order\n\n    // Coordinate variables returned by ncdfc are assumed to be lat, lon,\n    // height, time. For each native coordinate variable a derived\n    // coordinate variable has been created in Cartographic coordinates with\n    // elevation expressed in meters, and time in seconds\n    //\n    for (int i = 0; i < scoordvars.size(); i++) {\n        string xcv;\n        if (ncdfc->IsLonCoordVar(scoordvars[i])) {\n            xcv = scoordvars[i];\n        } else if (ncdfc->IsLatCoordVar(scoordvars[i])) {\n            xcv = scoordvars[i];\n        } else if (ncdfc->IsVertCoordVar(scoordvars[i])) {\n            xcv = scoordvars[i];\n        } else if (ncdfc->IsTimeCoordVar(scoordvars[i])) {\n            xcv = scoordvars[i];\n        }\n\n        // Rank of Cartographic coordinates must be less than or\n        // equal to that of the data variable, or we have to use\n        // the native coordinates\n        //\n        if (ncdfc->GetDimNames(xcv).size() <= sdimnames.size()) { scoordvars[i] = xcv; }\n    }\n\n    if (ncdfc->IsTimeVarying(varname)) {\n        time_dim_name = sdimnames.back();\n        sdimnames.pop_back();\n\n        time_coordvar = scoordvars.back();\n        scoordvars.pop_back();\n    }\n\n    return (0);\n}\n\n// Initialize the meshMap\n//\nint DCCF::initMesh(NetCDFCFCollection *ncdfc, std::map<string, DC::Mesh> &meshMap)\n{\n    meshMap.clear();\n    //\n    // Get names of variables  in the CF data set that have 0 to 3\n    // spatial dimensions\n    //\n    vector<string> vars;\n    for (int i = 0; i < 4; i++) {\n        vector<string> v = ncdfc->GetDataVariableNames(i, true);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    // For each variable determine the mesh\n    //\n    for (int i = 0; i < vars.size(); i++) {\n        // variable type must be float or int\n        //\n        int type = ncdfc->GetXType(vars[i]);\n        if (!(NetCDFSimple::IsNCTypeFloat(type) || NetCDFSimple::IsNCTypeInt(type))) continue;\n\n        vector<string> sdimnames;\n        vector<string> scoordvars;\n        string         time_dim_name;\n        string         time_coordvar;\n\n        int rc = getVarCoordinates(ncdfc, vars[i], sdimnames, scoordvars, time_dim_name, time_coordvar);\n        if (rc < 0) {\n            SetErrMsg(\"Invalid variable : %s\", vars[i].c_str());\n            return (-1);\n        }\n\n        Mesh mesh(\"\", sdimnames, scoordvars);\n\n        // Create new mesh. We're being lazy here and probably should only\n        // createone if it doesn't ready exist\n        //\n        meshMap[mesh.GetName()] = mesh;\n    }\n\n    return (0);\n}\n\nint DCCF::initAuxilliaryVars(NetCDFCFCollection *ncdfc, std::map<string, DC::AuxVar> &auxVarsMap)\n{\n    auxVarsMap.clear();\n    return (0);\n}\n\n\n// Collect metadata for all data variables found in the CF data\n// set. Initialize dataVarsMap member\n//\nint DCCF::initDataVars(NetCDFCFCollection *ncdfc, std::map<string, DC::DataVar> &dataVarsMap)\n{\n    vector<bool> periodic(3, false);\n    //\n    // Get names of variables  in the CF data set that have 0 to 3\n    // spatial dimensions\n    //\n    vector<string> vars;\n    for (int i = 0; i < 4; i++) {\n        vector<string> v = ncdfc->GetDataVariableNames(i, true);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    // For each variable add a member to dataVarsMap\n    //\n    for (auto varName : vars) {\n\n        // variable type must be float or int\n        //\n        int type = ncdfc->GetXType(varName);\n        if (!(NetCDFSimple::IsNCTypeFloat(type) || NetCDFSimple::IsNCTypeInt(type))) continue;\n\n        vector<string> sdimnames;\n        vector<string> scoordvars;\n        string         time_dim_name;\n        string         time_coordvar;\n\n        int rc = getVarCoordinates(ncdfc, varName, sdimnames, scoordvars, time_dim_name, time_coordvar);\n        if (rc < 0) {\n            SetErrMsg(\"Invalid variable : %s\", varName.c_str());\n            return (-1);\n        }\n\n        string meshName = DC::Mesh::MakeMeshName(sdimnames);\n\n        string units;\n        ncdfc->GetAtt(varName, \"units\", units);\n        if (!_udunits.ValidUnit(units)) { units = \"\"; }\n\n        double mv;\n        bool   has_missing = ncdfc->GetMissingValue(varName, mv);\n\n        if (!has_missing) {\n            dataVarsMap[varName] = DataVar(varName, units, DC::FLOAT, periodic, meshName, time_coordvar, DC::Mesh::NODE);\n        } else {\n            dataVarsMap[varName] = DataVar(varName, units, DC::FLOAT, periodic, meshName, time_coordvar, DC::Mesh::NODE, mv);\n        }\n\n        rc = DCUtils::CopyAtt(*ncdfc, varName, dataVarsMap[varName]);\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n"
  },
  {
    "path": "lib/vdc/DCMPAS.cpp",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <stdio.h>\n\n#ifdef _WINDOWS\n    #define _USE_MATH_DEFINES\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <cmath>\n\n#include <vapor/GeoUtil.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/DCUtils.h>\n#include <vapor/DCMPAS.h>\n\nusing namespace VAPoR;\nusing namespace std;\n\nnamespace {\n\n// MPAS variable and dimension names are hard-wired in the NetCDF\n// file :-(\n\n// Dimension names\n//\nconst string timeDimName = \"Time\";\nconst string nVertLevelsDimName = \"nVertLevels\";\nconst string nVertLevelsP1DimName = \"nVertLevelsP1\";\nconst string nCellsDimName = \"nCells\";\nconst string nVerticesDimName = \"nVertices\";\nconst string nEdgesDimName = \"nEdges\";\nconst string maxEdgesDimName = \"maxEdges\";\nconst string maxEdges2DimName = \"maxEdges2\";\nconst string vertexDegreeDimName = \"vertexDegree\";\n\nconst vector<string> requiredDimNames = {timeDimName, nCellsDimName, nVerticesDimName, vertexDegreeDimName};\n\nconst vector<string> optionalVertDimNames = {nVertLevelsDimName};\n\n// Horizontal coordinate variable names\n//\nconst string latCellVarName = \"latCell\";\nconst string lonCellVarName = \"lonCell\";\nconst string xCellVarName = \"xCell\";    // Cartesian coord - not used\nconst string yCellVarName = \"yCell\";    // Cartesian coord - not used\nconst string zCellVarName = \"zCell\";    // Cartesian coord - not used\n\nconst string latVertexVarName = \"latVertex\";\nconst string lonVertexVarName = \"lonVertex\";\nconst string xVertexVarName = \"xVertex\";    // Cartesian coord - not used\nconst string yVertexVarName = \"yVertex\";    // Cartesian coord - not used\nconst string zVertexVarName = \"zVertex\";    // Cartesian coord - not used\n\nconst string latEdgeVarName = \"latEdge\";\nconst string lonEdgeVarName = \"lonEdge\";\nconst string xEdgeVarName = \"xEdge\";    // Cartesian coord - not used\nconst string yEdgeVarName = \"yEdge\";    // Cartesian coord - not used\nconst string zEdgeVarName = \"zEdge\";    // Cartesian coord - not used\n\nconst vector<string> requiredHorizCoordVarNames = {latCellVarName, lonCellVarName, latVertexVarName, lonVertexVarName};\n\nconst vector<string> lonCoordVarNames = {lonCellVarName, lonVertexVarName, lonEdgeVarName};\n\n// Vertical coordinate variables\n//\nconst string zGridP1VarName = \"zgrid\";    // atmosphere vertical coordinate\nconst string zTopVarName = \"zTop\";        // ocean vertical coordinate\n\nconst vector<string> optionalVertCoordVarNames = {zGridP1VarName, zTopVarName};\n\n// Time coordinate variables\n//\nconst string xTimeVarName = \"xtime\";\n\n// Auxilliary variables (connectivity variables and others)\n//\nconst string cellsOnVertexVarName = \"cellsOnVertex\";\nconst string verticesOnCellVarName = \"verticesOnCell\";\nconst string verticesOnEdge = \"verticesOnEdge\";\nconst string edgesOnVertexVarName = \"edgesOnVertex\";\nconst string edgesOnCellVarName = \"edgesOnCell\";\nconst string nEdgesOnCellVarName = \"nEdgesOnCell\";\nconst string angleEdgeVarName = \"angleEdge\";\n\n// Special data variables\n//\nconst string uNormalVarName = \"u\";\nconst string uTangentialVarName = \"v\";\n\nconst vector<string> connectivityVarNames = {cellsOnVertexVarName, verticesOnCellVarName, verticesOnEdge, edgesOnCellVarName};\n\nconst vector<string> requiredAuxVarNames = {cellsOnVertexVarName, verticesOnCellVarName};\n\n// Meshes: dual mesh (triangle) and primal (hexagonal cell)\n//\nconst string mesh2DTriName = \"mesh2DTri\";\nconst string mesh3DTriName = \"mesh3DTri\";\nconst string mesh3DP1TriName = \"mesh3DTriP1\";\nconst string mesh2DCellName = \"mesh2DCell\";\nconst string mesh3DCellName = \"mesh3DCell\";\nconst string mesh3DP1CellName = \"mesh3DCellP1\";\n\n// Attributes\n//\nconst string coreNameAttr = \"core_name\";\nconst string onASphereAttr = \"on_a_sphere\";\n\n// Derived MPAS-A variable names. These don't appear in the MPAS output.\n// They are derived at run-time by the DCMPAS class\n//\nconst string zGridVertP1VarName = \"zgridVert\";\nconst string zGridVarName = \"zgridM1\";\nconst string zGridVertVarName = \"zgridVertM1\";\n\n// Derived MPAS-O variable names. These don't appear in the MPAS output.\n// They are derived at run-time by the DCMPAS class\n//\nconst string zTopVertVarName = \"zTopVert\";\n\nconst vector<string> requiredAttrNames = {\n    //\t\tcoreNameAttr,\n    onASphereAttr};\n\n// Product of elements in a vector\n//\nsize_t vproduct(vector<size_t> a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n\n// Return the name of the mesh for a specific set of dimension names\n//\nstring get_mesh_name(vector<string> dimnames)\n{\n    VAssert(dimnames.size() == 1 || dimnames.size() == 2);\n\n    if (dimnames[0] == nCellsDimName) {\n        if ((dimnames.size() == 2) && (dimnames[1] == nVertLevelsDimName)) {\n            // 3D dual mesh, unstaggered\n            //\n            return (mesh3DTriName);\n        } else if ((dimnames.size() == 2) && (dimnames[1] == nVertLevelsP1DimName)) {\n            // 3D dual mesh, staggered\n            //\n            return (mesh3DP1TriName);\n        } else {\n            // 2D dual mesh\n            //\n            return (mesh2DTriName);\n        }\n    }\n\n    if (dimnames[0] == nVerticesDimName) {\n        if ((dimnames.size() == 2) && (dimnames[1] == nVertLevelsDimName)) {\n            // 3D primal mesh, unstaggered\n            //\n            return (mesh3DCellName);\n        } else if ((dimnames.size() == 2) && (dimnames[1] == nVertLevelsP1DimName)) {\n            // 3D primal mesh, staggered\n            //\n            return (mesh3DP1CellName);\n        } else {\n            // 2D primal mesh\n            //\n            return (mesh2DCellName);\n        }\n    }\n    return (\"\");\n}\n\n// Is 'varname' a connectivity variable?\n//\nbool is_connectivity_var(string varname) { return (find(connectivityVarNames.begin(), connectivityVarNames.end(), varname) != connectivityVarNames.end()); }\n\nbool is_lat_or_lon(string varname) { return (find(requiredHorizCoordVarNames.begin(), requiredHorizCoordVarNames.end(), varname) != requiredHorizCoordVarNames.end()); }\n\nbool is_lon(string varname) { return (find(lonCoordVarNames.begin(), lonCoordVarNames.end(), varname) != lonCoordVarNames.end()); }\n\nvoid rad2degrees(float *buf, size_t n)\n{\n    for (size_t i = 0; i < n; i++) { buf[i] = buf[i] * 180.0 / M_PI; }\n}\n\n// MPAS orders 3D data with vertical axis varying fastest. VAPOR\n// wants horizontal dimensions varying fastest. Return true if this is\n// a 3D variable with transposed horizontal and vertical dimensions\n//\nbool isTransposed(NetCDFCollection *ncdfc, string varname)\n{\n    vector<string> v = ncdfc->GetSpatialDimNames(varname);\n    if (v.size() != 2) return (false);\n\n    if ((v[1] == nVertLevelsDimName || v[1] == nVertLevelsP1DimName)) { return (true); }\n\n    return (false);\n}\n\nbool isEdgeVariable(NetCDFCollection *ncdfc, string varname)\n{\n    vector<string> v = ncdfc->GetSpatialDimNames(varname);\n\n    if (v[0] == nEdgesDimName) { return (true); }\n\n    return (false);\n}\ntemplate<class T> int _xgetVar(NetCDFCollection *ncdfc, size_t ts, string varname, T *buf)\n{\n    int fd = ncdfc->OpenRead(ts, varname);\n    if (fd < 0) return (fd);\n\n    int rc = ncdfc->Read(buf, fd);\n    if (rc < 0) return (fd);\n\n    return (ncdfc->Close(fd));\n}\n\nDC::XType netcdf_to_dc_xtype(int t)\n{\n    switch (t) {\n    case NC_DOUBLE: return (DC::XType::DOUBLE);\n    case NC_INT64: return (DC::XType::INT64);\n    case NC_CHAR: return (DC::XType::TEXT);\n    default: return (DC::XType::INVALID);\n    }\n}\n\n};    // namespace\n\nDCMPAS::DCMPAS()\n{\n    _ncdfc = NULL;\n    _dimsMap.clear();\n    _coordVarsMap.clear();\n    _dataVarsMap.clear();\n    _meshMap.clear();\n    _cellVars.clear();\n    _pointVars.clear();\n    _edgeVars.clear();\n    _hasVertical = false;\n}\n\nDCMPAS::~DCMPAS()\n{\n    if (_ncdfc) delete _ncdfc;\n\n    vector<string> names = _dvm.GetDataVarNames();\n    for (int i = 0; i < names.size(); i++) {\n        if (_dvm.GetVar(names[i])) delete _dvm.GetVar(names[i]);\n    }\n}\n\nint DCMPAS::initialize(const vector<string> &files, const std::vector<string> &options)\n{\n    if (_ncdfc) delete _ncdfc;\n    _ncdfc = nullptr;\n\n    // Use UDUnits for unit conversion\n    //\n    int rc = _udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", _udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n    NetCDFCollection *ncdfc = new NetCDFCollection();\n\n    // Initialize NetCDFCollection class\n    //\n    vector<string> time_dimnames(1, timeDimName);\n    rc = ncdfc->Initialize(files, time_dimnames, vector<string>());\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize netCDF data collection for reading\");\n        return (-1);\n    }\n\n    // Make sure NetCDF file(s) have everything we need\n    //\n    rc = _CheckRequiredFields(ncdfc);\n    if (rc < 0) return (-1);\n\n    _hasVertical = _HasVertical(ncdfc);\n\n    //\n    //  Get the dimensions of the grid.\n    //\tInitializes members: _dimsMap\n    //\n    rc = _InitDimensions(ncdfc);\n    if (rc < 0) {\n        SetErrMsg(\"No valid dimensions\");\n        return (-1);\n    }\n\n    rc = _InitCoordvars(ncdfc);\n    if (rc < 0) { return (-1); }\n\n    // Create derived coordinate variables.\n    //\n    rc = _InitDerivedVars(ncdfc);\n    if (rc < 0) {\n        SetErrMsg(\"Failed to created required derived coordinate variables\");\n        return (-1);\n    }\n\n    rc = _InitMeshes(ncdfc);\n    if (rc < 0) return (-1);\n\n    //\n    // Identify data and coordinate variables. Sets up members:\n    // Initializes members: _dataVarsMap, _coordVarsMap, _meshMap\n    //\n    rc = _InitAuxVars(ncdfc);\n    if (rc < 0) return (-1);\n\n    // Finally, get metdata for all data variables\n    //\n    rc = _InitDataVars(ncdfc);\n    if (rc < 0) return (-1);\n\n    // If u and v variables are present create derived Uzonal and Umeridional\n    // variables.\n    //\n    if (ncdfc->VariableExists(uNormalVarName) && ncdfc->VariableExists(uTangentialVarName)) {\n        for (auto varname : {\"Uzonal\", \"Umeridional\"}) {\n            bool                   zonalFlag = (varname == string(\"Uzonal\"));\n            DerivedZonalMeridonal *derivedVar = new DerivedZonalMeridonal(varname, this, ncdfc, uNormalVarName, uTangentialVarName, zonalFlag);\n\n            rc = derivedVar->Initialize();\n            if (rc < 0) {\n                delete (derivedVar);\n                return (-1);\n            }\n\n            _dvm.AddDataVar(derivedVar);\n\n            DC::DataVar dvarInfo;\n            (void)derivedVar->GetDataVarInfo(dvarInfo);\n            _dataVarsMap[varname] = dvarInfo;\n        }\n    }\n\n    _ncdfc = ncdfc;\n\n    return (0);\n}\n\ntemplate<class T> bool DCMPAS::_getAttTemplate(string varname, string attname, T &values) const\n{\n    if (varname.empty()) {\n        _ncdfc->GetAtt(\"\", attname, values);\n        return (true);\n    }\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (status);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (status);\n\n    att.GetValues(values);\n\n    return (true);\n}\n\nbool DCMPAS::getAtt(string varname, string attname, vector<double> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCMPAS::getAtt(string varname, string attname, vector<long> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCMPAS::getAtt(string varname, string attname, string &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nstd::vector<string> DCMPAS::getAttNames(string varname) const\n{\n    if (varname.empty()) return (_ncdfc->GetAttNames(\"\"));\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (vector<string>());\n\n    vector<string> names;\n\n    const std::map<string, Attribute> &         atts = var.GetAttributes();\n    std::map<string, Attribute>::const_iterator itr;\n    for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nDC::XType DCMPAS::getAttType(string varname, string attname) const\n{\n    if (varname.empty()) { return (netcdf_to_dc_xtype(_ncdfc->GetAttType(\"\", attname))); }\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (DC::INVALID);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (DC::INVALID);\n\n    return (att.GetXType());\n}\n\nbool DCMPAS::getDimension(string dimname, DC::Dimension &dimension) const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    itr = _dimsMap.find(dimname);\n    if (itr == _dimsMap.end()) return (false);\n\n    dimension = itr->second;\n    return (true);\n}\n\nstd::vector<string> DCMPAS::getDimensionNames() const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    vector<string> names;\n\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nvector<string> DCMPAS::getMeshNames() const\n{\n    vector<string>                         mesh_names;\n    std::map<string, Mesh>::const_iterator itr = _meshMap.begin();\n    for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); }\n    return (mesh_names);\n}\n\nbool DCMPAS::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    map<string, Mesh>::const_iterator itr = _meshMap.find(mesh_name);\n    if (itr == _meshMap.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nbool DCMPAS::getCoordVarInfo(string varname, DC::CoordVar &cvar) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr == _coordVarsMap.end()) { return (false); }\n\n    cvar = itr->second;\n    return (true);\n}\n\nbool DCMPAS::getDataVarInfo(string varname, DC::DataVar &datavar) const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    itr = _dataVarsMap.find(varname);\n    if (itr == _dataVarsMap.end()) { return (false); }\n\n    datavar = itr->second;\n    return (true);\n}\n\nbool DCMPAS::getAuxVarInfo(string varname, DC::AuxVar &auxvar) const\n{\n    map<string, DC::AuxVar>::const_iterator itr;\n\n    itr = _auxVarsMap.find(varname);\n    if (itr == _auxVarsMap.end()) { return (false); }\n\n    auxvar = itr->second;\n    return (true);\n}\n\nbool DCMPAS::getBaseVarInfo(string varname, DC::BaseVar &var) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr != _coordVarsMap.end()) {\n        var = itr->second;\n        return (true);\n    }\n\n    map<string, DC::DataVar>::const_iterator itr1 = _dataVarsMap.find(varname);\n    if (itr1 != _dataVarsMap.end()) {\n        var = itr1->second;\n        return (true);\n    }\n\n    return (false);\n}\n\nstd::vector<string> DCMPAS::getDataVarNames() const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nstd::vector<string> DCMPAS::getCoordVarNames() const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nstd::vector<string> DCMPAS::getAuxVarNames() const\n{\n    map<string, DC::AuxVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _auxVarsMap.begin(); itr != _auxVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nint DCMPAS::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    if (_dvm.HasVar(varname)) { return (_dvm.GetDimLensAtLevel(varname, 0, dims_at_level, bs_at_level, -1)); }\n\n    bool ok = GetVarDimLens(varname, true, dims_at_level, -1);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\n// Read the MPAS nEdgesOnCell auxiliary variable and store it for\n// use later\n//\nint DCMPAS::_read_nEdgesOnCell(size_t ts)\n{\n    DC::Dimension dimension;\n    bool          ok = GetDimension(nCellsDimName, dimension, -1);\n    if (!ok) {\n        SetErrMsg(\"Invalid MPAS auxiliary variable: %s\", nEdgesOnCellVarName.c_str());\n        return (-1);\n    }\n\n    int *buf = (int *)_nEdgesOnCellBuf.Alloc(dimension.GetLength() * sizeof(*buf));\n\n    int fd = _ncdfc->OpenRead(ts, nEdgesOnCellVarName);\n    if (fd < 0) return (fd);\n\n    int rc = _ncdfc->Read(buf, fd);\n    if (rc < 0) return (fd);\n\n    return (_ncdfc->Close(fd));\n}\n\n// Read a floating point variable (data or coordinate) into a SmartBuf\n//\nint DCMPAS::_readVarToSmartBuf(size_t ts, string varname, Wasp::SmartBuf &smartBuf)\n{\n    vector<size_t> dims;\n    bool           ok = GetVarDimLens(varname, true, dims, -1);\n    VAssert(ok);\n\n    size_t n = vproduct(dims);\n    float *buf = (float *)smartBuf.Alloc(n * sizeof(*buf));\n\n    int fd = _ncdfc->OpenRead(ts, varname);\n    if (fd < 0) return (fd);\n\n    int rc = _ncdfc->Read(buf, fd);\n    if (rc < 0) return (fd);\n\n\n    if (is_lat_or_lon(varname)) { rad2degrees((float *)buf, n); }\n\n    if (is_lon(varname)) { GeoUtil::ShiftLon(buf, buf + n, 180.0); }\n\n    return (_ncdfc->Close(fd));\n}\n\n// Read the longitude coordinates for cell and vertices. Need these\n// to split the periodic mesh\n//\nint DCMPAS::_readCoordinates(size_t ts)\n{\n    int rc = _readVarToSmartBuf(ts, lonCellVarName, _lonCellSmartBuf);\n    if (rc < 0) return (rc);\n\n    rc = _readVarToSmartBuf(ts, lonVertexVarName, _lonVertexSmartBuf);\n    if (rc < 0) return (rc);\n\n    return (0);\n}\n\n// MPAS uses an auxiliary array (the variable nEdgesOnCelll) to\n// indicate the number of elements (edges or vertices) in\n// multi-dimensional arrays with varying dimension lengths. But DC uses\n// a padding flag: -1. So using nEdgesOnCell we pad the fixed size\n// DC connectivity array with -1.\n//\nvoid DCMPAS::_addMissingFlag(int *data) const\n{\n    int *nEdgesOnCell = (int *)_nEdgesOnCellBuf.GetBuf();\n\n    DC::Dimension dimension;\n    bool          ok = GetDimension(nCellsDimName, dimension, -1);\n    VAssert(ok);\n\n    size_t nCells = dimension.GetLength();\n\n    ok = GetDimension(maxEdgesDimName, dimension, -1);\n    VAssert(ok);\n\n    size_t nMaxEdges = dimension.GetLength();\n\n    // Add padding\n    //\n    for (size_t j = 0; j < nCells; j++) {\n        for (int i = nEdgesOnCell[j]; i < nMaxEdges; i++) { data[j * nMaxEdges + i] = -1; }\n    }\n}\n\n// MPAS data on sphere is periodic. But we're projecting the geographic\n// data to Cartesian coordinates. We need split the cells that straddle\n// the split location, here chose to be 180 (-180) degrees\n//\nvoid DCMPAS::_splitOnBoundary(string varname, int *connData) const\n{\n    vector<size_t> connDims;\n    bool           ok = GetVarDimLens(varname, true, connDims, -1);\n    VAssert(ok && connDims.size() == 2);\n\n    // Dimensions for vertex lon\n    //\n    vector<size_t> lonVertexDims;\n    ok = GetVarDimLens(lonVertexVarName, true, lonVertexDims, -1);\n    VAssert(ok && lonVertexDims.size() == 1);\n\n    // Dimensions for cell lon\n    //\n    vector<size_t> lonCellDims;\n    ok = GetVarDimLens(lonCellVarName, true, lonCellDims, -1);\n    VAssert(ok && lonCellDims.size() == 1);\n\n    // float *lonBuf1 = NULL;\n    float *lonBuf2 = NULL;\n    if (connDims[1] == lonVertexDims[0]) {\n        // lonBuf1 = (float *) _lonVertexSmartBuf.GetBuf();\n        lonBuf2 = (float *)_lonCellSmartBuf.GetBuf();\n    } else if (connDims[1] == lonCellDims[0]) {\n        // lonBuf1 = (float *) _lonCellSmartBuf.GetBuf();\n        lonBuf2 = (float *)_lonVertexSmartBuf.GetBuf();\n    } else {\n        VAssert(0);\n    }\n\n    // For each cell (vertex) in the connectivity array make sure\n    // that the cell's (vertices') coordinates and all of it's neighboring\n    // vertices (cells) are on the same side of the split line for\n    // longitude If not, introduce a split\n    // by changing the index of the offending vertices (cells) to -2,\n    // the boundary marker. This code assumes the valid lon coordiates\n    // are 0.0 .. 2*M_PI, as\n    // per the MPAS Mesh Specification, Version 1.0 (Oct. 8, 2015) document.\n    //\n    int n = connDims[0];\n    for (size_t j = 0; j < connDims[1]; j++) {\n        // MPAS apparently uses a 0 to indicate cell boundaries. This is a undocumented feature\n        // the we need to handle here\n        //\n        bool mpas_boundary_marker = false;\n        for (size_t i = 0; i < n; i++) {\n            if (connData[j * n + i] == 0) {\n                for (size_t ii = 0; ii < n; ii++) { connData[j * n + ii] = -2; }\n                mpas_boundary_marker = true;\n                break;\n            }\n        }\n        if (mpas_boundary_marker) continue;\n\n        // Ha ha. despite MPAS documentation longitude may run -pi to pi\n        //\n        double lon1 = lonBuf2[connData[j * n] - 1];\n        if (lon1 > 180.0) lon1 -= 360.0;\n        for (size_t i = 1; i < n && connData[j * n + i] >= 0; i++) {\n            size_t index = connData[j * n + i] - 1;    // Arrg. Index starts from 1!!\n\n            double lon2 = lonBuf2[index];\n\n            // Ha ha. despite MPAS documentation longitude may run -pi to pi\n            //\n            if (lon2 > 180.0) lon2 -= 360.0;\n\n            // Ugh. Test for cell stradling -pi and pi\n            //\n            if (fabs(lon1 - lon2) > 180.0 * 0.5) { connData[j * n + i] = -2; }\n        }\n    }\n}\n\nint DCMPAS::openVariableRead(size_t ts, string varname, int, int)\n{\n    int  aux;\n    bool derivedFlag;\n    if (_dvm.HasVar(varname)) {\n        aux = _dvm.OpenVariableRead(ts, varname);\n        derivedFlag = true;\n    } else {\n        aux = _ncdfc->OpenRead(ts, varname);\n        derivedFlag = false;\n\n        // Special handling for some auxiliary variables\n        //\n        if (varname == verticesOnCellVarName) {\n            if (_read_nEdgesOnCell(ts) < 0) return (-1);\n        }\n\n        if (is_connectivity_var(varname)) {\n            if (_readCoordinates(ts) < 0) return (-1);\n        }\n    }\n\n    MPASFileObject *w = new MPASFileObject(ts, varname, 0, 0, aux, derivedFlag);\n\n    return (_fileTable.AddEntry(w));\n}\n\nint DCMPAS::closeVariable(int fd)\n{\n    MPASFileObject *w = (MPASFileObject *)_fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    int rc;\n    if (w->GetDerivedFlag()) {\n        rc = _dvm.CloseVariable(aux);\n    } else {\n        rc = _ncdfc->Close(aux);\n    }\n    _fileTable.RemoveEntry(fd);\n\n    delete w;\n    return (rc);\n}\n\nint DCMPAS::_readRegionTransposed(MPASFileObject *w, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 1 || min.size() == 2);\n    VAssert(min.size() == max.size());\n\n    int aux = w->GetAux();\n\n    vector<size_t> ncdf_start = min;\n    vector<size_t> ncdf_max = max;\n\n    vector<size_t> ncdf_count;\n    for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); }\n\n    float *buf = new float[vproduct(ncdf_count)];\n\n    if (min.size() == 2) {\n        int rc = _ncdfc->Read(ncdf_start, ncdf_count, buf, aux);\n        if (rc < 0) return (-1);\n\n        Wasp::Transpose(buf, region, ncdf_count[1], ncdf_count[0]);\n    }\n    // No transpose needed. 1D variable\n    //\n    else {\n        int rc = _ncdfc->Read(ncdf_start, ncdf_count, region, aux);\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\nint DCMPAS::_readRegionEdgeVariable(MPASFileObject *w, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 1 || min.size() == 2);\n    VAssert(min.size() == max.size());\n\n    vector<size_t> dims = _ncdfc->GetDims(edgesOnVertexVarName);\n    int *          edgesOnVertex = new int[vproduct(dims)];\n    int            rc = _xgetVar(_ncdfc, w->GetTS(), edgesOnVertexVarName, edgesOnVertex);\n    if (rc < 0) {\n        delete[] edgesOnVertex;\n        return (-1);\n    }\n\n    size_t vertexDegree = dims[1];\n    VAssert(vertexDegree == 3);\n\n    string varname = w->GetVarname();\n\n    // Don't need to reverse dims because we have to do a tranpose anyway\n    //\n    dims = _ncdfc->GetSpatialDims(varname);\n    float *edgeVariable = new float[vproduct(dims)];\n\n    vector<size_t> minAll, maxAll;\n    for (int i = 0; i < dims.size(); i++) {\n        VAssert(dims[i] > 0);\n        minAll.push_back(0);\n        maxAll.push_back(dims[i] - 1);\n    }\n\n    rc = _readRegionTransposed(w, minAll, maxAll, edgeVariable);\n    if (rc < 0) {\n        delete[] edgesOnVertex;\n        delete[] edgeVariable;\n        return (-1);\n    }\n\n    size_t j0 = min.size() == 2 ? min[1] : 0;\n    size_t j1 = max.size() == 2 ? max[1] : 0;\n\n    float wgt = 1.0 / (float)vertexDegree;\n    for (size_t j = j0; j <= j1; j++) {\n        for (size_t i = min[0], ii = 0; i <= max[0]; i++, ii++) {\n            size_t vidx0 = edgesOnVertex[i * vertexDegree + 0] - 1;\n            size_t vidx1 = edgesOnVertex[i * vertexDegree + 1] - 1;\n            size_t vidx2 = edgesOnVertex[i * vertexDegree + 2] - 1;\n\n            region[j * (max[0] - min[0] + 1) + ii] = edgeVariable[j * dims[0] + vidx0] * wgt + edgeVariable[j * dims[0] + vidx1] * wgt + edgeVariable[j * dims[0] + vidx2] * wgt;\n        }\n    }\n\n    delete[] edgesOnVertex;\n    delete[] edgeVariable;\n\n    return (0);\n}\n\ntemplate<class T> int DCMPAS::_readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region)\n{\n    MPASFileObject *w = (MPASFileObject *)_fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int    aux = w->GetAux();\n    string varname = w->GetVarname();\n\n    if (w->GetDerivedFlag()) { return (_dvm.ReadRegion(aux, min, max, region)); }\n\n    if (isEdgeVariable(_ncdfc, varname)) {\n        VAssert((std::is_same<float *, T *>::value) == true);\n        return (_readRegionEdgeVariable(w, min, max, (float *)region));\n\n    } else if (isTransposed(_ncdfc, varname)) {\n        VAssert((std::is_same<float *, T *>::value) == true);\n        return (_readRegionTransposed(w, min, max, (float *)region));\n    }\n\n    // Need to reverse coordinate ordering for NetCDFCollection API, which\n    // orders coordinates from slowest to fastest. DC class expects order\n    // from fastest to slowest. Unless the variable is tranposed, then\n    // we need to \"untranspose\" it.\n    //\n    vector<size_t> ncdf_start = min;\n    vector<size_t> ncdf_max = max;\n\n    reverse(ncdf_start.begin(), ncdf_start.end());\n    reverse(ncdf_max.begin(), ncdf_max.end());\n\n    vector<size_t> ncdf_count;\n    for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); }\n\n    int rc = _ncdfc->Read(ncdf_start, ncdf_count, region, aux);\n    if (rc < 0) return (-1);\n\n    // If reading a coordinate variable need to convert from\n    // radians to degrees :-(\n    //\n    if (is_lat_or_lon(varname)) { rad2degrees((float *)region, max[0] - min[0] + 1); }\n\n    // Special handling for some auxiliary variables\n    //\n    if (varname == verticesOnCellVarName) { _addMissingFlag((int *)region); }\n\n    if (is_connectivity_var(varname)) { _splitOnBoundary(varname, (int *)region); }\n\n    return (0);\n}\n\nbool DCMPAS::variableExists(size_t ts, string varname, int, int) const\n{\n    if (_dvm.HasVar(varname)) { return (_dvm.VariableExists(ts, varname, 0, 0)); }\n\n    return (_ncdfc->VariableExists(ts, varname));\n}\n\nint DCMPAS::_InitCoordvars(NetCDFCollection *ncdfc)\n{\n    string time_dim_name = \"\";\n\n    // longitude coordinates, native (those found in MPAS output files), and\n    // derived (those created on-the-fly by the DCMPAS class. The latter\n    // are longitude coordinate variables mapped to PCS coordinates (e.g\n    // meters on the ground)\n    //\n    vector<string> cvars = {lonCellVarName, lonVertexVarName, lonEdgeVarName};\n    for (int i = 0; i < cvars.size(); i++) {\n        vector<bool>   periodic(true);\n        vector<string> dimnames;\n\n        string units = \"degrees_east\";\n        int    axis = 0;\n        string name = cvars[i];\n        dimnames = ncdfc->GetDimNames(name);\n        if (dimnames.size() != 1) continue;\n\n        _coordVarsMap[name] = CoordVar(name, units, DC::FLOAT, periodic, axis, false, dimnames, time_dim_name);\n\n        int rc = DCUtils::CopyAtt(*ncdfc, name, _coordVarsMap[name]);\n        if (rc < 0) return (-1);\n    }\n\n    // LAtitude coordinate variables\n    //\n    cvars = {latCellVarName, latVertexVarName, latEdgeVarName};\n    for (int i = 0; i < cvars.size(); i++) {\n        vector<bool>   periodic(false);\n        vector<string> dimnames;\n\n        string units = \"degrees_north\";\n        int    axis = 1;\n        string name = cvars[i];\n        dimnames = ncdfc->GetDimNames(name);\n        if (dimnames.size() != 1) continue;\n\n        _coordVarsMap[name] = CoordVar(name, units, DC::FLOAT, periodic, axis, false, dimnames, time_dim_name);\n\n        int rc = DCUtils::CopyAtt(*ncdfc, name, _coordVarsMap[name]);\n        if (rc < 0) return (-1);\n    }\n\n    vector<bool>   periodic(false);\n    vector<string> dimnames;\n\n    if (_hasVertical && (_isAtmosphere(ncdfc) || _isOcean(ncdfc))) {\n        string name;\n        if (_isAtmosphere(ncdfc)) {\n            name = zGridP1VarName;\n        } else {\n            name = zTopVarName;\n        }\n\n        // Vertical coordinate variables\n        //\n        string units = \"meters\";\n        int    axis = 2;\n        dimnames = ncdfc->GetSpatialDimNames(name);\n        time_dim_name = ncdfc->GetTimeDimName(name);\n        VAssert(dimnames.size() == 2);\n\n        _coordVarsMap[name] = CoordVar(name, units, DC::FLOAT, periodic, axis, false, dimnames, time_dim_name);\n        int rc = DCUtils::CopyAtt(*ncdfc, name, _coordVarsMap[name]);\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\n// Create all of the derived coordinate variables\n//\nint DCMPAS::_InitDerivedVars(NetCDFCollection *ncdfc)\n{\n    int rc = _InitVerticalCoordinatesDerivedAtmosphere(ncdfc);\n    if (rc < 0) return (-1);\n\n    rc = _InitVerticalCoordinatesDerivedOcean(ncdfc);\n    if (rc < 0) return (-1);\n\n    DC::CoordVar cvarInfo;\n    if (ncdfc->VariableExists(ncdfc->GetNumTimeSteps() - 1, xTimeVarName)) {\n        // Create and install the Time coordinate variable\n        //\n        DerivedCoordVar_WRFTime *derivedVar = new DerivedCoordVar_WRFTime(timeDimName, ncdfc, xTimeVarName, timeDimName);\n\n        rc = derivedVar->Initialize();\n        if (rc < 0) return (-1);\n\n        _dvm.AddCoordVar(derivedVar);\n\n        // Time coordinate is a derived variable\n        //\n        bool ok = _dvm.GetCoordVarInfo(timeDimName, cvarInfo);\n        VAssert(ok);\n    } else {\n        // Synthesize and install a Time coordinate variable\n        //\n        DerivedCoordVar_Time *derivedVar = new DerivedCoordVar_Time(timeDimName, timeDimName, ncdfc->GetNumTimeSteps());\n\n        rc = derivedVar->Initialize();\n        if (rc < 0) return (-1);\n\n        _dvm.AddCoordVar(derivedVar);\n\n        // Time coordinate is a derived variable\n        //\n        bool ok = _dvm.GetCoordVarInfo(timeDimName, cvarInfo);\n        VAssert(ok);\n    }\n\n    _coordVarsMap[timeDimName] = cvarInfo;\n\n    return (0);\n}\n\nint DCMPAS::_InitVerticalCoordinatesDerivedAtmosphere(NetCDFCollection *ncdfc)\n{\n    // MPAS-A only outputs a single vertical coordinate variable, zgrid,\n    // which is the elevation of the staggered grid, primary (cell) mesh.\n    //\n\n    if (!_hasVertical) return (0);\n    if (!_isAtmosphere(ncdfc)) return (0);\n\n    DerivedCoordVar *derivedVar = NULL;\n\n    derivedVar = new DerivedCoordVar_UnStaggered(zGridVarName, nVertLevelsDimName, this, zGridP1VarName, nVertLevelsP1DimName);\n\n    int rc = derivedVar->Initialize();\n    if (rc < 0) return (-1);\n    _dvm.AddCoordVar(derivedVar);\n\n    DC::CoordVar cvarInfo;\n    bool         ok = _dvm.GetCoordVarInfo(zGridVarName, cvarInfo);\n    VAssert(ok);\n    _coordVarsMap[zGridVarName] = cvarInfo;\n\n    derivedVar = new DerivedCoordVertFromCell(zGridVertP1VarName, nVerticesDimName, this, zGridP1VarName, cellsOnVertexVarName);\n\n    rc = derivedVar->Initialize();\n    if (rc < 0) return (-1);\n    _dvm.AddCoordVar(derivedVar);\n\n    ok = _dvm.GetCoordVarInfo(zGridVertP1VarName, cvarInfo);\n    VAssert(ok);\n    _coordVarsMap[zGridVertP1VarName] = cvarInfo;\n\n    derivedVar = new DerivedCoordVertFromCell(zGridVertVarName, nVerticesDimName, this, zGridVarName, cellsOnVertexVarName);\n\n    rc = derivedVar->Initialize();\n    if (rc < 0) return (-1);\n    _dvm.AddCoordVar(derivedVar);\n\n    ok = _dvm.GetCoordVarInfo(zGridVertVarName, cvarInfo);\n    VAssert(ok);\n    _coordVarsMap[zGridVertVarName] = cvarInfo;\n\n    return (0);\n}\n\nint DCMPAS::_InitVerticalCoordinatesDerivedOcean(NetCDFCollection *ncdfc)\n{\n    // MPAS-O only outputs a single vertical coordinate variable, zTop,\n    // which is the elevation of the primary (cell) mesh.\n    //\n\n    if (!_hasVertical) return (0);\n    if (!_isOcean(ncdfc)) return (0);\n\n    DerivedCoordVar *derivedVar = NULL;\n\n    derivedVar = new DerivedCoordVertFromCell(zTopVertVarName, nVerticesDimName, this, zTopVarName, cellsOnVertexVarName);\n\n    int rc = derivedVar->Initialize();\n    if (rc < 0) return (-1);\n    _dvm.AddCoordVar(derivedVar);\n\n    DC::CoordVar cvarInfo;\n    bool         ok = _dvm.GetCoordVarInfo(zTopVertVarName, cvarInfo);\n    VAssert(ok);\n    _coordVarsMap[zTopVertVarName] = cvarInfo;\n\n    return (0);\n}\n\nint DCMPAS::_CheckRequiredFields(NetCDFCollection *ncdfc) const\n{\n    vector<string>::const_iterator itr;\n\n    // Check for dimensions\n    //\n    vector<string> dimnames = ncdfc->GetDimNames();\n    for (int i = 0; i < requiredDimNames.size(); i++) {\n        string s = requiredDimNames[i];\n\n        itr = find(dimnames.begin(), dimnames.end(), s);\n        if (itr == dimnames.end()) {\n            SetErrMsg(\"Missing required dimension \\\"%s\\\"\", s.c_str());\n            return (-1);\n        }\n    }\n\n    // Check for horizontal coordinate variables and auxiallary vars\n    //\n    vector<string> varnames;\n    for (int ndim = 1; ndim < 3; ndim++) {\n        vector<string> v = ncdfc->GetVariableNames(ndim, true);\n        varnames.insert(varnames.end(), v.begin(), v.end());\n    }\n\n    for (int i = 0; i < requiredHorizCoordVarNames.size(); i++) {\n        string s = requiredHorizCoordVarNames[i];\n\n        itr = find(varnames.begin(), varnames.end(), s);\n        if (itr == varnames.end()) {\n            SetErrMsg(\"Missing required dimension \\\"%s\\\"\", s.c_str());\n            return (-1);\n        }\n    }\n\n    for (int i = 0; i < requiredAuxVarNames.size(); i++) {\n        string s = requiredAuxVarNames[i];\n\n        itr = find(varnames.begin(), varnames.end(), s);\n        if (itr == varnames.end()) {\n            SetErrMsg(\"Missing required dimension \\\"%s\\\"\", s.c_str());\n            return (-1);\n        }\n    }\n\n    // Check for required global attrs\n    //\n    vector<string> attnames = ncdfc->GetAttNames(\"\");\n    for (int i = 0; i < requiredAttrNames.size(); i++) {\n        string s = requiredAttrNames[i];\n\n        itr = find(attnames.begin(), attnames.end(), s);\n        if (itr == attnames.end()) {\n            SetErrMsg(\"Missing required dimension \\\"%s\\\"\", s.c_str());\n            return (-1);\n        }\n    }\n\n    return (0);\n}\n\nbool DCMPAS::_HasVertical(NetCDFCollection *ncdfc) const\n{\n    vector<string>::const_iterator itr;\n\n    // Check for dimensions\n    //\n    vector<string> dimnames = ncdfc->GetDimNames();\n    for (int i = 0; i < optionalVertDimNames.size(); i++) {\n        string s = optionalVertDimNames[i];\n\n        itr = find(dimnames.begin(), dimnames.end(), s);\n        if (itr == dimnames.end()) { return (false); }\n    }\n\n    vector<string> varnames;\n    for (int ndim = 1; ndim < 3; ndim++) {\n        vector<string> v = ncdfc->GetVariableNames(ndim, true);\n        varnames.insert(varnames.end(), v.begin(), v.end());\n    }\n\n    for (int i = 0; i < optionalVertCoordVarNames.size(); i++) {\n        string s = optionalVertCoordVarNames[i];\n\n        itr = find(varnames.begin(), varnames.end(), s);\n        if (itr != varnames.end()) { return (true); }\n    }\n    return (false);\n}\n\n// Get Space and time dimensions from MPAS data set. Initialize\n// _dimsMap\n//\nint DCMPAS::_InitDimensions(NetCDFCollection *ncdfc)\n{\n    _dimsMap.clear();\n\n    // Get dimension names and lengths for all dimensions in the\n    // MPAS data set.\n    //\n    vector<string> dimnames = ncdfc->GetDimNames();\n    vector<size_t> dimlens = ncdfc->GetDims();\n    VAssert(dimnames.size() == dimlens.size());\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        Dimension dim(dimnames[i], dimlens[i]);\n        _dimsMap[dimnames[i]] = dim;\n    }\n\n    return (0);\n}\n\n// Given a data variable name return the variable's dimensions and\n// associated coordinate variables.\n//\n// The order of the returned vectors\n// is significant.\n//\nint DCMPAS::_GetVarCoordinates(NetCDFCollection *ncdfc, string varname, vector<string> &sdimnames, vector<string> &scoordvars, string &time_dim_name, string &time_coordvar)\n{\n    sdimnames.clear();\n    scoordvars.clear();\n    time_dim_name.clear();\n    time_coordvar.clear();\n\n    vector<string> dimnames = ncdfc->GetDimNames(varname);\n    VAssert(dimnames.size() >= 1);\n\n    if (ncdfc->IsTimeVarying(varname)) {\n        time_dim_name = dimnames[0];\n        time_coordvar = timeDimName;\n        dimnames.erase(dimnames.begin());\n    }\n\n    string verticalCellVarName;\n    string verticalVertexVarName;\n    if (_isAtmosphere(ncdfc)) {\n        verticalCellVarName = zGridVarName;\n        verticalVertexVarName = zGridVertVarName;\n    } else {\n        verticalCellVarName = zTopVarName;\n        verticalVertexVarName = zTopVertVarName;\n    }\n\n    if (find(_cellVars.begin(), _cellVars.end(), varname) != _cellVars.end()) {\n        sdimnames.push_back(nCellsDimName);\n        scoordvars.push_back(lonCellVarName);\n        scoordvars.push_back(latCellVarName);\n\n        if (dimnames.size() > 1) {\n            sdimnames.push_back(dimnames[1]);\n            if (dimnames[1] == nVertLevelsDimName) {\n                scoordvars.push_back(verticalCellVarName);\n            } else {\n                scoordvars.push_back(zGridP1VarName);\n            }\n        }\n    } else if (find(_pointVars.begin(), _pointVars.end(), varname) != _pointVars.end()) {\n        sdimnames.push_back(nVerticesDimName);\n        scoordvars.push_back(lonVertexVarName);\n        scoordvars.push_back(latVertexVarName);\n\n        if (dimnames.size() > 1) {\n            sdimnames.push_back(dimnames[1]);\n            if (dimnames[1] == nVertLevelsDimName) {\n                scoordvars.push_back(verticalVertexVarName);\n            } else {\n                scoordvars.push_back(zGridVertP1VarName);\n            }\n        }\n    } else if (find(_edgeVars.begin(), _edgeVars.end(), varname) != _edgeVars.end()) {\n        sdimnames.push_back(nEdgesDimName);\n        scoordvars.push_back(lonEdgeVarName);\n        scoordvars.push_back(latEdgeVarName);\n\n        if (dimnames.size() > 1) {\n            sdimnames.push_back(dimnames[1]);\n            if (dimnames[1] == nVertLevelsDimName) {\n                scoordvars.push_back(verticalCellVarName);\n            } else {\n                scoordvars.push_back(zGridP1VarName);\n            }\n        }\n    } else {\n        VAssert(0);\n    }\n\n    return (0);\n}\n\nint DCMPAS::_InitMeshes(NetCDFCollection *ncdfc)\n{\n    // Max vertices or edges per cell\n    //\n    DC::Dimension dimension;\n    bool          ok = GetDimension(maxEdgesDimName, dimension, -1);\n    VAssert(ok);\n\n    //\n    // Dual meshes (triangle mesh)\n    // N.B. for the dual node the meanings of cellsOnVertexVarName,\n    // and verticesOnCellVarName are reversed.\n    //\n    // 2D, layered, and layered with staggered dimensions\n    //\n\n    vector<string> coordvars = {lonCellVarName, latCellVarName};\n    _meshMap[mesh2DTriName] = Mesh(mesh2DTriName, 3, dimension.GetLength(), nCellsDimName, nVerticesDimName, coordvars, cellsOnVertexVarName, verticesOnCellVarName);\n\n    if ((_isAtmosphere(ncdfc) || _isOcean(ncdfc)) && _hasVertical) {\n        if (_isAtmosphere(ncdfc)) {\n            coordvars = {lonCellVarName, latCellVarName, zGridP1VarName};\n            _meshMap[mesh3DP1TriName] = Mesh(mesh3DP1TriName, 3, dimension.GetLength(), nCellsDimName, nVerticesDimName, nVertLevelsP1DimName, coordvars, cellsOnVertexVarName, verticesOnCellVarName);\n\n            coordvars = {lonCellVarName, latCellVarName, zGridVarName};\n        } else {\n            coordvars = {lonCellVarName, latCellVarName, zTopVarName};\n        }\n\n        _meshMap[mesh3DTriName] = Mesh(mesh3DTriName, 3, dimension.GetLength(), nCellsDimName, nVerticesDimName, nVertLevelsDimName, coordvars, cellsOnVertexVarName, verticesOnCellVarName);\n    }\n\n    //\n    // Primal meshes (hexagonal mesh)\n    //\n    // 2D, layered, and layered with staggered dimensions\n    //\n\n    coordvars = {lonVertexVarName, latVertexVarName};\n    _meshMap[mesh2DCellName] = Mesh(mesh2DCellName, dimension.GetLength(), 3, nVerticesDimName, nCellsDimName, coordvars, verticesOnCellVarName, cellsOnVertexVarName);\n\n    if ((_isAtmosphere(ncdfc) || _isOcean(ncdfc)) && _hasVertical) {\n        if (_isAtmosphere(ncdfc)) {\n            coordvars = {lonVertexVarName, latVertexVarName, zGridVertP1VarName};\n            _meshMap[mesh3DP1CellName] =\n                Mesh(mesh3DP1CellName, dimension.GetLength(), 3, nVerticesDimName, nCellsDimName, nVertLevelsP1DimName, coordvars, verticesOnCellVarName, cellsOnVertexVarName);\n\n            coordvars = {lonVertexVarName, latVertexVarName, zGridVertVarName};\n        } else {\n            coordvars = {lonVertexVarName, latVertexVarName, zTopVertVarName};\n        }\n\n        _meshMap[mesh3DCellName] = Mesh(mesh3DCellName, dimension.GetLength(), 3, nVerticesDimName, nCellsDimName, nVertLevelsDimName, coordvars, verticesOnCellVarName, cellsOnVertexVarName);\n    }\n\n    return (0);\n}\n\nint DCMPAS::_InitAuxVars(NetCDFCollection *ncdfc)\n{\n    _auxVarsMap.clear();\n\n    vector<bool> periodic(3, false);\n    //\n    // Get names of variables  in the MPAS data set that have 1 or 2\n    // spatial dimensions\n    //\n    vector<string> vars;\n    for (int i = 1; i < 3; i++) {\n        vector<string> v = ncdfc->GetVariableNames(i, true);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    // For each variable add a member to _dataVarsMap\n    //\n    for (int i = 0; i < vars.size(); i++) {\n        // variable type must be int\n        //\n        int type = ncdfc->GetXType(vars[i]);\n        if (!(NetCDFSimple::IsNCTypeInt(type))) { continue; }\n\n        vector<string> dimnames = _GetSpatialDimNames(ncdfc, vars[i]);\n        if (!dimnames.size()) continue;\n\n        _auxVarsMap[vars[i]] = AuxVar(vars[i], \"\", DC::INT32, \"\", vector<size_t>(), periodic, dimnames);\n\n        // IDs in MPAS files start from 1, not 0 :-(\n        //\n        if (vars[i] == cellsOnVertexVarName || vars[i] == verticesOnCellVarName || vars[i] == verticesOnEdge || vars[i] == edgesOnCellVarName) { _auxVarsMap[vars[i]].SetOffset(-1); }\n    }\n\n    return (0);\n}\n\nint DCMPAS::_InitDataVars(NetCDFCollection *ncdfc)\n{\n    _dataVarsMap.clear();\n\n    vector<bool> periodic(3, false);\n    //\n    // Get names of variables  in the MPAS data set that have 1 or 2\n    // spatial dimensions\n    //\n    vector<string> vars;\n    for (int i = 1; i < 3; i++) {\n        vector<string> v = ncdfc->GetVariableNames(i, true);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    // For each variable add a member to _dataVarsMap\n    //\n    for (int i = 0; i < vars.size(); i++) {\n        // variable type must be float\n        //\n        int type = ncdfc->GetXType(vars[i]);\n        if (!(NetCDFSimple::IsNCTypeFloat(type))) { continue; }\n\n        if (_isCoordVar(vars[i])) continue;\n\n        vector<string> sdimnames;\n        vector<string> scoordvars;\n        string         time_dim_name;\n        string         time_coordvar;\n\n        vector<string> dimnames = _GetSpatialDimNames(ncdfc, vars[i]);\n        if (!dimnames.size()) continue;\n\n        if (dimnames[0] == nCellsDimName) {\n            _cellVars.push_back(vars[i]);\n        } else if (dimnames[0] == nVerticesDimName) {\n            _pointVars.push_back(vars[i]);\n        } else if (dimnames[0] == nEdgesDimName) {\n            // No grid support for edge variables in VAPOR, so we turn\n            // them into node-centered data\n            //\n            //_edgeVars.push_back(vars[i]);\n            dimnames[0] = nVerticesDimName;\n            _pointVars.push_back(vars[i]);\n        } else {\n            continue;\n        }\n\n        string meshname = get_mesh_name(dimnames);\n        if (meshname.empty()) continue;\n\n        int rc = _GetVarCoordinates(ncdfc, vars[i], sdimnames, scoordvars, time_dim_name, time_coordvar);\n        if (rc < 0) {\n            SetErrMsg(\"Invalid variable : %s\", vars[i].c_str());\n            return (-1);\n        }\n\n        string units;\n        ncdfc->GetAtt(vars[i], \"units\", units);\n        if (!_udunits.ValidUnit(units)) { units = \"\"; }\n\n        double mv;\n        bool   has_missing = ncdfc->GetMissingValue(vars[i], mv);\n\n        if (!has_missing) {\n            _dataVarsMap[vars[i]] = DataVar(vars[i], units, DC::FLOAT, periodic, meshname, time_coordvar, DC::Mesh::NODE);\n        } else {\n            _dataVarsMap[vars[i]] = DataVar(vars[i], units, DC::FLOAT, periodic, meshname, time_coordvar, DC::Mesh::NODE, mv);\n        }\n\n        rc = DCUtils::CopyAtt(*ncdfc, vars[i], _dataVarsMap[vars[i]]);\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\nvector<string> DCMPAS::_GetSpatialDimNames(NetCDFCollection *ncdfc, string varname) const\n{\n    vector<string> v = ncdfc->GetSpatialDimNames(varname);\n    if (v.size() == 0) return (v);\n\n    if (!isTransposed(ncdfc, varname)) { reverse(v.begin(), v.end()); }\n\n    return (v);\n}\n\n// Atmosphere core configuration ?\n//\nbool DCMPAS::_isAtmosphere(NetCDFCollection *ncdfc) const\n{\n    string value;\n    ncdfc->GetAtt(\"\", coreNameAttr, value);\n\n    return (value == \"\" || value == \"atmosphere\");\n}\n\n// Ocean core configuration ?\n//\nbool DCMPAS::_isOcean(NetCDFCollection *ncdfc) const\n{\n    string value;\n    ncdfc->GetAtt(\"\", coreNameAttr, value);\n\n    return (value == \"ocean\");\n}\n\n//\n//\nbool DCMPAS::_isCoordVar(string varname) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr == _coordVarsMap.end()) { return (false); }\n    return (true);\n}\n\nbool DCMPAS::_isDataVar(string varname) const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    itr = _dataVarsMap.find(varname);\n    if (itr == _dataVarsMap.end()) { return (false); }\n    return (true);\n}\n\n//////////////////////////////////////////////////////////////////////\n//\n// Class definitions for derived coordinate variables\n//\n//////////////////////////////////////////////////////////////////////\n\nDCMPAS::DerivedCoordVertFromCell::DerivedCoordVertFromCell(string derivedVarName, string derivedDimName, DC *dc, string inName, string cellsOnVertexName\n\n                                                           )\n: DerivedCoordVar(derivedVarName)\n{\n    _derivedDimName = derivedDimName;\n    _dc = dc;\n    _inName = inName;\n    _cellsOnVertexName = cellsOnVertexName;\n}\n\nint DCMPAS::DerivedCoordVertFromCell::Initialize()\n{\n    // Set up CoordVarInfo for derived variable. Only difference between\n    // it and native variable is dimension name for first dimension\n    //\n    bool status = _dc->GetCoordVarInfo(_inName, _coordVarInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _inName.c_str());\n        return (-1);\n    }\n\n    vector<string> dimNames = _coordVarInfo.GetDimNames();\n    VAssert(dimNames.size());\n\n    dimNames[0] = _derivedDimName;\n\n    _coordVarInfo.SetDimNames(dimNames);\n\n    return (0);\n}\n\nbool DCMPAS::DerivedCoordVertFromCell::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DCMPAS::DerivedCoordVertFromCell::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DCMPAS::DerivedCoordVertFromCell::GetDimLensAtLevel(int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    int rc = _dc->GetDimLensAtLevel(_inName, -1, dims_at_level, bs_at_level, -1);\n    if (rc < 0) return (-1);\n\n    DC::Dimension dimension;\n    bool          ok = _dc->GetDimension(_derivedDimName, dimension, -1);\n    if (!ok) {\n        SetErrMsg(\"Invalid dimension name : %s\", _derivedDimName.c_str());\n        return (-1);\n    }\n\n    dims_at_level[0] = dimension.GetLength();\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DCMPAS::DerivedCoordVertFromCell::OpenVariableRead(size_t ts, int, int)\n{\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, 0, 0, 0);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DCMPAS::DerivedCoordVertFromCell::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nfloat *DCMPAS::DerivedCoordVertFromCell::_getCellData()\n{\n    // Dimensions of input (cell) grid:\n    //\n    vector<size_t> inDims, dummy;\n    int            rc = _dc->GetDimLensAtLevel(_inName, -1, inDims, dummy, -1);\n    if (rc < 0) return (NULL);\n\n    vector<size_t> inMin, inMax;\n    for (int i = 0; i < inDims.size(); i++) {\n        inMin.push_back(0);\n        inMax.push_back(inDims[i] - 1);\n    }\n\n    float *buf = new float[vproduct(inDims)];\n\n    rc = _getVar(_dc, 0, _inName, -1, -1, inMin, inMax, buf);\n    if (rc < 0) {\n        delete[] buf;\n        return (NULL);\n    }\n\n    return (buf);\n}\n\nint *DCMPAS::DerivedCoordVertFromCell::_getCellsOnVertex(size_t i0, size_t i1, int &vertexDegree)\n{\n    vertexDegree = 0;\n\n    vector<size_t> dims;\n    bool           ok = _dc->GetVarDimLens(_cellsOnVertexName, true, dims, -1);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", _cellsOnVertexName.c_str());\n        return (NULL);\n    }\n\n    int fd = _dc->OpenVariableRead(0, _cellsOnVertexName, 0, 0);\n\n    vertexDegree = dims[0];\n\n    int *buf = new int[(i1 - i0 + 1) * vertexDegree];\n\n    vector<size_t> min, max;\n    min.push_back(0);\n    min.push_back(i0);\n    max.push_back(vertexDegree - 1);\n    max.push_back(i1);\n\n    int rc = _dc->ReadRegion(fd, min, max, buf);\n    if (rc < 0) {\n        delete[] buf;\n        return (NULL);\n    }\n\n    _dc->CloseVariable(fd);\n\n    return (buf);\n}\n\nint DCMPAS::DerivedCoordVertFromCell::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    string varname = f->GetVarname();\n\n    vector<size_t> inDims, dummy;\n    int            rc = _dc->GetDimLensAtLevel(_inName, -1, inDims, dummy, -1);\n    if (rc < 0) return (-1);\n\n    float *cellData = _getCellData();\n    if (!cellData) return (-1);\n\n    int  vertexDegree;\n    int *cellsOnVertex = _getCellsOnVertex(min[0], max[0], vertexDegree);\n\n    // only handle triangles for dual mesh\n    //\n    VAssert(vertexDegree == 3);\n\n    if (!cellsOnVertex) {\n        delete[] cellData;\n        return (-1);\n    }\n\n    size_t ny = min.size() >= 2 ? max[1] - min[1] + 1 : 1;\n    size_t nx = min.size() >= 1 ? max[0] - min[0] + 1 : 1;\n\n    // Interpolation weights. Assume interpolated sample is at geometric\n    // center of triangle\n    //\n    float wgt0 = 1.0 / 3.0;\n    float wgt1 = 1.0 / 3.0;\n    float wgt2 = 1.0 / 3.0;\n\n    int offset = -1;    // indexing in MPAS starts from -1\n    for (size_t j = 0; j < ny; j++) {\n        for (size_t i = 0; i < nx; i++) {\n            float v0 = cellData[j * inDims[0] + cellsOnVertex[i * vertexDegree + 0] + offset];\n            float v1 = cellData[j * inDims[0] + cellsOnVertex[i * vertexDegree + 1] + offset];\n            float v2 = cellData[j * inDims[0] + cellsOnVertex[i * vertexDegree + 2] + offset];\n\n            region[j * nx + i] = v0 * wgt0 + v1 * wgt1 + v2 * wgt2;\n        }\n    }\n\n    delete[] cellData;\n    delete[] cellsOnVertex;\n\n    return (0);\n}\n\nbool DCMPAS::DerivedCoordVertFromCell::VariableExists(size_t ts, int, int) const { return (_dc->VariableExists(ts, _inName, -1, -1)); }\n\n//////////////////////////////////////////////////////////////////////\n//\n// Class definitions for derived data variables\n//\n//////////////////////////////////////////////////////////////////////\n\nDCMPAS::DerivedZonalMeridonal::DerivedZonalMeridonal(string derivedVarName, DC *dc, NetCDFCollection *ncdfc, string normalVarName, string tangentialVarName, bool zonalFlag\n\n                                                     )\n: DerivedDataVar(derivedVarName)\n{\n    _dc = dc;\n    _ncdfc = ncdfc;\n    _normalVarName = normalVarName;\n    _tangentialVarName = tangentialVarName;\n    _zonalFlag = zonalFlag;\n}\n\nint DCMPAS::DerivedZonalMeridonal::Initialize()\n{\n    // Set up DataVarInfo for derived variable. No difference between\n    // it and native variables derived from\n    //\n    bool status = _dc->GetDataVarInfo(_normalVarName, _dataVarInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _normalVarName.c_str());\n        return (-1);\n    }\n\n    return (0);\n}\n\nbool DCMPAS::DerivedZonalMeridonal::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _dataVarInfo;\n    return (true);\n}\n\nbool DCMPAS::DerivedZonalMeridonal::GetDataVarInfo(DC::DataVar &cvar) const\n{\n    cvar = _dataVarInfo;\n    return (true);\n}\n\nint DCMPAS::DerivedZonalMeridonal::GetDimLensAtLevel(int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    int rc = _dc->GetDimLensAtLevel(_normalVarName, -1, dims_at_level, bs_at_level, -1);\n    if (rc < 0) return (-1);\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DCMPAS::DerivedZonalMeridonal::OpenVariableRead(size_t ts, int, int)\n{\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, 0, 0, 0);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DCMPAS::DerivedZonalMeridonal::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nint DCMPAS::DerivedZonalMeridonal::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 2);\n    VAssert(min.size() == max.size());\n\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n    size_t                     ts = f->GetTS();\n\n    vector<size_t> dims = _ncdfc->GetDims(edgesOnVertexVarName);\n    vector<int>    edgesOnVertex(vproduct(dims));\n    int            rc = _xgetVar(_ncdfc, ts, edgesOnVertexVarName, edgesOnVertex.data());\n    if (rc < 0) return (-1);\n\n    size_t vertexDegree = dims[1];\n\n    dims = _ncdfc->GetDims(angleEdgeVarName);\n    vector<float> angleEdge(vproduct(dims));\n    rc = _xgetVar(_ncdfc, ts, angleEdgeVarName, angleEdge.data());\n    if (rc < 0) return (-1);\n\n    dims = _ncdfc->GetSpatialDims(_normalVarName);\n    vector<size_t> ncdf_start = {0, min[1]};\n    vector<size_t> ncdf_count = {dims[0], max[1] - min[1] + 1};\n\n    vector<float> u(vproduct(ncdf_count));\n    vector<float> v(vproduct(ncdf_count));\n    vector<float> buf(vproduct(ncdf_count));\n\n    int myfd = _ncdfc->OpenRead(ts, _normalVarName);\n    if (rc < 0) return (-1);\n\n    rc = _ncdfc->Read(ncdf_start, ncdf_count, buf.data(), myfd);\n    if (rc < 0) return (-1);\n\n    Wasp::Transpose(buf.data(), u.data(), ncdf_count[1], ncdf_count[0]);\n\n    (void)_ncdfc->Close(myfd);\n\n    myfd = _ncdfc->OpenRead(ts, _tangentialVarName);\n    if (rc < 0) return (-1);\n\n    rc = _ncdfc->Read(ncdf_start, ncdf_count, buf.data(), myfd);\n    if (rc < 0) return (-1);\n\n    Wasp::Transpose(buf.data(), v.data(), ncdf_count[1], ncdf_count[0]);\n\n    (void)_ncdfc->Close(myfd);\n\n    size_t j0 = min.size() == 2 ? min[1] : 0;\n    size_t j1 = max.size() == 2 ? max[1] : 0;\n\n    float wgt = 1.0 / (float)vertexDegree;\n    for (size_t j = j0; j <= j1; j++) {\n        for (size_t i = min[0], ii = 0; i <= max[0]; i++, ii++) {\n            size_t vidx0 = edgesOnVertex[i * vertexDegree + 0] - 1;\n            size_t vidx1 = edgesOnVertex[i * vertexDegree + 1] - 1;\n            size_t vidx2 = edgesOnVertex[i * vertexDegree + 2] - 1;\n\n            float alpha0 = angleEdge[vidx0];\n            float alpha1 = angleEdge[vidx1];\n            float alpha2 = angleEdge[vidx2];\n\n            float u0, u1, u2;\n\n            //\n            // |Um| = |cos(alpha)    -sin(alpha)|   |u|\n            // |  |   |                         | x | |\n            // |Uz| = |sin(alpha)    cos(alpha) |   |v|\n            //\n            if (_zonalFlag) {\n                u0 = (cos(alpha0) * u.data()[j * dims[0] + vidx0]) - (sin(alpha0) * v.data()[j * dims[0] + vidx0]);\n\n                u1 = (cos(alpha1) * u.data()[j * dims[0] + vidx1]) - (sin(alpha1) * v.data()[j * dims[0] + vidx1]);\n\n                u2 = (cos(alpha2) * u.data()[j * dims[0] + vidx2]) - (sin(alpha2) * v.data()[j * dims[0] + vidx2]);\n            } else {\n                u0 = (sin(alpha0) * u.data()[j * dims[0] + vidx0]) + (cos(alpha0) * v.data()[j * dims[0] + vidx0]);\n\n                u1 = (sin(alpha1) * u.data()[j * dims[0] + vidx1]) + (cos(alpha1) * v.data()[j * dims[0] + vidx1]);\n\n                u2 = (sin(alpha2) * u.data()[j * dims[0] + vidx2]) + (cos(alpha2) * v.data()[j * dims[0] + vidx2]);\n            }\n\n            region[j * (max[0] - min[0] + 1) + ii] = u0 * wgt + u1 * wgt + u2 * wgt;\n        }\n    }\n\n    return (0);\n}\n\nbool DCMPAS::DerivedZonalMeridonal::VariableExists(size_t ts, int, int) const { return (_dc->VariableExists(ts, _normalVarName, -1, -1) && _dc->VariableExists(ts, _tangentialVarName, -1, -1)); }\n"
  },
  {
    "path": "lib/vdc/DCMelanie.cpp",
    "content": "#ifdef BUILD_DC_MELANIE\n\n    #include <algorithm>\n    #include <cassert>\n    #include <vector>\n    #include <map>\n    #include <iostream>\n    #include \"vapor/VAssert.h\"\n    #include <stdio.h>\n\n    #ifdef _WINDOWS\n        #define _USE_MATH_DEFINES\n        #pragma warning(disable : 4251 4100)\n    #endif\n    #include <cmath>\n\n    #include <vapor/GeoUtil.h>\n    #include <vapor/UDUnitsClass.h>\n    #include <vapor/DCMelanie.h>\n    #include <vapor/DCUtils.h>\n\nusing namespace VAPoR;\n\nDCMelanie::DCMelanie()\n{\n    _ncdfc = NULL;\n\n    _dimsMap.clear();\n    _coordVarsMap.clear();\n    _dataVarsMap.clear();\n    _meshMap.clear();\n    _coordVarKeys.clear();\n    _derivedVars.clear();\n}\n\nDCMelanie::~DCMelanie()\n{\n    if (_ncdfc) delete _ncdfc;\n\n    for (int i = 0; i < _derivedVars.size(); i++) {\n        if (_derivedVars[i]) delete _derivedVars[i];\n    }\n    _derivedVars.clear();\n}\n\nstatic void ReplaceAll(string *s, char a, char b)\n{\n    for (auto &c : *s) c = c == a ? b : c;\n}\n\nint DCMelanie::initialize(const vector<string> &paths, const std::vector<string> &options)\n{\n    if (_ncdfc) delete _ncdfc;\n    _ncdfc = nullptr;\n\n    NetCDFCFCollection *ncdfc = new NetCDFCFCollection();\n\n    // Initialize the NetCDFCFCollection class.\n    //\n    int rc = ncdfc->Initialize(paths);\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize netCDF data collection for reading\");\n        return (-1);\n    }\n\n    // Use UDUnits for unit conversion\n    //\n    rc = _udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", _udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n    auto particleAttributes = ncdfc->GetVariableNames(1, true);\n    auto particleVecs = ncdfc->GetVariableNames(2, true);\n\n    for (auto &n : particleAttributes) n = sanitizeVarName(n);\n    for (auto &n : particleVecs) n = sanitizeVarName(n);\n\n    string         particlePositions = \"Position\";\n    vector<string> coords = {\n        particlePositions + \"_x\",\n        particlePositions + \"_y\",\n        particlePositions + \"_z\",\n    };\n    {\n        auto positionPos = find(particleVecs.begin(), particleVecs.end(), particlePositions);\n        VAssert(positionPos != particleVecs.end());\n        particleVecs.erase(positionPos);\n    }\n\n    //    printf(\"Particle Coordinates\\n\");\n    //    printf(\"\\t%s\\n\", particlePositions.c_str());\n    //    printf(\"Particle Vecs\\n\");\n    //    for (auto s : particleVecs)\n    //        printf(\"\\t%s\\n\", s.c_str());\n    //    printf(\"Particle Attributes\\n\");\n    //    for (auto s : particleAttributes)\n    //        printf(\"\\t%s\\n\", s.c_str());\n\n\n    // Dimensions\n    // ==================\n    const string particlesDim = \"phony_dim_0\";\n    const string axesDim = \"phony_dim_1\";\n    auto         dimNames = ncdfc->GetDimNames();\n    auto         dimLens = ncdfc->GetDims();\n    string       timeDim = \"\";\n    assert(dimNames.size() == dimLens.size());\n    for (int i = 0; i < dimNames.size(); i++) _dimsMap[dimNames[i]] = DC::Dimension(dimNames[i], dimLens[i]);\n\n    // Coord Vars\n    // ==================\n    string timeCoordVar = \"\";\n    {\n        vector<bool> periodic(false);\n        for (int i = 0; i < 3; i++) {\n            auto c = coords[i];\n            auto axis = i;\n            _coordVarsMap[c] = CoordVar(c, \"\", DC::FLOAT, periodic, axis, false, {\"phony_dim_0\"}, timeDim);\n        }\n    }\n\n    // Aux Vars\n    // ==================\n    {\n        vector<bool> periodic(3, false);\n        for (auto v : {nodeFaceVar, faceNodeVar}) _auxVarsMap[v] = AuxVar(v, \"\", DC::INT32, \"\", vector<size_t>(), periodic, {particlesDim});\n    }\n\n    // Mesh\n    // ==================\n    DC::Mesh mesh(\"particles\", 1, 1, \"phony_dim_0\", \"phony_dim_0\", coords);\n    mesh.SetNodeFaceVar(nodeFaceVar);\n    mesh.SetFaceNodeVar(faceNodeVar);\n    _meshMap[mesh.GetName()] = mesh;\n\n\n    // Data Vars\n    // ==================\n    {\n        vector<bool> periodic(3, false);\n        for (string v : particleVecs) {\n            auto dims = ncdfc->GetDimNames(getOriginalVarName(v));\n            if (STLUtils::Contains(dims, axesDim)) {\n                for (auto axis : {\"_x\", \"_y\", \"_z\"}) _dataVarsMap[v + axis] = DC::DataVar(v + axis, \"\", DC::FLOAT, periodic, mesh.GetName(), timeCoordVar, DC::Mesh::NODE);\n            } else {\n                _dataVarsMap[v] = DC::DataVar(v, \"\", DC::FLOAT, periodic, mesh.GetName(), timeCoordVar, DC::Mesh::NODE);\n            }\n        }\n    }\n\n    _ncdfc = ncdfc;\n\n    return (0);\n}\n\n\nbool DCMelanie::getDimension(string dimname, DC::Dimension &dimension) const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    itr = _dimsMap.find(dimname);\n    if (itr == _dimsMap.end()) return (false);\n\n    dimension = itr->second;\n    return (true);\n}\n\nstd::vector<string> DCMelanie::getDimensionNames() const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    vector<string> names;\n\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nvector<string> DCMelanie::getMeshNames() const\n{\n    vector<string>                         mesh_names;\n    std::map<string, Mesh>::const_iterator itr = _meshMap.begin();\n    for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); }\n    return (mesh_names);\n}\n\nbool DCMelanie::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    map<string, Mesh>::const_iterator itr = _meshMap.find(mesh_name);\n    if (itr == _meshMap.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nbool DCMelanie::getCoordVarInfo(string varname, DC::CoordVar &cvar) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr == _coordVarsMap.end()) { return (false); }\n\n    cvar = itr->second;\n    return (true);\n}\n\nbool DCMelanie::getDataVarInfo(string varname, DC::DataVar &datavar) const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    itr = _dataVarsMap.find(varname);\n    if (itr == _dataVarsMap.end()) { return (false); }\n\n    datavar = itr->second;\n    return (true);\n}\n\nbool DCMelanie::getBaseVarInfo(string varname, DC::BaseVar &var) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr != _coordVarsMap.end()) {\n        var = itr->second;\n        return (true);\n    }\n\n    map<string, DC::DataVar>::const_iterator itr1 = _dataVarsMap.find(varname);\n    if (itr1 != _dataVarsMap.end()) {\n        var = itr1->second;\n        return (true);\n    }\n\n    return (false);\n}\n\n\nstd::vector<string> DCMelanie::getDataVarNames() const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\n\nstd::vector<string> DCMelanie::getCoordVarNames() const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\ntemplate<class T> bool DCMelanie::_getAttTemplate(string varname, string attname, T &values) const\n{\n    //    printf(\"%s(%s, %s, %s&)\\n\", __func__, varname.c_str(), attname.c_str(), TypeToChar(values));\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (status);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (status);\n\n    att.GetValues(values);\n\n    return (true);\n}\n\nbool DCMelanie::getAtt(string varname, string attname, vector<double> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCMelanie::getAtt(string varname, string attname, vector<long> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCMelanie::getAtt(string varname, string attname, string &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nstd::vector<string> DCMelanie::getAttNames(string varname) const\n{\n    //    printf(\"%s(%s) = \", __func__, varname.c_str());\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) {\n        //        printf(\"{} (ERR)\\n\");\n        return (vector<string>());\n    }\n\n    vector<string> names;\n\n    const std::map<string, Attribute> &         atts = var.GetAttributes();\n    std::map<string, Attribute>::const_iterator itr;\n    for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); }\n\n    //    printf(\"%s\\n\", ToStr(names).c_str());\n    return (names);\n}\n\nDC::XType DCMelanie::getAttType(string varname, string attname) const\n{\n    //    printf(\"%s(%s, %s)\\n\", __func__, varname.c_str(), attname.c_str());\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (DC::INVALID);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (DC::INVALID);\n\n    return (att.GetXType());\n}\n\nint DCMelanie::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    VAssert(0);\n    bool ok = GetVarDimLens(varname, true, dims_at_level, 0);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\n\nint DCMelanie::openVariableRead(size_t ts, string varname)\n{\n    //    printf(\"%s(%li, %s) = \", __func__, ts, varname.c_str());\n\n    if (STLUtils::Contains(fakeVars, varname)) {\n        int ret = fakeVarsFileCounter++;\n        //        printf(\"(fake) %i\\n\", ret);\n        _fdMap[ret] = varname;\n        return ret;\n    }\n\n    string ncdfName = varname;\n    if (STLUtils::EndsWith(ncdfName, \"_x\") || STLUtils::EndsWith(ncdfName, \"_y\") || STLUtils::EndsWith(ncdfName, \"_z\")) {\n        ncdfName = ncdfName.substr(0, ncdfName.length() - 2);\n        //        printf(\"<removing _axis>\\n\\t\");\n        //        printf(\"%s(%li, %s) = \", __func__, ts, ncdfName.c_str());\n    }\n\n    ncdfName = getOriginalVarName(ncdfName);\n\n    int aux = _ncdfc->OpenRead(ts, ncdfName);\n    if (!(aux < 0)) {\n        FileTable::FileObject *f = new FileTable::FileObject(ts, ncdfName, 0, 0, aux);\n        aux = _fileTable.AddEntry(f);\n    }\n\n    //    printf(\"%i\\n\", aux);\n    _fdMap[aux] = varname;\n    return aux;\n}\n\n\nint DCMelanie::closeVariable(int fd)\n{\n    //    printf(\"%s(%i)\\n\", __func__, fd);\n    _fdMap.erase(_fdMap.find(fd));\n\n    if (fd >= fakeVarsFileCounterStart) {\n        fakeVarsFileCounter--;\n        return 0;\n    }\n\n    DC::FileTable::FileObject *w = _fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    int rc = _ncdfc->Close(aux);\n\n    _fileTable.RemoveEntry(fd);\n\n    return (rc);\n}\n\n// min -> max is inclusive\n\ntemplate<class T> int DCMelanie::_readRegionTemplate(int fd, const vector<size_t> &min_, const vector<size_t> &max_, T *region)\n{\n    vector<size_t> min = min_;\n    vector<size_t> max = max_;\n    string         varname = _fdMap[fd];\n    //    printf(\"%s(%i(%s), %s, %s, %s*)\\n\", __func__, fd, varname.c_str(), ToStr(min).c_str(), ToStr(max).c_str(), TypeToChar(*region));\n\n    VAssert(min.size() == 1);\n\n    bool fake = fd >= fakeVarsFileCounterStart;\n\n    if (fake) {\n        //        printf(\"\\t (Fake)\\n\");\n        for (size_t i = min[0]; i <= max[0]; i++) region[i] = i / (double)(max[0] - 1);\n        return 0;\n    }\n\n    int axis = -1;\n    if (STLUtils::EndsWith(varname, \"_x\")) axis = 0;\n    if (STLUtils::EndsWith(varname, \"_y\")) axis = 1;\n    if (STLUtils::EndsWith(varname, \"_z\")) axis = 2;\n    if (axis != -1) {\n        //        printf(\"\\t Read data from header\\n\");\n        //        for (size_t i = min[0]; i <= max[0]; i++)\n        //            region[i] = Particle_Position[i*3+axis];\n        //        return 0;\n\n\n        //        min.push_back(axis);\n        //        max.push_back(axis);\n        min.push_back(min[0]);\n        max.push_back(max[0]);\n        min[0] = axis;\n        max[0] = axis;\n\n        //        printf(\"\\t %s(%i(%s), %s, %s, %s*)\\n\", __func__, fd, varname.substr(0,varname.length()-2).c_str(), ToStr(min).c_str(), ToStr(max).c_str(), TypeToChar(*region));\n    }\n\n    FileTable::FileObject *w = (FileTable::FileObject *)_fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    vector<size_t> ncdf_start = min;\n    reverse(ncdf_start.begin(), ncdf_start.end());\n\n    vector<size_t> ncdf_max = max;\n    reverse(ncdf_max.begin(), ncdf_max.end());\n\n    vector<size_t> ncdf_count;\n    for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); }\n\n    return (_ncdfc->Read(ncdf_start, ncdf_count, region, aux));\n}\n\nbool DCMelanie::variableExists(size_t ts, string varname, int, int) const\n{\n    bool found = false;\n\n    for (const auto &it : _dataVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n    for (const auto &it : _coordVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n    for (const auto &it : _auxVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n\n    //    if (found == false)\n    //        printf(\"WARNING %s(%li, %s) = %s\\n\", __func__, ts, varname.c_str(), found?\"true\":\"false\");\n    return found;\n}\n\n\nstd::vector<string> DCMelanie::getAuxVarNames() const\n{\n    vector<string> names(_auxVarsMap.size());\n    for (const auto &it : _auxVarsMap) names.push_back(it.first);\n    return names;\n}\n\nbool DCMelanie::getAuxVarInfo(string varname, DC::AuxVar &var) const\n{\n    const auto &it = _auxVarsMap.find(varname);\n    if (it == _auxVarsMap.end()) return false;\n    var = it->second;\n    return true;\n}\n\nstring DCMelanie::sanitizeVarName(const string &name)\n{\n    assert(_sanitizedToOriginalMap.count(name) == 0);\n\n    string sanitizedName = name;\n    ReplaceAll(&sanitizedName, ' ', '_');\n    _sanitizedToOriginalMap[sanitizedName] = name;\n\n    return sanitizedName;\n}\n\nstring DCMelanie::getOriginalVarName(const string &name) const\n{\n    auto it = _sanitizedToOriginalMap.find(name);\n    if (it == _sanitizedToOriginalMap.end()) return name;\n    return it->second;\n}\n\n#endif\n"
  },
  {
    "path": "lib/vdc/DCP.cpp",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <cassert>\n#include \"vapor/VAssert.h\"\n#include <stdio.h>\n\n#ifdef _WINDOWS\n    #define _USE_MATH_DEFINES\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <cmath>\n\n#include <vapor/GeoUtil.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/DCP.h>\n#include <vapor/DCUtils.h>\n\nusing namespace VAPoR;\n\nDCP::DCP()\n{\n    _ncdfc = NULL;\n\n    _dimsMap.clear();\n    _coordVarsMap.clear();\n    _dataVarsMap.clear();\n    _meshMap.clear();\n    _coordVarKeys.clear();\n}\n\nDCP::~DCP()\n{\n    if (_ncdfc) delete _ncdfc;\n}\n\nstatic void ReplaceAll(string *s, char a, char b)\n{\n    for (auto &c : *s) c = c == a ? b : c;\n}\n\nint DCP::initialize(const vector<string> &paths, const std::vector<string> &options)\n{\n    if (_ncdfc) delete _ncdfc;\n    _ncdfc = nullptr;\n\n    NetCDFCollection *ncdfc = new NetCDFCollection();\n    _ncdfc = ncdfc;\n\n    // Initialize the NetCDFCFCollection class.\n    //\n    int rc = ncdfc->Initialize(paths, {\"time\", \"T\"}, {\"time\", \"T\"});\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize netCDF data collection for reading\");\n        return (-1);\n    }\n\n    // Use UDUnits for unit conversion\n    //\n    rc = _udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", _udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n\n    // Dimensions\n    // ==================\n    string particlesDim;\n    string axisDim;\n    auto   dimNames = ncdfc->GetDimNames();\n    auto   dimLens = ncdfc->GetDims();\n    auto   dimIsTimeVarying = ncdfc->GetDimsAreTimeVarying();\n\n    bool dimNamePhony = false;\n    for (auto d : dimNames)\n        if (STLUtils::BeginsWith(d, \"phony\")) dimNamePhony = true;\n    if (dimNamePhony) {\n        particlesDim = \"phony_dim_0\";\n        axisDim = \"phony_dim_1\";\n    } else {\n        particlesDim = \"P\";\n        axisDim = \"axis\";\n        if (!STLUtils::Contains(dimNames, string(\"P\"))) {\n            MyBase::SetErrMsg(\"File missing required dimension P\");\n            return -1;\n        }\n    }\n\n    for (int i = 0; i < dimNames.size(); i++)\n        if (dimIsTimeVarying[i])\n            _dimsMap[dimNames[i]] = DC::Dimension(dimNames[i], vector<size_t>{dimLens[i], 0});\n        else\n            _dimsMap[dimNames[i]] = DC::Dimension(dimNames[i], dimLens[i]);\n\n#if DCP_ENABLE_PARTICLE_DENSITY\n    //! Vapor does not support derived dimensions so this is a \"derived\" dimension to allow particle densities.\n    //! See documentation in DCP.h\n    _dimsMap[\"densityX\"] = DC::Dimension(\"densityX\", 32);\n    _dimsMap[\"densityY\"] = DC::Dimension(\"densityY\", 32);\n    _dimsMap[\"densityZ\"] = DC::Dimension(\"densityZ\", 4);\n#endif\n\n\n    // Aux Vars\n    // ==================\n    {\n        vector<bool> periodic(3, false);\n        for (auto v : {_nodeFaceVar, _faceNodeVar}) _auxVarsMap[v] = AuxVar(v, \"\", DC::INT32, \"\", vector<size_t>(), periodic, {particlesDim});\n    }\n\n    // Coord Vars\n    // ==================\n    for (int dim = 0; dim < 5; dim++) {\n        auto vars = ncdfc->GetVariableNames(dim, true);\n        for (auto &var : vars) {\n            if (isCoordVar(var)) {\n                const vector<bool> periodic(false);\n                auto               spacialDims = ncdfc->GetSpatialDimNames(var);\n                auto               timeDim = ncdfc->GetTimeDimName(var);\n                if (STLUtils::Contains(spacialDims, axisDim)) {\n                    spacialDims.erase(find(spacialDims.begin(), spacialDims.end(), axisDim));\n                    for (auto axis : {\"_x\", \"_y\", \"_z\"}) _coordVarsMap[var + axis] = CoordVar(var + axis, getUnits(var), DC::FLOAT, periodic, getAxis(var + axis), false, spacialDims, timeDim);\n                } else {\n                    _coordVarsMap[var] = CoordVar(var, getUnits(var), DC::FLOAT, periodic, getAxis(var), false, spacialDims, timeDim);\n                }\n            }\n        }\n    }\n\n    vector<string> coordVarsNames;\n    for (auto it = _coordVarsMap.cbegin(); it != _coordVarsMap.cend(); ++it) coordVarsNames.push_back(it->first);\n\n    string         particlePositions = \"Position\";\n    vector<string> coords = {\n        particlePositions + \"_x\",\n        particlePositions + \"_y\",\n        particlePositions + \"_z\",\n    };\n\n    for (const auto &requiredCoordVar : coords) {\n        if (!STLUtils::Contains(coordVarsNames, requiredCoordVar)) {\n            MyBase::SetErrMsg(\"File missing required coord var %s\", requiredCoordVar.c_str());\n            return -1;\n        }\n    }\n\n    // Mesh\n    // ==================\n    DC::Mesh mesh(\"particles\", 1, 1, particlesDim, particlesDim, coords);\n    mesh.SetNodeFaceVar(_nodeFaceVar);\n    mesh.SetFaceNodeVar(_faceNodeVar);\n    _meshMap[mesh.GetName()] = mesh;\n\n    // Data Vars\n    // ==================\n    {\n        vector<bool> periodic(3, false);\n        for (int dim = 0; dim < 5; dim++) {\n            auto vars = ncdfc->GetVariableNames(dim, true);\n            for (auto v : vars) {\n                if (!isCoordVar(v)) {\n                    auto v_san = sanitizeVarName(v);\n                    auto dims = ncdfc->GetDimNames(v);\n                    if (STLUtils::Contains(dims, axisDim)) {\n                        for (auto axis : {\"_x\", \"_y\", \"_z\"}) {\n                            auto name = v_san + axis;\n                            _dataVarsMap[name] = DC::DataVar(name, \"\", DC::FLOAT, periodic, mesh.GetName(), getTimeCoordVar(v), DC::Mesh::NODE);\n                        }\n                    } else {\n                        _dataVarsMap[v_san] = DC::DataVar(v_san, \"\", DC::FLOAT, periodic, mesh.GetName(), getTimeCoordVar(v), DC::Mesh::NODE);\n                    }\n                }\n            }\n        }\n    }\n\n    if (_dataVarsMap.empty()) {\n        // If no data other than position, add a fake empty var to allow\n        // the position data to be rendered on its own\n        vector<bool> periodic(3, false);\n        _dataVarsMap[_fakeEmptyVar] = DC::DataVar(_fakeEmptyVar, \"\", DC::FLOAT, periodic, mesh.GetName(), getTimeCoordVar(coords[0]), DC::Mesh::NODE);\n        _fakeVars.push_back(_fakeEmptyVar);\n    }\n\n    return 0;\n}\n\nbool DCP::isCoordVar(const string &var) const\n{\n    return STLUtils::BeginsWith(var, \"Position\") || var == \"T\";\n\n    int type = _ncdfc->GetAttType(var, \"coordinates\");\n    if (type < 0) return true;\n    assert(type == NC_CHAR);\n    return false;\n}\n\nint DCP::getAxis(const string &var) const\n{\n    string s;\n    _ncdfc->GetAtt(var, \"axis\", s);\n    s = STLUtils::ToLower(s);\n    if (s == \"x\") return 0;\n    if (s == \"y\") return 1;\n    if (s == \"z\") return 2;\n    if (s == \"t\") return 3;\n    if (var == \"T\") return 3;\n    if (STLUtils::EndsWith(var, \"_x\")) return 0;\n    if (STLUtils::EndsWith(var, \"_y\")) return 1;\n    if (STLUtils::EndsWith(var, \"_z\")) return 2;\n    VAssert(0);\n    return -1;\n}\n\nstring DCP::getUnits(const string &var) const\n{\n    string s;\n    _ncdfc->GetAtt(var, \"units\", s);\n    return s;\n}\n\nstring DCP::getTimeCoordVar(const string &var) const\n{\n    if (_ncdfc->GetTimeDimName(var) == \"T\") return \"T\";\n    return \"\";\n}\n\nbool DCP::getDimension(string dimname, DC::Dimension &dimension) const\n{\n    VAssert(0);\n    return false;\n}\n\nbool DCP::getDimension(string dimname, DC::Dimension &dimension, long ts) const\n{\n    if (ts == -1\n#if DCP_ENABLE_PARTICLE_DENSITY\n        //! Vapor does not support derived dimensions so this is a \"derived\" dimension to allow particle densities.\n        //! See documentation in DCP.h\n        && !STLUtils::Contains(dimname, \"density\")\n#endif\n    ) {\n        assert(0);\n        return false;\n    }\n\n    map<string, DC::Dimension>::const_iterator itr;\n    itr = _dimsMap.find(dimname);\n    if (itr == _dimsMap.end()) return (false);\n    dimension = itr->second;\n\n    if (dimension.IsTimeVarying()) {\n        long len = _ncdfc->GetDimLengthAtTime(dimname, ts);\n        if (len >= 0) { dimension = Dimension(dimname, len); }\n    }\n\n    return true;\n}\n\nstd::vector<string> DCP::getDimensionNames() const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    vector<string> names;\n\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nvector<string> DCP::getMeshNames() const\n{\n    vector<string>                         mesh_names;\n    std::map<string, Mesh>::const_iterator itr = _meshMap.begin();\n    for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); }\n    return (mesh_names);\n}\n\nbool DCP::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    map<string, Mesh>::const_iterator itr = _meshMap.find(mesh_name);\n    if (itr == _meshMap.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nbool DCP::getCoordVarInfo(string varname, DC::CoordVar &cvar) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr == _coordVarsMap.end()) { return (false); }\n\n    cvar = itr->second;\n    return (true);\n}\n\nbool DCP::getDataVarInfo(string varname, DC::DataVar &datavar) const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    itr = _dataVarsMap.find(varname);\n    if (itr == _dataVarsMap.end()) { return (false); }\n\n    datavar = itr->second;\n    return (true);\n}\n\nbool DCP::getBaseVarInfo(string varname, DC::BaseVar &var) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr != _coordVarsMap.end()) {\n        var = itr->second;\n        return (true);\n    }\n\n    map<string, DC::DataVar>::const_iterator itr1 = _dataVarsMap.find(varname);\n    if (itr1 != _dataVarsMap.end()) {\n        var = itr1->second;\n        return (true);\n    }\n\n    return (false);\n}\n\n\nstd::vector<string> DCP::getDataVarNames() const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\n\nstd::vector<string> DCP::getCoordVarNames() const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\ntemplate<class T> bool DCP::_getAttTemplate(string varname, string attname, T &values) const\n{\n    //    printf(\"%s(%s, %s, %s&)\\n\", __func__, varname.c_str(), attname.c_str(), TypeToChar(values));\n\n    if (_ncdfc->GetAttType(varname, attname) < 0) return false;\n\n    _ncdfc->GetAtt(varname, attname, values);\n\n    return (true);\n}\n\nbool DCP::getAtt(string varname, string attname, vector<double> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCP::getAtt(string varname, string attname, vector<long> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCP::getAtt(string varname, string attname, string &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nstd::vector<string> DCP::getAttNames(string varname) const\n{\n    //    printf(\"%s(%s) = \", __func__, varname.c_str());\n\n    if (varname.empty()) {\n        return _ncdfc->GetAttNames(\"\");\n    } else {\n        DC::BaseVar var;\n        bool        status = getBaseVarInfo(varname, var);\n        if (!status) {\n            //            printf(\"{} (ERR)\\n\");\n            return (vector<string>());\n        }\n\n        vector<string> names;\n\n        const std::map<string, Attribute> &         atts = var.GetAttributes();\n        std::map<string, Attribute>::const_iterator itr;\n        for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); }\n\n        //        printf(\"%s\\n\", ToStr(names).c_str());\n        return (names);\n    }\n}\n\nDC::XType DCP::getAttType(string varname, string attname) const\n{\n    //    printf(\"%s(%s, %s)\\n\", __func__, varname.c_str(), attname.c_str());\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (DC::INVALID);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (DC::INVALID);\n\n    return (att.GetXType());\n}\n\nint DCP::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    VAssert(0);\n    return -1;\n}\n\nint DCP::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    bool ok = GetVarDimLens(varname, true, dims_at_level, ts);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\n\nint DCP::openVariableRead(size_t ts, string varname)\n{\n    //    printf(\"DCP::%s(%li, %s) = \", __func__, ts, varname.c_str());\n\n    if (STLUtils::Contains(_fakeVars, varname)) {\n        int ret = _fakeVarsFileCounter++;\n        //        printf(\"(fake) %i\\n\", ret);\n        _fdMap[ret] = varname;\n        return ret;\n    }\n\n    string ncdfName = varname;\n    if (STLUtils::EndsWith(ncdfName, \"_x\") || STLUtils::EndsWith(ncdfName, \"_y\") || STLUtils::EndsWith(ncdfName, \"_z\")) {\n        if (!_ncdfc->VariableExists(varname)) {\n            ncdfName = ncdfName.substr(0, ncdfName.length() - 2);\n            //            printf(\"<removing _axis>\\n\\t\");\n            //            printf(\"DCP::%s(%li, %s) = \", __func__, ts, ncdfName.c_str());\n        }\n    }\n\n    ncdfName = getOriginalVarName(ncdfName);\n\n    int aux = _ncdfc->OpenRead(ts, ncdfName);\n    if (!(aux < 0)) {\n        FileTable::FileObject *f = new FileTable::FileObject(ts, ncdfName, 0, 0, aux);\n        aux = _fileTable.AddEntry(f);\n    }\n\n    //    printf(\"%i\\n\", aux);\n    _fdMap[aux] = varname;\n    return aux;\n}\n\n\nint DCP::closeVariable(int fd)\n{\n    //    printf(\"DCP::%s(%i)\\n\", __func__, fd);\n\n    auto fdIt = _fdMap.find(fd);\n    if (fdIt != _fdMap.end()) _fdMap.erase(fdIt);\n\n    if (fd >= _fakeVarsFileCounterStart) {\n        _fakeVarsFileCounter--;\n        return 0;\n    }\n\n    DC::FileTable::FileObject *w = _fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    int rc = _ncdfc->Close(aux);\n\n    _fileTable.RemoveEntry(fd);\n\n    return (rc);\n}\n\n// min -> max is inclusive\n\ntemplate<class T> int DCP::_readRegionTemplate(int fd, const vector<size_t> &min_, const vector<size_t> &max_, T *region)\n{\n    vector<size_t> min = min_;\n    vector<size_t> max = max_;\n    string         varname = _fdMap[fd];\n    //    printf(\"%s(%i(%s), %s, %s, %s*)\\n\", __func__, fd, varname.c_str(), ToStr(min).c_str(), ToStr(max).c_str(), TypeToChar(*region));\n\n    //    VAssert(min.size() == 1);\n\n    bool fake = fd >= _fakeVarsFileCounterStart;\n\n    if (fake) {\n        if (_fdMap[fd] == _fakeEmptyVar) {\n            for (size_t i = min[0]; i <= max[0]; i++) region[i] = 0;\n        } else {\n            for (size_t i = min[0]; i <= max[0]; i++) region[i] = i / (double)(max[0] - 1);\n        }\n        return 0;\n    }\n\n    if (!_ncdfc->VariableExists(varname)) {\n        int axis = -1;\n        if (STLUtils::EndsWith(varname, \"_x\")) axis = 0;\n        if (STLUtils::EndsWith(varname, \"_y\")) axis = 1;\n        if (STLUtils::EndsWith(varname, \"_z\")) axis = 2;\n        if (axis != -1) {\n            //        printf(\"\\t Read data from header\\n\");\n            //        for (size_t i = min[0]; i <= max[0]; i++)\n            //            region[i] = Particle_Position[i*3+axis];\n            //        return 0;\n            //        min.push_back(axis);\n            //        max.push_back(axis);\n\n            min.push_back(min[0]);\n            max.push_back(max[0]);\n            min[0] = axis;\n            max[0] = axis;\n\n            //            printf(\"\\t %s(%i(%s), %s, %s, %s*)\\n\", __func__, fd, varname.substr(0,varname.length()-2).c_str(), ToStr(min).c_str(), ToStr(max).c_str(), TypeToChar(*region));\n        }\n    }\n\n    FileTable::FileObject *w = (FileTable::FileObject *)_fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    vector<size_t> ncdf_start = min;\n    reverse(ncdf_start.begin(), ncdf_start.end());\n\n    vector<size_t> ncdf_max = max;\n    reverse(ncdf_max.begin(), ncdf_max.end());\n\n    vector<size_t> ncdf_count;\n    for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); }\n\n    return (_ncdfc->Read(ncdf_start, ncdf_count, region, aux));\n}\n\nbool DCP::variableExists(size_t ts, string varname, int, int) const\n{\n    bool found = false;\n\n    for (const auto &it : _dataVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n    for (const auto &it : _coordVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n    for (const auto &it : _auxVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n\n    //    if (found == false)\n    //        printf(\"WARNING %s(%li, %s) = %s\\n\", __func__, ts, varname.c_str(), found?\"true\":\"false\");\n    return found;\n}\n\n\nstd::vector<string> DCP::getAuxVarNames() const\n{\n    vector<string> names(_auxVarsMap.size());\n    for (const auto &it : _auxVarsMap) names.push_back(it.first);\n    return names;\n}\n\nbool DCP::getAuxVarInfo(string varname, DC::AuxVar &var) const\n{\n    const auto &it = _auxVarsMap.find(varname);\n    if (it == _auxVarsMap.end()) return false;\n    var = it->second;\n    return true;\n}\n\nstring DCP::sanitizeVarName(const string &name)\n{\n    assert(_sanitizedToOriginalMap.count(name) == 0);\n\n    string sanitizedName = name;\n    ReplaceAll(&sanitizedName, ' ', '_');\n    _sanitizedToOriginalMap[sanitizedName] = name;\n\n    return sanitizedName;\n}\n\nstring DCP::getOriginalVarName(const string &name) const\n{\n    auto it = _sanitizedToOriginalMap.find(name);\n    if (it == _sanitizedToOriginalMap.end()) return name;\n    return it->second;\n}\n"
  },
  {
    "path": "lib/vdc/DCRAM.cpp",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <cassert>\n#include <functional>\n#include \"vapor/VAssert.h\"\n#include <stdio.h>\n\n#ifdef _WINDOWS\n    #define _USE_MATH_DEFINES\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <cmath>\n\n#include <vapor/GeoUtil.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/DCRAM.h>\n#include <vapor/DCUtils.h>\n\nusing namespace VAPoR;\n\nDCRAM::DCRAM()\n{\n    _dimsMap.clear();\n    _coordVarsMap.clear();\n    _meshMap.clear();\n}\n\nDCRAM::~DCRAM()\n{\n    for (const auto &it : _dataMap)\n        delete [] it.second;\n    _dataMap.clear();\n}\n\nint DCRAM::initialize(const vector<string> &paths, const std::vector<string> &options)\n{\n#ifdef DCRAM_GENERATE_TEST_DATA\n    // Dimensions\n    // ==================\n    string particlesDim;\n    string axisDim;\n    auto   dimNames = ncdfc->GetDimNames();\n    auto   dimLens = ncdfc->GetDims();\n    auto   dimIsTimeVarying = ncdfc->GetDimsAreTimeVarying();\n\n    _dimsMap[\"dimX\"] = DC::Dimension(\"dimX\", 32);\n    _dimsMap[\"dimY\"] = DC::Dimension(\"dimY\", 32);\n    _dimsMap[\"dimZ\"] = DC::Dimension(\"dimZ\", 32);\n    \n    // Coords\n    // ==================\n    const vector<bool> periodic(false);\n    _coordVarsMap[\"coordX\"] = CoordVar(\"coordX\", \"m\", DC::FLOAT, periodic, /*axis=x*/0, /*uniformHint=*/true, {\"dimX\"}, /*timeDim*/\"\");\n    _coordVarsMap[\"coordY\"] = CoordVar(\"coordY\", \"m\", DC::FLOAT, periodic, /*axis=y*/1, /*uniformHint=*/true, {\"dimY\"}, /*timeDim*/\"\");\n    _coordVarsMap[\"coordZ\"] = CoordVar(\"coordZ\", \"m\", DC::FLOAT, periodic, /*axis=z*/2, /*uniformHint=*/true, {\"dimZ\"}, /*timeDim*/\"\");\n\n    // Mesh\n    // ==================\n    vector<string> dims = {\"dimX\", \"dimY\", \"dimZ\"};\n    vector<string> coords = {\"coordX\", \"coordY\", \"coordZ\"};\n    DC::Mesh mesh(\"test_mesh\", dims, coords);\n    _meshMap[mesh.GetName()] = mesh;\n\n    // Data Vars\n    // ==================\n    {\n    vector<bool> periodic(3, false);\n    _dataVarsMap[\"sphere\"] = DC::DataVar(\"sphere\", \"\", DC::FLOAT, periodic, mesh.GetName(), /*timeCoordVar*/\"\", DC::Mesh::NODE);\n    _dataVarsMap[\"empty\"]  = DC::DataVar(\"empty\",  \"\", DC::FLOAT, periodic, mesh.GetName(), /*timeCoordVar*/\"\", DC::Mesh::NODE);\n    _dataVarsMap[\"xval\"]   = DC::DataVar(\"xval\",   \"\", DC::FLOAT, periodic, mesh.GetName(), /*timeCoordVar*/\"\", DC::Mesh::NODE);\n    }\n#endif\n\n    return 0;\n}\n\nvoid DCRAM::Test()\n{\n#ifdef DCRAM_GENERATE_TEST_DATA\n    // ==========================\n    // New data on existing grid\n    // ==========================\n    vector<bool> periodic(3, false);\n    _dataVarsMap[\"sine\"] = DC::DataVar(\"sine\", \"\", DC::FLOAT, periodic, \"test_mesh\", /*timeCoordVar*/\"\", DC::Mesh::NODE);\n    \n    \n    // ==========================\n    // New data on new grid\n    // ==========================\n    \n    _dimsMap[\"dim2X\"] = DC::Dimension(\"dim2X\", 64);\n    _dimsMap[\"dim2Y\"] = DC::Dimension(\"dim2Y\", 64);\n    _dimsMap[\"dim2Z\"] = DC::Dimension(\"dim2Z\", 64);\n    \n    // Coords\n    // ==================\n    _coordVarsMap[\"coord2X\"] = CoordVar(\"coord2X\", \"m\", DC::FLOAT, periodic, /*axis=x*/0, /*uniformHint=*/true, {\"dim2X\"}, /*timeDim*/\"\");\n    _coordVarsMap[\"coord2Y\"] = CoordVar(\"coord2Y\", \"m\", DC::FLOAT, periodic, /*axis=y*/1, /*uniformHint=*/true, {\"dim2Y\"}, /*timeDim*/\"\");\n    _coordVarsMap[\"coord2Z\"] = CoordVar(\"coord2Z\", \"m\", DC::FLOAT, periodic, /*axis=z*/2, /*uniformHint=*/true, {\"dim2Z\"}, /*timeDim*/\"\");\n\n    // Mesh\n    // ==================\n    vector<string> dims = {\"dim2X\", \"dim2Y\", \"dim2Z\"};\n    vector<string> coords = {\"coord2X\", \"coord2Y\", \"coord2Z\"};\n    DC::Mesh mesh(\"test_mesh2\", dims, coords);\n    _meshMap[mesh.GetName()] = mesh;\n    \n    _dataVarsMap[\"grid\"] = DC::DataVar(\"grid\", \"\", DC::FLOAT, periodic, \"test_mesh2\", /*timeCoordVar*/\"\", DC::Mesh::NODE);\n    _dataVarsMap[\"xval2\"] = DC::DataVar(\"xval2\", \"\", DC::FLOAT, periodic, \"test_mesh2\", /*timeCoordVar*/\"\", DC::Mesh::NODE);\n    \n    \n    // ==========================\n    // New data on curve grid\n    // ==========================\n    \n    _dimsMap[\"curveDimX\"] = DC::Dimension(\"curveDimX\", 8);\n    _dimsMap[\"curveDimY\"] = DC::Dimension(\"curveDimY\", 8);\n    _dimsMap[\"curveDimZ\"] = DC::Dimension(\"curveDimZ\", 8);\n    \n    // Coords\n    // ==================\n    _coordVarsMap[\"curveCoordX\"] = CoordVar(\"curveCoordX\", \"m\", DC::FLOAT, periodic, /*axis=x*/0, /*uniformHint=*/false, {\"curveDimX\", \"curveDimY\"}, /*timeDim*/\"\");\n    _coordVarsMap[\"curveCoordY\"] = CoordVar(\"curveCoordY\", \"m\", DC::FLOAT, periodic, /*axis=y*/1, /*uniformHint=*/false, {\"curveDimX\", \"curveDimY\"}, /*timeDim*/\"\");\n    _coordVarsMap[\"curveCoordZ\"] = CoordVar(\"curveCoordZ\", \"m\", DC::FLOAT, periodic, /*axis=z*/2, /*uniformHint=*/false, {\"curveDimX\", \"curveDimY\", \"curveDimZ\"}, /*timeDim*/\"\");\n\n    // Mesh\n    // ==================\n    vector<string> curveDims = {\"curveDimX\", \"curveDimY\", \"curveDimZ\"};\n    vector<string> curveCoords = {\"curveCoordX\", \"curveCoordY\", \"curveCoordZ\"};\n    DC::Mesh curveMesh(\"curveMesh\", curveDims, curveCoords);\n    _meshMap[curveMesh.GetName()] = curveMesh;\n    \n    _dataVarsMap[\"curveData\"] = DC::DataVar(\"curveData\", \"\", DC::FLOAT, periodic, curveMesh.GetName(), /*timeCoordVar*/\"\", DC::Mesh::NODE);\n#endif\n}\n\n\nvoid DCRAM::AddDimension(const DC::Dimension &dim)\n{\n    _dimsMap[dim.GetName()] = dim;\n}\n\n\nvoid DCRAM::AddMesh(const DC::Mesh &mesh)\n{\n    _meshMap[mesh.GetName()] = mesh;\n}\n\n\nvoid DCRAM::AddCoordVar(const DC::CoordVar &var, const float *buf)\n{\n    _coordVarsMap[var.GetName()] = var;\n    \n    size_t size = 1;\n    auto dimNames = var.GetDimNames();\n    for (auto name : dimNames) {\n        DC::Dimension dim;\n        getDimension(name, dim);\n        size *= dim.GetLength();\n    }\n    copyVarData(var, buf, size);\n}\n\n\nvoid DCRAM::AddDataVar(const DC::DataVar &var, const float *buf)\n{\n    _dataVarsMap[var.GetName()] = var;\n    \n    size_t size = 1;\n    vector<size_t> dimLens;\n    GetMeshDimLens(var.GetMeshName(), dimLens);\n    for (auto len : dimLens)\n        size *= len;\n    copyVarData(var, buf, size);\n}\n\n\nvoid DCRAM::copyVarData(const DC::BaseVar &var, const float *buf, const size_t size)\n{\n    if (_dataMap.count(var.GetName()))\n        delete [] _dataMap[var.GetName()];\n    \n    float *copy = new float[size];\n    memcpy(copy, buf, sizeof(float)*size);\n    _dataMap[var.GetName()] = copy;\n}\n\n\nbool DCRAM::getDimension(string dimname, DC::Dimension &dimension) const\n{\n    return getDimension(dimname, dimension, -1);\n}\n\nbool DCRAM::getDimension(string dimname, DC::Dimension &dimension, long ts) const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n    itr = _dimsMap.find(dimname);\n    if (itr == _dimsMap.end()) return (false);\n    dimension = itr->second;\n\n    if (dimension.IsTimeVarying()) {\n#ifndef NDEBUG\n        printf(\"WARNING: RAM dimension '%s' is time varying\", dimname.c_str());\n#endif\n    }\n\n    return true;\n}\n\nstd::vector<string> DCRAM::getDimensionNames() const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    vector<string> names;\n\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nvector<string> DCRAM::getMeshNames() const\n{\n    vector<string>                         mesh_names;\n    std::map<string, Mesh>::const_iterator itr = _meshMap.begin();\n    for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); }\n    return (mesh_names);\n}\n\nbool DCRAM::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    map<string, Mesh>::const_iterator itr = _meshMap.find(mesh_name);\n    if (itr == _meshMap.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nbool DCRAM::getCoordVarInfo(string varname, DC::CoordVar &cvar) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr == _coordVarsMap.end()) { return (false); }\n\n    cvar = itr->second;\n    return (true);\n}\n\nbool DCRAM::getDataVarInfo(string varname, DC::DataVar &datavar) const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    itr = _dataVarsMap.find(varname);\n    if (itr == _dataVarsMap.end()) { return (false); }\n\n    datavar = itr->second;\n    return (true);\n}\n\nbool DCRAM::getBaseVarInfo(string varname, DC::BaseVar &var) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr != _coordVarsMap.end()) {\n        var = itr->second;\n        return (true);\n    }\n\n    map<string, DC::DataVar>::const_iterator itr1 = _dataVarsMap.find(varname);\n    if (itr1 != _dataVarsMap.end()) {\n        var = itr1->second;\n        return (true);\n    }\n\n    return (false);\n}\n\n\nstd::vector<string> DCRAM::getDataVarNames() const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\n\nstd::vector<string> DCRAM::getCoordVarNames() const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\ntemplate<class T> bool DCRAM::_getAttTemplate(string varname, string attname, T &values) const\n{\n    DC::BaseVar var;\n    bool status = getBaseVarInfo(varname, var);\n    if (!status)\n        return false;\n\n    const std::map<string, Attribute> &atts = var.GetAttributes();\n    \n    if (!atts.count(attname))\n        return false;\n    \n    atts.at(attname).GetValues(values);\n\n    return true;\n}\n\nbool DCRAM::getAtt(string varname, string attname, vector<double> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCRAM::getAtt(string varname, string attname, vector<long> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCRAM::getAtt(string varname, string attname, string &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nstd::vector<string> DCRAM::getAttNames(string varname) const\n{\n    if (varname.empty()) {\n        return {};\n    } else {\n        DC::BaseVar var;\n        bool        status = getBaseVarInfo(varname, var);\n        if (!status) {\n            return (vector<string>());\n        }\n\n        vector<string> names;\n\n        const std::map<string, Attribute> &         atts = var.GetAttributes();\n        std::map<string, Attribute>::const_iterator itr;\n        for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); }\n        return (names);\n    }\n}\n\nDC::XType DCRAM::getAttType(string varname, string attname) const\n{\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (DC::INVALID);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (DC::INVALID);\n\n    return (att.GetXType());\n}\n\nint DCRAM::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    VAssert(0);\n    return -1;\n}\n\nint DCRAM::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    bool ok = GetVarDimLens(varname, true, dims_at_level, ts);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\n\nint DCRAM::openVariableRead(size_t ts, string varname)\n{\n    int ret = _fakeVarsFileCounter++;\n    _fdMap[ret] = varname;\n    return ret;\n}\n\n\nint DCRAM::closeVariable(int fd)\n{\n    auto fdIt = _fdMap.find(fd);\n    if (fdIt != _fdMap.end()) _fdMap.erase(fdIt);\n\n    if (fd >= _fakeVarsFileCounterStart) {\n        _fakeVarsFileCounter--;\n        return 0;\n    }\n\n    assert(0);\n    return -1;\n}\n\n// min -> max is inclusive\n\n#include <glm/glm.hpp>\nusing glm::vec3;\nusing glm::vec2;\n\ntemplate<class T> int DCRAM::_readRegionTemplate(int fd, const vector<size_t> &min_, const vector<size_t> &max_, T *region)\n{\n    vector<size_t> min = min_;\n    vector<size_t> max = max_;\n    string         varname = _fdMap[fd];\n//    printf(\"%s(%i(%s), %s, %s, %s*)\\n\", __func__, fd, varname.c_str(), S(min).c_str(), S(max).c_str(), TypeToChar(*region));\n    \n    bool fake = fd >= _fakeVarsFileCounterStart;\n\n    const size_t w = 1 + max[0] - min[0];\n    const size_t h = 1 + max[1] - min[1];\n    const size_t d = 1 + max[2] - min[2];\n    vec3 s(w,h,d);\n#ifdef DCRAM_GENERATE_TEST_DATA\n    vec3 c = s/2.f;\n#endif\n    \n    auto var3d = [=](function<float(vec3 p)> f)\n    {\n        for (size_t z = min[2]; z <= max[2]; z++)\n            for (size_t y = min[1]; y <= max[1]; y++)\n                for (size_t x = min[0]; x <= max[0]; x++)\n                    region[z*w*h+y*w+x] = f(vec3(x,y,z));\n        return 0;\n    };\n    \n    auto var2d = [=](function<float(vec2 p)> f)\n    {\n        for (size_t y = min[1]; y <= max[1]; y++)\n            for (size_t x = min[0]; x <= max[0]; x++)\n                region[y*w+x] = f(vec2(x,y));\n        return 0;\n    };\n    \n    if (_dataMap.count(varname)) {\n        float *data = _dataMap[varname];\n        vector<size_t> dimLens;\n        GetVarDimLens(varname, true, dimLens);\n        assert((dimLens.size() == min.size()) && (min.size() == max.size()));\n        int nDims = dimLens.size();\n        size_t rw=0, rh=0, sx=0, sy=0, sz=0;\n        rw = dimLens[0];\n        sx = min[0];\n        if (nDims > 1) {\n            rh = dimLens[1];\n            sy = min[1];\n        }\n        if (nDims > 2) {\n            sz = min[2];\n        }\n        \n        if (nDims == 1) {\n            for (size_t x = min[0]; x <= max[0]; x++)\n                region[(x-sx)] = data[x];\n        }\n        else if (nDims == 2) {\n            for (size_t y = min[1]; y <= max[1]; y++)\n                for (size_t x = min[0]; x <= max[0]; x++)\n                    region[(y-sy)*w+(x-sx)] = data[y*rw+x];\n        }\n        else if (nDims == 3) {\n            for (size_t z = min[2]; z <= max[2]; z++)\n                for (size_t y = min[1]; y <= max[1]; y++)\n                    for (size_t x = min[0]; x <= max[0]; x++)\n                        region[(z-sz)*w*h+(y-sy)*w+(x-sx)] = data[z*rw*rh+y*rw+x];\n        }\n        return 0;\n    }\n\n#ifdef DCRAM_GENERATE_TEST_DATA\n    \n    if (varname == \"empty\")\n        return var3d([=](vec3 p) { return 0; });\n    \n    if (varname == \"sphere\")\n        return var3d([=](vec3 p) { return glm::distance(p, c); });\n    \n    if (varname == \"sine\")\n        return var3d([=](vec3 p) { return sinf(p.x/(float)w*36); });\n    \n    if (varname == \"grid\")\n        return var3d([=](vec3 p) { return (int)p.x/8%2 == (int)p.y/8%2 == (int)p.z/8%2; });\n    \n    if (varname == \"xval\" || varname == \"xval2\")\n        return var3d([=](vec3 p) { return p.x; });\n    \n    \n    \n    if (varname == \"curveCoordX\")\n        return var2d([=](vec2 p) { return cosf(p.y/(float)h*M_PI) * (p.x+(w+1)); });\n    \n    if (varname == \"curveCoordY\")\n        return var2d([=](vec2 p) { return sinf(p.y/(float)h*M_PI) * (p.x+(w+1)); });\n    \n    if (varname == \"curveCoordZ\")\n        return var3d([=](vec3 p) { return p.z; });\n    \n    if (varname == \"curveData\")\n        return var3d([=](vec3 p) { return glm::distance(p, c); });\n\n#endif\n    \n    \n    if (fake) {\n        // Generate Regular Coords\n        for (size_t i = min[0]; i <= max[0]; i++) region[i] = i / (double)(max[0] - 1);\n        return 0;\n    }\n    \n    VAssert(0);\n    return -1;\n}\n\nbool DCRAM::variableExists(size_t ts, string varname, int, int) const\n{\n    bool found = false;\n\n    for (const auto &it : _dataVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n    for (const auto &it : _coordVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n    for (const auto &it : _auxVarsMap) {\n        if (found) break;\n        if (it.first == varname) found = true;\n    }\n    return found;\n}\n\n\nstd::vector<string> DCRAM::getAuxVarNames() const\n{\n    vector<string> names(_auxVarsMap.size());\n    for (const auto &it : _auxVarsMap) names.push_back(it.first);\n    return names;\n}\n\nbool DCRAM::getAuxVarInfo(string varname, DC::AuxVar &var) const\n{\n    const auto &it = _auxVarsMap.find(varname);\n    if (it == _auxVarsMap.end()) return false;\n    var = it->second;\n    return true;\n}\n"
  },
  {
    "path": "lib/vdc/DCUGRID.cpp",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include <cmath>\n\n#include <vapor/GeoUtil.h>\n#include <vapor/DCUtils.h>\n#include <vapor/DCUGRID.h>\n#include <vapor/VAssert.h>\n\nusing namespace VAPoR;\nusing namespace std;\n\nnamespace {\n\n// Attribute names and values for \"dummy\" UGRID mesh variable\n//\nconst string cfRoleAttName = \"cf_role\";\nconst string cfRoleValueName = \"mesh_topology\";\nconst string topologyAttName = \"topology_dimension\";\nconst string nodeCoordinatesAttName = \"node_coordinates\";\nconst string faceNodeConnectivityAttName = \"face_node_connectivity\";\nconst string faceDimensionAttName = \"face_dimension\";\nconst string edgeNodeConnectivityAttName = \"edge_node_connectivity\";\nconst string edgeDimensionAttName = \"edge_dimension\";\nconst string faceEdgeConnectivityAttName = \"face_edge_connectivity\";\nconst string faceFaceConnectivityAttName = \"face_face_connectivity\";\nconst string edgeFaceConnectivityAttName = \"edge_face_connectivity\";\nconst string boundaryNodeConnectivityAttName = \"boundary_node_connectivity\";\nconst string faceCoordinatesAttName = \"face_coordinates\";\nconst string edgeCoordinatesAttName = \"edge_coordinates\";\n\n// Attribute names and values for data variables\n//\nconst string meshAttName = \"mesh\";\nconst string locationAttName = \"location\";\n\n\ntemplate<class T> int getVar(NetCDFCFCollection *ncdfc, size_t ts, string varname, T *buf)\n{\n    int fd = ncdfc->OpenRead(ts, varname);\n    if (fd < 0) return (fd);\n\n    int rc = ncdfc->Read(buf, fd);\n    if (rc < 0) return (fd);\n\n    return (ncdfc->Close(fd));\n}\n\n// Read a netcdf attribute of type int\n//\nint getAttInt(NetCDFCFCollection *ncdfc, string varName, string attName)\n{\n    vector<long> values;\n    ncdfc->GetAtt(varName, attName, values);\n    if (values.size()) { return (values[0]); }\n\n    return (0);\n}\n\n// Read a netcdf attribute of type string\n//\nstring getAttString(NetCDFCFCollection *ncdfc, string varName, string attName)\n{\n    string v;\n    ncdfc->GetAtt(varName, attName, v);\n    return (v);\n}\n\nbool isUGridDummyVar(NetCDFCFCollection *ncdfc, string varName)\n{\n    string v = getAttString(ncdfc, varName, cfRoleAttName);\n    return (v == cfRoleValueName);\n}\n\nvoid unzipLongitude(vector<int> &connVar, size_t numFaces, size_t maxNodes, const vector<float> &lonVar, int missingNode)\n{\n    VAssert(connVar.size() == numFaces * maxNodes);\n\n    for (size_t j = 0; j < numFaces; j++) {\n        // Sanitize the connectivity array\n        //\n        for (size_t i = 0; i < maxNodes; i++) {\n            int nodeIdx = connVar[j * maxNodes + i];\n            if (nodeIdx < 0 || nodeIdx >= lonVar.size()) { connVar[j * maxNodes + i] = missingNode; }\n        }\n\n\n        // Find first valid node\n        //\n        size_t i = 0;\n        for (; i < maxNodes; i++) {\n            int nodeIdx = connVar[j * maxNodes + i];\n            if (nodeIdx != missingNode) { break; }\n        }\n\n        float p0 = 0.0;\n        if (i < maxNodes) {\n            int nodeIdx = connVar[j * maxNodes + i];\n            p0 = lonVar[nodeIdx];\n            i++;\n        }\n        for (; i < maxNodes; i++) {\n            int nodeIdx = connVar[j * maxNodes + i];\n            if (nodeIdx == missingNode || (std::abs(p0 - lonVar[nodeIdx])) > 180.0) { connVar[j * maxNodes + i] = -2; }\n        }\n    }\n}\n\n};    // namespace\n\n\n\n// The vertical coordinate for a \"layered\" mesh is not explicity identified\n// by a mesh \"dummy\" variable. Instead we have to identify them using\n// the rules of the NetCDF CF conventions upon which UGRID is based\n//\nstring DCUGRID::_getLayeredVerticalCoordVar(NetCDFCFCollection *ncdfc, string varName) const\n{\n    // First check for CF \"1D coordinate\" variable. I.e a variable\n    // with the same name as the vertical dimension\n    //\n    vector<string> dimNames = ncdfc->GetSpatialDimNames(varName);\n    if (dimNames.size() != 2) return (\"\");\n\n    if (ncdfc->IsCoordVarCF(dimNames[0]) && ncdfc->IsVertCoordVar(dimNames[0])) { return (dimNames[0]); }\n\n    // We didn't find a \"1D coordinate\" variable, so see if varName's\n    // \"coordinates\" attribute names a vertical coordinate. I.e. look\n    // for what the CF conventions call an \"auxilliary\" variable\n    //\n    string meshName = getAttString(ncdfc, varName, meshAttName);\n\n    if (meshName.empty() || (_uGridMeshMap.find(meshName) == _uGridMeshMap.end())) { return (\"\"); }\n\n    string s;\n    ncdfc->GetAtt(varName, \"coordinates\", s);\n\n    vector<string> atts;\n    Wasp::StrToWordVec(s, atts);\n    for (auto att : atts) {\n        if (ncdfc->IsVertCoordVar(att)) return (att);\n    }\n\n    return (\"\");\n}\n\n\n// Read metadata for a UGRID \"dummy\" mesh variable, but do no validatation\n//\nvoid DCUGRID::_getUGridMeshFromFile(NetCDFCFCollection *ncdfc, string meshVarName, uGridMeshType &m)\n{\n    m.topology = 0;\n    m.nodeCoordinates = {};\n    m.faceNodeConnectivity = \"\";\n    m.faceDimension = \"\";\n    m.edgeNodeConnectivity = \"\";\n    m.edgeDimension = \"\";\n    m.faceEdgeConnectivity = \"\";\n    m.faceFaceConnectivity = \"\";\n    m.edgeFaceConnectivity = \"\";\n    m.boundaryNodeConnectivity = \"\";\n    m.faceCoordinates = {};\n    m.edgeCoordinates = {};\n\n    string s;\n\n    m.topology = getAttInt(ncdfc, meshVarName, topologyAttName);\n\n    s = getAttString(ncdfc, meshVarName, nodeCoordinatesAttName);\n    Wasp::StrToWordVec(s, m.nodeCoordinates);\n\n    m.faceNodeConnectivity = getAttString(ncdfc, meshVarName, faceNodeConnectivityAttName);\n    m.faceDimension = getAttString(ncdfc, meshVarName, faceDimensionAttName);\n    m.edgeNodeConnectivity = getAttString(ncdfc, meshVarName, edgeNodeConnectivityAttName);\n    m.edgeDimension = getAttString(ncdfc, meshVarName, edgeDimensionAttName);\n    m.faceEdgeConnectivity = getAttString(ncdfc, meshVarName, faceEdgeConnectivityAttName);\n    m.faceFaceConnectivity = getAttString(ncdfc, meshVarName, faceFaceConnectivityAttName);\n    m.edgeFaceConnectivity = getAttString(ncdfc, meshVarName, edgeFaceConnectivityAttName);\n    m.boundaryNodeConnectivity = getAttString(ncdfc, meshVarName, boundaryNodeConnectivityAttName);\n\n    s = getAttString(ncdfc, meshVarName, faceCoordinatesAttName);\n    Wasp::StrToWordVec(s, m.faceCoordinates);\n\n    s = getAttString(ncdfc, meshVarName, edgeCoordinatesAttName);\n    Wasp::StrToWordVec(s, m.edgeCoordinates);\n}\n\n// Get the meshes node dimension by way of meshes' coordinate variables\n//\nstring DCUGRID::_getMeshNodeDimName(NetCDFCFCollection *ncdfc, const uGridMeshType &m) const\n{\n    if (!m.nodeCoordinates.size()) { return (\"\"); }\n\n    // Pick the first coordinate variable. According to the spec they must\n    // all be dimension'd by nNodes\n    //\n    string cVarName = m.nodeCoordinates[0];\n\n    vector<string> dimNames = ncdfc->GetSpatialDimNames(cVarName);\n    if (!dimNames.size()) { return (\"\"); }\n\n    return (dimNames[0]);\n}\n\n// Get the meshes face dimension by way of meshes' face-node connectivity\n// variables\n//\nstring DCUGRID::_getMeshFaceDimName(NetCDFCFCollection *ncdfc, const uGridMeshType &m) const\n{\n    if (m.faceNodeConnectivity.empty()) { return (\"\"); }\n\n    vector<string> dimNames = ncdfc->GetSpatialDimNames(m.faceNodeConnectivity);\n    if (!dimNames.size()) { return (\"\"); }\n\n    return (dimNames[0]);\n}\n\n// Get the meshes max nodes per face\n//\nsize_t DCUGRID::_getMeshMaxNodesPerFace(NetCDFCFCollection *ncdfc, const uGridMeshType &m) const\n{\n    if (m.faceNodeConnectivity.empty()) { return (0); }\n\n    vector<size_t> dimLens = ncdfc->GetSpatialDims(m.faceNodeConnectivity);\n    if (dimLens.size() < 2) { return (0); }\n\n    return (dimLens[1]);\n}\n\n\n// Get the time coordinate variable for a named variable\n//\nbool DCUGRID::_getVarTimeCoords(NetCDFCFCollection *ncdfc, string varName, string &coordName) const\n{\n    coordName.clear();\n\n    vector<string> vars = ncdfc->GetTimeCoordVars();\n\n    string timeDimName = ncdfc->GetTimeDimName(varName);\n\n    if (find(vars.begin(), vars.end(), timeDimName) != vars.end()) { coordName = timeDimName; }\n\n    return (true);\n}\n\n\nint DCUGRID::_initFaceNodeConnectivityMap(NetCDFCFCollection *ncdfc)\n{\n    _faceNodeConnectivityMap.clear();\n\n    // We need to synthesize the node-on-face connectivity map for each\n    // mesh, splitting\n    // faces that straddle the min and max longitude extent\n    //\n    vector<string> meshNames = GetMeshNames();\n    for (auto mName : meshNames) {\n        DC::Mesh mesh;\n\n        bool ok = GetMesh(mName, mesh);\n        VAssert(ok);\n\n        string connVarName = mesh.GetFaceNodeVar();\n\n        // Get the longitude coordinate variable name for this mesh\n        //\n        string         lonVarName;\n        vector<string> coordVarNames = mesh.GetCoordVars();\n        for (auto coordVarName : coordVarNames) {\n            DC::CoordVar cvar;\n\n            ok = GetCoordVarInfo(coordVarName, cvar);\n            VAssert(ok);\n\n            if (cvar.GetAxis() == 0) {\n                lonVarName = coordVarName;\n                break;\n            }\n        }\n        if (lonVarName.empty()) {\n            SetErrMsg(\"Invalid mesh %s : No longitude variable\", mName.c_str());\n            return (-1);\n        }\n\n        // If a connection variable has a Fill Value attribute it indicates\n        // missing nodes from a face. I.e. faces that less than the maximum\n        // number of nodes.\n        //\n        int          missingNode = -1;\n        vector<long> atts;\n        ok = GetAtt(connVarName, \"_FillValue\", atts);\n        if (ok && atts.size() > 0) missingNode = atts[0];\n\n\n        vector<size_t> connVarDims;\n        GetDimLens(connVarName, connVarDims);\n        VAssert(connVarDims.size() == 2);\n\n        vector<size_t> lonVarDims;\n        GetDimLens(lonVarName, lonVarDims);\n        VAssert(lonVarDims.size() == 1);\n\n        // Allocate space for the synthetic variable\n        //\n        _faceNodeConnectivityMap[connVarName] = vector<int>(connVarDims[0] * connVarDims[1], 0);\n\n        vector<int> &connVar = _faceNodeConnectivityMap[connVarName];\n        int          rc = getVar(ncdfc, 0, connVarName, connVar.data());\n        if (rc < 0) {\n            SetErrMsg(\"Unable to read connectivity variable %s\", connVarName.c_str());\n            return (rc);\n        }\n\n        // N.B. Can't call DC::GetVar because this class overrides it\n        //\n        vector<float> lonVar(lonVarDims[0], 0);\n        rc = getVar(ncdfc, 0, lonVarName, lonVar.data());\n        if (rc < 0) {\n            SetErrMsg(\"Unable to read longitude coordinate variable %s\", lonVarName.c_str());\n            return (rc);\n        }\n\n        unzipLongitude(connVar, connVarDims[1], connVarDims[0], lonVar, missingNode);\n    }\n\n    return (0);\n}\n\nint DCUGRID::initialize(const vector<string> &paths, const std::vector<string> &options)\n{\n    int rc = DCCF::initialize(paths, options);\n    if (rc < 0) return (rc);\n\n    return (_initFaceNodeConnectivityMap(_ncdfc));\n}\n\nint DCUGRID::initMesh(NetCDFCFCollection *ncdfc, std::map<string, DC::Mesh> &meshMap)\n{\n    //\n    // Get names of variables of all the 0D variables so we can look\n    // for the UGRID \"dummy\" variables. N.B. we can't use\n    // NetCDFCFCollection::GetDataVariableNames() because that class\n    // distinguishes data variables from other variables in a way\n    // that is not compatible with UGRID\n    //\n    vector<string> vars = ncdfc->GetVariableNames(0, true);\n\n    for (auto v : vars) {\n        if (!isUGridDummyVar(ncdfc, v)) { continue; }\n\n        uGridMeshType m;\n\n        _getUGridMeshFromFile(ncdfc, v, m);\n\n        _uGridMeshMap[v] = m;\n    }\n\n    // Next go through list of all variables in the file, identify those that\n    // are associated with one of the meshes we just found, and convert\n    // from uGridMeshType to DC::Mesh\n    //\n    vars.clear();\n    for (int i = 1; i < 4; i++) {\n        vector<string> v = ncdfc->GetVariableNames(i, true);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    // For each variable determine the mesh\n    //\n    for (auto varName : vars) {\n        // variable type must be float or int\n        //\n        int type = ncdfc->GetXType(varName);\n        if (!(NetCDFSimple::IsNCTypeFloat(type) || NetCDFSimple::IsNCTypeInt(type))) continue;\n\n        string meshName = getAttString(ncdfc, varName, meshAttName);\n\n        if (meshName.empty() || (_uGridMeshMap.find(meshName) == _uGridMeshMap.end())) { continue; }\n\n        auto itr = _uGridMeshMap.find(meshName);\n        if (itr == _uGridMeshMap.end()) { continue; }\n\n        const uGridMeshType &m = itr->second;\n\n        string nodeDimName = _getMeshNodeDimName(ncdfc, m);\n        string faceDimName = _getMeshFaceDimName(ncdfc, m);\n        size_t maxNodesPerFace = _getMeshMaxNodesPerFace(ncdfc, m);\n\n        // We could calculate the max faces per node, but this isn't\n        // used and should probably be removed from the Mesh class\n        //\n        size_t maxFacesPerNode = 0;\n\n        vector<string> dimNames = ncdfc->GetSpatialDimNames(varName);\n        reverse(dimNames.begin(), dimNames.end());\n\n\n        if (dimNames.size() == 1) {\n            // Create new mesh. We're being lazy here and probably should only\n            // create one if it doesn't ready exist\n            //\n            meshMap[meshName] = Mesh(meshName, maxNodesPerFace, maxFacesPerNode, nodeDimName, faceDimName, m.nodeCoordinates, m.faceNodeConnectivity, \"\");\n        } else if (dimNames.size() == 2) {\n            // Layered grids (dimNames.size() == 2) require special handling\n            // to identify the vertical coordinate. Also, because non layered\n            // (2D) and layered (3D) variables can share the same UGRID mesh\n            // we need to generate a unique mesh name for one of them\n            //\n\n            string layeredVarName = _getLayeredVerticalCoordVar(ncdfc, varName);\n            if (layeredVarName.empty()) continue;\n\n            vector<string> coordVarNames = m.nodeCoordinates;\n            coordVarNames.push_back(layeredVarName);\n\n            meshName += layeredVarName;\n\n            meshMap[meshName] = Mesh(meshName, maxNodesPerFace, maxFacesPerNode, nodeDimName, faceDimName, dimNames[1], coordVarNames, m.faceNodeConnectivity, \"\");\n        } else {\n            continue;\n        }\n    }\n\n    // Should the correct behavior be to return an error code if\n    // no valid meshes are found? Right now need this is done so that MainForm\n    // can auto-detect the file. We should probably introduce a separate\n    // detection method on the DC class.\n    //\n    if (meshMap.size() == 0) {\n        SetErrMsg(\"No valid UGRID meshes found\");\n        return (-1);\n    }\n\n    return (0);\n}\n\nint DCUGRID::initAuxilliaryVars(NetCDFCFCollection *ncdfc, std::map<string, DC::AuxVar> &auxVarsMap)\n{\n    auxVarsMap.clear();\n\n    vector<bool> periodic(3, false);\n    //\n    // Get names of variables in the UGRID data set that have 1 or 2\n    // \"spatial\" dimensions\n    //\n    vector<string> vars;\n    for (int i = 1; i < 3; i++) {\n        vector<string> v = ncdfc->GetVariableNames(i, true);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    for (auto varName : vars) {\n        // variable type must be int\n        //\n        int type = ncdfc->GetXType(varName);\n        if (!(NetCDFSimple::IsNCTypeInt(type))) { continue; }\n\n        vector<string> dimnames = ncdfc->GetSpatialDimNames(varName);\n        if (!dimnames.size()) continue;\n\n        reverse(dimnames.begin(), dimnames.end());\n\n        auxVarsMap[varName] = AuxVar(varName, \"\", DC::INT32, \"\", vector<size_t>(), periodic, dimnames);\n    }\n\n    return (0);\n}\n\nint DCUGRID::initDataVars(NetCDFCFCollection *ncdfc, std::map<string, DC::DataVar> &dataVarsMap)\n{\n    dataVarsMap.clear();\n\n    vector<bool> periodic(3, false);\n    //\n    // Get names of variables in the UGRID data set that have 1 or 2\n    // \"spatial\" dimensions\n    //\n    vector<string> vars;\n    for (int i = 1; i < 3; i++) {\n        vector<string> v = ncdfc->GetVariableNames(i, true);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    // For each variable add a member to dataVarsMap\n    //\n    for (auto varName : vars) {\n        // variable type must be float\n        //\n        int type = ncdfc->GetXType(varName);\n        if (!(NetCDFSimple::IsNCTypeFloat(type))) { continue; }\n\n        // Checking for whether a variable can be a coordinate variable\n        // eliminates a lot of variables from being data variables. There\n        // doesn't seem to be any reason why a variable can't be both a\n        // data variable and a coordinate variable. Leaving this code\n        // commented out for now.\n        //\n        // if (IsCoordVar(varName)) {continue; }\n        // Currently coordinate variables can't be data variables :-(\n        //\n        if (ncdfc->IsCoordinateVar(varName)) continue;\n\n        // variable must have valid mesh attribute\n        //\n        string meshName = getAttString(ncdfc, varName, meshAttName);\n\n        if (meshName.empty()) { continue; }\n\n        if (_uGridMeshMap.find(meshName) == _uGridMeshMap.end()) {\n            SetDiagMsg(\"No valid mesh for variable named %s\", varName.c_str());\n            continue;\n        }\n\n        // Need to generate a unique mesh name for layered grids since\n        // UGRID allows 2D and 3D layered variables to share same mesh,\n        // but DC class does not.\n        //\n        vector<string> dimNames = ncdfc->GetSpatialDimNames(varName);\n        if (dimNames.size() == 2) { meshName += _getLayeredVerticalCoordVar(ncdfc, varName); }\n\n        // Only node-centered variables supported currently\n        //\n        string locationName = getAttString(ncdfc, varName, locationAttName);\n\n        if (locationName != \"node\") {\n            SetDiagMsg(\"Only node-centered data supported for variable named %s\", varName.c_str());\n            continue;\n        }\n\n        string coordName;\n        bool   ok = _getVarTimeCoords(ncdfc, varName, coordName);\n        if (!ok) {\n            SetDiagMsg(\"Invalid variable : %s\", varName.c_str());\n            continue;\n        }\n\n        string units;\n        ncdfc->GetAtt(varName, \"units\", units);\n\n        double mv;\n        bool   has_missing = ncdfc->GetMissingValue(varName, mv);\n\n        if (!has_missing) {\n            dataVarsMap[varName] = DataVar(varName, units, DC::FLOAT, periodic, meshName, coordName, DC::Mesh::NODE);\n        } else {\n            dataVarsMap[varName] = DataVar(varName, units, DC::FLOAT, periodic, meshName, coordName, DC::Mesh::NODE, mv);\n        }\n\n        int rc = DCUtils::CopyAtt(*ncdfc, varName, dataVarsMap[varName]);\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\nint DCUGRID::OpenVariableRead(size_t ts, string varname, int level, int lod)\n{\n    // Pass through normal open operation if this is not a synthesized\n    // connectivity variable\n    //\n    if (_faceNodeConnectivityMap.find(varname) == _faceNodeConnectivityMap.end()) { return (DC::OpenVariableRead(ts, varname, level, lod)); }\n\n    FileTable::FileObject *f = new FileTable::FileObject(ts, varname);\n    return (_fileTable.AddEntry(f));\n}\n\nint DCUGRID::Read(int fd, int *data)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    // Pass through normal read operation if this is not a synthesized\n    // connectivity variable\n    //\n    if (_faceNodeConnectivityMap.find(f->GetVarname()) == _faceNodeConnectivityMap.end()) { return (DC::Read(fd, data)); }\n\n    const vector<int> &connVar = _faceNodeConnectivityMap[f->GetVarname()];\n    std::copy_n(connVar.data(), connVar.size(), data);\n    return (0);\n}\n\nint DCUGRID::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *data)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    if (_faceNodeConnectivityMap.find(f->GetVarname()) == _faceNodeConnectivityMap.end()) { return (DC::ReadRegion(fd, min, max, data)); }\n    VAssert(min.size() == max.size());\n\n    size_t n = 1;\n    for (int i = 0; i < min.size(); i++) {\n        VAssert(min[i] == 0);\n        n *= max[i] + 1;\n    }\n\n    const vector<int> &connVar = _faceNodeConnectivityMap[f->GetVarname()];\n    VAssert(n == connVar.size());\n    std::copy_n(connVar.data(), connVar.size(), data);\n    return (0);\n}\n\nint DCUGRID::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    if (_faceNodeConnectivityMap.find(f->GetVarname()) == _faceNodeConnectivityMap.end()) { return (DC::CloseVariable(fd)); }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n"
  },
  {
    "path": "lib/vdc/DCUtils.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2018\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tDataMgrUtils.cpp\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune 2018\n//\n//\tDescription:\tImplements the DataMgrUtils free functions\n//\n#ifdef WIN32\n    #pragma warning(disable : 4251 4100)\n#endif\n\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <algorithm>\n\n#include <vapor/NetCDFCollection.h>\n#include <vapor/DCUtils.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nint DCUtils::CopyAtt(const NetCDFCollection &ncdfc, string varname, string attname, DC::BaseVar &var)\n{\n    int nctype = ncdfc.GetAttType(varname, attname);\n\n    if (nctype == NC_INT64) {\n        vector<long> values;\n        ncdfc.GetAtt(varname, attname, values);\n\n        DC::Attribute attr(attname, DC::INT64, values);\n        var.SetAttribute(attr);\n\n    } else if (nctype == NC_DOUBLE) {\n        vector<double> values;\n        ncdfc.GetAtt(varname, attname, values);\n\n        DC::Attribute attr(attname, DC::DOUBLE, values);\n        var.SetAttribute(attr);\n\n    } else if (nctype == NC_CHAR) {\n        string values;\n        ncdfc.GetAtt(varname, attname, values);\n\n        DC::Attribute attr(attname, DC::TEXT, values);\n        var.SetAttribute(attr);\n\n    } else {\n        Wasp::MyBase::SetErrMsg(\"Invalid attribute : %s.%s\", varname.c_str(), attname.c_str());\n        return -1;\n    }\n    return 0;\n}\n\nint DCUtils::CopyAtt(const NetCDFCollection &ncdfc, string varname, DC::BaseVar &var)\n{\n    vector<string> attNames = ncdfc.GetAttNames(varname);\n\n    for (int i = 0; i < attNames.size(); i++) {\n        int rc = CopyAtt(ncdfc, varname, attNames[i], var);\n        if (rc < 0) return (rc);\n    }\n    return (0);\n}\n"
  },
  {
    "path": "lib/vdc/DCWRF.cpp",
    "content": "#include <vector>\n#include <algorithm>\n#include <map>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <cassert>\n#include <stdio.h>\n\n#ifdef _WINDOWS\n    #define _USE_MATH_DEFINES\n    #pragma warning(disable : 4251 4100)\n#endif\n#include <cmath>\n\n#include <vapor/GeoUtil.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/DCUtils.h>\n#include <vapor/DCWRF.h>\n#include <vapor/DerivedVar.h>\n#include <vapor/utils.h>\n#include <netcdf.h>\n\nusing namespace VAPoR;\nusing namespace std;\n\nnamespace {\n#ifdef UNUSED_FUNCTION\nbool mycompare(const pair<int, float> &a, const pair<int, float> &b) { return (a.second < b.second); }\n#endif\n\nfloat read_scalar_float_attr(NetCDFCollection *ncdfc, string varname, string attrname, float default_value)\n{\n    vector<double> dvalues;\n    ncdfc->GetAtt(varname, attrname, dvalues);\n    if (dvalues.size() != 1) return (default_value);\n\n    return ((float)dvalues[0]);\n}\n\nDC::XType netcdf_to_dc_xtype(int t)\n{\n    switch (t) {\n    case NC_DOUBLE: return (DC::XType::DOUBLE);\n    case NC_INT64: return (DC::XType::INT64);\n    case NC_CHAR: return (DC::XType::TEXT);\n    default: return (DC::XType::INVALID);\n    }\n}\n\n};    // namespace\n\nDCWRF::DCWRF()\n{\n    _ncdfc = NULL;\n\n    _dx = 0.0;\n    _dy = 0.0;\n    _cen_lat = 0.0;\n    _cen_lon = 0.0;\n    _true_lat1 = 0.0;\n    _true_lat2 = 0.0;\n    _pole_lat = 90.0;\n    _pole_lon = 0.0;\n    _grav = 9.81;\n    _radius = 0.0;\n    _p2si = 1.0;\n    _mapProj = 0;\n\n    _proj4String.clear();\n\n    _derivedVars.clear();\n    _derivedTime = NULL;\n\n    _dimsMap.clear();\n    _coordVarsMap.clear();\n    _dataVarsMap.clear();\n    _meshMap.clear();\n}\n\nDCWRF::~DCWRF()\n{\n    for (int i = 0; i < _derivedVars.size(); i++) {\n        if (_derivedVars[i]) delete _derivedVars[i];\n    }\n    if (_derivedTime) delete _derivedTime;\n\n    if (_ncdfc) delete _ncdfc;\n}\n\nint DCWRF::initialize(const vector<string> &files, const std::vector<string> &options)\n{\n    if (_ncdfc) delete _ncdfc;\n    _ncdfc = nullptr;\n\n    if (_derivedTime) delete _ncdfc;\n    _derivedTime = nullptr;\n\n    NetCDFCollection *ncdfc = new NetCDFCollection();\n\n    // Initialize the NetCDFCollection class. Need to specify the name\n    // of the time dimension (\"Time\" for WRF), and time coordinate variable\n    // names (N/A for WRF)\n    //\n    vector<string> time_dimnames;\n    vector<string> time_coordvars;\n    time_dimnames.push_back(\"Time\");\n    int rc = ncdfc->Initialize(files, time_dimnames, time_coordvars);\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize netCDF data collection for reading\");\n        return (-1);\n    }\n\n    // Use UDUnits for unit conversion\n    //\n    rc = _udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", _udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n    // Get required and optional global attributes  from WRF files.\n    // Initializes members: _dx, _dy, _cen_lat, _cen_lon, _pole_lat,\n    // _pole_lon, _grav, _radius, _p2si\n    //\n    rc = _InitAtts(ncdfc);\n    if (rc < 0) return (-1);\n\n    //\n    //  Get the dimensions of the grid.\n    //\tInitializes members: _dimsMap\n    //\n    rc = _InitDimensions(ncdfc);\n    if (rc < 0) {\n        SetErrMsg(\"No valid dimensions\");\n        return (-1);\n    }\n\n    // Set up map projection transforms\n    // Initializes members: _proj4String, _mapProj\n    //\n    rc = _InitProjection(ncdfc, _radius);\n    if (rc < 0) { return (-1); }\n\n    // Set up the horizontal coordinate variables\n    //\n    // Initializes members: _coordVarMap\n    //\n    rc = _InitHorizontalCoordinates(ncdfc);\n    if (rc < 0) { return (-1); }\n\n    // Set up the vertical coordinate variable. WRF data set doesn't\n    // provide one.\n    //\n    // Initializes members: _coordVarMap\n    //\n    rc = _InitVerticalCoordinates(ncdfc);\n    if (rc < 0) { return (-1); }\n\n    // Set up user time coordinate derived variable . Time must be\n    // in seconds.\n    // Initializes members: _coordVarsMap\n    //\n    rc = _InitTime(ncdfc);\n    if (rc < 0) { return (-1); }\n\n    //\n    // Identify data and coordinate variables. Sets up members:\n    // Initializes members: _dataVarsMap, _meshMap, _coordVarsMap\n    //\n    rc = _InitVars(ncdfc);\n    if (rc < 0) return (-1);\n\n    _ncdfc = ncdfc;\n\n    return (0);\n}\n\nbool DCWRF::getDimension(string dimname, DC::Dimension &dimension) const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    itr = _dimsMap.find(dimname);\n    if (itr == _dimsMap.end()) return (false);\n\n    dimension = itr->second;\n    return (true);\n}\n\nstd::vector<string> DCWRF::getDimensionNames() const\n{\n    map<string, DC::Dimension>::const_iterator itr;\n\n    vector<string> names;\n\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nvector<string> DCWRF::getMeshNames() const\n{\n    vector<string>                         mesh_names;\n    std::map<string, Mesh>::const_iterator itr = _meshMap.begin();\n    for (; itr != _meshMap.end(); ++itr) { mesh_names.push_back(itr->first); }\n    return (mesh_names);\n}\n\nbool DCWRF::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    map<string, Mesh>::const_iterator itr = _meshMap.find(mesh_name);\n    if (itr == _meshMap.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nbool DCWRF::getCoordVarInfo(string varname, DC::CoordVar &cvar) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr == _coordVarsMap.end()) { return (false); }\n\n    cvar = itr->second;\n    return (true);\n}\n\nbool DCWRF::getDataVarInfo(string varname, DC::DataVar &datavar) const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    itr = _dataVarsMap.find(varname);\n    if (itr == _dataVarsMap.end()) { return (false); }\n\n    datavar = itr->second;\n    return (true);\n}\n\nbool DCWRF::getBaseVarInfo(string varname, DC::BaseVar &var) const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    itr = _coordVarsMap.find(varname);\n    if (itr != _coordVarsMap.end()) {\n        var = itr->second;\n        return (true);\n    }\n\n    map<string, DC::DataVar>::const_iterator itr1 = _dataVarsMap.find(varname);\n    if (itr1 != _dataVarsMap.end()) {\n        var = itr1->second;\n        return (true);\n    }\n\n    return (false);\n}\n\nstd::vector<string> DCWRF::getDataVarNames() const\n{\n    map<string, DC::DataVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _dataVarsMap.begin(); itr != _dataVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nstd::vector<string> DCWRF::getCoordVarNames() const\n{\n    map<string, DC::CoordVar>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _coordVarsMap.begin(); itr != _coordVarsMap.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\ntemplate<class T> bool DCWRF::_getAttTemplate(string varname, string attname, T &values) const\n{\n    if (varname.empty()) {\n        _ncdfc->GetAtt(\"\", attname, values);\n        return (true);\n    }\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (status);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (status);\n\n    att.GetValues(values);\n\n    return (true);\n}\n\nbool DCWRF::getAtt(string varname, string attname, vector<double> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCWRF::getAtt(string varname, string attname, vector<long> &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nbool DCWRF::getAtt(string varname, string attname, string &values) const\n{\n    values.clear();\n\n    return (_getAttTemplate(varname, attname, values));\n}\n\nstd::vector<string> DCWRF::getAttNames(string varname) const\n{\n    if (varname.empty()) return (_ncdfc->GetAttNames(\"\"));\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (vector<string>());\n\n    vector<string> names;\n\n    const std::map<string, Attribute> &         atts = var.GetAttributes();\n    std::map<string, Attribute>::const_iterator itr;\n    for (itr = atts.begin(); itr != atts.end(); ++itr) { names.push_back(itr->first); }\n\n    return (names);\n}\n\nDC::XType DCWRF::getAttType(string varname, string attname) const\n{\n    if (varname.empty()) { return (netcdf_to_dc_xtype(_ncdfc->GetAttType(\"\", attname))); }\n\n    DC::BaseVar var;\n    bool        status = getBaseVarInfo(varname, var);\n    if (!status) return (DC::INVALID);\n\n    DC::Attribute att;\n    status = var.GetAttribute(attname, att);\n    if (!status) return (DC::INVALID);\n\n    return (att.GetXType());\n}\nint DCWRF::getDimLensAtLevel(string varname, int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    bool ok;\n    if (_dvm.IsCoordVar(varname)) {\n        return (_dvm.GetDimLensAtLevel(varname, 0, dims_at_level, bs_at_level, -1));\n    } else {\n        ok = GetVarDimLens(varname, true, dims_at_level, -1);\n    }\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Never blocked\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nstring DCWRF::getMapProjection() const { return (_proj4String); }\n\nint DCWRF::openVariableRead(size_t ts, string varname)\n{\n    if (ts >= _ncdfc->GetNumTimeSteps()) {\n        SetErrMsg(\"Time step out of range : %d\", ts);\n        return (-1);\n    }\n    ts = _derivedTime->TimeLookup(ts);\n\n    int  fd;\n    bool derivedFlag;\n    if (_dvm.IsCoordVar(varname)) {\n        fd = _dvm.OpenVariableRead(ts, varname);\n        derivedFlag = true;\n    } else {\n        fd = _ncdfc->OpenRead(ts, varname);\n        derivedFlag = false;\n    }\n    if (fd < 0) return (-1);\n\n    WRFFileObject *w = new WRFFileObject(ts, varname, 0, 0, fd, derivedFlag);\n\n    return (_fileTable.AddEntry(w));\n}\n\nint DCWRF::closeVariable(int fd)\n{\n    WRFFileObject *w = (WRFFileObject *)_fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    int rc;\n    if (w->GetDerivedFlag()) {\n        rc = _dvm.CloseVariable(aux);\n    } else {\n        rc = _ncdfc->Close(aux);\n    }\n    _fileTable.RemoveEntry(fd);\n    delete w;\n\n    return (rc);\n}\n\ntemplate<class T> int DCWRF::_readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region)\n{\n    VAssert(min.size() == max.size());\n\n    WRFFileObject *w = (WRFFileObject *)_fileTable.GetEntry(fd);\n\n    if (!w) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int aux = w->GetAux();\n\n    if (w->GetDerivedFlag()) { return (_dvm.ReadRegion(aux, min, max, region)); }\n\n    vector<size_t> ncdf_start = min;\n    reverse(ncdf_start.begin(), ncdf_start.end());\n\n    vector<size_t> ncdf_max = max;\n    reverse(ncdf_max.begin(), ncdf_max.end());\n\n    vector<size_t> ncdf_count;\n    for (int i = 0; i < ncdf_start.size(); i++) { ncdf_count.push_back(ncdf_max[i] - ncdf_start[i] + 1); }\n\n    return (_ncdfc->Read(ncdf_start, ncdf_count, region, aux));\n}\n\nbool DCWRF::variableExists(size_t ts, string varname, int, int) const\n{\n    if (ts >= _ncdfc->GetNumTimeSteps()) { return (false); }\n    ts = _derivedTime->TimeLookup(ts);\n\n    if (_dvm.IsCoordVar(varname)) { return (_dvm.VariableExists(ts, varname, 0, 0)); }\n    return (_ncdfc->VariableExists(ts, varname));\n}\n\nvector<size_t> DCWRF::_GetSpatialDims(NetCDFCollection *ncdfc, string varname) const\n{\n    vector<size_t> dims = ncdfc->GetSpatialDims(varname);\n    reverse(dims.begin(), dims.end());\n    return (dims);\n}\n\nvector<string> DCWRF::_GetSpatialDimNames(NetCDFCollection *ncdfc, string varname) const\n{\n    vector<string> v = ncdfc->GetSpatialDimNames(varname);\n    reverse(v.begin(), v.end());\n    return (v);\n}\n\n//\n// Read select attributes from the WRF files. Most of the attributes are\n// needed for map projections\n//\nint DCWRF::_InitAtts(NetCDFCollection *ncdfc)\n{\n    _dx = read_scalar_float_attr(ncdfc, \"\", \"DX\", _dx);\n    _dy = read_scalar_float_attr(ncdfc, \"\", \"DY\", _dy);\n    _cen_lat = read_scalar_float_attr(ncdfc, \"\", \"CEN_LAT\", _cen_lat);\n    _cen_lon = read_scalar_float_attr(ncdfc, \"\", \"CEN_LON\", _cen_lon);\n    _true_lat1 = read_scalar_float_attr(ncdfc, \"\", \"TRUELAT1\", _true_lat1);\n    _true_lat2 = read_scalar_float_attr(ncdfc, \"\", \"TRUELAT2\", _true_lat2);\n    _pole_lat = read_scalar_float_attr(ncdfc, \"\", \"POLE_LAT\", _pole_lat);\n    _pole_lon = read_scalar_float_attr(ncdfc, \"\", \"POLE_LON\", _pole_lon);\n\n    //\n    // \"PlanetWRF\" attributes\n    //\n    // RADIUS is the radius of the planet\n    //\n    // P2SI is the number of SI seconds in an planetary solar day\n    // divided by the number of SI seconds in an earth solar day\n    //\n    vector<double> dvalues;\n    ncdfc->GetAtt(\"\", \"G\", dvalues);\n    if (dvalues.size() == 1) {\n        _grav = dvalues[0];\n\n        _radius = read_scalar_float_attr(ncdfc, \"\", \"RADIUS\", _radius);\n        _p2si = read_scalar_float_attr(ncdfc, \"\", \"P2SI\", _p2si);\n    }\n\n    return (0);\n}\n\n//\n// Generate a Proj4 projection string for whatever map projection is used\n// by the data. Map projection type is indicated by map_proj\n// The Proj4 string will be used to transform from geographic coordinates\n// measured in degrees to Cartographic coordinates in meters.\n//\nint DCWRF::_GetProj4String(NetCDFCollection *ncdfc, float radius, int map_proj, string &projstring)\n{\n    projstring.clear();\n    ostringstream oss;\n\n    vector<double> dvalues;\n    switch (map_proj) {\n    case 0: {    // Lat Lon\n\n        double lon_0 = _cen_lon;\n        double lat_0 = _cen_lat;\n        oss << \" +lon_0=\" << lon_0 << \" +lat_0=\" << lat_0;\n        projstring = \"+proj=eqc +ellps=WGS84\" + oss.str();\n\n    } break;\n    case 1: {    // Lambert\n        ncdfc->GetAtt(\"\", \"STAND_LON\", dvalues);\n        if (dvalues.size() != 1) {\n            SetErrMsg(\"Error reading required attribute : STAND_LON\");\n            return (-1);\n        }\n        float lon0 = dvalues[0];\n\n        // Construct the projection string:\n        projstring = \"+proj=lcc\";\n        projstring += \" +lon_0=\";\n        oss.str(\"\");\n        oss << (double)lon0;\n        projstring += oss.str();\n\n        projstring += \" +lat_1=\";\n        oss.str(\"\");\n        oss << (double)_true_lat1;\n        projstring += oss.str();\n\n        projstring += \" +lat_2=\";\n        oss.str(\"\");\n        oss << (double)_true_lat2;\n        projstring += oss.str();\n\n        break;\n    }\n\n    case 2: {    // Polar stereographic (pure north or south)\n        projstring = \"+proj=stere\";\n\n        // Determine whether north or south pole (lat_ts is pos or neg)\n\n        float lat0;\n        if (_true_lat1 < 0.)\n            lat0 = -90.0;\n        else\n            lat0 = 90.0;\n\n        projstring += \" +lat_0=\";\n        oss.str(\"\");\n        oss << (double)lat0;\n        projstring += oss.str();\n\n        projstring += \" +lat_ts=\";\n        oss.str(\"\");\n        oss << (double)_true_lat1;\n        projstring += oss.str();\n\n        ncdfc->GetAtt(\"\", \"STAND_LON\", dvalues);\n        if (dvalues.size() != 1) {\n            SetErrMsg(\"Error reading required attribute : STAND_LON\");\n            return (-1);\n        }\n        float lon0 = dvalues[0];\n\n        projstring += \" +lon_0=\";\n        oss.str(\"\");\n        oss << (double)lon0;\n        projstring += oss.str();\n\n        break;\n    }\n\n    case (3): {    // Mercator\n\n        ncdfc->GetAtt(\"\", \"STAND_LON\", dvalues);\n        if (dvalues.size() != 1) {\n            SetErrMsg(\"Error reading required attribute : STAND_LON\");\n            return (-1);\n        }\n        float lon0 = dvalues[0];\n\n        // Construct the projection string:\n        projstring = \"+proj=merc\";\n\n        projstring += \" +lon_0=\";\n        oss.str(\"\");\n        oss << (double)lon0;\n        projstring += oss.str();\n\n        projstring += \" +lat_ts=\";\n        oss.str(\"\");\n        oss << (double)_true_lat1;\n        projstring += oss.str();\n\n        break;\n    }\n\n    case (6): {    // lat-long, possibly rotated, possibly cassini\n\n        // See if this is a regular cylindrical equidistant projection\n        // with the pole in the default location\n        //\n        if (_pole_lat == 90.0 && _pole_lon == 0.0) {\n            double        lon_0 = _cen_lon;\n            double        lat_0 = _cen_lat;\n            ostringstream oss;\n            oss << \" +lon_0=\" << lon_0 << \" +lat_0=\" << lat_0;\n            projstring = \"+proj=eqc +ellps=WGS84\" + oss.str();\n        } else {\n            //\n            // Assume arbitrary pole displacement. Probably should\n            // check for cassini projection (transverse cylindrical)\n            // but general rotated cyl. equidist. projection should work\n            //\n            ncdfc->GetAtt(\"\", \"STAND_LON\", dvalues);\n            if (dvalues.size() != 1) {\n                SetErrMsg(\"Error reading required attribute : STAND_LON\");\n                return (-1);\n            }\n            float lon0 = dvalues[0];\n\n            projstring = \"+proj=ob_tran\";\n            projstring += \" +o_proj=eqc\";\n            projstring += \" +to_meter=0.0174532925199\";\n\n            projstring += \" +o_lat_p=\";\n            oss.str(\"\");\n            oss << (double)_pole_lat;\n            projstring += oss.str();\n            projstring += \"d\";    // degrees, not radians\n\n            projstring += \" +o_lon_p=\";\n            oss.str(\"\");\n            oss << (double)(180. - _pole_lon);\n            projstring += oss.str();\n            projstring += \"d\";    // degrees, not radians\n\n            projstring += \" +lon_0=\";\n            oss.str(\"\");\n            oss << (double)(-lon0);\n            projstring += oss.str();\n            projstring += \"d\";    // degrees, not radians\n        }\n\n        break;\n    }\n    default: {\n        SetErrMsg(\"Unsupported MAP_PROJ value : %d\", _mapProj);\n        return -1;\n    }\n    }\n\n    if (projstring.empty()) return (0);\n\n    //\n    // PlanetWRF data if radius is not zero\n    //\n    if (radius > 0) {    // planetWRf (not on earth)\n        projstring += \" +ellps=sphere\";\n        stringstream ss;\n        ss << radius;\n        projstring += \" +a=\" + ss.str() + \" +es=0\";\n    } else {\n        projstring += \" +ellps=WGS84\";\n    }\n\n    return (0);\n}\n\n// Check to see if the horizontal coordinates, XLONG and XLAT, are\n// constant value. For simplicity, only check the\n// first two elements of each array.\n//\n// N.B. older WRF files (pre 4.x) don't have an attribute that identifies\n// the files as being \"idealized\"; for idealized cases the horizontal\n// coordinates are initialized to constant values.\n//\nbool DCWRF::_isConstantValuedVariable(NetCDFCollection *ncdfc, string varname) const\n{\n    bool enabled = EnableErrMsg(false);\n\n    vector<float> data;\n\n    vector<size_t> dims = ncdfc->GetSpatialDims(varname);\n\n    vector<size_t> start(dims.size(), 0);\n    vector<size_t> count = dims;\n\n    // Edge case.\n    //\n    if (Wasp::VProduct(dims) < 2) return (true);\n\n    data.resize(Wasp::VProduct(dims));\n\n    int fd = ncdfc->OpenRead(0, varname);\n    if (fd < 0) {\n        EnableErrMsg(enabled);\n        return (false);\n    }\n\n    int rc = ncdfc->Read(start.data(), count.data(), data.data(), fd);\n    if (rc < 0) {\n        EnableErrMsg(enabled);\n        return (false);\n    }\n\n    ncdfc->Close(fd);\n\n    float a0 = data[0];\n    float epsilon = 0.000001;\n    for (size_t i = 1; i < Wasp::VProduct(dims); i++) {\n        if (!Wasp::NearlyEqual(a0, data[i], epsilon)) {\n            EnableErrMsg(enabled);\n            return (false);\n        }\n    }\n\n    EnableErrMsg(enabled);\n\n    return (true);\n}\n\nbool DCWRF::_isIdealized(NetCDFCollection *ncdfc) const\n{\n    // Version 4.0 of WRF introduced \"IDEAL_CASE\" attribute.\n    // For earlier versions we look for hints\n    //\n    vector<long> l;\n    ncdfc->GetAtt(\"\", \"IDEAL_CASE\", l);\n    if (l.size() && l[0] != 0) return (true);\n\n    string s;\n    ncdfc->GetAtt(\"\", \"MAP_PROJ_CHAR\", s);\n    if (Wasp::StrCmpNoCase(s, \"Cartesian\") == 0) return (true);\n\n    ncdfc->GetAtt(\"\", \"SIMULATION_INITIALIZATION_TYPE\", s);\n    if (Wasp::StrCmpNoCase(s, \"IDEALIZED DATA\") == 0) return (true);\n\n    // Pre version 4.x WRF did not have an attribute to identify\n    // idealized cases. However, these cases have constant-valued\n    // XLONG and XLAT coordinates. N.B. The staggered grid horizontal\n    // coordinates (XLONG_U, XLAT_V, etc.) may not exist.\n    //\n    vector<string> cvars = {\"XLONG\", \"XLAT\"};\n    for (auto &c : cvars) {\n        if (_isConstantValuedVariable(ncdfc, c)) return (true);\n    }\n\n    if (_isWRFSFIRE(ncdfc) && _cen_lat == 0.0 && _cen_lon == 0.0 && _true_lat1 == 0.0 && _true_lat2 == 0.0) { return (true); }\n\n    return (false);\n}\n\nbool DCWRF::_isWRFSFIRE(NetCDFCollection *ncdfc) const\n{\n    if (!ncdfc->VariableExists(\"FXLONG\")) return (false);\n\n    if (!ncdfc->VariableExists(\"FXLAT\")) return (false);\n\n    return (true);\n}\n\n//\n// Set up map projection stuff\n//\nint DCWRF::_InitProjection(NetCDFCollection *ncdfc, float radius)\n{\n    _proj4String.clear();\n    _mapProj = 0;\n\n    if (_isIdealized(ncdfc)) return (0);\n\n    vector<long> ivalues;\n    ncdfc->GetAtt(\"\", \"MAP_PROJ\", ivalues);\n    if (ivalues.size() != 1) {\n        SetErrMsg(\"Error reading required attribute : MAP_PROJ\");\n        return (-1);\n    }\n    _mapProj = ivalues[0];\n\n    int rc = _GetProj4String(ncdfc, radius, _mapProj, _proj4String);\n    if (rc < 0) return (rc);\n\n    return (0);\n}\n\nDerivedCoordVar_CF2D *DCWRF::_makeDerivedHorizontalIdealized(NetCDFCollection *ncdfc, string name, string &timeDimName, vector<string> &spaceDimNames)\n{\n    timeDimName.clear();\n    spaceDimNames.clear();\n\n    timeDimName = ncdfc->GetTimeDimName(name);\n    spaceDimNames = ncdfc->GetSpatialDimNames(name);\n    reverse(spaceDimNames.begin(), spaceDimNames.end());\n\n    vector<size_t> dimLens = ncdfc->GetSpatialDims(name);\n    reverse(dimLens.begin(), dimLens.end());\n    VAssert(dimLens.size() == 2);\n\n    vector<float> data;\n    data.resize(dimLens[0] * dimLens[1]);\n\n    string units = \"km\";\n    float  offset = 0.0;\n    int    axis = 0;\n    if (name == \"XLONG\") {\n        axis = 0;\n        offset = _dx / 2.0;\n    } else if (name == \"XLAT\") {\n        axis = 1;\n        offset = _dy / 2.0;\n    } else if (name == \"XLONG_U\") {\n        axis = 0;\n        offset = 0.0;\n    } else if (name == \"XLAT_U\") {\n        axis = 1;\n        offset = _dy / 2.0;\n    } else if (name == \"XLONG_V\") {\n        axis = 0;\n        offset = _dx / 2.0;\n    } else if (name == \"XLAT_V\") {\n        axis = 1;\n        offset = 0.0;\n    } else {\n        return (NULL);\n    }\n\n    if (axis == 0) {\n        for (size_t j = 0; j < dimLens[1]; j++) {\n            for (size_t i = 0; i < dimLens[0]; i++) { data[j * dimLens[0] + i] = i * _dx + offset; }\n        }\n    } else {\n        for (size_t j = 0; j < dimLens[1]; j++) {\n            for (size_t i = 0; i < dimLens[0]; i++) { data[j * dimLens[0] + i] = j * _dy + offset; }\n        }\n    }\n\n    DerivedCoordVar_CF2D *derivedVar = new DerivedCoordVar_CF2D(name, spaceDimNames, dimLens, axis, units, data);\n\n    int rc = derivedVar->Initialize();\n    if (rc < 0) return (NULL);\n\n    _dvm.AddCoordVar(derivedVar);\n\n    return (derivedVar);\n}\n\nDerivedCoordVar_Staggered *DCWRF::_makeDerivedHorizontalStaggered(NetCDFCollection *ncdfc, string name, string &timeDimName, vector<string> &spaceDimNames)\n{\n    timeDimName.clear();\n    spaceDimNames.clear();\n\n    int    stagDim;\n    string stagDimName;\n    string inName;\n    string dimName;\n    if (name == \"XLONG_U\") {\n        stagDim = 0;\n        stagDimName = \"west_east_stag\";\n        inName = \"XLONG\";\n        dimName = \"west_east\";\n    } else if (name == \"XLAT_U\") {\n        stagDim = 0;\n        stagDimName = \"west_east_stag\";\n        inName = \"XLAT\";\n        dimName = \"west_east\";\n    } else if (name == \"XLONG_V\") {\n        stagDim = 1;\n        stagDimName = \"south_north_stag\";\n        inName = \"XLONG\";\n        dimName = \"south_north\";\n    } else if (name == \"XLAT_V\") {\n        stagDim = 1;\n        stagDimName = \"south_north_stag\";\n        inName = \"XLAT\";\n        dimName = \"south_north\";\n    } else {\n        return (NULL);\n    }\n\n    timeDimName = ncdfc->GetTimeDimName(inName);\n    spaceDimNames = ncdfc->GetSpatialDimNames(inName);\n    reverse(spaceDimNames.begin(), spaceDimNames.end());\n\n    spaceDimNames[stagDim] = stagDimName;\n\n    DerivedCoordVar_Staggered *derivedVar = new DerivedCoordVar_Staggered(name, stagDimName, this, inName, dimName);\n    int                        rc = derivedVar->Initialize();\n    if (rc < 0) return (NULL);\n\n    _dvm.AddCoordVar(derivedVar);\n\n    return (derivedVar);\n}\n\nint DCWRF::_InitHorizontalCoordinatesHelper(NetCDFCollection *ncdfc, string name, int axis)\n{\n    VAssert(axis == 0 || axis == 1);\n\n    DerivedVar *derivedVar = NULL;\n\n    string         timeDimName;\n    vector<string> spaceDimNames;\n\n    //\n    // Set up coordinate units identifier\n    //\n    string units;\n    if (_proj4String.empty()) {\n        if (_isWRFSFIRE(ncdfc)) {\n            // For *idealized* WRF-SFIRE model runs the 'units' attribute\n            // say degrees, but it's actually meters. Clever.\n            //\n            units = \"meters\";\n        } else {\n            units = \"km\";\n        }\n    } else {\n        units = axis == 0 ? \"degrees_east\" : \"degrees_north\";\n    }\n\n    if (ncdfc->VariableExists(name) && !_proj4String.empty()) {\n        timeDimName = ncdfc->GetTimeDimName(name);\n\n        spaceDimNames = ncdfc->GetSpatialDimNames(name);\n        reverse(spaceDimNames.begin(), spaceDimNames.end());\n    } else if (ncdfc->VariableExists(name) && _proj4String.empty() && _isConstantValuedVariable(ncdfc, name)) {\n        // For idealized case we need to synthesize Cartesian coordinates\n        //\n        derivedVar = _makeDerivedHorizontalIdealized(ncdfc, name, timeDimName, spaceDimNames);\n        if (!derivedVar) return (-1);\n    } else if (ncdfc->VariableExists(name) && _proj4String.empty() && _isWRFSFIRE(ncdfc) && !_isConstantValuedVariable(ncdfc, name)) {\n        // Idealized WRF-SFIRE cases do have coordinate variables that\n        // are already represented in meters\n        //\n        timeDimName = ncdfc->GetTimeDimName(name);\n\n        spaceDimNames = ncdfc->GetSpatialDimNames(name);\n        reverse(spaceDimNames.begin(), spaceDimNames.end());\n\n    } else {\n        // Ugh. Older WRF files don't have coordinate variables for\n        // staggered dimensions, so we need to derive them.\n        //\n        derivedVar = _makeDerivedHorizontalStaggered(ncdfc, name, timeDimName, spaceDimNames);\n        if (!derivedVar) return (-1);\n    }\n\n    // Finally, add the variable to _coordVarsMap. Probably don't\n    // need to do this here. Could do this when we process native WRF\n    // variables later. Sigh\n    //\n    vector<bool> periodic(2, false);\n    _coordVarsMap[name] = CoordVar(name, units, DC::FLOAT, periodic, axis, false, spaceDimNames, timeDimName);\n\n    int rc = DCUtils::CopyAtt(*ncdfc, name, _coordVarsMap[name]);\n    if (rc < 0) return (-1);\n\n    if (derivedVar) { _derivedVars.push_back(derivedVar); }\n\n    return (0);\n}\n\n//\n// Set up horizontal coordinates\n//\nint DCWRF::_InitHorizontalCoordinates(NetCDFCollection *ncdfc)\n{\n    _coordVarsMap.clear();\n\n    // XLONG and XLAT must have same dimensionality\n    //\n    vector<size_t> latlondims = ncdfc->GetDims(\"XLONG\");\n    vector<size_t> dummy = ncdfc->GetDims(\"XLAT\");\n    if (dummy != latlondims) {\n        SetErrMsg(\"Coordinate variables XLONG and XLAT having different dimensions!\\n\");\n        return (-1);\n    }\n    if (latlondims.size() < 2 || latlondims.size() > 3) {\n        SetErrMsg(\"Coordinate variables XLONG and XLAT are not 2D or 3D variables!\\n\");\n        return (-1);\n    }\n\n    // \"XLONG\" coordinate, unstaggered\n    //\n    (void)_InitHorizontalCoordinatesHelper(ncdfc, \"XLONG\", 0);\n\n    // \"XLAT\" coordinate, unstaggered\n    //\n    (void)_InitHorizontalCoordinatesHelper(ncdfc, \"XLAT\", 1);\n\n    // \"XLONG_U\" coordinate, staggered\n    //\n    (void)_InitHorizontalCoordinatesHelper(ncdfc, \"XLONG_U\", 0);\n\n    // \"XLAT_U\" coordinate, staggered\n    //\n    (void)_InitHorizontalCoordinatesHelper(ncdfc, \"XLAT_U\", 1);\n\n    // \"XLONG_V\" coordinate, staggered\n    //\n    (void)_InitHorizontalCoordinatesHelper(ncdfc, \"XLONG_V\", 0);\n\n    // \"XLAT_V\" coordinate, staggered\n    //\n    (void)_InitHorizontalCoordinatesHelper(ncdfc, \"XLAT_V\", 1);\n\n    if (_isWRFSFIRE(ncdfc)) {\n        // \"FXLONG\" coordinate, unstaggered\n        //\n        (void)_InitHorizontalCoordinatesHelper(ncdfc, \"FXLONG\", 0);\n\n        // \"FXLAT\" coordinate, staggered\n        //\n        (void)_InitHorizontalCoordinatesHelper(ncdfc, \"FXLAT\", 1);\n    }\n\n    return (0);\n}\n\nDerivedCoordVar_CF1D *DCWRF::_InitVerticalCoordinatesHelper(string varName, string dimName)\n{\n    DerivedCoordVar_CF1D *derivedVar;\n\n    vector<string> dimNames = {dimName};\n    string         units = \"\";\n    int            axis = 2;\n\n    derivedVar = new DerivedCoordVar_CF1D(varName, this, dimName, axis, units);\n    (void)derivedVar->Initialize();\n\n    _dvm.AddCoordVar(derivedVar);\n\n    vector<bool> periodic(1, false);\n    string       time_dim_name = \"\";\n\n    CoordVar cvar(varName, units, DC::FLOAT, periodic, axis, false, dimNames, time_dim_name);\n\n    if (varName == \"bottom_top\" || varName == \"bottom_top_stag\") {\n        cvar.SetAttribute(Attribute(\"standard_name\", DC::XType::TEXT, \"wrf_terrain\"));\n\n        string formula_terms = \"PH: PH PHB: PHB\";\n        cvar.SetAttribute(Attribute(\"formula_terms\", DC::XType::TEXT, formula_terms));\n    }\n\n    _coordVarsMap[varName] = cvar;\n\n    return (derivedVar);\n}\n\n//\n// Create 1D derived variables expressing the vertical coordinates\n// in unitless grid index coordinates.\n//\nint DCWRF::_InitVerticalCoordinates(NetCDFCollection *ncdfc)\n{\n    // Create 1D vertical coordinate variable for each \"vertical\" dimension\n    //\n    // First do ones we know about. These require special treatment because\n    // they may be transformed to other units\n    //\n    string name = \"bottom_top\";\n    if (_dimsMap.find(name) != _dimsMap.end()) { _derivedVars.push_back(_InitVerticalCoordinatesHelper(name, name)); }\n\n    name = \"bottom_top_stag\";\n    if (_dimsMap.find(name) != _dimsMap.end()) { _derivedVars.push_back(_InitVerticalCoordinatesHelper(name, name)); }\n\n    // Now handle dimensions that are  not documented . I.e. everything\n    // else in the 3rd dimension position\n    //\n    vector<string> vars = ncdfc->GetVariableNames(3, true);\n\n    for (int i = 0; i < vars.size(); i++) {\n        vector<string> dimnames = ncdfc->GetSpatialDimNames(vars[i]);\n        assert(dimnames.size() == 3);\n        reverse(dimnames.begin(), dimnames.end());\n        name = dimnames[2];\n        if (_dimsMap.find(name) == _dimsMap.end()) continue;\n\n        // no duplicates\n        //\n        if (_coordVarsMap.find(name) != _coordVarsMap.end()) continue;\n\n        _derivedVars.push_back(_InitVerticalCoordinatesHelper(name, name));\n    }\n\n    return (0);\n}\n\n// Create a derived variable for the time coordinate. Time in WRF data\n// is an array of formatted time strings. The DC class requires that\n// time be expressed as seconds represented as floats.\n//\nint DCWRF::_InitTime(NetCDFCollection *ncdfc)\n{\n    _derivedTime = NULL;\n\n    // Create and install the Time coordinate variable\n    //\n\n    string derivedName = \"Time\";\n    string wrfVarName = \"Times\";\n    string dimName = \"Time\";\n    _derivedTime = new DerivedCoordVar_WRFTime(derivedName, ncdfc, wrfVarName, dimName, _p2si);\n\n    int rc = _derivedTime->Initialize();\n    if (rc < 0) return (-1);\n\n    _dvm.AddCoordVar(_derivedTime);\n\n    DC::CoordVar cvarInfo;\n    (void)_dvm.GetCoordVarInfo(derivedName, cvarInfo);\n\n    _coordVarsMap[derivedName] = cvarInfo;\n\n    return (0);\n}\n\n// Get Space and time dimensions from WRF data set. Initialize\n// _dimsMap\n//\nint DCWRF::_InitDimensions(NetCDFCollection *ncdfc)\n{\n    _dimsMap.clear();\n\n    // Get dimension names and lengths for all dimensions in the\n    // WRF data set.\n    //\n    vector<string> dimnames = ncdfc->GetDimNames();\n    vector<size_t> dimlens = ncdfc->GetDims();\n    VAssert(dimnames.size() == dimlens.size());\n\n    // WRF files use reserved names for dimensions. The time dimension\n    // is always named \"Time\", etc.\n    // Dimensions are expressed in the DC::Dimension class as a\n    // combination of name, and length.\n    //\n    string timedimname = \"Time\";\n    for (int i = 0; i < dimnames.size(); i++) {\n        Dimension dim(dimnames[i], dimlens[i]);\n        _dimsMap[dimnames[i]] = dim;\n    }\n\n    if ((_dimsMap.find(\"west_east\") == _dimsMap.end()) || (_dimsMap.find(\"west_east_stag\") == _dimsMap.end()) || (_dimsMap.find(\"south_north\") == _dimsMap.end())\n        || (_dimsMap.find(\"south_north_stag\") == _dimsMap.end()) ||\n        // (_dimsMap.find(\"bottom_top\") == _dimsMap.end()) ||\n        // (_dimsMap.find(\"bottom_top_stag\") == _dimsMap.end()) ||\n        (_dimsMap.find(\"Time\") == _dimsMap.end())) {\n        SetErrMsg(\"Missing dimension\");\n        return (-1);\n    }\n    return (0);\n}\n\n// Given a data variable name return the variable's dimension names and\n// associated coordinate variables. The coordinate variable names\n// returned is for the derived coordinate variables expressed in\n// Cartographic coordinates, not the native geographic coordinates\n// found in the WRF file.\n//\n// The order of the returned vectors\n// is significant.\n//\nbool DCWRF::_GetVarCoordinates(NetCDFCollection *ncdfc, string varname, vector<string> &sdimnames, vector<string> &scoordvars, string &time_dim_name, string &time_coordvar\n\n)\n{\n    sdimnames.clear();\n    scoordvars.clear();\n    time_dim_name.clear();\n    time_coordvar.clear();\n\n    // Order of dimensions in WRF files is reverse of DC convention\n    //\n    vector<string> dimnames = ncdfc->GetDimNames(varname);\n    reverse(dimnames.begin(), dimnames.end());\n\n    // Deal with time dimension first\n    //\n    if (dimnames.size() == 1) {\n        if (dimnames[0].compare(\"Time\") != 0) { return (false); }\n        time_dim_name = \"Time\";\n        time_coordvar = \"Time\";\n        return (true);\n    }\n\n    // only handle 2d, 3d, and 4d variables\n    //\n    if (dimnames.size() < 2) return (false);\n\n    if (dimnames[0].compare(\"west_east\") == 0 && dimnames[1].compare(\"south_north\") == 0) {\n        scoordvars.push_back(\"XLONG\");\n        scoordvars.push_back(\"XLAT\");\n    } else if (dimnames[0].compare(\"west_east_stag\") == 0 && dimnames[1].compare(\"south_north\") == 0) {\n        scoordvars.push_back(\"XLONG_U\");\n        scoordvars.push_back(\"XLAT_U\");\n    } else if (dimnames[0].compare(\"west_east\") == 0 && dimnames[1].compare(\"south_north_stag\") == 0) {\n        scoordvars.push_back(\"XLONG_V\");\n        scoordvars.push_back(\"XLAT_V\");\n    } else if (_isWRFSFIRE(ncdfc) && dimnames[0].compare(\"west_east_subgrid\") == 0 && dimnames[1].compare(\"south_north_subgrid\") == 0) {\n        scoordvars.push_back(\"FXLONG\");\n        scoordvars.push_back(\"FXLAT\");\n    } else {\n        return (false);\n    }\n\n    if (dimnames.size() > 2 && dimnames[2] != \"Time\") { scoordvars.push_back(dimnames[2]); }\n\n    sdimnames = dimnames;\n\n    if (dimnames.size() == 2) { return (true); }\n\n    if (sdimnames.back().compare(\"Time\") == 0) {\n        time_dim_name = \"Time\";\n        time_coordvar = \"Time\";\n        sdimnames.pop_back();    // Oops. Remove time dimension\n    }\n    return (true);\n}\n\n// Collect metadata for all data variables found in the WRF data\n// set. Initialize the _dataVarsMap member\n//\nint DCWRF::_InitVars(NetCDFCollection *ncdfc)\n{\n    _dataVarsMap.clear();\n    _meshMap.clear();\n\n    //\n    // Get names of variables  in the WRF data set that have 1 2 or 3\n    // spatial dimensions\n    //\n    vector<string> vars;\n    for (int i = 1; i < 4; i++) {\n        vector<string> v = ncdfc->GetVariableNames(i, true);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    // For each variable add a member to _dataVarsMap\n    //\n    for (int i = 0; i < vars.size(); i++) {\n        // variable type must be float or int\n        //\n        int type = ncdfc->GetXType(vars[i]);\n        if (!(NetCDFSimple::IsNCTypeFloat(type) || NetCDFSimple::IsNCTypeInt(type))) continue;\n\n        // If variables are in _coordVarsMap then they are coordinate, not\n        // data, variables\n        //\n        if (_coordVarsMap.find(vars[i]) != _coordVarsMap.end()) continue;\n\n        vector<string> sdimnames;\n        vector<string> scoordvars;\n        string         time_dim_name;\n        string         time_coordvar;\n\n        bool ok = _GetVarCoordinates(ncdfc, vars[i], sdimnames, scoordvars, time_dim_name, time_coordvar);\n\n        // Must have a coordinate variable for each dimension!\n        //\n        if (sdimnames.size() != scoordvars.size()) { continue; }\n\n        if (!ok) continue;\n        // if (! ok) {\n        //\tSetErrMsg(\"Invalid variable : %s\", vars[i].c_str());\n        //\treturn(-1);\n        //}\n\n        Mesh mesh(\"\", sdimnames, scoordvars);\n\n        // Create new mesh. We're being lazy here and probably should only\n        // createone if it doesn't ready exist\n        //\n        _meshMap[mesh.GetName()] = mesh;\n\n        string units;\n        ncdfc->GetAtt(vars[i], \"units\", units);\n        if (!_udunits.ValidUnit(units)) { units = \"\"; }\n\n        vector<bool> periodic(3, false);\n        DC::DataVar  dvar = DataVar(vars[i], units, DC::FLOAT, periodic, mesh.GetName(), time_coordvar, DC::Mesh::NODE);\n\n        int rc = DCUtils::CopyAtt(*ncdfc, vars[i], dvar);\n        if (rc < 0) return (-1);\n\n        _dataVarsMap[vars[i]] = dvar;\n    }\n\n    return (0);\n}\n"
  },
  {
    "path": "lib/vdc/DataMgr.cpp",
    "content": "#include <iostream>\n#include <sstream>\n#include <stdio.h>\n#include <cstring>\n#include \"vapor/VAssert.h\"\n#include <cfloat>\n#include <vector>\n#include <map>\n#include <algorithm>\n#include <type_traits>\n#include <vapor/VDCNetCDF.h>\n#include <vapor/DCWRF.h>\n#include <vapor/DCCF.h>\n#include <vapor/DCMPAS.h>\n#include <vapor/DCBOV.h>\n#include <vapor/DCP.h>\n#include <vapor/DCRAM.h>\n#include <vapor/DCMelanie.h>\n#include <vapor/DerivedVar.h>\n#if DCP_ENABLE_PARTICLE_DENSITY\n    #include <vapor/DerivedParticleDensity.h>\n#endif\n#include <vapor/DCUGRID.h>\n#include <vapor/DataMgr.h>\n#include <vapor/GeoUtil.h>\n#ifdef WIN32\n    #include <float.h>\n#endif\nusing namespace Wasp;\nusing namespace VAPoR;\n\nnamespace {\n\nsize_t vproduct(DimsType a)\n{\n    size_t ntotal = 1;\n\n    for (size_t i = 0; i < a.size(); i++) ntotal *= a[i];\n\n    return (ntotal);\n}\n\nDimsType box_dims(const DimsType &min, const DimsType &max)\n{\n    DimsType dims;\n\n    for (int i = 0; i < min.size(); i++) {\n        VAssert(min[i] <= max[i]);\n        dims[i] = (max[i] - min[i] + 1);\n    }\n    return (dims);\n}\n\n// Again, stupid gcc-4.8 on CentOS7 requires this alias.\ntemplate<bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;\n\n// Format a vector as a space-separated element string\n//\ntemplate<class T> string vector_to_string(T v)\n{\n    ostringstream oss;\n\n    oss << \"[\";\n    for (int i = 0; i < v.size(); i++) { oss << v[i] << \" \"; }\n    oss << \"]\";\n    return (oss.str());\n}\n\nsize_t number_of_dimensions(DimsType dims)\n{\n    size_t ndims = 0;\n    for (int i = 0; i < dims.size() && dims[i] > 1; i++) ndims++;\n\n    return (ndims);\n}\n\n#ifdef UNUSED_FUNCTION\n\nsize_t decimate_length(size_t l)\n{\n    if (l % 2)\n        return ((l + 1) / 2);\n    else\n        return (l / 2);\n}\n\n// Compute dimensions of a multidimensional array, specified by dims,\n// after undergoing decimiation\n//\nvector<size_t> decimate_dims(const DimsType &dims, int l)\n{\n    DimsType new_dims = dims;\n    for (int i = 0; i < l; i++) {\n        for (int j = 0; j < new_dims.size(); j++) { new_dims[j] = decimate_length(new_dims[j]); }\n    }\n    return (new_dims);\n}\n\n// Decimate a 1D array with simple averaging.\n//\ntemplate<typename T> void decimate1d(const DimsType &src_bs, const T *src, T *dst)\n{\n    DimsType dst_bs;\n    for (int i = 0; i < src_bs.size(); i++) { dst_bs[i] = (decimate_length(src_bs[i])); }\n\n    size_t ni0 = src_bs[0];\n\n    size_t ni1 = dst_bs[0];\n\n    for (size_t i = 0; i < ni1; i++) { dst[i] = 0.0; }\n\n    // Perform in-place 4-node averaging, handling odd boundary cases\n    //\n    for (size_t i = 0, ii = 0; i < ni0; i++) {\n        float iwgt = 0.5;\n        if (i == ni0 - 1 && ni0 % 2) iwgt = 1.0;    // odd i boundary\n        float w = iwgt;\n\n        VAssert(w <= 1.0);\n\n        dst[ii] += w * src[i];\n        if (i % 2) ii++;\n    }\n}\n\ntemplate<typename T> void decimate2d(const DimsType &src_bs, const T *src, T *dst)\n{\n    DimsType dst_bs;\n    for (int i = 0; i < src_bs.size(); i++) { dst_bs[i] = (decimate_length(src_bs[i])); }\n\n    size_t ni0 = src_bs[0];\n    size_t nj0 = src_bs[1];\n\n    size_t ni1 = dst_bs[0];\n    size_t nj1 = dst_bs[1];\n\n    for (size_t j = 0; j < nj1; j++) {\n        for (size_t i = 0; i < ni1; i++) { dst[j * ni1 + i] = 0.0; }\n    }\n\n    // Perform in-place 4-node averaging, handling odd boundary cases\n    //\n    for (size_t j = 0, jj = 0; j < nj0; j++) {\n        float jwgt = 0.0;\n        if (j == nj0 - 1 && nj0 % 2) jwgt = 0.25;    // odd j boundary\n\n        for (size_t i = 0, ii = 0; i < ni0; i++) {\n            float iwgt = 0.25;\n            if (i == ni0 - 1 && ni0 % 2) iwgt = 0.5;    // odd i boundary\n            float w = iwgt + jwgt;\n\n            VAssert(w <= 1.0);\n\n            dst[jj * ni1 + ii] += w * src[j * ni0 + i];\n            if (i % 2) ii++;\n        }\n        if (j % 2) jj++;\n    }\n}\n\ntemplate<typename T> void decimate3d(const DimsType > &src_bs, const T *src, T *dst)\n{\n    DimsType dst_bs;\n    for (int i = 0; i < src_bs.size(); i++) { dst_bs[i] = (decimate_length(src_bs[i])); }\n\n    size_t ni0 = src_bs[0];\n    size_t nj0 = src_bs[1];\n    size_t nk0 = src_bs[2];\n\n    size_t ni1 = dst_bs[0];\n    size_t nj1 = dst_bs[1];\n    size_t nk1 = dst_bs[2];\n\n    for (size_t k = 0; k < nk1; k++) {\n        for (size_t j = 0; j < nj1; j++) {\n            for (size_t i = 0; i < ni1; i++) { dst[k * ni1 * nj1 + j * ni1 + i] = 0.0; }\n        }\n    }\n\n    // Perform in-place 8-node averaging, handling odd boundary cases\n    //\n    for (size_t k = 0, kk = 0; k < nk0; k++) {\n        float kwgt = 0.0;\n        if (k == nk0 - 1 && nk0 % 2) kwgt = 0.125;    // odd k boundary\n\n        for (size_t j = 0, jj = 0; j < nj0; j++) {\n            float jwgt = 0.0;\n            if (j == nj0 - 1 && nj0 % 2) jwgt = 0.125;    // odd j boundary\n\n            for (size_t i = 0, ii = 0; i < ni0; i++) {\n                float iwgt = 0.125;\n                if (i == ni0 - 1 && ni0 % 2) iwgt = 0.25;    // odd i boundary\n                float w = iwgt + jwgt + kwgt;\n\n                VAssert(w <= 1.0);\n\n                dst[kk * ni1 * nj1 + jj * ni1 + ii] += w * src[k * ni0 * nj0 + j * ni0 + i];\n                if (i % 2) ii++;\n            }\n            if (j % 2) jj++;\n        }\n        if (k % 2) kk++;\n    }\n}\n\n// Perform decimation of a 1D, 2D, or 3D blocked array\n//\ntemplate<typename T> void decimate(const DimsType &bmin, const DimsType &bmax, const DimsType &src_bs, const T *src, T *dst)\n{\n    DimsType dst_bs;\n    for (int i = 0; i < src_bs.size(); i++) { dst_bs[i] = (decimate_length(src_bs[i])); }\n\n    size_t src_block_size = VProduct(src_bs);\n    size_t dst_block_size = VProduct(dst_bs);\n\n    size_t ndims = number_of_dimensions(src_bs);\n\n    if (ndims == 1) {\n        for (int i = bmin[0]; i <= bmax[0]; i++) {\n            decimate1d(src_bs, src, dst);\n            src += src_block_size;\n            dst += dst_block_size;\n        }\n    } else if (ndims == 2) {\n        for (int j = bmin[1]; j <= bmax[1]; j++) {\n            for (int i = bmin[0]; i <= bmax[0]; i++) {\n                decimate2d(src_bs, src, dst);\n                src += src_block_size;\n                dst += dst_block_size;\n            }\n        }\n    } else {\n        for (int k = bmin[2]; k <= bmax[2]; k++) {\n            for (int j = bmin[1]; j <= bmax[1]; j++) {\n                for (int i = bmin[0]; i <= bmax[0]; i++) {\n                    decimate3d(src_bs, src, dst);\n                    src += src_block_size;\n                    dst += dst_block_size;\n                }\n            }\n        }\n    }\n}\n\n#endif\n\nvoid downsample_compute_weights(size_t nIn, size_t nOut, vector<float> &wgts)\n{\n    VAssert(nOut <= nIn);\n    wgts.resize(nOut, 0.0);\n\n    float deltax = (float)nIn / (float)nOut;\n    float shift = ((nIn - 1) - (deltax * (nOut - 1))) / 2.0;\n    for (int i = 0; i < nOut; i++) { wgts[i] = (i * deltax) + shift; }\n}\n\ntemplate<typename T> void downsample1d(const T *signalIn, size_t nIn, size_t strideIn, T *signalOut, size_t nOut, size_t strideOut, const vector<float> &wgts)\n{\n    VAssert(nOut <= nIn);\n    VAssert(nOut == wgts.size());\n\n    for (size_t i = 0; i < nOut; i++) {\n        size_t i0 = wgts[i];\n        float  w = wgts[i] - i0;\n        signalOut[i * strideOut] = (signalIn[i0 * strideIn] * (1.0 - w)) + (signalIn[(i0 + 1) * strideIn] * w);\n    }\n}\n\ntemplate<typename T> void downsample2d(const T *signalIn, DimsType inDims, T *signalOut, DimsType outDims)\n{\n\n    // Sample along first dimension\n    //\n    vector<float> wgts;\n    downsample_compute_weights(inDims[0], outDims[0], wgts);\n\n    T *buf = new T[inDims[1] * outDims[0]];\n\n    size_t nIn = inDims[0];\n    size_t nOut = outDims[0];\n    size_t strideIn = 1;\n    size_t strideOut = 1;\n    size_t n = inDims[1];\n    for (int i = 0; i < n; i++) {\n        const T *inPtr = signalIn + (i * nIn);\n        T *      outPtr = buf + (i * nOut);\n        downsample1d(inPtr, nIn, strideIn, outPtr, nOut, strideOut, wgts);\n    }\n\n    // Sample along second dimension\n    //\n    downsample_compute_weights(inDims[1], outDims[1], wgts);\n\n    nIn = inDims[1];\n    nOut = outDims[1];\n    strideIn = outDims[0];\n    strideOut = outDims[0];\n    n = outDims[0];\n    for (int i = 0; i < n; i++) {\n        const T *inPtr = buf + i;\n        T *      outPtr = signalOut + i;\n        downsample1d(inPtr, nIn, strideIn, outPtr, nOut, strideOut, wgts);\n    }\n\n    delete[] buf;\n}\n\ntemplate<typename T> void downsample3d(const T *signalIn, DimsType inDims, T *signalOut, DimsType outDims)\n{\n\n    // Sample along XY planes first\n    //\n\n    T *buf = new T[inDims[2] * outDims[1] * outDims[0]];\n\n    DimsType inDims2d = {inDims[0], inDims[1]};\n    DimsType outDims2d = {outDims[0], outDims[1]};\n\n    size_t nIn = inDims[0] * inDims[1];\n    size_t nOut = outDims[0] * outDims[1];\n    size_t n = inDims[2];\n    for (int i = 0; i < n; i++) {\n        const T *inPtr = signalIn + (i * nIn);\n        T *      outPtr = buf + (i * nOut);\n        downsample2d(inPtr, inDims2d, outPtr, outDims2d);\n    }\n\n    // Sample along Z dimension\n    //\n    vector<float> wgts;\n    downsample_compute_weights(inDims[2], outDims[2], wgts);\n\n    nIn = inDims[2];\n    nOut = outDims[2];\n    size_t strideIn = outDims[0] * outDims[1];\n    size_t strideOut = outDims[0] * outDims[1];\n    n = outDims[0] * outDims[1];\n    for (int i = 0; i < n; i++) {\n        const T *inPtr = buf + i;\n        T *      outPtr = signalOut + i;\n        downsample1d(inPtr, nIn, strideIn, outPtr, nOut, strideOut, wgts);\n    }\n\n    delete[] buf;\n}\n\ntemplate<typename T> void downsample(const T *signalIn, DimsType inDims, T *signalOut, DimsType outDims)\n{\n    size_t ndims = number_of_dimensions(inDims);\n\n    if (ndims == 1) {\n        vector<float> wgts;\n        downsample_compute_weights(inDims[0], outDims[0], wgts);\n\n        downsample1d(signalIn, inDims[0], 1, signalOut, outDims[0], 1, wgts);\n    } else if (ndims == 2) {\n        downsample2d(signalIn, inDims, signalOut, outDims);\n    } else if (ndims == 3) {\n        downsample3d(signalIn, inDims, signalOut, outDims);\n    }\n}\n\n// Map voxel to block coordinates\n//\nvoid map_vox_to_blk(DimsType bs, const DimsType &vcoord, DimsType &bcoord)\n{\n    for (int i = 0; i < bs.size(); i++) { bcoord[i] = (vcoord[i] / bs[i]); }\n}\n\nvoid map_blk_to_vox(DimsType bs, const DimsType &bmin, const DimsType &bmax, DimsType &vmin, DimsType &vmax)\n{\n    for (int i = 0; i < bs.size(); i++) {\n        vmin[i] = (bmin[i] * bs[i]);\n        vmax[i] = (bmax[i] * bs[i] + bs[i] - 1);\n    }\n}\n\n// Map block to vox coordinates, and clamp to dimension boundaries\n//\nvoid map_blk_to_vox(const DimsType &bs, const DimsType &dims, const DimsType &bmin, const DimsType &bmax, DimsType &vmin, DimsType &vmax)\n{\n    for (int i = 0; i < bs.size(); i++) {\n        VAssert(dims[i] > 0);\n        vmin[i] = (bmin[i] * bs[i]);\n        vmax[i] = (bmax[i] * bs[i] + bs[i] - 1);\n        if (vmin[i] >= dims[i]) vmin[i] = dims[i] - 1;\n        if (vmax[i] >= dims[i]) vmax[i] = dims[i] - 1;\n    }\n}\n\n\n// Copy a contiguous region to a blocked grid\n//\n// src : pointer to contiguous region\n// dst : pointer to blocked grid\n// min : min region coordinates within destination grid (in voxels)\n// max : max region coordinates within destination grid (in voxels)\n// bs : block size of destination grid (in voxels)\n// dims : dimensions of destination grid (in voxels)\n//\ntemplate<class T> void copy_block(const T *src, T *dst, const DimsType &min, const DimsType &max, const DimsType &bs, const DimsType &grid_min, const DimsType &grid_max)\n{\n    DimsType dims;        // dimensions of destination region in voxels\n    DimsType bdims;       // dimensions of destination grid in blocks\n    DimsType src_dims;    // dimensions of source region in voxels\n    for (int i = 0; i < grid_min.size(); i++) {\n        dims[i] = (grid_max[i] - grid_min[i] + 1);\n        bdims[i] = (((dims[i] - 1) / bs[i]) + 1);\n        src_dims[i] = (max[i] - min[i] + 1);\n    }\n\n    // Input coordinates are specified relative to origin of entire\n    // domain, but 'dst' region origin is at 'grid_min'\n    //\n    DimsType my_min = min;\n    DimsType my_max = max;\n    for (int i = 0; i < min.size(); i++) {\n        my_min[i] -= grid_min[i];\n        my_max[i] -= grid_min[i];\n    }\n\n    size_t block_size = vproduct(bs);\n\n    for (long k = my_min[2], kk = 0; k <= (long)my_max[2] && k < (long)dims[2]; k++, kk++) {\n        if (k < 0) continue;\n\n        // Coordinates of destination block (block coordinates)\n        //\n        size_t dst_k_b = k / bs[2];\n\n        // Coordinates within destination block (voxel coordinates)\n        //\n        size_t dst_k = k % bs[2];\n\n        for (long j = my_min[1], jj = 0; j <= (long)my_max[1] && j < (long)dims[1]; j++, jj++) {\n            if (j < 0) continue;\n            size_t dst_j_b = j / bs[1];\n            size_t dst_j = j % bs[1];\n\n            for (long i = my_min[0], ii = 0; i <= (long)max[0] && i < (long)dims[0]; i++, ii++) {\n                if (i < 0) continue;\n\n                size_t dst_i_b = i / bs[0];\n                size_t dst_i = i % bs[0];\n\n                size_t dst_block_offset = (dst_k_b * bdims[0] * bdims[1] + dst_j_b * bdims[0] + dst_i_b) * block_size;\n\n                size_t dst_offset = dst_k * bs[0] * bs[1] + dst_j * bs[0] + dst_i;\n\n                size_t src_offset = kk * src_dims[0] * src_dims[1] + jj * src_dims[0] + ii;\n\n                dst[dst_block_offset + dst_offset] = src[src_offset];\n            }\n        }\n    }\n}\n\nbool is_blocked(const DimsType &bs)\n{\n    return (!std::all_of(bs.cbegin(), bs.cend(), [](size_t i) { return i == 1; }));\n}\n\n// Is string a number?\n//\nbool is_int(std::string str)\n{\n    if (!str.empty() && str[0] == '-') str.erase(0, 1);\n    return str.find_first_not_of(\"0123456789\") == std::string::npos;\n}\n\ntemplate<typename T, enable_if_t<std::is_floating_point<T>::value, int> = 0> void _sanitizeFloats(T *buffer, size_t n)\n{\n    for (size_t i = 0; i < n; i++) {\n        if (std::isnan(buffer[i])) buffer[i] = std::numeric_limits<T>::infinity();\n    }\n}\n\n// MSVC has a bug where isnan() is not overloaded for integral types.\n// This function specializes the template to bypass this bug.\ntemplate<typename T, enable_if_t<std::is_integral<T>::value, int> = 0> void _sanitizeFloats(T *buffer, size_t n) {}\n\ntemplate<typename T> bool contains(const vector<T> &v, T element) { return (find(v.begin(), v.end(), element) != v.end()); }\n\n\n\n};    // namespace\n\nDataMgr::DataMgr(string format, size_t mem_size, int nthreads)\n{\n    SetDiagMsg(\"DataMgr::DataMgr(%s,%d,%d)\", format.c_str(), nthreads, mem_size);\n\n    _format = format;\n    _nthreads = nthreads;\n    _mem_size = mem_size;\n\n    if (!_mem_size) _mem_size = std::numeric_limits<size_t>::max() / 1048576;\n\n    _dc = NULL;\n\n    _blk_mem_mgr = NULL;\n\n    _PipeLines.clear();\n\n    _regionsList.clear();\n\n    _varInfoCacheSize_T.Clear();\n    _varInfoCacheDouble.Clear();\n    _varInfoCacheVoidPtr.Clear();\n\n    _doTransformHorizontal = false;\n    _doTransformVertical = false;\n    _openVarName.clear();\n    _proj4String.clear();\n    _proj4StringDefault.clear();\n    _bs = {64, 64, 64};\n}\n\nDataMgr::~DataMgr()\n{\n    SetDiagMsg(\"DataMgr::~DataMgr()\");\n\n    if (_dc) delete _dc;\n    _dc = NULL;\n\n    Clear();\n    if (_blk_mem_mgr) delete _blk_mem_mgr;\n\n    _blk_mem_mgr = NULL;\n\n    vector<string> names = _dvm.GetDataVarNames();\n    for (int i = 0; i < names.size(); i++) {\n        if (_dvm.GetVar(names[i])) delete _dvm.GetVar(names[i]);\n    }\n\n    names = _dvm.GetCoordVarNames();\n    for (int i = 0; i < names.size(); i++) {\n        if (_dvm.GetVar(names[i])) delete _dvm.GetVar(names[i]);\n    }\n}\n\nint DataMgr::_parseOptions(vector<string> &options)\n{\n    vector<string> newOptions;\n    bool           ok = true;\n    int            i = 0;\n    while (i < options.size() && ok) {\n        if (options[i] == \"-proj4\") {\n            i++;\n            if (i >= options.size()) {\n                ok = false;\n            } else {\n                _proj4String = options[i];\n            }\n        }\n        if (options[i] == \"-project_to_pcs\") { _doTransformHorizontal = true; }\n        if (options[i] == \"-vertical_xform\") {\n            _doTransformVertical = true;\n        } else {\n            newOptions.push_back(options[i]);\n        }\n        i++;\n    }\n\n    options = newOptions;\n\n    if (!ok) {\n        SetErrMsg(\"Error parsing options\");\n        return (-1);\n    }\n    return (0);\n}\n\n\nint DataMgr::Initialize(const vector<string> &files, const std::vector<string> &options)\n{\n    vector<string> deviceOptions = options;\n    int            rc = _parseOptions(deviceOptions);\n    if (rc < 0) return (-1);\n\n    Clear();\n    if (_dc) delete _dc;\n\n    _dc = NULL;\n    if (files.empty()) {\n        SetErrMsg(\"Empty file list\");\n        return (-1);\n    }\n\n    if (_format.compare(\"vdc\") == 0) {\n        _dc = new VDCNetCDF(_nthreads);\n    } else if (_format.compare(\"wrf\") == 0) {\n        _dc = new DCWRF();\n    } else if (_format.compare(\"cf\") == 0) {\n        _dc = new DCCF();\n    } else if (_format.compare(\"mpas\") == 0) {\n        _dc = new DCMPAS();\n    } else if (_format.compare(\"bov\") == 0) {\n        _dc = new DCBOV();\n    } else if (_format.compare(\"dcp\") == 0) {\n        _dc = new DCP();\n    } else if (_format.compare(\"ram\") == 0) {\n        _dc = new DCRAM();\n    } else if (_format.compare(\"ugrid\") == 0) {\n        _dc = new DCUGRID();\n#ifdef BUILD_DC_MELANIE\n    } else if (_format.compare(\"melanie\") == 0) {\n        _dc = new DCMelanie();\n#endif\n    } else {\n        SetErrMsg(\"Invalid data collection format : %s\", _format.c_str());\n        return (-1);\n    }\n\n    rc = _dc->Initialize(files, deviceOptions);\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize data importer\");\n        return (-1);\n    }\n\n    // Use UDUnits for unit conversion\n    //\n    rc = _udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", _udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n    rc = _initHorizontalCoordVars();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize horizontal coordinates\");\n        return (-1);\n    }\n\n    rc = _initVerticalCoordVars();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize vertical coordinates\");\n        return (-1);\n    }\n\n    rc = _initTimeCoord();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to get time coordinates\");\n        return (-1);\n    }\n\n#if DCP_ENABLE_PARTICLE_DENSITY\n    //! Generates a regular 3D mesh for use in creating a particle density field.\n    //! See more documentation in DCP.h\n    if (_format == \"dcp\") {\n        vector<string> dims = {\"densityX\", \"densityY\", \"densityZ\"};\n\n        CoordType min, max;\n        GetVariableExtents(0, \"Position_x\", -1, -1, min, max);\n\n        DerivedCoordVar1DSpan *XC = new DerivedCoordVar1DSpan(\"XC\", _dc, dims[0], 0, \"\", \"Position_x\");\n        DerivedCoordVar1DSpan *YC = new DerivedCoordVar1DSpan(\"YC\", _dc, dims[1], 1, \"\", \"Position_y\");\n        DerivedCoordVar1DSpan *ZC = new DerivedCoordVar1DSpan(\"ZC\", _dc, dims[2], 2, \"\", \"Position_z\");\n        XC->Initialize();\n        YC->Initialize();\n        ZC->Initialize();\n        _dvm.AddCoordVar(XC);\n        _dvm.AddCoordVar(YC);\n        _dvm.AddCoordVar(ZC);\n\n        DC::Mesh mesh(\"density\", dims, {XC->GetName(), YC->GetName(), ZC->GetName()});\n        _dvm.AddMesh(mesh);\n\n        DerivedParticleDensity *dpd = new DerivedParticleDensity(\"Particle_Density\", _dc, mesh.GetName(), this);\n        dpd->Initialize();\n        AddDerivedVar(dpd);\n\n        auto dataVars = GetDataVarNames(3);\n        for (auto var : dataVars) {\n            DerivedParticleAverage *dpa = new DerivedParticleAverage(var + \"_avg\", _dc, mesh.GetName(), this, var);\n            dpa->Initialize();\n            AddDerivedVar(dpa);\n        }\n    }\n#endif\n\n    return (0);\n}\n\nbool DataMgr::GetMesh(string meshname, DC::Mesh &m) const\n{\n    VAssert(_dc);\n\n    bool ok = _dvm.GetMesh(meshname, m);\n    if (!ok) { ok = _dc->GetMesh(meshname, m); }\n\n    if (!ok) return (ok);\n\n    // Make sure the number of coordinate variables is greater or\n    // equal to the topological dimension. If not, add default coordinate\n    // variables\n    //\n    vector<string> coord_vars = m.GetCoordVars();\n    while (coord_vars.size() < m.GetTopologyDim()) {\n        if (!_hasCoordForAxis(coord_vars, 0)) {\n            coord_vars.insert(coord_vars.begin() + 0, _defaultCoordVar(m, 0));\n            continue;\n        } else if (!_hasCoordForAxis(coord_vars, 1)) {\n            coord_vars.insert(coord_vars.begin() + 1, _defaultCoordVar(m, 1));\n            continue;\n        } else {\n            coord_vars.insert(coord_vars.begin() + 2, _defaultCoordVar(m, 2));\n            continue;\n        }\n    }\n\n    // if requested, replace native horizontal geographic coordiate variables\n    // with derived PCS coordinate variables\n    //\n    if (_doTransformHorizontal) { _assignHorizontalCoords(coord_vars); }\n\n    m.SetCoordVars(coord_vars);\n\n    return (true);\n}\n\nvector<string> DataMgr::GetDataVarNames() const\n{\n    VAssert(_dc);\n\n    vector<string> validvars;\n    for (int ndim = 2; ndim <= 3; ndim++) {\n        vector<string> vars = GetDataVarNames(ndim);\n        validvars.insert(validvars.end(), vars.begin(), vars.end());\n    }\n    return (validvars);\n}\n\nvector<string> DataMgr::GetDataVarNames(int ndim, VarType type) const\n{\n    VAssert(_dc);\n\n    if (_dataVarNamesCache[std::make_pair(type, ndim)].size()) { return (_dataVarNamesCache[std::make_pair(type, ndim)]); }\n\n    vector<string> vars = _dc->GetDataVarNames(ndim);\n    vector<string> derived_vars = _getDataVarNamesDerived(ndim);\n    vars.insert(vars.end(), derived_vars.begin(), derived_vars.end());\n\n    vector<string> validVars;\n    for (int i = 0; i < vars.size(); i++) {\n        // If we don't have a grid class to support this variable reject it\n        //\n        if (_get_grid_type(vars[i]).empty()) continue;\n\n        vector<string> coordvars;\n        GetVarCoordVars(vars[i], true, coordvars);\n        if (coordvars.size() < ndim) continue;\n\n        if (type == VarType::Scalar && GetVarTopologyDim(vars[i]) == 0) continue;\n        if (type == VarType::Particle && GetVarTopologyDim(vars[i]) != 0) continue;\n\n        validVars.push_back(vars[i]);\n    }\n\n    _dataVarNamesCache[std::make_pair(type, ndim)] = validVars;\n    return (validVars);\n}\n\nvector<string> DataMgr::GetCoordVarNames() const\n{\n    VAssert(_dc);\n\n    vector<string> vars = _dc->GetCoordVarNames();\n    vector<string> derived_vars = _dvm.GetCoordVarNames();\n    vars.insert(vars.end(), derived_vars.begin(), derived_vars.end());\n\n    return (vars);\n}\n\nstring DataMgr::GetTimeCoordVarName() const\n{\n    VAssert(_dc);\n\n    // There can be only one time coordinate variable. If a\n    // derived one exists, use it.\n    //\n    vector<string> cvars = _dvm.GetTimeCoordVarNames();\n    if (!cvars.empty()) return (cvars[0]);\n\n    cvars = _dc->GetTimeCoordVarNames();\n    if (!cvars.empty()) return (cvars[0]);\n\n    return (\"\");\n}\n\nbool DataMgr::HasTimeVaryingCoordinates() const\n{\n    const auto time = GetTimeCoordVarName();\n    for (const auto &v : GetCoordVarNames()) {\n        if (v == time) continue;\n        if (IsTimeVarying(v)) return true;\n    }\n    return false;\n}\n\nbool DataMgr::HasMovingDomain() const\n{\n    return HasTimeVaryingCoordinates();\n}\n\nbool DataMgr::GetVarCoordVars(string varname, bool spatial, std::vector<string> &coord_vars) const\n{\n    VAssert(_dc);\n\n    coord_vars.clear();\n\n    DC::DataVar dvar;\n    bool        status = GetDataVarInfo(varname, dvar);\n    if (!status) return (false);\n\n    DC::Mesh m;\n    status = GetMesh(dvar.GetMeshName(), m);\n    if (!status) return (false);\n\n    coord_vars = m.GetCoordVars();\n\n    if (spatial) return (true);\n\n    if (!dvar.GetTimeCoordVar().empty()) { coord_vars.push_back(dvar.GetTimeCoordVar()); }\n\n    return (true);\n}\n\nvector<string> DataMgr::GetVarCoordVars(string varname, bool spatial) const\n{\n    vector<string> v;\n    GetVarCoordVars(varname, spatial, v);\n    return v;\n}\n\nbool DataMgr::GetDataVarInfo(string varname, VAPoR::DC::DataVar &var) const\n{\n    VAssert(_dc);\n\n    bool ok = _dvm.GetDataVarInfo(varname, var);\n    if (!ok) { ok = _dc->GetDataVarInfo(varname, var); }\n    if (!ok) return (ok);\n\n    return (true);\n}\n\nbool DataMgr::GetCoordVarInfo(string varname, VAPoR::DC::CoordVar &var) const\n{\n    VAssert(_dc);\n\n    bool ok = _dvm.GetCoordVarInfo(varname, var);\n    if (!ok) { ok = _dc->GetCoordVarInfo(varname, var); }\n    return (ok);\n}\n\nbool DataMgr::GetBaseVarInfo(string varname, VAPoR::DC::BaseVar &var) const\n{\n    VAssert(_dc);\n\n    bool ok = _dvm.GetBaseVarInfo(varname, var);\n    if (!ok) { ok = _dc->GetBaseVarInfo(varname, var); }\n    return (ok);\n}\n\nbool DataMgr::IsTimeVarying(string varname) const\n{\n    VAssert(_dc);\n\n    // If var is a data variable and has a time coordinate variable defined\n    //\n    DC::DataVar dvar;\n    bool        ok = GetDataVarInfo(varname, dvar);\n    if (ok) return (!dvar.GetTimeCoordVar().empty());\n\n    // If var is a coordinate variable and it has a time dimension\n    //\n    DC::CoordVar cvar;\n    ok = GetCoordVarInfo(varname, cvar);\n    if (ok) return (!cvar.GetTimeDimName().empty());\n\n    return (false);\n}\n\nbool DataMgr::IsCompressed(string varname) const\n{\n    VAssert(_dc);\n\n    DC::BaseVar var;\n\n    // No error checking here!!!!!\n    //\n    bool status = GetBaseVarInfo(varname, var);\n    if (!status) return (status);\n\n    return (var.IsCompressed());\n}\n\nint DataMgr::GetNumTimeSteps(string varname) const\n{\n    VAssert(_dc);\n\n    // If data variable get it's time coordinate variable if it exists\n    //\n    if (_isDataVar(varname)) {\n        DC::DataVar var;\n        bool        ok = GetDataVarInfo(varname, var);\n        if (!ok) return (0);\n\n        string time_coord_var = var.GetTimeCoordVar();\n        if (time_coord_var.empty()) return (1);\n        varname = time_coord_var;\n    }\n\n    DC::CoordVar var;\n    bool         ok = GetCoordVarInfo(varname, var);\n    if (!ok) return (0);\n\n    string time_dim_name = var.GetTimeDimName();\n    if (time_dim_name.empty()) return (1);\n\n    DC::Dimension dim;\n    ok = GetDimension(time_dim_name, dim, 0);\n    if (!ok) return (0);\n\n    return (dim.GetLength());\n}\n\nint DataMgr::GetNumTimeSteps() const { return (_timeCoordinates.size()); }\n\nsize_t DataMgr::GetNumRefLevels(string varname) const\n{\n    VAssert(_dc);\n\n    if (varname == \"\") return 1;\n\n    DerivedVar *dvar = _getDerivedVar(varname);\n    if (dvar) { return (dvar->GetNumRefLevels()); }\n\n    return (_dc->GetNumRefLevels(varname));\n}\n\nvector<size_t> DataMgr::GetCRatios(string varname) const\n{\n    VAssert(_dc);\n\n    if (varname == \"\") return vector<size_t>(1, 1);\n\n    DerivedVar *dvar = _getDerivedVar(varname);\n    if (dvar) { return (dvar->GetCRatios()); }\n\n    return (_dc->GetCRatios(varname));\n}\n\nGrid *DataMgr::GetVariable(size_t ts, string varname, int level, int lod, bool lock)\n{\n    SetDiagMsg(\"DataMgr::GetVariable(%d,%s,%d,%d,%d, %d)\", ts, varname.c_str(), level, lod, lock);\n\n    int rc = _level_correction(varname, level);\n    if (rc < 0) return (NULL);\n\n    rc = _lod_correction(varname, lod);\n    if (rc < 0) return (NULL);\n\n    Grid *rg = _getVariable(ts, varname, level, lod, lock, false);\n    if (!rg) {\n        SetErrMsg(\"Failed to read variable \\\"%s\\\" at time step (%d), and\\n\"\n                  \"refinement level (%d) and level-of-detail (%d)\",\n                  varname.c_str(), ts, level, lod);\n    }\n    return (rg);\n}\n\nGrid *DataMgr::GetVariable(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, bool lock)\n{\n\n    SetDiagMsg(\"DataMgr::GetVariable(%d, %s, %d, %d, %s, %s, %d)\", ts, varname.c_str(), level, lod, vector_to_string(min).c_str(), vector_to_string(max).c_str(), lock);\n\n    int rc = _level_correction(varname, level);\n    if (rc < 0) return (NULL);\n\n    rc = _lod_correction(varname, lod);\n    if (rc < 0) return (NULL);\n\n    //\n    // Find the coordinates in voxels of the grid that contains\n    // the axis aligned bounding box specified in user coordinates\n    // by min and max\n    //\n    DimsType min_ui, max_ui;\n    rc = _find_bounding_grid(ts, varname, level, lod, min, max, min_ui, max_ui);\n    if (rc < 0) return (NULL);\n\n    if (rc == 1) {\n        SetErrMsg(\"Failed to get requested variable: spatial extents out of range\");\n        return (NULL);\n    }\n\n    return (DataMgr::GetVariable(ts, varname, level, lod, min_ui, max_ui, lock));\n}\n\nGrid *DataMgr::_getVariable(size_t ts, string varname, int level, int lod, bool lock, bool dataless)\n{\n    if (!VariableExists(ts, varname, level, lod)) {\n        SetErrMsg(\"Invalid variable reference : %s\", varname.c_str());\n        return (NULL);\n    }\n\n    vector<size_t> dims_at_level;\n    int            rc = GetDimLensAtLevel(varname, level, dims_at_level, ts);\n    if (rc < 0) {\n        SetErrMsg(\"Invalid variable reference : %s\", varname.c_str());\n        return (NULL);\n    }\n\n    DimsType min = {0, 0, 0};\n    DimsType max = {0, 0, 0};\n    for (int i = 0; i < dims_at_level.size(); i++) {\n        min[i] = (0);\n        max[i] = (dims_at_level[i] - 1);\n    }\n\n    return (DataMgr::_getVariable(ts, varname, level, lod, min, max, lock, dataless));\n}\n\n// Find the subset of the data dimension that are the coord dimensions\n//\nvoid DataMgr::_setupCoordVecsHelper(string data_varname, const DimsType &data_dimlens, const DimsType &data_bmin, const DimsType &data_bmax, string coord_varname, int order, DimsType &coord_dimlens,\n                                    DimsType &coord_bmin, DimsType &coord_bmax, bool structured, long ts) const\n{\n    coord_dimlens = {1, 1, 1};\n    coord_bmin = {0, 0, 0};\n    coord_bmax = {0, 0, 0};\n\n    vector<DC::Dimension> data_dims;\n    bool                  ok = _getVarDimensions(data_varname, data_dims, ts);\n    VAssert(ok);\n\n    vector<DC::Dimension> coord_dims;\n    ok = _getVarDimensions(coord_varname, coord_dims, ts);\n    VAssert(ok);\n\n    if (structured) {\n        // For structured data\n        // Here we try to match dimensions of coordinate variables\n        // with dimensions of data variables. Ideally, this would be done\n        // by matching the dimension names. However, some CF data sets (e.g. MOM)\n        // have data and coordinate variables that use different dimension\n        // names (but have the same length)\n        //\n        if (data_dims.size() == 1) {\n            VAssert(coord_dims.size() == 1);\n            VAssert(order == 0);\n\n            coord_dimlens[0] = (data_dimlens[0]);\n            coord_bmin[0] = (data_bmin[0]);\n            coord_bmax[0] = (data_bmax[0]);\n        } else if (data_dims.size() == 2) {\n            VAssert(order >= 0 && order <= 1);\n\n            if (coord_dims.size() == 1) {\n                coord_dimlens[0] = (data_dimlens[order]);\n                coord_bmin[0] = (data_bmin[order]);\n                coord_bmax[0] = (data_bmax[order]);\n            } else {\n                coord_dimlens[0] = (data_dimlens[0]);\n                coord_bmin[0] = (data_bmin[0]);\n                coord_bmax[0] = (data_bmax[0]);\n\n                coord_dimlens[1] = (data_dimlens[1]);\n                coord_bmin[1] = (data_bmin[1]);\n                coord_bmax[1] = (data_bmax[1]);\n            }\n        } else if (data_dims.size() == 3) {\n            VAssert(order >= 0 && order <= 2);\n\n            if (coord_dims.size() == 1) {\n                coord_dimlens[0] = (data_dimlens[order]);\n                coord_bmin[0] = (data_bmin[order]);\n                coord_bmax[0] = (data_bmax[order]);\n            } else if (coord_dims.size() == 2) {\n                // We assume 2D coordinates are horizontal (in XY plane).\n                // No way currently to distinguish XZ and YZ plane 2D coordinates\n                // for 3D data :-(\n                //\n                VAssert(order >= 0 && order <= 1);\n                coord_dimlens[0] = (data_dimlens[0]);\n                coord_bmin[0] = (data_bmin[0]);\n                coord_bmax[0] = (data_bmax[0]);\n\n                coord_dimlens[1] = (data_dimlens[1]);\n                coord_bmin[1] = (data_bmin[1]);\n                coord_bmax[1] = (data_bmax[1]);\n\n            } else if (coord_dims.size() == 3) {\n                coord_dimlens[0] = (data_dimlens[0]);\n                coord_bmin[0] = (data_bmin[0]);\n                coord_bmax[0] = (data_bmax[0]);\n\n                coord_dimlens[1] = (data_dimlens[1]);\n                coord_bmin[1] = (data_bmin[1]);\n                coord_bmax[1] = (data_bmax[1]);\n\n                coord_dimlens[2] = (data_dimlens[2]);\n                coord_bmin[2] = (data_bmin[2]);\n                coord_bmax[2] = (data_bmax[2]);\n            }\n        } else {\n            VAssert(0 && \"Only 1, 2, or 3D data supported\");\n        }\n\n    } else {\n        // For unstructured data we can just match data dimension names\n        // with coord dimension names. Yay!\n        //\n        int i = 0;\n        for (int j = 0; j < coord_dims.size(); j++) {\n            while (data_dims[i].GetLength() != coord_dims[j].GetLength() && i < data_dims.size()) { i++; }\n            VAssert(i < data_dims.size());\n            coord_dimlens[j] = (data_dimlens[i]);\n            coord_bmin[j] = (data_bmin[i]);\n            coord_bmax[j] = (data_bmax[i]);\n        }\n    }\n}\n\nint DataMgr::_setupCoordVecs(size_t ts, string varname, int level, int lod, const DimsType &min, const DimsType &max, vector<string> &varnames, DimsType &roi_dims, vector<DimsType> &dimsvec,\n                             vector<DimsType> &bsvec, vector<DimsType> &bminvec, vector<DimsType> &bmaxvec, bool structured) const\n{\n    varnames.clear();\n    roi_dims = {1, 1, 1};\n    dimsvec.clear();\n    bsvec.clear();\n    bminvec.clear();\n    bmaxvec.clear();\n\n    // Compute dimenions of ROI\n    //\n    for (int i = 0; i < min.size(); i++) { roi_dims[i] = (max[i] - min[i] + 1); }\n\n    // Grid and block dimensions at requested refinement\n    //\n    vector<size_t> dimsv;\n    int            rc = GetDimLensAtLevel(varname, level, dimsv, ts);\n    VAssert(rc >= 0);\n    DimsType dims = {1, 1, 1};\n    Grid::CopyToArr3(dimsv, dims);\n    dimsvec.push_back(dims);\n\n    DimsType bs = {1, 1, 1};\n    Grid::CopyToArr3(_bs.data(), dimsv.size(), bs);\n    bsvec.push_back(bs);\n\n    // Map voxel coordinates into block coordinates\n    //\n    DimsType bmin, bmax;\n    map_vox_to_blk(bs, min, bmin);\n    map_vox_to_blk(bs, max, bmax);\n    bminvec.push_back(bmin);\n    bmaxvec.push_back(bmax);\n\n    vector<string> cvarnames;\n    bool           ok = GetVarCoordVars(varname, true, cvarnames);\n    VAssert(ok);\n\n    for (int i = 0; i < cvarnames.size(); i++) {\n        // Map data indices to coordinate indices. Coordinate indices\n        // are a subset of the data indices.\n        //\n        DimsType coord_dims, coord_bmin, coord_bmax;\n        _setupCoordVecsHelper(varname, dims, bmin, bmax, cvarnames[i], i, coord_dims, coord_bmin, coord_bmax, structured, ts);\n\n        dimsvec.push_back(coord_dims);\n        bminvec.push_back(coord_bmin);\n        bmaxvec.push_back(coord_bmax);\n\n        DimsType bs = {1, 1, 1};\n        Grid::CopyToArr3(_bs.data(), Grid::GetNumDimensions(coord_dims), bs);\n        bsvec.push_back(bs);\n    }\n\n    varnames.push_back(varname);\n    varnames.insert(varnames.end(), cvarnames.begin(), cvarnames.end());\n\n    return (0);\n}\n\nint DataMgr::_setupConnVecs(size_t ts, string varname, int level, int lod, vector<string> &varnames, vector<DimsType> &dimsvec, vector<DimsType> &bsvec, vector<DimsType> &bminvec,\n                            vector<DimsType> &bmaxvec) const\n{\n    varnames.clear();\n    dimsvec.clear();\n    bsvec.clear();\n    bminvec.clear();\n    bmaxvec.clear();\n\n    string face_node_var;\n    string node_face_var;\n    string face_edge_var;\n    string face_face_var;\n    string edge_node_var;\n    string edge_face_var;\n\n    bool ok = _getVarConnVars(varname, face_node_var, node_face_var, face_edge_var, face_face_var, edge_node_var, edge_face_var);\n    if (!ok) {\n        SetErrMsg(\"Invalid variable reference : %s\", varname.c_str());\n        return (-1);\n    }\n\n    if (!face_node_var.empty()) varnames.push_back(face_node_var);\n    if (!node_face_var.empty()) varnames.push_back(node_face_var);\n    if (!face_edge_var.empty()) varnames.push_back(face_edge_var);\n    if (!face_face_var.empty()) varnames.push_back(face_face_var);\n    if (!edge_node_var.empty()) varnames.push_back(edge_node_var);\n    if (!edge_face_var.empty()) varnames.push_back(edge_face_var);\n\n    for (int i = 0; i < varnames.size(); i++) {\n        string name = varnames[i];\n\n        vector<size_t> dimsv;\n        int            rc = GetDimLensAtLevel(name, level, dimsv, ts);\n        if (rc < 0) {\n            SetErrMsg(\"Invalid variable reference : %s\", name.c_str());\n            return (-1);\n        }\n\n        DimsType dims = {1, 1, 1};\n        Grid::CopyToArr3(dimsv, dims);\n\n        // Ugh. Connection data are not blocked.\n        //\n        DimsType bs = dims;\n\n        // Always read the entire connection variable\n        //\n        DimsType conn_min = {0, 0, 0};\n        DimsType conn_max = {dims[0] - 1, dims[1] - 1, dims[2] - 1};\n\n        // Map voxel coordinates into block coordinates\n        //\n        DimsType bmin, bmax;\n        map_vox_to_blk(bs, conn_min, bmin);\n        map_vox_to_blk(bs, conn_max, bmax);\n\n        dimsvec.push_back(dims);\n        bsvec.push_back(bs);\n        bminvec.push_back(bmin);\n        bmaxvec.push_back(bmax);\n    }\n\n    return (0);\n}\n\nGrid *DataMgr::_getVariable(size_t ts, string varname, int level, int lod, DimsType min, DimsType max, bool lock, bool dataless)\n{\n    Grid *rg = NULL;\n\n    string gridType = _get_grid_type(varname);\n    if (gridType.empty()) {\n        SetErrMsg(\"Unrecognized grid type for variable %s\", varname.c_str());\n        return (NULL);\n    }\n\n    DC::DataVar dvar;\n    bool        status = DataMgr::GetDataVarInfo(varname, dvar);\n    VAssert(status);\n\n    vector<DC::CoordVar> cvarsinfo;\n    DC::CoordVar         dummy;\n    status = _get_coord_vars(varname, cvarsinfo, dummy);\n    VAssert(status);\n\n    vector<string>         varnames;\n    DimsType               roi_dims;\n    vector<DimsType>       dimsvec;\n    vector<DimsType>       bsvec;\n    vector<DimsType>       bminvec;\n    vector<DimsType>       bmaxvec;\n\n    // Get dimensions for coordinate variables\n    //\n    int rc = _setupCoordVecs(ts, varname, level, lod, min, max, varnames, roi_dims, dimsvec, bsvec, bminvec, bmaxvec, !_gridHelper.IsUnstructured(gridType));\n    if (rc < 0) return (NULL);\n\n    //\n    // if dataless we only load coordinate data\n    //\n    if (dataless) varnames[0].clear();\n\n    vector<float *> blkvec;\n    rc = DataMgr::_get_regions<float>(ts, varnames, level, lod, true, dimsvec, bsvec, bminvec, bmaxvec, blkvec);\n    if (rc < 0) return (NULL);\n\n    // Get dimensions for connectivity variables (if any)\n    //\n    vector<string>         conn_varnames;\n    vector<DimsType>       conn_dimsvec;\n    vector<DimsType>       conn_bsvec;\n    vector<DimsType>       conn_bminvec;\n    vector<DimsType>       conn_bmaxvec;\n\n    vector<int *> conn_blkvec;\n    if (_gridHelper.IsUnstructured(gridType)) {\n        rc = _setupConnVecs(ts, varname, level, lod, conn_varnames, conn_dimsvec, conn_bsvec, conn_bminvec, conn_bmaxvec);\n        if (rc < 0) return (NULL);\n\n        rc = DataMgr::_get_regions<int>(ts, conn_varnames, level, lod, true, conn_dimsvec, conn_bsvec, conn_bminvec, conn_bmaxvec, conn_blkvec);\n        if (rc < 0) return (NULL);\n    }\n\n    if (_gridHelper.IsUnstructured(gridType)) {\n        DimsType                   vertexDims;\n        DimsType                   faceDims;\n        DimsType                   edgeDims;\n        UnstructuredGrid::Location location;\n        size_t                     maxVertexPerFace;\n        size_t                     maxFacePerVertex;\n        long                       vertexOffset;\n        long                       faceOffset;\n\n        _ugrid_setup(dvar, vertexDims, faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset, ts);\n\n        rg = _gridHelper.MakeGridUnstructured(gridType, ts, level, lod, dvar, cvarsinfo, roi_dims, dimsvec[0], blkvec, bsvec, bminvec, bmaxvec, conn_blkvec, conn_bsvec, conn_bminvec, conn_bmaxvec,\n                                              vertexDims, faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset);\n    } else {\n        rg = _gridHelper.MakeGridStructured(gridType, ts, level, lod, dvar, cvarsinfo, roi_dims, dimsvec[0], blkvec, bsvec, bminvec, bmaxvec);\n    }\n    VAssert(rg);\n\n    //\n    // Inform the grid of the offsets from the larger mesh to the\n    // mesh subset contained in g. In general, gmin<=min\n    //\n    DimsType gmin, gmax;\n    map_blk_to_vox(bsvec[0], dimsvec[0], bminvec[0], bmaxvec[0], gmin, gmax);\n    rg->SetMinAbs(gmin);\n\n    //\n    // Safe to remove locks now that were not explicitly requested\n    //\n    if (!lock) {\n        for (int i = 0; i < blkvec.size(); i++) {\n            if (blkvec[i]) _unlock_blocks(blkvec[i]);\n        }\n        for (int i = 0; i < conn_blkvec.size(); i++) {\n            if (conn_blkvec[i]) _unlock_blocks(conn_blkvec[i]);\n        }\n    } else {\n        if (blkvec.size()) _lockedFloatBlks[rg] = blkvec;\n        if (conn_blkvec.size()) _lockedIntBlks[rg] = conn_blkvec;\n    }\n\n    return (rg);\n}\n\nGrid *DataMgr::GetVariable(size_t ts, string varname, int level, int lod, DimsType min, DimsType max, bool lock)\n{\n\n    SetDiagMsg(\"DataMgr::GetVariable(%d, %s, %d, %d, %s, %s, %d)\", ts, varname.c_str(), level, lod, vector_to_string(min).c_str(), vector_to_string(max).c_str(), lock);\n\n    int rc = _level_correction(varname, level);\n    if (rc < 0) return (NULL);\n\n    rc = _lod_correction(varname, lod);\n    if (rc < 0) return (NULL);\n\n    // Make sure variable dimensions match extents specification\n    //\n    vector<string> coord_vars;\n    bool           ok = GetVarCoordVars(varname, true, coord_vars);\n    VAssert(ok);\n\n    DimsType min_vec = {0, 0, 0};\n    DimsType max_vec = {0, 0, 0};\n    for (int i = 0; i < coord_vars.size(); i++) {\n        min_vec[i] = (min[i]);\n        max_vec[i] = (max[i]);\n    }\n\n    Grid *rg = _getVariable(ts, varname, level, lod, min_vec, max_vec, lock, false);\n    if (!rg) {\n        SetErrMsg(\"Failed to read variable \\\"%s\\\" at time step (%d), and\\n\"\n                  \"refinement level (%d) and level-of-detail (%d)\",\n                  varname.c_str(), ts, level, lod);\n    }\n    return (rg);\n}\n\nint DataMgr::GetVariableExtents(size_t ts, string varname, int level, int lod, CoordType &min, CoordType &max)\n{\n    SetDiagMsg(\"DataMgr::GetVariableExtents(%d, %s, %d, %d)\", ts, varname.c_str(), level, lod);\n\n    min = {0.0, 0.0, 0.0};\n    max = min;\n\n    int rc = _lod_correction(varname, lod);\n    if (rc < 0) return (-1);\n\n    rc = _level_correction(varname, level);\n    if (rc < 0) return (-1);\n\n    vector<string> cvars;\n    string         dummy;\n    bool           ok = _get_coord_vars(varname, cvars, dummy);\n    if (!ok) return (-1);\n\n    string         key = \"VariableExtents\";\n    vector<double> values;\n    if (_varInfoCacheDouble.Get(ts, cvars, level, lod, key, values)) {\n        int n = values.size();\n        for (int i = 0; i < n / 2; i++) {\n            min[i] = values[i];\n            max[i] = values[i + (n / 2)];\n        }\n        return (0);\n    }\n\n    Grid *rg = _getVariable(ts, varname, level, lod, false, true);\n    if (!rg) return (-1);\n\n    rg->GetUserExtents(min, max);\n\n    // Cache results\n    //\n    values.clear();\n    for (int i = 0; i < min.size(); i++) values.push_back(min[i]);\n    for (int i = 0; i < max.size(); i++) values.push_back(max[i]);\n    _varInfoCacheDouble.Set(ts, cvars, level, lod, key, values);\n\n    return (0);\n}\n\nint DataMgr::GetDataRange(size_t ts, string varname, int level, int lod, vector<double> &range)\n{\n    SetDiagMsg(\"DataMgr::GetDataRange(%d,%s)\", ts, varname.c_str());\n\n    CoordType      min, max;\n    int            rc = GetVariableExtents(ts, varname, level, lod, min, max);\n    if (rc < 0) return (-1);\n\n    return (GetDataRange(ts, varname, level, lod, min, max, range));\n}\n\nint DataMgr::GetDataRange(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, vector<double> &range)\n{\n    SetDiagMsg(\"DataMgr::GetDataRange(%d,%s)\", ts, varname.c_str());\n\n    range = {0.0, 0.0};\n\n    int rc = _level_correction(varname, level);\n    if (rc < 0) return (-1);\n\n    rc = _lod_correction(varname, lod);\n    if (rc < 0) return (-1);\n\n    //\n    // Find the coordinates in voxels of the grid that contains\n    // the axis aligned bounding box specified in user coordinates\n    // by min and max\n    //\n    DimsType min_ui, max_ui;\n    rc = _find_bounding_grid(ts, varname, level, lod, min, max, min_ui, max_ui);\n    if (rc != 0) return (-1);\n\n    // See if we've already cache'd it.\n    //\n    ostringstream oss;\n    oss << \"VariableRange\";\n    oss << vector_to_string(min_ui);\n    oss << vector_to_string(max_ui);\n    string key = oss.str();\n\n    if (_varInfoCacheDouble.Get(ts, varname, level, lod, key, range)) {\n        VAssert(range.size() == 2);\n        return (0);\n    }\n\n    const Grid *sg = DataMgr::GetVariable(ts, varname, level, lod, min_ui, max_ui, false);\n    if (!sg) return (-1);\n\n    float range_f[2];\n    sg->GetRange(range_f);\n    range = {range_f[0], range_f[1]};\n\n    delete sg;\n\n    _varInfoCacheDouble.Set(ts, varname, level, lod, key, range);\n\n    return (0);\n}\n\nint DataMgr::GetDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const\n{\n    VAssert(_dc);\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    int         rc = 0;\n    DerivedVar *dvar = _getDerivedVar(varname);\n    if (dvar) {\n        rc = dvar->GetDimLensAtLevel(level, dims_at_level, bs_at_level);\n    } else {\n        rc = _dc->GetDimLensAtLevel(varname, level, dims_at_level, bs_at_level, ts);\n    }\n    if (rc < 0) return (-1);\n\n\n    return (0);\n}\n\nvector<string> DataMgr::_get_var_dependencies_1(string varname) const\n{\n    vector<string> varnames;\n\n    DerivedVar *derivedVar = _getDerivedVar(varname);\n    if (derivedVar) { varnames = derivedVar->GetInputs(); }\n\n    // No more dependencies if not a data variable\n    //\n    if (!_isDataVar(varname)) return (varnames);\n\n    vector<string> cvars;\n    bool           ok = GetVarCoordVars(varname, false, cvars);\n    if (ok) {\n        for (int i = 0; i < cvars.size(); i++) varnames.push_back(cvars[i]);\n    }\n\n    // Test for connectivity variables, if any\n    //\n    string face_node_var;\n    string node_face_var;\n    string face_edge_var;\n    string face_face_var;\n    string edge_node_var;\n    string edge_face_var;\n    ok = _getVarConnVars(varname, face_node_var, node_face_var, face_edge_var, face_face_var, edge_node_var, edge_face_var);\n    if (ok) {\n        if (!face_node_var.empty()) varnames.push_back(face_node_var);\n        if (!node_face_var.empty()) varnames.push_back(node_face_var);\n        if (!face_edge_var.empty()) varnames.push_back(face_edge_var);\n        if (!face_face_var.empty()) varnames.push_back(face_face_var);\n        if (!edge_node_var.empty()) varnames.push_back(edge_node_var);\n        if (!edge_face_var.empty()) varnames.push_back(edge_face_var);\n    }\n\n    sort(varnames.begin(), varnames.end());\n    varnames.erase(unique(varnames.begin(), varnames.end()), varnames.end());\n    return (varnames);\n}\n\nvector<string> DataMgr::_get_var_dependencies_all(vector<string> varnames, vector<string> dependencies) const\n{\n    // Recursively look for all of a variable's dependencies, handing any\n    // cycles in the dependency graph\n    //\n    vector<string> new_varnames;\n    for (int i = 0; i < varnames.size(); i++) {\n        vector<string> new_dependencies = _get_var_dependencies_1(varnames[i]);\n\n        for (int j = 0; j < new_dependencies.size(); j++) {\n            // Avoid cycles by not adding variable names that are already\n            // in the dependencies vector\n            //\n            if (!contains(dependencies, new_dependencies[j])) {\n                dependencies.push_back(new_dependencies[j]);\n                new_varnames.push_back(new_dependencies[j]);\n            }\n        }\n    }\n\n    if (new_varnames.size()) { return (_get_var_dependencies_all(new_varnames, dependencies)); }\n    return (dependencies);\n}\n\nbool DataMgr::VariableExists(size_t ts, string varname, int level, int lod) const\n{\n    if (varname.empty()) return (false);\n\n    // disable error reporting\n    //\n    bool enabled = EnableErrMsg(false);\n    int  rc = _level_correction(varname, level);\n    if (rc < 0) {\n        EnableErrMsg(enabled);\n        return (false);\n    }\n\n    rc = _lod_correction(varname, lod);\n    if (rc < 0) {\n        EnableErrMsg(enabled);\n        return (false);\n    }\n    EnableErrMsg(enabled);\n\n    string         key = \"VariableExists\";\n    vector<size_t> found;\n    if (_varInfoCacheSize_T.Get(ts, varname, level, lod, key, found)) { return (found[0]); }\n\n    //\n    // Recursively find all variable dependencies needed by this\n    // varible. E.g. coordinate variables, input for derived variables,\n    // auxillary variables\n    //\n    vector<string> varnames = _get_var_dependencies_all(vector<string>({varname}), vector<string>());\n    varnames.insert(varnames.begin(), varname);\n\n    // Now check for the existence of the variable and all of its\n    // dependencies, updating variable existence cache in process\n    //\n    for (int i = 0; i < varnames.size(); i++) {\n        if (_varInfoCacheSize_T.Get(ts, varnames[i], level, lod, key, found)) {\n            if (found[0])\n                continue;\n            else\n                return (false);\n        }\n\n        if (DataMgr::IsVariableNative(varnames[i])) {\n            bool exists = _dc->VariableExists(ts, varnames[i], level, lod);\n            if (!exists) {\n                _varInfoCacheSize_T.Set(ts, varnames[i], level, lod, key, vector<size_t>({0}));\n                return (false);\n            }\n        } else {\n            DerivedVar *derivedVar = _getDerivedVar(varnames[i]);\n            if (!derivedVar) {\n                _varInfoCacheSize_T.Set(ts, varnames[i], level, lod, key, vector<size_t>({0}));\n                return (false);\n            }\n        }\n    }\n\n    // Cache found results for later.\n    //\n    for (int i = 0; i < varnames.size(); i++) { _varInfoCacheSize_T.Set(ts, varnames[i], level, lod, key, vector<size_t>({1})); }\n    return (true);\n}\n\nbool DataMgr::IsVariableNative(string name) const\n{\n    vector<string> svec = _get_native_variables();\n\n    for (int i = 0; i < svec.size(); i++) {\n        if (name.compare(svec[i]) == 0) return (true);\n    }\n    return (false);\n}\n\nbool DataMgr::IsVariableDerived(string name) const { return (_getDerivedVar(name) != NULL); }\n\nint DataMgr::AddDerivedVar(DerivedDataVar *derivedVar)\n{\n    string varname = derivedVar->GetName();\n\n    if (_dvm.HasVar(varname)) {\n        SetErrMsg(\"Variable named %s already defined\", varname.c_str());\n        return (-1);\n    }\n    _dvm.AddDataVar(derivedVar);\n\n    //\n    // Clear variable name cache\n    //\n    for (auto itr = _dataVarNamesCache.begin(); itr != _dataVarNamesCache.end(); ++itr) {\n        vector<string> &ref = itr->second;\n        ref.clear();\n    }\n\n    _varInfoCacheSize_T.Purge(vector<string>({varname}));\n\n    return (0);\n}\n\nvoid DataMgr::RemoveDerivedVar(string varname)\n{\n    if (!_dvm.HasVar(varname)) return;\n\n    _dvm.RemoveVar(_dvm.GetVar(varname));\n\n    _free_var(varname);\n\n    //\n    // Clear variable name cache\n    //\n    for (auto itr = _dataVarNamesCache.begin(); itr != _dataVarNamesCache.end(); ++itr) {\n        vector<string> &ref = itr->second;\n        ref.clear();\n    }\n\n    _varInfoCacheSize_T.Purge(vector<string>({varname}));\n}\n\nvoid DataMgr::Clear()\n{\n    _PipeLines.clear();\n\n    list<region_t>::iterator itr;\n    for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) {\n        const region_t &region = *itr;\n\n        if (region.blks) _blk_mem_mgr->FreeMem(region.blks);\n    }\n    _regionsList.clear();\n}\n\nvoid DataMgr::UnlockGrid(const Grid *rg)\n{\n    SetDiagMsg(\"DataMgr::UnlockGrid()\");\n\n    const auto fb = _lockedFloatBlks.find(rg);\n    if (fb != _lockedFloatBlks.end()) {\n        auto &bvec = fb->second;\n        for (auto b : bvec) { _unlock_blocks(b); }\n        _lockedFloatBlks.erase(fb);\n    }\n\n    const auto ib = _lockedIntBlks.find(rg);\n    if (ib != _lockedIntBlks.end()) {\n        auto &bvec = ib->second;\n        for (auto b : bvec) { _unlock_blocks(b); }\n        _lockedIntBlks.erase(ib);\n    }\n}\n\nsize_t DataMgr::GetNumDimensions(string varname) const\n{\n    VAssert(_dc);\n\n    vector<size_t> dims, dummy;\n    bool           enabled = EnableErrMsg(false);\n    int            rc = GetDimLensAtLevel(varname, 0, dims, dummy, 0);\n    EnableErrMsg(enabled);\n\n    if (rc < 0) return (0);\n\n    return (dims.size());\n}\n\nsize_t DataMgr::GetVarTopologyDim(string varname) const\n{\n    VAssert(_dc);\n\n    DC::DataVar var;\n    bool        status = GetDataVarInfo(varname, var);\n    if (!status) return (0);\n\n    string mname = var.GetMeshName();\n\n    DC::Mesh mesh;\n    status = GetMesh(mname, mesh);\n    if (!status) return (0);\n\n    return (mesh.GetTopologyDim());\n}\n\nsize_t DataMgr::GetVarGeometryDim(string varname) const\n{\n    VAssert(_dc);\n\n    DC::DataVar var;\n    bool        status = GetDataVarInfo(varname, var);\n    if (!status) return (0);\n\n    string mname = var.GetMeshName();\n\n    DC::Mesh mesh;\n    status = GetMesh(mname, mesh);\n    if (!status) return (0);\n\n    return (mesh.GetGeometryDim());\n}\n\ntemplate<typename T> T *DataMgr::_get_region_from_cache(size_t ts, string varname, int level, int lod, const DimsType &bmin, const DimsType &bmax, bool lock)\n{\n    list<region_t>::iterator itr;\n    for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) {\n        region_t &region = *itr;\n\n        if (region.ts == ts && region.varname.compare(varname) == 0 && region.level == level && region.lod == lod && region.bmin == bmin && region.bmax == bmax) {\n            // Increment the lock counter\n            region.lock_counter += lock ? 1 : 0;\n\n            // Move region to front of list\n            region_t tmp_region = region;\n            _regionsList.erase(itr);\n            _regionsList.push_back(tmp_region);\n\n            SetDiagMsg(\"DataMgr::_get_region_from_cache() - data in cache %xll\\n\", tmp_region.blks);\n            return ((T *)tmp_region.blks);\n        }\n    }\n\n    return (NULL);\n}\n\ntemplate<typename T>\nint DataMgr::_get_unblocked_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_min, const DimsType &grid_max,\n                                           T *blks)\n{\n    int fd = _openVariableRead(ts, varname, level, lod);\n    if (fd < 0) return (fd);\n\n    T *region = new T[vproduct(box_dims(grid_min, grid_max))];\n\n    int nlevels = DataMgr::GetNumRefLevels(varname);\n\n    // Rank of array describing variable\n    //\n    size_t ndims = GetNumDimensions(varname);\n\n    // Downsample the data if needed\n    //\n    if (level < -nlevels) {\n        vector<size_t> dimsv;\n        int            rc = GetDimLensAtLevel(varname, level, dimsv, ts);\n\n        DimsType dims = {1, 1, 1};\n        Grid::CopyToArr3(dimsv, dims);\n\n        // grid_min and grid_max are specified in voxel coordinates\n        // relative to the downsampled grid. Figure out coordinates for\n        // region we need on the native grid\n        //\n        DimsType file_min, file_max;\n        for (int i = 0; i < dims.size(); i++) {\n            VAssert(dims[i] > 0);\n            vector<float> weights;\n            downsample_compute_weights(dims[i], grid_dims[i], weights);\n            int loffset = (int)weights[0];\n            int roffset = (dims[i] - 1) - (int)(weights[weights.size() - 1] + 1.0);\n            file_min[i] = ((int)weights[grid_min[i]] - loffset);\n            file_max[i] = ((int)weights[grid_max[i]] + 1 + roffset);\n        }\n\n        T *buf = new T[vproduct(box_dims(file_min, file_max))];\n\n        rc = _readRegion(fd, file_min, file_max, ndims, buf);\n        if (rc < 0) {\n            delete[] buf;\n            return (-1);\n        }\n\n        downsample(buf, box_dims(file_min, file_max), region, box_dims(grid_min, grid_max));\n\n        if (buf) delete[] buf;\n    } else {\n        int rc = _readRegion(fd, grid_min, grid_max, ndims, region);\n        if (rc < 0) {\n            if (region) delete[] region;\n            _closeVariable(fd);\n            return (-1);\n        }\n    }\n\n    copy_block(region, blks, grid_min, grid_max, grid_bs, grid_min, grid_max);\n\n    (void)_closeVariable(fd);\n\n    if (region) delete[] region;\n\n    return (0);\n}\n\ntemplate<typename T>\nint DataMgr::_get_blocked_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &file_bs, const DimsType &file_dims, const DimsType &grid_dims, const DimsType &grid_bs,\n                                         const DimsType &grid_min, const DimsType &grid_max, T *blks)\n{\n    // Map requested region voxel coordinates to disk block coordinates\n    //\n    DimsType file_bmin, file_bmax;\n    map_vox_to_blk(file_bs, grid_min, file_bmin);\n    map_vox_to_blk(file_bs, grid_max, file_bmax);\n\n    int fd = _openVariableRead(ts, varname, level, lod);\n    if (fd < 0) return (fd);\n\n    DimsType bmin = file_bmin;\n    DimsType bmax = file_bmax;\n\n    // For 3D data read 2D slabs one at a time. This just reduces\n    // memory requirements for the temporary buffer we need\n    //\n    size_t nreads = 1;\n    if (bmax[2] > bmin[2]) {\n        nreads = bmax[2] - bmin[2] + 1;\n        bmax[2] = bmin[2];\n    }\n\n    DimsType file_min, file_max;\n    map_blk_to_vox(file_bs, bmin, bmax, file_min, file_max);\n    T *file_block = new T[vproduct(box_dims(file_min, file_max))];\n\n    size_t ndims = GetNumDimensions(varname);\n\n    for (size_t i = 0; i < nreads; i++) {\n        map_blk_to_vox(file_bs, file_dims, bmin, bmax, file_min, file_max);\n\n        int rc = _readRegion(fd, file_min, file_max, ndims, file_block);\n        if (rc < 0) {\n            delete[] file_block;\n            return (-1);\n        }\n\n        copy_block(file_block, blks, file_min, file_max, grid_bs, grid_min, grid_max);\n\n        // Increment along slowest axis (2)\n        // This is a no-op if less than 3 dimensions\n        //\n        IncrementCoords(file_bmin.data(), file_bmax.data(), bmin.data(), bmin.size(), 2);\n        IncrementCoords(file_bmin.data(), file_bmax.data(), bmax.data(), bmin.size(), 2);\n    }\n\n    (void)_closeVariable(fd);\n\n    if (file_block) delete[] file_block;\n\n    return (0);\n}\n\ntemplate<typename T>\nT *DataMgr::_get_region_from_fs(size_t ts, string varname, int level, int lod, const DimsType &grid_dims, const DimsType &grid_bs, const DimsType &grid_bmin, const DimsType &grid_bmax, bool lock)\n{\n    T *blks = (T *)_alloc_region(ts, varname, level, lod, grid_bmin, grid_bmax, grid_bs, sizeof(T), lock, false);\n    if (!blks) return (NULL);\n\n    vector<size_t> file_dimsv, file_bsv;\n    int            rc = GetDimLensAtLevel(varname, level, file_dimsv, file_bsv, ts);\n    VAssert(rc >= 0);\n\n    DimsType file_dims = {1, 1, 1};\n    Grid::CopyToArr3(file_dimsv, file_dims);\n    DimsType file_bs = {1, 1, 1};\n    Grid::CopyToArr3(file_bsv, file_bs);\n\n    // Get voxel coordinates of requested region, clamped to grid\n    // boundaries.\n    //\n    DimsType grid_min, grid_max;\n    map_blk_to_vox(grid_bs, grid_dims, grid_bmin, grid_bmax, grid_min, grid_max);\n\n    int nlevels = DataMgr::GetNumRefLevels(varname);\n\n    // If data aren't blocked on disk or if the requested level is not\n    // available do a non-blocked read\n    //\n    if (!is_blocked(file_bs) || level < -nlevels) {\n        rc = _get_unblocked_region_from_fs(ts, varname, level, lod, grid_dims, grid_bs, grid_min, grid_max, blks);\n    } else {\n        rc = _get_blocked_region_from_fs(ts, varname, level, lod, file_bs, file_dims, grid_dims, grid_bs, grid_min, grid_max, blks);\n    }\n    if (rc < 0) {\n        _free_region(ts, varname, level, lod, grid_bmin, grid_bmax, true);\n        return (NULL);\n    }\n\n    SetDiagMsg(\"DataMgr::GetGrid() - data read from fs\\n\");\n    return (blks);\n}\n\ntemplate<typename T> T *DataMgr::_get_region(size_t ts, string varname, int level, int lod, int nlods, const DimsType &dims, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, bool lock)\n{\n    if (lod < -nlods) lod = -nlods;\n\n    // See if region is already in cache. If not, read from the\n    // file system.\n    //\n    T *blks = _get_region_from_cache<T>(ts, varname, level, lod, bmin, bmax, lock);\n    if (!blks) { blks = (T *)_get_region_from_fs<T>(ts, varname, level, lod, dims, bs, bmin, bmax, lock); }\n    if (!blks) {\n        SetErrMsg(\"Failed to read region from variable/timestep/level/lod (%s, %d, %d, %d)\", varname.c_str(), ts, level, lod);\n        return (NULL);\n    }\n    return (blks);\n}\n\ntemplate<typename T>\nint DataMgr::_get_regions(size_t ts, const vector<string> &varnames, int level, int lod, bool lock, const vector<DimsType> &dimsvec,\n                          const vector<DimsType> &bsvec,    // native coordinates\n                          const vector<DimsType> &bminvec, const vector<DimsType> &bmaxvec, vector<T *> &blkvec)\n{\n    blkvec.clear();\n\n    for (int i = 0; i < varnames.size(); i++) {\n        if (varnames[i].empty()) {    // nothing to do\n            blkvec.push_back(NULL);\n            continue;\n        }\n\n        DC::BaseVar var;\n        int         rc = GetBaseVarInfo(varnames[i], var);\n        if (rc < 0) return (rc);\n\n        int nlods = var.GetCRatios().size();\n\n        size_t my_ts = ts;\n\n        // If variable isn't time varying time step should always be 0\n        //\n        if (!DataMgr::IsTimeVarying(varnames[i])) my_ts = 0;\n\n        T *blks = _get_region<T>(my_ts, varnames[i], level, lod, nlods, dimsvec[i], bsvec[i], bminvec[i], bmaxvec[i], true);\n        if (!blks) {\n            for (int i = 0; i < blkvec.size(); i++) {\n                if (blkvec[i]) _unlock_blocks(blkvec[i]);\n            }\n            return (-1);\n        }\n        blkvec.push_back(blks);\n    }\n\n    //\n    // Safe to remove locks now that were not explicitly requested\n    //\n    if (!lock) {\n        for (int i = 0; i < blkvec.size(); i++) {\n            if (blkvec[i]) _unlock_blocks(blkvec[i]);\n        }\n    }\n    return (0);\n}\n\nvoid *DataMgr::_alloc_region(size_t ts, string varname, int level, int lod, DimsType bmin, DimsType bmax, DimsType bs, int element_sz, bool lock, bool fill)\n{\n    size_t mem_block_size;\n    if (!_blk_mem_mgr) {\n        mem_block_size = 1024 * 1024;\n\n        size_t num_blks = (_mem_size * 1024 * 1024) / mem_block_size;\n\n        BlkMemMgr::RequestMemSize(mem_block_size, num_blks);\n        _blk_mem_mgr = new BlkMemMgr();\n    }\n    mem_block_size = BlkMemMgr::GetBlkSize();\n\n    // Free region already exists\n    //\n    _free_region(ts, varname, level, lod, bmin, bmax, true);\n\n    size_t size = element_sz;\n    for (int i = 0; i < bmin.size(); i++) { size *= (bmax[i] - bmin[i] + 1) * bs[i]; }\n\n    size_t nblocks = (size_t)ceil((double)size / (double)mem_block_size);\n\n    void *blks;\n    while (!(blks = (void *)_blk_mem_mgr->Alloc(nblocks, fill))) {\n        if (!_free_lru()) {\n            SetErrMsg(\"Failed to allocate requested memory\");\n            return (NULL);\n        }\n    }\n\n    region_t region;\n\n    region.ts = ts;\n    region.varname = varname;\n    region.level = level;\n    region.lod = lod;\n    region.bmin = bmin;\n    region.bmax = bmax;\n    region.lock_counter = lock ? 1 : 0;\n    region.blks = blks;\n\n    _regionsList.push_back(region);\n\n    return (region.blks);\n}\n\nvoid DataMgr::_free_region(size_t ts, string varname, int level, int lod, DimsType bmin, DimsType bmax, bool forceFlag)\n{\n    list<region_t>::iterator itr;\n    for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) {\n        const region_t &region = *itr;\n\n        if (region.ts == ts && region.varname.compare(varname) == 0 && region.level == level && region.lod == lod && region.bmin == bmin && region.bmax == bmax) {\n            if (region.lock_counter == 0 || forceFlag) {\n                if (region.blks) _blk_mem_mgr->FreeMem(region.blks);\n\n                _regionsList.erase(itr);\n                return;\n            }\n        }\n    }\n\n    return;\n}\n\nvoid DataMgr::_free_var(string varname)\n{\n    list<region_t>::iterator itr;\n    for (itr = _regionsList.begin(); itr != _regionsList.end();) {\n        const region_t &region = *itr;\n\n        if (region.varname.compare(varname) == 0) {\n            if (region.blks) _blk_mem_mgr->FreeMem(region.blks);\n\n            _regionsList.erase(itr);\n            itr = _regionsList.begin();\n        } else\n            itr++;\n    }\n\n    _varInfoCacheSize_T.Purge(vector<string>(1, varname));\n    _varInfoCacheDouble.Purge(vector<string>(1, varname));\n    _varInfoCacheVoidPtr.Purge(vector<string>(1, varname));\n}\n\nbool DataMgr::_free_lru()\n{\n    // The least recently used region is at the front of the list\n    //\n    list<region_t>::iterator itr;\n    for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) {\n        const region_t &region = *itr;\n\n        if (region.lock_counter == 0) {\n            if (region.blks) _blk_mem_mgr->FreeMem(region.blks);\n            _regionsList.erase(itr);\n            return (true);\n        }\n    }\n\n    // nothing to free\n    return (false);\n}\n\n//\n// return complete list of native variables\n//\nvector<string> DataMgr::_get_native_variables() const\n{\n    vector<string> v1 = _dc->GetDataVarNames();\n    vector<string> v2 = _dc->GetCoordVarNames();\n    vector<string> v3 = _dc->GetAuxVarNames();\n\n    v1.insert(v1.end(), v2.begin(), v2.end());\n    v1.insert(v1.end(), v3.begin(), v3.end());\n    return (v1);\n}\n\nbool DataMgr::_hasHorizontalXForm() const\n{\n    VAssert(_dc);\n\n    vector<string> meshnames = _dc->GetMeshNames();\n\n    for (int i = 0; i < meshnames.size(); i++) {\n        if (_hasHorizontalXForm(meshnames[i])) return (true);\n    }\n\n    return (false);\n}\n\nbool DataMgr::_hasHorizontalXForm(string meshname) const\n{\n    DC::Mesh m;\n    bool     status = _dc->GetMesh(meshname, m);\n    if (!status) return (false);\n\n    vector<string> coordVars = m.GetCoordVars();\n\n    for (int i = 0; i < coordVars.size(); i++) {\n        DC::CoordVar varInfo;\n\n        bool ok = _dc->GetCoordVarInfo(coordVars[i], varInfo);\n        VAssert(ok);\n\n        //\n        if (varInfo.GetUnits().empty()) continue;\n\n        // Version 1.0 of CF conventions allows \"degrees\" as units\n        // for both lat and longitude. So we check IsLonUnit,\n        // which looks for \"degrees_east\", \"degrees_E\", etc., and\n        // IsLatOrLonUnit, which will return true for \"degrees\". Unforunately,\n        // IsLatOrLonUnit will also return true for an empty string \"\", so\n        // we explicitly test for that above.\n        //\n        if (varInfo.GetAxis() == 0 && (_udunits.IsLonUnit(varInfo.GetUnits()) || _udunits.IsLatOrLonUnit(varInfo.GetUnits()))) { return (true); }\n        if (varInfo.GetAxis() == 1 && (_udunits.IsLatUnit(varInfo.GetUnits()) || _udunits.IsLatOrLonUnit(varInfo.GetUnits()))) { return (true); }\n    }\n\n    return (false);\n}\n\nbool DataMgr::_hasVerticalXForm() const\n{\n    VAssert(_dc);\n\n    // Only 3D variables can have vertical coordinates?\n    //\n    vector<string> meshnames = _dc->GetMeshNames();\n\n    for (int i = 0; i < meshnames.size(); i++) {\n        if (_hasVerticalXForm(meshnames[i])) return (true);\n    }\n\n    return (false);\n}\n\nbool DataMgr::_hasVerticalXForm(string meshname, string &standard_name, string &formula_terms) const\n{\n    standard_name.clear();\n    formula_terms.clear();\n\n    DC::Mesh m;\n    bool     ok = _dc->GetMesh(meshname, m);\n    if (!ok) return (false);\n\n    if (m.GetDimNames().size() != 3) return (false);\n\n    vector<string> coordVars = m.GetCoordVars();\n\n    bool         hasVertCoord = false;\n    DC::CoordVar cvarInfo;\n    for (int i = 0; i < coordVars.size(); i++) {\n        bool ok = _dc->GetCoordVarInfo(coordVars[i], cvarInfo);\n        VAssert(ok);\n\n        if (cvarInfo.GetAxis() == 2) {\n            hasVertCoord = true;\n            break;\n        }\n    }\n    if (!hasVertCoord) return (false);\n\n    DC::Attribute attr_name;\n    if (!cvarInfo.GetAttribute(\"standard_name\", attr_name)) return (false);\n\n    attr_name.GetValues(standard_name);\n\n    if (standard_name.empty()) return (false);\n\n    DC::Attribute attr_formula;\n    if (!cvarInfo.GetAttribute(\"formula_terms\", attr_formula)) return (false);\n\n    attr_formula.GetValues(formula_terms);\n\n    if (formula_terms.empty()) return (false);\n\n    // Make sure all of the dependent variables needed by the\n    // formula actually exist\n    //\n    map<string, string> parsed_terms;\n    ok = DerivedCFVertCoordVar::ParseFormula(formula_terms, parsed_terms);\n    if (!ok) return (false);\n\n    for (auto itr = parsed_terms.begin(); itr != parsed_terms.end(); ++itr) {\n        const string &varname = itr->second;\n        if (!_dc->VariableExists(0, varname, 0, 0)) return (false);\n    }\n\n    // Does a converter exist for this standard name?\n    //\n    vector<string> names = DerivedCFVertCoordVarFactory::Instance()->GetFactoryNames();\n\n    for (int i = 0; i < names.size(); i++) {\n        if (standard_name == names[i]) return (true);\n    }\n\n    return (false);\n}\n\nbool DataMgr::_isCoordVarInUse(string varName) const\n{\n    std::vector<string> dataVars = GetDataVarNames();\n\n    for (auto dataVar : dataVars) {\n        std::vector<string> coordVars;\n        bool                ok = GetVarCoordVars(dataVar, false, coordVars);\n        if (!ok) continue;\n\n        if (find(coordVars.begin(), coordVars.end(), varName) != coordVars.end()) { return (true); }\n    }\n    return (false);\n}\n\ntemplate<typename C> string DataMgr::VarInfoCache<C>::_make_hash(string key, size_t ts, vector<string> varnames, int level, int lod)\n{\n    ostringstream oss;\n\n    oss << key << \":\";\n    oss << ts << \":\";\n    for (int i = 0; i < varnames.size(); i++) { oss << varnames[i] << \":\"; }\n    oss << level << \":\";\n    oss << lod;\n\n    return (oss.str());\n}\n\ntemplate<typename C> void DataMgr::VarInfoCache<C>::_decode_hash(const string &hash, string &key, size_t &ts, vector<string> &varnames, int &level, int &lod)\n{\n    varnames.clear();\n\n    stringstream   ss(hash);\n    vector<string> result;\n\n    // parse hash into vector of strings\n    //\n    while (ss.good()) {\n        string substr;\n        getline(ss, substr, ':');\n        result.push_back(substr);\n    }\n    VAssert(result.size() >= 5);\n\n    int i = 0;\n    key = result[i++];\n    ts = (size_t)stoi(result[i++]);\n    while (!is_int(result[i])) { varnames.push_back(result[i++]); }\n    level = stoi(result[i++]);\n    lod = stoi(result[i++]);\n}\n\ntemplate<typename C> void DataMgr::VarInfoCache<C>::Set(size_t ts, vector<string> varnames, int level, int lod, string key, const vector<C> &values)\n{\n    string hash = _make_hash(key, ts, varnames, level, lod);\n    _cache[hash] = values;\n}\n\ntemplate<typename C> bool DataMgr::VarInfoCache<C>::Get(size_t ts, vector<string> varnames, int level, int lod, string key, vector<C> &values) const\n{\n    values.clear();\n\n    string                                          hash = _make_hash(key, ts, varnames, level, lod);\n    typename map<string, vector<C>>::const_iterator itr = _cache.find(hash);\n\n    if (itr == _cache.end()) return (false);\n\n    values = itr->second;\n    return (true);\n}\n\ntemplate<typename C> void DataMgr::VarInfoCache<C>::Purge(size_t ts, vector<string> varnames, int level, int lod, string key)\n{\n    string                                    hash = _make_hash(key, ts, varnames, level, lod);\n    typename map<string, vector<C>>::iterator itr = _cache.find(hash);\n\n    if (itr == _cache.end()) return;\n\n    _cache.erase(itr);\n}\n\ntemplate<typename C> void DataMgr::VarInfoCache<C>::Purge(vector<string> varnames)\n{\n    vector<string>                                 hashes;\n    typename map<string, std::vector<C>>::iterator itr;\n    for (itr = _cache.begin(); itr != _cache.end(); ++itr) { hashes.push_back(itr->first); }\n\n    for (int i = 0; i < hashes.size(); i++) {\n        string         hash = hashes[i];\n        string         key;\n        size_t         ts;\n        vector<string> cvarnames;\n        int            level;\n        int            lod;\n\n        _decode_hash(hash, key, ts, cvarnames, level, lod);\n\n        if (varnames == cvarnames) { Purge(ts, varnames, level, lod, key); }\n    }\n}\n\nDataMgr::BlkExts::BlkExts(const DimsType &bmin, const DimsType &bmax)\n{\n\n    _bmin = bmin;\n    _bmax = bmax;\n\n    size_t nelements = Wasp::LinearizeCoords(bmax.data(), bmin.data(), bmax.data(), bmin.size()) + 1;\n\n    _mins.resize(nelements);\n    _maxs.resize(nelements);\n}\n\nvoid DataMgr::BlkExts::Insert(const DimsType &bcoord, const CoordType &min, const CoordType &max)\n{\n    size_t offset = Wasp::LinearizeCoords(bcoord.data(), _bmin.data(), _bmax.data(), bcoord.size());\n\n    _mins[offset] = min;\n    _maxs[offset] = max;\n}\n\nbool DataMgr::BlkExts::Intersect(const CoordType &min, const CoordType &max, DimsType &bmin, DimsType &bmax, int nCoords) const\n{\n    bmin = _bmax;\n    bmax = _bmin;\n\n    bool intersection = false;\n\n    // Test for intersection with the axis aligned bounding box of each\n    // block.\n    //\n    for (size_t offset = 0; offset < _mins.size(); offset++) {\n        bool overlap = true;\n        for (int j = 0; j < nCoords; j++) {\n            if (_maxs[offset][j] < min[j] || _mins[offset][j] > max[j]) {\n                overlap = false;\n                break;\n            }\n        }\n\n        // If the current block intersects the specified bounding volume\n        // compute the block coordinates of the first and last block\n        // that intersect the volume\n        //\n        if (overlap) {\n            intersection = true;    // at least one block intersects\n\n            DimsType coord;\n            Wasp::VectorizeCoords(offset, _bmin.data(), _bmax.data(), coord.data(), coord.size());\n\n            for (int i = 0; i < nCoords; i++) {\n                if (coord[i] < bmin[i]) bmin[i] = coord[i];\n                if (coord[i] > bmax[i]) bmax[i] = coord[i];\n            }\n        }\n    }\n\n    return (intersection);\n}\n\nint DataMgr::_level_correction(string varname, int &level) const\n{\n    int nlevels = DataMgr::GetNumRefLevels(varname);\n\n    if (level >= nlevels) level = nlevels - 1;\n    if (level >= 0) level = -(nlevels - level);\n    if (level < -nlevels) level = -nlevels;\n\n    return (0);\n}\n\nint DataMgr::_lod_correction(string varname, int &lod) const\n{\n    DC::BaseVar var;\n    int         rc = GetBaseVarInfo(varname, var);\n    if (rc < 0) return (rc);\n\n    int nlod = var.GetCRatios().size();\n\n    if (lod >= nlod) lod = nlod - 1;\n    if (lod >= 0) lod = -(nlod - lod);\n    if (lod < -nlod) lod = -nlod;\n\n    return (0);\n}\n\n//\n// Get coordiante variable names for a data variable, return as\n// a list of spatial coordinate variables, and a single (if it exists)\n// time coordinate variable\n//\nbool DataMgr::_get_coord_vars(string varname, vector<string> &scvars, string &tcvar) const\n{\n    scvars.clear();\n    tcvar.clear();\n\n    // Get space and time coord vars\n    //\n    bool ok = GetVarCoordVars(varname, false, scvars);\n    if (!ok) return (ok);\n\n    // Split out time and space coord vars\n    //\n    if (IsTimeVarying(varname)) {\n        VAssert(scvars.size());\n\n        tcvar = scvars.back();\n        scvars.pop_back();\n    }\n\n    return (true);\n}\n\nbool DataMgr::_get_coord_vars(string varname, vector<DC::CoordVar> &scvarsinfo, DC::CoordVar &tcvarinfo) const\n{\n    scvarsinfo.clear();\n\n    vector<string> scvarnames;\n    string         tcvarname;\n    bool           ok = _get_coord_vars(varname, scvarnames, tcvarname);\n    if (!ok) return (ok);\n\n    for (int i = 0; i < scvarnames.size(); i++) {\n        DC::CoordVar cvarinfo;\n\n        bool ok = GetCoordVarInfo(scvarnames[i], cvarinfo);\n        if (!ok) return (ok);\n\n        scvarsinfo.push_back(cvarinfo);\n    }\n\n    if (!tcvarname.empty()) {\n        bool ok = GetCoordVarInfo(tcvarname, tcvarinfo);\n        if (!ok) return (ok);\n    }\n\n    return (true);\n}\n\nint DataMgr::_initTimeCoord()\n{\n    _timeCoordinates.clear();\n\n\n    // A data collection can have multiple time variables, but\n    // the DataMgr currently can only handle one. If there are\n    // multiple time coordinate variables figure out how many\n    // are actually in use.\n    //\n    vector<string> vars;\n    for (auto varName : _dc->GetTimeCoordVarNames()) {\n        if (_isCoordVarInUse(varName)) { vars.push_back(varName); }\n    }\n\n    if (vars.size() > 1) {\n        SetErrMsg(\"Data set contains more than one time coordinate\");\n        return (-1);\n    }\n\n    if (vars.size() == 0) {\n        // No time coordinates present\n        //\n        _timeCoordinates.push_back(0.0);\n        return (0);\n    }\n\n    string nativeTimeCoordName = vars[0];\n\n    size_t numTS = _dc->GetNumTimeSteps(nativeTimeCoordName);\n\n    // If we have a time unit expressed as:\n    //\n    // (<unit > since YYYY-MM-DD hh:mm:ss )\n    //\n    // as supported by the UDUNITS2 package, try to convert to seconds from\n    // EPOCH. N.B. unforunately the UDUNITS API does not provide an interaface\n    // for programatically detecting a formatted time string. So we simply\n    // look for the keyword \"since\" :-(\n    //\n    VAPoR::DC::CoordVar cvar;\n    _dc->GetCoordVarInfo(nativeTimeCoordName, cvar);\n    if (_udunits.IsTimeUnit(cvar.GetUnits()) && STLUtils::ContainsIgnoreCase(cvar.GetUnits(), \"since\")) {\n        string derivedTimeCoordName = nativeTimeCoordName;\n\n        DerivedCoordVar_TimeInSeconds *derivedVar = new DerivedCoordVar_TimeInSeconds(derivedTimeCoordName, _dc, nativeTimeCoordName, cvar.GetTimeDimName());\n\n        int rc = derivedVar->Initialize();\n        if (rc < 0) {\n            SetErrMsg(\"Failed to initialize derived coord variable\");\n            return (-1);\n        }\n\n        _dvm.AddCoordVar(derivedVar);\n\n        _timeCoordinates = derivedVar->GetTimes();\n    } else {\n        double *buf = new double[numTS];\n        int    rc = _getVar(nativeTimeCoordName, -1, -1, buf);\n        if (rc < 0) { return (-1); }\n\n        for (int j = 0; j < numTS; j++) { _timeCoordinates.push_back(buf[j]); }\n        delete[] buf;\n    }\n\n    return (0);\n}\n\nvoid DataMgr::_ugrid_setup(const DC::DataVar &var, DimsType &vertexDims, DimsType &faceDims, DimsType &edgeDims,\n                           UnstructuredGrid::Location &location,    // node,face, edge\n                           size_t &maxVertexPerFace, size_t &maxFacePerVertex, long &vertexOffset, long &faceOffset, long ts) const\n{\n    vertexDims = {1, 1, 1};\n    faceDims = {1, 1, 1};\n    edgeDims = {1, 1, 1};\n\n    DC::Mesh m;\n    bool     status = GetMesh(var.GetMeshName(), m);\n    VAssert(status);\n\n    DC::Dimension dimension;\n\n    size_t layers_dimlen = 0;\n    if (m.GetMeshType() == DC::Mesh::UNSTRUC_LAYERED) {\n        string dimname = m.GetLayersDimName();\n        VAssert(!dimname.empty());\n        status = _dc->GetDimension(dimname, dimension, ts);\n        VAssert(status);\n        layers_dimlen = dimension.GetLength();\n    }\n\n    string dimname = m.GetNodeDimName();\n    status = _dc->GetDimension(dimname, dimension, ts);\n    VAssert(status);\n    vertexDims[0] = dimension.GetLength();\n    if (layers_dimlen) { vertexDims[1] = (layers_dimlen); }\n\n    dimname = m.GetFaceDimName();\n    if (!dimname.empty()) {\n        status = _dc->GetDimension(dimname, dimension, ts);\n        VAssert(status);\n        faceDims[0] = (dimension.GetLength());\n        if (layers_dimlen) { faceDims[1] = (layers_dimlen - 1); }\n    } else\n        VAssert(!\"FaceDim Required\");\n\n    dimname = m.GetEdgeDimName();\n    if (dimname.size()) {\n        status = _dc->GetDimension(dimname, dimension, ts);\n        VAssert(status);\n        edgeDims[0] = (dimension.GetLength());\n        if (layers_dimlen) { edgeDims[1] = (layers_dimlen - 1); }\n    }\n\n    DC::Mesh::Location l = var.GetSamplingLocation();\n    if (l == DC::Mesh::NODE) {\n        location = UnstructuredGrid::NODE;\n    } else if (l == DC::Mesh::EDGE) {\n        location = UnstructuredGrid::EDGE;\n    } else if (l == DC::Mesh::FACE) {\n        location = UnstructuredGrid::CELL;\n    } else if (l == DC::Mesh::VOLUME) {\n        location = UnstructuredGrid::CELL;\n    }\n\n    maxVertexPerFace = m.GetMaxNodesPerFace();\n    maxFacePerVertex = m.GetMaxFacesPerNode();\n\n    string face_node_var;\n    string node_face_var;\n    string dummy;\n\n    bool ok = _getVarConnVars(var.GetName(), face_node_var, node_face_var, dummy, dummy, dummy, dummy);\n    VAssert(ok);\n\n    DC::AuxVar auxvar;\n\n    if (!face_node_var.empty()) {\n        status = _dc->GetAuxVarInfo(face_node_var, auxvar);\n        VAssert(status);\n        vertexOffset = auxvar.GetOffset();\n    } else {\n        VAssert(!\"FaceNodeVar Required\");\n        vertexOffset = 0;\n    }\n\n    if (!node_face_var.empty()) {\n        status = _dc->GetAuxVarInfo(node_face_var, auxvar);\n        VAssert(status);\n        faceOffset = auxvar.GetOffset();\n    }\n}\n\nstring DataMgr::_get_grid_type(string varname) const\n{\n    vector<DC::CoordVar> cvarsinfo;\n    DC::CoordVar         dummy;\n    bool                 ok = _get_coord_vars(varname, cvarsinfo, dummy);\n    if (!ok) return (\"\");\n\n    vector<vector<string>> cdimnames;\n    for (int i = 0; i < cvarsinfo.size(); i++) {\n        vector<string> v;\n        bool           ok = _getVarDimNames(cvarsinfo[i].GetName(), v);\n        if (!ok) return (\"\");\n\n        cdimnames.push_back(v);\n    }\n\n    DC::DataVar dvar;\n    ok = GetDataVarInfo(varname, dvar);\n    VAssert(ok);\n\n    DC::Mesh m;\n    ok = GetMesh(dvar.GetMeshName(), m);\n    VAssert(ok);\n\n    return (_gridHelper.GetGridType(m, cvarsinfo, cdimnames));\n}\n\n// Find the grid coordinates, in voxels, for the region containing\n// the axis aligned bounding box specified by min and max\n//\nint DataMgr::_find_bounding_grid(size_t ts, string varname, int level, int lod, CoordType min, CoordType max, DimsType &min_ui, DimsType &max_ui)\n{\n    min_ui = {0, 0, 0};\n    max_ui = {0, 0, 0};\n\n    vector<string> scvars;\n    string         tcvar;\n\n    bool ok = _get_coord_vars(varname, scvars, tcvar);\n    if (!ok) return (-1);\n\n    size_t hash_ts = 0;\n    for (int i = 0; i < scvars.size(); i++) {\n        if (IsTimeVarying(scvars[i])) hash_ts = ts;\n    }\n\n    vector<size_t> dims_at_level;\n    int            rc = GetDimLensAtLevel(varname, level, dims_at_level, ts);\n    if (rc < 0) {\n        SetErrMsg(\"Invalid variable reference : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Currently unstructured grids can not be subset. We always need\n    // to read the entire data set.\n    //\n    if (_gridHelper.IsUnstructured(_get_grid_type(varname))) {\n        for (int i = 0; i < dims_at_level.size(); i++) {\n            min_ui[i] = 0;\n            max_ui[i] = dims_at_level[i] - 1;\n        }\n        return (0);\n    }\n\n    DimsType bs = {1, 1, 1};\n    for (int i = 0; i < dims_at_level.size(); i++) { bs[i] = _bs[i]; }\n\n    // hash tag for block coordinate cache\n    //\n    string hash = VarInfoCache<int>::_make_hash(\"BlkExts\", hash_ts, scvars, level, lod);\n\n    // See if bounding volumes for individual blocks are already\n    // cached for this grid\n    //\n    map<string, BlkExts>::iterator itr = _blkExtsCache.find(hash);\n\n    if (itr == _blkExtsCache.end()) {\n        SetDiagMsg(\"DataMgr::_find_bounding_grid() - coordinates not in cache\");\n\n        // Get a \"dataless\" Grid - a Grid class the contains\n        // coordiante information, but not data\n        //\n        Grid *rg = _getVariable(ts, varname, level, lod, false, true);\n        if (!rg) return (-1);\n\n        // Voxel and block min and max coordinates of entire grid\n        //\n        DimsType vmin = {0, 0, 0};\n        DimsType vmax = {0, 0, 0};\n        DimsType bmin = {0, 0, 0};\n        DimsType bmax = {0, 0, 0};\n\n        for (int i = 0; i < dims_at_level.size(); i++) {\n            vmin[i] = 0;\n            vmax[i] = (dims_at_level[i] - 1);\n        }\n        map_vox_to_blk(bs, vmin, bmin);\n        map_vox_to_blk(bs, vmax, bmax);\n\n        BlkExts blkexts(bmin, bmax);\n\n        // For each block in the grid compute the block's bounding\n        // box. Include a one-voxel halo region on all non-boundary\n        // faces\n        //\n        size_t nblocks = Wasp::LinearizeCoords(bmax.data(), bmin.data(), bmax.data(), bmax.size()) + 1;\n        for (size_t offset = 0; offset < nblocks; offset++) {\n            CoordType my_min, my_max;\n            DimsType  my_vmin, my_vmax;\n\n            // Get coordinates for current block\n            //\n            DimsType bcoord = {0, 0, 0};\n            Wasp::VectorizeCoords(offset, bmin.data(), bmax.data(), bcoord.data(), bmin.size());\n\n            for (int i = 0; i < bcoord.size(); i++) {\n                my_vmin[i] = bcoord[i] * bs[i];\n                if (my_vmin[i] > 0) my_vmin[i] -= 1;    // not boundary face\n\n                my_vmax[i] = bcoord[i] * bs[i] + bs[i] - 1;\n                if (my_vmax[i] > vmax[i]) my_vmax[i] = vmax[i];\n                if (my_vmax[i] < vmax[i]) my_vmax[i] += 1;\n            }\n\n            // Use the regular grid class to compute the user-coordinate\n            // axis aligned bounding volume for the block+halo\n            //\n            rg->GetBoundingBox(my_vmin, my_vmax, my_min, my_max);\n\n            // Insert the bounding volume into blkexts\n            //\n            blkexts.Insert(bcoord, my_min, my_max);\n        }\n\n        // Add to the hash table\n        //\n        _blkExtsCache[hash] = blkexts;\n        itr = _blkExtsCache.find(hash);\n        VAssert(itr != _blkExtsCache.end());\n\n    } else {\n        SetDiagMsg(\"DataMgr::_find_bounding_grid() - coordinates in cache\");\n    }\n\n    const BlkExts &blkexts = itr->second;\n\n\n\n    // Find block coordinates of region that contains the bounding volume\n    //\n    DimsType bmin, bmax;\n    ok = blkexts.Intersect(min, max, bmin, bmax, GetVarGeometryDim(varname));\n    if (!ok) { return (1); }\n\n    // Finally, map from block to voxel coordinates\n    //\n    map_blk_to_vox(bs, bmin, bmax, min_ui, max_ui);\n    for (int i = 0; i < dims_at_level.size(); i++) {\n        if (max_ui[i] >= dims_at_level[i]) { max_ui[i] = dims_at_level[i] - 1; }\n    }\n\n    return (0);\n}\n\nvoid DataMgr::_unlock_blocks(const void *blks)\n{\n    list<region_t>::iterator itr;\n    for (itr = _regionsList.begin(); itr != _regionsList.end(); itr++) {\n        region_t &region = *itr;\n\n        if (region.blks == blks && region.lock_counter > 0) {\n            region.lock_counter--;\n            return;\n        }\n    }\n    return;\n}\n\nvector<string> DataMgr::_getDataVarNamesDerived(int ndim) const\n{\n    vector<string> names;\n\n    vector<string> allnames = _dvm.GetDataVarNames();\n    ;\n    for (int i = 0; i < allnames.size(); i++) {\n        string name = allnames[i];\n\n        DC::DataVar dvar;\n        bool        ok = GetDataVarInfo(name, dvar);\n        if (!ok) continue;\n\n        string mesh_name;\n        mesh_name = dvar.GetMeshName();\n\n        DC::Mesh mesh;\n        ok = GetMesh(mesh_name, mesh);\n        if (!ok) continue;\n\n        size_t d = mesh.GetTopologyDim();\n\n        if (d == ndim) { names.push_back(name); }\n    }\n\n    return (names);\n}\n\nbool DataMgr::_hasCoordForAxis(vector<string> coord_vars, int axis) const\n{\n    for (int i = 0; i < coord_vars.size(); i++) {\n        DC::CoordVar varInfo;\n\n        bool ok = GetCoordVarInfo(coord_vars[i], varInfo);\n        if (!ok) continue;\n\n        if (varInfo.GetAxis() == axis) return (true);\n    }\n    return (false);\n}\n\nstring DataMgr::_defaultCoordVar(const DC::Mesh &m, int axis) const\n{\n    VAssert(axis >= 0 && axis <= 2);\n\n    // For a structured mesh use the coresponding dimension name\n    // as the coordinate variable name. For unstructured nothing\n    // we can do\n    //\n    if (m.GetMeshType() == DC::Mesh::STRUCTURED) {\n        VAssert(m.GetDimNames().size() >= axis);\n        return (m.GetDimNames()[axis]);\n    } else {\n        return (\"\");\n    }\n}\n\nvoid DataMgr::_assignHorizontalCoords(vector<string> &coord_vars) const\n{\n    for (int i = 0; i < coord_vars.size(); i++) {\n        DC::CoordVar varInfo;\n        bool         ok = GetCoordVarInfo(coord_vars[i], varInfo);\n        VAssert(ok);\n\n        if (_udunits.IsLonUnit(varInfo.GetUnits())) { coord_vars[i] = coord_vars[i] + \"X\"; }\n        if (_udunits.IsLatUnit(varInfo.GetUnits())) { coord_vars[i] = coord_vars[i] + \"Y\"; }\n    }\n}\n\nbool DataMgr::_getVarDimensions(string varname, vector<DC::Dimension> &dimensions, long ts) const\n{\n    dimensions.clear();\n\n    if (!IsVariableDerived(varname)) { return (_dc->GetVarDimensions(varname, true, dimensions, ts)); }\n\n    if (_getDerivedDataVar(varname)) {\n        return (_getDataVarDimensions(varname, dimensions, ts));\n    } else if (_getDerivedCoordVar(varname)) {\n        return (_getCoordVarDimensions(varname, dimensions, ts));\n    } else {\n        return (false);\n    }\n}\n\nbool DataMgr::_getDataVarDimensions(string varname, vector<DC::Dimension> &dimensions, long ts) const\n{\n    dimensions.clear();\n\n    DC::DataVar var;\n    bool        status = GetDataVarInfo(varname, var);\n    if (!status) return (false);\n\n    string mname = var.GetMeshName();\n\n    DC::Mesh mesh;\n    status = GetMesh(mname, mesh);\n    if (!status) return (false);\n\n    vector<string> dimnames;\n    if (mesh.GetMeshType() == DC::Mesh::STRUCTURED) {\n        dimnames = mesh.GetDimNames();\n    } else {\n        switch (var.GetSamplingLocation()) {\n        case DC::Mesh::NODE: dimnames.push_back(mesh.GetNodeDimName()); break;\n        case DC::Mesh::EDGE: dimnames.push_back(mesh.GetEdgeDimName()); break;\n        case DC::Mesh::FACE: dimnames.push_back(mesh.GetFaceDimName()); break;\n        case DC::Mesh::VOLUME: VAssert(0 && \"VOLUME cells not supported\"); break;\n        }\n        if (mesh.GetMeshType() == DC::Mesh::UNSTRUC_LAYERED) { dimnames.push_back(mesh.GetLayersDimName()); }\n    }\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        DC::Dimension dim;\n\n        status = _dc->GetDimension(dimnames[i], dim, ts);\n        if (!status) return (false);\n\n        dimensions.push_back(dim);\n    }\n\n    return (true);\n}\n\nbool DataMgr::_getCoordVarDimensions(string varname, vector<DC::Dimension> &dimensions, long ts) const\n{\n    dimensions.clear();\n\n    DC::CoordVar var;\n    bool         status = GetCoordVarInfo(varname, var);\n    if (!status) return (false);\n\n    vector<string> dimnames = var.GetDimNames();\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        DC::Dimension dim;\n        status = _dc->GetDimension(dimnames[i], dim, ts);\n        if (!status) return (false);\n\n        dimensions.push_back(dim);\n    }\n    return (true);\n}\n\nbool DataMgr::_getVarDimNames(string varname, vector<string> &dimnames) const\n{\n    dimnames.clear();\n\n    vector<DC::Dimension> dims;\n\n    bool status = _getVarDimensions(varname, dims, 0);\n    if (!status) return (status);\n\n    for (int i = 0; i < dims.size(); i++) { dimnames.push_back(dims[i].GetName()); }\n\n    return (true);\n}\n\nbool DataMgr::_getVarConnVars(string varname, string &face_node_var, string &node_face_var, string &face_edge_var, string &face_face_var, string &edge_node_var, string &edge_face_var) const\n{\n    face_node_var.clear();\n    node_face_var.clear();\n    face_edge_var.clear();\n    face_face_var.clear();\n    edge_node_var.clear();\n    edge_face_var.clear();\n\n    DC::DataVar dvar;\n    bool        status = GetDataVarInfo(varname, dvar);\n    if (!status) return (false);\n\n    DC::Mesh m;\n    status = GetMesh(dvar.GetMeshName(), m);\n    if (!status) return (false);\n\n    face_node_var = m.GetFaceNodeVar();\n    node_face_var = m.GetNodeFaceVar();\n    face_edge_var = m.GetFaceEdgeVar();\n    face_face_var = m.GetFaceFaceVar();\n    edge_node_var = m.GetEdgeNodeVar();\n    edge_face_var = m.GetEdgeFaceVar();\n\n    return (true);\n}\n\nDerivedVar *DataMgr::_getDerivedVar(string varname) const\n{\n    DerivedVar *dvar;\n\n    dvar = _getDerivedDataVar(varname);\n    if (dvar) return (dvar);\n\n    dvar = _getDerivedCoordVar(varname);\n    if (dvar) return (dvar);\n\n    return (NULL);\n}\n\nDerivedDataVar *DataMgr::_getDerivedDataVar(string varname) const\n{\n    vector<string> varnames = _dvm.GetDataVarNames();\n    if (find(varnames.begin(), varnames.end(), varname) != varnames.end()) { return (dynamic_cast<DerivedDataVar *>(_dvm.GetVar(varname))); }\n\n    return (NULL);\n}\n\nDerivedCoordVar *DataMgr::_getDerivedCoordVar(string varname) const\n{\n    vector<string> varnames = _dvm.GetCoordVarNames();\n    if (find(varnames.begin(), varnames.end(), varname) != varnames.end()) { return (dynamic_cast<DerivedCoordVar *>(_dvm.GetVar(varname))); }\n\n    return (NULL);\n}\n\nint DataMgr::_openVariableRead(size_t ts, string varname, int level, int lod)\n{\n    _openVarName = varname;\n\n    DerivedVar *derivedVar = _getDerivedVar(_openVarName);\n    if (derivedVar) { return (derivedVar->OpenVariableRead(ts, level, lod)); }\n\n    return (_dc->OpenVariableRead(ts, _openVarName, level, lod));\n}\n\n\ntemplate<class T> int DataMgr::_readRegion(int fd, const DimsType &min, const DimsType &max, size_t ndims, T *region)\n{\n    vector<size_t> minv, maxv;\n    Grid::CopyFromArr3(min, minv);\n    minv.resize(ndims);\n    Grid::CopyFromArr3(max, maxv);\n    maxv.resize(ndims);\n\n    int         rc = 0;\n    DerivedVar *derivedVar = _getDerivedVar(_openVarName);\n    if (derivedVar) {\n        VAssert((std::is_same<T, float>::value) == true);\n        rc = derivedVar->ReadRegion(fd, minv, maxv, (float *)region);\n    } else {\n        rc = _dc->ReadRegion(fd, minv, maxv, region);\n    }\n\n   _sanitizeFloats(region, vproduct(box_dims(min, max)));\n    return (rc);\n}\n\nint DataMgr::_closeVariable(int fd)\n{\n    DerivedVar *derivedVar = _getDerivedVar(_openVarName);\n    if (derivedVar) { return (derivedVar->CloseVariable(fd)); }\n\n    _openVarName.clear();\n\n    return (_dc->CloseVariable(fd));\n}\n\ntemplate<class T> int DataMgr::_getVar(string varname, int level, int lod, T *data)\n{\n    vector<size_t> dims_at_level, dummy;\n\n    size_t numts = _dc->GetNumTimeSteps(varname);\n\n    T *ptr = data;\n    for (size_t ts = 0; ts < numts; ts++) {\n        int rc = _dc->GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts);\n        if (rc < 0) return (-1);\n        size_t var_size = 1;\n        for (int i = 0; i < dims_at_level.size(); i++) { var_size *= dims_at_level[i]; }\n\n        rc = _getVar(ts, varname, level, lod, ptr);\n        if (rc < 0) return (-1);\n\n        ptr += var_size;\n    }\n\n    return (0);\n}\n\ntemplate<class T> int DataMgr::_getVar(size_t ts, string varname, int level, int lod, T *data)\n{\n    vector<size_t> dims_at_level, dummy;\n    int            rc = _dc->GetDimLensAtLevel(varname, level, dims_at_level, dummy, ts);\n    if (rc < 0) return (-1);\n    vector<size_t> min, max;\n    for (int i = 0; i < dims_at_level.size(); i++) {\n        min.push_back(0);\n        max.push_back(dims_at_level[i] - 1);\n    }\n\n    int fd = _dc->OpenVariableRead(ts, varname, level, lod);\n    if (fd < 0) return (-1);\n\n    rc = _dc->ReadRegion(fd, min, max, data);\n    if (rc < 0) return (-1);\n\n    rc = _dc->CloseVariable(fd);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\nvoid DataMgr::_getLonExtents(vector<float> &lons, DimsType dims, float &min, float &max) const\n{\n    min = max = 0.0;\n\n    if (!lons.size()) return;\n\n    auto minmaxitr = std::minmax_element(lons.begin(), lons.end());\n    min = *(minmaxitr.first);\n    max = *(minmaxitr.second);\n}\n\nvoid DataMgr::_getLatExtents(vector<float> &lats, DimsType dims, float &min, float &max) const\n{\n    min = max = 0.0;\n\n    if (!lats.size()) return;\n\n    auto minmaxitr = std::minmax_element(lats.begin(), lats.end());\n    min = *(minmaxitr.first);\n    max = *(minmaxitr.second);\n}\n\nint DataMgr::_getCoordPairExtents(string lon, string lat, float &lonmin, float &lonmax, float &latmin, float &latmax, long ts)\n{\n    lonmin = lonmax = latmin = latmax = 0.0;\n\n    vector<size_t> dimsv, dummy;\n    int            rc = _dc->GetDimLensAtLevel(lon, 0, dimsv, dummy, ts);\n\n    if (rc < 0) {\n        SetErrMsg(\"Invalid variable reference : %s\", lon.c_str());\n        return (-1);\n    }\n    if (!(dimsv.size() == 1 || dimsv.size() == 2)) {\n        SetErrMsg(\"Unsupported variable dimension for variable \\\"%s\\\"\", lon.c_str());\n        return (-1);\n    }\n\n\n    DimsType dims = {1, 1, 1};\n    Grid::CopyToArr3(dimsv, dims);\n    vector<float> buf(VProduct(dimsv));\n\n    rc = _getVar(0, lon, 0, 0, buf.data());\n    if (rc < 0) return (-1);\n\n    _getLonExtents(buf, dims, lonmin, lonmax);\n\n    rc = _dc->GetDimLensAtLevel(lat, 0, dimsv, dummy, ts);\n    if (rc < 0) {\n        SetErrMsg(\"Invalid variable reference : %s\", lat.c_str());\n        return (-1);\n    }\n    if (!(dimsv.size() == 1 || dimsv.size() == 2)) {\n        SetErrMsg(\"Unsupported variable dimension for variable \\\"%s\\\"\", lat.c_str());\n        return (-1);\n    }\n\n    dims = {1, 1, 1};\n    Grid::CopyToArr3(dimsv, dims);\n    buf.resize(vproduct(dims));\n\n    rc = _getVar(0, lat, 0, 0, buf.data());\n    if (rc < 0) return (-1);\n\n    _getLatExtents(buf, dims, latmin, latmax);\n\n    return (0);\n}\n\nint DataMgr::_initProj4StringDefault()\n{\n    // If data set has a map projection use it\n    //\n    _proj4StringDefault = _dc->GetMapProjection();\n    if (!_proj4StringDefault.empty()) { return (0); }\n\n    // Generate our own proj4 string\n    //\n\n    vector<string> meshnames = _dc->GetMeshNames();\n    if (meshnames.empty()) return (0);\n\n    vector<string> coordvars;\n    for (int i = 0; i < meshnames.size() && coordvars.size() < 2; i++) {\n        if (!_hasHorizontalXForm(meshnames[i])) continue;\n\n        DC::Mesh m;\n        bool     ok = _dc->GetMesh(meshnames[i], m);\n        if (!ok) continue;\n\n        if (m.GetCoordVars().size() < 2) continue;\n\n        coordvars = m.GetCoordVars();\n    }\n    if (coordvars.empty()) return (0);\n\n    float lonmin, lonmax, latmin, latmax;\n    int   rc = _getCoordPairExtents(coordvars[0], coordvars[1], lonmin, lonmax, latmin, latmax, 0);\n    if (rc < 0) return (-1);\n\n    float         lon_0 = (lonmin + lonmax) / 2.0;\n    float         lat_0 = (latmin + latmax) / 2.0;\n    ostringstream oss;\n    oss << \" +lon_0=\" << lon_0 << \" +lat_0=\" << lat_0;\n    _proj4StringDefault = \"+proj=eqc +ellps=WGS84\" + oss.str();\n\n    return (0);\n}\n\nint DataMgr::_initHorizontalCoordVars()\n{\n    if (!_doTransformHorizontal) return (0);\n\n    if (!_hasHorizontalXForm()) return (0);\n\n    int rc = _initProj4StringDefault();\n    if (rc < 0) return (-1);\n\n    // Already initialized via Initialize() options\n    //\n    if (_proj4String.empty()) { _proj4String = _proj4StringDefault; }\n\n    vector<string> meshnames = _dc->GetMeshNames();\n\n    vector<string> coordvars;\n    for (int i = 0; i < meshnames.size(); i++) {\n        if (!_hasHorizontalXForm(meshnames[i])) continue;\n\n        DC::Mesh m;\n        bool     ok = _dc->GetMesh(meshnames[i], m);\n        if (!ok) continue;\n\n        if (m.GetCoordVars().size() < 2) continue;\n\n        coordvars = m.GetCoordVars();\n        while (coordvars.size() > 2) { coordvars.pop_back(); }\n\n        vector<string> derivedCoordvars = coordvars;\n        _assignHorizontalCoords(derivedCoordvars);\n\n        // no duplicates\n        //\n        if (!_getDerivedCoordVar(derivedCoordvars[0])) {\n            DerivedCoordVar_PCSFromLatLon *derivedVar = new DerivedCoordVar_PCSFromLatLon(derivedCoordvars[0], _dc, coordvars, _proj4String, m.GetMeshType() != DC::Mesh::STRUCTURED, true);\n\n            rc = derivedVar->Initialize();\n            if (rc < 0) {\n                SetErrMsg(\"Failed to initialize derived coord variable\");\n                return (-1);\n            }\n\n            _dvm.AddCoordVar(derivedVar);\n        }\n\n        if (!_getDerivedCoordVar(derivedCoordvars[1])) {\n            DerivedCoordVar_PCSFromLatLon *derivedVar = new DerivedCoordVar_PCSFromLatLon(derivedCoordvars[1], _dc, coordvars, _proj4String, m.GetMeshType() != DC::Mesh::STRUCTURED, false);\n\n            rc = derivedVar->Initialize();\n            if (rc < 0) {\n                SetErrMsg(\"Failed to initialize derived coord variable\");\n                return (-1);\n            }\n\n            _dvm.AddCoordVar(derivedVar);\n        }\n    }\n\n    return (0);\n}\n\nint DataMgr::_initVerticalCoordVars()\n{\n    if (!_doTransformVertical) return (0);\n\n    if (!_hasVerticalXForm()) return (0);\n\n    vector<string> meshnames = _dc->GetMeshNames();\n\n    vector<string> coordvars;\n    for (int i = 0; i < meshnames.size(); i++) {\n        string standard_name, formula_terms;\n        if (!_hasVerticalXForm(meshnames[i], standard_name, formula_terms)) { continue; }\n\n        DC::Mesh m;\n        bool     ok = _dc->GetMesh(meshnames[i], m);\n        if (!ok) continue;\n\n        VAssert(m.GetCoordVars().size() > 2);\n\n        DerivedCoordVar *derivedVar = NULL;\n\n        derivedVar = DerivedCFVertCoordVarFactory::Instance()->CreateInstance(standard_name, _dc, meshnames[i], formula_terms);\n        if (!derivedVar) {\n            SetErrMsg(\"Failed to initialize derived coord variable\");\n            return (-1);\n        }\n\n        int rc = derivedVar->Initialize();\n        if (rc < 0) {\n            SetErrMsg(\"Failed to initialize derived coord variable\");\n            return (-1);\n        }\n\n        _dvm.AddCoordVar(derivedVar);\n\n        vector<string> coord_vars = m.GetCoordVars();\n        coord_vars[2] = derivedVar->GetName();\n        m.SetCoordVars(coord_vars);\n\n        _dvm.AddMesh(m);\n    }\n\n    return (0);\n}\n\nnamespace VAPoR {\n\nstd::ostream &operator<<(std::ostream &o, const DataMgr::BlkExts &b)\n{\n    VAssert(b._bmin.size() == b._bmax.size());\n    VAssert(b._mins.size() == b._maxs.size());\n\n    o << \"Block dimensions\" << endl;\n    for (int i = 0; i < b._bmin.size(); i++) { o << \"  \" << b._bmin[i] << \" \" << b._bmax[i] << endl; }\n    o << \"Block coordinates\" << endl;\n    for (int i = 0; i < b._mins.size(); i++) {\n        VAssert(b._mins[i].size() == b._maxs[i].size());\n        o << \"Block index \" << i << endl;\n        for (int j = 0; j < b._mins[i].size(); j++) { o << \"  \" << b._mins[i][j] << \" \" << b._maxs[i][j] << endl; }\n        o << endl;\n    }\n\n    return (o);\n}\n\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/DataMgrUtils.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t\t Copyright (C)  2017\t\t\t\t*\n//\t University Corporation for Atmospheric Research\t\t\t*\n//\t\t\t All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\tDataMgrUtils.cpp\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJune 2017\n//\n//\tDescription:\tImplements the DataMgrUtils free functions\n//\n#ifdef WIN32\n    #pragma warning(disable : 4251 4100)\n#endif\n\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <algorithm>\n#include <cfloat>\n#include <vector>\n#include <numeric>\n\n#include <vapor/DataMgr.h>\n#include <vapor/Proj4API.h>\n#include <vapor/DataMgrUtils.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nbool DataMgrUtils::MaxXFormPresent(const DataMgr *dataMgr, size_t timestep, string varname, size_t &maxXForm)\n{\n    size_t maxx = dataMgr->GetNumRefLevels(varname);\n\n    maxXForm = 0;\n    for (; maxXForm < maxx; maxXForm++) {\n        if (!dataMgr->VariableExists(timestep, varname, maxXForm)) break;\n    }\n    if (maxXForm == 0) return false;\n\n    maxXForm -= 1;\n    return true;\n}\n\nbool DataMgrUtils::MaxLODPresent(const DataMgr *dataMgr, size_t timestep, string varname, size_t &maxLOD)\n{\n    maxLOD = 0;\n\n    vector<size_t> cratios = dataMgr->GetCRatios(varname);\n    VAssert(cratios.size() > 0);\n\n    for (maxLOD = 0; maxLOD < cratios.size(); maxLOD++) {\n        if (!dataMgr->VariableExists(timestep, varname, 0, maxLOD)) break;\n    }\n    if (maxLOD == 0) return false;\n\n    maxLOD -= 1;\n    return true;\n}\n\nint DataMgrUtils::ConvertPCSToLonLat(const DataMgr *dataMgr, double coords[2], int npoints)\n{\n    // Set up proj.4 to convert to latlon\n    string pstring = dataMgr->GetMapProjection();\n    if (pstring.size() == 0) return 0;\n\n    return ConvertPCSToLonLat(pstring, coords, npoints);\n}\n\nint DataMgrUtils::ConvertPCSToLonLat(string pstring, double coords[2], int npoints)\n{\n    if (pstring.size() == 0) return 0;\n\n    Proj4API proj4API;\n    int      rc = proj4API.Initialize(pstring, \"\");\n    if (rc < 0) return (rc);\n\n    rc = proj4API.Transform(coords, coords + 1, npoints, 2);\n    if (rc < 0) return (rc);\n\n    return 0;\n}\n\nint DataMgrUtils::ConvertLonLatToPCS(const DataMgr *dataMgr, double coords[2], int npoints)\n{\n    // Set up proj.4 to convert from LatLon to VDC coords\n    string projString = dataMgr->GetMapProjection();\n    if (projString.size() == 0) return (0);\n\n    return ConvertLonLatToPCS(projString, coords, npoints);\n}\n\nint DataMgrUtils::ConvertLonLatToPCS(string projString, double coords[2], int npoints)\n{\n    Proj4API proj4API;\n    int      rc = proj4API.Initialize(\"\", projString);\n    if (rc < 0) return (rc);\n\n    rc = proj4API.Transform(coords, coords + 1, npoints, 2);\n    if (rc < 0) return (rc);\n\n    return 0;\n}\n\ntemplate<typename T>\nint DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, const vector<string> &varnames, const T &minExtsReq, const T &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, vector<Grid *> &grids,\n                           bool lock)\n{\n    grids.clear();\n    VAssert(minExtsReq.size() == maxExtsReq.size());\n\n    for (int i = 0; i < varnames.size(); i++) grids.push_back(NULL);\n\n    // First, find an lod and a refinement level that will work with\n    // all variables.\n    //\n    int tempRefLevel = *refLevel;\n    int tempLOD = *lod;\n    for (int i = 0; i < varnames.size(); i++) {\n        if (varnames[i].empty()) continue;\n\n        size_t maxRefLevel;\n        bool   status = MaxXFormPresent(dataMgr, ts, varnames[i], maxRefLevel);\n        if (!status) {\n            MyBase::SetErrMsg(\"Variable not present at required refinement and LOD\");\n            return -1;\n        }\n\n        tempRefLevel = std::min((int)maxRefLevel, tempRefLevel);\n\n        size_t maxLOD;\n        status = MaxLODPresent(dataMgr, ts, varnames[i], maxLOD);\n        if (!status) {\n            MyBase::SetErrMsg(\"Variable not present at required refinement and LOD\");\n            return -1;\n        }\n\n        tempLOD = std::min((int)maxLOD, tempLOD);\n    }\n\n    if (useLowerAccuracy) {\n        *lod = tempLOD;\n        *refLevel = tempRefLevel;\n    } else {\n        if (tempRefLevel < *refLevel || tempLOD < *lod) {\n            MyBase::SetErrMsg(\"Variable not present at required refinement and LOD\");\n            return -1;\n        }\n    }\n\n    // Now obtain a regular grid for each valid variable\n    //\n    for (int i = 0; i < varnames.size(); i++) {\n        if (varnames[i].empty()) continue;\n\n        Grid *rGrid = dataMgr->GetVariable(ts, varnames[i], *refLevel, *lod, minExtsReq, maxExtsReq, true);\n\n        if (!rGrid) {\n            for (int j = 0; j < i; j++) {\n                if (grids[j]) dataMgr->UnlockGrid(grids[j]);\n            }\n            MyBase::SetErrMsg(\"Error retrieving variable data\");\n            return -1;\n        }\n        grids[i] = rGrid;\n    }\n\n    if (!lock) {\n        for (auto g : grids) {\n            if (g) dataMgr->UnlockGrid(g);\n        }\n    }\n\n    // obtained all of the grids needed\n    return 0;\n}\n\n\ntemplate VDF_API int DataMgrUtils::GetGrids<CoordType>(DataMgr *dataMgr, size_t ts, const vector<string> &varnames, const CoordType &minExtsReq, const CoordType &maxExtsReq, bool useLowerAccuracy,\n                                                       int *refLevel, int *lod, vector<Grid *> &grids, bool lock);\n\ntemplate VDF_API int DataMgrUtils::GetGrids<DimsType>(DataMgr *dataMgr, size_t ts, const vector<string> &varnames, const DimsType &minExtsReq, const DimsType &maxExtsReq, bool useLowerAccuracy,\n                                                      int *refLevel, int *lod, vector<Grid *> &grids, bool lock);\n\nint DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, string varname, const CoordType &minExtsReq, const CoordType &maxExtsReq, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr,\n                           bool lock)\n{\n    *gridptr = NULL;\n\n    if (varname == \"\") {\n        MyBase::SetErrMsg(\"Cannot get grid for variable \\\"\\\"\");\n        return -1;\n    }\n\n    vector<string> varnames;\n    varnames.push_back(varname);\n    vector<Grid *> grids;\n    int            rc = GetGrids(dataMgr, ts, varnames, minExtsReq, maxExtsReq, useLowerAccuracy, refLevel, lod, grids, lock);\n    if (rc < 0) return (rc);\n\n    *gridptr = grids[0];\n    return (0);\n}\n\nint DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, const vector<string> &varnames, bool useLowerAccuracy, int *refLevel, int *lod, vector<Grid *> &grids, bool lock)\n{\n    grids.clear();\n\n    CoordType minExtsReq, maxExtsReq;\n    for (int i = 0; i < 3; i++) { minExtsReq[i] = (std::numeric_limits<double>::lowest()); }\n\n    for (int i = 0; i < 3; i++) { maxExtsReq[i] = (std::numeric_limits<double>::max()); }\n\n    return (DataMgrUtils::GetGrids(dataMgr, ts, varnames, minExtsReq, maxExtsReq, useLowerAccuracy, refLevel, lod, grids, lock));\n}\n\nint DataMgrUtils::GetGrids(DataMgr *dataMgr, size_t ts, string varname, bool useLowerAccuracy, int *refLevel, int *lod, Grid **gridptr, bool lock)\n{\n    *gridptr = NULL;\n\n    vector<string> varnames;\n    varnames.push_back(varname);\n    vector<Grid *> grids;\n    int            rc = GetGrids(dataMgr, ts, varnames, useLowerAccuracy, refLevel, lod, grids, lock);\n    if (rc < 0) return (rc);\n\n    *gridptr = grids[0];\n    return (0);\n}\n\nvoid DataMgrUtils::UnlockGrids(DataMgr *dataMgr, const std::vector<Grid *> &grids)\n{\n    for (int i = 0; i < grids.size(); i++) { dataMgr->UnlockGrid(grids[i]); }\n}\n\nbool DataMgrUtils::GetAxes(const DataMgr *dataMgr, string varname, vector<int> &axes)\n{\n    axes.clear();\n\n    vector<string> coordvars;\n    bool           status = dataMgr->GetVarCoordVars(varname, true, coordvars);\n    if (!status) return (status);\n\n    for (int i = 0; i < coordvars.size(); i++) {\n        VAPoR::DC::CoordVar cvar;\n\n        status = dataMgr->GetCoordVarInfo(coordvars[i], cvar);\n        VAssert(status);\n\n        axes.push_back(cvar.GetAxis());\n    }\n    return (true);\n}\n\nbool DataMgrUtils::GetExtents(DataMgr *dataMgr, size_t timestep, string varname, int refLevel, int lod, CoordType &minExts, CoordType &maxExts)\n{\n    minExts = {0.0, 0.0, 0.0};\n    maxExts = {0.0, 0.0, 0.0};\n\n    // If varname not specified look for first variable of highest\n    // dimensionality\n    //\n    if (varname.empty()) {\n        for (int ndim = 3; ndim > 0; ndim--) {\n            bool ok = DataMgrUtils::GetFirstExistingVariable(dataMgr, timestep, refLevel, lod, ndim, varname);\n\n            if (ok) break;\n        }\n    }\n\n    if (varname.empty()) return (false);\n\n    if (refLevel == -1) {\n        size_t maxXForm;\n        bool   status = DataMgrUtils::MaxXFormPresent(dataMgr, timestep, varname, maxXForm);\n        if (!status) return (status);\n        refLevel = (int)maxXForm;\n    }\n\n    bool errEnabled = MyBase::EnableErrMsg(false);\n    int  rc = dataMgr->GetVariableExtents(timestep, varname, refLevel, lod, minExts, maxExts);\n    MyBase::EnableErrMsg(errEnabled);\n\n    if (rc < 0) return (false);\n\n    return (true);\n}\n\nbool DataMgrUtils::GetExtents(DataMgr *dataMgr, size_t timestep, const vector<string> &varnames, int refLevel, int lod, CoordType &minExts, CoordType &maxExts, vector<int> &axes)\n{\n    minExts = {0.0, 0.0, 0.0};\n    maxExts = {0.0, 0.0, 0.0};\n    axes.clear();\n\n    vector<double> tmpMinExts(3, std::numeric_limits<double>::max());\n    vector<double> tmpMaxExts(3, std::numeric_limits<double>::lowest());\n\n    // Get the coordinate extents of each variable. Grow the bounding\n    // box to accomodate each new variable. Handle cases where variables\n    // have different dimensionality, or, in 2D case, live in different\n    // planes.\n    //\n    // Have to be careful\n    // about what coordinate axis the coordinate extents apply to\n    //\n    for (int i = 0; i < varnames.size(); i++) {\n        if (varnames[i] == \"\") { continue; }\n\n        CoordType      varMinExts = {0.0, 0.0, 0.0};\n        CoordType      varMaxExts = {0.0, 0.0, 0.0};\n        vector<int>    varAxes;\n\n        bool status = DataMgrUtils::GetExtents(dataMgr, timestep, varnames[i], refLevel, lod, varMinExts, varMaxExts);\n        if (!status) continue;\n\n        // Figure out which axes the variable coordinate extents\n        // apply to.\n        //\n        status = DataMgrUtils::GetAxes(dataMgr, varnames[i], varAxes);\n        VAssert(status);\n\n        for (int j = 0; j < varAxes.size(); j++) {\n            int axis = varAxes[j];\n\n            if (varMinExts[j] < tmpMinExts[axis]) { tmpMinExts[axis] = varMinExts[j]; }\n            if (varMaxExts[j] > tmpMaxExts[axis]) { tmpMaxExts[axis] = varMaxExts[j]; }\n        }\n    }\n\n    // tmp{Min,Max}Exts are always 3D vectors.\n    //\n    for (int i = 0; i < tmpMinExts.size(); i++) {\n        if (tmpMinExts[i] != std::numeric_limits<double>::max()) {\n            minExts[i] = (tmpMinExts[i]);\n            maxExts[i] = (tmpMaxExts[i]);\n            axes.push_back(i);\n        }\n    }\n    return (true);\n}\n\n// This is an arbitrary number and method for determening a default that I just moved from elsewhere\n#define REQUIRED_SAMPLE_SIZE 1000000\n\nint DataMgrUtils::GetDefaultMetaInfoStride(DataMgr *dataMgr, std::string varname, int refinementLevel)\n{\n    std::vector<size_t> dimsAtLevel;\n    int                 rc = dataMgr->GetDimLensAtLevel(varname, refinementLevel, dimsAtLevel, 0);\n    VAssert(rc >= 0);\n\n    long size = 1;\n    for (int i = 0; i < dimsAtLevel.size(); i++) size *= dimsAtLevel[i];\n\n    int stride = 1;\n    if (size > REQUIRED_SAMPLE_SIZE) stride = 1 + size / REQUIRED_SAMPLE_SIZE;\n\n    return stride;\n}\n\ndouble DataMgrUtils::Get2DRendererDefaultZ(DataMgr *dataMgr, size_t ts, int refLevel, int lod)\n{\n    CoordType minExts;\n    CoordType maxExts;\n\n    bool status = DataMgrUtils::GetExtents(dataMgr, ts, \"\", refLevel, lod, minExts, maxExts);\n    if (!status) return (0.0);\n\n    // Return whichever XY plane is closest to 0 meters (typically MSL)\n    return (std::abs(minExts[2]) < std::abs(maxExts[2])) ? minExts[2] : maxExts[2];\n}\n\nbool DataMgrUtils::GetFirstExistingVariable(DataMgr *dataMgr, int level, int lod, int ndim, string &varname, size_t &ts)\n{\n    varname.clear();\n    size_t numTS = dataMgr->GetTimeCoordinates().size();\n\n    if (ts < 0 || ts >= numTS)\n        ts = 0;\n\n    std::vector<size_t> timesteps(numTS);\n    std::iota(timesteps.begin(), timesteps.end(), 0);\n    std::sort(timesteps.begin(), timesteps.end(), [ts](size_t a, size_t b) { return abs((long)ts-(long)a) < abs((long)ts-(long)b); });\n\n    for (size_t l_ts : timesteps) {\n        bool ok = GetFirstExistingVariable(dataMgr, l_ts, level, lod, ndim, varname);\n        if (ok) {\n            ts = l_ts;\n            return (true);\n        }\n    }\n    return (false);\n}\n\nbool DataMgrUtils::GetFirstExistingVariable(DataMgr *dataMgr, size_t ts, int level, int lod, int ndim, string &varname)\n{\n    varname.clear();\n    vector<string> varnames = dataMgr->GetDataVarNames(ndim);\n    for (int i = 0; i < varnames.size(); i++) {\n        if (dataMgr->VariableExists(ts, varnames[i], level, lod)) {\n            varname = varnames[i];\n            return (true);\n        }\n    }\n    return (false);\n}\n\n#ifdef VAPOR3_0_0_ALPHA\n// Map corners of box to voxels.\nvoid DataMgrUtils::mapBoxToVox(Box *box, string varname, int refLevel, int lod, int timestep, size_t voxExts[6])\n{\n    double userExts[6];\n    box->GetUserExtents(userExts, (size_t)timestep);\n    vector<double> minexts, maxexts;\n    for (int i = 0; i < 3; i++) {\n        minexts.push_back(userExts[i]);\n        maxexts.push_back(userExts[i + 3]);\n    }\n    bool  errEnabled = MyBase::EnableErrMsg(false);\n    Grid *rg = dataMgr->GetVariable(timestep, varname, refLevel, lod, minexts, maxexts);\n    MyBase::EnableErrMsg(errEnabled);\n\n    if (rg) {\n        rg->GetIJKIndex(minexts[0], minexts[1], minexts[2], voxExts, voxExts + 1, voxExts + 2);\n        rg->GetIJKIndex(maxexts[0], maxexts[1], maxexts[2], voxExts + 3, voxExts + 4, voxExts + 5);\n    } else {\n        for (int i = 0; i < 6; i++) voxExts[i] = 0;\n    }\n    //(Note: this can be expensive with layered data)\n    return;\n}\n\ndouble DataMgrUtils::getVoxelSize(size_t ts, string varname, int refLevel, int dir)\n{\n    DataMgr *dataMgr = GetActiveDataMgr();\n    if (!dataMgr) { return (1.0); }\n\n    // If refLevel is -1, use maximum refinement level\n    // Obtain the variable at lowest refinement level, then convert to higher levels if needed\n    // If dir is -1 get maximum side of voxel\n    // If dir is -2 get minimum side of voxel\n    Grid *rGrid = dataMgr->GetVariable(ts, varname, 0, 0);\n    if (refLevel == -1) refLevel = dataMgr->GetNumRefLevels(varname) - 1;\n    size_t dims[3];\n    rGrid->GetDimensions(dims);\n    for (int i = 0; i < 3; i++) dims[i] *= 2 << refLevel;\n    double extents[6];\n    rGrid->GetUserExtents(extents);\n    int numdims = rGrid->GetRank();\n    if (numdims < dir) return 0.;\n    if (dir >= 0) {\n        double vsize = ((extents[dir + 3] - extents[dir]) / dims[dir]);\n        return vsize;\n    } else if (dir == -1) {    // maximum size\n        double maxsize = -1.;\n        for (int i = 0; i < numdims; i++) {\n            double vsize = ((extents[dir + 3] - extents[dir]) / dims[dir]);\n            if (vsize > maxsize) maxsize = vsize;\n        }\n        return maxsize;\n    } else {    // minimum size\n        double minsize = DBL_MAX;\n        for (int i = 0; i < numdims; i++) {\n            double vsize = ((extents[dir + 3] - extents[dir]) / dims[dir]);\n            if (vsize < minsize) minsize = vsize;\n        }\n        return minsize;\n    }\n}\n\n#endif\n"
  },
  {
    "path": "lib/vdc/DerivedParticleDensity.cpp",
    "content": "#include <vapor/DerivedParticleDensity.h>\n#include <vapor/STLUtils.h>\n#include <vapor/DataMgrUtils.h>\n#include <float.h>\n#include <glm/glm.hpp>\n\nusing namespace VAPoR;\nusing glm::ivec3;\nusing glm::vec3;\n\n// ===================================\n//       DerivedParticleDensity\n// ===================================\n\nDerivedParticleDensity::DerivedParticleDensity(string varName, DC *dc, string meshName, DataMgr *dataMgr) : DerivedDataVar(varName), _dc(dc), _meshName(meshName), _dataMgr(dataMgr) {}\n\nint DerivedParticleDensity::Initialize()\n{\n    auto   dataVarNames = _dataMgr->GetDataVarNames(3);\n    string dataVar;\n    for (auto dv : dataVarNames) {\n        vector<string> coordNames;\n        _dataMgr->GetVarCoordVars(dv, true, coordNames);\n        if (STLUtils::Contains(coordNames, string(\"Position_x\")) && STLUtils::Contains(coordNames, string(\"Position_y\")) && STLUtils::Contains(coordNames, string(\"Position_z\"))) {\n            dataVar = dv;\n            break;\n        }\n    }\n\n    if (dataVar.empty()) {\n        assert(0);\n        return -1;\n    }\n\n    _dataVar = dataVar;\n\n    return 0;\n}\n\nint DerivedParticleDensity::OpenVariableRead(size_t ts, int level, int lod)\n{\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n    return _fileTable.AddEntry(f);\n}\n\nint DerivedParticleDensity::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return -1;\n    }\n    _fileTable.RemoveEntry(fd);\n    delete f;\n    return 0;\n}\n\nint DerivedParticleDensity::ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return -1;\n    }\n\n\n    vector<size_t> dims;\n    _dataMgr->GetDimLens(_derivedVarName, dims, f->GetTS());\n    if (dims.size() != 3) {\n        assert(0);\n        return -1;\n    }\n\n    Grid *g = _dataMgr->GetVariable(f->GetTS(), _dataVar, -1, -1, true);\n    if (!g) {\n        assert(0);\n        return -1;\n    }\n\n    vector<size_t> particleDims;\n    _dataMgr->GetDimLens(_dataVar, particleDims, f->GetTS());\n    assert(particleDims.size() == 1);\n    size_t realNP = particleDims[0];\n\n    int    xd = dims[0], yd = dims[1], zd = dims[2];\n    float *data = new float[xd * yd * zd];\n    compute(g, data, xd, yd, zd, realNP);\n    delete g;\n\n    //    assert(max[0]-min[0]+1 == xd);\n    //    assert(max[1]-min[1]+1 == yd);\n    //    assert(max[2]-min[2]+1 == zd);\n\n    //    for (int z = 0; z < zd; z++)\n    //        for (int y = 0; y < yd; y++)\n    //            for (int x = 0; x < xd; x++)\n    //                if (x > 10 && x < 20 && y > 10 && y < 20 && z > 10 && z < 20)\n    //                    data[z*yd*xd + y*xd + x] = 1;\n    //                else\n    //                    data[z*yd*xd + y*xd + x] = 0;\n\n    int oxd = 1 + max[0] - min[0], oyd = 1 + max[1] - min[1], ozd = 1 + max[2] - min[2];\n    //    printf(\"Read(%s, %s, %s)\\n\", C(_derivedVarName), C(min), C(max));\n\n    // Copy subvolume\n    for (int z = 0; z < ozd; z++)\n        for (int y = 0; y < oyd; y++)\n            for (int x = 0; x < oxd; x++) region[z * oyd * oxd + y * oxd + x] = data[(min[2] + z) * yd * xd + (min[1] + y) * xd + (min[0] + x)];\n    //                region[z*oyd*oxd + y*oxd + x] = y % 3 ? 0 : 1;\n\n    //    for (size_t i = 0; i < nbins; i++)\n    //        region[i] = data[i];\n\n    delete[] data;\n    return 0;\n}\n\nvoid DerivedParticleDensity::compute(Grid *inGrid, float *output, int xd, int yd, int zd, size_t realNP) const\n{\n    CoordType minud, maxud;\n    inGrid->GetUserExtents(minud, maxud);\n    vec3 minu(minud[0], minud[1], minud[2]);\n    vec3 maxu(maxud[0], maxud[1], maxud[2]);\n    vec3 diffu = maxu - minu;\n\n    vec3    binDimsF(xd, yd, zd);\n    ivec3   binDimsI(xd, yd, zd);\n    size_t  nbins = xd * yd * zd;\n    size_t *bins = new size_t[nbins];\n    for (size_t i = 0; i < nbins; i++) bins[i] = 0;\n\n    auto it = inGrid->ConstCoordBegin();\n    auto end = inGrid->ConstCoordEnd();\n    for (size_t j = 0; it != end && j < realNP; ++it, ++j) {\n        vec3  c((*it)[0], (*it)[1], (*it)[2]);\n        vec3  t = (c - minu) / diffu;\n        ivec3 i = t * binDimsF;\n        i = glm::clamp(i, ivec3(0), binDimsI - ivec3(1, 1, 1));\n        bins[i.z * yd * xd + i.y * xd + i.x]++;\n    }\n\n    for (size_t i = 0; i < nbins; i++) output[i] = bins[i];\n\n    delete[] bins;\n}\n\n\nint DerivedParticleDensity::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    DC::Mesh mesh;\n    _dataMgr->GetMesh(_meshName, mesh);\n    DC::Dimension dim;\n    for (auto dimName : mesh.GetDimNames()) {\n        _dataMgr->GetDimension(dimName, dim, -1);\n        dims_at_level.push_back(dim.GetLength());\n    }\n\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n    return 0;\n}\n\nbool DerivedParticleDensity::VariableExists(size_t ts, int reflevel, int lod) const { return true; }\n\nbool DerivedParticleDensity::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    DC::DataVar dvar;\n    GetDataVarInfo(dvar);\n    var = dvar;\n    return true;\n}\n\nbool DerivedParticleDensity::GetDataVarInfo(DC::DataVar &dvar) const\n{\n    if (_dataVar.empty()) return false;\n\n    dvar.SetName(_derivedVarName);\n    dvar.SetMeshName(_meshName);\n    dvar.SetUnits(\"\");\n    dvar.SetXType(DC::FLOAT);\n    dvar.SetWName(\"\");\n    dvar.SetCRatios(vector<size_t>());\n    dvar.SetPeriodic(vector<bool>(3, false));\n\n    //    dvar.SetHasMissing(true);\n    //    dvar.SetMissingValue(-1);\n\n    DC::DataVar dv;\n    _dc->GetDataVarInfo(_dataVar, dv);\n    dvar.SetTimeCoordVar(dv.GetTimeCoordVar());\n\n    return true;\n}\n\nvector<string> DerivedParticleDensity::GetInputs() const { return {_dataVar}; }\n\n\n// ===================================\n//       DerivedParticleAverage\n// ===================================\n\n\nDerivedParticleAverage::DerivedParticleAverage(string varName, DC *dc, string meshName, DataMgr *dataMgr, string inputVar) : DerivedParticleDensity(varName, dc, meshName, dataMgr)\n{\n    _dataVar = inputVar;\n}\n\nvoid DerivedParticleAverage::compute(Grid *inGrid, float *output, int xd, int yd, int zd, size_t realNP) const\n{\n    CoordType minud, maxud;\n    inGrid->GetUserExtents(minud, maxud);\n    vec3 minu(minud[0], minud[1], minud[2]);\n    vec3 maxu(maxud[0], maxud[1], maxud[2]);\n    vec3 diffu = maxu - minu;\n\n    vec3    binDimsF(xd, yd, zd);\n    ivec3   binDimsI(xd, yd, zd);\n    size_t  nbins = xd * yd * zd;\n    size_t *bins = new size_t[nbins];\n    double *accum = new double[nbins];\n    for (size_t i = 0; i < nbins; i++) {\n        bins[i] = 0;\n        accum[i] = 0;\n    }\n\n    auto it = inGrid->ConstCoordBegin();\n    auto dit = inGrid->cbegin();\n    auto end = inGrid->ConstCoordEnd();\n    for (size_t j = 0; it != end && j < realNP; ++it, ++dit, ++j) {\n        vec3  c((*it)[0], (*it)[1], (*it)[2]);\n        vec3  t = (c - minu) / diffu;\n        ivec3 i = t * binDimsF;\n        i = glm::clamp(i, ivec3(0), binDimsI - ivec3(1, 1, 1));\n        size_t index = i.z * yd * xd + i.y * xd + i.x;\n        bins[index]++;\n        accum[index] += *dit;\n    }\n\n    for (size_t i = 0; i < nbins; i++) output[i] = accum[i] / (float)bins[i];\n\n    delete[] accum;\n    delete[] bins;\n}\n\n\n// ===================================\n//        DerivedCoordVar1DSpan\n// ===================================\n\n\nDerivedCoordVar1DSpan::DerivedCoordVar1DSpan(string derivedVarName, DC *dc, string dimName, int axis, string units, float minExt, float maxExt)\n: DerivedCoordVar_CF1D(derivedVarName, dc, dimName, axis, units), _dc(dc), _minExt(minExt), _maxExt(maxExt)\n{\n    VAssert(maxExt >= minExt);\n}\n\nDerivedCoordVar1DSpan::DerivedCoordVar1DSpan(string derivedVarName, DC *dc, string dimName, int axis, string units, string inputCoordVar)\n: DerivedCoordVar1DSpan(derivedVarName, dc, dimName, axis, units, 0, 1)\n{\n    _inputCoordVar = inputCoordVar;\n}\n\nint DerivedCoordVar1DSpan::ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 1);\n    VAssert(max.size() == 1);\n    long ts = -1;\n\n    if (!_derivedVarName.empty()) {\n        if (!_dc->IsCoordVar(_inputCoordVar)) {\n            assert(0);\n            return -1;\n        }\n\n        DC::CoordVar cvInfo;\n        _dc->GetCoordVarInfo(_inputCoordVar, cvInfo);\n        auto dims = cvInfo.GetDimNames();\n        if (dims.size() != 1) {\n            assert(0);\n            return -1;\n        }\n\n        DC::CoordVar myInfo;\n        GetCoordVarInfo(myInfo);\n        if (myInfo.GetAxis() != cvInfo.GetAxis()) {\n            assert(0);\n            return -1;\n        }\n\n        DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n        if (!f) {\n            assert(0);\n            return -1;\n        }\n\n        DC::Dimension dim;\n        _dc->GetDimension(dims[0], dim, f->GetTS());\n        int fd = _dc->OpenVariableRead(f->GetTS(), _inputCoordVar);\n        if (fd < 0) {\n            assert(0);\n            return -1;\n        }\n        size_t nCoords = dim.GetLength();\n        float *coords = new float[nCoords];\n        ts = f->GetTS();\n\n        _dc->ReadRegion(fd, {0}, {nCoords - 1}, coords);\n        float min = FLT_MAX;\n        float max = -FLT_MAX;\n        for (size_t i = 0; i < nCoords; i++) {\n            min = std::min(min, coords[i]);\n            max = std::max(max, coords[i]);\n        }\n        _minExt = min;\n        _maxExt = max;\n\n        _dc->CloseVariable(fd);\n        delete[] coords;\n    }\n\n    DC::CoordVar cv;\n    GetCoordVarInfo(cv);\n    auto dims = cv.GetDimNames();\n    if (dims.size() != 1) {\n        assert(0);\n        return -1;\n    }\n    DC::Dimension dim;\n    _dc->GetDimension(dims[0], dim, ts);\n    size_t dimLen = dim.GetLength();\n\n    size_t n = 1 + max[0] - min[0];\n    if (n == 1) {\n        *region = (_maxExt + _minExt) / 2.f;\n    } else {\n        float diff = _maxExt - _minExt;\n        for (size_t i = 0; i < n; i++) {\n            size_t ri = i + min[0];\n            float  t = ri / (float)(dimLen - 1);\n            region[i] = t * diff + _minExt;\n        }\n    }\n\n    return 0;\n}\n\nvector<string> DerivedCoordVar1DSpan::GetInputs() const\n{\n    if (!_inputCoordVar.empty())\n        return {_inputCoordVar};\n    else\n        return {};\n}\n"
  },
  {
    "path": "lib/vdc/DerivedVar.cpp",
    "content": "#include \"vapor/VAssert.h\"\n#include <sstream>\n#include <algorithm>\n#include <set>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/NetCDFCollection.h>\n#include <vapor/utils.h>\n#include <vapor/WASP.h>\n#include <vapor/DerivedVar.h>\n#include <vapor/GeoUtil.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nnamespace {\n\n#ifdef UNUSED_FUNCTION\nsize_t numBlocks(size_t min, size_t max, size_t bs)\n{\n    size_t b0 = min / bs;\n    size_t b1 = max / bs;\n    return (b1 - b0 + 1);\n}\n#endif\n\n#ifdef UNUSED_FUNCTION\nsize_t numBlocks(const vector<size_t> &min, const vector<size_t> &max, const vector<size_t> &bs)\n{\n    VAssert(min.size() == max.size());\n    VAssert(min.size() == bs.size());\n\n    size_t nblocks = 1;\n    for (int i = 0; i < bs.size(); i++) { nblocks *= numBlocks(min[i], max[i], bs[i]); }\n    return (nblocks);\n}\n#endif\n\n#ifdef UNUSED_FUNCTION\nsize_t numBlocks(const vector<size_t> &dims, const vector<size_t> &bs)\n{\n    VAssert(dims.size() == bs.size());\n\n    size_t nblocks = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        VAssert(dims[i] != 0);\n        nblocks *= (((dims[i] - 1) / bs[i]) + 1);\n    }\n    return (nblocks);\n}\n#endif\n\nsize_t numElements(const vector<size_t> &min, const vector<size_t> &max)\n{\n    VAssert(min.size() == max.size());\n\n    size_t nElements = 1;\n    for (int i = 0; i < min.size(); i++) { nElements *= (max[i] - min[i] + 1); }\n    return (nElements);\n}\n\n#ifdef UNUSED_FUNCTION\nsize_t blockSize(const vector<size_t> &bs)\n{\n    size_t sz = 1;\n    for (int i = 0; i < bs.size(); i++) { sz *= bs[i]; }\n    return (sz);\n}\n#endif\n\n#ifdef UNUSED_FUNCTION\nvector<size_t> increment(vector<size_t> dims, vector<size_t> coord)\n{\n    VAssert(dims.size() == coord.size());\n\n    for (int i = 0; i < coord.size(); i++) {\n        coord[i] += 1;\n        if (coord[i] < (dims[i])) { break; }\n        coord[i] = 0;\n    }\n    return (coord);\n}\n#endif\n\n// Product of elements in a vector\n//\nsize_t vproduct(vector<size_t> a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n\n#ifdef UNUSED_FUNCTION\nvoid extractBlock(const float *data, const vector<size_t> &dims, const vector<size_t> &bcoords, const vector<size_t> &bs, float *block)\n{\n    VAssert(dims.size() == bcoords.size());\n    VAssert(dims.size() == bs.size());\n\n    // Block dimensions\n    //\n    size_t bz = bs.size() > 2 ? bs[2] : 1;\n    size_t by = bs.size() > 1 ? bs[1] : 1;\n    size_t bx = bs.size() > 0 ? bs[0] : 1;\n\n    // Data dimensions\n    //\n    size_t nz = dims.size() > 2 ? dims[2] : 1;\n    size_t ny = dims.size() > 1 ? dims[1] : 1;\n    size_t nx = dims.size() > 0 ? dims[0] : 1;\n\n    // Data dimensions\n    //\n    size_t bcz = bcoords.size() > 2 ? bcoords[2] : 0;\n    size_t bcy = bcoords.size() > 1 ? bcoords[1] : 0;\n    size_t bcx = bcoords.size() > 0 ? bcoords[0] : 0;\n\n    size_t z = bcz * bz;\n    for (size_t zb = 0; zb < bz && z < nz; zb++, z++) {\n        size_t y = bcy * by;\n\n        for (size_t yb = 0; yb < by && y < ny; yb++, y++) {\n            size_t x = bcx * bx;\n\n            for (size_t xb = 0; xb < bx && x < nx; xb++, x++) { block[bx * by * zb + bx * yb + xb] = data[nx * ny * z + nx * y + x]; }\n        }\n    }\n}\n#endif\n\n#ifdef UNUSED_FUNCTION\nvoid blockit(const float *data, const vector<size_t> &dims, const vector<size_t> &bs, float *blocks)\n{\n    VAssert(dims.size() == bs.size());\n\n    size_t block_size = vproduct(bs);\n\n    vector<size_t> bdims;\n    for (int i = 0; i < bs.size(); i++) {\n        VAssert(dims[i] > 0);\n        bdims.push_back(((dims[i] - 1) / bs[i]) + 1);\n    }\n\n    size_t nbz = bdims.size() > 2 ? bdims[2] : 1;\n    size_t nby = bdims.size() > 1 ? bdims[1] : 1;\n    size_t nbx = bdims.size() > 0 ? bdims[0] : 1;\n\n    float *        blockptr = blocks;\n    vector<size_t> bcoord(bdims.size(), 0);\n\n    for (size_t zb = 0; zb < nbz; zb++) {\n        for (size_t yb = 0; yb < nby; yb++) {\n            for (size_t xb = 0; xb < nbx; xb++) {\n                extractBlock(data, dims, bcoord, bs, blockptr);\n                blockptr += block_size;\n                bcoord = increment(bdims, bcoord);\n            }\n        }\n    }\n}\n#endif\n\n// make 2D lat and lon arrays from 1D arrays by replication, in place\n//\nvoid make2D(float *lonBuf, float *latBuf, vector<size_t> dims)\n{\n    VAssert(dims.size() == 2);\n    size_t nx = dims[0];\n    size_t ny = dims[1];\n\n    // longitude\n    //\n    for (int j = 1; j < ny; j++) {\n        for (int i = 0; i < nx; i++) { lonBuf[j * nx + i] = lonBuf[i]; }\n    }\n\n    // latitude requires a transpose first\n    //\n    for (int i = 0; i < ny; i++) { latBuf[i * nx] = latBuf[i]; }\n\n    for (int j = 0; j < ny; j++) {\n        for (int i = 1; i < nx; i++) { latBuf[j * nx + i] = latBuf[j * nx]; }\n    }\n}\n\n// Transpose a 1D, 2D, or 3D array. For 1D 'a' is simply copied\n// to 'b'. Otherwise 'b' contains a permuted version of 'a' as follows:\n//\n//    axis        1D        2D        3D\n//    ----        --        --        --\n//    0\t          (0)       (0,1)     (0,1,2)\n//    1\t          N/A       (1,0)     (1,0,2)\n//    2\t          N/A       N/A       (2,0,1)\n//\n// where the numbers in parenthesis indicate the permutation of the\n// axes.\n//\n// NOTE: The contents of 'a' are overwritten\n//\nvoid transpose(float *a, float *b, vector<size_t> inDims, int axis)\n{\n    VAssert(inDims.size() < 4);\n    VAssert(axis >= 0 && axis < inDims.size());\n\n    size_t sz = vproduct(inDims);\n\n    // No-op if axis is 0\n    //\n    if (axis == 0) {    // 1D, 2D, and 3D case\n        for (size_t i = 0; i < sz; i++) { b[i] = a[i]; }\n        return;\n    }\n\n    if (inDims.size() == 2) {\n        VAssert(axis == 1);\n\n        Wasp::Transpose(a, b, inDims[0], inDims[1]);\n    } else if (inDims.size() == 3) {\n        VAssert(axis == 1 || axis == 2);\n\n        size_t stride = inDims[0] * inDims[1];\n        ;\n        const float *aptr = a;\n        float *      bptr = b;\n        for (size_t i = 0; i < inDims[2]; i++) {\n            Wasp::Transpose(aptr, bptr, inDims[0], inDims[1]);\n            aptr += stride;\n            bptr += stride;\n        }\n\n        // For (2,1,0) permutation we do (0,1,2) -> (1,0,2) -> (2,1,0)\n        //\n        if (axis == 2) {\n            // We can treat 3D array as 2D in this case, linearizing X and Y\n            //\n            Wasp::Transpose(b, a, inDims[0] * inDims[1], inDims[2]);\n\n            // Ugh need to copy data from a back to b\n            //\n            for (size_t i = 0; i < vproduct(inDims); i++) { b[i] = a[i]; }\n        }\n    }\n}\n\nvoid transpose(vector<size_t> inDims, int axis, vector<size_t> &outDims)\n{\n    outDims = inDims;\n\n    if (axis == 1) {\n        size_t tmp = outDims[0];\n        outDims[0] = outDims[1];\n        outDims[1] = tmp;\n    } else if (axis == 2) {\n        size_t tmp = outDims[0];\n        outDims[0] = outDims[2];\n        outDims[2] = tmp;\n    }\n}\n\nvoid resampleToStaggered(float *src, const vector<size_t> &inMin, const vector<size_t> &inMax, float *dst, const vector<size_t> &outMin, const vector<size_t> &outMax, int stagDim)\n{\n    VAssert(inMin.size() == inMax.size());\n    VAssert(inMin.size() == outMax.size());\n    VAssert(inMin.size() == outMax.size());\n\n    vector<size_t> inDims, outDims;\n    for (size_t i = 0; i < outMin.size(); i++) {\n        inDims.push_back(inMax[i] - inMin[i] + 1);\n        outDims.push_back(outMax[i] - outMin[i] + 1);\n    }\n    size_t sz = std::max(vproduct(outDims), vproduct(inDims));\n\n    float *buf = new float[sz];\n\n    // Tranpose the dimensions and array so that we always interpolate\n    // with unit stride\n    //\n    vector<size_t> inDimsT;     // transposed input dimensions\n    vector<size_t> outDimsT;    // transposed output dimensions\n    transpose(inDims, stagDim, inDimsT);\n    transpose(outDims, stagDim, outDimsT);\n\n    transpose(src, buf, inDims, stagDim);\n\n    size_t nz = inDimsT.size() >= 3 ? inDimsT[2] : 1;\n    size_t ny = inDimsT.size() >= 2 ? inDimsT[1] : 1;\n    size_t nx = inDimsT.size() >= 1 ? inDimsT[0] : 1;\n\n    // Interpolate interior\n    //\n    size_t nxs = outDimsT[0];    // staggered dimension\n    size_t i0 = outMin[stagDim] > inMin[stagDim] ? 0 : 1;\n\n    for (size_t k = 0; k < nz; k++) {\n        for (size_t j = 0; j < ny; j++) {\n            for (size_t i = 0, ii = i0; i < nx - 1; i++, ii++) { src[k * nxs * ny + j * nxs + ii] = 0.5 * (buf[k * nx * ny + j * nx + i] + buf[k * nx * ny + j * nx + i + 1]); }\n        }\n    }\n\n    // Next extrapolate boundary points if needed\n    //\n    // left boundary\n    //\n    if (outMin[stagDim] <= inMin[stagDim]) {\n        if (inMin[stagDim] < inMax[stagDim]) {\n            for (size_t k = 0; k < nz; k++) {\n                for (size_t j = 0; j < ny; j++) { src[k * nxs * ny + j * nxs] = buf[k * nx * ny + j * nx + 0] + (-0.5 * (buf[k * nx * ny + j * nx + 1] - buf[k * nx * ny + j * nx + 0])); }\n            }\n        } else {\n            for (size_t k = 0; k < nz; k++) {\n                for (size_t j = 0; j < ny; j++) { src[k * nxs * ny + j * nxs] = buf[k * nx * ny + j * nx + 0]; }\n            }\n        }\n    }\n\n    // right boundary\n    //\n    if (outMax[stagDim] > inMax[stagDim]) {\n        if (inMin[stagDim] < inMax[stagDim]) {\n            for (size_t k = 0; k < nz; k++) {\n                for (size_t j = 0; j < ny; j++) {\n                    src[k * nxs * ny + j * nxs + nxs - 1] = buf[k * nx * ny + j * nx + nx - 1] + (0.5 * (buf[k * nx * ny + j * nx + nx - 1] - buf[k * nx * ny + j * nx + nx - 2]));\n                }\n            }\n        } else {\n            for (size_t k = 0; k < nz; k++) {\n                for (size_t j = 0; j < ny; j++) { src[k * nxs * ny + j * nxs + nxs - 1] = buf[k * nx * ny + j * nx + nx - 1]; }\n            }\n        }\n    }\n\n    // Undo tranpose\n    //\n    transpose(src, dst, outDimsT, stagDim);\n\n    delete[] buf;\n}\n\nvoid resampleToUnStaggered(float *src, const vector<size_t> &inMin, const vector<size_t> &inMax, float *dst, const vector<size_t> &outMin, const vector<size_t> &outMax, int stagDim)\n{\n    VAssert(inMin.size() == inMax.size());\n    VAssert(inMin.size() == outMax.size());\n    VAssert(inMin.size() == outMax.size());\n\n    vector<size_t> myOutMax = outMax;\n    vector<size_t> myOutMin = outMin;\n\n    myOutMin[stagDim] += 1;\n    myOutMax[stagDim] += 1;\n\n    resampleToStaggered(src, inMin, inMax, dst, myOutMin, myOutMax, stagDim);\n}\n\n#ifdef UNIT_TEST\n\nvoid print_matrix(const float *a, const vector<size_t> &dims)\n{\n    size_t nz = dims.size() >= 3 ? dims[2] : 1;\n    size_t ny = dims.size() >= 2 ? dims[1] : 1;\n    size_t nx = dims.size() >= 1 ? dims[0] : 1;\n\n    for (int k = 0; k < nz; k++) {\n        for (int j = 0; j < ny; j++) {\n            for (int i = 0; i < nx; i++) { cout << a[k * nx * ny + j * nx + i] << \" \"; }\n            cout << endl;\n        }\n        cout << endl;\n    }\n}\n\nvoid test_resample(int stagDim)\n{\n    vector<size_t> inMin = {0, 0, 0};\n    vector<size_t> inMax = {1, 2, 3};\n\n    vector<size_t> outMin = inMin;\n    vector<size_t> outMax = inMax;\n\n    outMax[stagDim] += 1;\n\n    vector<size_t> inDims, outDims;\n    for (int i = 0; i < inMax.size(); i++) {\n        inDims.push_back(inMax[i] - inMin[i] + 1);\n        outDims.push_back(outMax[i] - outMin[i] + 1);\n    }\n\n    size_t nz = inDims.size() >= 3 ? inDims[2] : 1;\n    size_t ny = inDims.size() >= 2 ? inDims[1] : 1;\n    size_t nx = inDims.size() >= 1 ? inDims[0] : 1;\n\n    size_t nzs = outDims.size() >= 3 ? outDims[2] : 1;\n    size_t nys = outDims.size() >= 2 ? outDims[1] : 1;\n    size_t nxs = outDims.size() >= 1 ? outDims[0] : 1;\n\n    size_t sz = std::max(vproduct(outDims), vproduct(inDims));\n    float *src = new float[sz];\n    float *dst = new float[sz];\n\n    for (int k = 0; k < nz; k++) {\n        for (int j = 0; j < ny; j++) {\n            for (int i = 0; i < nx; i++) { src[k * nx * ny + j * nx + i] = k * nx * ny + j * nx + i; }\n        }\n    }\n\n    for (int k = 0; k < nzs; k++) {\n        for (int j = 0; j < nys; j++) {\n            for (int i = 0; i < nxs; i++) { dst[k * nxs * nys + j * nxs + i] = 99; }\n        }\n    }\n\n    cout << \"original array\" << endl;\n    print_matrix(src, inDims);\n\n    resampleToStaggered(src, inMin, inMax, dst, outMin, outMax, stagDim);\n\n    cout << endl << endl;\n\n    cout << \"staggered array\" << endl;\n    print_matrix(dst, outDims);\n\n    resampleToUnStaggered(dst, outMin, outMax, src, inMin, inMax, stagDim);\n\n    cout << \"reconstructed unstaggered array\" << endl;\n    print_matrix(src, inDims);\n}\n\nint main(int argc, char **argv)\n{\n    VAssert(argc == 2);\n    int stagDim = atoi(argv[1]);\n    test_resample(stagDim);\n}\n\n#endif\n\n};    // namespace\n\nint DerivedVar::_getVar(DC *dc, size_t ts, string varname, int level, int lod, const vector<size_t> &min, const vector<size_t> &max, float *region) const\n{\n    int fd = dc->OpenVariableRead(ts, varname, level, lod);\n    if (fd < 0) return (-1);\n\n    int rc = dc->ReadRegion(fd, min, max, region);\n    if (rc < 0) {\n        dc->CloseVariable(fd);\n        return (-1);\n    }\n\n    return (dc->CloseVariable(fd));\n}\n\nint DerivedVar::_getVarDestagger(DC *dc, size_t ts, string varname, int level, int lod, const vector<size_t> &min, const vector<size_t> &max, float *region, int stagDim) const\n{\n    VAssert(stagDim >= 0 && stagDim < max.size());\n    VAssert(min.size() == max.size());\n\n    vector<size_t> maxIn = max;\n    maxIn[stagDim]++;\n\n    vector<size_t> dimsIn;\n    for (int i = 0; i < min.size(); i++) { dimsIn.push_back(max[i] - min[i] + 1); }\n    vector<float> buf(vproduct(dimsIn));\n\n    int rc = _getVar(dc, ts, varname, level, lod, min, maxIn, buf.data());\n    if (rc < 0) return (rc);\n\n    resampleToUnStaggered(buf.data(), min, maxIn, region, min, max, stagDim);\n\n    return (0);\n}\n\n\nint DerivedVar::ReadRegion(int fd, const std::vector<size_t> &min, const std::vector<size_t> &max, double *region)\n{\n    SetErrMsg(\"Not implemented\");\n    return (-1);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVar_PCSFromLatLon\n//\n//////////////////////////////////////////////////////////////////////////////\n\nDerivedCoordVar_PCSFromLatLon::DerivedCoordVar_PCSFromLatLon(string derivedVarName, DC *dc, vector<string> inNames, string proj4String, bool uGridFlag, bool lonFlag) : DerivedCoordVar(derivedVarName)\n{\n    VAssert(inNames.size() == 2);\n\n    _dc = dc;\n    _proj4String = proj4String;\n    _lonName = inNames[0];\n    _latName = inNames[1];\n    _make2DFlag = false;\n    _uGridFlag = uGridFlag;\n    _lonFlag = lonFlag;\n    _dimLens.clear();\n}\n\nint DerivedCoordVar_PCSFromLatLon::Initialize()\n{\n    int rc = _proj4API.Initialize(\"\", _proj4String);\n    if (rc < 0) {\n        SetErrMsg(\"Invalid map projection : %s\", _proj4String.c_str());\n        return (-1);\n    }\n\n    rc = _setupVar();\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\nbool DerivedCoordVar_PCSFromLatLon::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVar_PCSFromLatLon::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVar_PCSFromLatLon::GetDimLensAtLevel(int, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    dims_at_level = _dimLens;\n\n    // No blocking\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DerivedCoordVar_PCSFromLatLon::OpenVariableRead(size_t ts, int, int)\n{\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, -1, -1);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVar_PCSFromLatLon::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n    return (0);\n}\nint DerivedCoordVar_PCSFromLatLon::_readRegionHelperCylindrical(DC::FileTable::FileObject *f, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 1);\n    VAssert(min.size() == max.size());\n\n    size_t ts = f->GetTS();\n    string varname = f->GetVarname();\n    int    lod = f->GetLOD();\n\n    size_t        nElements = max[0] - min[0] + 1;\n    vector<float> buf(nElements, 0.0);\n\n    string geoCoordVar;\n    if (_lonFlag) {\n        geoCoordVar = _lonName;\n    } else {\n        geoCoordVar = _latName;\n    }\n\n    int rc = _getVar(_dc, ts, geoCoordVar, -1, lod, min, max, region);\n    if (rc < 0) { return (rc); }\n\n    if (_lonFlag) {\n        rc = _proj4API.Transform(region, buf.data(), nElements);\n    } else {\n        rc = _proj4API.Transform(buf.data(), region, nElements);\n    }\n\n    return (rc);\n}\n\nint DerivedCoordVar_PCSFromLatLon::_readRegionHelper1D(DC::FileTable::FileObject *f, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    size_t ts = f->GetTS();\n    string varname = f->GetVarname();\n    int    lod = f->GetLOD();\n\n    // Need temporary buffer space for the X or Y coordinate\n    // NOT being returned (we still need to calculate it)\n    //\n    size_t        nElements = numElements(min, max);\n    vector<float> buf(nElements);\n\n    vector<size_t> roidims;\n    for (int i = 0; i < min.size(); i++) { roidims.push_back(max[i] - min[i] + 1); }\n\n    // Assign temporary buffer 'buf' as appropriate\n    //\n    float *lonBufPtr;\n    float *latBufPtr;\n    if (_lonFlag) {\n        lonBufPtr = region;\n        latBufPtr = buf.data();\n    } else {\n        lonBufPtr = buf.data();\n        latBufPtr = region;\n    }\n\n    // Reading 1D data so no blocking\n    //\n    vector<size_t> lonMin = {min[0]};\n    vector<size_t> lonMax = {max[0]};\n    int            rc = _getVar(_dc, ts, _lonName, -1, lod, lonMin, lonMax, lonBufPtr);\n    if (rc < 0) { return (rc); }\n\n    vector<size_t> latMin = {min[1]};\n    vector<size_t> latMax = {max[1]};\n    rc = _getVar(_dc, ts, _latName, -1, lod, latMin, latMax, latBufPtr);\n    if (rc < 0) { return (rc); }\n\n    // Combine the 2 1D arrays into a 2D array\n    //\n    make2D(lonBufPtr, latBufPtr, roidims);\n\n    rc = _proj4API.Transform(lonBufPtr, latBufPtr, vproduct(roidims));\n\n    return (rc);\n}\n\nint DerivedCoordVar_PCSFromLatLon::_readRegionHelper2D(DC::FileTable::FileObject *f, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    size_t ts = f->GetTS();\n    string varname = f->GetVarname();\n    int    lod = f->GetLOD();\n\n    // Need temporary buffer space for the X or Y coordinate\n    // NOT being returned (we still need to calculate it)\n    //\n    size_t        nElements = numElements(min, max);\n    vector<float> buf(nElements);\n\n    // Assign temporary buffer 'buf' as appropriate\n    //\n    float *lonBufPtr;\n    float *latBufPtr;\n    if (_lonFlag) {\n        lonBufPtr = region;\n        latBufPtr = buf.data();\n    } else {\n        lonBufPtr = buf.data();\n        latBufPtr = region;\n    }\n\n    int rc = _getVar(_dc, ts, _lonName, -1, lod, min, max, lonBufPtr);\n    if (rc < 0) { return (rc); }\n\n    rc = _getVar(_dc, ts, _latName, -1, lod, min, max, latBufPtr);\n    if (rc < 0) { return (rc); }\n\n    rc = _proj4API.Transform(lonBufPtr, latBufPtr, nElements);\n\n\n    return (rc);\n}\n\nint DerivedCoordVar_PCSFromLatLon::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor: %d\", fd);\n        return (-1);\n    }\n\n    if (min.size() == 1) {\n        // Lat and Lon are 1D variables\n        //\n        return (_readRegionHelperCylindrical(f, min, max, region));\n    } else {\n        if (_make2DFlag) {\n            // Lat and Lon are 1D variables but projections to PCS\n            // result in X and Y coordinate variables that are 2D\n            //\n            return (_readRegionHelper1D(f, min, max, region));\n        } else {\n            return (_readRegionHelper2D(f, min, max, region));\n        }\n    }\n}\n\nbool DerivedCoordVar_PCSFromLatLon::VariableExists(size_t ts, int, int) const { return (_dc->VariableExists(ts, _lonName, -1, -1) && _dc->VariableExists(ts, _latName, -1, -1)); }\n\nint DerivedCoordVar_PCSFromLatLon::_setupVar()\n{\n    DC::CoordVar lonVar;\n    bool         ok = _dc->GetCoordVarInfo(_lonName, lonVar);\n    if (!ok) return (-1);\n\n    DC::CoordVar latVar;\n    ok = _dc->GetCoordVarInfo(_latName, latVar);\n    if (!ok) return (-1);\n\n    vector<size_t> lonDims;\n    ok = _dc->GetVarDimLens(_lonName, true, lonDims, -1);\n    if (!ok) {\n        SetErrMsg(\"GetVarDimLens(%s) failed\", _lonName.c_str());\n        return (-1);\n    }\n\n    vector<size_t> latDims;\n    ok = _dc->GetVarDimLens(_latName, true, latDims, -1);\n    if (!ok) {\n        SetErrMsg(\"GetVarDimLens(%s) failed\", _lonName.c_str());\n        return (-1);\n    }\n\n    if (lonDims.size() != latDims.size()) {\n        SetErrMsg(\"Incompatible block size\");\n        return (-1);\n    }\n\n    bool cylProj = _proj4API.IsCylindrical();\n\n    vector<string> dimNames;\n    if (lonVar.GetDimNames().size() == 1 && !_uGridFlag) {\n        if (cylProj) {\n            if (_lonFlag) {\n                dimNames.push_back(lonVar.GetDimNames()[0]);\n                _dimLens.push_back(lonDims[0]);\n            } else {\n                dimNames.push_back(latVar.GetDimNames()[0]);\n                _dimLens.push_back(latDims[0]);\n            }\n        } else {\n            dimNames.push_back(lonVar.GetDimNames()[0]);\n            dimNames.push_back(latVar.GetDimNames()[0]);\n            _dimLens.push_back(lonDims[0]);\n            _dimLens.push_back(latDims[0]);\n            _make2DFlag = true;\n        }\n    } else if (lonVar.GetDimNames().size() == 2 && !_uGridFlag) {\n        if (lonDims[0] != latDims[0] && lonDims[1] != latDims[1]) {\n            SetErrMsg(\"Incompatible dimensions \");\n            return (-1);\n        }\n        dimNames.push_back(lonVar.GetDimNames()[0]);\n        dimNames.push_back(lonVar.GetDimNames()[1]);\n        _dimLens.push_back(lonDims[0]);\n        _dimLens.push_back(lonDims[1]);\n        _make2DFlag = false;\n    } else {\n        VAssert(lonVar.GetDimNames().size() == 1 && _uGridFlag);\n        dimNames = lonVar.GetDimNames();\n        _dimLens = lonDims;\n    }\n\n    if (lonVar.GetTimeDimName() != latVar.GetTimeDimName()) {\n        SetErrMsg(\"Incompatible time dimensions\");\n        return (-1);\n    }\n    string timeDimName = lonVar.GetTimeDimName();\n\n    DC::XType    xtype = lonVar.GetXType();\n    vector<bool> periodic = lonVar.GetPeriodic();\n\n    _coordVarInfo.SetName(_derivedVarName);\n    _coordVarInfo.SetUnits(\"meters\");\n    _coordVarInfo.SetXType(xtype);\n    _coordVarInfo.SetWName(\"\");\n    _coordVarInfo.SetCRatios(vector<size_t>());\n    _coordVarInfo.SetPeriodic(periodic);\n    _coordVarInfo.SetUniform(false);\n\n    _coordVarInfo.SetDimNames(dimNames);\n    _coordVarInfo.SetTimeDimName(timeDimName);\n\n    _coordVarInfo.SetAxis(_lonFlag ? 0 : 1);\n\n    return (0);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVar_CF1D\n//\n//////////////////////////////////////////////////////////////////////////////\n\nDerivedCoordVar_CF1D::DerivedCoordVar_CF1D(string derivedVarName, DC *dc, string dimName, int axis, string units) : DerivedCoordVar(derivedVarName)\n{\n    _dc = dc;\n    _dimName = dimName;\n\n    _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector<bool>(1, false), axis, true, vector<string>(1, dimName), \"\");\n}\n\nint DerivedCoordVar_CF1D::Initialize() { return (0); }\n\nbool DerivedCoordVar_CF1D::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVar_CF1D::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVar_CF1D::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const { return GetDimLensAtLevel(level, dims_at_level, bs_at_level, -1); }\n\nint DerivedCoordVar_CF1D::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level, long ts) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    DC::Dimension dimension;\n    int           rc = _dc->GetDimension(_dimName, dimension, ts);\n    if (rc < 0) return (-1);\n\n    dims_at_level.push_back(dimension.GetLength());\n\n    // No blocking\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DerivedCoordVar_CF1D::OpenVariableRead(size_t ts, int level, int lod)\n{\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVar_CF1D::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nint DerivedCoordVar_CF1D::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 1);\n    VAssert(max.size() == 1);\n\n    float *regptr = region;\n    for (size_t i = min[0]; i <= max[0]; i++) { *regptr++ = (float)i; }\n\n    return (0);\n}\n\nbool DerivedCoordVar_CF1D::VariableExists(size_t ts, int reflevel, int lod) const\n{\n    if (reflevel != 0) return (false);\n    if (lod != 0) return (false);\n\n    return (true);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVar_CF2D\n//\n//////////////////////////////////////////////////////////////////////////////\n\nDerivedCoordVar_CF2D::DerivedCoordVar_CF2D(string derivedVarName, vector<string> dimNames, vector<size_t> dimLens, int axis, string units, const vector<float> &data) : DerivedCoordVar(derivedVarName)\n{\n    VAssert(dimNames.size() == 2);\n    VAssert(dimLens.size() == 2);\n    VAssert(dimLens[0] * dimLens[1] <= data.size());\n\n    _dimNames = dimNames;\n    _dimLens = dimLens;\n    _data = data;\n\n    _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector<bool>(2, false), axis, false, dimNames, \"\");\n}\n\nint DerivedCoordVar_CF2D::Initialize() { return (0); }\n\nbool DerivedCoordVar_CF2D::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVar_CF2D::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVar_CF2D::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    dims_at_level = _dimLens;\n\n    // No blocking\n    //\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DerivedCoordVar_CF2D::OpenVariableRead(size_t ts, int level, int lod) { return (0); }\n\nint DerivedCoordVar_CF2D::CloseVariable(int fd) { return (0); }\n\nint DerivedCoordVar_CF2D::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 2);\n    VAssert(max.size() == 2);\n\n    float *regptr = region;\n    for (size_t j = min[1]; j <= max[1]; j++) {\n        for (size_t i = min[0]; i <= max[0]; i++) { *regptr++ = (float)_data[j * _dimLens[0] + i]; }\n    }\n\n    return (0);\n}\n\nbool DerivedCoordVar_CF2D::VariableExists(size_t ts, int reflevel, int lod) const\n{\n    if (reflevel != 0) return (false);\n    if (lod != 0) return (false);\n\n    return (true);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVar_WRFTime\n//\n//////////////////////////////////////////////////////////////////////////////\n\nDerivedCoordVar_WRFTime::DerivedCoordVar_WRFTime(string derivedVarName, NetCDFCollection *ncdfc, string wrfTimeVar, string dimName, float p2si) : DerivedCoordVar(derivedVarName)\n{\n    _ncdfc = ncdfc;\n    _times.clear();\n    _timePerm.clear();\n    _wrfTimeVar = wrfTimeVar;\n    _p2si = p2si;\n    _ovr_ts = 0;\n\n    string units = \"seconds\";\n    int    axis = 3;\n    _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector<bool>(), axis, false, vector<string>(), dimName);\n}\n\nint DerivedCoordVar_WRFTime::_encodeTime(UDUnits &udunits, const vector<string> &timeStrings, vector<double> &times) const\n{\n    times.clear();\n\n    for (int i = 0; i < timeStrings.size(); i++) {\n        const string &s = timeStrings[i];\n\n        const char *format6 = \"%4d-%2d-%2d_%2d:%2d:%2d\";\n        int         year, mon, mday, hour, min, sec;\n        int         rc = sscanf(s.data(), format6, &year, &mon, &mday, &hour, &min, &sec);\n        if (rc != 6) {\n            // Alternate date format\n            //\n            const char *format5 = \"%4d-%5d_%2d:%2d:%2d\";\n            rc = sscanf(s.data(), format5, &year, &mday, &hour, &min, &sec);\n            if (rc != 5) {\n                SetErrMsg(\"Unrecognized time stamp: %s\", s.data());\n                return (-1);\n            }\n            mon = 1;\n        }\n\n        times.push_back(udunits.EncodeTime(year, mon, mday, hour, min, sec) * _p2si);\n    }\n    return (0);\n}\n\nint DerivedCoordVar_WRFTime::Initialize()\n{\n    _times.clear();\n    _timePerm.clear();\n\n    // Use UDUnits for unit conversion\n    //\n    UDUnits udunits;\n    int     rc = udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n    size_t numTS = _ncdfc->GetNumTimeSteps();\n    if (numTS < 1) return (0);\n\n    vector<size_t> dims = _ncdfc->GetSpatialDims(_wrfTimeVar);\n    if (dims.size() != 1) {\n        SetErrMsg(\"Invalid WRF time variable : %s\", _wrfTimeVar.c_str());\n        return (-1);\n    }\n\n    // Read all of the formatted time strings up front - it's a 1D array\n    // so we can simply store the results in memory - and convert from\n    // a formatted time string to seconds since the EPOCH\n    //\n    vector<string> timeStrings;\n    char *         buf = new char[dims[0] + 1];\n    buf[dims[0]] = '\\0';\n    for (size_t ts = 0; ts < numTS; ts++) {\n        int fd = _ncdfc->OpenRead(ts, _wrfTimeVar);\n        if (fd < 0) {\n            SetErrMsg(\"Can't read time variable\");\n            return (-1);\n        }\n\n        int rc = _ncdfc->Read(buf, fd);\n        if (rc < 0) {\n            SetErrMsg(\"Can't read time variable\");\n            _ncdfc->Close(fd);\n            delete[] buf;\n            return (-1);\n        }\n        _ncdfc->Close(fd);\n\n        timeStrings.push_back(buf);\n    }\n    delete[] buf;\n\n    // Encode time stamp string as double precision float\n    //\n    rc = _encodeTime(udunits, timeStrings, _times);\n    if (rc < 0) return (rc);\n\n    // The NetCDFCollection class doesn't handle the WRF time\n    // variable. Hence, the time steps aren't sorted. Sort them now and\n    // create a lookup table to map a time index to the correct time step\n    // in the WRF data collection. N.B. this is only necessary if multiple\n    // WRF files are present and they're not passed to Initialize() in\n    // the correct order.\n    //\n\n    _timePerm.clear();\n    for (int i = 0; i != _times.size(); i++) { _timePerm.push_back(i); }\n    sort(_timePerm.begin(), _timePerm.end(), [&](const int &a, const int &b) { return (_times[a] < _times[b]); });\n\n    return (0);\n}\n\nbool DerivedCoordVar_WRFTime::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVar_WRFTime::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVar_WRFTime::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    return (0);\n}\n\nint DerivedCoordVar_WRFTime::OpenVariableRead(size_t ts, int level, int lod)\n{\n    ts = ts < _times.size() ? ts : _times.size() - 1;\n\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVar_WRFTime::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nint DerivedCoordVar_WRFTime::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 0);\n    VAssert(max.size() == 0);\n\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor: %d\", fd);\n        return (-1);\n    }\n\n    size_t ts = f->GetTS();\n\n    *region = _times[ts];\n\n    return (0);\n}\n\nint DerivedCoordVar_WRFTime::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region)\n{\n    VAssert(min.size() == 0);\n    VAssert(max.size() == 0);\n\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor: %d\", fd);\n        return (-1);\n    }\n\n    size_t ts = f->GetTS();\n\n    *region = _times[ts];\n\n    return (0);\n}\n\nbool DerivedCoordVar_WRFTime::VariableExists(size_t ts, int reflevel, int lod) const { return (ts < _times.size()); }\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVar_TimeInSeconds\n//\n//////////////////////////////////////////////////////////////////////////////\n\nDerivedCoordVar_TimeInSeconds::DerivedCoordVar_TimeInSeconds(string derivedVarName, DC *dc, string nativeTimeVar, string dimName) : DerivedCoordVar(derivedVarName)\n{\n    _dc = dc;\n    _times.clear();\n    _nativeTimeVar = nativeTimeVar;\n\n    string units = \"seconds\";\n    int    axis = 3;\n    _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector<bool>(), axis, false, vector<string>(), dimName);\n}\n\nint DerivedCoordVar_TimeInSeconds::Initialize()\n{\n    // Use UDUnits for unit conversion\n    //\n    UDUnits udunits;\n    int     rc = udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n    DC::CoordVar cvar;\n    bool         status = _dc->GetCoordVarInfo(_nativeTimeVar, cvar);\n    if (!status) {\n        SetErrMsg(\"Invalid coordinate variable %s\", _nativeTimeVar.c_str());\n        return (-1);\n    }\n\n    if (!udunits.IsTimeUnit(cvar.GetUnits())) {\n        SetErrMsg(\"Invalid coordinate variable %s\", _nativeTimeVar.c_str());\n        return (-1);\n    }\n\n    size_t numTS = _dc->GetNumTimeSteps(_nativeTimeVar);\n\n    //\n    double *dbuf = new double[2 * numTS];\n    double *dbufptr1 = dbuf;\n    double *dbufptr2 = dbuf + numTS;\n\n    rc = _dc->GetVar(_nativeTimeVar, -1, -1, dbuf);\n    if (rc < 0) {\n        SetErrMsg(\"Can't read time variable\");\n        return (-1);\n    }\n    for (int i = 0; i < numTS; i++) { dbufptr1[i] = (double)dbuf[i]; }\n\n    status = udunits.Convert(cvar.GetUnits(), \"seconds\", dbufptr1, dbufptr2, numTS);\n    if (!status) {\n        SetErrMsg(\"Invalid coordinate variable %s\", _nativeTimeVar.c_str());\n        return (-1);\n    }\n\n    _times.clear();\n    for (int i = 0; i < numTS; i++) { _times.push_back(dbufptr2[i]); }\n    delete[] dbuf;\n\n    return (0);\n}\n\nbool DerivedCoordVar_TimeInSeconds::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVar_TimeInSeconds::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVar_TimeInSeconds::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    return (0);\n}\n\nint DerivedCoordVar_TimeInSeconds::OpenVariableRead(size_t ts, int level, int lod)\n{\n    ts = ts < _times.size() ? ts : _times.size() - 1;\n\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVar_TimeInSeconds::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nint DerivedCoordVar_TimeInSeconds::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 0);\n    VAssert(max.size() == 0);\n\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor: %d\", fd);\n        return (-1);\n    }\n\n    size_t ts = f->GetTS();\n\n    *region = _times[ts];\n\n    return (0);\n}\n\nint DerivedCoordVar_TimeInSeconds::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region)\n{\n    VAssert(min.size() == 0);\n    VAssert(max.size() == 0);\n\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor: %d\", fd);\n        return (-1);\n    }\n\n    size_t ts = f->GetTS();\n\n    *region = _times[ts];\n\n    return (0);\n}\n\nbool DerivedCoordVar_TimeInSeconds::VariableExists(size_t ts, int reflevel, int lod) const { return (ts < _times.size()); }\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVar_Time\n//\n//////////////////////////////////////////////////////////////////////////////\n\nDerivedCoordVar_Time::DerivedCoordVar_Time(string derivedVarName, string dimName, size_t n) : DerivedCoordVar(derivedVarName)\n{\n    _times.clear();\n    for (size_t i = 0; i < n; i++) _times.push_back((float)i);\n\n    string units = \"seconds\";\n    int    axis = 3;\n    _coordVarInfo = DC::CoordVar(_derivedVarName, units, DC::XType::FLOAT, vector<bool>(), axis, false, vector<string>(), dimName);\n}\n\nint DerivedCoordVar_Time::Initialize() { return (0); }\n\nbool DerivedCoordVar_Time::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVar_Time::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVar_Time::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    return (0);\n}\n\nint DerivedCoordVar_Time::OpenVariableRead(size_t ts, int level, int lod)\n{\n    ts = ts < _times.size() ? ts : _times.size() - 1;\n\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVar_Time::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nint DerivedCoordVar_Time::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    VAssert(min.size() == 0);\n    VAssert(max.size() == 0);\n\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor: %d\", fd);\n        return (-1);\n    }\n\n    size_t ts = f->GetTS();\n\n    *region = _times[ts];\n\n    return (0);\n}\n\nbool DerivedCoordVar_Time::VariableExists(size_t ts, int reflevel, int lod) const { return (ts < _times.size()); }\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVar_Staggered\n//\n//////////////////////////////////////////////////////////////////////////////\n\nDerivedCoordVar_Staggered::DerivedCoordVar_Staggered(string derivedVarName, string stagDimName, DC *dc, string inName, string dimName) : DerivedCoordVar(derivedVarName)\n{\n    _stagDimName = stagDimName;\n    _inName = inName;\n    _dimName = dimName;\n    _dc = dc;\n}\n\nint DerivedCoordVar_Staggered::Initialize()\n{\n    bool ok = _dc->GetCoordVarInfo(_inName, _coordVarInfo);\n    if (!ok) return (-1);\n\n    vector<string> dimNames = _coordVarInfo.GetDimNames();\n    _stagDim = -1;\n    for (int i = 0; i < dimNames.size(); i++) {\n        if (dimNames[i] == _dimName) {\n            _stagDim = i;\n            dimNames[i] = _stagDimName;\n            break;\n        }\n    }\n    if (_stagDim < 0) {\n        SetErrMsg(\"Dimension %s not found\", _dimName.c_str());\n        return (-1);\n    }\n\n    // Change the name of the staggered dimension\n    //\n    _coordVarInfo.SetDimNames(dimNames);\n\n    return (0);\n}\n\nbool DerivedCoordVar_Staggered::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVar_Staggered::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVar_Staggered::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    vector<size_t> dummy;\n    int            rc = _dc->GetDimLensAtLevel(_inName, level, dims_at_level, dummy, -1);\n    if (rc < 0) return (-1);\n\n    dims_at_level[_stagDim] += 1;\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DerivedCoordVar_Staggered::OpenVariableRead(size_t ts, int level, int lod)\n{\n    int fd = _dc->OpenVariableRead(ts, _inName, level, lod);\n    if (fd < 0) return (fd);\n\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod, fd);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVar_Staggered::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int rc = _dc->CloseVariable(f->GetAux());\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (rc);\n}\n\nint DerivedCoordVar_Staggered::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    vector<size_t> dims, dummy;\n    int            rc = GetDimLensAtLevel(f->GetLevel(), dims, dummy);\n    if (rc < 0) return (-1);\n\n    vector<size_t> inMin = min;\n    vector<size_t> inMax = max;\n\n    // adjust coords for native data so that we have what we\n    // need for interpolation or extrapolation.\n    //\n\n    // Adjust min max boundaries to handle 4 case (below) where X's\n    // are samples on the destination grid (staggered) and O's are samples\n    // on the source grid (unstaggered) and the numbers represent\n    // the address of the samples in their respective arrays\n    //\n    //\tX O X O X O X\n    //\t0 0 1 1 2 2 3\n    //\n    //\t  O X O X O X\n    //\t  0 1 1 2 2 3\n    //\n    //\tX O X O X O\n    //\t0 0 1 1 2 2\n    //\n    //\t  O X O X O\n    //\t  0 1 1 2 2\n\n    // Adjust input min so we can interpolate interior.\n    //\n    if (min[_stagDim] > 0) { inMin[_stagDim] -= 1; }\n\n    // input dimensions are one less then output\n    //\n    if (max[_stagDim] >= (dims[_stagDim] - 1)) { inMax[_stagDim] -= 1; }\n\n    // Adjust min and max for edge cases\n    //\n    if (max[_stagDim] == 0 && (dims[_stagDim] - 1) > 1) { inMax[_stagDim] += 1; }\n    if (min[_stagDim] == dims[_stagDim] - 1 && min[_stagDim] > 0) { inMin[_stagDim] -= 1; }\n\n    vector<size_t> inDims, outDims;\n    for (size_t i = 0; i < min.size(); i++) {\n        inDims.push_back(inMax[i] - inMin[i] + 1);\n        outDims.push_back(max[i] - min[i] + 1);\n    }\n    size_t sz = std::max(vproduct(outDims), vproduct(inDims));\n\n    float *buf = new float[sz];\n\n    // Read unstaggered data\n    //\n    rc = _dc->ReadRegion(f->GetAux(), inMin, inMax, buf);\n    if (rc < 0) return (-1);\n\n    resampleToStaggered(buf, inMin, inMax, region, min, max, _stagDim);\n\n    delete[] buf;\n\n    return (0);\n}\n\nbool DerivedCoordVar_Staggered::VariableExists(size_t ts, int reflevel, int lod) const { return (_dc->VariableExists(ts, _inName, reflevel, lod)); }\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVar_UnStaggered\n//\n//////////////////////////////////////////////////////////////////////////////\n\nDerivedCoordVar_UnStaggered::DerivedCoordVar_UnStaggered(string derivedVarName, string unstagDimName, DC *dc, string inName, string dimName) : DerivedCoordVar(derivedVarName)\n{\n    _unstagDimName = unstagDimName;\n    _inName = inName;\n    _dimName = dimName;\n    _dc = dc;\n}\n\nint DerivedCoordVar_UnStaggered::Initialize()\n{\n    bool ok = _dc->GetCoordVarInfo(_inName, _coordVarInfo);\n    if (!ok) return (-1);\n\n    vector<string> dimNames = _coordVarInfo.GetDimNames();\n    _stagDim = -1;\n    for (int i = 0; i < dimNames.size(); i++) {\n        if (dimNames[i] == _dimName) {\n            _stagDim = i;\n            dimNames[i] = _unstagDimName;\n            break;\n        }\n    }\n    if (_stagDim < 0) {\n        SetErrMsg(\"Dimension %s not found\", _dimName.c_str());\n        return (-1);\n    }\n\n    // Change the name of the staggered dimension\n    //\n    _coordVarInfo.SetDimNames(dimNames);\n\n    return (0);\n}\n\nbool DerivedCoordVar_UnStaggered::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVar_UnStaggered::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVar_UnStaggered::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    int rc = _dc->GetDimLensAtLevel(_inName, level, dims_at_level, bs_at_level, -1);\n    if (rc < 0) return (-1);\n\n    dims_at_level[_stagDim] -= 1;\n    bs_at_level = vector<size_t>(dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DerivedCoordVar_UnStaggered::OpenVariableRead(size_t ts, int level, int lod)\n{\n    int fd = _dc->OpenVariableRead(ts, _inName, level, lod);\n    if (fd < 0) return (fd);\n\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod, fd);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVar_UnStaggered::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int rc = _dc->CloseVariable(f->GetAux());\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (rc);\n}\n\nint DerivedCoordVar_UnStaggered::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    vector<size_t> dims, dummy;\n    int            rc = GetDimLensAtLevel(f->GetLevel(), dims, dummy);\n    if (rc < 0) return (-1);\n\n    vector<size_t> inMin = min;\n    vector<size_t> inMax = max;\n\n    // adjust coords for native data so that we have what we\n    // need for interpolation .\n    //\n    inMax[_stagDim] += 1;\n\n    vector<size_t> inDims, outDims;\n    for (size_t i = 0; i < min.size(); i++) {\n        inDims.push_back(inMax[i] - inMin[i] + 1);\n        outDims.push_back(max[i] - min[i] + 1);\n    }\n    size_t sz = std::max(vproduct(outDims), vproduct(inDims));\n\n    float *buf = new float[sz];\n\n    // Read staggered data\n    //\n    rc = _dc->ReadRegion(f->GetAux(), inMin, inMax, buf);\n    if (rc < 0) return (-1);\n\n    resampleToUnStaggered(buf, inMin, inMax, region, min, max, _stagDim);\n\n    delete[] buf;\n\n    return (0);\n}\n\nbool DerivedCoordVar_UnStaggered::VariableExists(size_t ts, int reflevel, int lod) const { return (_dc->VariableExists(ts, _inName, reflevel, lod)); }\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCFVertCoordVar\n//\n//////////////////////////////////////////////////////////////////////////////\n\nbool DerivedCFVertCoordVar::ParseFormula(string formula_terms, map<string, string> &parsed_terms)\n{\n    parsed_terms.clear();\n\n    // Remove \":\" to ease parsing. It's superflous\n    //\n    replace(formula_terms.begin(), formula_terms.end(), ':', ' ');\n\n    string       buf;                  // Have a buffer string\n    stringstream ss(formula_terms);    // Insert the string into a stream\n\n    vector<string> tokens;    // Create vector to hold our words\n\n    while (ss >> buf) { tokens.push_back(buf); }\n\n    if (tokens.size() % 2) return (false);\n\n    for (int i = 0; i < tokens.size(); i += 2) {\n        parsed_terms[tokens[i]] = tokens[i + 1];\n        if (parsed_terms[tokens[i]].empty()) return (false);\n    }\n    return (true);\n}\n\nbool DerivedCFVertCoordVar::ValidFormula(const vector<string> &required_terms, string formula)\n{\n    map<string, string> formulaMap;\n    if (!ParseFormula(formula, formulaMap)) { return (false); }\n\n    for (int i = 0; i < required_terms.size(); i++) {\n        map<string, string>::const_iterator itr;\n        itr = formulaMap.find(required_terms[i]);\n        if (itr == formulaMap.end()) return (false);\n    }\n    return (true);\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// DerivedCFVertCoordVarFactory Class\n//\n/////////////////////////////////////////////////////////////////////////\n\nDerivedCFVertCoordVar *DerivedCFVertCoordVarFactory::CreateInstance(string standard_name, DC *dc, string mesh, string formula)\n{\n    DerivedCFVertCoordVar *instance = NULL;\n\n    // find standard_name in the registry and call factory method.\n    //\n    auto it = _factoryFunctionRegistry.find(standard_name);\n    if (it != _factoryFunctionRegistry.end()) { instance = it->second(dc, mesh, formula); }\n\n    return instance;\n}\n\nvector<string> DerivedCFVertCoordVarFactory::GetFactoryNames() const\n{\n    vector<string>                                                                       names;\n    map<string, function<DerivedCFVertCoordVar *(DC *, string, string)>>::const_iterator itr;\n\n    for (const auto &itr : _factoryFunctionRegistry) { names.push_back(itr.first); }\n    return (names);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVarStandardWRF_Terrain\n//\n//////////////////////////////////////////////////////////////////////////////\n\nstatic DerivedCFVertCoordVarFactoryRegistrar<DerivedCoordVarStandardWRF_Terrain> registrar_wrf_terrain(\"wrf_terrain\");\n\nDerivedCoordVarStandardWRF_Terrain::DerivedCoordVarStandardWRF_Terrain(DC *dc, string mesh, string formula) : DerivedCFVertCoordVar(\"\", dc, mesh, formula)\n{\n    _PHVar.clear();\n    _PHBVar.clear();\n    _grav = 9.80665;\n}\n\nint DerivedCoordVarStandardWRF_Terrain::Initialize()\n{\n    map<string, string> formulaMap;\n    if (!ParseFormula(_formula, formulaMap)) {\n        SetErrMsg(\"Invalid conversion formula \\\"%s\\\"\", _formula.c_str());\n        return (-1);\n    }\n\n    map<string, string>::const_iterator itr;\n    itr = formulaMap.find(\"PH\");\n    if (itr != formulaMap.end()) { _PHVar = itr->second; }\n\n    itr = formulaMap.find(\"PHB\");\n    if (itr != formulaMap.end()) { _PHBVar = itr->second; }\n\n    if (_PHVar.empty() || _PHBVar.empty()) {\n        SetErrMsg(\"Invalid conversion formula \\\"%s\\\"\", _formula.c_str());\n        return (-1);\n    }\n\n    DC::DataVar dvarInfo;\n    bool        status = _dc->GetDataVarInfo(_PHVar, dvarInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _PHVar.c_str());\n        return (-1);\n    }\n\n    string timeCoordVar = dvarInfo.GetTimeCoordVar();\n    string timeDimName;\n    if (!timeCoordVar.empty()) {\n        DC::CoordVar cvarInfo;\n        bool         status = _dc->GetCoordVarInfo(timeCoordVar, cvarInfo);\n        if (!status) {\n            SetErrMsg(\"Invalid variable \\\"%s\\\"\", timeCoordVar.c_str());\n            return (-1);\n        }\n        timeDimName = cvarInfo.GetTimeDimName();\n    }\n\n    DC::Mesh m;\n    status = _dc->GetMesh(_mesh, m);\n    if (!status) {\n        SetErrMsg(\"Invalid mesh \\\"%s\\\"\", _mesh.c_str());\n        return (-1);\n    }\n\n    // Elevation variable\n    //\n    vector<string> dimnames = m.GetDimNames();\n    VAssert(dimnames.size() == 3);\n    if (dimnames[0] == \"west_east\" && dimnames[1] == \"south_north\" && dimnames[2] == \"bottom_top\") {\n        _derivedVarName = \"Elevation\";\n    } else if (dimnames[0] == \"west_east_stag\" && dimnames[1] == \"south_north\" && dimnames[2] == \"bottom_top\") {\n        _derivedVarName = \"ElevationU\";\n    } else if (dimnames[0] == \"west_east\" && dimnames[1] == \"south_north_stag\" && dimnames[2] == \"bottom_top\") {\n        _derivedVarName = \"ElevationV\";\n    } else if (dimnames[0] == \"west_east\" && dimnames[1] == \"south_north\" && dimnames[2] == \"bottom_top_stag\") {\n        _derivedVarName = \"ElevationW\";\n    } else {\n        SetErrMsg(\"Invalid mesh \\\"%s\\\"\", _mesh.c_str());\n        return (-1);\n    }\n\n    _coordVarInfo = DC::CoordVar(_derivedVarName, \"m\", DC::XType::FLOAT, dvarInfo.GetWName(), dvarInfo.GetCRatios(), vector<bool>(3, false), dimnames, timeDimName, 2, false);\n\n    return (0);\n}\n\nbool DerivedCoordVarStandardWRF_Terrain::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVarStandardWRF_Terrain::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nint DerivedCoordVarStandardWRF_Terrain::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    vector<size_t> dims, bs;\n    int            rc = _dc->GetDimLensAtLevel(_PHVar, -1, dims, bs, -1);\n    if (rc < 0) return (-1);\n\n    if (_derivedVarName == \"Elevation\") {\n        if (dims[2] > 1) dims[2]--;\n    } else if (_derivedVarName == \"ElevationU\") {\n        dims[0]++;\n        if (dims[2] > 1) dims[2]--;\n    } else if (_derivedVarName == \"ElevationV\") {\n        dims[1]++;\n        if (dims[2] > 1) dims[2]--;\n    } else if (_derivedVarName == \"ElevationW\") {\n    } else {\n        SetErrMsg(\"Invalid variable name: %s\", _derivedVarName.c_str());\n        return (-1);\n    }\n\n    int nlevels = _dc->GetNumRefLevels(_PHVar);\n    if (level < 0) level = nlevels + level;\n\n    WASP::InqDimsAtLevel(_coordVarInfo.GetWName(), level, dims, bs, dims_at_level, bs_at_level);\n\n    // No blocking\n    //\n    //\tbs_at_level = vector <size_t> (dims_at_level.size(), 1);\n\n    return (0);\n}\n\nint DerivedCoordVarStandardWRF_Terrain::OpenVariableRead(size_t ts, int level, int lod)\n{\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVarStandardWRF_Terrain::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nint DerivedCoordVarStandardWRF_Terrain::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    string varname = f->GetVarname();\n\n    // Dimensions of \"W\" grid: PH and PHB variables are sampled on the\n    // same grid as the W component of velocity\n    //\n    vector<size_t> wDims, dummy;\n    int            rc = _dc->GetDimLensAtLevel(_PHVar, f->GetLevel(), wDims, dummy, -1);\n    if (rc < 0) return (-1);\n\n    vector<size_t> myDims;\n    rc = DerivedCoordVarStandardWRF_Terrain::GetDimLensAtLevel(f->GetLevel(), myDims, dummy);\n    if (rc < 0) return (-1);\n\n    // coordinates of \"W\" grid.\n    //\n    vector<size_t> wMin = min;\n    vector<size_t> wMax = max;\n\n    // coordinates of base (Elevation) grid.\n    //\n    if (varname == \"Elevation\") {\n        // In general myDims[2] != wDims[2]. However, for multiresolution\n        // data the two can be equal\n        //\n        if (myDims[2] != wDims[2]) { wMax[2] += 1; }\n\n    } else if (varname == \"ElevationU\") {\n        if (myDims[2] != wDims[2]) { wMax[2] += 1; }\n\n        if (min[0] > 0) { wMin[0] -= 1; }\n        if (max[0] >= (wDims[0] - 1)) { wMax[0] -= 1; }\n    } else if (varname == \"ElevationV\") {\n        if (myDims[2] != wDims[2]) { wMax[2] += 1; }\n\n        if (min[1] > 0) { wMin[1] -= 1; }\n        if (max[1] >= (wDims[1] - 1)) { wMax[1] -= 1; }\n    }\n\n    // Base grid dimensions\n    //\n    vector<size_t> bMin = wMin;\n    vector<size_t> bMax = wMax;\n    if (myDims[2] != wDims[2]) { bMax[2] -= 1; }\n\n    size_t nElements = std::max(numElements(wMin, wMax), numElements(min, max));\n\n    vector<float> buf1(nElements);\n    rc = _getVar(_dc, f->GetTS(), _PHVar, f->GetLevel(), f->GetLOD(), wMin, wMax, buf1.data());\n    if (rc < 0) { return (rc); }\n\n    vector<float> buf2(nElements);\n    rc = _getVar(_dc, f->GetTS(), _PHBVar, f->GetLevel(), f->GetLOD(), wMin, wMax, buf2.data());\n    if (rc < 0) { return (rc); }\n\n    float *dst = region;\n    if (varname != \"ElevationW\" && wDims[2] > 1) { dst = buf1.data(); }\n\n    // Compute elevation on the W grid\n    //\n    for (size_t i = 0; i < nElements; i++) { dst[i] = (buf1.data()[i] + buf2.data()[i]) / _grav; }\n\n    if (wDims[2] < 2) return (0);\n\n    // Elevation is correct for W grid. If we want Elevation, ElevationU, or\n    // Elevation V grid we need to interpolate\n    //\n\n    if (varname == \"Elevation\") {\n        // Resample stagged W grid to base grid\n        //\n        resampleToUnStaggered(buf1.data(), wMin, wMax, region, min, max, 2);\n    } else if (varname == \"ElevationU\") {\n        // Resample stagged W grid to base grid\n        //\n        resampleToUnStaggered(buf1.data(), wMin, wMax, buf2.data(), bMin, bMax, 2);\n\n        resampleToStaggered(buf2.data(), bMin, bMax, region, min, max, 0);\n    } else if (varname == \"ElevationV\") {\n        // Resample stagged W grid to base grid\n        //\n        resampleToUnStaggered(buf1.data(), wMin, wMax, buf2.data(), bMin, bMax, 2);\n\n        resampleToStaggered(buf2.data(), bMin, bMax, region, min, max, 1);\n    }\n\n    return (0);\n}\n\nbool DerivedCoordVarStandardWRF_Terrain::VariableExists(size_t ts, int reflevel, int lod) const\n{\n    return (_dc->VariableExists(ts, _PHVar, reflevel, lod) && _dc->VariableExists(ts, _PHBVar, reflevel, lod));\n}\n\nbool DerivedCoordVarStandardWRF_Terrain::ValidFormula(string formula) { return (DerivedCFVertCoordVar::ValidFormula(vector<string>{\"PH\", \"PHB\"}, formula)); }\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVarStandardOceanSCoordinate\n//\n//////////////////////////////////////////////////////////////////////////////\n\n//\n// Register class with object factory!!!\n//\nstatic DerivedCFVertCoordVarFactoryRegistrar<DerivedCoordVarStandardOceanSCoordinate> registrar_ocean_s_coordinate_g1(\"ocean_s_coordinate_g1\");\n\nstatic DerivedCFVertCoordVarFactoryRegistrar<DerivedCoordVarStandardOceanSCoordinate> registrar_ocean_s_coordinate_g2(\"ocean_s_coordinate_g2\");\n\nDerivedCoordVarStandardOceanSCoordinate::DerivedCoordVarStandardOceanSCoordinate(DC *dc, string mesh, string formula) : DerivedCFVertCoordVar(\"\", dc, mesh, formula)\n{\n    _standard_name = \"ocean_s_coordinate_g1\";\n    _sVar.clear();\n    _CVar.clear();\n    _etaVar.clear();\n    _depthVar.clear();\n    _depth_cVar.clear();\n\n    _CVarMV = std::numeric_limits<double>::infinity();\n    _etaVarMV = std::numeric_limits<double>::infinity();\n    _depthVarMV = std::numeric_limits<double>::infinity();\n\n    _destaggerEtaXDim = false;\n    _destaggerEtaYDim = false;\n    _destaggerDepthXDim = false;\n    _destaggerDepthYDim = false;\n}\n\nint DerivedCoordVarStandardOceanSCoordinate::initialize_missing_values()\n{\n    DC::DataVar dataInfo;\n    bool        status = _dc->GetDataVarInfo(_CVar, dataInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _CVar.c_str());\n        return (-1);\n    }\n    if (dataInfo.GetHasMissing()) _CVarMV = dataInfo.GetMissingValue();\n\n    status = _dc->GetDataVarInfo(_etaVar, dataInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _etaVar.c_str());\n        return (-1);\n    }\n    if (dataInfo.GetHasMissing()) _etaVarMV = dataInfo.GetMissingValue();\n\n    status = _dc->GetDataVarInfo(_depthVar, dataInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _depthVar.c_str());\n        return (-1);\n    }\n    if (dataInfo.GetHasMissing()) _depthVarMV = dataInfo.GetMissingValue();\n\n    return (0);\n}\n\nint DerivedCoordVarStandardOceanSCoordinate::initialize_stagger_flags()\n{\n    vector<size_t> derivedDims;\n    bool           status = _dc->GetMeshDimLens(_mesh, derivedDims);\n    if (!status) {\n        SetErrMsg(\"Invalid mesh \\\"%s\\\"\", _mesh.c_str());\n        return (-1);\n    }\n\n    vector<size_t> nativeDims;\n    int            rc = _dc->GetDimLens(_etaVar, nativeDims);\n    if (rc < 0) return (-1);\n\n    if (nativeDims[0] == derivedDims[0] - 1) _destaggerEtaXDim = true;\n    if (nativeDims[1] == derivedDims[1] - 1) _destaggerEtaYDim = true;\n\n    rc = _dc->GetDimLens(_depthVar, nativeDims);\n    if (rc < 0) return (-1);\n\n    if (nativeDims[0] == derivedDims[0] - 1) _destaggerDepthXDim = true;\n    if (nativeDims[1] == derivedDims[1] - 1) _destaggerDepthYDim = true;\n\n    return (0);\n}\n\nint DerivedCoordVarStandardOceanSCoordinate::Initialize()\n{\n    map<string, string> formulaMap;\n    if (!ParseFormula(_formula, formulaMap)) {\n        SetErrMsg(\"Invalid conversion formula \\\"%s\\\"\", _formula.c_str());\n        return (-1);\n    }\n\n    map<string, string>::const_iterator itr;\n    VAssert((itr = formulaMap.find(\"s\")) != formulaMap.end());\n    _sVar = itr->second;\n\n    VAssert((itr = formulaMap.find(\"C\")) != formulaMap.end());\n    _CVar = itr->second;\n\n    VAssert((itr = formulaMap.find(\"eta\")) != formulaMap.end());\n    _etaVar = itr->second;\n\n    VAssert((itr = formulaMap.find(\"depth\")) != formulaMap.end());\n    _depthVar = itr->second;\n\n    VAssert((itr = formulaMap.find(\"depth_c\")) != formulaMap.end());\n    _depth_cVar = itr->second;\n\n    if (initialize_missing_values() < 0) return (-1);\n\n    if (initialize_stagger_flags() < 0) return (-1);\n\n    // Figure out if this is a Ocean s-coordinate, generic form 1, or\n    // Ocean s-coordinate, generic form 2\n    //\n    DC::CoordVar sInfo;\n    bool         status = _dc->GetCoordVarInfo(_sVar, sInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _sVar.c_str());\n        return (-1);\n    }\n\n    DC::Attribute attr_name;\n    if (!sInfo.GetAttribute(\"standard_name\", attr_name)) {\n        // Default to generic form 1\n        //\n        _standard_name = \"ocean_s_coordinate_g1\";\n    } else {\n        attr_name.GetValues(_standard_name);\n    }\n\n    // Use the eta variable to set up metadata for the derived variable\n    //\n    DC::DataVar etaInfo;\n    status = _dc->GetDataVarInfo(_etaVar, etaInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _etaVar.c_str());\n        return (-1);\n    }\n\n    string timeCoordVar = etaInfo.GetTimeCoordVar();\n    string timeDimName;\n    if (!timeCoordVar.empty()) {\n        DC::CoordVar cvarInfo;\n        bool         status = _dc->GetCoordVarInfo(timeCoordVar, cvarInfo);\n        if (!status) {\n            SetErrMsg(\"Invalid variable \\\"%s\\\"\", timeCoordVar.c_str());\n            return (-1);\n        }\n        timeDimName = cvarInfo.GetTimeDimName();\n    }\n\n    _derivedVarName = \"Z_\" + _sVar;\n\n    vector<string> dimnames;\n    status = _dc->GetMeshDimNames(_mesh, dimnames);\n    if (!status) {\n        SetErrMsg(\"Invalid mesh \\\"%s\\\"\", _mesh.c_str());\n        return (-1);\n    }\n    VAssert(dimnames.size() == 3);\n\n    // We're deriving a 3D varible from 1D and 2D varibles. We arbitarily\n    // use one of the 2D variables to configure metadata such as the\n    // available compression ratios\n    //\n    _coordVarInfo = DC::CoordVar(_derivedVarName, \"m\", DC::XType::FLOAT, vector<bool>(3, false), 2, false, dimnames, timeDimName);\n\n    return (0);\n}\n\nbool DerivedCoordVarStandardOceanSCoordinate::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVarStandardOceanSCoordinate::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nvector<string> DerivedCoordVarStandardOceanSCoordinate::GetInputs() const\n{\n    map<string, string> formulaMap;\n    bool                ok = ParseFormula(_formula, formulaMap);\n    VAssert(ok);\n\n    vector<string> inputs;\n    for (auto it = formulaMap.begin(); it != formulaMap.end(); ++it) { inputs.push_back(it->second); }\n    return (inputs);\n}\n\nint DerivedCoordVarStandardOceanSCoordinate::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    vector<size_t> dims2d, bs2d;\n    int            rc = _dc->GetDimLensAtLevel(_etaVar, -1, dims2d, bs2d);\n    if (rc < 0) return (-1);\n\n    vector<size_t> dims1d, bs1d;\n    rc = _dc->GetDimLensAtLevel(_sVar, -1, dims1d, bs1d);\n    if (rc < 0) return (-1);\n\n    dims_at_level = {dims2d[0], dims2d[1], dims1d[0]};\n    bs_at_level = {bs2d[0], bs2d[1], bs1d[0]};\n\n    return (0);\n}\n\nint DerivedCoordVarStandardOceanSCoordinate::OpenVariableRead(size_t ts, int level, int lod)\n{\n    // Compression not supported\n    //\n    level = -1;\n    lod = -1;\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVarStandardOceanSCoordinate::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nint DerivedCoordVarStandardOceanSCoordinate::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    string varname = f->GetVarname();\n\n    vector<size_t> dims, dummy;\n    int            rc = GetDimLensAtLevel(f->GetLevel(), dims, dummy);\n    if (rc < 0) return (-1);\n\n    vector<float>  s(dims[2]);\n    vector<size_t> myMin = {min[2]};\n    vector<size_t> myMax = {max[2]};\n    rc = _getVar(_dc, f->GetTS(), _sVar, f->GetLevel(), f->GetLOD(), myMin, myMax, s.data());\n    if (rc < 0) return (rc);\n\n    vector<float> C(dims[2]);\n    myMin = {min[2]};\n    myMax = {max[2]};\n    rc = _getVar(_dc, f->GetTS(), _CVar, f->GetLevel(), f->GetLOD(), myMin, myMax, C.data());\n    if (rc < 0) return (rc);\n\n    vector<float> eta(dims[0] * dims[1]);\n    myMin = {min[0], min[1]};\n    myMax = {max[0], max[1]};\n    if (_destaggerEtaXDim) {\n        rc = _getVarDestagger(_dc, f->GetTS(), _etaVar, f->GetLevel(), f->GetLOD(), myMin, myMax, eta.data(), 0);\n    } else if (_destaggerEtaYDim) {\n        rc = _getVarDestagger(_dc, f->GetTS(), _etaVar, f->GetLevel(), f->GetLOD(), myMin, myMax, eta.data(), 1);\n    } else {\n        rc = _getVar(_dc, f->GetTS(), _etaVar, f->GetLevel(), f->GetLOD(), myMin, myMax, eta.data());\n    }\n    if (rc < 0) return (rc);\n\n    vector<float> depth(dims[0] * dims[1]);\n    myMin = {min[0], min[1]};\n    myMax = {max[0], max[1]};\n    if (_destaggerDepthXDim) {\n        rc = _getVarDestagger(_dc, f->GetTS(), _depthVar, f->GetLevel(), f->GetLOD(), myMin, myMax, depth.data(), 0);\n    } else if (_destaggerDepthYDim) {\n        rc = _getVarDestagger(_dc, f->GetTS(), _depthVar, f->GetLevel(), f->GetLOD(), myMin, myMax, depth.data(), 1);\n    } else {\n        rc = _getVar(_dc, f->GetTS(), _depthVar, f->GetLevel(), f->GetLOD(), myMin, myMax, depth.data());\n    }\n\n    float depth_c;\n    myMin = {};\n    myMax = {};\n    rc = _getVar(_dc, f->GetTS(), _depth_cVar, f->GetLevel(), f->GetLOD(), myMin, myMax, &depth_c);\n\n    if (_standard_name == \"ocean_s_coordinate_g1\") {\n        compute_g1(min, max, s.data(), C.data(), eta.data(), depth.data(), depth_c, region);\n    } else {\n        compute_g2(min, max, s.data(), C.data(), eta.data(), depth.data(), depth_c, region);\n    }\n\n    return (0);\n}\n\nbool DerivedCoordVarStandardOceanSCoordinate::VariableExists(size_t ts, int reflevel, int lod) const\n{\n    return (_dc->VariableExists(ts, _sVar, reflevel, lod) && _dc->VariableExists(ts, _CVar, reflevel, lod) && _dc->VariableExists(ts, _etaVar, reflevel, lod)\n            && _dc->VariableExists(ts, _depthVar, reflevel, lod) && _dc->VariableExists(ts, _depth_cVar, reflevel, lod));\n}\n\nbool DerivedCoordVarStandardOceanSCoordinate::ValidFormula(string formula) { return (DerivedCFVertCoordVar::ValidFormula(vector<string>{\"s\", \"C\", \"eta\", \"depth\", \"depth_c\"}, formula)); }\n\nvoid DerivedCoordVarStandardOceanSCoordinate::compute_g1(const vector<size_t> &min, const vector<size_t> &max, const float *s, const float *C, const float *eta, const float *depth, float depth_c,\n                                                         float *region) const\n{\n    vector<size_t> rDims;\n    for (int i = 0; i < 3; i++) { rDims.push_back(max[i] - min[i] + 1); }\n\n    for (size_t k = 0; k < max[2] - min[2] + 1; k++) {\n        for (size_t j = 0; j < max[1] - min[1] + 1; j++) {\n            for (size_t i = 0; i < max[0] - min[0] + 1; i++) {\n                if (depth[j * rDims[0]] == 0.0) {\n                    region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 0.0;\n                    continue;\n                }\n\n                // We are deriving coordinate values from data values, so missing\n                // values may be present\n                //\n                if (C[k] == _CVarMV || eta[j * rDims[0] + i] == _etaVarMV || depth[j * rDims[0] + i] == _depthVarMV) {\n                    region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 0.0;\n                    continue;\n                }\n\n                float tmp = depth_c * s[k] + (depth[j * rDims[0] + i] - depth_c) * C[k];\n\n                region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = tmp + eta[j * rDims[0] + i] * (1 + tmp / depth[j * rDims[0] + i]);\n            }\n        }\n    }\n}\n\nvoid DerivedCoordVarStandardOceanSCoordinate::compute_g2(const vector<size_t> &min, const vector<size_t> &max, const float *s, const float *C, const float *eta, const float *depth, float depth_c,\n                                                         float *region) const\n{\n    vector<size_t> rDims;\n    for (int i = 0; i < 3; i++) { rDims.push_back(max[i] - min[i] + 1); }\n\n    for (size_t k = 0; k < max[2] - min[2] + 1; k++) {\n        for (size_t j = 0; j < max[1] - min[1] + 1; j++) {\n            for (size_t i = 0; i < max[0] - min[0] + 1; i++) {\n                if ((depth_c + depth[j * rDims[0]]) == 0.0) {\n                    region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 0.0;\n                    continue;\n                }\n\n                // We are deriving coordinate values from data values, so missing\n                // values may be present\n                //\n                if (C[k] == _CVarMV || eta[j * rDims[0] + i] == _etaVarMV || depth[j * rDims[0] + i] == _depthVarMV) {\n                    region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 0.0;\n                    continue;\n                }\n\n                float tmp = (depth_c * s[k] + depth[j * rDims[0] + i] * C[k]) / (depth_c + depth[j * rDims[0] + i]);\n\n                region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = eta[j * rDims[0] + i] + (eta[j * rDims[0] + i] + depth[j * rDims[0] + i]) * tmp;\n            }\n        }\n    }\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//\tDerivedCoordVarStandardAHSPC\n//\n//\tAtmosphere Hybrid Sigma Pressure Coordinate\n//\n//////////////////////////////////////////////////////////////////////////////\n\n//\n// Register class with object factory!!!\n//\n\n#ifdef VAPOR3_6_0\n\n//\n// The atmosphere_hybrid_sigma_pressure_coordinate conversion from pressure\n// to meters unforunately results in a flipped (inverted?) vertical coordinate\n// system with logical grid indices increasing as user coordinates\n// decrease. I.e. Z[k] > Z[k+1]. In numerous places VAPOR\n// expects the grid index and associated vertical coordinate  to be\n// monotonically increasing. This needs to be fixed as this assumption\n// often does not hold true. However it is a big lift. For now, just\n// remove the atmosphere_hybrid_sigma_pressure_coordinate converter from\n// the object factory.\n//\n\n\nstatic DerivedCFVertCoordVarFactoryRegistrar<DerivedCoordVarStandardAHSPC> registrar_atmosphere_hybrid_sigma_pressure_coordinate(\"atmosphere_hybrid_sigma_pressure_coordinate\");\n\n#endif\n\nDerivedCoordVarStandardAHSPC::DerivedCoordVarStandardAHSPC(DC *dc, string mesh, string formula) : DerivedCFVertCoordVar(\"\", dc, mesh, formula)\n{\n    _standard_name = \"atmosphere_hybrid_sigma_pressure_coordinate\";\n    _aVar.clear();\n    _apVar.clear();\n    _bVar.clear();\n    _p0Var.clear();\n    _psVar.clear();\n\n    _psVarMV = std::numeric_limits<double>::infinity();\n}\n\nint DerivedCoordVarStandardAHSPC::initialize_missing_values()\n{\n    DC::DataVar dataInfo;\n    bool        status = _dc->GetDataVarInfo(_psVar, dataInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _psVar.c_str());\n        return (-1);\n    }\n    if (dataInfo.GetHasMissing()) _psVarMV = dataInfo.GetMissingValue();\n\n    return (0);\n}\n\nint DerivedCoordVarStandardAHSPC::Initialize()\n{\n    map<string, string> formulaMap;\n    if (!ParseFormula(_formula, formulaMap)) {\n        SetErrMsg(\"Invalid conversion formula \\\"%s\\\"\", _formula.c_str());\n        return (-1);\n    }\n\n    // There are two possible formulations, one with 'ap', and one\n    // with 'a' and 'p0'\n    //\n    map<string, string>::const_iterator itr;\n    VAssert((itr = formulaMap.find(\"a\")) != formulaMap.end());\n    if (itr != formulaMap.end()) {\n        _aVar = itr->second;\n        VAssert((itr = formulaMap.find(\"p0\")) != formulaMap.end());\n        _p0Var = itr->second;\n    } else {\n        VAssert((itr = formulaMap.find(\"ap\")) != formulaMap.end());\n        _apVar = itr->second;\n    }\n\n    VAssert((itr = formulaMap.find(\"b\")) != formulaMap.end());\n    _bVar = itr->second;\n\n    VAssert((itr = formulaMap.find(\"ps\")) != formulaMap.end());\n    _psVar = itr->second;\n\n    if (initialize_missing_values() < 0) return (-1);\n\n    // Use the 'b' and 'ps' variables to set up metadata for the derived\n    // variable\n    //\n    DC::DataVar bInfo;\n    bool        status = _dc->GetDataVarInfo(_bVar, bInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _bVar.c_str());\n        return (-1);\n    }\n\n    DC::DataVar psInfo;\n    status = _dc->GetDataVarInfo(_psVar, psInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", _psVar.c_str());\n        return (-1);\n    }\n\n    // Construct spatial and temporal dimensions from the 1D 'b'\n    // variable and 2D, time-varying 'ps' variable\n    //\n    DC::Mesh m;\n    status = _dc->GetMesh(psInfo.GetMeshName(), m);\n    if (!status) {\n        SetErrMsg(\"Invalid mesh \\\"%s\\\"\", _mesh.c_str());\n        return (-1);\n    }\n    vector<string> dimnames = m.GetDimNames();\n\n    status = _dc->GetMesh(bInfo.GetMeshName(), m);\n    if (!status) {\n        SetErrMsg(\"Invalid mesh \\\"%s\\\"\", _mesh.c_str());\n        return (-1);\n    }\n    dimnames.push_back(m.GetDimNames()[0]);\n\n    string timeCoordVar = psInfo.GetTimeCoordVar();\n    string timeDimName;\n    if (!timeCoordVar.empty()) {\n        DC::CoordVar cvarInfo;\n        bool         status = _dc->GetCoordVarInfo(timeCoordVar, cvarInfo);\n        if (!status) {\n            SetErrMsg(\"Invalid variable \\\"%s\\\"\", timeCoordVar.c_str());\n            return (-1);\n        }\n        timeDimName = cvarInfo.GetTimeDimName();\n    }\n\n    // We're deriving a 3D varible from 1D and 2D varibles. We arbitarily\n    // use one of the 2D variables to configure metadata such as the\n    // available compression ratios\n    //\n    _derivedVarName = \"Z_\" + _bVar;\n    _coordVarInfo = DC::CoordVar(_derivedVarName, \"m\", DC::XType::FLOAT, vector<bool>(3, false), 2, false, dimnames, timeDimName);\n\n    return (0);\n}\n\nbool DerivedCoordVarStandardAHSPC::GetBaseVarInfo(DC::BaseVar &var) const\n{\n    var = _coordVarInfo;\n    return (true);\n}\n\nbool DerivedCoordVarStandardAHSPC::GetCoordVarInfo(DC::CoordVar &cvar) const\n{\n    cvar = _coordVarInfo;\n    return (true);\n}\n\nvector<string> DerivedCoordVarStandardAHSPC::GetInputs() const\n{\n    map<string, string> formulaMap;\n    bool                ok = ParseFormula(_formula, formulaMap);\n    VAssert(ok);\n\n    vector<string> inputs;\n    for (auto it = formulaMap.begin(); it != formulaMap.end(); ++it) { inputs.push_back(it->second); }\n    return (inputs);\n}\n\nint DerivedCoordVarStandardAHSPC::GetDimLensAtLevel(int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    vector<size_t> dims2d, bs2d;\n    int            rc = _dc->GetDimLensAtLevel(_psVar, -1, dims2d, bs2d);\n    if (rc < 0) return (-1);\n\n    vector<size_t> dims1d, bs1d;\n    rc = _dc->GetDimLensAtLevel(_bVar, -1, dims1d, bs1d);\n    if (rc < 0) return (-1);\n\n    dims_at_level = {dims2d[0], dims2d[1], dims1d[0]};\n    bs_at_level = {bs2d[0], bs2d[1], bs1d[0]};\n\n    return (0);\n}\n\nint DerivedCoordVarStandardAHSPC::OpenVariableRead(size_t ts, int level, int lod)\n{\n    // We don't support compressed data\n    //\n    level = -1;\n    lod = -1;\n\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, _derivedVarName, level, lod);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedCoordVarStandardAHSPC::CloseVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (0);\n}\n\nint DerivedCoordVarStandardAHSPC::ReadRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    vector<size_t> dims, dummy;\n    int            rc = GetDimLensAtLevel(f->GetLevel(), dims, dummy);\n    if (rc < 0) return (-1);\n\n    string         aVar = _aVar.empty() ? _apVar : _aVar;\n    vector<float>  a(dims[2]);\n    vector<size_t> myMin = {min[2]};\n    vector<size_t> myMax = {max[2]};\n    rc = _getVar(_dc, f->GetTS(), aVar, f->GetLevel(), f->GetLOD(), myMin, myMax, a.data());\n    if (rc < 0) return (rc);\n\n    vector<float> b(dims[2]);\n    myMin = {min[2]};\n    myMax = {max[2]};\n    rc = _getVar(_dc, f->GetTS(), _bVar, f->GetLevel(), f->GetLOD(), myMin, myMax, b.data());\n    if (rc < 0) return (rc);\n\n    vector<float> ps(dims[0] * dims[1]);\n    myMin = {min[0], min[1]};\n    myMax = {max[0], max[1]};\n    rc = _getVar(_dc, f->GetTS(), _psVar, f->GetLevel(), f->GetLOD(), myMin, myMax, ps.data());\n    if (rc < 0) return (rc);\n\n    float p0 = 1.0;\n    if (!_aVar.empty()) {\n        myMin = {};\n        myMax = {};\n        rc = _getVar(_dc, f->GetTS(), _p0Var, f->GetLevel(), f->GetLOD(), myMin, myMax, &p0);\n    }\n\n    compute_a(min, max, a.data(), b.data(), ps.data(), p0, region);\n\n    return (0);\n}\n\nbool DerivedCoordVarStandardAHSPC::VariableExists(size_t ts, int reflevel, int lod) const\n{\n    if (!_aVar.empty()) {\n        return (_dc->VariableExists(ts, _aVar, reflevel, lod) && _dc->VariableExists(ts, _bVar, reflevel, lod) && _dc->VariableExists(ts, _psVar, reflevel, lod));\n    } else {\n        return (_dc->VariableExists(ts, _apVar, reflevel, lod) && _dc->VariableExists(ts, _bVar, reflevel, lod) && _dc->VariableExists(ts, _psVar, reflevel, lod)\n                && _dc->VariableExists(ts, _p0Var, reflevel, lod));\n    }\n}\n\nbool DerivedCoordVarStandardAHSPC::ValidFormula(string formula)\n{\n    return (DerivedCFVertCoordVar::ValidFormula(vector<string>{\"a\", \"b\", \"p0\", \"ps\"}, formula) || DerivedCFVertCoordVar::ValidFormula(vector<string>{\"ap\", \"b\", \"ps\"}, formula));\n}\n\nvoid DerivedCoordVarStandardAHSPC::compute_a(const vector<size_t> &min, const vector<size_t> &max, const float *a, const float *b, const float *ps, float p0, float *region) const\n{\n    vector<size_t> rDims;\n    for (int i = 0; i < 3; i++) { rDims.push_back(max[i] - min[i] + 1); }\n\n    for (size_t k = 0; k < max[2] - min[2] + 1; k++) {\n        for (size_t j = 0; j < max[1] - min[1] + 1; j++) {\n            for (size_t i = 0; i < max[0] - min[0] + 1; i++) {\n                // We are deriving coordinate values from data values, so missing\n                // values may be present\n                //\n                float l_ps = ps[j * rDims[0] + i];\n                if (l_ps == _psVarMV) l_ps = 0;\n\n                float pressure = (a[k] * p0) + (b[k] * l_ps);\n\n                // Convert from pressure to meters above the ground:\n                // [1] \"A Quick Derivation relating altitude to air pressure\" from\n                // Portland State Aerospace Society, Version 1.03, 12/22/2004.\n                //\n                region[k * rDims[0] * rDims[1] + j * rDims[0] + i] = 44331.5 - (4946.62 * std::pow(pressure, 0.190263));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "lib/vdc/DerivedVarMgr.cpp",
    "content": "#include \"vapor/VAssert.h\"\n#include <sstream>\n#include \"vapor/DerivedVarMgr.h\"\n\nusing namespace VAPoR;\n\nDerivedVarMgr::DerivedVarMgr() {}\n\nint DerivedVarMgr::initialize(const std::vector<string> &, const std::vector<string> &) { return (0); }\n\nvoid DerivedVarMgr::AddCoordVar(DerivedCoordVar *cvar)\n{\n    _coordVars[cvar->GetName()] = cvar;\n    _vars[cvar->GetName()] = cvar;\n}\n\nvoid DerivedVarMgr::AddDataVar(DerivedDataVar *dvar)\n{\n    _dataVars[dvar->GetName()] = dvar;\n    _vars[dvar->GetName()] = dvar;\n}\n\nvoid DerivedVarMgr::RemoveVar(const DerivedVar *var)\n{\n    bool done = false;\n    while (!done) {\n        map<string, DerivedVar *>::iterator itr;\n        done = true;\n        for (itr = _vars.begin(); itr != _vars.end(); ++itr) {\n            if (itr->second == var) {\n                _vars.erase(itr);\n                done = false;\n                break;\n            }\n        }\n    }\n\n    done = false;\n    while (!done) {\n        map<string, DerivedCoordVar *>::iterator itr;\n        done = true;\n        for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) {\n            if (itr->second == var) {\n                _coordVars.erase(itr);\n                done = false;\n                break;\n            }\n        }\n    }\n\n    done = false;\n    while (!done) {\n        map<string, DerivedDataVar *>::iterator itr;\n        done = true;\n        for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) {\n            if (itr->second == var) {\n                _dataVars.erase(itr);\n                done = false;\n                break;\n            }\n        }\n    }\n}\n\nvoid DerivedVarMgr::AddMesh(const Mesh &m) { _meshes[m.GetName()] = m; }\n\nDerivedVar *DerivedVarMgr::GetVar(string varname) const\n{\n    DerivedVar *var = _getDataVar(varname);\n    if (var) return (var);\n\n    var = _getCoordVar(varname);\n    if (var) return (var);\n\n    return (NULL);\n}\n\nstd::vector<string> DerivedVarMgr::getMeshNames() const\n{\n    std::map<string, Mesh>::const_iterator itr;\n    vector<string>                         names;\n    for (itr = _meshes.begin(); itr != _meshes.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nbool DerivedVarMgr::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    std::map<string, Mesh>::const_iterator itr;\n    itr = _meshes.find(mesh_name);\n    if (itr == _meshes.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nbool DerivedVarMgr::getCoordVarInfo(string varname, DC::CoordVar &cvarInfo) const\n{\n    DerivedCoordVar *dvar = _getCoordVar(varname);\n    if (!dvar) return (false);\n\n    return (dvar->GetCoordVarInfo(cvarInfo));\n}\n\nbool DerivedVarMgr::getDataVarInfo(string varname, DC::DataVar &dvarInfo) const\n{\n    DerivedDataVar *dvar = _getDataVar(varname);\n    if (!dvar) return (false);\n\n    return (dvar->GetDataVarInfo(dvarInfo));\n}\n\nbool DerivedVarMgr::getBaseVarInfo(string varname, DC::BaseVar &varInfo) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (false);\n\n    return (var->GetBaseVarInfo(varInfo));\n}\n\nstd::vector<string> DerivedVarMgr::getDataVarNames() const\n{\n    ;\n    map<string, DerivedDataVar *>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nstd::vector<string> DerivedVarMgr::getCoordVarNames() const\n{\n    ;\n    map<string, DerivedCoordVar *>::const_iterator itr;\n\n    vector<string> names;\n    for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nsize_t DerivedVarMgr::getNumRefLevels(string varname) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (0);\n\n    return (var->GetNumRefLevels());\n}\n\nbool DerivedVarMgr::getAtt(string varname, string attname, vector<double> &values) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (false);\n\n    return (var->GetAtt(attname, values));\n}\n\nbool DerivedVarMgr::getAtt(string varname, string attname, vector<long> &values) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (false);\n\n    return (var->GetAtt(attname, values));\n}\n\nbool DerivedVarMgr::getAtt(string varname, string attname, string &values) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (false);\n\n    return (var->GetAtt(attname, values));\n}\n\nstd::vector<string> DerivedVarMgr::getAttNames(string varname) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (vector<string>());\n\n    return (var->GetAttNames());\n}\n\nDC::XType DerivedVarMgr::getAttType(string varname, string attname) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (DC::INVALID);\n\n    return (var->GetAttType(attname));\n}\n\nint DerivedVarMgr::getDimLensAtLevel(string varname, int level, std::vector<size_t> &dims_at_level, std::vector<size_t> &bs_at_level) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (-1);\n\n    return (var->GetDimLensAtLevel(level, dims_at_level, bs_at_level));\n}\n\nint DerivedVarMgr::openVariableRead(size_t ts, string varname, int level, int lod)\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) {\n        SetErrMsg(\"Invalid variable : %s\", varname.c_str());\n        return (-1);\n    }\n\n    int fd = var->OpenVariableRead(ts, level, lod);\n    if (fd < 0) return (fd);\n\n    DC::FileTable::FileObject *f = new DC::FileTable::FileObject(ts, varname, level, lod, fd);\n\n    return (_fileTable.AddEntry(f));\n}\n\nint DerivedVarMgr::closeVariable(int fd)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    string      varname = f->GetVarname();\n    DerivedVar *var = _getVar(varname);\n    if (!var) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    int derivedFD = f->GetAux();\n\n    _fileTable.RemoveEntry(fd);\n    delete f;\n\n    return (var->CloseVariable(derivedFD));\n}\n\nint DerivedVarMgr::readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    string      varname = f->GetVarname();\n    DerivedVar *var = _getVar(varname);\n    if (!var) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    int derivedFD = f->GetAux();\n\n    return (var->ReadRegion(derivedFD, min, max, region));\n}\n\nint DerivedVarMgr::readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region)\n{\n    DC::FileTable::FileObject *f = _fileTable.GetEntry(fd);\n\n    if (!f) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    string      varname = f->GetVarname();\n    DerivedVar *var = _getVar(varname);\n    if (!var) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    int derivedFD = f->GetAux();\n\n    return (var->ReadRegion(derivedFD, min, max, region));\n}\n\nbool DerivedVarMgr::variableExists(size_t ts, string varname, int reflevel, int lod) const\n{\n    DerivedVar *var = _getVar(varname);\n    if (!var) return (false);\n\n    return (var->VariableExists(ts, reflevel, lod));\n}\n\nDerivedVar *DerivedVarMgr::_getVar(string name) const\n{\n    map<string, DerivedVar *>::const_iterator itr;\n\n    itr = _vars.find(name);\n    if (itr == _vars.end()) return (NULL);\n\n    return (itr->second);\n}\n\nDerivedDataVar *DerivedVarMgr::_getDataVar(string name) const\n{\n    map<string, DerivedDataVar *>::const_iterator itr;\n\n    itr = _dataVars.find(name);\n    if (itr == _dataVars.end()) return (NULL);\n\n    return (itr->second);\n}\n\nDerivedCoordVar *DerivedVarMgr::_getCoordVar(string name) const\n{\n    map<string, DerivedCoordVar *>::const_iterator itr;\n\n    itr = _coordVars.find(name);\n    if (itr == _coordVars.end()) return (NULL);\n\n    return (itr->second);\n}\n"
  },
  {
    "path": "lib/vdc/GeoUtil.cpp",
    "content": "#include <cmath>\n#include <iostream>\n#include <algorithm>\n#include <vapor/GeoUtil.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nnamespace {\n\ntemplate<class T> void _minmax(const T *a, int n, int stride, T &min, T &max)\n{\n    min = max = a[0];\n\n    for (int i = 0; i < n; i++) {\n        if (a[i * stride] < min) min = a[i * stride];\n        if (a[i * stride] > max) max = a[i * stride];\n    }\n}\n//\n// Shift 1D array of longitudes, if needed, such that values\n// are in the specified range, typically [-360.0..360.0] or [-180.0..180.0]\n//\ntemplate<class ForwardIt> void shiftLonTemplate(ForwardIt first, ForwardIt last, double bound)\n{\n    for (auto itr = first; itr != last; ++itr) {\n        while (*itr > bound) *itr -= 360.0;\n    }\n\n    for (auto itr = first; itr != last; ++itr) {\n        while (*itr < (-1 * bound)) *itr += 360.0;\n    }\n}\n\n//\n// Make longitude values monotonically increasing\n//\ntemplate<class ForwardIt> void unwrapLongitudeTemplate(ForwardIt first, ForwardIt last)\n{\n    auto itr = first;\n    if (itr == last) return;\n\n    auto startValue = *itr;\n    ++itr;\n\n    for (; itr != last; ++itr) {\n        while (*itr < startValue) { *itr += 360.0; }\n    }\n}\n\n\n\ntemplate<class T> void _ExtractBoundaryTemplate(const T *a, int nx, int ny, T *bdry)\n{\n    T *bdryptr = bdry;\n\n    for (int i = 0; i < nx; i++) *bdryptr++ = a[i];\n    for (int j = 1; j < ny; j++) *bdryptr++ = a[nx * j + nx - 1];\n    for (int i = nx - 2; i >= 0; i--) *bdryptr++ = a[nx * (ny - 1) + i];\n    for (int j = ny - 2; j >= 1; j--) *bdryptr++ = a[j * nx];\n}\n\n};    // namespace\n\nvoid GeoUtil::ShiftLon(vector<float>::iterator first, vector<float>::iterator last, double bound) { shiftLonTemplate(first, last, bound); }\nvoid GeoUtil::ShiftLon(vector<double>::iterator first, vector<double>::iterator last, double bound) { shiftLonTemplate(first, last, bound); }\nvoid GeoUtil::ShiftLon(float *first, float *last, double bound) { shiftLonTemplate(first, last, bound); }\n\nvoid GeoUtil::UnwrapLongitude(vector<float>::iterator first, vector<float>::iterator last) { unwrapLongitudeTemplate(first, last); }\nvoid GeoUtil::UnwrapLongitude(vector<double>::iterator first, vector<double>::iterator last) { unwrapLongitudeTemplate(first, last); }\nvoid GeoUtil::UnwrapLongitude(float *first, float *last) { unwrapLongitudeTemplate(first, last); }\n\n\nvoid GeoUtil::ExtractBoundary(const float *a, int nx, int ny, float *bdry) { _ExtractBoundaryTemplate(a, nx, ny, bdry); }\n\nvoid GeoUtil::ExtractBoundary(const double *a, int nx, int ny, double *bdry) { _ExtractBoundaryTemplate(a, nx, ny, bdry); }\n"
  },
  {
    "path": "lib/vdc/Grid.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <numeric>\n#include <cmath>\n#include <cassert>\n#include <algorithm>\n#include <time.h>\n#ifdef Darwin\n    #include <mach/mach_time.h>\n#endif\n#ifdef _WINDOWS\n    #include \"windows.h\"\n    #include \"Winbase.h\"\n    #include <limits>\n#endif\n\n#include <vapor/utils.h>\n#include <vapor/Grid.h>\n#include <vapor/OpenMPSupport.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nnamespace {\n\n// Check for point on a quadralateral vertex\n//\nbool interpolate_point_on_node(const std::array<float, 4> &verts, double xwgt, double ywgt, float mv, float &v)\n{\n    if (xwgt == 1.0 && ywgt == 1.0) {\n        v = verts[0];\n        return (true);\n    }\n    if (xwgt == 0.0 && ywgt == 1.0) {\n        v = verts[1];\n        return (true);\n    }\n    if (xwgt == 1.0 && ywgt == 0.0) {\n        v = verts[2];\n        return (true);\n    }\n    if (xwgt == 0.0 && ywgt == 0.0) {\n        v = verts[3];\n        return (true);\n    }\n\n    return (false);\n}\n\n// Check for point on a quad edge, linear interplate along edge if found\n//\nbool interpolate_point_on_edge(const std::array<float, 4> &verts, double xwgt, double ywgt, float mv, float &v)\n{\n    // X edge, bottom\n    //\n    if (ywgt == 1.0 && xwgt > 0.0 && xwgt < 1.0 && verts[0] != mv && verts[1] != mv) {\n        v = (verts[0] * xwgt) + (verts[1] * (1.0 - xwgt));\n        return (true);\n    }\n\n    // Y edge, right\n    //\n    if (xwgt == 0.0 && ywgt > 0.0 && ywgt < 1.0 && verts[1] != mv && verts[3] != mv) {\n        v = (verts[1] * ywgt) + (verts[3] * (1.0 - ywgt));\n        return (true);\n    }\n\n    // X edge, top\n    //\n    if (ywgt == 0.0 && xwgt > 0.0 && xwgt < 1.0 && verts[2] != mv && verts[3] != mv) {\n        v = (verts[2] * xwgt) + (verts[3] * (1.0 - xwgt));\n        return (true);\n    }\n\n    // Y edge, left\n    //\n    if (xwgt == 1.0 && ywgt > 0.0 && ywgt < 1.0 && verts[0] != mv && verts[2] != mv) {\n        v = (verts[0] * ywgt) + (verts[2] * (1.0 - ywgt));\n        return (true);\n    }\n\n    return (false);\n}\n\n}    // namespace\n\nGrid::Grid() { _dims = {1, 1, 1}; }\n\nvoid Grid::_grid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, size_t topology_dimension)\n{\n    for (int i = 0; i < bs.size(); i++) {\n        VAssert(bs[i] > 0);\n        VAssert(dims[i] > 0);\n\n        _bdims[i] = ((dims[i] - 1) / bs[i]) + 1;\n        _bs[i] = bs[i];\n        _bdimsDeprecated.push_back(_bdims[i]);\n        _bsDeprecated.push_back(_bs[i]);\n    }\n    VAssert(blks.size() == 0 ||    // dataless\n            blks.size() == std::accumulate(_bdims.begin(), _bdims.end(), 1, std::multiplies<size_t>()));\n\n    _dims = dims;\n    _periodic = vector<bool>(topology_dimension, false);\n    _topologyDimension = topology_dimension;\n    _missingValue = INFINITY;\n    _hasMissing = false;\n    _nodeIDOffset = 0;\n    _cellIDOffset = 0;\n    _minAbs = {0, 0, 0};\n\n    //\n    // Shallow  copy blocks\n    //\n    _blks = blks;\n}\n\nGrid::Grid(const DimsType &dims, const DimsType &bs, const std::vector<float *> &blks, size_t topology_dimension) { _grid(dims, bs, blks, topology_dimension); }\n\nGrid::Grid(const std::vector<size_t> &dimsv, const std::vector<size_t> &bsv, const std::vector<float *> &blks, size_t topology_dimension)\n{\n    VAssert(dimsv.size() <= 3);\n    VAssert(dimsv.size() == bsv.size());\n\n    DimsType dims = {1, 1, 1};\n    DimsType bs = {1, 1, 1};\n    CopyToArr3(dimsv, dims);\n    CopyToArr3(bsv, bs);\n    _grid(dims, bs, blks, topology_dimension);\n}\n\nsize_t Grid::GetNumDimensions(DimsType dims)\n{\n    size_t nDims = 0;\n    for (size_t i = 0; i < dims.size(); i++) {\n        VAssert(dims[i] > 0);\n        if (dims[i] > 1) nDims++;\n    }\n    return (nDims);\n}\n\n\nfloat Grid::GetMissingValue() const { return (_missingValue); }\n\nvoid Grid::GetUserExtents(CoordType &minu, CoordType &maxu) const\n{\n    size_t n = min(GetGeometryDim(), _minuCache.size());\n    auto   p = [](double v) { return (v == std::numeric_limits<double>::infinity()); };\n    if (std::any_of(_minuCache.begin(), _minuCache.begin() + n, p) || std::any_of(_maxuCache.begin(), _maxuCache.begin() + n, p)) {\n        _minuCache = {0.0, 0.0, 0.0};\n        _maxuCache = {0.0, 0.0, 0.0};\n        GetUserExtentsHelper(_minuCache, _maxuCache);\n    }\n\n    minu = _minuCache;\n    maxu = _maxuCache;\n}\n\nfloat Grid::GetValueAtIndex(const DimsType &indices) const\n{\n    float *fptr = GetValuePtrAtIndex(_blks, indices);\n    if (!fptr) return (GetMissingValue());\n    return (*fptr);\n}\n\nvoid Grid::SetValue(const DimsType &indices, float v)\n{\n    float *fptr = GetValuePtrAtIndex(_blks, indices);\n    if (!fptr) return;\n    *fptr = v;\n}\n\nfloat *Grid::GetValuePtrAtIndex(const std::vector<float *> &blks, const DimsType &indices) const\n{\n    if (!blks.size()) return (NULL);\n\n    DimsType cIndices;\n    ClampIndex(indices, cIndices);\n\n    size_t xb = cIndices[0] / _bs[0];\n    size_t yb = cIndices[1] / _bs[1];\n    size_t zb = cIndices[2] / _bs[2];\n\n    size_t x = cIndices[0] % _bs[0];\n    size_t y = cIndices[1] % _bs[1];\n    size_t z = cIndices[2] % _bs[2];\n\n    float *blk = blks[zb * _bdims[0] * _bdims[1] + yb * _bdims[0] + xb];\n    return (&blk[z * _bs[0] * _bs[1] + y * _bs[0] + x]);\n}\n\nfloat Grid::AccessIJK(size_t i, size_t j, size_t k) const\n{\n    DimsType indices = {i, j, k};\n    return (GetValueAtIndex(indices));\n}\n\nvoid Grid::SetValueIJK(size_t i, size_t j, size_t k, float v)\n{\n    DimsType indices = {i, j, k};\n    return (SetValue(indices, v));\n}\n\nvoid Grid::GetRange(float range[2]) const\n{\n    const auto missingVal = GetMissingValue();\n    const auto num_vals = _dims[0] * _dims[1] * _dims[2];\n    auto num_threads = size_t{1};\n#pragma omp parallel\n    {\n      if (omp_get_thread_num() == 0)\n        num_threads = omp_get_num_threads();\n    }\n    const auto stride_size = num_vals / num_threads;\n\n    auto min_vec = std::vector<float>(num_threads, missingVal);\n    auto max_vec = std::vector<float>(num_threads, missingVal);\n\n#pragma omp parallel for\n    for (size_t i = 0; i < num_threads; i++) {\n      auto beg = this->cbegin() + i * stride_size;\n      auto end = beg;\n      if (i < num_threads - 1) \n        end += stride_size;\n      else\n        end = this->cend();\n\n      while (*beg == missingVal && beg != end)\n        ++beg;\n\n      if (beg != end) {\n        auto min = *beg;\n        auto max = *beg;\n        for (auto itr  = beg + 1; itr != end; ++itr) {\n          if (*itr != missingVal) {\n            min = std::min(*itr, min);      \n            max = std::max(*itr, max);      \n          }\n        }\n        min_vec[i] = min;\n        max_vec[i] = max;\n      }\n    } // finish omp section\n\n    if (std::all_of(min_vec.begin(), min_vec.end(), \n        [missingVal](float v){return v == missingVal;})) {\n      range[0] = missingVal;\n      range[1] = missingVal;\n    }\n    else {\n      auto it = std::remove(min_vec.begin(), min_vec.end(), missingVal);\n      range[0] = *std::min_element(min_vec.begin(), it);\n      it = std::remove(max_vec.begin(), max_vec.end(), missingVal);\n      range[1] = *std::max_element(max_vec.begin(), it);\n    }\n}\n\nvoid Grid::GetRange(const DimsType &min, const DimsType &max, float range[2]) const\n{\n    DimsType cMin;\n    ClampIndex(min, cMin);\n\n    DimsType cMax;\n    ClampIndex(max, cMax);\n\n    float mv = GetMissingValue();\n\n    range[0] = range[1] = mv;\n\n    bool first = true;\n    for (size_t k = cMin[2]; k <= cMax[2]; k++) {\n        for (size_t j = cMin[1]; j <= cMax[1]; j++) {\n            for (size_t i = cMin[0]; i <= cMax[0]; i++) {\n                float v = AccessIJK(i, j, k);\n                if (first && v != mv) {\n                    range[0] = range[1] = v;\n                    first = false;\n                }\n\n                if (!first) {\n                    if (v < range[0] && v != mv)\n                        range[0] = v;\n                    else if (v > range[1] && v != mv)\n                        range[1] = v;\n                }\n            }\n        }\n    }\n}\n\nfloat Grid::GetValue(const CoordType &coords) const\n{\n    if (!_blks.size()) return (GetMissingValue());\n\n    // Clamp coordinates on periodic boundaries to grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    if (_interpolationOrder == 0) {\n        return (GetValueNearestNeighbor(cCoords));\n    } else {\n        return (GetValueLinear(cCoords));\n    }\n}\n\n\nvoid Grid::GetUserCoordinates(size_t i, double &x, double &y, double &z) const\n{\n    x = y = z = 0.0;\n    vector<size_t> indices = {i};\n    vector<double> coords;\n    GetUserCoordinates(indices, coords);\n    x = coords[0];\n    y = coords[1];\n    z = coords[2];\n}\n\nvoid Grid::GetUserCoordinates(size_t i, size_t j, double &x, double &y, double &z) const\n{\n    x = y = z = 0.0;\n    vector<size_t> indices = {i, j};\n    vector<double> coords;\n    GetUserCoordinates(indices, coords);\n    x = coords[0];\n    y = coords[1];\n    z = coords[2];\n}\n\nvoid Grid::GetUserCoordinates(size_t i, size_t j, size_t k, double &x, double &y, double &z) const\n{\n    x = y = z = 0.0;\n    vector<size_t> indices = {i, j, k};\n    vector<double> coords;\n    GetUserCoordinates(indices, coords);\n    x = coords[0];\n    y = coords[1];\n    z = coords[2];\n}\n\nvoid Grid::SetInterpolationOrder(int order)\n{\n    if (order < 0 || order > 2) order = 1;\n    _interpolationOrder = order;\n}\n\nDimsType Grid::Dims(const DimsType &min, const DimsType &max)\n{\n    DimsType dims;\n\n    for (int i = 0; i < min.size(); i++) { dims[i] = (max[i] - min[i] + 1); }\n    return (dims);\n}\n\nfloat Grid::BilinearInterpolate(size_t i, size_t j, size_t k, const double xwgt, const double ywgt) const\n{\n    auto dims = GetDimensions();\n    VAssert(i < dims[0]);\n    VAssert(j < dims[1]);\n    VAssert(k < dims[2]);\n\n    float mv = GetMissingValue();\n\n    std::array<float, 4> verts{0.0, 0.0, 0.0, 0.0};\n    verts[0] = AccessIJK(i, j, k);\n    verts[1] = dims[0] > 1 ? AccessIJK(i + 1, j, k) : 0.0;\n    verts[2] = dims[1] > 1 ? AccessIJK(i, j + 1, k) : 0.0;\n    verts[3] = dims[0] > 1 && dims[1] > 1 ? AccessIJK(i + 1, j + 1, k) : 0.0;\n\n    if (std::any_of(verts.begin(), verts.end(), [&mv](float v) { return (mv == v); })) {\n        float v = 0.0;\n        if (interpolate_point_on_node(verts, xwgt, ywgt, mv, v)) return (v);\n\n        if (interpolate_point_on_edge(verts, xwgt, ywgt, mv, v)) return (v);\n\n        return (mv);\n    }\n\n    return (((verts[0] * xwgt + verts[1] * (1.0 - xwgt)) * ywgt) + ((verts[2] * xwgt + verts[3] * (1.0 - xwgt)) * (1.0 - ywgt)));\n}\n\nfloat Grid::TrilinearInterpolate(size_t i, size_t j, size_t k, const double xwgt, const double ywgt, const double zwgt) const\n{\n    auto dims = GetDimensions();\n    VAssert(i < dims[0]);\n    VAssert(j < dims[1]);\n    VAssert(k < dims[2]);\n\n    float mv = GetMissingValue();\n\n    float v0 = BilinearInterpolate(i, j, k, xwgt, ywgt);\n\n    if (dims[2] > 1 && k < (dims[2] - 1))\n        k++;\n    else\n        return (v0);\n\n    float v1 = BilinearInterpolate(i, j, k, xwgt, ywgt);\n\n    if (v0 == mv || v1 == mv) {\n        if (zwgt == 1.0)\n            return (v0);\n        else if (zwgt == 0.0)\n            return (v1);\n        else\n            return (mv);\n    }\n\n\n    // Linearly interpolate along Z axis\n    //\n    return (v0 * zwgt + v1 * (1.0 - zwgt));\n}\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Iterators\n//\n/////////////////////////////////////////////////////////////////////////////\n\nGrid::ConstNodeIteratorSG::ConstNodeIteratorSG(const Grid *g, bool begin) : ConstNodeIteratorAbstract()\n{\n    _dims = g->GetNodeDimensions();\n    _index = {0, 0, 0};\n    _lastIndex = {0, 0, _dims[_dims.size() - 1]};\n\n    if (!begin) { _index = _lastIndex; }\n}\n\nGrid::ConstNodeIteratorSG::ConstNodeIteratorSG(const ConstNodeIteratorSG &rhs) : ConstNodeIteratorAbstract()\n{\n    _dims = rhs._dims;\n    _index = rhs._index;\n    _lastIndex = rhs._lastIndex;\n}\n\nGrid::ConstNodeIteratorSG::ConstNodeIteratorSG() : ConstNodeIteratorAbstract()\n{\n    _dims = {1, 1, 1};\n    _index = {0, 0, 0};\n    _lastIndex = {0, 0, 0};\n}\n\nvoid Grid::ConstNodeIteratorSG::next()\n{\n    _index[0]++;\n    if (_index[0] < _dims[0]) { return; }\n\n    _index[0] = 0;\n    _index[1]++;\n    if (_index[1] < _dims[1]) { return; }\n\n    _index[1] = 0;\n    _index[2]++;\n    if (_index[2] < _dims[2]) { return; }\n\n    _index[2] = _dims[2];    // last index;\n}\n\nvoid Grid::ConstNodeIteratorSG::next(const long &offset)\n{\n    if (!_index.size()) return;\n\n    long maxIndexL = Wasp::VProduct(_dims.data(), _dims.size()) - 1;\n    long newIndexL = Wasp::LinearizeCoords(_index.data(), _dims.data(), _dims.size()) + offset;\n    if (newIndexL < 0) { newIndexL = 0; }\n    if (newIndexL > maxIndexL) {\n        _index = _lastIndex;\n        return;\n    }\n\n    Wasp::VectorizeCoords(newIndexL, _dims.data(), _index.data(), _dims.size());\n}\n\nGrid::ConstNodeIteratorBoxSG::ConstNodeIteratorBoxSG(const Grid *g, const CoordType &minu, const CoordType &maxu) : ConstNodeIteratorSG(g, true), _pred(minu, maxu)\n{\n    _coordItr = g->ConstCoordBegin();\n\n    // Advance to first node inside box\n    //\n    if (!_pred(*_coordItr)) { next(); }\n}\n\nGrid::ConstNodeIteratorBoxSG::ConstNodeIteratorBoxSG(const ConstNodeIteratorBoxSG &rhs) : ConstNodeIteratorSG()\n{\n    _coordItr = rhs._coordItr;\n    _pred = rhs._pred;\n}\n\nGrid::ConstNodeIteratorBoxSG::ConstNodeIteratorBoxSG() : ConstNodeIteratorSG() {}\n\nvoid Grid::ConstNodeIteratorBoxSG::next()\n{\n    do {\n        ConstNodeIteratorSG::next();\n        ++_coordItr;\n    } while (_index != _lastIndex && !_pred(*_coordItr));\n}\n\nvoid Grid::ConstNodeIteratorBoxSG::next(const long &offset)\n{\n    _coordItr += offset;\n\n    while (_index != _lastIndex && !_pred(*_coordItr)) {\n        ConstNodeIteratorSG::next();\n        ++_coordItr;\n    }\n}\n\nGrid::ConstCellIteratorSG::ConstCellIteratorSG(const Grid *g, bool begin) : ConstCellIteratorAbstract()\n{\n    _dims = g->GetCellDimensions();\n    _index = {0, 0, 0};\n    _lastIndex = {0, 0, _dims[_dims.size() - 1]};\n\n    if (!begin) { _index = _lastIndex; }\n}\n\nGrid::ConstCellIteratorSG::ConstCellIteratorSG(const ConstCellIteratorSG &rhs) : ConstCellIteratorAbstract()\n{\n    _dims = rhs._dims;\n    _index = rhs._index;\n    _lastIndex = rhs._lastIndex;\n}\n\nGrid::ConstCellIteratorSG::ConstCellIteratorSG() : ConstCellIteratorAbstract()\n{\n    _dims = {1, 1, 1};\n    _index = {0, 0, 0};\n    _lastIndex = {0, 0, 0};\n}\n\nvoid Grid::ConstCellIteratorSG::next()\n{\n    _index[0]++;\n    if (_index[0] < (_dims[0])) { return; }\n\n    _index[0] = 0;\n    _index[1]++;\n    if (_index[1] < (_dims[1])) { return; }\n\n    _index[1] = 0;\n    _index[2]++;\n    if (_index[2] < (_dims[2])) { return; }\n\n    _index[2] = _dims[2];    // last index;\n}\n\nvoid Grid::ConstCellIteratorSG::next(const long &offset)\n{\n    long maxIndexL = Wasp::VProduct(_dims.data(), _dims.size()) - 1;\n    long newIndexL = Wasp::LinearizeCoords(_index.data(), _dims.data(), _dims.size()) + offset;\n    if (newIndexL < 0) { newIndexL = 0; }\n    if (newIndexL > maxIndexL) {\n        _index = _lastIndex;\n        return;\n    }\n\n    Wasp::VectorizeCoords(newIndexL, _dims.data(), _index.data(), _dims.size());\n}\n\nbool Grid::ConstCellIteratorBoxSG::_cellInsideBox(const size_t cindices[]) const\n{\n    return (true);\n}\n\nGrid::ConstCellIteratorBoxSG::ConstCellIteratorBoxSG(const Grid *g, const CoordType &minu, const CoordType &maxu) : ConstCellIteratorSG(g, true), _pred(minu, maxu)\n{\n    _g = g;\n\n    // Advance to first node inside box\n    //\n    if (!_cellInsideBox(_index.data())) { next(); }\n}\n\nGrid::ConstCellIteratorBoxSG::ConstCellIteratorBoxSG(const ConstCellIteratorBoxSG &rhs) : ConstCellIteratorSG()\n{\n    _pred = rhs._pred;\n}\n\nGrid::ConstCellIteratorBoxSG::ConstCellIteratorBoxSG() : ConstCellIteratorSG() {}\n\nvoid Grid::ConstCellIteratorBoxSG::next()\n{\n    do {\n        ConstCellIteratorSG::next();\n    } while (!_cellInsideBox(_index.data()) && _index != _lastIndex);\n}\n\nvoid Grid::ConstCellIteratorBoxSG::next(const long &offset)\n{\n    long count = offset;\n    while (!_cellInsideBox(_index.data()) && _index != _lastIndex && count > 0) {\n        ConstCellIteratorSG::next();\n        count--;\n    }\n}\n\n//\n//\n// Iterators\n//\n//\n\ntemplate<class T> Grid::ForwardIterator<T>::ForwardIterator(T *rg, bool begin, const CoordType &minu, const CoordType &maxu) : _pred(minu, maxu)\n{\n    _blks = rg->GetBlks();\n\n    _dims3d = rg->GetDimensions();\n    _bdims3d = {1, 1, 1};\n    _bs3d = {1, 1, 1};\n    CopyToArr3(rg->GetDimensionInBlks(), _bdims3d);\n    CopyToArr3(rg->GetBlockSize(), _bs3d);\n\n    _blocksize = Wasp::VProduct(_bs3d.data(), _bs3d.size());\n\n    _index = {0, 0, 0};\n    _lastIndex = {0, 0, _dims3d[_dims3d.size() - 1]};\n\n    if (!begin || !_blks.size()) {\n        _index = _lastIndex;\n        _itr = nullptr;\n        _coordItr = rg->ConstCoordEnd();\n        return;\n    }\n\n    _coordItr = rg->ConstCoordBegin();\n    _xb = 0;\n    _itr = &_blks[0][0];\n\n    if (!_pred(*_coordItr)) { operator++(); }\n}\n\ntemplate<class T> Grid::ForwardIterator<T>::ForwardIterator(ForwardIterator<T> &&rhs)\n{\n    _blks = rhs._blks;\n    _dims3d = rhs._dims3d;\n    _bdims3d = rhs._bdims3d;\n    _bs3d = rhs._bs3d;\n    _blocksize = rhs._blocksize;\n    _coordItr = std::move(rhs._coordItr);\n    _index = rhs._index;\n    _lastIndex = rhs._lastIndex;\n    _xb = rhs._xb;\n    _itr = rhs._itr;\n    rhs._itr = nullptr;\n    _pred = rhs._pred;\n}\n\ntemplate<class T> Grid::ForwardIterator<T>::ForwardIterator()\n{\n    _blks.clear();\n    _dims3d = {1, 1, 1};\n    _bdims3d = {1, 1, 1};\n    _bs3d = {1, 1, 1};\n    _blocksize = 1;\n    _index = {0, 0, 0};\n    _lastIndex = {0, 0, 0};\n    _xb = 0;\n    _itr = nullptr;\n}\n\ntemplate<class T> Grid::ForwardIterator<T> &Grid::ForwardIterator<T>::operator=(ForwardIterator<T> rhs)\n{\n    swap(*this, rhs);\n    return (*this);\n}\n\ntemplate<class T> Grid::ForwardIterator<T> &Grid::ForwardIterator<T>::operator++()\n{\n    if (!_blks.size()) return (*this);\n\n    size_t xb = 0;\n    size_t yb = 0;\n    size_t zb = 0;\n    size_t x = 0;\n    size_t y = 0;\n    size_t z = 0;\n    do {\n        _xb++;\n        _itr++;\n        _index[0]++;\n        if (_pred.Enabled()) ++_coordItr;\n\n        if (_xb < _bs3d[0] && _index[0] < _dims3d[0]) {\n            if (_pred(*_coordItr)) { return (*this); }\n\n            continue;\n        }\n\n        _xb = 0;\n        if (_index[0] >= _dims3d[0]) {\n            _index[0] = _xb = 0;\n            _index[1]++;\n        }\n\n        if (_index[1] >= _dims3d[1]) {\n            _index[1] = 0;\n            _index[2]++;\n        }\n\n        if (_index == _lastIndex) {\n            return (*this);    // last element\n        }\n\n        x = _index[0] % _bs3d[0];\n        xb = _index[0] / _bs3d[0];\n        y = _index[1] % _bs3d[1];\n        yb = _index[1] / _bs3d[1];\n        z = _index[2] % _bs3d[2];\n        zb = _index[2] / _bs3d[2];\n\n        float *blk = _blks[zb * _bdims3d[0] * _bdims3d[1] + yb * _bdims3d[0] + xb];\n        _itr = &blk[z * _bs3d[0] * _bs3d[1] + y * _bs3d[0] + x];\n\n    } while (_index != _lastIndex && !_pred(*_coordItr));\n\n    return (*this);\n}\n\ntemplate<class T> Grid::ForwardIterator<T> Grid::ForwardIterator<T>::operator++(int)\n{\n    ForwardIterator temp(*this);\n    ++(*this);\n    return (temp);\n}\n\ntemplate<class T> Grid::ForwardIterator<T> &Grid::ForwardIterator<T>::operator+=(const long int &offset)\n{\n    VAssert(offset >= 0);\n\n    if (!_blks.size()) return (*this);\n\n    long maxIndexL = Wasp::VProduct(_dims3d.data(), _dims3d.size()) - 1;\n    long indexL = Wasp::LinearizeCoords(_index.data(), _dims3d.data(), _index.size()) + offset;\n\n    // Check for overflow\n    //\n    if (indexL < 0) { indexL = 0; }\n    if (indexL > maxIndexL) {\n        _index = _lastIndex;\n        return (*this);\n    }\n\n    Wasp::VectorizeCoords(indexL, _dims3d.data(), _index.data(), _index.size());\n    if (_pred.Enabled()) _coordItr += offset;\n\n    size_t x = _index[0] % _bs3d[0];\n    size_t xb = _index[0] / _bs3d[0];\n    size_t y = _index[1] % _bs3d[1];\n    size_t yb = _index[1] / _bs3d[1];\n    size_t z = _index[2] % _bs3d[2];\n    size_t zb = _index[2] / _bs3d[2];\n\n    _xb = x;\n\n    float *blk = _blks[zb * _bdims3d[0] * _bdims3d[1] + yb * _bdims3d[0] + xb];\n    _itr = &blk[z * _bs3d[0] * _bs3d[1] + y * _bs3d[0] + x];\n\n    // If no predicate, or if there is a predicate and it evaluates to\n    // true, we're done.\n    //\n    if (!_pred.Enabled() || _pred(*_coordItr)) { return (*this); }\n\n    // Let operator++ increment until predicate passes (or end of list)\n    //\n    return (++(*this));\n}\n\ntemplate<class T> Grid::ForwardIterator<T> Grid::ForwardIterator<T>::operator+(const long int &offset) const\n{\n    ForwardIterator temp(*this);\n\n    temp += offset;\n    return (temp);\n}\n\n// Need this so that template definitions can be made in .cpp file, not .h file\n//\ntemplate class Grid::ForwardIterator<Grid>;\ntemplate class Grid::ForwardIterator<const Grid>;\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const Grid &g)\n{\n    o << \"Grid\" << endl;\n\n    o << \" Dimensions \";\n    for (int i = 0; i < g._dims.size(); i++) { o << g._dims[i] << \" \"; }\n    o << endl;\n\n    o << \" Block dimensions \";\n    for (int i = 0; i < g._bs.size(); i++) { o << g._bs[i] << \" \"; }\n    o << endl;\n\n    o << \" Grid dimensions in blocks \";\n    for (int i = 0; i < g._bdims.size(); i++) { o << g._bdims[i] << \" \"; }\n    o << endl;\n\n    o << \" Topological dimension \" << g._topologyDimension << endl;\n\n    o << \" Periodicity \";\n    for (int i = 0; i < g._periodic.size(); i++) { o << g._periodic[i] << \" \"; }\n    o << endl;\n\n    o << \" Missing value flag \" << g._hasMissing << endl;\n    o << \" Missing value \" << g._missingValue << endl;\n    o << \" Interpolation order \" << g._interpolationOrder << endl;\n\n    return (o);\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/GridHelper.cpp",
    "content": "#include <iostream>\n#include <sstream>\n#include <vector>\n#include <map>\n#include <vapor/QuadTreeRectangleP.h>\n#include <vapor/GridHelper.h>\n#include <vapor/UnstructuredGrid3D.h>\nusing namespace Wasp;\nusing namespace VAPoR;\n\nnamespace {\n\n// Format a vector type as a space-separated element string\n//\ntemplate<class T> string vector_to_string(T v)\n{\n    ostringstream oss;\n\n    oss << \"[\";\n    for (int i = 0; i < v.size(); i++) { oss << v[i] << \" \"; }\n    oss << \"]\";\n    return (oss.str());\n}\n\nbool isUnstructured2D(const DC::Mesh &m, const vector<DC::CoordVar> &cvarsinfo, const vector<vector<string>> &cdimnames)\n{\n    DC::Mesh::Type mtype = m.GetMeshType();\n    if (mtype == DC::Mesh::UNSTRUC_2D) { return (true); }\n    return (false);\n}\n\nbool isUnstructuredLayered(const DC::Mesh &m, const vector<DC::CoordVar> &cvarsinfo, const vector<vector<string>> &cdimnames)\n{\n    DC::Mesh::Type mtype = m.GetMeshType();\n    if (mtype == DC::Mesh::UNSTRUC_LAYERED) { return (true); }\n    return (false);\n}\n\nbool isRegular(const DC::Mesh &m, const vector<DC::CoordVar> &cvarsinfo, const vector<vector<string>> &cdimnames)\n{\n    VAssert(cvarsinfo.size() == cdimnames.size());\n\n    for (int i = 0; i < cdimnames.size(); i++) {\n        if (!(cdimnames[i].size() == 1 && cvarsinfo[i].GetUniform())) { return (false); }\n    }\n    return (true);\n}\n\nbool isStretched(const DC::Mesh &m, const vector<DC::CoordVar> &cvarsinfo, const vector<vector<string>> &cdimnames)\n{\n    VAssert(cvarsinfo.size() == cdimnames.size());\n\n    // All dimensions need to be 1D and at least one non-uniform\n    //\n    for (int i = 0; i < cdimnames.size(); i++) {\n        if (!(cdimnames[i].size() == 1)) { return (false); }\n    }\n\n    // Need at least one non-uniform dimension\n    //\n    for (int i = 0; i < cvarsinfo.size(); i++) {\n        if (!(cvarsinfo[i].GetUniform())) { return (true); }\n    }\n\n    return (false);\n}\n\nbool isLayered(const DC::Mesh &m, const vector<DC::CoordVar> &cvarsinfo, const vector<vector<string>> &cdimnames)\n{\n    VAssert(cvarsinfo.size() == cdimnames.size());\n\n    if (cdimnames.size() != 3) return (false);\n\n    for (int i = 0; i < 2; i++) {\n        if (!(cdimnames[i].size() == 1)) { return (false); }\n    }\n\n    if (!(cdimnames[2].size() == 3)) return (false);\n\n    return (true);\n}\n\nbool isUnstructured3D(const DC::Mesh &m, const std::vector<DC::CoordVar> &cvarsinfo, const std::vector<std::vector<string>> &cdimnames)\n{\n    DC::Mesh::Type mtype = m.GetMeshType();\n    if (mtype == DC::Mesh::UNSTRUC_3D) { return (true); }\n    return (false);\n}\n\nbool isCurvilinear(const DC::Mesh &m, const vector<DC::CoordVar> &cvarsinfo, const vector<vector<string>> &cdimnames)\n{\n    VAssert(cvarsinfo.size() == cdimnames.size());\n\n    if (!(cdimnames.size() == 2 || cdimnames.size() == 3)) return (false);\n\n    if (cdimnames.size() == 3 && !((cdimnames[2].size() == 1) || (cdimnames[2].size() == 3))) { return (false); }\n\n    if (!(cdimnames[0].size() == 2 && cdimnames[1].size() == 2)) return (false);\n\n    return (true);\n}\n\n\n};    // namespace\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nstring GridHelper::_getQuadTreeRectangleKey(size_t ts, int level, int lod, const vector<DC::CoordVar> &cvarsinfo, const DimsType &bmin, const DimsType &bmax) const\n{\n    VAssert(cvarsinfo.size() >= 2);\n\n    vector<string> varnames;\n    for (int i = 0; i < cvarsinfo.size(); i++) { varnames.push_back(cvarsinfo[i].GetName()); }\n\n    bool time_varying = false;\n    for (int i = 0; i < cvarsinfo.size(); i++) {\n        if (!cvarsinfo[i].GetTimeDimName().empty()) { time_varying = true; }\n    }\n\n    if (!time_varying) ts = 0;\n\n    ostringstream oss;\n\n    oss << ts;\n    oss << \":\";\n    oss << vector_to_string(varnames);\n    oss << \":\";\n    oss << level;\n    oss << \":\";\n    oss << vector_to_string(bmin);\n    oss << \":\";\n    oss << vector_to_string(bmax);\n\n    return (oss.str());\n}\n\nRegularGrid *GridHelper::_make_grid_regular(const DimsType &dims, const vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax\n\n) const\n{\n    CoordType minu = {0.0, 0.0, 0.0};\n    CoordType maxu = {0.0, 0.0, 0.0};\n    for (int i = 0; i < blkvec.size() - 1 && blkvec[i + 1]; i++) {\n        VAssert(dims[i] > 0);\n        float *coords = blkvec[i + 1];\n        minu[i] = (coords[0]);\n        maxu[i] = (coords[dims[i] - 1]);\n    }\n\n    size_t nblocks = 1;\n    size_t block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    vector<float *> blkptrs;\n    if (blkvec[0]) {\n        for (int i = 0; i < nblocks; i++) { blkptrs.push_back(blkvec[0] + i * block_size); }\n    }\n\n    RegularGrid *rg = new RegularGrid(dims, bs, blkptrs, minu, maxu);\n\n    return (rg);\n}\n\nStretchedGrid *GridHelper::_make_grid_stretched(const DimsType &dims, const vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax\n\n) const\n{\n    size_t nblocks = 1;\n    size_t block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    vector<float *> blkptrs;\n    if (blkvec[0]) {\n        for (int i = 0; i < nblocks; i++) { blkptrs.push_back(blkvec[0] + i * block_size); }\n    }\n\n    vector<double> xcoords;\n    if (blkvec.size() > 1 && blkvec[1]) {\n        for (int i = 0; i < dims[0]; i++) xcoords.push_back(blkvec[1][i]);\n    }\n\n    vector<double> ycoords;\n    if (blkvec.size() > 2 && blkvec[2]) {\n        for (int i = 0; i < dims[1]; i++) ycoords.push_back(blkvec[2][i]);\n    }\n\n    vector<double> zcoords;\n    if (blkvec.size() > 3 && blkvec[3]) {\n        for (int i = 0; i < dims[2]; i++) zcoords.push_back(blkvec[3][i]);\n    }\n\n    StretchedGrid *sg = new StretchedGrid(dims, bs, blkptrs, xcoords, ycoords, zcoords);\n\n    return (sg);\n}\n\nLayeredGrid *GridHelper::_make_grid_layered(const DimsType &dims, const vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax) const\n{\n    // Get horizontal dimensions\n    //\n    vector<double> xcoords;\n    for (int i = 0; i < dims[0]; i++) xcoords.push_back(blkvec[1][i]);\n\n    vector<double> ycoords;\n    for (int i = 0; i < dims[1]; i++) ycoords.push_back(blkvec[2][i]);\n\n    // Data blocks\n    //\n    size_t nblocks = 1;\n    size_t block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    vector<float *> blkptrs, zcblkptrs;\n\n    if (blkvec[0]) {\n        for (int i = 0; i < nblocks; i++) { blkptrs.push_back(blkvec[0] + i * block_size); }\n    }\n\n    // Z Coord blocks\n    //\n    nblocks = 1;\n    block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n    for (int i = 0; i < nblocks; i++) { zcblkptrs.push_back(blkvec[3] + i * block_size); }\n\n    RegularGrid rg(dims, bs, zcblkptrs, CoordType{0.0, 0.0, 0.0}, CoordType{1.0, 1.0, 1.0});\n\n    LayeredGrid *lg = new LayeredGrid(dims, bs, blkptrs, xcoords, ycoords, rg);\n\n    return (lg);\n}\n\nCurvilinearGrid *GridHelper::_make_grid_curvilinear(size_t ts, int level, int lod, const vector<DC::CoordVar> &cvarsinfo, const DimsType &dims, const vector<float *> &blkvec, const DimsType &bs,\n                                                    const DimsType &bmin, const DimsType &bmax)\n{\n\n    // Data blocks\n    //\n    size_t nblocks = 1;\n    size_t block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    // block pointers for data\n    //\n    vector<float *> blkptrs;\n    for (int i = 0; i < nblocks; i++) {\n        if (blkvec[0]) blkptrs.push_back(blkvec[0] + i * block_size);\n    }\n\n    // X horizontal coord blocks\n    //\n    DimsType       bs2d = {bs[0], bs[1], 1};\n    DimsType       bmin2d = {bmin[0], bmin[1], 0};\n    DimsType       bmax2d = {bmax[0], bmax[1], 0};\n    size_t         nblocks2d = 1;\n    size_t         block_size2d = 1;\n    for (int i = 0; i < bs2d.size(); i++) {\n        nblocks2d *= bmax2d[i] - bmin2d[i] + 1;\n        block_size2d *= bs2d[i];\n    }\n\n    vector<float *> xcblkptrs;\n    for (int i = 0; i < nblocks2d; i++) { xcblkptrs.push_back(blkvec[1] + i * block_size2d); }\n\n    // Y horizontal coord blocks\n    //\n    vector<float *> ycblkptrs;\n    for (int i = 0; i < nblocks2d; i++) { ycblkptrs.push_back(blkvec[2] + i * block_size2d); }\n\n    CoordType      minu2d = {0.0, 0.0, 0.0};\n    CoordType      maxu2d = {1.0, 1.0, 1.0};\n    DimsType       dims2d = {dims[0], dims[1], 1};\n    RegularGrid    xrg(dims2d, bs2d, xcblkptrs, minu2d, maxu2d);\n    RegularGrid    yrg(dims2d, bs2d, ycblkptrs, minu2d, maxu2d);\n\n    string qtr_key = _getQuadTreeRectangleKey(ts, level, lod, cvarsinfo, bmin2d, bmax2d);\n\n    // Try to get a shared pointer to the QuadTreeRectangle from the\n    // cache. If one does not exist the Grid class will make one. We use\n    // a shared pointer so that we can cache it for use by other Grid\n    // classes. This a peformance optimization, necessary be creating\n    // a QuadTreeRectangle is expensive.\n    //\n    std::shared_ptr<const QuadTreeRectangleP> qtr = _qtrCache.get(qtr_key);\n\n    CurvilinearGrid *g;\n    if (Grid::GetNumDimensions(dims) == 3 && cvarsinfo[2].GetDimNames().size() == 3) {\n        // Terrain following vertical\n        //\n        CoordType minu = {0.0, 0.0, 0.0};\n        CoordType maxu = {1.0, 1.0, 1.0};\n\n        vector<float *> zcblkptrs;\n        for (int i = 0; i < nblocks; i++) { zcblkptrs.push_back(blkvec[3] + i * block_size); }\n\n        RegularGrid zrg(dims, bs, zcblkptrs, minu, maxu);\n\n        g = new CurvilinearGrid(dims, bs, blkptrs, xrg, yrg, zrg, qtr);\n\n    } else if (Grid::GetNumDimensions(dims) == 3 && cvarsinfo[2].GetDimNames().size() == 1) {\n        // stretched vertical\n        //\n        vector<double> zcoords;\n        for (int i = 0; i < dims[2]; i++) zcoords.push_back(blkvec[3][i]);\n\n        g = new CurvilinearGrid(dims, bs, blkptrs, xrg, yrg, zcoords, qtr);\n    } else {\n        // 2D\n        //\n        g = new CurvilinearGrid(dims, bs, blkptrs, xrg, yrg, vector<double>(), qtr);\n    }\n\n    // No QuadTreeRectangle in cache. So get shared pointer for one created\n    // by UnstructuredGrid2D() and cache it for later use. The memory\n    // will be garbage collected when all pointers to it go out of scope\n    //\n    if (!qtr) {\n        qtr = g->GetQuadTreeRectangle();\n        (void)_qtrCache.put(qtr_key, qtr);\n    }\n\n    return (g);\n}\n\nUnstructuredGrid2D *GridHelper::_make_grid_unstructured2d(size_t ts, int level, int lod, const DC::DataVar &var, const vector<DC::CoordVar> &cvarsinfo, const DimsType &dims,\n                                                          const vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector<int *> &conn_blkvec,\n                                                          const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims,\n                                                          const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset,\n                                                          long faceOffset)\n{\n    VAssert(conn_blkvec.size() >= 1);\n\n    // block pointers for data\n    //\n    size_t nblocks = 1;\n    size_t block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    vector<float *> blkptrs;\n    for (int i = 0; i < nblocks; i++) {\n        if (blkvec[0]) blkptrs.push_back(blkvec[0] + i * block_size);\n    }\n\n    // Block pointers for X coordinates, which are always 1D\n    //\n    vector<float *> xcblkptrs;\n    for (int i = 0; i < nblocks; i++) { xcblkptrs.push_back(blkvec[1] + i * block_size); }\n\n    // Block pointers for X coordinates, which are always 1D\n    //\n    vector<float *> ycblkptrs;\n    for (int i = 0; i < nblocks; i++) { ycblkptrs.push_back(blkvec[2] + i * block_size); }\n\n    // N.B. assumes blkvec contains contiguous blocks :-(\n    //\n    const int *vertexOnFace = conn_blkvec[0];\n    const int *faceOnVertex = conn_blkvec.size() > 1 ? conn_blkvec[1] : NULL;\n    const int *faceOnFace = conn_blkvec.size() > 2 ? conn_blkvec[2] : NULL;\n\n    UnstructuredGridCoordless xug(vertexDims, faceDims, edgeDims, bs, xcblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset);\n\n    UnstructuredGridCoordless yug(vertexDims, faceDims, edgeDims, bs, ycblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset);\n\n    UnstructuredGridCoordless zug;\n\n    string qtr_key = _getQuadTreeRectangleKey(ts, level, lod, cvarsinfo, bmin, bmax);\n\n    // Try to get a shared pointer to the QuadTreeRectangle from the\n    // cache. If one does not exist the Grid class will make one. We use\n    // a shared pointer so that we can cache it for use by other Grid\n    // classes. This a peformance optimization, necessary be creating\n    // a QuadTreeRectangle is expensive.\n    //\n    std::shared_ptr<const QuadTreeRectangleP> qtr = _qtrCache.get(qtr_key);\n\n    UnstructuredGrid2D *g = new UnstructuredGrid2D(vertexDims, faceDims, edgeDims, bs, blkptrs, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset,\n                                                   faceOffset, xug, yug, zug, qtr);\n\n    // No QuadTreeRectangle in cache. So get shared pointer for one created\n    // by UnstructuredGrid2D() and cache it for later use. The memory\n    // will be garbage collected when all pointers to it go out of scope\n    //\n    if (!qtr) {\n        qtr = g->GetQuadTreeRectangle();\n        (void)_qtrCache.put(qtr_key, qtr);\n    }\n\n    return (g);\n}\n\nUnstructuredGridLayered *GridHelper::_make_grid_unstructured_layered(size_t ts, int level, int lod, const DC::DataVar &var, const vector<DC::CoordVar> &cvarsinfo, const DimsType &dims,\n                                                                     const vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector<int *> &conn_blkvec,\n                                                                     const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims,\n                                                                     const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace,\n                                                                     size_t maxFacePerVertex, long vertexOffset, long faceOffset)\n{\n    VAssert(blkvec.size() == 4);\n\n    VAssert(conn_blkvec.size() >= 1);\n\n    // block pointers for data\n    //\n    size_t nblocks = 1;\n    size_t block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    vector<float *> blkptrs;\n    for (int i = 0; i < nblocks; i++) {\n        if (blkvec[0]) blkptrs.push_back(blkvec[0] + i * block_size);\n    }\n\n    // Block pointers for X coordinates, which are always 1D\n    //\n    nblocks = 1;\n    block_size = 1;\n    for (int i = 0; i < 1; i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    vector<float *> xcblkptrs;\n    for (int i = 0; i < nblocks; i++) { xcblkptrs.push_back(blkvec[1] + i * block_size); }\n\n    // Block pointers for Y coordinates, which are always 1D\n    //\n    vector<float *> ycblkptrs;\n    for (int i = 0; i < nblocks; i++) { ycblkptrs.push_back(blkvec[2] + i * block_size); }\n\n    // Block pointers for Z coordinates, which are always 2D\n    //\n    nblocks = 1;\n    block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n    vector<float *> zcblkptrs;\n    for (int i = 0; i < nblocks; i++) { zcblkptrs.push_back(blkvec[3] + i * block_size); }\n\n    // N.B. assumes blkvec contains contiguous blocks :-(\n    //\n    const int *vertexOnFace = conn_blkvec[0];\n    const int *faceOnVertex = conn_blkvec[1];\n    const int *faceOnFace = conn_blkvec.size() == 3 ? conn_blkvec[2] : NULL;\n\n    DimsType vertexDims1D = {vertexDims[0], 1, 1};\n    DimsType faceDims1D = {faceDims[0], 1, 1};\n    DimsType edgeDims1D = {edgeDims[0], 1, 1};\n    DimsType bs1D = {bs[0], 1, 1};\n\n    UnstructuredGridCoordless xug(vertexDims1D, faceDims1D, edgeDims1D, bs1D, xcblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset,\n                                  faceOffset);\n\n    UnstructuredGridCoordless yug(vertexDims1D, faceDims1D, edgeDims1D, bs1D, ycblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset,\n                                  faceOffset);\n\n    UnstructuredGridCoordless zug(vertexDims, faceDims, edgeDims, bs, zcblkptrs, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset);\n\n    string qtr_key = _getQuadTreeRectangleKey(ts, level, lod, cvarsinfo, bmin, bmax);\n\n    // Try to get a shared pointer to the QuadTreeRectangle from the\n    // cache. If one does not exist the Grid class will make one. We use\n    // a shared pointer so that we can cache it for use by other Grid\n    // classes. This a peformance optimization, necessary be creating\n    // a QuadTreeRectangle is expensive.\n    //\n    std::shared_ptr<const QuadTreeRectangleP> qtr = _qtrCache.get(qtr_key);\n\n    UnstructuredGridLayered *g = new UnstructuredGridLayered(vertexDims, faceDims, edgeDims, bs, blkptrs, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex,\n                                                             vertexOffset, faceOffset, xug, yug, zug, qtr);\n\n    // No QuadTreeRectangle in cache. So get shared pointer for one created\n    // by UnstructuredGrid2D() and cache it for later use. The memory\n    // will be garbage collected when all pointers to it go out of scope\n    //\n    if (!qtr) {\n        qtr = g->GetQuadTreeRectangle();\n        (void)_qtrCache.put(qtr_key, qtr);\n    }\n\n    return (g);\n}\n\n\nUnstructuredGrid3D *GridHelper::_make_grid_unstructured_3d(size_t ts, int level, int lod, const DC::DataVar &var, const vector<DC::CoordVar> &cvarsinfo, const DimsType &dims,\n                                                           const vector<float *> &blkvec, const DimsType &bs, const DimsType &bmin, const DimsType &bmax, const vector<int *> &conn_blkvec,\n                                                           const DimsType &conn_bs, const DimsType &conn_bmin, const DimsType &conn_bmax, const DimsType &vertexDims, const DimsType &faceDims,\n                                                           const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace, size_t maxFacePerVertex, long vertexOffset,\n                                                           long faceOffset)\n{\n    VAssert(blkvec.size() == 4);\n\n    VAssert(conn_blkvec.size() >= 2);\n\n\n    // block pointers for data\n    //\n    size_t nblocks = 1;\n    size_t block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    vector<float *> blkptrs;\n    for (int i = 0; i < nblocks; i++) {\n        if (blkvec[0]) blkptrs.push_back(blkvec[0] + i * block_size);\n    }\n\n\n    // Block pointers for X coordinates, which are always 1D\n    //\n    nblocks = 1;\n    block_size = 1;\n    for (int i = 0; i < 1; i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n\n    vector<float *> xcblkptrs;\n    for (int i = 0; i < nblocks; i++) { xcblkptrs.push_back(blkvec[1] + i * block_size); }\n\n    // Block pointers for Y coordinates, which are always 1D\n    //\n    vector<float *> ycblkptrs;\n    for (int i = 0; i < nblocks; i++) { ycblkptrs.push_back(blkvec[2] + i * block_size); }\n\n    // Block pointers for Z coordinates, which are always 2D\n    //\n    nblocks = 1;\n    block_size = 1;\n    for (int i = 0; i < bs.size(); i++) {\n        nblocks *= bmax[i] - bmin[i] + 1;\n        block_size *= bs[i];\n    }\n    vector<float *> zcblkptrs;\n    for (int i = 0; i < nblocks; i++) { zcblkptrs.push_back(blkvec[3] + i * block_size); }\n\n    // N.B. assumes blkvec contains contiguous blocks :-(\n    //\n    const int *vertexOnFace = conn_blkvec[0];\n    const int *faceOnVertex = conn_blkvec[1];\n    const int *faceOnFace = conn_blkvec.size() == 3 ? conn_blkvec[2] : NULL;\n\n    DimsType vertexDims1D = {vertexDims[0], 1, 1};\n    DimsType faceDims1D = {faceDims[0], 1, 1};\n    DimsType edgeDims1D = {edgeDims[0], 1, 1};\n    DimsType bs1D = {bs[0], 1, 1};\n\n    UnstructuredGridCoordless xug(vertexDims1D, faceDims1D, edgeDims1D, bs1D, xcblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset,\n                                  faceOffset);\n\n    UnstructuredGridCoordless yug(vertexDims1D, faceDims1D, edgeDims1D, bs1D, ycblkptrs, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset,\n                                  faceOffset);\n\n    UnstructuredGridCoordless zug(vertexDims, faceDims, edgeDims, bs, zcblkptrs, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset);\n\n\n    UnstructuredGrid3D *g = new UnstructuredGrid3D(vertexDims, faceDims, edgeDims, bs, blkptrs, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset,\n                                                   faceOffset, xug, yug, zug);\n\n\n    return (g);\n}\n\n\nvoid GridHelper::_makeGridHelper(const DC::DataVar &var, const DimsType &roi_dims, const DimsType &dims, Grid *g) const\n{\n\n    vector<bool> has_periodic = var.GetPeriodic();\n    vector<bool> periodic;\n    for (int i = 0; i < dims.size(); i++) {\n        if (i < has_periodic.size() && has_periodic[i] && roi_dims[i] == dims[i]) {\n            periodic.push_back(true);\n        } else {\n            periodic.push_back(false);\n        }\n    }\n\n    bool  has_missing = false;\n    float mv = 0.0;\n    if (var.GetHasMissing()) {\n        has_missing = true;\n        mv = var.GetMissingValue();\n    }\n\n    // Don't allow NaNs as missing values. We replace any\n    // missing values in the data with infinity\n    //\n    if (std::isnan(mv)) mv = std::numeric_limits<float>::infinity();\n\n    g->SetPeriodic(periodic);\n    if (has_missing) {\n        g->SetHasMissingValues(true);\n        g->SetMissingValue(mv);\n    }\n}\n\n//\tvar: variable info\n//  roi_dims: spatial dimensions of ROI\n//\tdims: spatial dimensions of full variable domain in voxels\n//\tblkvec: data blocks, and coordinate blocks\n//\tbsvec: data block dimensions, and coordinate block dimensions\n//  bminvec: ROI offsets in blocks, full domain, data and coordinates\n//  bmaxvec: ROI offsets in blocks, full domain, data and coordinates\n//\n\nStructuredGrid *GridHelper::MakeGridStructured(string gridType, size_t ts, int level, int lod, const DC::DataVar &var, const vector<DC::CoordVar> &cvarsinfo, const DimsType &roi_dims,\n                                               const DimsType &dims, const vector<float *> &blkvec, const vector<DimsType> &bsvec, const vector<DimsType> &bminvec, const vector<DimsType> &bmaxvec)\n{\n    StructuredGrid *rg = NULL;\n    if (gridType == RegularGrid::GetClassType()) {\n        rg = _make_grid_regular(roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0]);\n    } else if (gridType == StretchedGrid::GetClassType()) {\n        rg = _make_grid_stretched(roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0]);\n    } else if (gridType == LayeredGrid::GetClassType()) {\n        rg = _make_grid_layered(roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0]);\n    } else if (gridType == CurvilinearGrid::GetClassType()) {\n        rg = _make_grid_curvilinear(ts, level, lod, cvarsinfo, roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0]);\n    } else {\n        return (NULL);\n    }\n\n    _makeGridHelper(var, roi_dims, dims, rg);\n\n    return (rg);\n}\n\nUnstructuredGrid *GridHelper::MakeGridUnstructured(string gridType, size_t ts, int level, int lod, const DC::DataVar &var, const vector<DC::CoordVar> &cvarsinfo, const DimsType &roi_dims,\n                                                   const DimsType &dims, const vector<float *> &blkvec, const vector<DimsType> &bsvec, const vector<DimsType> &bminvec, const vector<DimsType> &bmaxvec,\n                                                   const vector<int *> &conn_blkvec, const vector<DimsType> &conn_bsvec, const vector<DimsType> &conn_bminvec, const vector<DimsType> &conn_bmaxvec,\n                                                   const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, UnstructuredGrid::Location location, size_t maxVertexPerFace,\n                                                   size_t maxFacePerVertex, long vertexOffset, long faceOffset)\n{\n    UnstructuredGrid *rg = NULL;\n\n    if (gridType == UnstructuredGrid2D::GetClassType()) {\n        rg = _make_grid_unstructured2d(ts, level, lod, var, cvarsinfo, roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0], conn_blkvec, conn_bsvec[0], conn_bminvec[0], conn_bmaxvec[0], vertexDims,\n                                       faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset);\n    } else if (gridType == UnstructuredGridLayered::GetClassType()) {\n        rg = _make_grid_unstructured_layered(ts, level, lod, var, cvarsinfo, roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0], conn_blkvec, conn_bsvec[0], conn_bminvec[0], conn_bmaxvec[0],\n                                             vertexDims, faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset);\n    } else if (gridType == UnstructuredGrid3D::GetClassType()) {\n        rg = _make_grid_unstructured_3d(ts, level, lod, var, cvarsinfo, roi_dims, blkvec, bsvec[0], bminvec[0], bmaxvec[0], conn_blkvec, conn_bsvec[0], conn_bminvec[0], conn_bmaxvec[0], vertexDims,\n                                        faceDims, edgeDims, location, maxVertexPerFace, maxFacePerVertex, vertexOffset, faceOffset);\n    } else {\n        return (NULL);\n    }\n\n    _makeGridHelper(var, roi_dims, dims, rg);\n\n    return (rg);\n}\n\nGridHelper::~GridHelper()\n{\n    while ((_qtrCache.remove_lru()) != NULL) {}\n}\n\nstring GridHelper::GetGridType(const DC::Mesh &m, const vector<DC::CoordVar> &cvarsinfo, const vector<vector<string>> &cdimnames) const\n{\n    if (isUnstructured2D(m, cvarsinfo, cdimnames)) { return (UnstructuredGrid2D::GetClassType()); }\n\n    if (isUnstructuredLayered(m, cvarsinfo, cdimnames)) { return (UnstructuredGridLayered::GetClassType()); }\n\n    if (isUnstructured3D(m, cvarsinfo, cdimnames)) { return UnstructuredGrid3D::GetClassType(); }\n\n    if (isRegular(m, cvarsinfo, cdimnames)) { return (RegularGrid::GetClassType()); }\n\n    if (isStretched(m, cvarsinfo, cdimnames)) { return (StretchedGrid::GetClassType()); }\n\n    if (isLayered(m, cvarsinfo, cdimnames)) { return (LayeredGrid::GetClassType()); }\n\n    if (isCurvilinear(m, cvarsinfo, cdimnames)) { return (CurvilinearGrid::GetClassType()); }\n\n    if (isUnstructured3D(m, cvarsinfo, cdimnames)) { return UnstructuredGrid3D::GetClassType(); }\n\n    return (\"\");\n}\n\nbool GridHelper::IsUnstructured(std::string gridType) const\n{\n    return (gridType == UnstructuredGrid2D::GetClassType() || gridType == UnstructuredGridLayered::GetClassType() || gridType == UnstructuredGrid3D::GetClassType());\n}\n\nbool GridHelper::IsStructured(std::string gridType) const\n{\n    return ((gridType == RegularGrid::GetClassType()) || (gridType == StretchedGrid::GetClassType()) || (gridType == LayeredGrid::GetClassType()) || (gridType == CurvilinearGrid::GetClassType()));\n}\n"
  },
  {
    "path": "lib/vdc/KDTreeRG.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n\n#include <vapor/utils.h>\n#include <vapor/KDTreeRG.h>\n#include \"kdtree.h\"\n\nusing namespace std;\nusing namespace VAPoR;\n\nKDTreeRG::KDTreeRG(const Grid &xg, const Grid &yg) : _points(xg, yg), _kdtree(2 /* dimension */, _points, nanoflann::KDTreeSingleIndexAdaptorParams(20 /* max leaf num */))\n{\n    auto tmp = xg.GetDimensions();\n    _dims = {tmp[0], tmp[1], tmp[2]};\n    _dims.resize(xg.GetNumDimensions());\n    _kdtree.buildIndex();\n}\n\nKDTreeRG::~KDTreeRG() {}\n\nvoid KDTreeRG::Nearest(const vector<float> &coordu, vector<size_t> &coord) const\n{\n    VAssert(coordu.size() == 2);    // 3D case isn't supported yet\n\n    size_t                                 ret_index;\n    float                                  dist_sqr;\n    nanoflann::KNNResultSet<float, size_t> resultSet(1);\n    resultSet.init(&ret_index, &dist_sqr);\n    bool rt = _kdtree.findNeighbors(resultSet, coordu.data(), nanoflann::SearchParams());\n    VAssert(rt);\n\n    // De-serialize the linear offset and put it back in vector form\n    coord.clear();\n    coord = Wasp::VectorizeCoords(ret_index, _dims);\n}\n\nKDTreeRGSubset::KDTreeRGSubset()\n{\n    _kdtree = NULL;\n    _min.clear();\n    _max.clear();\n}\n\nKDTreeRGSubset::KDTreeRGSubset(const KDTreeRG *kdtreerg, const vector<size_t> &min, const vector<size_t> &max)\n{\n    VAssert(min.size() == max.size());\n\n    vector<size_t> dims = kdtreerg->GetDimensions();\n    VAssert(min.size() == dims.size());\n\n    for (int i = 0; i < dims.size(); i++) {\n        VAssert(min[i] <= max[i]);\n        VAssert(max[i] < dims[i]);\n    }\n\n    _kdtree = kdtreerg;    // shallow copy\n    _min = min;\n    _max = max;\n}\n\n// Returned coordinates are relative to min and max used in constructor\n// The origin is given by min\n//\nvoid KDTreeRGSubset::Nearest(const vector<float> &coordu, vector<size_t> &coord) const\n{\n    VAssert(coordu.size() == _min.size());\n\n    coord.clear();\n\n    vector<size_t> global_coords;\n\n    // Find voxel coorindates of nearest point in global mesh\n    //\n    _kdtree->Nearest(coordu, global_coords);\n\n    // Clamp global coordinates to region defined by _min, and _max\n    //\n    for (int i = 0; i < global_coords.size(); i++) {\n        if (global_coords[i] < _min[i]) global_coords[i] = _min[i];\n        if (global_coords[i] > _max[i]) global_coords[i] = _max[i];\n    }\n\n    // Translate global coordinates to ROI coordinates\n    //\n    for (int i = 0; i < global_coords.size(); i++) { coord.push_back(global_coords[i] - _min[i]); }\n}\n"
  },
  {
    "path": "lib/vdc/LayeredGrid.cpp",
    "content": "#include <stdio.h>\n#include <iostream>\n#include <cmath>\n#include <cfloat>\n#include <vapor/vizutil.h>\n#include \"vapor/utils.h\"\n#include \"vapor/LayeredGrid.h\"\n#define INCLUDE_DEPRECATED_LEGACY_VECTOR_MATH\n#include \"vapor/LegacyVectorMath.h\"\n#include \"vapor/VAssert.h\"\n\nusing namespace std;\nusing namespace VAPoR;\n\nvoid LayeredGrid::_layeredGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks, const std::vector<double> &xcoords, const std::vector<double> &ycoords, const RegularGrid &zrg)\n{\n    VAssert(GetDimensions().size() == 3);\n    VAssert(xcoords.size() == GetDimensions()[0]);\n    VAssert(ycoords.size() == GetDimensions()[1]);\n    VAssert(zrg.GetDimensions()[0] == xcoords.size());\n    VAssert(zrg.GetDimensions()[1] == ycoords.size());\n\n    _interpolationOrder = 1;\n\n    // Set horizontal extents from sg2d\n    //\n    _sg2d.GetUserExtents(_minu, _maxu);\n\n    // Get extents of layered dimension\n    //\n    float range[2];\n    _zrg.GetRange(range);\n    _minu[2] = (double)range[0];\n    _maxu[2] = (double)range[1];\n}\n\nLayeredGrid::LayeredGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks, const std::vector<double> &xcoords, const std::vector<double> &ycoords, const RegularGrid &zrg)\n: StructuredGrid(dims, bs, blks), _sg2d(DimsType{dims[0], dims[1], 1}, DimsType{bs[0], bs[1], 1}, vector<float *>(), xcoords, ycoords, vector<double>()), _zrg(zrg), _xcoords(xcoords),\n  _ycoords(ycoords)\n{\n    _layeredGrid(dims, bs, blks, xcoords, ycoords, zrg);\n}\n\nLayeredGrid::LayeredGrid(const vector<size_t> &dimsv, const vector<size_t> &bsv, const vector<float *> &blks, const std::vector<double> &xcoords, const std::vector<double> &ycoords,\n                         const RegularGrid &zrg)\n: StructuredGrid(dimsv, bsv, blks), _sg2d(vector<size_t>(dimsv.begin(), dimsv.begin() + 2), vector<size_t>(bsv.begin(), bsv.begin() + 2), vector<float *>(), xcoords, ycoords, vector<double>()),\n  _zrg(zrg), _xcoords(xcoords), _ycoords(ycoords)\n{\n    DimsType dims = {1, 1, 1};\n    DimsType bs = {1, 1, 1};\n    CopyToArr3(dimsv, dims);\n    CopyToArr3(bsv, bs);\n\n    _layeredGrid(dims, bs, blks, xcoords, ycoords, zrg);\n}\n\nDimsType LayeredGrid::GetCoordDimensions(size_t dim) const\n{\n    DimsType dims = {1, 1, 1};\n\n    if (dim == 0) {\n        dims[0] = GetDimensions()[0];\n    } else if (dim == 1) {\n        dims[0] = GetDimensions()[1];\n    } else if (dim == 2) {\n        dims = _zrg.GetDimensions();\n    }\n\n    return (dims);\n}\n\nvoid LayeredGrid::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const\n{\n    minu = _minu;\n    maxu = _maxu;\n}\n\nvoid LayeredGrid::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const\n{\n    DimsType cMin;\n    ClampIndex(min, cMin);\n\n    DimsType cMax;\n    ClampIndex(max, cMax);\n\n    // Get extents of horizontal dimensions. Note: also get vertical\n    // dimension, but it's bogus for layered grid.\n    //\n    GetUserCoordinates(cMin, minu);\n    GetUserCoordinates(cMax, maxu);\n\n    // Initialize min and max coordinates of varying dimension with\n    // coordinates of \"first\" and \"last\" grid point. Coordinates of\n    // varying dimension are stored as values of a scalar function\n    // sampling the coordinate space.\n    //\n    float mincoord = _zrg.GetValueAtIndex(cMin);\n    float maxcoord = _zrg.GetValueAtIndex(cMax);\n\n    // Now find the extreme values of the varying dimension's coordinates\n    //\n    for (int j = cMin[1]; j <= cMax[1]; j++) {\n        for (int i = cMin[0]; i <= cMax[0]; i++) {\n            float v = _zrg.AccessIJK(i, j, cMin[2]);\n\n            if (v < mincoord) mincoord = v;\n        }\n    }\n\n    for (int j = cMin[1]; j <= cMax[1]; j++) {\n        for (int i = cMin[0]; i <= cMax[0]; i++) {\n            float v = _zrg.AccessIJK(i, j, cMax[2]);\n\n            if (v > maxcoord) maxcoord = v;\n        }\n    }\n\n    minu[2] = mincoord;\n    maxu[2] = maxcoord;\n}\n\nbool LayeredGrid::_insideGrid(const CoordType &coords, DimsType &indices, double wgts[3]) const\n{\n    // Get indices and weights for horizontal slice\n    //\n    bool found = _sg2d.GetIndicesCell(coords, indices, wgts);\n    if (!found) return (found);\n\n    // XZ and YZ cell sides are planar, but XY sides may not be. We divide\n    // the XY faces into two triangles (changing hexahedrals into prims)\n    // and figure out which triangle (prism) the point is in (first or\n    // second). Then we search the stack of first (or second) prism in Z\n    //\n    //\n\n    // Check if point is in \"first\" triangle (0,0), (1,0), (1,1)\n    //\n    double   lambda[3];\n    double   pt[] = {coords[0], coords[1]};\n    DimsType iv = {indices[0], indices[0] + 1, indices[0] + 1};\n    DimsType jv = {indices[1], indices[1], indices[1] + 1};\n    double   tverts[] = {_xcoords[iv[0]], _ycoords[jv[0]], _xcoords[iv[1]], _ycoords[jv[1]], _xcoords[iv[2]], _ycoords[jv[2]]};\n\n    bool inside = VAPoR::BarycentricCoordsTri(tverts, pt, lambda);\n    if (!inside) {\n        // Not in first triangle.\n        // Now check if point is in \"second\" triangle (0,0), (1,1), (0,1)\n        //\n        iv = {indices[0], indices[0] + 1, indices[0]};\n        jv = {indices[1], indices[1] + 1, indices[1] + 1};\n        double tverts[] = {_xcoords[iv[0]], _ycoords[jv[0]], _xcoords[iv[1]], _ycoords[jv[1]], _xcoords[iv[2]], _ycoords[jv[2]]};\n\n        inside = VAPoR::BarycentricCoordsTri(tverts, pt, lambda);\n\n        // Mathematically this shouldn't happen if _sg2d.GetIndicesCell()\n        // returns true, but have to contend with floating point roundoff\n        //\n        if (!inside) return (false);\n    }\n\n    float z0, z1;\n\n    // Find k index of cell containing z. Already know i and j indices\n    //\n    vector<double> zcoords;\n\n    size_t nz = GetDimensions()[2];\n    zcoords.reserve(nz);\n    for (int kk = 0; kk < nz; kk++) {\n        // Interpolate Z coordinate across triangle\n        //\n        float zk = _zrg.AccessIJK(iv[0], jv[0], kk) * lambda[0] + _zrg.AccessIJK(iv[1], jv[1], kk) * lambda[1] + _zrg.AccessIJK(iv[2], jv[2], kk) * lambda[2];\n\n        zcoords.push_back(zk);\n    }\n\n    if (!Wasp::BinarySearchRange(zcoords, coords[2], indices[2])) return (false);\n\n    z0 = zcoords[indices[2]];\n    z1 = indices[2] < nz - 1 ? zcoords[indices[2] + 1] : z0;\n\n    wgts[2] = z0 == z1 ? 1.0 : (1.0 - (coords[2] - z0) / (z1 - z0));\n\n    return (true);\n}\n\nfloat LayeredGrid::GetValueNearestNeighbor(const CoordType &coords) const\n{\n    DimsType indices;\n    double   wgts[3];\n    bool     found = _insideGrid(coords, indices, wgts);\n    if (!found) return (GetMissingValue());\n\n    if (wgts[0] < 0.5) indices[0] += 1;\n    if (wgts[1] < 0.5) indices[1] += 1;\n    if (wgts[2] < 0.5) indices[2] += 1;\n\n    return (AccessIJK(indices[0], indices[1], indices[2]));\n}\n\nfloat LayeredGrid::GetValueLinear(const CoordType &coords) const\n{\n    DimsType indices;\n    double   wgts[3];\n    bool     found = _insideGrid(coords, indices, wgts);\n    if (!found) return (GetMissingValue());\n\n    return (TrilinearInterpolate(indices[0], indices[1], indices[2], wgts[0], wgts[1], wgts[2]));\n}\n\nfloat LayeredGrid::GetValue(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    auto dims = GetDimensions();\n\n    // Figure out interpolation order\n    //\n    int interp_order = _interpolationOrder;\n    if (interp_order == 2) {\n        if (dims[2] < 3) interp_order = 1;\n    }\n\n    if (interp_order == 0) {\n        return (GetValueNearestNeighbor(cCoords));\n    } else if (interp_order == 1) {\n        return (GetValueLinear(cCoords));\n    }\n\n    return _getValueQuadratic(cCoords.data());\n}\n\nvoid LayeredGrid::SetInterpolationOrder(int order)\n{\n    if (order < 0 || order > 3) order = 2;\n    _interpolationOrder = order;\n}\n\nvoid LayeredGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const\n{\n    DimsType cIndices;\n    ClampIndex(indices, cIndices);\n\n    // First get coordinates of (horizontal) dimensions\n    //\n    _sg2d.GetUserCoordinates(indices, coords);\n\n    // Now get coordinates of z dimension\n    //\n    coords[2] = _zrg.GetValueAtIndex(cIndices);\n}\n\nbool LayeredGrid::GetIndicesCell(const CoordType &coords, DimsType &indices) const\n{\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    double dummy[3];\n    return (_insideGrid(coords, indices, dummy));\n\n    return (true);\n}\n\nbool LayeredGrid::InsideGrid(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to reside within the\n    // grid extents (vary-dimensions can not have periodic boundaries)\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    DimsType indices;\n    bool     found = GetIndicesCell(cCoords, indices);\n    return (found);\n}\n\nLayeredGrid::ConstCoordItrLayered::ConstCoordItrLayered(const LayeredGrid *lg, bool begin) : ConstCoordItrAbstract()\n{\n    _lg = lg;\n    _nElements2D = lg->GetDimensions()[0] * lg->GetDimensions()[1];\n    _coords = {0.0, 0.0, 0.0};\n\n    if (begin) {\n        _index2D = 0;\n        _zCoordItr = lg->_zrg.cbegin();\n        _itr2D = lg->_sg2d.ConstCoordBegin();\n    } else {\n        _index2D = _nElements2D - 1;\n        _zCoordItr = lg->_zrg.cend();\n        _itr2D = lg->_sg2d.ConstCoordEnd();\n    }\n}\n\nLayeredGrid::ConstCoordItrLayered::ConstCoordItrLayered(const ConstCoordItrLayered &rhs) : ConstCoordItrAbstract()\n{\n    _lg = rhs._lg;\n    _nElements2D = rhs._nElements2D;\n    _coords = rhs._coords;\n    _index2D = rhs._index2D;\n    _zCoordItr = rhs._zCoordItr;\n    _itr2D = rhs._itr2D;\n}\n\nLayeredGrid::ConstCoordItrLayered::ConstCoordItrLayered() : ConstCoordItrAbstract() { _coords = {0.0, 0.0, 0.0}; }\n\nvoid LayeredGrid::ConstCoordItrLayered::next()\n{\n    ++_index2D;\n    ++_itr2D;\n    ++_zCoordItr;\n\n    // Check for overflow\n    //\n    if (_index2D == _nElements2D) {\n        _itr2D = _lg->_sg2d.ConstCoordBegin();\n        _index2D = 0;\n    }\n\n    _coords[0] = (*_itr2D)[0];\n    _coords[1] = (*_itr2D)[1];\n\n    _coords[2] = *_zCoordItr;\n}\n\nvoid LayeredGrid::ConstCoordItrLayered::next(const long &offset)\n{\n    long offset2D = offset % _nElements2D;\n\n    if (offset2D + _index2D < _nElements2D) {\n        _itr2D += offset;\n        _index2D += offset;\n    } else {\n        size_t o = (offset2D + _index2D) % _nElements2D;\n        _itr2D = _lg->_sg2d.ConstCoordBegin() + o;\n        _index2D = o;\n    }\n\n    _coords[0] = (*_itr2D)[0];\n    _coords[1] = (*_itr2D)[1];\n\n    _zCoordItr += offset;\n    _coords[2] = *_zCoordItr;\n}\n\nvoid LayeredGrid::_getBilinearWeights(const double coords[3], double &iwgt, double &jwgt) const\n{\n    auto dims = GetDimensions();\n\n    size_t indices0[3];\n    bool   found = GetIndicesCell(coords, indices0);\n    VAssert(found);\n\n    size_t indices1[3] = {indices0[0], indices0[1], indices0[2]};\n    if (indices0[0] != dims[0] - 1) { indices1[0] += 1; }\n    if (indices0[1] != dims[1] - 1) { indices1[1] += 1; }\n\n    double coords0[3], coords1[3];\n    GetUserCoordinates(indices0, coords0);\n    GetUserCoordinates(indices1, coords1);\n    double x = coords[0];\n    double y = coords[1];\n    double x0 = coords0[0];\n    double y0 = coords0[1];\n    double x1 = coords1[0];\n    double y1 = coords1[1];\n\n    if (x1 != x0)\n        iwgt = fabs((x - x0) / (x1 - x0));\n    else\n        iwgt = 0.0;\n    if (y1 != y0)\n        jwgt = fabs((y - y0) / (y1 - y0));\n    else\n        jwgt = 0.0;\n}\n\ndouble LayeredGrid::_bilinearInterpolation(size_t i0, size_t i1, size_t j0, size_t j1, size_t k0, double iwgt, double jwgt) const\n{\n    double val00, val01, val10, val11, xVal0, result;\n    double xVal1 = 0.0;\n    double mv = GetMissingValue();\n\n    val00 = AccessIJK(i0, j0, k0);\n    val10 = AccessIJK(i1, j0, k0);\n    if ((val00 == mv) || (val10 == mv)) return mv;\n    if (val00 == mv)\n        xVal0 = val10;\n    else if (val10 == mv)\n        xVal0 = val00;\n    else\n        xVal0 = val00 * (1 - iwgt) + val10 * iwgt;\n\n    val01 = AccessIJK(i0, j1, k0);\n    val11 = AccessIJK(i1, j1, k0);\n    if ((val01 == mv) || (val11 == mv)) return mv;\n    if (val01 == mv)\n        xVal0 = val11;\n    else if (val11 == mv)\n        xVal0 = val01;\n    else\n        xVal1 = val01 * (1 - iwgt) + val11 * iwgt;\n\n    result = xVal0 * (1 - jwgt) + xVal1 * jwgt;\n\n    if ((val00 == mv) || (val01 == mv) || (val10 == mv) || (val11 == mv))\n        return mv;\n    else\n        return result;\n}\n\ndouble LayeredGrid::_bilinearElevation(size_t i0, size_t i1, size_t j0, size_t j1, size_t k0, double iwgt, double jwgt) const\n{\n    double xVal0, result;\n    double xVal1 = 0.0;\n    double x, y, z00, z10, z01, z11;\n\n    GetUserCoordinates(i0, j0, k0, x, y, z00);\n    GetUserCoordinates(i1, j0, k0, x, y, z10);\n    xVal0 = z00 * (1 - iwgt) + z10 * iwgt;\n\n    GetUserCoordinates(i0, j1, k0, x, y, z01);\n    GetUserCoordinates(i1, j1, k0, x, y, z11);\n    xVal1 = z01 * (1 - iwgt) + z11 * iwgt;\n\n    result = xVal0 * (1 - jwgt) + xVal1 * jwgt;\n    return result;\n}\n\nfloat LayeredGrid::_getValueQuadratic(const double coords[3]) const\n{\n    double mv = GetMissingValue();\n    auto   dims = GetDimensions();\n\n    // Get the indecies of the hyperslab containing the point\n    // k0 = level above the point\n    // k1 = level below the point\n    // k2 = two levels below the point\n    //\n    size_t indices[3];\n    bool   found = GetIndicesCell(coords, indices);\n    if (!found) return (GetMissingValue());\n\n    size_t i0 = indices[0];\n    size_t j0 = indices[1];\n    size_t k1 = indices[2];\n\n    size_t k0, k2;\n    size_t i1, j1;\n\n    if (i0 == dims[0] - 1)\n        i1 = i0;\n    else\n        i1 = i0 + 1;\n    if (j0 == dims[1] - 1)\n        j1 = j0;\n    else\n        j1 = j0 + 1;\n    if (k1 == 0) {\n        k2 = 0;\n        k1 = 1;\n        k0 = 2;\n    } else if (k1 == dims[2] - 1) {\n        k2 = dims[2] - 3;\n        k1 = dims[2] - 2;\n        k0 = dims[2] - 1;\n    } else {\n        k0 = k1 + 1;\n        k2 = k1 - 1;\n    }\n\n    double iwgt, jwgt;\n    _getBilinearWeights(coords, iwgt, jwgt);\n\n    // bilinearly interpolated values at each k0, k1 and k2\n    double val0, val1, val2;\n    val0 = _bilinearInterpolation(i0, i1, j0, j1, k0, iwgt, jwgt);\n    val1 = _bilinearInterpolation(i0, i1, j0, j1, k1, iwgt, jwgt);\n    val2 = _bilinearInterpolation(i0, i1, j0, j1, k2, iwgt, jwgt);\n    if ((val0 == mv) || (val1 == mv) || (val2 == mv)) return mv;\n\n    // bilinearly interpolated elevations at each k0, k1, and k2\n    double z0, z1, z2;\n    z0 = _bilinearElevation(i0, i1, j0, j1, k0, iwgt, jwgt);\n    z1 = _bilinearElevation(i0, i1, j0, j1, k1, iwgt, jwgt);\n    z2 = _bilinearElevation(i0, i1, j0, j1, k2, iwgt, jwgt);\n    if ((z0 == mv) || (z1 == mv) || (z2 == mv)) return mv;\n\n    // quadratic interpolation weights\n    double z = coords[2];\n    double w0, w1, w2;\n    w0 = ((z - z1) * (z - z2)) / ((z0 - z1) * (z0 - z2));\n    w1 = ((z - z0) * (z - z2)) / ((z1 - z0) * (z1 - z2));\n    w2 = ((z - z0) * (z - z1)) / ((z2 - z0) * (z2 - z1));\n\n    double val;\n    val = val0 * w0 + val1 * w1 + val2 * w2;\n\n    return val;\n}\n\ndouble LayeredGrid::_interpolateVaryingCoord(size_t i0, size_t j0, size_t k0, double x, double y) const\n{\n    // varying dimension coord at corner grid points of cell face\n    //\n    double c00, c01, c10, c11;\n\n    auto dims = GetDimensions();\n\n    size_t i1, j1, k1;\n    if (i0 == dims[0] - 1)\n        i1 = i0;\n    else\n        i1 = i0 + 1;\n    if (j0 == dims[1] - 1)\n        j1 = j0;\n    else\n        j1 = j0 + 1;\n    if (k0 == dims[2] - 1)\n        k1 = k0;\n    else\n        k1 = k0 + 1;\n\n    // Coordinates of grid points for non-varying dimensions\n    double x0, y0, z0, x1, y1, z1;\n    GetUserCoordinates(i0, j0, k0, x0, y0, z0);\n    GetUserCoordinates(i1, j1, k1, x1, y1, z1);\n    double iwgt, jwgt;\n\n    c00 = _zrg.AccessIJK(i0, j0, k0);\n    c01 = _zrg.AccessIJK(i1, j0, k0);\n    c10 = _zrg.AccessIJK(i0, j1, k0);\n    c11 = _zrg.AccessIJK(i1, j1, k0);\n\n    if (x1 != x0)\n        iwgt = fabs((x - x0) / (x1 - x0));\n    else\n        iwgt = 0.0;\n    if (y1 != y0)\n        jwgt = fabs((y - y0) / (y1 - y0));\n    else\n        jwgt = 0.0;\n\n    double z = c00 + iwgt * (c01 - c00) + jwgt * ((c10 + iwgt * (c11 - c10)) - (c00 + iwgt * (c01 - c00)));\n    return (z);\n}\n"
  },
  {
    "path": "lib/vdc/NetCDFCFCollection.cpp",
    "content": "#include <iostream>\n#include <sstream>\n#include <iterator>\n#include <algorithm>\n#include \"vapor/VAssert.h\"\n#ifdef WIN32\n    #include \"vapor/udunits2.h\"\n#else\n    #include <udunits2.h>\n#endif\n#include <vapor/NetCDFCFCollection.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\nusing namespace std;\n\nnamespace {\nvector<string> make_unique(vector<string> v)\n{\n    sort(v.begin(), v.end());\n    vector<string>::iterator last2;\n    last2 = unique(v.begin(), v.end());\n    v.erase(last2, v.end());\n    return (v);\n}\n};    // namespace\n\nNetCDFCFCollection::NetCDFCFCollection() : NetCDFCollection()\n{\n    _coordinateVars.clear();\n    _auxCoordinateVars.clear();\n    _lonCoordVars.clear();\n    _latCoordVars.clear();\n    _vertCoordVars.clear();\n    _timeCoordVars.clear();\n    _missingValueMap.clear();\n\n    _udunit = NULL;\n}\nNetCDFCFCollection::~NetCDFCFCollection()\n{\n    if (_udunit) delete _udunit;\n\n}\n\nstatic bool IsNameCFCompliant(const string &name, bool strict=true) {\n    if (!isalpha(name[0]) || (!strict && name[0] == '_')) return false;\n    for (int i = 1; i < name.size(); i++)\n        if (!(isalnum(name[i]) || name[i] == '_' || (!strict && (name[i] == '_' || name[i] == '.' || name[i] == '-'))))\n            return false;\n    return true;\n}\n\nint NetCDFCFCollection::_Initialize(const vector<string> &files)\n{\n    // Look for time coordinate variables. Must be 1D and have same\n    // name as dimension. Need not be present in all files.\n    //\n    vector<string> tv;\n    for (int j = 0; j < files.size(); j++) {\n        vector<string> emptyvec;\n        vector<string> file(1, files[j]);\n        int            rc = NetCDFCollection::Initialize(file, emptyvec, emptyvec);\n        if (rc < 0) return (-1);\n\n        // Get all 1D variables\n        //\n        vector<string> vars = NetCDFCollection::GetVariableNames(1, false);\n        for (int i = 0; i < vars.size(); i++) {\n            NetCDFSimple::Variable varinfo;\n            (void)NetCDFCollection::GetVariableInfo(vars[i], varinfo);\n\n            if (_IsCoordinateVar(varinfo) && _IsTimeCoordVar(varinfo)) { tv.push_back(vars[i]); }\n        }\n        if (tv.size()) break;    // Should we process all files???\n    }\n\n    //\n    // Reinitialize the base class now that we know the time coordinate\n    // variable. We're assuming that the time coordinate variable and\n    // the time dimension have the same name. Thus we're not handling\n    // the case where time variable could be a CF \"auxilliary\n    // coordinate variable\".\n    //\n    int rc = NetCDFCollection::Initialize(files, tv, tv);\n    if (rc < 0) return (-1);\n\n    for (const auto &v : GetVariableNames(-1, false)) {\n        if (!IsNameCFCompliant(v, false)) {\n            SetErrMsg(\"Variable name \\\"%s\\\" is not compliant with NetCDF-CF\", v.c_str());\n            return -1;\n        }\n    }\n\n    return (0);\n}\n\nint NetCDFCFCollection::Initialize(const vector<string> &files)\n{\n    _coordinateVars.clear();\n    _auxCoordinateVars.clear();\n    _lonCoordVars.clear();\n    _latCoordVars.clear();\n    _vertCoordVars.clear();\n    _timeCoordVars.clear();\n    _missingValueMap.clear();\n\n    if (_udunit) delete _udunit;\n    _udunit = new UDUnits();\n    int rc = _udunit->Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialized udunits2 library : %s\", _udunit->GetErrMsg().c_str());\n        return (0);\n    }\n\n    rc = _Initialize(files);\n    if (rc < 0) return (-1);\n\n    //\n    // Identify all of the CF \"coordinate\" variables first,\n    // which are 1D in space\n    // or 1D in time and have\n    // the same name as their one dimension\n    //\n    vector<string> vars = NetCDFCollection::GetVariableNames(1, true);\n    vector<string> tcvars = NetCDFCollection::GetVariableNames(1, false);\n    vars.insert(vars.end(), tcvars.begin(), tcvars.end());\n    for (int i = 0; i < vars.size(); i++) {\n        NetCDFSimple::Variable varinfo;\n        (void)NetCDFCollection::GetVariableInfo(vars[i], varinfo);\n\n        if (_IsCoordinateVar(varinfo)) { _coordinateVars.push_back(vars[i]); }\n    }\n\n\n    // Now find all coordinate variables that can be identified\n    // by their units, standard name, etc.\n    //\n    vars.clear();\n    for (int i = 1; i < 4; i++) {\n        vector<string> v = NetCDFCollection::GetVariableNames(i, false);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    for (auto varName : vars) {\n        NetCDFSimple::Variable varinfo;\n        (void)NetCDFCollection::GetVariableInfo(varName, varinfo);\n\n        if (_IsLonCoordVar(varinfo)) {\n            _lonCoordVars.push_back(varName);\n            _auxCoordinateVars.push_back(varName);\n        } else if (_IsLatCoordVar(varinfo)) {\n            _latCoordVars.push_back(varName);\n            _auxCoordinateVars.push_back(varName);\n        } else if (_IsVertCoordVar(varinfo)) {\n            _vertCoordVars.push_back(varName);\n            _auxCoordinateVars.push_back(varName);\n            //\n            // Only support CF \"Coordinate\" variables as time coord variables\n            //\n        } else if (_IsCoordinateVar(varinfo) && _IsTimeCoordVar(varinfo)) {\n            _timeCoordVars.push_back(varName);\n            _auxCoordinateVars.push_back(varName);\n        }\n    }\n\n    // Finally, any variable that is identified by a \"coordinate\" variable\n    // attribute is an \"auxilliary\" coordinate variable\n    //\n    vars.clear();\n    for (int i = 0; i < 4; i++) {\n        vector<string> v = NetCDFCollection::GetVariableNames(1, false);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    for (auto varName : vars) {\n        string                 timeDimName;\n        NetCDFSimple::Variable varinfo;\n        (void)NetCDFCollection::GetVariableInfo(varName, varinfo);\n\n        if (!GetTimeDimName(varName).empty()) timeDimName = GetTimeDimName(varName);\n\n        vector<string> coordattr = _GetCoordAttrs(varinfo);\n        if (!coordattr.size()) continue;\n\n        for (int j = 0; j < coordattr.size(); j++) {\n            //\n            // Make sure the auxiliary coordinate variable\n            // actually exists in the data collection\n            //\n            if (NetCDFCollection::VariableExists(coordattr[j])) { _auxCoordinateVars.push_back(coordattr[j]); }\n        }\n    }\n\n    //\n    // sort and remove duplicate coordinate variables\n    //\n    _coordinateVars = make_unique(_coordinateVars);\n    _auxCoordinateVars = make_unique(_auxCoordinateVars);\n    _lonCoordVars = make_unique(_lonCoordVars);\n    _latCoordVars = make_unique(_latCoordVars);\n    _vertCoordVars = make_unique(_vertCoordVars);\n    _timeCoordVars = make_unique(_timeCoordVars);\n\n    string mvattname;\n    _GetMissingValueMap(_missingValueMap);\n\n    return (0);\n}\n\nvector<string> NetCDFCFCollection::GetDataVariableNames(int ndim, bool spatial) const\n{\n    vector<string> tmp = NetCDFCollection::GetVariableNames(ndim, spatial);\n\n    vector<string> varnames;\n    for (int i = 0; i < tmp.size(); i++) {\n        //\n        // Strip off any coordinate variables\n        //\n        if (IsCoordVarCF(tmp[i])) continue;\n\n        vector<string> cvars;\n        bool           enable = EnableErrMsg(false);\n        int            rc = NetCDFCFCollection::GetVarCoordVarNames(tmp[i], cvars);\n        EnableErrMsg(enable);\n        SetErrCode(0);\n\n        if (rc < 0) continue;    // Doesn't have coordinate variables\n\n        int myndim = cvars.size();\n        if (spatial && IsTimeVarying(tmp[i])) {\n            myndim--;    // don't count time dimension\n        }\n        if (myndim != ndim) continue;\n\n        varnames.push_back(tmp[i]);\n    }\n\n    return (varnames);\n}\n\nint NetCDFCFCollection::GetVarCoordVarNames(string var, vector<string> &cvars) const\n{\n    cvars.clear();\n\n    NetCDFSimple::Variable varinfo;\n\n    int rc = NetCDFCollection::GetVariableInfo(var, varinfo);\n    if (rc < 0) return (rc);\n\n    vector<string> dimnames = varinfo.GetDimNames();\n\n    //\n    // First look for auxiliary coordinate variables\n    //\n    bool           hasTimeCoord = false;\n    bool           hasLatCoord = false;\n    bool           hasLonCoord = false;\n    bool           hasVertCoord = false;\n    vector<string> tmpcvars;\n    vector<string> auxcvars = _GetCoordAttrs(varinfo);\n    for (int i = 0; i < auxcvars.size(); i++) {\n        //\n        // Make sure variable specified by \"coordinate\" attribute is in\n        // fact an auxiliary coordinate variable (any coordinate variables\n        // specified by the \"coordinate\" attribute should have already\n        // been picked up above\n        //\n        if (NetCDFCFCollection::IsTimeCoordVar(auxcvars[i]) && !hasTimeCoord) {\n            hasTimeCoord = true;\n            tmpcvars.push_back(auxcvars[i]);\n        }\n        if (NetCDFCFCollection::IsLatCoordVar(auxcvars[i]) && !hasLatCoord) {\n            hasLatCoord = true;\n            tmpcvars.push_back(auxcvars[i]);\n        }\n        if (NetCDFCFCollection::IsLonCoordVar(auxcvars[i]) && !hasLonCoord) {\n            hasLonCoord = true;\n            tmpcvars.push_back(auxcvars[i]);\n        }\n        if (NetCDFCFCollection::IsVertCoordVar(auxcvars[i]) && !hasVertCoord) {\n            hasVertCoord = true;\n            tmpcvars.push_back(auxcvars[i]);\n        }\n    }\n\n    // Ugh. Stupid hack to make Z3 the vertical coordinate variable\n    // for 3D CAM variables\n    //\n    if (!hasVertCoord) {\n        vector<string> v, vars;\n        v = NetCDFCollection::GetVariableNames(3, false);\n        vars.insert(vars.end(), v.begin(), v.end());\n        v = NetCDFCollection::GetVariableNames(4, false);\n        vars.insert(vars.end(), v.begin(), v.end());\n    }\n\n    //\n    // Now see if any \"coordinate variables\" for which we haven't\n    // already identified a coord var exist.\n    //\n    if (tmpcvars.size() != dimnames.size()) {\n        for (int i = 0; i < dimnames.size(); i++) {\n            if (NetCDFCFCollection::IsCoordVarCF(dimnames[i])) {    // is a CF \"coordinate variable\"?\n                if (NetCDFCFCollection::IsTimeCoordVar(dimnames[i]) && !hasTimeCoord) {\n                    hasTimeCoord = true;\n                    tmpcvars.push_back(dimnames[i]);\n                }\n                if (NetCDFCFCollection::IsLatCoordVar(dimnames[i]) && !hasLatCoord) {\n                    hasLatCoord = true;\n                    tmpcvars.push_back(dimnames[i]);\n                }\n                if (NetCDFCFCollection::IsLonCoordVar(dimnames[i]) && !hasLonCoord) {\n                    hasLonCoord = true;\n                    tmpcvars.push_back(dimnames[i]);\n                }\n                if (NetCDFCFCollection::IsVertCoordVar(dimnames[i]) && !hasVertCoord) {\n                    hasVertCoord = true;\n                    tmpcvars.push_back(dimnames[i]);\n                }\n            }\n        }\n    }\n\n    //\n    // If we still don't have lat and lon coordinate (or auxiliary)\n    // variables for 'var' then we look for coordinate variables whose\n    // dim names match the dim names of 'var'. Don't think this is\n    // part of the CF 1.6 spec, but it seems necessary for ROMS data sets\n    //\n    //\n    // If \"coordinate variables\" are specified for each dimension we're don\n    //\n    if (tmpcvars.size() != dimnames.size()) {\n        if (!hasLatCoord) {\n            vector<string> latcvs = NetCDFCFCollection::GetLatCoordVars();\n            for (int i = 0; i < latcvs.size(); i++) {\n                NetCDFSimple::Variable varinfo;\n                NetCDFCollection::GetVariableInfo(latcvs[i], varinfo);\n                vector<string> dns = varinfo.GetDimNames();\n\n                if (dimnames.size() >= dns.size()) {\n                    vector<string> tmp(dimnames.end() - dns.size(), dimnames.end());\n                    if (tmp == dns) {\n                        tmpcvars.push_back(latcvs[i]);\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (!hasLonCoord) {\n            vector<string> loncvs = NetCDFCFCollection::GetLonCoordVars();\n            for (int i = 0; i < loncvs.size(); i++) {\n                NetCDFSimple::Variable varinfo;\n                NetCDFCollection::GetVariableInfo(loncvs[i], varinfo);\n                vector<string> dns = varinfo.GetDimNames();\n\n                if (dimnames.size() >= dns.size()) {\n                    vector<string> tmp(dimnames.end() - dns.size(), dimnames.end());\n                    if (tmp == dns) {\n                        tmpcvars.push_back(loncvs[i]);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n    if (tmpcvars.size() != dimnames.size()) {\n        SetErrMsg(\"Non-conforming CF variable : %s\", var.c_str());\n        return (-1);\n    }\n\n    //\n    // Finally, order the coordinate variables from slowest to fastest\n    // varying dimension\n    //\n    for (int i = 0; i < tmpcvars.size(); i++) {\n        if (NetCDFCFCollection::IsTimeCoordVar(tmpcvars[i])) {\n            cvars.push_back(tmpcvars[i]);\n            break;\n        }\n    }\n    for (int i = 0; i < tmpcvars.size(); i++) {\n        if (NetCDFCFCollection::IsVertCoordVar(tmpcvars[i])) {\n            cvars.push_back(tmpcvars[i]);\n            break;\n        }\n    }\n    for (int i = 0; i < tmpcvars.size(); i++) {\n        if (NetCDFCFCollection::IsLatCoordVar(tmpcvars[i])) {\n            cvars.push_back(tmpcvars[i]);\n            break;\n        }\n    }\n    for (int i = 0; i < tmpcvars.size(); i++) {\n        if (NetCDFCFCollection::IsLonCoordVar(tmpcvars[i])) {\n            cvars.push_back(tmpcvars[i]);\n            break;\n        }\n    }\n    VAssert(cvars.size() == tmpcvars.size());\n\n    return (0);\n}\n\nbool NetCDFCFCollection::IsVertCoordVarPressure(string var) const\n{\n    if (!IsVertCoordVar(var)) return (false);\n\n    NetCDFSimple::Variable varinfo;\n\n    bool enable = EnableErrMsg(false);\n    int  rc = NetCDFCollection::GetVariableInfo(var, varinfo);\n    if (rc < 0) {\n        EnableErrMsg(enable);\n        return (false);\n    }\n\n    string unit;\n    varinfo.GetAtt(\"units\", unit);\n    if (unit.empty()) return (false);    // No coordinates attribute found\n\n    return (_udunit->IsPressureUnit(unit));\n}\n\nbool NetCDFCFCollection::IsVertCoordVarLength(string var) const\n{\n    if (!IsVertCoordVar(var)) return (false);\n\n    NetCDFSimple::Variable varinfo;\n\n    bool enable = EnableErrMsg(false);\n    int  rc = NetCDFCollection::GetVariableInfo(var, varinfo);\n    EnableErrMsg(enable);\n    if (rc < 0) { return (false); }\n\n    string unit;\n    varinfo.GetAtt(\"units\", unit);\n    if (unit.empty()) return (false);    // No coordinates attribute found\n\n    return (_udunit->IsLengthUnit(unit));\n}\n\nbool NetCDFCFCollection::IsVertCoordVarUp(string cvar) const\n{\n    NetCDFSimple::Variable varinfo;\n\n    int rc = NetCDFCollection::GetVariableInfo(cvar, varinfo);\n    if (rc < 0) {\n        SetErrCode(0);\n        return (false);\n    }\n\n    string s;\n    varinfo.GetAtt(\"positive\", s);\n\n    if (StrCmpNoCase(s, \"up\") == 0)\n        return (true);\n    else\n        return (false);\n}\n\nint NetCDFCFCollection::GetVarUnits(string var, string &units) const\n{\n    units.clear();\n\n    NetCDFSimple::Variable varinfo;\n\n    int rc = NetCDFCollection::GetVariableInfo(var, varinfo);\n    if (rc < 0) return (rc);\n\n    varinfo.GetAtt(\"units\", units);\n    return (0);\n}\n\nint NetCDFCFCollection::Convert(const string from, const string to, const double *src, double *dst, size_t n) const\n{\n    bool status = _udunit->Convert(from, to, src, dst, n);\n\n    if (!status) {\n        SetErrMsg(\"NetCDFCFCollection::Convert(%s , %s,,) : failed\", from.c_str(), to.c_str());\n        return (-1);\n    }\n    return (0);\n}\nint NetCDFCFCollection::Convert(const string from, const string to, const float *src, float *dst, size_t n) const\n{\n    bool status = _udunit->Convert(from, to, src, dst, n);\n\n    if (!status) {\n        SetErrMsg(\"NetCDFCFCollection::Convert(%s , %s,,) : failed\", from.c_str(), to.c_str());\n        return (-1);\n    }\n    return (0);\n}\n\nbool NetCDFCFCollection::GetMissingValue(string varname, double &mv) const\n{\n    map<string, double>::const_iterator itr;\n\n    itr = _missingValueMap.find(varname);\n    if (itr != _missingValueMap.end()) {\n        mv = itr->second;\n        return (true);\n    }\n    return (false);\n}\n\nint NetCDFCFCollection::OpenRead(size_t ts, string varname)\n{\n    int fd = NetCDFCollection::OpenRead(ts, varname);\n\n    return (fd);\n}\n\nbool NetCDFCFCollection::IsVertDimensionless(string cvar) const\n{\n    //\n    // Return false if variable isn't a vertical coordinate variable at all\n    //\n    if (!IsVertCoordVar(cvar)) return (false);\n\n    //\n    // If we get to here the cvar is a valid coordinate variable\n    // so GetVariableInfo() should return successfully\n    //\n    NetCDFSimple::Variable varinfo;\n    (void)NetCDFCollection::GetVariableInfo(cvar, varinfo);\n\n    string unit;\n    varinfo.GetAtt(\"units\", unit);\n    if (unit.empty()) return (false);    // No coordinates attribute found\n\n    return (!(_udunit->IsPressureUnit(unit) || _udunit->IsLengthUnit(unit)));\n}\n\nbool NetCDFCFCollection::GetMapProjectionProj4(string varname, string &proj4string) const\n{\n    proj4string.clear();\n\n    bool                   enable = EnableErrMsg(false);\n    NetCDFSimple::Variable varinfo;\n    int                    rc = NetCDFCollection::GetVariableInfo(varname, varinfo);\n    EnableErrMsg(enable);\n    SetErrCode(0);\n    if (rc < 0) return (false);\n\n    // If variable has a map projection  a NetCDF variable named\n    // after the projection will exist that contains map projection\n    // parameter attributes\n    //\n    string projection;\n    varinfo.GetAtt(\"grid_mapping\", projection);\n    if (projection.empty()) return (false);    // No map projection found\n\n    // Currently only support rotated_latitude_longitude\n    //\n    if (projection.compare(\"rotated_latitude_longitude\") != 0) return (false);\n\n    enable = EnableErrMsg(false);\n    rc = NetCDFCollection::GetVariableInfo(projection, varinfo);\n    EnableErrMsg(enable);\n    SetErrCode(0);\n    if (rc < 0) return (false);\n\n    vector<double> lon0, pole_lat, pole_lon;\n    varinfo.GetAtt(\"longitude_of_prime_meridian\", lon0);\n    varinfo.GetAtt(\"grid_north_pole_longitude\", pole_lon);\n    varinfo.GetAtt(\"grid_north_pole_latitude\", pole_lat);\n\n    if (lon0.size() != 1 || pole_lon.size() != 1 || pole_lat.size() != 1) {\n        return (false);    // Probably should return error\n    }\n\n    ostringstream oss;\n\n    proj4string = \"+ellps=WGS84 \";\n\n    proj4string += \"+proj=ob_tran\";\n    proj4string += \" +o_proj=eqc\";\n    proj4string += \" +to_meter=0.0174532925199\";\n\n    proj4string += \" +o_lat_p=\";\n    oss.str(\"\");\n    oss << (double)pole_lat[0];\n    proj4string += oss.str();\n    proj4string += \"d\";    // degrees, not radians\n\n    proj4string += \" +o_lon_p=\";\n    oss.str(\"\");\n    //\toss << (double)(180. + pole_lon[0]);\n    oss << (double)(-lon0[0]);\n    proj4string += oss.str();\n    proj4string += \"d\";    // degrees, not radians\n\n    proj4string += \" +lon_0=\";\n    oss.str(\"\");\n    //\toss << (double)(-lon0[0]);\n    oss << (double)(180. + pole_lon[0]);\n    proj4string += oss.str();\n    proj4string += \"d\";    // degrees, not radians\n\n    proj4string += \" +no_defs\";\n\n    return (true);\n}\n\nvoid NetCDFCFCollection::FormatTimeStr(double seconds, string &str) const\n{\n    int year, month, day, hour, minute, second;\n    _udunit->DecodeTime(seconds, &year, &month, &day, &hour, &minute, &second);\n\n    ostringstream oss;\n    oss.fill('0');\n    oss.width(4);\n    oss << year;\n    oss << \"-\";\n    oss.width(2);\n    oss << month;\n    oss << \"-\";\n    oss.width(2);\n    oss << day;\n    oss << \" \";\n    oss.width(2);\n    oss << hour;\n    oss << \":\";\n    oss.width(2);\n    oss << minute;\n    oss << \":\";\n    oss.width(2);\n    oss << second;\n    oss << \" \";\n\n    str = oss.str();\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const NetCDFCFCollection &ncdfcfc)\n{\n    o << \"NetCDFCFCollection\" << endl;\n    o << \" _coordinateVars : \";\n    for (int i = 0; i < ncdfcfc._coordinateVars.size(); i++) { o << ncdfcfc._coordinateVars[i] << \" \"; }\n    o << endl;\n\n    o << \" _lonCoordVars : \";\n    for (int i = 0; i < ncdfcfc._lonCoordVars.size(); i++) { o << ncdfcfc._lonCoordVars[i] << \" \"; }\n    o << endl;\n\n    o << \" _latCoordVars : \";\n    for (int i = 0; i < ncdfcfc._latCoordVars.size(); i++) { o << ncdfcfc._latCoordVars[i] << \" \"; }\n    o << endl;\n\n    o << \" _vertCoordVars : \";\n    for (int i = 0; i < ncdfcfc._vertCoordVars.size(); i++) { o << ncdfcfc._vertCoordVars[i] << \" \"; }\n    o << endl;\n\n    o << \" _timeCoordVars : \";\n    for (int i = 0; i < ncdfcfc._timeCoordVars.size(); i++) { o << ncdfcfc._timeCoordVars[i] << \" \"; }\n    o << endl;\n\n    o << \" _missingValueMap : \";\n    std::map<string, double>::const_iterator itr;\n    for (itr = ncdfcfc._missingValueMap.begin(); itr != ncdfcfc._missingValueMap.end(); ++itr) { o << itr->first << \" \" << itr->second << \", \"; }\n    o << endl;\n\n    o << \" Data Variables and coordinates :\" << endl;\n    for (int dim = 1; dim < 4; dim++) {\n        vector<string> vars = ncdfcfc.GetDataVariableNames(dim, true);\n        for (int i = 0; i < vars.size(); i++) {\n            o << \"  \" << vars[i] << \" : \";\n            vector<string> cvars;\n            int            rc = ncdfcfc.GetVarCoordVarNames(vars[i], cvars);\n            if (rc < 0) continue;\n            for (int j = 0; j < cvars.size(); j++) { o << cvars[j] << \" \"; }\n            o << endl;\n        }\n    }\n\n    o << endl;\n    o << endl;\n\n    o << (const NetCDFCollection &)ncdfcfc;\n\n    return (o);\n}\n};    // namespace VAPoR\n\nbool NetCDFCFCollection::_IsCoordinateVar(const NetCDFSimple::Variable &varinfo) const\n{\n    string         varname = varinfo.GetName();\n    vector<string> dimnames = varinfo.GetDimNames();\n\n    // A CF \"coordinate variable\" is a 1D variable whose name matches\n    // its dimension name. Here we also allow a variable with 1 spatial\n    // dimension and 1 time dimension\n    //\n    if (dimnames.size() == 1 && varname == dimnames[0]) return (true);\n\n    if (dimnames.size() == 2 && IsTimeVarying(varname) && varname == dimnames[1]) return (true);\n\n    return (false);\n}\n\nvector<string> NetCDFCFCollection::_GetCoordAttrs(const NetCDFSimple::Variable &varinfo) const\n{\n    vector<string> coordattrs;\n\n    string s;\n    varinfo.GetAtt(\"coordinates\", s);\n    if (s.empty()) return (coordattrs);    // No coordinates attribute found\n\n    //\n    // split the string using white space as the delimiter\n    //\n    stringstream                  ss(s);\n    istream_iterator<std::string> begin(ss);\n    istream_iterator<std::string> end;\n    coordattrs.insert(coordattrs.begin(), begin, end);\n\n    return (coordattrs);\n}\n\nbool NetCDFCFCollection::_IsLonCoordVar(const NetCDFSimple::Variable &varinfo) const\n{\n    string s;\n    varinfo.GetAtt(\"axis\", s);\n    if (StrCmpNoCase(s, \"X\") == 0) return (true);\n\n    s.clear();\n    varinfo.GetAtt(\"standard_name\", s);\n    if (StrCmpNoCase(s, \"longitude\") == 0) return (true);\n\n    if (StrCmpNoCase(s, \"grid_longitude\") == 0) return (true);\n\n    string unit;\n    varinfo.GetAtt(\"units\", unit);\n    if (unit.empty()) return (false);    // No coordinates attribute found\n\n    return (_udunit->IsLonUnit(unit));\n}\n\nbool NetCDFCFCollection::_IsLatCoordVar(const NetCDFSimple::Variable &varinfo) const\n{\n    string s;\n    varinfo.GetAtt(\"axis\", s);\n    if (StrCmpNoCase(s, \"Y\") == 0) return (true);\n\n    s.clear();\n    varinfo.GetAtt(\"standard_name\", s);\n    if (StrCmpNoCase(s, \"latitude\") == 0) return (true);\n\n    if (StrCmpNoCase(s, \"grid_latitude\") == 0) return (true);\n\n    string unit;\n    varinfo.GetAtt(\"units\", unit);\n    if (unit.empty()) return (false);    // No coordinates attribute found\n\n    return (_udunit->IsLatUnit(unit));\n}\n\nbool NetCDFCFCollection::_IsVertCoordVar(const NetCDFSimple::Variable &varinfo) const\n{\n    if (varinfo.GetDimNames().size() < 1) return (false);\n\n    string s;\n    varinfo.GetAtt(\"axis\", s);\n    if (StrCmpNoCase(s, \"Z\") == 0) return (true);\n\n    // The attribute \"cartesian_axis\" is not part of the CF spec, but\n    // apparently the MOM6 ocean model uses it :-(\n    //\n    varinfo.GetAtt(\"cartesian_axis\", s);\n    if (StrCmpNoCase(s, \"Z\") == 0) return (true);\n\n    s.clear();\n    varinfo.GetAtt(\"standard_name\", s);\n\n    if (StrCmpNoCase(s, \"atmosphere_ln_pressure_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"atmosphere_sigma_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"atmosphere_hybrid_sigma_pressure_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"atmosphere_hybrid_height_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"atmosphere_sleve_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"ocean_sigma_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"ocean_s_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"ocean_double_sigma_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"ocean_double_sigma_coordinate\") == 0) return (true);\n    if (StrCmpNoCase(s, \"ocean_s_coordinate_g1\") == 0) return (true);\n    if (StrCmpNoCase(s, \"ocean_s_coordinate_g2\") == 0) return (true);\n    if (StrCmpNoCase(s, \"altitude\") == 0) return (true);\n\n    s.clear();\n    varinfo.GetAtt(\"long_name\", s);\n\n    if (StrCmpNoCase(s, \"model_level_number\") == 0) return (true);\n\n    varinfo.GetAtt(\"positive\", s);\n    if ((StrCmpNoCase(s, \"up\") == 0) || (StrCmpNoCase(s, \"down\") == 0)) return (true);\n\n    string unit;\n    varinfo.GetAtt(\"units\", unit);\n    if (unit.empty()) return (false);    // No coordinates attribute found\n\n    return (_udunit->IsPressureUnit(unit) || _udunit->IsLengthUnit(unit));\n}\n\nbool NetCDFCFCollection::_IsTimeCoordVar(const NetCDFSimple::Variable &varinfo) const\n{\n    string s;\n    varinfo.GetAtt(\"axis\", s);\n    if (StrCmpNoCase(s, \"T\") == 0) return (true);\n\n    s.clear();\n    varinfo.GetAtt(\"standard_name\", s);\n    if (StrCmpNoCase(s, \"time\") == 0) return (true);\n\n    string unit;\n    varinfo.GetAtt(\"units\", unit);\n    if (unit.empty()) return (false);    // No coordinates attribute found\n\n    return (_udunit->IsTimeUnit(unit));\n}\n\nbool NetCDFCFCollection::_GetMissingValue(string varname, string attname, double &mv) const\n{\n    mv = 0.0;\n\n    NetCDFSimple::Variable varinfo;\n    (void)NetCDFCollection::GetVariableInfo(varname, varinfo);\n\n    vector<double> dvec;\n\n    varinfo.GetAtt(attname, dvec);\n    if (dvec.size()) {\n        mv = dvec[0];\n        return (true);\n    }\n\n    return (false);\n}\n\nvoid NetCDFCFCollection::_GetMissingValueMap(map<string, double> &missingValueMap) const\n{\n    missingValueMap.clear();\n\n    //\n    // Generate a map from all data variables with missing value\n    // attributes to missing value values. The CF conventions allow\n    // for two different attributes to specify missing values, \"missing_value\",\n    // and \"_FillValue\". The latter is for historical reasaons. Here we look\n    // for either, but give priority to \"missing_value\"\n    //\n    for (int d = 1; d < 5; d++) {\n        vector<string> vars = NetCDFCFCollection::GetDataVariableNames(d, false);\n\n        for (int i = 0; i < vars.size(); i++) {\n            double mv;\n            if (_GetMissingValue(vars[i], \"_FillValue\", mv)) { missingValueMap[vars[i]] = mv; }\n            if (_GetMissingValue(vars[i], \"missing_value\", mv)) { missingValueMap[vars[i]] = mv; }\n        }\n    }\n}\n"
  },
  {
    "path": "lib/vdc/NetCDFCollection.cpp",
    "content": "#include <algorithm>\n#include <cassert>\n#include <iostream>\n#include <utility>\n#include \"vapor/VAssert.h\"\n#include <netcdf.h>\n#include <vapor/NetCDFCollection.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\nusing namespace std;\n\nnamespace {\n\nconst string derivedTimeDimName = \"derivedTimeDim\";\n\ntemplate<class T> vector<T> make_container_unique(vector<T> v)\n{\n    sort(v.begin(), v.end());\n    auto last2 = unique(v.begin(), v.end());\n    v.erase(last2, v.end());\n    return (v);\n}\n\n\n};    // namespace\n\nNetCDFCollection::NetCDFCollection()\n{\n    _variableList.clear();\n    _dimNames.clear();\n    _dimLens.clear();\n    _missingValAttName.clear();\n    _times.clear();\n    _timesMap.clear();\n    _ovr_table.clear();\n    _ncdfmap.clear();\n    _failedVars.clear();\n}\n\nNetCDFCollection::~NetCDFCollection() { ReInitialize(); }\n\nvoid NetCDFCollection::ReInitialize()\n{\n    map<string, NetCDFSimple *>::iterator itr;\n    for (itr = _ncdfmap.begin(); itr != _ncdfmap.end(); ++itr) { delete itr->second; }\n\n    std::map<int, fileHandle>::iterator itr1;\n    for (itr1 = _ovr_table.begin(); itr1 != _ovr_table.end(); ++itr1) {\n        int fd = itr1->first;\n        (void)NetCDFCollection::Close(fd);\n    }\n\n    _variableList.clear();\n    _dimNames.clear();\n    _dimLens.clear();\n    _missingValAttName.clear();\n    _times.clear();\n    _timesMap.clear();\n    _ovr_table.clear();\n    _ncdfmap.clear();\n    _failedVars.clear();\n}\n\nint NetCDFCollection::Initialize(const vector<string> &files, const vector<string> &time_dimnames, const vector<string> &time_coordvars)\n{\n    vector<string> l_time_dimnames = time_dimnames;\n\n    ReInitialize();\n\n    //\n    // Build a hash table to map a variable's time dimension\n    // to its time coordinates\n    //\n    int                 file_org;    // case 1, 2, 3 (3a or 3b)\n    map<string, size_t> timeDimLens;\n    int                 rc = NetCDFCollection::_InitializeTimesMap(files, l_time_dimnames, time_coordvars, _timesMap, timeDimLens, _times, file_org);\n    if (rc < 0) return (-1);\n\n    for (auto itr : timeDimLens) {\n        _dimNames.push_back(itr.first);\n        _dimLens.push_back(itr.second);\n        _dimIsTimeVarying.push_back(false);\n    }\n\n    for (int i = 0; i < files.size(); i++) {\n        NetCDFSimple *netcdf = new NetCDFSimple();\n        _ncdfmap[files[i]] = netcdf;\n\n        rc = netcdf->Initialize(files[i]);\n        if (rc < 0) {\n            SetErrMsg(\"NetCDFSimple::Initialize(%s)\", files[i].c_str());\n            return (-1);\n        }\n        //        printf(\"INIT %i = %s\\n\", i, files[i].c_str());\n\n        //\n        // Get dimension names and lengths\n        //\n        vector<string> dimnames;\n        vector<size_t> dims;\n        netcdf->GetDimensions(dimnames, dims);\n        for (int j = 0; j < dimnames.size(); j++) {\n            // Handle time dims separately\n            //\n            if (timeDimLens.find(dimnames[j]) != timeDimLens.end()) continue;\n\n            // No duplicates\n            //\n            vector<string>::iterator itr;\n            itr = find(_dimNames.begin(), _dimNames.end(), dimnames[j]);\n            if (itr == _dimNames.end()) {\n                _dimNames.push_back(dimnames[j]);\n                _dimLens.push_back(dims[j]);\n                _dimIsTimeVarying.push_back(false);\n            } else if (_dimLens[itr - _dimNames.begin()] != dims[j]) {\n                _dimIsTimeVarying[itr - _dimNames.begin()] = true;\n            }\n        }\n\n        //\n        // Get variable info for all variables in current file\n        //\n        const vector<NetCDFSimple::Variable> &variables = netcdf->GetVariables();\n\n        //\n        // For each variable in the file add it to _variablesList\n        //\n        for (int j = 0; j < variables.size(); j++) {\n            string name = variables[j].GetName();\n\n            map<string, TimeVaryingVar>::iterator p = _variableList.find(name);\n\n            //\n            // If this is the first time we've seen this variable\n            // add it to _variablesList\n            //\n            if (p == _variableList.end()) {\n                TimeVaryingVar tvv;\n                _variableList[name] = tvv;\n                p = _variableList.find(name);\n            }\n            TimeVaryingVar &tvvref = p->second;\n\n            bool enable = EnableErrMsg(false);\n            int  rc = tvvref.Insert(netcdf, variables[j], files[i], l_time_dimnames, _timesMap, file_org);\n            (void)EnableErrMsg(enable);\n            if (rc < 0) {\n                SetErrCode(0);\n                _failedVars.push_back(files[i] + \": \" + variables[j].GetName());\n                continue;\n            }\n        }\n    }\n\n    for (auto itr = _variableList.begin(); itr != _variableList.end(); ++itr) {\n        TimeVaryingVar &tvvref = itr->second;\n        tvvref.Sort();\n    }\n\n    return (0);\n}\n\n#include <vapor/STLUtils.h>\n\nlong NetCDFCollection::GetDimLengthAtTime(string name, long ts)\n{\n    double realTime = _times[ts];\n\n    const auto end = _timesMap.cend();\n    string     filePath;\n    for (auto it = _timesMap.cbegin(); it != end; ++it) {\n        for (int i = 0; i < it->second.size(); i++) {\n            if (it->second[i] == realTime) {\n                filePath = it->first;\n                if (filePath == \"constant\")\n                    continue;\n                goto SEARCH_FINISHED;\n            }\n        }\n    }\nSEARCH_FINISHED:\n\n    if (filePath.empty()) {\n        MyBase::SetErrMsg(\"Time %li (%f) not found\", ts, realTime);\n        assert(0);\n        return -1;\n    }\n\n    NetCDFSimple *nc = nullptr;\n    for (auto it = _ncdfmap.cbegin(); it != _ncdfmap.cend(); ++it) {\n        if (STLUtils::BeginsWith(filePath, it->first)) {\n            nc = it->second;\n            break;\n        }\n    }\n\n    if (!nc) {\n        MyBase::SetErrMsg(\"NC for file not found\");\n        assert(0);\n        return -1;\n    }\n\n    vector<string> names;\n    vector<size_t> lengths;\n    nc->GetDimensions(names, lengths);\n\n    for (int i = 0; i < names.size(); i++) {\n        if (names[i] == name) { return lengths[i]; }\n    }\n\n    MyBase::SetErrMsg(\"Dimension not found at timestep %li\", ts);\n    return -1;\n}\n\nbool NetCDFCollection::VariableExists(string varname) const\n{\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) { return (false); }\n    return (true);\n}\n\nbool NetCDFCollection::VariableExists(size_t ts, string varname) const\n{\n    if (ts >= _times.size()) return (false);\n\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) { return (false); }\n    const TimeVaryingVar &tvvar = p->second;\n\n    if (!tvvar.GetTimeVarying()) return (true);    // CV variables exist for all times\n\n    double mytime = _times[ts];\n\n    vector<double> times = tvvar.GetTimes();\n    for (int i = 0; i < times.size(); i++) {\n        if (times[i] == mytime) return (true);\n    }\n    return (false);\n}\n\nvector<string> NetCDFCollection::GetVariableNames(int ndims, bool spatial) const\n{\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.begin();\n\n    vector<string> names;\n\n    for (; p != _variableList.end(); ++p) {\n        const TimeVaryingVar &tvvars = p->second;\n        int                   myndims = tvvars.GetSpatialDims().size();\n        if (!spatial && tvvars.GetTimeVarying()) { myndims++; }\n        if (myndims == ndims || ndims == -1) { names.push_back(p->first); }\n    }\n\n    return (names);\n}\n\nvector<size_t> NetCDFCollection::GetSpatialDims(string varname) const\n{\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) { return (vector<size_t>()); }\n    const TimeVaryingVar &tvvars = p->second;\n\n    return (tvvars.GetSpatialDims());\n}\n\nvector<string> NetCDFCollection::GetSpatialDimNames(string varname) const\n{\n    vector<string> dimnames;\n\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) { return (dimnames); }\n    const TimeVaryingVar &tvvars = p->second;\n\n    dimnames = tvvars.GetSpatialDimNames();\n    return (dimnames);\n}\n\nsize_t NetCDFCollection::GetTimeDim(string varname) const\n{\n\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) { return (0); }\n    const TimeVaryingVar &tvvars = p->second;\n\n    return (tvvars.GetNumTimeSteps());\n}\n\nstring NetCDFCollection::GetTimeDimName(string varname) const\n{\n    string dimname;\n\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) { return (dimname); }\n    const TimeVaryingVar &tvvars = p->second;\n\n    dimname = tvvars.GetTimeDimName();\n    return (dimname);\n}\n\nvector<size_t> NetCDFCollection::GetDims(string varname) const\n{\n    std::vector<size_t> dims = NetCDFCollection::GetSpatialDims(varname);\n    if (NetCDFCollection::IsTimeVarying(varname)) { dims.insert(dims.begin(), NetCDFCollection::GetTimeDim(varname)); }\n    return (dims);\n}\n\nvector<string> NetCDFCollection::GetDimNames(string varname) const\n{\n    std::vector<string> dimnames = NetCDFCollection::GetSpatialDimNames(varname);\n    if (NetCDFCollection::IsTimeVarying(varname)) { dimnames.insert(dimnames.begin(), NetCDFCollection::GetTimeDimName(varname)); }\n    return (dimnames);\n}\n\nbool NetCDFCollection::IsTimeVarying(string varname) const\n{\n\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) { return (false); }\n    const TimeVaryingVar &tvvars = p->second;\n    return (tvvars.GetTimeVarying());\n}\n\nint NetCDFCollection::GetXType(string varname) const\n{\n\n    NetCDFSimple::Variable varinfo;\n    int                    rc = NetCDFCollection::GetVariableInfo(varname, varinfo);\n    if (rc < 0) return (-1);\n\n    return (varinfo.GetXType());\n}\n\nstd::vector<string> NetCDFCollection::GetAttNames(string varname) const\n{\n    std::vector<string> attnames;\n\n    //\n    // See if global attribute\n    //\n    if (varname.empty()) {\n        if (_ncdfmap.empty()) { return (attnames); }\n        NetCDFSimple *netcdf = _ncdfmap.begin()->second;\n        return (netcdf->GetAttNames());\n    }\n\n    NetCDFSimple::Variable varinfo;\n    bool                   ok = NetCDFCollection::_GetVariableInfo(varname, varinfo);\n    if (!ok) { return (attnames); }\n\n    return (varinfo.GetAttNames());\n}\n\nint NetCDFCollection::GetAttType(string varname, string attname) const\n{\n    //\n    // See if global attribute\n    //\n    if (varname.empty()) {\n        if (_ncdfmap.empty()) { return (-1); }\n        NetCDFSimple *netcdf = _ncdfmap.begin()->second;\n        return (netcdf->GetAttType(attname));\n    }\n\n    NetCDFSimple::Variable varinfo;\n    bool                   ok = NetCDFCollection::_GetVariableInfo(varname, varinfo);\n    if (!ok) { return (-1); }\n\n    return (varinfo.GetAttType(attname));\n}\n\nvoid NetCDFCollection::GetAtt(string varname, string attname, std::vector<double> &values) const\n{\n    values.clear();\n\n    //\n    // See if global attribute\n    //\n    if (varname.empty()) {\n        if (_ncdfmap.empty()) { return; }\n        NetCDFSimple *netcdf = _ncdfmap.begin()->second;\n        netcdf->GetAtt(attname, values);\n        return;\n    }\n\n    NetCDFSimple::Variable varinfo;\n    bool                   ok = NetCDFCollection::_GetVariableInfo(varname, varinfo);\n    if (!ok) { return; }\n    varinfo.GetAtt(attname, values);\n}\n\nvoid NetCDFCollection::GetAtt(string varname, string attname, std::vector<long> &values) const\n{\n    values.clear();\n\n    //\n    // See if global attribute\n    //\n    if (varname.empty()) {\n        if (_ncdfmap.empty()) { return; }\n        NetCDFSimple *netcdf = _ncdfmap.begin()->second;\n        netcdf->GetAtt(attname, values);\n        return;\n    }\n\n    NetCDFSimple::Variable varinfo;\n    bool                   ok = NetCDFCollection::_GetVariableInfo(varname, varinfo);\n    if (!ok) { return; }\n    varinfo.GetAtt(attname, values);\n}\n\nvoid NetCDFCollection::GetAtt(string varname, string attname, string &values) const\n{\n    values.clear();\n\n    //\n    // See if global attribute\n    //\n    if (varname.empty()) {\n        if (_ncdfmap.empty()) { return; }\n        NetCDFSimple *netcdf = _ncdfmap.begin()->second;\n        netcdf->GetAtt(attname, values);\n        return;\n    }\n\n    NetCDFSimple::Variable varinfo;\n    bool                   ok = NetCDFCollection::_GetVariableInfo(varname, varinfo);\n    if (!ok) { return; }\n    varinfo.GetAtt(attname, values);\n}\n\nint NetCDFCollection::GetTime(size_t ts, double &time) const\n{\n    time = 0.0;\n    if (ts >= _times.size()) {\n        SetErrMsg(\"Invalid time step: %d\", ts);\n        return (-1);\n    }\n    time = _times[ts];\n    return (0);\n}\n\nint NetCDFCollection::GetTimes(string varname, vector<double> &times) const\n{\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", varname.c_str());\n        return (-1);\n    }\n    const TimeVaryingVar &tvvars = p->second;\n    if (!tvvars.GetTimeVarying()) {\n        times = _times;    // CV variables defined for all times\n    } else {\n        times = tvvars.GetTimes();\n    }\n    return (0);\n}\n\nint NetCDFCollection::GetFile(size_t ts, string varname, string &file, size_t &local_ts) const\n{\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", varname.c_str());\n        return (-1);\n    }\n    const TimeVaryingVar &tvvars = p->second;\n\n    double time;\n    int    rc = GetTime(ts, time);\n    if (rc < 0) return (-1);\n\n    size_t var_ts;\n    rc = tvvars.GetTimeStep(time, var_ts);\n    if (rc < 0) return (-1);\n\n    local_ts = tvvars.GetLocalTimeStep(var_ts);\n\n    return (tvvars.GetFile(var_ts, file));\n}\n\nbool NetCDFCollection::_GetVariableInfo(string varname, NetCDFSimple::Variable &varinfo) const\n{\n\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) { return (false); }\n    const TimeVaryingVar &tvvars = p->second;\n    tvvars.GetVariableInfo(varinfo);\n\n    vector<string> dimnames = tvvars.GetSpatialDimNames();\n    if (!(tvvars.GetTimeDimName().empty())) { dimnames.insert(dimnames.begin(), tvvars.GetTimeDimName()); }\n    varinfo.SetDimNames(dimnames);\n\n    return (true);\n}\n\nint NetCDFCollection::GetVariableInfo(string varname, NetCDFSimple::Variable &varinfo) const\n{\n    bool ok = NetCDFCollection::_GetVariableInfo(varname, varinfo);\n    if (!ok) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", varname.c_str());\n        return (-1);\n    }\n\n    return (0);\n}\n\nbool NetCDFCollection::GetMissingValue(string varname, double &mv) const\n{\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", varname.c_str());\n        return (false);\n    }\n    const TimeVaryingVar &tvvars = p->second;\n\n    return (tvvars.GetMissingValue(_missingValAttName, mv));\n}\n\nint NetCDFCollection::OpenRead(size_t ts, string varname)\n{\n    //\n    // Find a file descriptor. Use lowest available, starting with zero\n    //\n    int fd;\n    for (fd = 0; fd < _ovr_table.size(); fd++) {\n        if (_ovr_table.find(fd) == _ovr_table.end()) { break; }\n    }\n    fileHandle fh;\n\n    _ovr_table[fd] = fh;\n\n    map<string, TimeVaryingVar>::const_iterator p = _variableList.find(varname);\n    if (p == _variableList.end()) {\n        SetErrMsg(\"Invalid variable \\\"%s\\\"\", varname.c_str());\n        return (-1);\n    }\n    const TimeVaryingVar &tvvars = p->second;\n\n    double time;\n    int    rc = GetTime(ts, time);\n    if (rc < 0) return (-1);\n\n    size_t var_ts;\n    rc = tvvars.GetTimeStep(time, var_ts);\n    if (rc < 0) return (-1);\n\n    fh._tvvars = tvvars;\n    fh._local_ts = fh._tvvars.GetLocalTimeStep(var_ts);\n    fh._slice = 0;\n    fh._first_slice = true;\n\n    string                 path;\n    NetCDFSimple::Variable varinfo;\n    fh._tvvars.GetFile(var_ts, path);\n    fh._tvvars.GetVariableInfo(varinfo);\n\n    fh._has_missing = fh._tvvars.GetMissingValue(_missingValAttName, fh._missing_value);\n\n    fh._ncdfptr = _ncdfmap[path];\n    fh._fd = fh._ncdfptr->OpenRead(varinfo);\n    if (fh._fd < 0) {\n        SetErrMsg(\"NetCDFCollection::OpenRead(%d, %s) : failed\", var_ts, varname.c_str());\n        return (-1);\n    }\n\n    _ovr_table[fd] = fh;\n    return (fd);\n}\n\ntemplate<typename T> int NetCDFCollection::_read_template(size_t start[], size_t count[], T *data, int fd)\n{\n    size_t mystart[NC_MAX_VAR_DIMS];\n    size_t mycount[NC_MAX_VAR_DIMS];\n\n    std::map<int, fileHandle>::iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    fileHandle &fh = itr->second;\n\n    int idx = 0;\n    if (fh._tvvars.GetTimeVarying() && !(fh._tvvars.GetTimeDimName().empty() || fh._tvvars.GetTimeDimName() == derivedTimeDimName)) {\n        mystart[idx] = fh._local_ts;\n        mycount[idx] = 1;\n        idx++;\n    }\n    for (int i = 0; i < fh._tvvars.GetSpatialDims().size(); i++) {\n        mystart[idx] = start[i];\n        mycount[idx] = count[i];\n        idx++;\n    }\n\n    return (fh._ncdfptr->Read(mystart, mycount, data, fh._fd));\n}\n\nint NetCDFCollection::Read(size_t start[], size_t count[], double *data, int fd) { return (_read_template(start, count, data, fd)); }\nint NetCDFCollection::Read(size_t start[], size_t count[], float *data, int fd) { return (_read_template(start, count, data, fd)); }\nint NetCDFCollection::Read(size_t start[], size_t count[], int *data, int fd) { return (_read_template(start, count, data, fd)); }\nint NetCDFCollection::Read(size_t start[], size_t count[], char *data, int fd) { return (_read_template(start, count, data, fd)); }\n\n\nint NetCDFCollection::_InitializeTimesMap(const vector<string> &files, const vector<string> &time_dimnames, const vector<string> &time_coordvars, map<string, vector<double>> &timesMap,\n                                          map<string, size_t> &timeDimLens, vector<double> &times, int &file_org) const\n{\n    timesMap.clear();\n    timeDimLens.clear();\n    if (time_coordvars.size() && (time_coordvars.size() != time_dimnames.size())) {\n        SetErrMsg(\"NetCDFCollection::Initialize() : number of time coordinate variables and time dimensions must match when time coordinate variables specified\");\n        return (-1);\n    }\n\n    int rc;\n    if (time_dimnames.size() == 0) {\n        file_org = 1;\n        rc = _InitializeTimesMapCase1(files, timesMap, timeDimLens);\n    } else if ((time_dimnames.size() != 0) && (time_coordvars.size() == 0)) {\n        file_org = 2;\n        rc = _InitializeTimesMapCase2(files, time_dimnames, timesMap, timeDimLens);\n    } else {\n        file_org = 3;\n        rc = _InitializeTimesMapCase3(files, time_dimnames, time_coordvars, timesMap, timeDimLens);\n    }\n    if (rc < 0) return (rc);\n\n    //\n    // Generate times: a single vector of all the time coordinates\n    //\n    map<string, vector<double>>::const_iterator itr1;\n    for (itr1 = timesMap.begin(); itr1 != timesMap.end(); ++itr1) {\n        const vector<double> &timesref = itr1->second;\n        times.insert(times.end(), timesref.begin(), timesref.end());\n    }\n\n    //\n    // sort and remove duplicates\n    //\n    times = make_container_unique(times);\n\n    if (times.empty()) { times.push_back(0.0); }\n\n    //\n    // Create an entry for constant variables, which are defined at all times\n    //\n    timesMap[\"constant\"] = times;\n    return (0);\n}\n\nint NetCDFCollection::_InitializeTimesMapCase1(const vector<string> &files, map<string, vector<double>> &timesMap, map<string, size_t> &timeDimLens) const\n{\n    timesMap.clear();\n\n    // If only on file and no time dimensions than there is no\n    //\n    if (files.size() < 2) return (0);\n\n    map<string, double> currentTime;    // current time for each variable\n\n    // Case 1: No TDs or TCVs => synthesize TCV\n    // A variable's time coordinate is determined by the ordering\n    // of the file that it occurs in. The timesMap key is the\n    // concatentation of file name (where the variable occurs) and\n    // variable name. The only type of variables present are ITVV\n    //\n\n    for (int i = 0; i < files.size(); i++) {\n        NetCDFSimple *netcdf = new NetCDFSimple();\n\n        int rc = netcdf->Initialize(files[i]);\n        if (rc < 0) {\n            SetErrMsg(\"NetCDFSimple::Initialize(%s)\", files[i].c_str());\n            return (-1);\n        }\n\n        const vector<NetCDFSimple::Variable> &variables = netcdf->GetVariables();\n\n        for (int j = 0; j < variables.size(); j++) {\n            //\n            // Skip 0D variables\n            //\n            if (variables[j].GetDimNames().size() == 0) continue;\n\n            string varname = variables[j].GetName();\n\n            // If first time this variable has been seen\n            // initialize the currentTime\n            //\n            if (currentTime.find(varname) == currentTime.end()) { currentTime[varname] = 0.0; }\n\n            string         key = files[i] + varname;\n            vector<double> times(1, currentTime[varname]);\n            timesMap[key] = times;\n\n            currentTime[varname] += 1.0;\n        }\n        delete netcdf;\n    }\n    timeDimLens[derivedTimeDimName] = files.size();\n    return (0);\n}\n\nint NetCDFCollection::_InitializeTimesMapCase2(const vector<string> &files, const vector<string> &time_dimnames, map<string, vector<double>> &timesMap, map<string, size_t> &timeDimLens) const\n{\n    timesMap.clear();\n    map<string, double>         currentTime;    // current time for each variable\n    map<string, vector<double>> timeDimTimes;\n\n    // Case 2: TD specified, but no TCV.\n    // A variable's time coordinate is determined by the ordering\n    // of the file that it occurs in, offset by its time dimesion.\n    // The timesMap key is the\n    // concatentation of file name (where the variable occurs) and\n    // variable name.\n    // Both TVV and CV variables may be present.\n    //\n\n    for (int i = 0; i < files.size(); i++) {\n        NetCDFSimple *netcdf = new NetCDFSimple();\n\n        int rc = netcdf->Initialize(files[i]);\n        if (rc < 0) {\n            SetErrMsg(\"NetCDFSimple::Initialize(%s)\", files[i].c_str());\n            return (-1);\n        }\n\n        const vector<NetCDFSimple::Variable> &variables = netcdf->GetVariables();\n\n        for (int j = 0; j < variables.size(); j++) {\n            //\n            // Skip 0D variables\n            //\n            if (variables[j].GetDimNames().size() == 0) continue;\n\n            string varname = variables[j].GetName();\n            string key = files[i] + varname;\n            string timedim = variables[j].GetDimNames()[0];\n\n            // If this is a CV variable (no time dimension) we skip it\n            //\n            if (find(time_dimnames.begin(), time_dimnames.end(), timedim) == time_dimnames.end()) continue;    // CV variable\n\n            // Number of time steps for this variable\n            //\n            size_t timedimlen = netcdf->DimLen(timedim);\n\n            // If first time this varname has been seen\n            // initialize the currentTime\n            //\n            if (currentTime.find(varname) == currentTime.end()) { currentTime[varname] = 0.0; }\n\n            vector<double> times;\n            for (int t = 0; t < timedimlen; t++) {\n                times.push_back(currentTime[varname]);\n                currentTime[varname] += 1.0;\n            }\n\n            timesMap[key] = times;\n\n            vector<double> &timesref = timeDimTimes[timedim];\n            for (int t = 0; t < times.size(); t++) { timesref.push_back(times[t]); }\n        }\n        delete netcdf;\n    }\n\n    for (auto itr : timeDimTimes) {\n        vector<double> &ref = itr.second;\n        ref = make_container_unique(ref);\n        timeDimLens[itr.first] = ref.size();\n    }\n    return (0);\n}\n\nint NetCDFCollection::_InitializeTimesMapCase3(const vector<string> &files, const vector<string> &time_dimnames, const vector<string> &time_coordvars, map<string, vector<double>> &timesMap,\n                                               map<string, size_t> &timeDimLens) const\n{\n    timesMap.clear();\n\n    //\n    // tcvcount counts occurrences of each TCV. tcvfile and tcvdim record\n    // the last file name and TD pair used to generate hash key for each TCV\n    //\n    map<string, int>            tcvcount;    // # of files of TCV appears in\n    map<string, string>         tcvfile;\n    map<string, string>         tcvdim;\n    map<string, vector<double>> timeDimTimes;\n    for (int i = 0; i < time_coordvars.size(); i++) { tcvcount[time_coordvars[i]] = 0; }\n\n    for (int i = 0; i < files.size(); i++) {\n        NetCDFSimple *netcdf = new NetCDFSimple();\n\n        int rc = netcdf->Initialize(files[i]);\n        if (rc < 0) return (-1);\n\n        const vector<NetCDFSimple::Variable> &variables = netcdf->GetVariables();\n\n        //\n        // For each TCV see if it exists in current file, if so\n        // read it and add times to timesMap\n        //\n        for (int j = 0; j < time_coordvars.size(); j++) {\n            int index = _get_var_index(variables, time_coordvars[j]);\n            if (index < 0) continue;    // TCV doesn't exist\n\n            // Increment count\n            //\n\n            tcvcount[time_coordvars[j]] += 1;\n\n            // Read TCV\n            double *buf = _Get1DVar(netcdf, variables[index]);\n            if (!buf) {\n                SetErrMsg(\"Failed to read time coordinate variable \\\"%s\\\"\", time_coordvars[j].c_str());\n                return (-1);\n            }\n\n            string timedim = variables[index].GetDimNames()[0];\n            size_t timedimlen = netcdf->DimLen(timedim);\n\n            vector<double> times;\n            for (int t = 0; t < timedimlen; t++) { times.push_back(buf[t]); }\n            delete[] buf;\n\n            //\n            // The hash key for timesMap is the file plus the\n            // time dimension name\n            //\n            string key = files[i] + timedim;\n\n            // record file and timedim used to generate the hash key\n            //\n            tcvfile[time_coordvars[j]] = files[i];\n            tcvdim[time_coordvars[j]] = timedim;\n\n            if (timesMap.find(key) == timesMap.end()) {\n                timesMap[key] = times;\n            } else {\n                vector<double> &timesref = timesMap[key];\n                for (int t = 0; t < times.size(); t++) { timesref.push_back(times[t]); }\n            }\n\n            // Map between time dimention names and time coordinates\n            //\n            vector<double> &timesref = timeDimTimes[timedim];\n            for (int t = 0; t < times.size(); t++) { timesref.push_back(times[t]); }\n        }\n\n        delete netcdf;\n    }\n\n    for (auto itr : timeDimTimes) {\n        vector<double> &ref = itr.second;\n        ref = make_container_unique(ref);\n        timeDimLens[itr.first] = ref.size();\n    }\n\n    //\n    // Finally, if see if this is case 3a (only one file contains the TCV),\n    // or case 3b (a TCV is present in any file containing a TVV).\n    // We're only checking for case 3a here. If case 1, replicate the\n    // times for each file & time dimension pair\n    //\n    //\n\n    for (int i = 0; i < time_coordvars.size(); i++) {\n        if (tcvcount[time_coordvars[i]] == 1) {\n            string                                      key1 = tcvfile[time_coordvars[i]] + tcvdim[time_coordvars[i]];\n            map<string, vector<double>>::const_iterator itr;\n            for (int j = 0; j < files.size(); j++) {\n                string key = files[j] + tcvdim[time_coordvars[i]];\n                timesMap[key] = timesMap[key1];\n            }\n        }\n    }\n\n    return (0);\n}\n\ndouble *NetCDFCollection::_Get1DVar(NetCDFSimple *netcdf, const NetCDFSimple::Variable &variable) const\n{\n    if (variable.GetDimNames().size() != 1) return (NULL);\n    int fd = netcdf->OpenRead(variable);\n    if (fd < 0) {\n        SetErrMsg(\"Time coordinate variable \\\"%s\\\" is invalid\", variable.GetName().c_str());\n        return (NULL);\n    }\n    string dimname = variable.GetDimNames()[0];\n    size_t dimlen = netcdf->DimLen(dimname);\n    size_t start[] = {0};\n    size_t count[] = {dimlen};\n    double *buf = new double[dimlen];\n    int    rc = netcdf->Read(start, count, buf, fd);\n    if (rc < 0) { return (NULL); }\n    netcdf->Close(fd);\n    return (buf);\n}\n\nint NetCDFCollection::_get_var_index(const vector<NetCDFSimple::Variable> variables, string varname) const\n{\n    for (int i = 0; i < variables.size(); i++) {\n        if (varname.compare(variables[i].GetName()) == 0) return (i);\n    }\n    return (-1);\n}\n\n\ntemplate<typename T> int NetCDFCollection::_read_slice_template(T *data, int fd)\n{\n    std::map<int, fileHandle>::iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    fileHandle &fh = itr->second;\n\n    const TimeVaryingVar &var = fh._tvvars;\n    vector<size_t>        dims = var.GetSpatialDims();\n\n    if (dims.size() < 2 || dims.size() > 3) {\n        SetErrMsg(\"Only 2D and 3D variables supported\");\n        return (-1);\n    }\n\n    size_t nx = dims[dims.size() - 1];\n    size_t ny = dims[dims.size() - 2];\n    size_t nz = dims.size() > 2 ? dims[dims.size() - 3] : 1;\n\n    if (fh._slice >= nz) return (0);\n\n    size_t start[] = {0, 0, 0};\n    size_t count[] = {1, 1, 1};\n\n    if (dims.size() > 2) {\n        start[0] = fh._slice;\n        count[1] = ny;\n        count[2] = nx;\n    } else {\n        count[0] = ny;\n        count[1] = nx;\n    }\n\n    int rc = NetCDFCollection::Read(start, count, data, fd);\n    fh._slice++;\n    if (rc < 0) return (rc);\n    return (1);\n}\n\nint NetCDFCollection::ReadSlice(float *data, int fd) { return (_read_slice_template(data, fd)); }\n\nint NetCDFCollection::SeekSlice(int offset, int whence, int fd)\n{\n    std::map<int, fileHandle>::iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    fileHandle &fh = itr->second;\n\n    if (whence < 0 || whence > 2) {\n        SetErrMsg(\"Invalid whence specification : %d\", whence);\n        return (-1);\n    }\n\n    vector<size_t> dims = fh._tvvars.GetSpatialDims();\n    vector<string> dimnames = fh._tvvars.GetSpatialDimNames();\n\n    size_t nz = dims.size() == 3 ? dims[dims.size() - 3] : 1;\n    long   nzus = nz;\n\n    int slice = 0;\n    if (whence == 0) {\n        slice = offset;\n    } else if (whence == 1) {\n        slice = fh._slice + offset;\n    } else if (whence == 2) {\n        slice = offset + nzus - 1;\n    }\n    if (slice < 0) slice = 0;\n    if (slice > nzus - 1) slice = nzus - 1;\n\n    fh._slice = slice;\n    fh._first_slice = true;\n    return (0);\n}\n\nint NetCDFCollection::Read(vector<size_t> start, vector<size_t> count, double *data, int fd)\n{\n    VAssert(start.size() == count.size());\n\n    size_t mystart[NC_MAX_VAR_DIMS];\n    size_t mycount[NC_MAX_VAR_DIMS];\n    for (int i = 0; i < start.size(); i++) {\n        mystart[i] = start[i];\n        mycount[i] = count[i];\n    }\n    return (NetCDFCollection::Read(mystart, mycount, data, fd));\n}\n\nint NetCDFCollection::Read(vector<size_t> start, vector<size_t> count, float *data, int fd)\n{\n    VAssert(start.size() == count.size());\n\n    size_t mystart[NC_MAX_VAR_DIMS];\n    size_t mycount[NC_MAX_VAR_DIMS];\n    for (int i = 0; i < start.size(); i++) {\n        mystart[i] = start[i];\n        mycount[i] = count[i];\n    }\n    return (NetCDFCollection::Read(mystart, mycount, data, fd));\n}\n\nint NetCDFCollection::Read(vector<size_t> start, vector<size_t> count, int *data, int fd)\n{\n    VAssert(start.size() == count.size());\n\n    size_t mystart[NC_MAX_VAR_DIMS];\n    size_t mycount[NC_MAX_VAR_DIMS];\n    for (int i = 0; i < start.size(); i++) {\n        mystart[i] = start[i];\n        mycount[i] = count[i];\n    }\n    return (NetCDFCollection::Read(mystart, mycount, data, fd));\n}\n\n\ntemplate<typename T> int NetCDFCollection::_read_template(T *data, int fd)\n{\n    std::map<int, fileHandle>::iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    fileHandle &fh = itr->second;\n\n    const TimeVaryingVar &var = fh._tvvars;\n    vector<size_t>        dims = var.GetSpatialDims();\n    vector<string>        dimnames = var.GetSpatialDimNames();\n\n    //\n    // Handle different dimenion cases\n    //\n    if (dims.size() > 3) {\n        SetErrMsg(\"Only 0D, 1D, 2D and 3D variables supported\");\n        return (-1);\n    }\n\n    size_t start[3] = {0, 0, 0};\n    size_t count[3];\n    if (dims.size() == 0) {\n        count[0] = 1;\n        return (NetCDFCollection::Read(start, count, data, fd));\n    } else if (dims.size() == 1) {\n        size_t nx = dims[dims.size() - 1];\n        count[0] = nx;\n    } else if (dims.size() == 2) {\n        size_t nx = dims[dims.size() - 1];\n        size_t ny = dims[dims.size() - 2];\n        count[0] = ny;\n        count[1] = nx;\n    } else if (dims.size() == 3) {\n        size_t nx = dims[dims.size() - 1];\n        size_t ny = dims[dims.size() - 2];\n        size_t nz = dims[dims.size() - 3];\n        count[0] = nz;\n        count[1] = ny;\n        count[2] = nx;\n    }\n\n    return (NetCDFCollection::Read(start, count, data, fd));\n}\n\nint NetCDFCollection::Read(char *data, int fd) { return (_read_template(data, fd)); }\n\nint NetCDFCollection::Read(int *data, int fd) { return (_read_template(data, fd)); }\n\nint NetCDFCollection::Read(float *data, int fd) { return (_read_template(data, fd)); }\n\nint NetCDFCollection::Read(double *data, int fd) { return (_read_template(data, fd)); }\n\nint NetCDFCollection::Close(int fd)\n{\n    std::map<int, fileHandle>::iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    fileHandle &fh = itr->second;\n\n    if (!fh._ncdfptr) return (0);\n\n    int rc = fh._ncdfptr->Close(fh._fd);\n    if (fh._slicebuf) delete[] fh._slicebuf;\n    if (fh._linebuf) delete[] fh._linebuf;\n\n    _ovr_table.erase(itr);\n    return (rc);\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const NetCDFCollection &ncdfc)\n{\n    o << \"NetCDFCollection\" << endl;\n    o << \" _times : \";\n    for (int i = 0; i < ncdfc._times.size(); i++) { o << ncdfc._times[i] << \" \"; }\n    o << endl;\n    o << \" _missingValAttName : \" << ncdfc._missingValAttName << endl;\n\n    o << \" _variableList : \" << endl;\n    map<string, NetCDFCollection::TimeVaryingVar>::const_iterator itr;\n    for (itr = ncdfc._variableList.begin(); itr != ncdfc._variableList.end(); ++itr) {\n        o << itr->second;\n        o << endl;\n    }\n\n    return (o);\n}\n};    // namespace VAPoR\n\nNetCDFCollection::TimeVaryingVar::TimeVaryingVar()\n{\n    _files.clear();\n    _tvmaps.clear();\n    _spatial_dims.clear();\n    _spatial_dim_names.clear();\n    _name.clear();\n    _time_name.clear();\n    _time_varying = false;\n}\n\nint NetCDFCollection::TimeVaryingVar::Insert(const NetCDFSimple *netcdf, const NetCDFSimple::Variable &variable, string file, const vector<string> &time_dimnames,\n                                             const map<string, vector<double>> &timesmap, int file_org)\n{\n    bool first = (_tvmaps.size() == 0);    // first insertion?\n\n    vector<string> space_dim_names = variable.GetDimNames();\n    vector<size_t> space_dims;\n    for (int i = 0; i < space_dim_names.size(); i++) { space_dims.push_back(netcdf->DimLen(space_dim_names[i])); }\n    string time_name;\n\n    //\n    // Check if variable is time varying. I.e. if its slowest varying\n    // dimension name matches a dimension name specified in time_dimnames\n    //\n    bool   time_varying = false;\n    string key;    // hash key for timesmap\n\n    if (variable.GetDimNames().size()) {\n        string s = variable.GetDimNames()[0];\n\n        // Handle ITVV case\n        //\n        if (time_dimnames.size() == 1 && time_dimnames[0] == derivedTimeDimName) {\n            time_varying = true;\n            time_name = derivedTimeDimName;\n        } else if (find(time_dimnames.begin(), time_dimnames.end(), s) != time_dimnames.end()) {\n            time_varying = true;\n            time_name = s;\n            space_dims.erase(space_dims.begin());\n            space_dim_names.erase(space_dim_names.begin());\n        }\n    }\n\n    if (!time_varying) {\n        key = \"constant\";\n    } else if (file_org == 1 || file_org == 2) {\n        key = file + variable.GetName();\n    } else {\n        key = file + variable.GetDimNames()[0];\n    }\n\n    if (first) {\n        _spatial_dims = space_dims;\n        _spatial_dim_names = space_dim_names;\n        _time_varying = time_varying;\n        _name = variable.GetName();\n        _time_name = time_name;\n        _variable = variable;\n    } else {\n        //\n        // If this isn't the first variable to be inserted the new variable\n        // must match the existing ones\n        //\n        if (!((variable.GetDimNames() == _variable.GetDimNames()) && variable.GetXType() == _variable.GetXType())) {\n            SetErrMsg(\"Multiple definitions of variable \\\"%s\\\"\", variable.GetName().c_str());\n            return (-1);\n        }\n    }\n    _files.push_back(file);\n\n    map<string, vector<double>>::const_iterator itr;\n    itr = timesmap.find(key);\n    if (itr == timesmap.end()) {\n        SetErrMsg(\"Time coordinates not available for variable\");\n        return (-1);\n    }\n    const vector<double> &timesref = itr->second;\n\n    size_t local_ts = 0;\n    for (int i = 0; i < timesref.size(); i++) {\n        tvmap_t tvmap;\n        tvmap._fileidx = _files.size() - 1;\n        tvmap._time = timesref[i];\n        tvmap._local_ts = local_ts;\n        _tvmaps.push_back(tvmap);\n        local_ts++;\n    }\n\n    return (0);\n}\n\nint NetCDFCollection::TimeVaryingVar::GetTime(size_t ts, double &time) const\n{\n    if (ts >= _tvmaps.size()) return (-1);\n\n    time = _tvmaps[ts]._time;\n\n    return (0);\n}\n\nvector<double> NetCDFCollection::TimeVaryingVar::GetTimes() const\n{\n    vector<double> times;\n\n    for (int i = 0; i < _tvmaps.size(); i++) times.push_back(_tvmaps[i]._time);\n\n    return (times);\n}\n\nint NetCDFCollection::TimeVaryingVar::GetTimeStep(double time, size_t &ts) const\n{\n    if (!_time_varying) {\n        ts = 0;\n        return (0);\n    }\n\n    for (size_t i = 0; i < _tvmaps.size(); i++) {\n        if (_tvmaps[i]._time == time) {\n            ts = i;\n            return (0);\n        }\n    }\n    SetErrMsg(\"Invalid time %f\", time);\n    return (-1);\n}\n\nsize_t NetCDFCollection::TimeVaryingVar::GetLocalTimeStep(size_t ts) const\n{\n    if (ts >= _tvmaps.size()) return (0);\n\n    return (_tvmaps[ts]._local_ts);\n}\n\nint NetCDFCollection::TimeVaryingVar::GetFile(size_t ts, string &file) const\n{\n    if (ts >= _tvmaps.size()) return (-1);\n\n    int fileidx = _tvmaps[ts]._fileidx;\n    file = _files[fileidx];\n    return (0);\n}\n\nbool NetCDFCollection::TimeVaryingVar::GetMissingValue(string attname, double &mv) const\n{\n    mv = 0.0;\n\n    if (!attname.length()) return (false);\n\n    vector<double> vec;\n    _variable.GetAtt(attname, vec);\n    if (!vec.size()) return (false);\n\n    mv = vec[0];\n    return (true);\n}\n\nvoid NetCDFCollection::TimeVaryingVar::Sort()\n{\n    //\n    // Sort variable by time\n    //\n\n    auto lambda = [](const NetCDFCollection::TimeVaryingVar::tvmap_t &s1, const NetCDFCollection::TimeVaryingVar::tvmap_t &s2) -> bool { return (s1._time < s2._time); };\n\n    std::sort(_tvmaps.begin(), _tvmaps.end(), lambda);\n}\n\nNetCDFCollection::fileHandle::fileHandle()\n{\n    _ncdfptr = NULL;\n    _fd = -1;\n    _local_ts = 0;\n    _slice = 0;\n    _slicebuf = NULL;\n    _slicebufsz = 0;\n    _linebuf = NULL;\n    _linebufsz = 0;\n    _has_missing = false;\n    _missing_value = 0.0;\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const NetCDFCollection::TimeVaryingVar &var)\n{\n    o << \" TimeVaryingVar\" << endl;\n    o << \" Variable : \" << var._name << endl;\n    o << \"  Files : \" << endl;\n    for (int i = 0; i < var._files.size(); i++) { o << \"   \" << var._files[i] << endl; }\n    o << \"  Dims : \";\n    for (int i = 0; i < var._spatial_dims.size(); i++) { o << var._spatial_dims[i] << \" \"; }\n    o << endl;\n    o << \"  Dim Names : \";\n    for (int i = 0; i < var._spatial_dim_names.size(); i++) { o << var._spatial_dim_names[i] << \" \"; }\n    o << endl;\n\n    o << \"  Time Varying : \" << var._time_varying << endl;\n\n    o << \"  Time Varying Map : \" << endl;\n    for (int i = 0; i < var._tvmaps.size(); i++) {\n        o << \"   _fileidx : \" << var._tvmaps[i]._fileidx << endl;\n        o << \"   _time : \" << var._tvmaps[i]._time << endl;\n        o << \"   _local_ts : \" << var._tvmaps[i]._local_ts << endl;\n        o << endl;\n    }\n\n    return (o);\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/NetCDFSimple.cpp",
    "content": "#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <netcdf.h>\n#include <vapor/NetCDFSimple.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\nusing namespace std;\n\nNetCDFSimple::NetCDFSimple()\n{\n    _ncid = -1;\n    _ovr_table.clear();\n    _path = \"\";    // so _path.c_str() returns an empty string\n    _dimnames.clear();\n    _dims.clear();\n    _unlimited_dimnames.clear();\n    _flt_atts.clear();\n    _int_atts.clear();\n    _str_atts.clear();\n    _variables.clear();\n}\n\nNetCDFSimple::~NetCDFSimple()\n{\n    if (_ncid != -1) {\n        int rc = nc_close(_ncid);\n        if (rc != 0) {\n            SetErrMsg(\"nc_close(%d) : %s\", _ncid, nc_strerror(rc));\n            return;\n        }\n    }\n}\n\nint NetCDFSimple::Initialize(string path)\n{\n    _dimnames.clear();\n    _dims.clear();\n    _unlimited_dimnames.clear();\n    _flt_atts.clear();\n    _int_atts.clear();\n    _str_atts.clear();\n    _variables.clear();\n    _path = path;\n\n    int ncid;\n    int rc = nc_open(path.c_str(), NC_NOWRITE, &ncid);\n    if (rc != 0) {\n        SetErrMsg(\"nc_open(%s,) : %s\", path.c_str(), nc_strerror(rc));\n        return (-1);\n    }\n\n    int ndims;\n    rc = nc_inq_ndims(ncid, &ndims);\n    if (rc != 0) {\n        SetErrMsg(\"nc_inq_ndims(%d) : %s\", ncid, nc_strerror(rc));\n        return (-1);\n    }\n\n    //\n    // Get all the dimensions\n    //\n    for (int i = 0; i < ndims; i++) {\n        char   namebuf[NC_MAX_NAME + 1];\n        size_t len;\n        rc = nc_inq_dim(ncid, i, namebuf, &len);\n        if (rc != 0) {\n            SetErrMsg(\"nc_inq_dim(%d, %d) : %s\", ncid, i, nc_strerror(rc));\n            return (-1);\n        }\n        _dimnames.push_back(namebuf);\n        _dims.push_back(len);\n    }\n\n    //\n    // Get unlimited dim. N.B. in netCDF-4/HDF5 there can be multiple\n    // unlimited dimensions. Here we only check for one!\n    //\n    int dimid;\n    rc = nc_inq_unlimdim(ncid, &dimid);\n    if (rc != 0) {\n        SetErrMsg(\"nc_inq_unlimdim(%d) : %s\", ncid, nc_strerror(rc));\n        return (-1);\n    }\n    if (dimid >= 0) _unlimited_dimnames.push_back(_dimnames[dimid]);\n\n    //\n    // Get all the global attributes\n    //\n    rc = _GetAtts(ncid, NC_GLOBAL, _flt_atts, _int_atts, _str_atts);\n    if (rc < 0) return (-1);\n\n    //\n    // Finally, get all of the variable metadata\n    //\n    int nvars;\n    rc = nc_inq_nvars(ncid, &nvars);\n    if (rc != 0) {\n        SetErrMsg(\"nc_inq_nvars(%d) : %s\", ncid, nc_strerror(rc));\n        return (-1);\n    }\n\n    for (int varid = 0; varid < nvars; varid++) {\n        char    namebuf[NC_MAX_NAME + 1];\n        nc_type xtype;\n        int     ndims;\n        int     dimids[NC_MAX_VAR_DIMS];\n        int     natts;\n\n        rc = nc_inq_var(ncid, varid, namebuf, &xtype, &ndims, dimids, &natts);\n        if (rc != 0) {\n            SetErrMsg(\"nc_inq_var(%d, %d, %d) : %s\", ncid, varid, namebuf, nc_strerror(rc));\n            return (-1);\n        }\n        vector<string> dimnames;\n        vector<size_t> dims;\n        for (int i = 0; i < ndims; i++) {\n            dimnames.push_back(DimName(dimids[i]));\n            dims.push_back(_dims[dimids[i]]);\n        }\n\n        Variable var(namebuf, dimnames, xtype);\n\n        vector<pair<string, vector<double>>> flt_atts;\n        vector<pair<string, vector<long>>>   int_atts;\n        vector<pair<string, string>>         str_atts;\n        rc = _GetAtts(ncid, varid, flt_atts, int_atts, str_atts);\n        if (rc < 0) return (-1);\n\n        for (int i = 0; i < flt_atts.size(); i++) { var.SetAtt(flt_atts[i].first, flt_atts[i].second); }\n        for (int i = 0; i < int_atts.size(); i++) { var.SetAtt(int_atts[i].first, int_atts[i].second); }\n        for (int i = 0; i < str_atts.size(); i++) { var.SetAtt(str_atts[i].first, str_atts[i].second); }\n\n        _variables.push_back(var);\n    }\n\n    nc_close(ncid);\n    return (0);\n}\n\nint NetCDFSimple::OpenRead(const NetCDFSimple::Variable &variable)\n{\n    //\n    // If _ncid is not valid open the NetCDF file\n    //\n    if (_ncid == -1) {\n        int ncid;\n        int rc = nc_open(_path.c_str(), NC_NOWRITE, &ncid);\n        if (rc != 0) {\n            SetErrMsg(\"nc_open(%s,) : %s\", _path.c_str(), nc_strerror(rc));\n            return (-1);\n        }\n        _ncid = ncid;\n    }\n\n    int varid;\n    int rc = nc_inq_varid(_ncid, variable.GetName().c_str(), &varid);\n    if (rc != 0) {\n        SetErrMsg(\"nc_inq_varid(%d, %s, ) : %s\", _ncid, variable.GetName().c_str(), nc_strerror(rc));\n        return (-1);\n    }\n\n    //\n    // Find a file descriptor. Use lowest available, starting with zero\n    //\n    int fd;\n    for (fd = 0; fd < _ovr_table.size(); fd++) {\n        if (_ovr_table.find(fd) == _ovr_table.end()) { break; }\n    }\n    _ovr_table[fd] = varid;\n\n    return (fd);\n}\n\nint NetCDFSimple::Read(const size_t start[], const size_t count[], double *data, int fd) const\n{\n    std::map<int, int>::const_iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int varid = itr->second;\n\n    int rc = nc_get_vara_double(_ncid, varid, start, count, data);\n    if (rc != 0) {\n        SetErrMsg(\"nc_get_vara_double(%d, %d) : %s\", _ncid, varid, nc_strerror(rc));\n        return (-1);\n    }\n    return (0);\n}\n\nint NetCDFSimple::Read(const size_t start[], const size_t count[], float *data, int fd) const\n{\n    std::map<int, int>::const_iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int varid = itr->second;\n\n    int rc = nc_get_vara_float(_ncid, varid, start, count, data);\n    if (rc != 0) {\n        SetErrMsg(\"nc_get_vara_float(%d, %d) : %s\", _ncid, varid, nc_strerror(rc));\n        return (-1);\n    }\n    return (0);\n}\n\nint NetCDFSimple::Read(const size_t start[], const size_t count[], int *data, int fd) const\n{\n    std::map<int, int>::const_iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int varid = itr->second;\n\n    int rc = nc_get_vara_int(_ncid, varid, start, count, data);\n    if (rc != 0) {\n        SetErrMsg(\"nc_get_vara_int(%d, %d) : %s\", _ncid, varid, nc_strerror(rc));\n        return (-1);\n    }\n    return (0);\n}\n\nint NetCDFSimple::Read(const size_t start[], const size_t count[], char *data, int fd) const\n{\n    std::map<int, int>::const_iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    int varid = itr->second;\n\n    int rc = nc_get_vara_text(_ncid, varid, start, count, data);\n    if (rc != 0) {\n        SetErrMsg(\"nc_get_vara_text(%d, %d) : %s\", _ncid, varid, nc_strerror(rc));\n        return (-1);\n    }\n    return (0);\n}\n\nint NetCDFSimple::Close(int fd)\n{\n    std::map<int, int>::iterator itr;\n    if ((itr = _ovr_table.find(fd)) == _ovr_table.end()) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    _ovr_table.erase(itr);\n\n    if (_ovr_table.empty() && _ncid != -1) {\n        (void)nc_close(_ncid);\n        _ncid = -1;\n    }\n\n    return (0);\n}\n\nvoid NetCDFSimple::GetDimensions(vector<string> &names, vector<size_t> &dims) const\n{\n    names = _dimnames;\n    dims = _dims;\n}\n\nstring NetCDFSimple::DimName(int id) const\n{\n    if (id >= 0 && id < _dimnames.size()) return (_dimnames[id]);\n\n    return (\"\");\n}\n\nsize_t NetCDFSimple::DimLen(string name) const\n{\n    vector<string> names;\n    vector<size_t> dims;\n    VAssert(dims.size() == names.size());\n\n    NetCDFSimple::GetDimensions(names, dims);\n    for (int i = 0; i < names.size(); i++) {\n        if (names[i].compare(name) == 0) return (dims[i]);\n    }\n    return (0);    // unknown name\n}\n\nint NetCDFSimple::DimId(string name) const\n{\n    for (int i = 0; i < _dimnames.size(); i++) {\n        if (_dimnames[i].compare(name) == 0) return (i);\n    }\n    return (-1);\n}\n\nstd::vector<string> NetCDFSimple::GetAttNames() const\n{\n    vector<string> names;\n\n    for (int i = 0; i < _flt_atts.size(); i++) { names.push_back(_flt_atts[i].first); }\n    for (int i = 0; i < _int_atts.size(); i++) { names.push_back(_int_atts[i].first); }\n    for (int i = 0; i < _str_atts.size(); i++) { names.push_back(_str_atts[i].first); }\n    return (names);\n}\n\nint NetCDFSimple::GetAttType(string name) const\n{\n    for (int i = 0; i < _flt_atts.size(); i++) {\n        if (name.compare(_flt_atts[i].first) == 0) return (NC_DOUBLE);\n    }\n    for (int i = 0; i < _int_atts.size(); i++) {\n        if (name.compare(_int_atts[i].first) == 0) return (NC_INT64);\n    }\n    for (int i = 0; i < _str_atts.size(); i++) {\n        if (name.compare(_str_atts[i].first) == 0) return (NC_CHAR);\n    }\n    return (-1);\n}\n\nvoid NetCDFSimple::GetAtt(string name, vector<double> &values) const\n{\n    values.clear();\n    for (int i = 0; i < _flt_atts.size(); i++) {\n        if (_flt_atts[i].first.compare(name) == 0) {\n            values = _flt_atts[i].second;\n            return;\n        }\n    }\n    //\n    // Look for atts of type int and then cast to float if found\n    //\n    for (int i = 0; i < _int_atts.size(); i++) {\n        if (_int_atts[i].first.compare(name) == 0) {\n            for (int j = 0; j < _int_atts[i].second.size(); j++) { values.push_back(_int_atts[i].second[j]); }\n            return;\n        }\n    }\n    return;\n}\nvoid NetCDFSimple::GetAtt(string name, vector<long> &values) const\n{\n    values.clear();\n    for (int i = 0; i < _int_atts.size(); i++) {\n        if (_int_atts[i].first.compare(name) == 0) {\n            values = _int_atts[i].second;\n            return;\n        }\n    }\n\n    //\n    // Look for atts of type float and then cast to int if found\n    //\n    for (int i = 0; i < _flt_atts.size(); i++) {\n        if (_flt_atts[i].first.compare(name) == 0) {\n            for (int j = 0; j < _flt_atts[i].second.size(); j++) { values.push_back((long)_flt_atts[i].second[j]); }\n            return;\n        }\n    }\n    return;\n}\n\nvoid NetCDFSimple::GetAtt(string name, string &values) const\n{\n    values.clear();\n    for (int i = 0; i < _str_atts.size(); i++) {\n        if (_str_atts[i].first.compare(name) == 0) {\n            values = _str_atts[i].second;\n            return;\n        }\n    }\n    return;\n}\n\nbool NetCDFSimple::IsNCTypeInt(int type)\n{\n    if (type == NC_BYTE || type == NC_SHORT || type == NC_INT || type == NC_LONG || type == NC_UBYTE || type == NC_USHORT || type == NC_UINT || type == NC_INT64 || type == NC_UINT64) {\n        return (true);\n    }\n\n    return (false);\n}\n\nbool NetCDFSimple::IsNCTypeFloat(int type)\n{\n    if (type == NC_FLOAT || type == NC_DOUBLE) { return (true); }\n\n    return (false);\n}\n\nbool NetCDFSimple::IsNCTypeText(int type)\n{\n    if (type == NC_CHAR) { return (true); }\n\n    return (false);\n}\n\nint NetCDFSimple::_GetAtts(int ncid, int varid, vector<pair<string, vector<double>>> &flt_atts, vector<pair<string, vector<long>>> &int_atts, vector<pair<string, string>> &str_atts)\n{\n    flt_atts.clear();\n    int_atts.clear();\n    str_atts.clear();\n\n    int rc;\n    int natts;\n    if (varid == NC_GLOBAL) {\n        rc = nc_inq_natts(ncid, &natts);\n    } else {\n        rc = nc_inq_varnatts(ncid, varid, &natts);\n    }\n    if (rc != 0) {\n        SetErrMsg(\"nc_inq_varnatts(%d, %d) : %s\", ncid, varid, nc_strerror(rc));\n        return (-1);\n    }\n\n    for (int i = 0; i < natts; i++) {\n        char namebuf[NC_MAX_NAME + 1];\n        rc = nc_inq_attname(ncid, varid, i, namebuf);\n        if (rc != 0) {\n            SetErrMsg(\"nc_inq_attname(%d, %d, %d) : %s\", ncid, varid, i, nc_strerror(rc));\n            return (-1);\n        }\n\n        nc_type xtype;\n        size_t  len;\n        rc = nc_inq_att(ncid, varid, namebuf, &xtype, &len);\n        if (rc != 0) {\n            SetErrMsg(\"nc_inq_att(%d, %d, %s) : %s\", ncid, varid, namebuf, nc_strerror(rc));\n            return (-1);\n        }\n\n        else if (IsNCTypeInt(xtype)) {\n\n            // N.B. Use long long for windows platforms, which may\n            // represent longs as 32 bits. \n            // See https://github.com/NCAR/VAPOR/issues/3139\n            //\n            vector <long long> longbuf(len);\n\n            rc = nc_get_att_longlong(ncid, varid, namebuf, longbuf.data());\n            if (rc != 0) {\n                SetErrMsg(\"nc_get_att_long(%d, %d, %s) : %s\", ncid, varid, namebuf, nc_strerror(rc));\n                return (-1);\n            }\n\n\n            vector<long> vals;\n            for (int i = 0; i < len; i++) { vals.push_back(longbuf[i]); }\n            int_atts.push_back(make_pair(namebuf, vals));\n        } else if (IsNCTypeFloat(xtype)) {\n            vector <double> dblbuf(len);\n\n            rc = nc_get_att_double(ncid, varid, namebuf, dblbuf.data());\n            if (rc != 0) {\n                SetErrMsg(\"nc_get_att_double(%d, %d, %s) : %s\", ncid, varid, namebuf, nc_strerror(rc));\n                return (-1);\n            }\n\n            flt_atts.push_back(make_pair(namebuf, dblbuf));\n\n        } else if (IsNCTypeText(xtype)) {\n            vector <char> textbuf(len+1, '\\0');\n\n            rc = nc_get_att_text(ncid, varid, namebuf, textbuf.data());\n            if (rc != 0) {\n                SetErrMsg(\"nc_get_att_text(%d, %d, %s) : %s\", ncid, varid, namebuf, nc_strerror(rc));\n                return (-1);\n            }\n\n            str_atts.push_back(make_pair(namebuf, textbuf.data()));\n\n        } else {\n            SetErrMsg(\"Unhandled attribute type : %d\", xtype);\n            return (-1);\n        }\n    }\n\n    return (0);\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const NetCDFSimple &nc)\n{\n    o << \"NetCDFSimple\" << endl;\n    o << \" File : \" << nc._path << endl;\n    o << \" Dimensions : \" << endl;\n    for (int i = 0; i < nc._dimnames.size(); i++) { o << \"  \" << nc._dimnames[i] << \" \" << nc._dims[i] << endl; }\n    o << \" Unlimited Dimensions : \" << endl;\n    for (int i = 0; i < nc._unlimited_dimnames.size(); i++) { o << \"  \" << nc._unlimited_dimnames[i] << endl; }\n\n    o << \" Attributes : \" << endl;\n    for (int i = 0; i < nc._flt_atts.size(); i++) {\n        o << \"  \" << nc._flt_atts[i].first << \": \";\n        for (int j = 0; j < nc._flt_atts[i].second.size(); j++) { o << nc._flt_atts[i].second[j] << \" \"; }\n        o << endl;\n    }\n    for (int i = 0; i < nc._int_atts.size(); i++) {\n        o << \"  \" << nc._int_atts[i].first << \": \";\n        for (int j = 0; j < nc._int_atts[i].second.size(); j++) { o << nc._int_atts[i].second[j] << \" \"; }\n        o << endl;\n    }\n    for (int i = 0; i < nc._str_atts.size(); i++) {\n        o << \"  \" << nc._str_atts[i].first << \": \";\n        o << nc._str_atts[i].second << endl;\n    }\n\n    for (int i = 0; i < nc._variables.size(); i++) { o << nc._variables[i]; }\n\n    return (o);\n}\n}    // namespace VAPoR\n\nNetCDFSimple::Variable::Variable()\n{\n    _name.clear();\n    _dimnames.clear();\n    _flt_atts.clear();\n    _int_atts.clear();\n    _str_atts.clear();\n    _type = -1;\n}\n\nNetCDFSimple::Variable::Variable(string name, vector<string> dimnames, int type)\n{\n    _name = name;\n    _dimnames = dimnames;\n    _type = type;\n    _flt_atts.clear();\n    _int_atts.clear();\n    _str_atts.clear();\n}\n\nvector<string> NetCDFSimple::Variable::GetAttNames() const\n{\n    vector<string> names;\n\n    for (int i = 0; i < _flt_atts.size(); i++) { names.push_back(_flt_atts[i].first); }\n    for (int i = 0; i < _int_atts.size(); i++) { names.push_back(_int_atts[i].first); }\n    for (int i = 0; i < _str_atts.size(); i++) { names.push_back(_str_atts[i].first); }\n    return (names);\n}\n\nint NetCDFSimple::Variable::GetAttType(string name) const\n{\n    for (int i = 0; i < _flt_atts.size(); i++) {\n        if (name.compare(_flt_atts[i].first) == 0) return (NC_DOUBLE);\n    }\n    for (int i = 0; i < _int_atts.size(); i++) {\n        if (name.compare(_int_atts[i].first) == 0) return (NC_INT64);\n    }\n    for (int i = 0; i < _str_atts.size(); i++) {\n        if (name.compare(_str_atts[i].first) == 0) return (NC_CHAR);\n    }\n    return (-1);\n}\n\nvoid NetCDFSimple::Variable::GetAtt(string name, vector<double> &values) const\n{\n    values.clear();\n    for (int i = 0; i < _flt_atts.size(); i++) {\n        if (_flt_atts[i].first.compare(name) == 0) {\n            values = _flt_atts[i].second;\n            return;\n        }\n    }\n    //\n    // Look for atts of type int and then cast to float if found\n    //\n    for (int i = 0; i < _int_atts.size(); i++) {\n        if (_int_atts[i].first.compare(name) == 0) {\n            for (int j = 0; j < _int_atts[i].second.size(); j++) { values.push_back(_int_atts[i].second[j]); }\n            return;\n        }\n    }\n    return;\n}\nvoid NetCDFSimple::Variable::GetAtt(string name, vector<long> &values) const\n{\n    values.clear();\n    for (int i = 0; i < _int_atts.size(); i++) {\n        if (_int_atts[i].first.compare(name) == 0) {\n            values = _int_atts[i].second;\n            return;\n        }\n    }\n\n    //\n    // Look for atts of type float and then cast to int if found\n    //\n    for (int i = 0; i < _flt_atts.size(); i++) {\n        if (_flt_atts[i].first.compare(name) == 0) {\n            for (int j = 0; j < _flt_atts[i].second.size(); j++) { values.push_back((long)_flt_atts[i].second[j]); }\n            return;\n        }\n    }\n    return;\n}\n\nvoid NetCDFSimple::Variable::GetAtt(string name, string &values) const\n{\n    values.clear();\n    for (int i = 0; i < _str_atts.size(); i++) {\n        if (_str_atts[i].first.compare(name) == 0) {\n            values = _str_atts[i].second;\n            return;\n        }\n    }\n    return;\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const NetCDFSimple::Variable &var)\n{\n    o << \"Variable\" << endl;\n    o << \" Name : \" << var._name << endl;\n    o << \" NetCDFSimple type : \" << var._type << endl;\n    o << \" Dimensions : \" << endl;\n    for (int i = 0; i < var._dimnames.size(); i++) { o << \"  \" << var._dimnames[i] << endl; }\n    o << \" Attributes : \" << endl;\n    for (int i = 0; i < var._flt_atts.size(); i++) {\n        o << \"  \" << var._flt_atts[i].first << \": \";\n        for (int j = 0; j < var._flt_atts[i].second.size(); j++) { o << var._flt_atts[i].second[j] << \" \"; }\n        o << endl;\n    }\n    for (int i = 0; i < var._int_atts.size(); i++) {\n        o << \"  \" << var._int_atts[i].first << \": \";\n        for (int j = 0; j < var._int_atts[i].second.size(); j++) { o << var._int_atts[i].second[j] << \" \"; }\n        o << endl;\n    }\n    for (int i = 0; i < var._str_atts.size(); i++) {\n        o << \"  \" << var._str_atts[i].first << \": \";\n        o << var._str_atts[i].second << endl;\n    }\n\n    return (o);\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/Proj4API.cpp",
    "content": "#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1\n\n#include <iostream>\n#include <proj_api.h>\n#include <vapor/ResourcePath.h>\n#include <vapor/Proj4API.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nProj4API::Proj4API()\n{\n    _pjSrc = NULL;\n    _pjDst = NULL;\n\n    string path = GetSharePath(\"proj\");\n    if (!path.empty()) {\n#ifdef WIN32\n        path = \"PROJ_LIB=\" + path;\n        int rc = _putenv(path.c_str());\n        if (rc != 0) MyBase::SetErrMsg(\"putenv failed on PROJ_LIB setting\");\n#else\n        setenv(\"PROJ_LIB\", path.c_str(), 1);\n#endif\n    }\n}\n\nProj4API::~Proj4API()\n{\n    if (_pjSrc) pj_free(_pjSrc);\n    if (_pjDst) pj_free(_pjDst);\n}\n\nint Proj4API::_Initialize(string srcdef, string dstdef, void **pjSrc, void **pjDst) const\n{\n    *pjSrc = NULL;\n    *pjDst = NULL;\n\n    if (!srcdef.empty()) {\n        *pjSrc = pj_init_plus(srcdef.c_str());\n        if (!*pjSrc) {\n            SetErrMsg(\"pj_init_plus(%s) : %s\", srcdef.c_str(), ProjErr().c_str());\n            return (-1);\n        }\n    }\n\n    if (!dstdef.empty()) {\n        *pjDst = pj_init_plus(dstdef.c_str());\n        if (!*pjDst) {\n            SetErrMsg(\"pj_init_plus(%s) : %s\", dstdef.c_str(), ProjErr().c_str());\n            return (-1);\n        }\n    }\n\n    //\n    // If either the source or destination definition string is\n    // not provided - but not both - generate a \"latlong\" conversion\n    //\n    if (srcdef.empty() && !dstdef.empty()) {\n        *pjSrc = pj_latlong_from_proj(*pjDst);\n        if (!*pjSrc) {\n            SetErrMsg(\"pj_latlong_from_proj() : %s\", ProjErr().c_str());\n            return (-1);\n        }\n    } else if (!srcdef.empty() && dstdef.empty()) {\n        *pjDst = pj_latlong_from_proj(*pjSrc);\n        if (!*pjDst) {\n            SetErrMsg(\"pj_latlong_from_proj() : %s\", ProjErr().c_str());\n            return (-1);\n        }\n    } else {\n        // NULL transform. Transforms will be no-ops\n    }\n    return (0);\n}\n\nint Proj4API::Initialize(string srcdef, string dstdef)\n{\n    if (_pjSrc) pj_free(_pjSrc);\n    if (_pjDst) pj_free(_pjDst);\n    _pjSrc = NULL;\n    _pjDst = NULL;\n\n    return (_Initialize(srcdef, dstdef, &_pjSrc, &_pjDst));\n}\n\nbool Proj4API::IsLatLonSrc() const\n{\n    if (!_pjSrc) return (false);\n\n    return ((bool)pj_is_latlong(_pjSrc));\n}\n\nbool Proj4API::IsLatLonDst() const\n{\n    if (!_pjDst) return (false);\n\n    return ((bool)pj_is_latlong(_pjDst));\n}\n\nbool Proj4API::IsGeocentSrc() const\n{\n    if (!_pjSrc) return (false);\n\n    return ((bool)pj_is_geocent(_pjSrc));\n}\n\nbool Proj4API::IsGeocentDst() const\n{\n    if (!_pjDst) return (false);\n\n    return ((bool)pj_is_geocent(_pjDst));\n}\n\nstring Proj4API::GetSrcStr() const\n{\n    if (!_pjSrc) return (\"\");\n\n    return ((string)pj_get_def(_pjSrc, 0));\n}\n\nstring Proj4API::GetDstStr() const\n{\n    if (!_pjDst) return (\"\");\n\n    return ((string)pj_get_def(_pjDst, 0));\n}\n\nint Proj4API::Transform(double *x, double *y, size_t n, int offset) const { return (Proj4API::Transform(x, y, NULL, n, offset)); }\n\nint Proj4API::_Transform(void *pjSrc, void *pjDst, double *x, double *y, double *z, size_t n, int offset) const\n{\n    // no-op\n    //\n    if (pjSrc == NULL || pjDst == NULL) return (0);\n\n    //\n    // Convert from degrees to radians if source is in\n    // geographic coordinates\n    //\n    if (pj_is_latlong(pjSrc)) {\n        if (x) {\n            for (size_t i = 0; i < n; i++) { x[i * (size_t)offset] *= DEG_TO_RAD; }\n        }\n        if (y) {\n            for (size_t i = 0; i < n; i++) { y[i * (size_t)offset] *= DEG_TO_RAD; }\n        }\n        if (z) {\n            for (size_t i = 0; i < n; i++) { z[i * (size_t)offset] *= DEG_TO_RAD; }\n        }\n    }\n\n    int rc = pj_transform(pjSrc, pjDst, n, offset, x, y, NULL);\n    if (rc != 0) {\n        SetErrMsg(\"pj_transform() : %s\", ProjErr().c_str());\n        return (-1);\n    }\n\n    //\n    // Convert from radians degrees if destination is in\n    // geographic coordinates\n    //\n    if (pj_is_latlong(pjDst)) {\n        if (x) {\n            for (size_t i = 0; i < n; i++) { x[i * (size_t)offset] *= RAD_TO_DEG; }\n        }\n        if (y) {\n            for (size_t i = 0; i < n; i++) { y[i * (size_t)offset] *= RAD_TO_DEG; }\n        }\n        if (z) {\n            for (size_t i = 0; i < n; i++) { z[i * (size_t)offset] *= RAD_TO_DEG; }\n        }\n    }\n    return (0);\n}\n\nint Proj4API::Transform(double *x, double *y, double *z, size_t n, int offset) const { return (_Transform(_pjSrc, _pjDst, x, y, z, n, offset)); }\n\nint Proj4API::Transform(float *x, float *y, size_t n, int offset) const { return (Proj4API::Transform(x, y, NULL, n, offset)); }\n\nint Proj4API::_Transform(void *pjSrc, void *pjDst, float *x, float *y, float *z, size_t n, int offset) const\n{\n    double *xd = NULL;\n    double *yd = NULL;\n    double *zd = NULL;\n\n    if (x) {\n        xd = new double[n];\n        for (size_t i = 0; i < n; i++) xd[i] = x[i * offset];\n    }\n    if (y) {\n        yd = new double[n];\n        for (size_t i = 0; i < n; i++) yd[i] = y[i * offset];\n    }\n    if (z) {\n        zd = new double[n];\n        for (size_t i = 0; i < n; i++) zd[i] = z[i * offset];\n    }\n\n    int rc = _Transform(pjSrc, pjDst, xd, yd, zd, n, 1);\n\n    if (xd) {\n        for (size_t i = 0; i < n; i++) x[i * offset] = xd[i];\n        delete[] xd;\n    }\n    if (yd) {\n        for (size_t i = 0; i < n; i++) y[i * offset] = yd[i];\n        delete[] yd;\n    }\n    if (zd) {\n        for (size_t i = 0; i < n; i++) z[i * offset] = zd[i];\n        delete[] zd;\n    }\n    return (rc);\n}\n\nint Proj4API::Transform(float *x, float *y, float *z, size_t n, int offset) const { return (Proj4API::_Transform(_pjSrc, _pjDst, x, y, z, n, offset)); }\n\nint Proj4API::Transform(string srcdef, string dstdef, double *x, double *y, double *z, size_t n, int offset) const\n{\n    void *pjSrc = NULL;\n    void *pjDst = NULL;\n\n    int rc = _Initialize(srcdef, dstdef, &pjSrc, &pjDst);\n    if (rc < 0) return (rc);\n\n    return (_Transform(pjSrc, pjDst, x, y, z, n, offset));\n\n    return (0);\n}\n\nint Proj4API::Transform(string srcdef, string dstdef, float *x, float *y, float *z, size_t n, int offset) const\n{\n    void *pjSrc = NULL;\n    void *pjDst = NULL;\n\n    int rc = _Initialize(srcdef, dstdef, &pjSrc, &pjDst);\n    if (rc < 0) return (rc);\n\n    return (_Transform(pjSrc, pjDst, x, y, z, n, offset));\n\n    return (0);\n}\n\nstring Proj4API::ProjErr() const { return (pj_strerrno(*pj_get_errno_ref())); }\n\nvoid Proj4API::Clamp(double *x, double *y, size_t n, int offset) const\n{\n    double minx, miny, maxx, maxy;\n\n    string projstring = GetSrcStr();\n\n    if (IsLatLonSrc()) {\n        minx = -180.0;\n        miny = -90.0;\n        maxx = 180.0;\n        maxy = 90.0;\n    } else if (std::string::npos != projstring.find(\"proj=eqc\")) {\n        minx = -20037508.3427892;\n        miny = -10018754.1713946;\n        maxx = -minx;\n        maxy = -miny;\n    } else if (std::string::npos != projstring.find(\"proj=merc\")) {\n        minx = -20037508.340;\n        miny = minx;\n        maxx = -minx;\n        maxy = -miny;\n    } else {\n        return;    // unknown  projectoin\n    }\n\n    for (int i = 0; i < n; i++) {\n        if (x[i * offset] < minx) x[i * offset] = minx;\n        if (y[i * offset] < miny) y[i * offset] = miny;\n        if (x[i * offset] > maxx) x[i * offset] = maxx;\n        if (y[i * offset] > maxy) y[i * offset] = maxy;\n    }\n}\n\nbool Proj4API::IsCylindrical() const\n{\n    string proj4String = GetDstStr();\n\n    return ((proj4String.find(\"+proj=eqc\") != std::string::npos) || (proj4String.find(\"+proj=merc\") != std::string::npos));\n}\n"
  },
  {
    "path": "lib/vdc/PythonDataMgr.cpp",
    "content": "#include <vapor/VAssert.h>\n#include <vapor/DCRAM.h>\n#include <vapor/PythonDataMgr.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nPythonDataMgr::PythonDataMgr(string format, size_t mem_size, int nthreads)\n: DataMgr(format, mem_size, nthreads)\n{\n    // TODO: Disable caching.\n    // TODO: DataMgr will fail to load anything if the cache is too small rather than\n    // TODO: just loading it and not caching the result.\n    // Disable caching\n    // Setting to 0 will just cause it to be rejected and fallback to default cache size.\n    // _mem_size = 1;\n}\n\nPythonDataMgr::~PythonDataMgr() {}\n\nvoid PythonDataMgr::AddRegularData(string name, const float *buf, vector<int> dimLens)\n{\n    auto dcr = GetDC();\n    \n    size_t totalSize = 1;\n//    printf(\"%s(dims=%li)\\n\", __func__, dimLens.size());\n    for (int i = 0; i < dimLens.size(); i++) {\n        totalSize *= dimLens[i];\n//        printf(\"\\t dim[%i] = %i\\n\", i, dimLens[i]);\n    }\n//    printf(\"\\t data = \");\n    for (int i = 0; i < (totalSize < 5 ? totalSize : 5); i++) {\n//        printf(\"%f, \", buf[i]);\n    }\n//    printf(\"\\n\");\n    \n    \n    vector<DC::Dimension> dims;\n    \n    for (auto len : dimLens) {\n        string genName = \"__regDim_\" + std::to_string(len);\n        DC::Dimension dim;\n        if (!GetDimension(genName, dim, -1)) {\n            dim = DC::Dimension(genName, len);\n            dcr->AddDimension(dim);\n//            printf(\"Created new dimension \\\"%s\\\"\\n\", dim.GetName().c_str());\n        }\n        dims.push_back(dim);\n    }\n    \n    vector<DC::CoordVar> coords;\n    int currDim = 0; // (x,y,z,t) = (0,1,2,3)\n    auto dimToStr = [](int d){ return \"xyzt\"[d]; };\n    \n    for (auto dim : dims) {\n        string genName = \"__regCoord_\" + std::to_string(dim.GetLength()) + \"_\" + dimToStr(currDim);\n        DC::CoordVar coord;\n        if (!GetCoordVarInfo(genName, coord)) {\n            coord = DC::CoordVar(genName, \"m\", DC::FLOAT, {false}, /*axis=x*/currDim, /*uniformHint=*/true, {dim.GetName()}, /*timeDim*/\"\");\n            vector<float> cbuf;\n            for (size_t i = 0; i < dim.GetLength(); i++)\n                cbuf.push_back(i);\n            dcr->AddCoordVar(coord, cbuf.data());\n//            printf(\"Created new coordinate \\\"%s\\\"\\n\", coord.GetName().c_str());\n        }\n        coords.push_back(coord);\n        currDim++;\n    }\n    \n    \n    vector<string> dimNames, coordNames;\n    for (auto dim : dims)   dimNames.push_back(dim.GetName());\n    for (auto crd : coords) coordNames.push_back(crd.GetName());\n    \n    string meshGenName = \"__\" + DC::Mesh::MakeMeshName(dimNames);\n    DC::Mesh mesh;\n    if (!GetMesh(meshGenName, mesh)) {\n        mesh = DC::Mesh(meshGenName, dimNames, coordNames);\n        dcr->AddMesh(mesh);\n//        printf(\"Created new mesh \\\"%s\\\"\\n\", mesh.GetName().c_str());\n    }\n    \n    \n    \n    vector<bool> periodic(dims.size(), false);\n    auto v = DC::DataVar(name, \"\", DC::FLOAT, periodic, mesh.GetName(), /*timeCoordVar*/\"\", DC::Mesh::NODE);\n    \n    dcr->AddDataVar(v, buf);\n    ClearCache(name);\n}\n\nDCRAM *PythonDataMgr::GetDC() const\n{\n    auto dcr = dynamic_cast<DCRAM*>(_dc);\n    VAssert(dcr);\n    return dcr;\n}\n\nvoid PythonDataMgr::ClearCache(string varname)\n{\n//    printf(\"%s(%s)\\n\", __func__, varname.c_str());\n    _free_var(varname);\n    _dataVarNamesCache.clear();\n}\n"
  },
  {
    "path": "lib/vdc/QuadTreeRectangleP.cpp",
    "content": "#include <iostream>\n#include <vapor/VAssert.h>\n#include <vapor/utils.h>\n#include <cstdint>\n#include <vapor/QuadTreeRectangleP.h>\n#include <vapor/OpenMPSupport.h>\n\nusing namespace VAPoR;\nusing namespace std;\n\nusing UInt32_tArr2 = std::array<uint32_t, 2>;\nusing pType = UInt32_tArr2;\n\nQuadTreeRectangleP::QuadTreeRectangleP(float left, float top, float right, float bottom, size_t max_depth, size_t reserve_size) : _left(left), _right(right)\n{\n    VAssert(left <= right);\n    VAssert(top <= bottom);\n\n    int nthreads = 1;\n#pragma omp parallel\n    {\n        if (omp_get_thread_num() == 0) nthreads = omp_get_num_threads();\n    }\n\n    // We split the quadtree along the X-axis to create one subtree for\n    // each thread. This way there are no dependencies between the regions\n    // covered by each subtree and we can process each subtree in parallel\n    //\n    float bin_width = ((float)right - (float)left) / ((float)nthreads);\n    float binLeft = left;\n    for (int i = 0; i < nthreads; i++) {\n        float binRight = binLeft + bin_width;\n\n        if (i == nthreads - 1) binRight = right;\n\n        _qtrs.push_back(new QuadTreeRectangle<float, pType>(binLeft, top, binRight, bottom, max_depth, reserve_size / nthreads));\n        binLeft = binRight;\n    }\n}\n\nQuadTreeRectangleP::QuadTreeRectangleP(size_t max_depth, size_t reserve_size) : _left(0.0), _right(1.0)\n{\n    int nthreads = 1;\n#pragma omp parallel\n    {\n        nthreads = omp_get_num_threads();\n    }\n\n    float bin_width = (1.0 - 0.0) / ((float)nthreads);\n    float binLeft = 0.0;\n    for (int i = 0; i < nthreads; i++) {\n        float binRight = binLeft + bin_width;\n\n        if (i == nthreads - 1) binRight = 1.0;\n\n        _qtrs.push_back(new QuadTreeRectangle<float, pType>(binLeft, 0.0, binRight, 1.0, max_depth, reserve_size / nthreads));\n\n        binLeft = binRight;\n    }\n}\n\nQuadTreeRectangleP::QuadTreeRectangleP(const QuadTreeRectangleP &rhs)\n{\n    _left = rhs._left;\n    _right = rhs._right;\n\n    _qtrs.resize(rhs._qtrs.size());\n    for (int i = 0; i < _qtrs.size(); i++) { _qtrs[i] = new QuadTreeRectangle<float, pType>(*(rhs._qtrs[i])); }\n}\n\nQuadTreeRectangleP &QuadTreeRectangleP::operator=(const QuadTreeRectangleP &rhs)\n{\n    _left = rhs._left;\n    _right = rhs._right;\n    for (int i = 0; i < _qtrs.size(); i++) {\n        if (_qtrs[i]) delete _qtrs[i];\n    }\n\n    _qtrs.resize(rhs._qtrs.size());\n    for (size_t i = 0; i < rhs._qtrs.size(); i++) { _qtrs[i] = new QuadTreeRectangle<float, pType>(*(rhs._qtrs[i])); }\n    return *this;\n}\n\nQuadTreeRectangleP::~QuadTreeRectangleP()\n{\n    for (size_t i = 0; i < _qtrs.size(); i++) {\n        if (_qtrs[i]) delete _qtrs[i];\n    }\n    _qtrs.clear();\n}\n\nbool QuadTreeRectangleP::Insert(float left, float top, float right, float bottom, DimsType payload)\n{\n    // Serial insertion of a single element\n    //\n    bool  status = true;\n    float bin_width = (_right - _left) / ((float)_qtrs.size());\n    float binLeft = _left;\n    for (int i = 0; i < _qtrs.size(); i++) {\n        float binRight = binLeft + bin_width;\n\n        if (i == _qtrs.size() - 1) binRight = right;\n\n        if (left <= binRight && right >= binLeft) {\n            pType p = {(uint32_t)payload[0], (uint32_t)payload[1]};\n            status &= _qtrs[i]->Insert(left, top, right, bottom, p);\n        }\n\n        binLeft = binRight;\n    }\n    return (status);\n}\n\nbool QuadTreeRectangleP::Insert(std::vector<class QuadTreeRectangle<float, pType>::rectangle_t> rectangles, std::vector<pType> payloads)\n{\n    VAssert(rectangles.size() == payloads.size());\n\n    bool status = true;\n\n    vector<vector<class QuadTreeRectangle<float, pType>::rectangle_t>> parRectangles(_qtrs.size());\n    vector<vector<pType>>                                              parPayloads(_qtrs.size());\n\n    // Pre-allocate space for each tree\n    //\n    for (int i = 0; i < _qtrs.size(); i++) {\n        parRectangles[i].reserve(rectangles.size() / _qtrs.size());\n        parPayloads[i].reserve(payloads.size() / _qtrs.size());\n    }\n\n    // parRectangles and parPayloads will contain the regions that\n    // need to be inserted into each subtree\n    //\n    float bin_width = (_right - _left) / ((float)_qtrs.size());\n    float binLeft = _left;\n    for (size_t j = 0; j < rectangles.size(); j++) {\n        for (int i = 0; i < _qtrs.size(); i++) {\n            float binRight = binLeft + bin_width;\n\n            if (i == _qtrs.size() - 1) binRight = _right;\n\n            if ((rectangles[j]._left <= binRight) && (rectangles[j]._right >= binLeft)) {\n                parRectangles[i].push_back(rectangles[j]);\n                parPayloads[i].push_back(payloads[j]);\n            }\n\n            binLeft = binRight;\n        }\n    }\n\n// Perform parallel construction of tree\n//\n#pragma omp parallel\n#pragma omp for\n    for (int i = 0; i < _qtrs.size(); i++) {\n        for (size_t j = 0; j < parRectangles[i].size(); j++) { status &= _qtrs[i]->Insert(parRectangles[i][j], parPayloads[i][j]); }\n    }\n\n    return (status);\n}\n\nbool QuadTreeRectangleP::Insert(const Grid *grid, size_t ncells)\n{\n    if (ncells == 0) { ncells = Wasp::VProduct(grid->GetCellDimensions().data(), grid->GetNumCellDimensions()); }\n\n    // parRectangles and parPayloads will contain the rectangles and their\n    // payloads that need to be inserted into each substree\n    //\n    vector<vector<class QuadTreeRectangle<float, pType>::rectangle_t>> parRectangles(_qtrs.size());\n    vector<vector<pType>>                                              parPayloads(_qtrs.size());\n    for (int i = 0; i < _qtrs.size(); i++) {\n        parRectangles[i].reserve(ncells / _qtrs.size());\n        parPayloads[i].reserve(ncells / _qtrs.size());\n    }\n\n    int ncellindices = grid->GetNumCellDimensions();\n\n// Populate parRectangles and parPayloads with the data that will\n// be used to contruct the quadtree\n//\n#pragma omp parallel\n    {\n        size_t           maxNodes = grid->GetMaxVertexPerCell();\n        vector<DimsType> nodes(maxNodes);\n\n        int    id = omp_get_thread_num();\n        int    nthreads = omp_get_num_threads();\n        size_t istart = id * ncells / nthreads;\n        size_t iend = (id + 1) * ncells / nthreads;\n        if (id == nthreads - 1) iend = ncells;\n\n        CoordType               coords;\n        Grid::ConstCellIterator itr = grid->ConstCellBegin() + istart;\n\n        for (size_t i = istart; i < iend; i++, ++itr) {\n            DimsType cell = {0, 0, 0};\n            Grid::CopyToArr3((*itr).data(), ncellindices, cell);\n\n            grid->GetCellNodes(cell, nodes);\n            if (nodes.size() < 2) continue;\n\n            grid->GetUserCoordinates(nodes[0], coords);\n\n            float left = (float)coords[0];\n            float right = (float)coords[0];\n            float top = (float)coords[1];\n            float bottom = (float)coords[1];\n\n            for (int j = 1; j < nodes.size(); j++) {\n                grid->GetUserCoordinates(nodes[j], coords);\n\n                if (coords[0] < left) left = (float)coords[0];\n                if (coords[0] > right) right = (float)coords[0];\n                if (coords[1] < top) top = (float)coords[1];\n                if (coords[1] > bottom) bottom = (float)coords[1];\n            }\n\n            // Figure out which subtree(s) contain the rectangle. In general,\n            // a rectangle can span multiple subtrees, in which case it\n            // will be inserted into both.\n            //\n            float bin_width = (_right - _left) / ((float)_qtrs.size());\n            float binLeft = _left;\n            for (int j = 0; j < _qtrs.size(); j++) {\n                float binRight = binLeft + bin_width;\n\n                if (j == _qtrs.size() - 1) binRight = _right;\n\n                if ((left <= binRight) && (right >= binLeft)) {\n                    class QuadTreeRectangle<float, pType>::rectangle_t r(left, top, right, bottom);\n\n                    pType p = {(uint32_t)cell[0], (uint32_t)cell[1]};\n#pragma omp critical\n                    {\n                        parRectangles[j].push_back(r);\n                        parPayloads[j].push_back(p);\n                    }\n                }\n\n                binLeft = binRight;\n            }\n        }\n    }\n\n    // At this point parRectangles and parPayloads contain a vector of\n    // rectangles and their payloads that intersect each of the subtrees that\n    // make up the tree. Since there is no shared data between each of\n    // the subtrees we can populate each subtree in parallel without any need\n    // for synchronization (mutex, etc.)\n    //\n    bool status = true;\n#pragma omp parallel\n#pragma omp for\n    for (int i = 0; i < _qtrs.size(); i++) {\n        for (size_t j = 0; j < parRectangles[i].size(); j++) { status &= _qtrs[i]->Insert(parRectangles[i][j], parPayloads[i][j]); }\n    }\n\n    return (status);\n}\n\nvoid QuadTreeRectangleP::GetPayloadContained(float x, float y, std::vector<DimsType> &payloads) const\n{\n    payloads.clear();\n\n    int   bin = 0;\n    float bin_width = ((float)_right - (float)_left) / ((float)_qtrs.size());\n    float binLeft = _left;\n    for (int i = 0; i < _qtrs.size(); i++) {\n        float binRight = binLeft + bin_width;\n        if (i == _qtrs.size() - 1) binRight = _right;\n\n        if (x >= binLeft && x <= binRight) {\n            bin = i;\n            break;\n        }\n        binLeft = binRight;\n    }\n\n    std::vector<pType> p;\n    _qtrs[bin]->GetPayloadContained(x, y, p);\n\n    for (auto itr = p.begin(); itr != p.end(); ++itr) { payloads.push_back(DimsType{(*itr)[0], (*itr)[1], 0}); }\n}\n\nvoid QuadTreeRectangleP::GetStats(std::vector<size_t> &payload_histo, std::vector<size_t> &level_histo) const\n{\n    payload_histo.clear();\n    level_histo.clear();\n\n    for (int i = 0; i < _qtrs.size(); i++) {\n        std::vector<size_t> p;\n        std::vector<size_t> l;\n\n        _qtrs[i]->GetStats(p, l);\n        payload_histo.insert(payload_histo.end(), p.begin(), p.end());\n        level_histo.insert(level_histo.end(), l.begin(), l.end());\n    }\n}\n"
  },
  {
    "path": "lib/vdc/RegularGrid.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <time.h>\n#ifdef Darwin\n    #include <mach/mach_time.h>\n#endif\n#ifdef _WINDOWS\n    #include \"windows.h\"\n    #include \"Winbase.h\"\n    #include <limits>\n#endif\n\n#include <vapor/utils.h>\n#include \"vapor/RegularGrid.h\"\n\nusing namespace std;\nusing namespace VAPoR;\n\nvoid RegularGrid::_regularGrid(const CoordType &minu, const CoordType &maxu)\n{\n    VAssert(minu.size() == maxu.size());\n\n    _delta = {0.0, 0.0, 0.0};\n\n    _geometryDim = 0;\n    for (int i = 0; i < minu.size(); i++) {\n        if (minu[i] != maxu[i])\n            _geometryDim++;\n        else\n            break;\n    }\n    VAssert(_geometryDim >= GetNumDimensions());\n\n    _minu = minu;\n    _maxu = maxu;\n\n    DimsType dims = GetDimensions();\n    for (int i = 0; i < minu.size(); i++) {\n        if (dims[i] > 1) {\n            _delta[i] = (_maxu[i] - _minu[i]) / (double)(dims[i] - 1);\n        } else {\n            _delta[i] = 0.0;\n        }\n    }\n}\n\nRegularGrid::RegularGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks, const CoordType &minu, const CoordType &maxu) : StructuredGrid(dims, bs, blks)\n{\n    _regularGrid(minu, maxu);\n}\n\nRegularGrid::RegularGrid(const vector<size_t> &dimsv, const vector<size_t> &bsv, const vector<float *> &blks, const vector<double> &minuv, const vector<double> &maxuv)\n: StructuredGrid(dimsv, bsv, blks)\n{\n    VAssert(minuv.size() == maxuv.size());\n    VAssert(minuv.size() >= GetNumDimensions());\n\n    CoordType minu = {0.0, 0.0, 0.0};\n    CoordType maxu = {0.0, 0.0, 0.0};\n    CopyToArr3(minuv, minu);\n    CopyToArr3(maxuv, maxu);\n\n    _regularGrid(minu, maxu);\n}\n\nDimsType RegularGrid::GetCoordDimensions(size_t dim) const\n{\n    DimsType dims = {1, 1, 1};\n\n    if (dim == 0) {\n        dims[0] = GetDimensions()[0];\n    } else if (dim == 1) {\n        dims[0] = GetDimensions()[1];\n    } else if (dim == 2) {\n        dims[0] = GetDimensions()[2];\n    }\n\n    return (dims);\n}\n\nfloat RegularGrid::GetValueNearestNeighbor(const CoordType &coords) const\n{\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    if (!InsideGrid(cCoords)) return (GetMissingValue());\n\n    size_t i = 0;\n    size_t j = 0;\n    size_t k = 0;\n\n    if (_delta[0] != 0.0) i = (size_t)floor((cCoords[0] - _minu[0]) / _delta[0]);\n    if (_delta[1] != 0.0) j = (size_t)floor((cCoords[1] - _minu[1]) / _delta[1]);\n\n    auto dims = GetDimensions();\n\n    if (GetGeometryDim() == 3)\n        if (_delta[2] != 0.0) k = (size_t)floor((cCoords[2] - _minu[2]) / _delta[2]);\n\n    VAssert(i < dims[0]);\n    VAssert(j < dims[1]);\n\n    if (GetNumDimensions() == 3) VAssert(k < dims[2]);\n\n    double iwgt = 0.0;\n    double jwgt = 0.0;\n    double kwgt = 0.0;\n\n    if (_delta[0] != 0.0) { iwgt = ((cCoords[0] - _minu[0]) - (i * _delta[0])) / _delta[0]; }\n\n    if (_delta[1] != 0.0) { jwgt = ((cCoords[1] - _minu[1]) - (j * _delta[1])) / _delta[1]; }\n\n    if (GetGeometryDim() == 3) {\n        if (_delta[2] != 0.0) { kwgt = ((cCoords[2] - _minu[2]) - (k * _delta[2])) / _delta[2]; }\n    }\n\n    if (iwgt > 0.5) i++;\n    if (jwgt > 0.5) j++;\n\n    if (GetNumDimensions() == 3 && kwgt > 0.5) k++;\n\n\n    return (AccessIJK(i, j, k));\n}\n\nfloat RegularGrid::GetValueLinear(const CoordType &coords) const\n{\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    float mv = GetMissingValue();\n    if (!InsideGrid(cCoords)) return (mv);\n\n    size_t i = 0;\n    size_t j = 0;\n    size_t k = 0;\n\n    if (_delta[0] != 0.0) { i = (size_t)floor((cCoords[0] - _minu[0]) / _delta[0]); }\n    if (_delta[1] != 0.0) { j = (size_t)floor((cCoords[1] - _minu[1]) / _delta[1]); }\n    if (_delta[2] != 0.0) { k = (size_t)floor((cCoords[2] - _minu[2]) / _delta[2]); }\n\n    auto dims = GetDimensions();\n    VAssert(i < dims[0]);\n    VAssert(j < dims[1]);\n    VAssert(k < dims[2]);\n\n    double xwgt = 0.0;\n    double ywgt = 0.0;\n    double zwgt = 0.0;\n\n    if (_delta[0] != 0.0) { xwgt = 1.0 - (((cCoords[0] - _minu[0]) - (i * _delta[0])) / _delta[0]); }\n    if (_delta[1] != 0.0) { ywgt = 1.0 - (((cCoords[1] - _minu[1]) - (j * _delta[1])) / _delta[1]); }\n    if (_delta[2] != 0.0) { zwgt = 1.0 - (((cCoords[2] - _minu[2]) - (k * _delta[2])) / _delta[2]); }\n\n    return (TrilinearInterpolate(i, j, k, xwgt, ywgt, zwgt));\n}\n\nvoid RegularGrid::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const\n{\n    minu = _minu;\n    maxu = _maxu;\n}\n\nvoid RegularGrid::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const\n{\n    DimsType cMin;\n    ClampIndex(min, cMin);\n\n    DimsType cMax;\n    ClampIndex(max, cMax);\n\n    GetUserCoordinates(cMin, minu);\n    GetUserCoordinates(cMax, maxu);\n}\n\nvoid RegularGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const\n{\n    coords = {0.0, 0.0, 0.0};\n\n    DimsType cIndices;\n    ClampIndex(indices, cIndices);\n\n    auto dims = GetDimensions();\n\n    for (int i = 0; i < dims.size(); i++) {\n        size_t index = cIndices[i];\n        VAssert(dims[i] > 0);\n\n        if (index >= dims[i]) { index = dims[i] - 1; }\n\n        coords[i] = cIndices[i] * _delta[i] + _minu[i];\n    }\n}\n\nbool RegularGrid::GetIndicesCell(const CoordType &coords, DimsType &indices) const\n{\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    auto dims = GetDimensions();\n\n    vector<double> wgts;\n\n    VAssert(GetGeometryDim() <= 3);\n    for (int i = 0; i < GetGeometryDim(); i++) {\n        VAssert(dims[i] > 0);\n        if (cCoords[i] < _minu[i] || cCoords[i] > _maxu[i]) { return (false); }\n\n        if (_delta[i] != 0.0) {\n            indices[i] = (size_t)floor((cCoords[i] - _minu[i]) / _delta[i]);\n\n            // Edge case\n            //\n            if (indices[i] == dims[i] - 1) indices[i]--;\n        }\n\n        VAssert(indices[i] < dims[i] - 1);\n    }\n\n    return (true);\n}\n\nbool RegularGrid::InsideGrid(const CoordType &coords) const\n{\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    VAssert(GetGeometryDim() <= 3);\n    for (int i = 0; i < GetGeometryDim(); i++) {\n        if (cCoords[i] < _minu[i]) return (false);\n\n        if (cCoords[i] > _maxu[i]) return (false);\n    }\n\n    return (true);\n}\n\nRegularGrid::ConstCoordItrRG::ConstCoordItrRG(const RegularGrid *rg, bool begin) : ConstCoordItrAbstract()\n{\n    _dims = rg->GetDimensions();\n    _delta = rg->_delta;\n    _minu = rg->_minu;\n    _coords = rg->_minu;\n    _index = {0, 0, 0};\n\n\n    if (!begin) { _index = {0, 0, _dims[_dims.size() - 1]}; }\n}\n\nRegularGrid::ConstCoordItrRG::ConstCoordItrRG(const ConstCoordItrRG &rhs) : ConstCoordItrAbstract()\n{\n    _index = rhs._index;\n    _dims = rhs._dims;\n    _minu = rhs._minu;\n    _delta = rhs._delta;\n    _coords = rhs._coords;\n}\n\nRegularGrid::ConstCoordItrRG::ConstCoordItrRG() : ConstCoordItrAbstract()\n{\n    _index = {0, 0, 0};\n    _dims = {1, 1, 1};\n    _minu = {0.0, 0.0, 0.0};\n    _delta = {0.0, 0.0, 0.0};\n    _coords = {0.0, 0.0, 0.0};\n}\n\nvoid RegularGrid::ConstCoordItrRG::next()\n{\n    _index[0]++;\n    _coords[0] += _delta[0];\n    if (_index[0] < _dims[0]) { return; }\n\n    _index[0] = 0;\n    _coords[0] = _minu[0];\n    _index[1]++;\n    _coords[1] += _delta[1];\n\n    if (_index[1] < _dims[1]) { return; }\n\n    _index[1] = 0;\n    _coords[1] = _minu[1];\n    _index[2]++;\n    _coords[2] += _delta[2];\n\n    if (_index[2] < _dims[2]) { return; }\n\n    _index[2] = _dims[2];    // last index;\n}\n\nvoid RegularGrid::ConstCoordItrRG::next(const long &offset)\n{\n    long maxIndexL = Wasp::VProduct(_dims.data(), _dims.size()) - 1;\n    long newIndexL = Wasp::LinearizeCoords(_index.data(), _dims.data(), _dims.size()) + offset;\n    if (newIndexL < 0) { newIndexL = 0; }\n    if (newIndexL > maxIndexL) {\n        _index = {0, 0, _dims[_dims.size() - 1]};\n        return;\n    }\n\n    Wasp::VectorizeCoords(newIndexL, _dims.data(), _index.data(), _dims.size());\n\n    for (int i = 0; i < _dims.size(); i++) { _coords[i] = _index[i] * _delta[i] + _minu[i]; }\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const RegularGrid &rg)\n{\n    o << \"RegularGrid \" << endl;\n    o << \" Min coord \";\n    for (int i = 0; i < rg._minu.size(); i++) { o << rg._minu[i] << \" \"; }\n    o << endl;\n\n    o << \" Max coord \";\n    for (int i = 0; i < rg._maxu.size(); i++) { o << rg._maxu[i] << \" \"; }\n    o << endl;\n\n    o << (const StructuredGrid &)rg;\n\n    return o;\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/StretchedGrid.cpp",
    "content": "#include <stdio.h>\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <cfloat>\n#include <vapor/utils.h>\n#include <vapor/StretchedGrid.h>\n#include <vapor/KDTreeRG.h>\n#include <vapor/vizutil.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nvoid StretchedGrid::_stretchedGrid(const vector<double> &xcoords, const vector<double> &ycoords, const vector<double> &zcoords)\n{\n    VAssert(xcoords.size() != 0);\n    VAssert(ycoords.size() != 0);\n\n    _xcoords.clear();\n    _ycoords.clear();\n    _zcoords.clear();\n    _xcoords = xcoords;\n    _ycoords = ycoords;\n    _zcoords = zcoords;\n\n    // Get the user extents now. Do this only once.\n    //\n    GetUserExtentsHelper(_minu, _maxu);\n}\n\nStretchedGrid::StretchedGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks, const vector<double> &xcoords, const vector<double> &ycoords, const vector<double> &zcoords)\n: StructuredGrid(dims, bs, blks)\n{\n    _stretchedGrid(xcoords, ycoords, zcoords);\n}\n\nStretchedGrid::StretchedGrid(const vector<size_t> &dims, const vector<size_t> &bs, const vector<float *> &blks, const vector<double> &xcoords, const vector<double> &ycoords,\n                             const vector<double> &zcoords)\n: StructuredGrid(dims, bs, blks)\n{\n    VAssert(bs.size() == dims.size());\n    VAssert(bs.size() >= 1 && bs.size() <= 3);\n\n    _stretchedGrid(xcoords, ycoords, zcoords);\n}\n\nsize_t StretchedGrid::GetGeometryDim() const { return (_zcoords.size() == 0 ? 2 : 3); }\n\nDimsType StretchedGrid::GetCoordDimensions(size_t dim) const\n{\n    DimsType dims = {1, 1, 1};\n\n    if (dim < 3) { dims[0] = GetDimensions()[dim]; }\n\n    return (dims);\n}\n\nvoid StretchedGrid::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const\n{\n    DimsType cMin = {0,0,0};\n    ClampIndex(min, cMin);\n\n    DimsType cMax = {0,0,0};\n    ClampIndex(max, cMax);\n\n    for (int i = 0; i < GetNodeDimensions().size(); i++) { VAssert(cMin[i] <= cMax[i]); }\n\n    for (int i = 0; i < 3; i++) {\n        minu[i] = 0.0;\n        maxu[i] = 0.0;\n    }\n\n    minu[0] = _xcoords[cMin[0]];\n    maxu[0] = _xcoords[cMax[0]];\n    if (minu[0] > maxu[0]) std::swap(minu[0], maxu[0]);\n\n    minu[1] = _ycoords[cMin[1]];\n    maxu[1] = _ycoords[cMax[1]];\n    if (minu[1] > maxu[1]) std::swap(minu[1], maxu[1]);\n\n    // We're done if 2D grid\n    //\n    if (GetGeometryDim() == 2) return;\n\n    minu[2] = _zcoords[cMin[2]];\n    maxu[2] = _zcoords[cMax[2]];\n    if (minu[2] > maxu[2]) std::swap(minu[2], maxu[2]);\n}\n\nvoid StretchedGrid::GetUserCoordinates(const DimsType &indices, CoordType &coords) const\n{\n    DimsType cIndices;\n    ClampIndex(indices, cIndices);\n\n    coords[0] = _xcoords[cIndices[0]];\n    coords[1] = _ycoords[cIndices[1]];\n\n    if (GetGeometryDim() > 2) { coords[2] = _zcoords[cIndices[2]]; }\n}\n\nbool StretchedGrid::GetIndicesCell(const CoordType &coords, DimsType &indices, double wgts[3]) const\n{\n    // Clamp coordinates on periodic boundaries to grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    double x = cCoords[0];\n    double y = cCoords[1];\n    double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0;\n\n    size_t i, j, k;\n    wgts[0] = 0.0;\n    wgts[1] = 0.0;\n    wgts[2] = 0.0;\n    bool inside = _insideGrid(x, y, z, i, j, k, wgts[0], wgts[1], wgts[2]);\n\n    if (!inside) return (false);\n\n    indices[0] = i;\n    indices[1] = j;\n\n    if (GetGeometryDim() == 2) return (true);\n\n    indices[2] = k;\n\n    return (true);\n}\n\nbool StretchedGrid::InsideGrid(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to reside within the\n    // grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    // Do a quick check to see if the point is completely outside of\n    // the grid bounds.\n    //\n    VAssert(GetGeometryDim() <= 3);\n    for (int i = 0; i < GetGeometryDim(); i++) {\n        if (cCoords[i] < _minu[i] || cCoords[i] > _maxu[i]) return (false);\n    }\n\n    double xwgt, ywgt, zwgt;\n    size_t i, j, k;    // not used\n    double x = cCoords[0];\n    double y = cCoords[1];\n    double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0;\n\n    bool inside = _insideGrid(x, y, z, i, j, k, xwgt, ywgt, zwgt);\n\n    return (inside);\n}\n\nStretchedGrid::ConstCoordItrSG::ConstCoordItrSG(const StretchedGrid *sg, bool begin) : ConstCoordItrAbstract()\n{\n    _sg = sg;\n    _index = {0, 0, 0};\n    _coords = {0.0, 0.0, 0.0};\n    const DimsType &dims = sg->GetDimensions();\n\n    if (!begin) { _index = {0, 0, dims[dims.size() - 1]}; }\n\n    if (_sg->_xcoords.size()) _coords[0] = _sg->_xcoords[0];\n    if (_sg->_ycoords.size()) _coords[1] = _sg->_ycoords[0];\n    if (_sg->_zcoords.size()) _coords[2] = _sg->_zcoords[0];\n}\n\nStretchedGrid::ConstCoordItrSG::ConstCoordItrSG(const ConstCoordItrSG &rhs) : ConstCoordItrAbstract()\n{\n    _sg = rhs._sg;\n    _index = rhs._index;\n    _coords = rhs._coords;\n}\n\nStretchedGrid::ConstCoordItrSG::ConstCoordItrSG() : ConstCoordItrAbstract()\n{\n    _sg = NULL;\n    _index = {0, 0, 0};\n    _coords = {0.0, 0.0, 0.0};\n}\n\nvoid StretchedGrid::ConstCoordItrSG::next()\n{\n    auto dims = _sg->GetDimensions();\n\n    _index[0]++;\n\n    if (_index[0] < dims[0]) {\n        _coords[0] = _sg->_xcoords[_index[0]];\n        _coords[1] = _sg->_ycoords[_index[1]];\n        return;\n    }\n\n    _index[0] = 0;\n    _index[1]++;\n\n    if (_index[1] < dims[1]) {\n        _coords[0] = _sg->_xcoords[_index[0]];\n        _coords[1] = _sg->_ycoords[_index[1]];\n        return;\n    }\n\n    _index[1] = 0;\n    _index[2]++;\n    if (_index[2] < dims[2]) {\n        _coords[0] = _sg->_xcoords[_index[0]];\n        _coords[1] = _sg->_ycoords[_index[1]];\n        _coords[2] = _sg->_zcoords[_index[2]];\n        return;\n    }\n\n    _index[2] = dims[2];    // last index;\n}\n\nvoid StretchedGrid::ConstCoordItrSG::next(const long &offset)\n{\n    auto dims = _sg->GetDimensions();\n\n    long maxIndexL = Wasp::VProduct(dims.data(), dims.size()) - 1;\n    long newIndexL = Wasp::LinearizeCoords(_index.data(), dims.data(), dims.size()) + offset;\n    if (newIndexL < 0) { newIndexL = 0; }\n    if (newIndexL > maxIndexL) {\n        _index = {0, 0, dims[dims.size() - 1]};\n        return;\n    }\n\n    _index = {0, 0, 0};\n    Wasp::VectorizeCoords(newIndexL, dims.data(), _index.data(), dims.size());\n\n    _coords[0] = _sg->_xcoords[_index[0]];\n    _coords[1] = _sg->_ycoords[_index[1]];\n    _coords[2] = _sg->_zcoords[_index[2]];\n}\n\nfloat StretchedGrid::GetValueNearestNeighbor(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    double wgts[] = {0.0, 0.0, 0.0};\n    size_t i, j, k;\n    double x = cCoords[0];\n    double y = cCoords[1];\n    double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0;\n    bool   inside = _insideGrid(x, y, z, i, j, k, wgts[0], wgts[1], wgts[2]);\n\n    if (wgts[0] < 0.5) i++;\n    if (wgts[1] < 0.5) j++;\n    if (wgts[2] < 0.5) k++;\n\n    if (!inside) return (GetMissingValue());\n\n    return (AccessIJK(i, j, k));\n}\n\nfloat StretchedGrid::GetValueLinear(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    // handlese case where grid is 2D. I.e. if 2d then zwgt[0] == 1 &&\n    // zwgt[1] = 0.0\n    //\n    double wgts[] = {0.0, 0.0, 0.0};\n    size_t i, j, k;\n    double x = cCoords[0];\n    double y = cCoords[1];\n    double z = GetGeometryDim() == 3 ? cCoords[2] : 0.0;\n    bool   inside = _insideGrid(x, y, z, i, j, k, wgts[0], wgts[1], wgts[2]);\n\n\n    float mv = GetMissingValue();\n    if (!inside) return (mv);\n\n    return (TrilinearInterpolate(i, j, k, wgts[0], wgts[1], wgts[2]));\n}\n\nvoid StretchedGrid::GetUserExtentsHelper(CoordType &minext, CoordType &maxext) const\n{\n    auto dims = StructuredGrid::GetDimensions();\n\n    DimsType min = {0, 0, 0};\n    DimsType max = {0, 0, 0};\n    for (int i = 0; i < dims.size(); i++) {\n        assert(dims[i] > 0);    // will help debug\n        max[i] = (dims[i] - 1);\n    }\n\n    CoordType minv, maxv;\n    StretchedGrid::GetBoundingBox(min, max, minv, maxv);\n    for (int i = 0; i < min.size(); i++) {\n        minext[i] = minv[i];\n        maxext[i] = maxv[i];\n    }\n}\n\n// Search for a point inside the grid. If the point is inside return true,\n// and provide the weights/coordinates for the point within\n// the XYZ cell containing the point\n// If the point is outside of the\n// grid the values of 'xwgt', 'ywgt', and 'zwgt' are not defined\n//\nbool StretchedGrid::_insideGrid(double x, double y, double z, size_t &i, size_t &j, size_t &k, double &xwgt, double &ywgt, double &zwgt) const\n{\n    xwgt = 0.0;\n    ywgt = 0.0;\n    zwgt = 0.0;\n    i = j = k = 0;\n\n    if (!Wasp::BinarySearchRange(_xcoords, x, i)) return (false);\n\n    if (_xcoords.size() > 1) {\n        xwgt = 1.0 - (x - _xcoords[i]) / (_xcoords[i + 1] - _xcoords[i]);\n    } else {\n        xwgt = 1.0;\n    }\n\n\n    if (!Wasp::BinarySearchRange(_ycoords, y, j)) return (false);\n\n    if (_ycoords.size() > 1) {\n        ywgt = 1.0 - (y - _ycoords[j]) / (_ycoords[j + 1] - _ycoords[j]);\n    } else {\n        ywgt = 1.0;\n    }\n\n    if (GetGeometryDim() == 2) {\n        zwgt = 1.0;\n        return (true);\n    }\n\n    // Now verify that Z coordinate of point is in grid, and find\n    // its interpolation weights if so.\n    //\n    if (!Wasp::BinarySearchRange(_zcoords, z, k)) return (false);\n\n    if (_zcoords.size() > 1) {\n        zwgt = 1.0 - (z - _zcoords[k]) / (_zcoords[k + 1] - _zcoords[k]);\n    } else {\n        zwgt = 1.0;\n    }\n\n    return (true);\n}\n"
  },
  {
    "path": "lib/vdc/StructuredGrid.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include <algorithm>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <time.h>\n#include <glm/glm.hpp>\n\n#ifdef Darwin\n    #include <mach/mach_time.h>\n#endif\n#ifdef _WINDOWS\n    #include \"windows.h\"\n    #include \"Winbase.h\"\n    #include <limits>\n#endif\n\n#include <vapor/utils.h>\n#include <vapor/StructuredGrid.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nvoid StructuredGrid::_structuredGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks)\n{\n    _cellDims = Grid::GetDimensions();\n    for (int i = 0; i < _cellDims.size(); i++) {\n        _cellDims[i]--;\n        if (_cellDims[i] < 1) _cellDims[i] = 1;\n    }\n}\n\nStructuredGrid::StructuredGrid(const DimsType &dims, const DimsType &bs, const vector<float *> &blks) : Grid(dims, bs, blks, GetNumDimensions(dims)) { _structuredGrid(dims, bs, blks); }\n\nStructuredGrid::StructuredGrid(const vector<size_t> &dimsv, const vector<size_t> &bsv, const vector<float *> &blks) : Grid(dimsv, bsv, blks, dimsv.size())\n{\n    DimsType dims = {1, 1, 1};\n    DimsType bs = {1, 1, 1};\n    CopyToArr3(dimsv, dims);\n    CopyToArr3(bsv, bs);\n\n    _structuredGrid(dims, bs, blks);\n}\n\nconst DimsType &StructuredGrid::GetNodeDimensions() const { return GetDimensions(); }\n\nconst size_t StructuredGrid::GetNumNodeDimensions() const { return GetNumDimensions(); }\n\nbool StructuredGrid::GetCellNodes(const DimsType &cindices, vector<DimsType> &nodes) const\n{\n    DimsType cCindices;\n    ClampCellIndex(cindices, cCindices);\n\n    auto dims = GetDimensions();\n\n    // Cells have the same ID's as their first node\n    //\n    // walk counter-clockwise order\n    //\n\n    if (dims[0] > 1 && dims[1] > 1 && dims[2] < 2) {\n        nodes.resize(4);\n        nodes[0][0] = cCindices[0];\n        nodes[0][1] = cCindices[1];\n        nodes[0][2] = 0;\n\n        nodes[1][0] = cCindices[0] + 1;\n        nodes[1][1] = cCindices[1];\n        nodes[1][2] = 0;\n\n        nodes[2][0] = cCindices[0] + 1;\n        nodes[2][1] = cCindices[1] + 1;\n        nodes[2][2] = 0;\n\n        nodes[3][0] = cCindices[0];\n        nodes[3][1] = cCindices[1] + 1;\n        nodes[3][2] = 0;\n\n    } else if (dims[0] > 1 && dims[1] > 1 && dims[2] > 1) {\n        nodes.resize(8);\n        nodes[0][0] = cCindices[0];\n        nodes[0][1] = cCindices[1];\n        nodes[0][2] = cCindices[2];\n\n        nodes[1][0] = cCindices[0] + 1;\n        nodes[1][1] = cCindices[1];\n        nodes[1][2] = cCindices[2];\n\n        nodes[2][0] = cCindices[0] + 1;\n        nodes[2][1] = cCindices[1] + 1;\n        nodes[2][2] = cCindices[2];\n\n        nodes[3][0] = cCindices[0];\n        nodes[3][1] = cCindices[1] + 1;\n        nodes[3][2] = cCindices[2];\n\n        nodes[4][0] = cCindices[0];\n        nodes[4][1] = cCindices[1];\n        nodes[4][2] = cCindices[2] + 1;\n\n        nodes[5][0] = cCindices[0] + 1;\n        nodes[5][1] = cCindices[1];\n        nodes[5][2] = cCindices[2] + 1;\n\n        nodes[6][0] = cCindices[0] + 1;\n        nodes[6][1] = cCindices[1] + 1;\n        nodes[6][2] = cCindices[2] + 1;\n\n        nodes[7][0] = cCindices[0];\n        nodes[7][1] = cCindices[1] + 1;\n        nodes[7][2] = cCindices[2] + 1;\n    }\n\n    // Handle dims[i] == 1\n    //\n    for (int j = 0; j < nodes.size(); j++) {\n        for (int i = 0; i < dims.size(); i++) {\n            if (nodes[j][i] >= dims[i]) { nodes[j][i] -= 1; }\n        }\n    }\n\n    return (true);\n}\n\nbool StructuredGrid::GetCellNeighbors(const DimsType &cindices, std::vector<DimsType> &cells) const\n{\n    cells.clear();\n\n    DimsType cCindices;\n    ClampCellIndex(cindices, cCindices);\n\n    auto dims = GetDimensions();\n    auto ndims = GetNumDimensions();\n\n    VAssert((ndims == 2) && \"3D cells not yet supported\");\n    VAssert(dims[0] > 1 && dims[1] > 1);\n\n    // Cells have the same ID's as their first node\n    //\n    // walk counter-clockwise order\n    //\n    if (ndims == 2) {\n        DimsType indices;\n\n        if (cCindices[1] != 0) {    // below\n            indices = {cCindices[0], cCindices[1] - 1, 0};\n        }\n        cells.push_back(indices);\n\n        if (cCindices[0] != dims[0] - 2) {    // right\n            indices = {cCindices[0] + 1, cCindices[1], 0};\n        }\n        cells.push_back(indices);\n\n        if (cCindices[1] != dims[1] - 2) {    // top\n            indices = {cCindices[0], cCindices[1] + 1, 0};\n        }\n        cells.push_back(indices);\n\n        if (cCindices[0] != 0) {    // left\n            indices = {cCindices[0] - 1, cCindices[1], 0};\n        }\n        cells.push_back(indices);\n    }\n    return (true);\n}\n\nbool StructuredGrid::GetNodeCells(const DimsType &indices, std::vector<DimsType> &cells) const\n{\n    cells.clear();\n\n    auto dims = GetDimensions();\n    auto ndims = GetNumDimensions();\n\n    VAssert((ndims == 2) && \"3D cells not yet supported\");\n    VAssert(dims[0] > 1 && dims[1] > 1);\n\n    // Check if invalid indices\n    //\n    for (int i = 0; i < GetGeometryDim(); i++) {\n        VAssert(dims[i] > 0);\n        if (indices[i] > (dims[i] - 1)) return (false);\n    }\n\n    if (ndims == 2) {\n        DimsType indices;\n\n        if (indices[0] != 0 && indices[1] != 0) {    // below, left\n            indices = {indices[0] - 1, indices[1] - 1, 0};\n            cells.push_back(indices);\n        }\n\n        if (indices[1] != 0) {    // below, right\n            indices = {indices[0], indices[1] - 1, 0};\n            cells.push_back(indices);\n        }\n\n        if (indices[0] != (dims[0] - 1) && indices[1] != (dims[1])) {    // top, right\n            indices = {indices[0], indices[1], 0};\n            cells.push_back(indices);\n        }\n\n        if (indices[0] != 0) {    // top, top\n            indices = {indices[0] - 1, indices[1], 0};\n            cells.push_back(indices);\n        }\n    }\n    return (true);\n}\n\nbool StructuredGrid::GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const\n{\n    const DimsType &dims = GetNodeDimensions();\n\n    if (!GetIndicesCell(minu, min)) return (false);\n    if (!GetIndicesCell(maxu, max)) return (false);\n    for (int i = 0; i < max.size(); i++) {\n        if (max[i] < dims[i] - 1) max[i] += 1;\n    }\n\n    // For curvilinear grids it's possible that minu and maxu components\n    // are swapped\n    //\n    CoordType newMinu, newMaxu;\n    GetUserCoordinates(min.data(), newMinu.data());\n    GetUserCoordinates(max.data(), newMaxu.data());\n\n    for (int i = 0; i < newMinu.size(); i++) {\n        if (newMinu > newMaxu) std::swap(min[i], max[i]);\n    }\n\n    return (true);\n};\n\nvoid StructuredGrid::ClampCoord(const CoordType &coords, CoordType &cCoords) const\n{\n    const vector<bool> &periodic = GetPeriodic();\n\n    size_t n = min(GetGeometryDim(), periodic.size());\n    auto   p = [](bool v) { return (v == true); };\n    if (std::none_of(periodic.begin(), periodic.begin() + n, p)) {\n        cCoords = coords;\n        return;\n    }\n\n    auto dims = GetDimensions();\n\n    CoordType minu, maxu;\n    GetUserExtents(minu, maxu);\n\n    cCoords = coords;\n    VAssert(GetGeometryDim() <= 3);\n    for (int i = 0; i < GetGeometryDim(); i++) {\n        //\n        // Handle coordinates for dimensions of length 1\n        //\n        if (dims[i] == 1) {\n            cCoords[i] = minu[i];\n            continue;\n        }\n\n        if (cCoords[i] < minu[i] && periodic[i]) {\n            while (cCoords[i] < minu[i]) cCoords[i] += maxu[i] - minu[i];\n        }\n        if (cCoords[i] > maxu[i] && periodic[i]) {\n            while (cCoords[i] > maxu[i]) cCoords[i] -= maxu[i] - minu[i];\n        }\n    }\n}\n\nbool StructuredGrid::HasInvertedCoordinateSystemHandiness() const\n{\n    auto ndims = GetNumDimensions();\n\n    if (ndims < 2) return (true);    // Arbitrary\n\n    size_t vi0[] = {0, 0, 0};\n    size_t vi1[] = {1, 0, 0};\n    size_t vi2[] = {0, 1, 0};\n\n    double v0[3], v1[3], v2[3];\n\n    GetUserCoordinates(vi0, v0);\n    GetUserCoordinates(vi1, v1);\n    GetUserCoordinates(vi2, v2);\n\n    glm::vec3 glm_v0(v0[0], v0[1], v0[2]);\n    glm::vec3 glm_v1(v1[0], v1[1], v1[2]);\n    glm::vec3 glm_v2(v2[0], v2[1], v2[2]);\n\n    glm::vec3 c2d = glm::cross(glm_v1 - glm_v0, glm_v2 - glm_v0);\n\n    // CCW if Z component of cross product is positive\n    //\n    if (ndims == 2) return (c2d[2] >= 0.0);\n\n    size_t vi3[] = {0, 0, 1};\n    double v3[3];\n\n    GetUserCoordinates(vi3, v3);\n\n    return (c2d[2] * (v3[2] - v0[2]) >= 0.0);\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const StructuredGrid &sg)\n{\n    o << \"StructuredGrid \" << endl;\n    o << endl;\n\n    o << (const Grid &)sg;\n\n    return o;\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/TODO.txt",
    "content": "DataMgr:\n\tMake Get* methods const by making cache supporting elements mutable\n\nNetCDFCollection:\n\tRemove deprecated staggered grid handling\n\tAdd support for reading subsets of derived variables\n\nVDC:\n\tFile format should store the actual data range of each variable\n\tand DataMgr::GetDataRange should be changed to use this. Otherwise\n\tstatistics used for, e.g. histograms, will be wrong\n\nCurvlinearGrid:\n\tBroken with POP data in /glade/p/DASG/VAPOR/Data/POP/BryanASP/tenth_degree/daily\n\nDC:\n\tperiodicity should be a property of each coordinate variable, not \n\ta data variable property. I.e. each coordinate variable should have\n\ta boolean flag indicating whether it is periodic or not. This would\n\tmake more sense for unstructured grids\n"
  },
  {
    "path": "lib/vdc/UDUnitsClass.cpp",
    "content": "#include <iostream>\n#include <sstream>\n#include <iterator>\n#include <algorithm>\n#include \"vapor/VAssert.h\"\n#ifdef WIN32\n    #include \"vapor/udunits2.h\"\n#else\n    #include <udunits2.h>\n#endif\n#include <vapor/ResourcePath.h>\n#include <vapor/UDUnitsClass.h>\n\nusing namespace VAPoR;\nusing namespace Wasp;\nusing namespace std;\n\nUDUnits::UDUnits()\n{\n    _statmsg[UT_SUCCESS] = \"Success\";\n    _statmsg[UT_BAD_ARG] = \"An argument violates the function's contract\";\n    _statmsg[UT_EXISTS] = \"Unit, prefix, or identifier already exists\";\n    _statmsg[UT_NO_UNIT] = \"No such unit exists\";\n    _statmsg[UT_OS] = \"Operating-system error.\";\n    _statmsg[UT_NOT_SAME_SYSTEM] = \"The units belong to different unit-systems\";\n    _statmsg[UT_MEANINGLESS] = \"The operation on the unit(s) is meaningless\";\n    _statmsg[UT_NO_SECOND] = \"The unit-system doesn't have a unit named \\\"second\\\"\";\n    _statmsg[UT_VISIT_ERROR] = \"An error occurred while visiting a unit\";\n    _statmsg[UT_CANT_FORMAT] = \"A unit can't be formatted in the desired manner\";\n    _statmsg[UT_SYNTAX] = \"string unit representation contains syntax error\";\n    _statmsg[UT_UNKNOWN] = \"string unit representation contains unknown word\";\n    _statmsg[UT_OPEN_ARG] = \"Can't open argument-specified unit database\";\n    _statmsg[UT_OPEN_ENV] = \"Can't open environment-specified unit database\";\n    _statmsg[UT_OPEN_DEFAULT] = \"Can't open installed, default, unit database\";\n    _statmsg[UT_PARSE] = \"Error parsing unit specification\";\n\n    _pressureUnit = NULL;\n    _timeUnit = NULL;\n    _latUnit = NULL;\n    _lonUnit = NULL;\n    _lengthUnit = NULL;\n    _status = (int)UT_SUCCESS;\n    _unitSystem = NULL;\n}\n\nstd::string UDUnits::GetDatabasePath() { return GetSharePath(\"udunits/udunits2.xml\"); }\n\nint UDUnits::Initialize()\n{\n    //\n    // Need to turn off error messages, which go to stderr by default\n    //\n    ut_set_error_message_handler(ut_ignore);\n    string unitstr;\n\n    string path = GetDatabasePath();\n    if (!path.empty()) {\n        _unitSystem = ut_read_xml(path.c_str());\n    } else {\n        MyBase::SetErrMsg(\"Could not find VAPOR installed UDUnits database\");\n        MyBase::SetErrMsg(\"Attempting to fall back to system install\");\n        _unitSystem = ut_read_xml(NULL);\n    }\n\n    if (!_unitSystem) goto UDUnits_Initialize_Error;\n\n    //\n    // We need to be able to determine if a given unit is of a\n    // particular type (e.g. time, pressure, mass, etc). The udunit2\n    // API doesn't support this directly. So we create a 'unit'\n    // of a particular known type, and then later we can query udunit2\n    // to see if it is possible to convert between the known unit type\n    // and a unit of unknown type\n    //\n\n    unitstr = \"Pa\";    // Pascal units of Pressure\n    _pressureUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII);\n    if (!_pressureUnit) goto UDUnits_Initialize_Unit_Error;\n\n    unitstr = \"seconds\";\n    _timeUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII);\n    if (!_timeUnit) goto UDUnits_Initialize_Unit_Error;\n\n    unitstr = \"degrees_north\";\n    _latUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII);\n    if (!_latUnit) goto UDUnits_Initialize_Unit_Error;\n\n    unitstr = \"degrees_east\";\n    _lonUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII);\n    if (!_lonUnit) goto UDUnits_Initialize_Unit_Error;\n\n    unitstr = \"meter\";\n    _lengthUnit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII);\n    if (!_lengthUnit) goto UDUnits_Initialize_Unit_Error;\n\n    return 0;\n\nUDUnits_Initialize_Unit_Error:\n    MyBase::SetErrMsg(\"UDUnits failed to parse unit \\\"%s\\\"\", unitstr.c_str());\nUDUnits_Initialize_Error:\n    _status = (int)ut_get_status();\n    MyBase::SetErrMsg(\"UDUnits failed to initialize\");\n    MyBase::SetErrMsg(\"UDUnits Error: %s\", GetErrMsg().c_str());\n    return -1;\n}\n\nbool UDUnits::AreUnitsConvertible(const ut_unit *unit, string unitstr) const\n{\n    ut_unit *myunit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII);\n    if (!myunit) {\n        ut_set_status(UT_SUCCESS);    // clear error message\n        return (false);\n    }\n\n    bool          status = true;\n    cv_converter *cv = NULL;\n    if (!(cv = ut_get_converter((ut_unit *)unit, myunit))) {\n        status = false;\n        ut_set_status(UT_SUCCESS);\n    }\n\n    if (myunit) ut_free(myunit);\n    if (cv) cv_free(cv);\n    return (status);\n}\n\nbool UDUnits::ValidUnit(string unitstr) const\n{\n    ut_unit *myunit = ut_parse(_unitSystem, unitstr.c_str(), UT_ASCII);\n    if (!myunit) {\n        ut_set_status(UT_SUCCESS);    // clear error message\n        return (false);\n    }\n    return (true);\n}\n\nbool UDUnits::IsPressureUnit(string unitstr) const { return (AreUnitsConvertible(_pressureUnit, unitstr)); }\n\nbool UDUnits::IsTimeUnit(string unitstr) const { return (AreUnitsConvertible(_timeUnit, unitstr)); }\n\nbool UDUnits::IsLatUnit(string unitstr) const\n{\n    bool status = AreUnitsConvertible(_latUnit, unitstr);\n    if (!status) return (false);\n\n    // udunits2 does not distinguish between longitude and latitude, only\n    // whether a unit is a plane angle measure. N.B. the conditional\n    // below is probably all that is needed for this method.\n    //\n    if (!((unitstr.compare(\"degrees_north\") == 0) || (unitstr.compare(\"degree_north\") == 0) || (unitstr.compare(\"degree_N\") == 0) || (unitstr.compare(\"degrees_N\") == 0)\n          || (unitstr.compare(\"degreeN\") == 0) || (unitstr.compare(\"degreesN\") == 0))) {\n        status = false;\n    }\n    return (status);\n}\n\nbool UDUnits::IsLonUnit(string unitstr) const\n{\n    bool status = AreUnitsConvertible(_lonUnit, unitstr);\n    if (!status) return (false);\n\n    // udunits2 does not distinguish between longitude and latitude, only\n    // whether a unit is a plane angle measure. N.B. the conditional\n    // below is probably all that is needed for this method.\n    //\n    if (!((unitstr.compare(\"degrees_east\") == 0) || (unitstr.compare(\"degree_east\") == 0) || (unitstr.compare(\"degree_E\") == 0) || (unitstr.compare(\"degrees_E\") == 0)\n          || (unitstr.compare(\"degreeE\") == 0) || (unitstr.compare(\"degreesE\") == 0))) {\n        status = false;\n    }\n    return (status);\n}\nbool UDUnits::IsLatOrLonUnit(string unitstr) const { return (AreUnitsConvertible(_lonUnit, unitstr) || AreUnitsConvertible(_latUnit, unitstr)); }\n\nbool UDUnits::IsLengthUnit(string unitstr) const { return (AreUnitsConvertible(_lengthUnit, unitstr)); }\n\nbool UDUnits::Convert(const string from, const string to, const float *src, float *dst, size_t n) const\n{\n    ut_unit *fromunit = ut_parse(_unitSystem, from.c_str(), UT_ASCII);\n    if (!fromunit) {\n        ut_set_status(UT_SUCCESS);    // clear error message\n        return (false);\n    }\n\n    ut_unit *tounit = ut_parse(_unitSystem, to.c_str(), UT_ASCII);\n    if (!tounit) {\n        ut_free(fromunit);\n        ut_set_status(UT_SUCCESS);    // clear error message\n        return (false);\n    }\n\n    cv_converter *cv = NULL;\n    cv = ut_get_converter((ut_unit *)fromunit, tounit);\n    if (!cv) {\n        ut_free(tounit);\n        ut_free(fromunit);\n        ut_set_status(UT_SUCCESS);\n        return (false);\n    }\n\n    cv_convert_floats(cv, src, n, dst);\n\n    if (fromunit) ut_free(fromunit);\n    if (tounit) ut_free(tounit);\n    if (cv) cv_free(cv);\n    return (true);\n}\n\nbool UDUnits::Convert(const string from, const string to, const double *src, double *dst, size_t n) const\n{\n    ut_unit *fromunit = ut_parse(_unitSystem, from.c_str(), UT_ASCII);\n    if (!fromunit) {\n        ut_set_status(UT_SUCCESS);    // clear error message\n        return (false);\n    }\n\n    ut_unit *tounit = ut_parse(_unitSystem, to.c_str(), UT_ASCII);\n    if (!tounit) {\n        ut_free(fromunit);\n        ut_set_status(UT_SUCCESS);    // clear error message\n        return (false);\n    }\n\n    cv_converter *cv = NULL;\n    cv = ut_get_converter((ut_unit *)fromunit, tounit);\n    if (!cv) {\n        ut_free(tounit);\n        ut_free(fromunit);\n        ut_set_status(UT_SUCCESS);\n        return (false);\n    }\n\n    cv_convert_doubles(cv, src, n, dst);\n\n    if (fromunit) ut_free(fromunit);\n    if (tounit) ut_free(tounit);\n    if (cv) cv_free(cv);\n    return (true);\n}\n\nvoid UDUnits::DecodeTime(double seconds, int *year, int *month, int *day, int *hour, int *minute, int *second) const\n{\n    double dummy;\n    double second_d;\n    ut_decode_time(seconds, year, month, day, hour, minute, &second_d, &dummy);\n    *second = (int)second_d;\n}\n\ndouble UDUnits::EncodeTime(int year, int month, int day, int hour, int minute, int second) const { return (ut_encode_time(year, month, day, hour, minute, (double)second)); }\n\nstring UDUnits::GetErrMsg() const\n{\n    map<int, string>::const_iterator itr;\n    itr = _statmsg.find(_status);\n    if (itr == _statmsg.end()) return (string(\"UNKNOWN\"));\n\n    return (itr->second);\n}\n\nUDUnits::~UDUnits()\n{\n    if (_pressureUnit) ut_free(_pressureUnit);\n    if (_timeUnit) ut_free(_timeUnit);\n    if (_latUnit) ut_free(_latUnit);\n    if (_lonUnit) ut_free(_lonUnit);\n    if (_lengthUnit) ut_free(_lengthUnit);\n    if (_unitSystem) ut_free_system(_unitSystem);\n}\n"
  },
  {
    "path": "lib/vdc/UnstructuredGrid.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <cassert>\n#include <time.h>\n#ifdef Darwin\n    #include <mach/mach_time.h>\n#endif\n#ifdef _WINDOWS\n    #include \"windows.h\"\n    #include \"Winbase.h\"\n    #include <limits>\n#endif\n\n#include <vapor/utils.h>\n#include <vapor/UnstructuredGrid.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nvoid UnstructuredGrid::_unstructuredGrid(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks,\n                                         size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                                         Location location,    // node,face, edge\n                                         size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset)\n{\n    // vertexDims can be 0 in the case of a single-particle dataset since vapor considers length 1 topological data-dimensions as not contributing to the grids topological dimension\n    VAssert(GetNumDimensions(vertexDims) == 0 || GetNumDimensions(vertexDims) == 1 || GetNumDimensions(vertexDims) == 2);\n    VAssert(GetNumDimensions(vertexDims) == GetNumDimensions(faceDims));\n    VAssert((GetNumDimensions(vertexDims) == GetNumDimensions(edgeDims)) || (GetNumDimensions(edgeDims) == 0));\n\n    // Edge data not supported yet\n    //\n    VAssert(location == NODE || location == CELL);\n\n    _vertexDims = vertexDims;\n    _faceDims = faceDims;\n    _edgeDims = edgeDims;\n    _nDims = GetNumDimensions(vertexDims);\n\n    //\n    // Shallow copy raw pointers\n    //\n    _vertexOnFace = vertexOnFace;\n    _faceOnVertex = faceOnVertex;\n    _faceOnFace = faceOnFace;\n\n    _location = location;\n    _maxVertexPerFace = maxVertexPerFace;\n    _maxFacePerVertex = maxFacePerVertex;\n    _missingID = -1;\n    _boundaryID = -2;\n\n    Grid::SetNodeOffset(nodeOffset);\n    Grid::SetCellOffset(cellOffset);\n}\n\nUnstructuredGrid::UnstructuredGrid(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, size_t topology_dimension,\n                                   const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                                   Location location,    // node,face, edge\n                                   size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset)\n: Grid(location == NODE ? vertexDims : (location == CELL ? faceDims : edgeDims), bs, blks, topology_dimension)\n{\n    _unstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, topology_dimension, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset);\n}\n\nUnstructuredGrid::UnstructuredGrid(const std::vector<size_t> &vertexDimsv, const std::vector<size_t> &faceDimsv, const std::vector<size_t> &edgeDimsv, const std::vector<size_t> &bsv,\n                                   const std::vector<float *> &blks, size_t topology_dimension, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                                   Location location,    // node,face, edge\n                                   size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset)\n: Grid(location == NODE ? vertexDimsv : (location == CELL ? faceDimsv : edgeDimsv), bsv, blks, topology_dimension)\n{\n    DimsType vertexDims = {1, 1, 1};\n    DimsType faceDims = {1, 1, 1};\n    DimsType edgeDims = {1, 1, 1};\n    DimsType bs = {1, 1, 1};\n    CopyToArr3(vertexDimsv, vertexDims);\n    CopyToArr3(faceDimsv, faceDims);\n    CopyToArr3(edgeDimsv, edgeDims);\n    CopyToArr3(bsv, bs);\n\n    _unstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, topology_dimension, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset);\n}\n\n\nconst VAPoR::DimsType &UnstructuredGrid::GetNodeDimensions() const { return (_vertexDims); }\n\n\nconst size_t UnstructuredGrid::GetNumNodeDimensions() const { return _nDims; }\n\n\nbool UnstructuredGrid::GetCellNodes(const DimsType &cindices, vector<DimsType> &nodes) const\n{\n    DimsType cCindices;\n    ClampCellIndex(cindices, cCindices);\n\n    // _vertexOnFace is dimensioned cdims[0] x _maxVertexPerFace\n    //\n    const int *ptr = _vertexOnFace + (_maxVertexPerFace * cCindices[0]);\n    long       offset = GetNodeOffset();\n\n    size_t n = 0;\n    if (GetNumCellDimensions() == 1) {\n        nodes.resize(_maxVertexPerFace);    // ensure sufficient memory\n        for (int i = 0; i < _maxVertexPerFace; i++, ptr++) {\n            if (*ptr == GetMissingID()) break;\n            if (*ptr == GetBoundaryID()) continue;\n            if (*ptr + offset < 0) break;\n\n            nodes[n][0] = *ptr + offset;\n            nodes[n][1] = 0;\n            nodes[n][2] = 0;\n            n++;\n        }\n    } else {                                    // layered case\n        nodes.resize(2 * _maxVertexPerFace);    // ensure sufficient memory\n\n        // Bottom layer\n        //\n        for (int i = 0; i < _maxVertexPerFace; i++, ptr++) {\n            if (*ptr == GetMissingID()) break;\n            if (*ptr == GetBoundaryID()) continue;\n            if (*ptr + offset < 0) break;\n\n            nodes[n][0] = *ptr + offset;\n            nodes[n][1] = cCindices[1];\n            n++;\n        }\n\n        // Top layer is identical to bottom layer accept for the\n        // slowest varying index (the layer index)\n        //\n        int nNodesPerLayer = n;\n        for (int i = 0; i < nNodesPerLayer; i++) {\n            nodes[n][0] = nodes[i][0];\n            nodes[n][1] = nodes[i][1] + 1;\n            n++;\n        }\n    }\n    nodes.resize(n);    // resize to actual count\n    return (true);\n}\n\nbool UnstructuredGrid::GetCellNeighbors(const DimsType &cindices, std::vector<DimsType> &cells) const\n{\n    cells.clear();\n\n    DimsType cCindices = {0, 0, 0};\n    ClampCellIndex(cindices, cCindices);\n\n    const DimsType &cdims = GetCellDimensions();\n\n    // _faceOnFace is dimensioned cdims[0] x _maxVertexPerFace\n    //\n    const int *ptr = _faceOnFace + (_maxVertexPerFace * cCindices[0]);\n    long       offset = GetCellOffset();\n\n    DimsType indices = {0, 0, 0};\n    if (GetNumCellDimensions() == 1) {\n        for (int i = 0; i < _maxVertexPerFace; i++) {\n            if (*ptr == GetMissingID() || *ptr + offset < 0) break;\n\n            if (*ptr != GetBoundaryID()) { indices[0] = *ptr + offset; }\n            cells.push_back(indices);\n        }\n    } else {    // layered case\n\n        for (int i = 0; i < _maxVertexPerFace; i++) {\n            if (*ptr == GetMissingID() || *ptr + offset < 0) break;\n\n            if (*ptr != GetBoundaryID()) {\n                indices[0] = *ptr + offset;\n                indices[1] = cCindices[1];\n            }\n\n            cells.push_back(indices);\n        }\n\n        // layer below\n        //\n        if (cCindices[1] != 0) {\n            DimsType indices = {cCindices[0], cCindices[1], 0};\n            indices[1] = cCindices[1] - 1;\n            cells.push_back(indices);\n        }\n\n        // layer above\n        //\n        if (cCindices[1] != cdims[1] - 1) {\n            DimsType indices = {cCindices[0], cCindices[1], 0};\n            indices[1] = indices[1] + 1;\n            cells.push_back(indices);\n        }\n    }\n\n    return (true);\n}\n\nbool UnstructuredGrid::GetNodeCells(const DimsType &indices, std::vector<DimsType> &cells) const\n{\n    cells.clear();\n\n    VAssert(indices.size() == GetNumDimensions());\n\n    VAssert(0 && \"GetNodeCells() Not supported\");\n    return false;\n}\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Iterators\n//\n/////////////////////////////////////////////////////////////////////////////\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const UnstructuredGrid &ug)\n{\n    o << \"UnstructuredGrid \" << endl;\n    o << \" Node dimensions \";\n    for (int i = 0; i < ug._vertexDims.size(); i++) { o << ug._vertexDims[i] << \" \"; }\n    o << endl;\n\n    o << \" Cell dimensions \";\n    for (int i = 0; i < ug._faceDims.size(); i++) { o << ug._faceDims[i] << \" \"; }\n    o << endl;\n\n    o << \" Edge dimensions \";\n    for (int i = 0; i < ug._edgeDims.size(); i++) { o << ug._edgeDims[i] << \" \"; }\n    o << endl;\n\n    o << \" Max nodes per face \" << ug._maxVertexPerFace << endl;\n    o << \" Max face per node \" << ug._maxFacePerVertex << endl;\n    o << \" Sample location\" << ug._location << endl;\n    o << \" Missing ID\" << ug._missingID << endl;\n    o << \" Boundary ID\" << ug._boundaryID << endl;\n\n    o << (const Grid &)ug;\n\n    return o;\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/UnstructuredGrid2D.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <time.h>\n#ifdef Darwin\n    #include <mach/mach_time.h>\n#endif\n#ifdef _WINDOWS\n    #include \"windows.h\"\n    #include \"Winbase.h\"\n    #include <limits>\n#endif\n\n#include <vapor/utils.h>\n#include <vapor/vizutil.h>\n#include <vapor/UnstructuredGrid2D.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nUnstructuredGrid2D::UnstructuredGrid2D(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, const int *vertexOnFace,\n                                       const int *faceOnVertex, const int *faceOnFace,\n                                       Location location,    // node,face, edge\n                                       size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                                       const UnstructuredGridCoordless &zug, std::shared_ptr<const QuadTreeRectangleP> qtr)\n: UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _xug(xug), _yug(yug),\n  _zug(zug), _qtr(qtr)\n{\n    VAssert(xug.GetDimensions() == GetDimensions());\n    VAssert(yug.GetDimensions() == GetDimensions());\n    VAssert(zug.GetDimensions() == GetDimensions() || zug.GetNumDimensions() == 0);\n\n    VAssert(location == NODE);\n\n    if (!_qtr) { _qtr = _makeQuadTreeRectangle(); }\n}\n\nUnstructuredGrid2D::UnstructuredGrid2D(const std::vector<size_t> &vertexDims, const std::vector<size_t> &faceDims, const std::vector<size_t> &edgeDims, const std::vector<size_t> &bs,\n                                       const std::vector<float *> &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                                       Location location,    // node,face, edge\n                                       size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                                       const UnstructuredGridCoordless &zug, std::shared_ptr<const QuadTreeRectangleP> qtr)\n: UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 2, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _xug(xug), _yug(yug),\n  _zug(zug), _qtr(qtr)\n{\n    VAssert(xug.GetDimensions() == GetDimensions());\n    VAssert(yug.GetDimensions() == GetDimensions());\n    VAssert(zug.GetDimensions() == GetDimensions() || zug.GetNumDimensions() == 0);\n\n    VAssert(location == NODE);\n\n    if (!_qtr) { _qtr = _makeQuadTreeRectangle(); }\n}\n\nDimsType UnstructuredGrid2D::GetCoordDimensions(size_t dim) const\n{\n    DimsType dims = {1, 1, 1};\n\n    if (dim == 0) {\n        dims = _xug.GetDimensions();\n    } else if (dim == 1) {\n        dims = _yug.GetDimensions();\n    } else if (dim == 2) {\n        dims = _zug.GetDimensions();\n    }\n\n    return (dims);\n}\n\nsize_t UnstructuredGrid2D::GetGeometryDim() const { return (_zug.GetNumDimensions() == 0 ? 2 : 3); }\n\nvoid UnstructuredGrid2D::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const\n{\n    float range[2];\n\n    _xug.GetRange(range);\n    minu[0] = range[0];\n    maxu[0] = range[1];\n\n    _yug.GetRange(range);\n    minu[1] = range[0];\n    maxu[1] = range[1];\n\n    if (GetGeometryDim() < 3) return;\n\n    _zug.GetRange(range);\n    minu[2] = range[0];\n    maxu[2] = range[1];\n}\n\nvoid UnstructuredGrid2D::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const\n{\n    DimsType cMin;\n    ClampIndex(min, cMin);\n\n    DimsType cMax;\n    ClampIndex(max, cMax);\n\n    int ncoords = GetGeometryDim();\n    minu = {std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max()};\n    minu = {std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest()};\n\n    auto dims = GetDimensions();\n    auto ndims = GetNumDimensions();\n\n    size_t start = Wasp::LinearizeCoords(cMin.data(), dims.data(), ndims);\n    size_t stop = Wasp::LinearizeCoords(cMax.data(), dims.data(), ndims);\n\n    // Currently only support ++ opererator for ConstCoordItr. So random\n    // access is tricky.\n    //\n    ConstCoordItr itr = ConstCoordBegin();\n    ConstCoordItr enditr = ConstCoordBegin();\n\n    for (size_t i = 0; i < start; i++) ++itr;\n    for (size_t i = 0; i < stop; i++) ++enditr;\n\n    for (; itr != enditr; ++itr) {\n        for (int i = 0; i < ncoords; i++) {\n            if ((*itr)[i] < minu[i]) minu[i] = (*itr)[i];\n            if ((*itr)[i] > maxu[i]) maxu[i] = (*itr)[i];\n        }\n    }\n}\n\nbool UnstructuredGrid2D::GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const\n{\n    VAssert(0 && \"Not implemented\");\n    return (true);\n}\n\nvoid UnstructuredGrid2D::GetUserCoordinates(const DimsType &indices, CoordType &coords) const\n{\n    DimsType cIndices;\n    ClampIndex(indices, cIndices);\n\n    coords[0] = _xug.GetValueAtIndex(cIndices);\n    coords[1] = _yug.GetValueAtIndex(cIndices);\n    if (GetGeometryDim() == 3) { coords[2] = _zug.GetValueAtIndex(cIndices); }\n}\n\nbool UnstructuredGrid2D::GetIndicesCell(const CoordType &coords, DimsType &cindices, std::vector<std::vector<size_t>> &nodes, std::vector<double> &lambdav) const\n{\n    nodes.clear();\n    lambdav.clear();\n\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    std::vector<double> lambda(_maxVertexPerFace);\n    int     nlambda;\n\n    // See if point is inside any cells (faces)\n    //\n    size_t              my_index;\n    std::vector<size_t> my_nodes;\n    bool                status = _insideGridNodeCentered(cCoords, my_index, my_nodes, lambda.data(), nlambda);\n\n    if (status) {\n        cindices[0] = my_index;\n        for (int i = 0; i < nlambda; i++) {\n            lambdav.push_back(lambda[i]);\n            nodes.push_back(vector<size_t>(1, my_nodes[i]));\n        }\n    }\n\n    return (status);\n}\n\nbool UnstructuredGrid2D::InsideGrid(const CoordType &coords) const\n{\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    std::vector<double> lambda(_maxVertexPerFace);\n    int            nlambda;\n    size_t         face;\n    vector<size_t> nodes;\n\n    // See if point is inside any cells (faces)\n    //\n    bool status = _insideGridNodeCentered(cCoords, face, nodes, lambda.data(), nlambda);\n\n    return (status);\n}\n\nfloat UnstructuredGrid2D::GetValueNearestNeighbor(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to reside within the\n    // grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    std::vector<double> lambda(_maxVertexPerFace);\n    int            nlambda;\n    size_t         face;\n    vector<size_t> nodes;\n\n    // See if point is inside any cells (faces)\n    //\n    bool inside = _insideGrid(cCoords, face, nodes, lambda.data(), nlambda);\n\n    if (!inside) {\n        return (GetMissingValue());\n    }\n    VAssert(nodes.size() == nlambda);\n    VAssert(face < GetCellDimensions()[0]);\n\n    int maxindx = 0;\n    for (int i = 1; i < nlambda; i++) {\n        if (lambda[i] > lambda[maxindx]) maxindx = i;\n    }\n\n    float value = AccessIJK(nodes[maxindx], 0, 0);\n\n    return ((float)value);\n}\n\nfloat UnstructuredGrid2D::GetValueLinear(const CoordType &coords) const\n{\n    // Clamp coordinates on periodic boundaries to reside within the\n    // grid extents\n    //\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    std::vector<double> lambda(_maxVertexPerFace);\n    int            nlambda;\n    size_t         face;\n    vector<size_t> nodes;\n\n    // See if point is inside any cells (faces)\n    //\n    bool inside = _insideGrid(cCoords, face, nodes, lambda.data(), nlambda);\n\n    if (!inside) {\n        return (GetMissingValue());\n    }\n\n    VAssert(nodes.size() == nlambda);\n    VAssert(face < GetCellDimensions()[0]);\n\n    double value = 0;\n    float  mv = GetMissingValue();\n    for (int i = 0; i < nodes.size(); i++) {\n        float v = AccessIJK(nodes[i], 0, 0);\n        if (v == mv) {\n            if (lambda[i] != 0.0)\n                return (mv);\n            else\n                v = 0.0;\n        }\n\n        value += v * lambda[i];\n    }\n\n    return ((float)value);\n}\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Iterators\n//\n/////////////////////////////////////////////////////////////////////////////\n\nUnstructuredGrid2D::ConstCoordItrU2D::ConstCoordItrU2D(const UnstructuredGrid2D *ug, bool begin) : ConstCoordItrAbstract()\n{\n    _ncoords = ug->GetGeometryDim();\n    _coords = {0.0, 0.0, 0.0};\n    if (begin) {\n        _xCoordItr = ug->_xug.cbegin();\n        _yCoordItr = ug->_yug.cbegin();\n        _zCoordItr = ug->_zug.cbegin();\n        _coords[0] = *_xCoordItr;\n        _coords[1] = *_yCoordItr;\n        if (_ncoords >= 3) { _coords[2] = *_zCoordItr; }\n    } else {\n        _xCoordItr = ug->_xug.cend();\n        _yCoordItr = ug->_yug.cend();\n        _zCoordItr = ug->_zug.cend();\n    }\n}\n\nUnstructuredGrid2D::ConstCoordItrU2D::ConstCoordItrU2D(const ConstCoordItrU2D &rhs) : ConstCoordItrAbstract()\n{\n    _ncoords = rhs._ncoords;\n    _coords = rhs._coords;\n    _xCoordItr = rhs._xCoordItr;\n    _yCoordItr = rhs._yCoordItr;\n    if (rhs._ncoords >= 3) { _zCoordItr = rhs._zCoordItr; }\n}\n\nUnstructuredGrid2D::ConstCoordItrU2D::ConstCoordItrU2D() : ConstCoordItrAbstract() {}\n\nvoid UnstructuredGrid2D::ConstCoordItrU2D::next()\n{\n    ++_xCoordItr;\n    _coords[0] = *_xCoordItr;\n\n    ++_yCoordItr;\n    _coords[1] = *_yCoordItr;\n    if (_ncoords < 3) return;\n\n    ++_zCoordItr;\n    _coords[2] = *_zCoordItr;\n}\n\nvoid UnstructuredGrid2D::ConstCoordItrU2D::next(const long &offset)\n{\n    _xCoordItr += offset;\n    _yCoordItr += offset;\n\n    _coords[0] = *_xCoordItr;\n    _coords[1] = *_yCoordItr;\n\n    if (_ncoords < 3) return;\n\n    _zCoordItr += offset;\n    _coords[2] = *_zCoordItr;\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const UnstructuredGrid2D &ug)\n{\n    o << \"UnstructuredGrid2D \" << endl;\n    o << (const Grid &)ug;\n\n    return o;\n}\n};    // namespace VAPoR\n\n// Search for a point inside the grid. If the point is inside return true,\n// and provide the Wachspress weights/coordinates for the point within\n// the face containing the point in XY, and the linear\n// interpolation weights/coordinates along Z.\n//\nbool UnstructuredGrid2D::_insideGrid(const CoordType &coords, size_t &face, vector<size_t> &nodes, double *lambda, int &nlambda) const\n{\n    nodes.clear();\n\n    if (_location == NODE) {\n        return (_insideGridNodeCentered(coords, face, nodes, lambda, nlambda));\n    } else {\n        return (_insideGridFaceCentered(coords, face, nodes, lambda, nlambda));\n    }\n}\n\nbool UnstructuredGrid2D::_insideGridFaceCentered(const CoordType &coords, size_t &face, vector<size_t> &nodes, double *lambda, int &nlambda) const\n{\n    VAssert(0 && \"Not supported\");\n    return false;\n}\n\nbool UnstructuredGrid2D::_insideGridNodeCentered(const CoordType &coords, size_t &face_index, vector<size_t> &nodes, double *lambda, int &nlambda) const\n{\n    nodes.clear();\n\n    double pt[] = {coords[0], coords[1]};\n\n    // Find the indices for the faces that might contain the point\n    //\n    vector<DimsType> face_indices;\n    _qtr->GetPayloadContained(pt[0], pt[1], face_indices);\n\n    for (int i = 0; i < face_indices.size(); i++) {\n        if (_insideFace(face_indices[i][0], pt, nodes, lambda, nlambda)) {\n            face_index = face_indices[i][0];\n            return (true);\n        }\n    }\n\n    return (false);\n}\n\nbool UnstructuredGrid2D::_insideFace(size_t face, double pt[2], vector<size_t> &node_indices, double *lambda, int &nlambda) const\n{\n    node_indices.clear();\n    nlambda = 0;\n\n    double *verts = new double[_maxVertexPerFace * 2];\n\n    const int *ptr = _vertexOnFace + (face * _maxVertexPerFace);\n    long       offset = GetNodeOffset();\n\n    for (int i = 0; i < _maxVertexPerFace; i++) {\n        if (*ptr == GetMissingID()) break;\n\n        long vertex = *ptr + offset;\n        if (vertex < 0) break;\n\n        verts[i * 2 + 0] = _xug.AccessIJK(vertex, 0, 0);\n        verts[i * 2 + 1] = _yug.AccessIJK(vertex, 0, 0);\n        node_indices.push_back(*ptr + offset);\n        ptr++;\n        nlambda++;\n    }\n\n    // Should we test the line case where nlambda == 2?\n    //\n    if (nlambda < 3) {\n        delete[] verts;\n        return (false);\n    }\n\n    if (!Grid::PointInsideBoundingRectangle(pt, verts, nlambda)) {\n        delete[] verts;\n        return (false);\n    }\n\n    bool ret = WachspressCoords2D(verts, pt, nlambda, lambda);\n\n    delete[] verts;\n\n    return ret;\n}\n\nstd::shared_ptr<QuadTreeRectangleP> UnstructuredGrid2D::_makeQuadTreeRectangle() const\n{\n    auto   dims = GetDimensions();\n    size_t reserve_size = dims[0];\n\n    CoordType minu, maxu;\n    GetUserExtents(minu, maxu);\n\n    std::shared_ptr<QuadTreeRectangleP> qtr = std::make_shared<QuadTreeRectangleP>((float)minu[0], (float)minu[1], (float)maxu[0], (float)maxu[1], 12, reserve_size);\n\n    qtr->Insert(this);\n    return (qtr);\n}\n"
  },
  {
    "path": "lib/vdc/UnstructuredGrid3D.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <time.h>\n#ifdef Darwin\n    #include <mach/mach_time.h>\n#endif\n#ifdef _WINDOWS\n    #include \"windows.h\"\n    #include \"Winbase.h\"\n    #include <limits>\n#endif\n\n#include <vapor/utils.h>\n#include <vapor/vizutil.h>\n#include <vapor/UnstructuredGrid3D.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nUnstructuredGrid3D::UnstructuredGrid3D(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks, const int *vertexOnFace,\n                                       const int *faceOnVertex, const int *faceOnFace,\n                                       Location location,    // node,face, edge\n                                       size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                                       const UnstructuredGridCoordless &zug)\n: UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _xug(xug), _yug(yug),\n  _zug(zug)\n{\n    // These can be 0 in the case of a single-particle dataset since vapor considers length 1 topological data-dimensions as not contributing to the grids topological dimension\n    // VAssert(xug.GetNumDimensions() == 1);\n    // VAssert(yug.GetNumDimensions() == 1);\n    // VAssert(zug.GetNumDimensions() == 1);\n\n    VAssert(location == NODE);\n}\n\nUnstructuredGrid3D::UnstructuredGrid3D(const std::vector<size_t> &vertexDims, const std::vector<size_t> &faceDims, const std::vector<size_t> &edgeDims, const std::vector<size_t> &bs,\n                                       const std::vector<float *> &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                                       Location location,    // node,face, edge\n                                       size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug, const UnstructuredGridCoordless &yug,\n                                       const UnstructuredGridCoordless &zug)\n: UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset), _xug(xug), _yug(yug),\n  _zug(zug)\n{\n    // These can be 0 in the case of a single-particle dataset since vapor considers length 1 topological data-dimensions as not contributing to the grids topological dimension\n    // VAssert(xug.GetNumDimensions() == 1);\n    // VAssert(yug.GetNumDimensions() == 1);\n    // VAssert(zug.GetNumDimensions() == 1);\n\n    VAssert(location == NODE);\n}\n\n\nDimsType UnstructuredGrid3D::GetCoordDimensions(size_t dim) const\n{\n    DimsType dims = {1, 1, 1};\n\n    if (dim == 0) {\n        dims = _xug.GetDimensions();\n    } else if (dim == 1) {\n        dims = _yug.GetDimensions();\n    } else if (dim == 2) {\n        dims = _zug.GetDimensions();\n    }\n\n    return (dims);\n}\n\n\nsize_t UnstructuredGrid3D::GetGeometryDim() const { return (3); }\n\n\nvoid UnstructuredGrid3D::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const\n{\n    float range[2];\n\n    _xug.GetRange(range);\n    minu[0] = range[0];\n    maxu[0] = range[1];\n\n    _yug.GetRange(range);\n    minu[1] = range[0];\n    maxu[1] = range[1];\n\n    _zug.GetRange(range);\n    minu[2] = range[0];\n    maxu[2] = range[1];\n}\n\n\nvoid UnstructuredGrid3D::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const\n{\n    DimsType cMin;\n    ClampIndex(min, cMin);\n\n    DimsType cMax;\n    ClampIndex(max, cMax);\n\n    float range[2];\n\n    _xug.GetRange(min, max, range);\n    minu[0] = range[0];\n    maxu[0] = range[1];\n\n    _yug.GetRange(min, max, range);\n    minu[1] = range[0];\n    maxu[1] = range[1];\n\n    _zug.GetRange(min, max, range);\n    minu[2] = range[0];\n    maxu[2] = range[1];\n}\n\n\nbool UnstructuredGrid3D::GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const\n{\n    VAssert(0 && \"Not implemented\");\n    return (true);\n}\n\n\nvoid UnstructuredGrid3D::GetUserCoordinates(const DimsType &indices, CoordType &coords) const\n{\n    DimsType cIndices;\n    ClampIndex(indices, cIndices);\n\n    coords[0] = _xug.GetValueAtIndex(cIndices);\n    coords[1] = _yug.GetValueAtIndex(cIndices);\n    coords[2] = _zug.GetValueAtIndex(cIndices);\n}\n\n\nbool UnstructuredGrid3D::GetIndicesCell(const CoordType &coords, DimsType &indices) const\n{\n    vector<size_t> nodes2D;\n    vector<double> lambda;\n    float          zwgt[2];\n\n    return (_insideGrid(coords, indices, nodes2D, lambda, zwgt));\n}\n\n\nbool UnstructuredGrid3D::InsideGrid(const CoordType &coords) const\n{\n    DimsType            indices;\n    std::vector<size_t> nodes2D;\n    vector<double>      lambda;\n    float               zwgt[2];\n\n    return (_insideGrid(coords, indices, nodes2D, lambda, zwgt));\n}\n\n\nbool UnstructuredGrid3D::_insideGrid(const CoordType &coords, DimsType &cindices, std::vector<size_t> &nodes2D, std::vector<double> &lambda, float zwgt[2]) const\n{\n    VAssert(!\"Not implemented\");\n    return false;\n}\n\n\nfloat UnstructuredGrid3D::GetValueNearestNeighbor(const CoordType &coords) const\n{\n    VAssert(!\"Not implemented\");\n    return NAN;\n}\n\n\nfloat UnstructuredGrid3D::GetValueLinear(const CoordType &coords) const\n{\n    VAssert(!\"Not implemented\");\n    return NAN;\n}\n\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Iterators\n//\n/////////////////////////////////////////////////////////////////////////////\n\n\n\nUnstructuredGrid3D::ConstCoordItrU3D::ConstCoordItrU3D(const UnstructuredGrid3D *ug, bool begin) : ConstCoordItrAbstract()\n{\n    _ug = ug;\n    _coords = {0.0, 0.0, 0.0};\n    if (begin) {\n        _xCoordItr = ug->_xug.cbegin();\n        _yCoordItr = ug->_yug.cbegin();\n        _zCoordItr = ug->_zug.cbegin();\n        _coords[0] = *_xCoordItr;\n        _coords[1] = *_yCoordItr;\n        _coords[2] = *_zCoordItr;\n    } else {\n        _xCoordItr = ug->_xug.cend();\n        _yCoordItr = ug->_yug.cend();\n        _zCoordItr = ug->_zug.cend();\n    }\n}\n\n\nUnstructuredGrid3D::ConstCoordItrU3D::ConstCoordItrU3D(const ConstCoordItrU3D &rhs) : ConstCoordItrAbstract()\n{\n    _ug = rhs._ug;\n    _xCoordItr = rhs._xCoordItr;\n    _yCoordItr = rhs._yCoordItr;\n    _zCoordItr = rhs._zCoordItr;\n    _coords = rhs._coords;\n}\n\n\nUnstructuredGrid3D::ConstCoordItrU3D::ConstCoordItrU3D() : ConstCoordItrAbstract() {}\n\n\nvoid UnstructuredGrid3D::ConstCoordItrU3D::next()\n{\n    ++_xCoordItr;\n    ++_yCoordItr;\n    ++_zCoordItr;\n\n    _coords[0] = *_xCoordItr;\n    _coords[1] = *_yCoordItr;\n    _coords[2] = *_zCoordItr;\n}\n\n\nvoid UnstructuredGrid3D::ConstCoordItrU3D::next(const long &offset)\n{\n    VAssert(offset >= 0);\n\n    _xCoordItr += offset;\n    _yCoordItr += offset;\n    _zCoordItr += offset;\n\n    _coords[0] = *_xCoordItr;\n    _coords[1] = *_yCoordItr;\n    _coords[2] = *_zCoordItr;\n}\n\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const UnstructuredGrid3D &ug)\n{\n    o << \"UnstructuredGrid3D \" << endl;\n    o << (const Grid &)ug;\n\n    return o;\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/UnstructuredGridLayered.cpp",
    "content": "#include <iostream>\n#include <vector>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <time.h>\n#ifdef Darwin\n    #include <mach/mach_time.h>\n#endif\n#ifdef _WINDOWS\n    #include \"windows.h\"\n    #include \"Winbase.h\"\n    #include <limits>\n#endif\n\n#include <vapor/utils.h>\n#include <vapor/vizutil.h>\n#include <vapor/UnstructuredGridLayered.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nUnstructuredGridLayered::UnstructuredGridLayered(const DimsType &vertexDims, const DimsType &faceDims, const DimsType &edgeDims, const DimsType &bs, const std::vector<float *> &blks,\n                                                 const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                                                 Location location,    // node,face, edge\n                                                 size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug,\n                                                 const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr<const QuadTreeRectangleP> qtr)\n: UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset),\n  _ug2d(vector<size_t>{vertexDims[0]}, vector<size_t>{faceDims[0]}, edgeDims.size() ? vector<size_t>{edgeDims[0]} : vector<size_t>(), vector<size_t>{bs[0]}, vector<float *>(), vertexOnFace,\n        faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset, xug, yug, UnstructuredGridCoordless(), qtr),\n  _zug(zug)\n{\n    VAssert(xug.GetNumDimensions() == 1);\n    VAssert(yug.GetNumDimensions() == 1);\n    VAssert(zug.GetNumDimensions() == 2);\n\n    VAssert(location == NODE);\n}\n\nUnstructuredGridLayered::UnstructuredGridLayered(const std::vector<size_t> &vertexDims, const std::vector<size_t> &faceDims, const std::vector<size_t> &edgeDims, const std::vector<size_t> &bs,\n                                                 const std::vector<float *> &blks, const int *vertexOnFace, const int *faceOnVertex, const int *faceOnFace,\n                                                 Location location,    // node,face, edge\n                                                 size_t maxVertexPerFace, size_t maxFacePerVertex, long nodeOffset, long cellOffset, const UnstructuredGridCoordless &xug,\n                                                 const UnstructuredGridCoordless &yug, const UnstructuredGridCoordless &zug, std::shared_ptr<const QuadTreeRectangleP> qtr)\n: UnstructuredGrid(vertexDims, faceDims, edgeDims, bs, blks, 3, vertexOnFace, faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset),\n  _ug2d(vector<size_t>{vertexDims[0]}, vector<size_t>{faceDims[0]}, edgeDims.size() ? vector<size_t>{edgeDims[0]} : vector<size_t>(), vector<size_t>{bs[0]}, vector<float *>(), vertexOnFace,\n        faceOnVertex, faceOnFace, location, maxVertexPerFace, maxFacePerVertex, nodeOffset, cellOffset, xug, yug, UnstructuredGridCoordless(), qtr),\n  _zug(zug)\n{\n    VAssert(xug.GetNumDimensions() == 1);\n    VAssert(yug.GetNumDimensions() == 1);\n    VAssert(zug.GetNumDimensions() == 2);\n\n    VAssert(location == NODE);\n}\n\nDimsType UnstructuredGridLayered::GetCoordDimensions(size_t dim) const\n{\n    DimsType dims = {1, 1, 1};\n\n    if (dim == 0) {\n        dims = _ug2d.GetCoordDimensions(dim);\n    } else if (dim == 1) {\n        dims = _ug2d.GetCoordDimensions(dim);\n    } else if (dim == 2) {\n        dims = _zug.GetDimensions();\n    }\n\n    return (dims);\n}\n\nsize_t UnstructuredGridLayered::GetGeometryDim() const { return (3); }\n\nvoid UnstructuredGridLayered::GetUserExtentsHelper(CoordType &minu, CoordType &maxu) const\n{\n    // Get horizontal extents from base class\n    //\n    _ug2d.GetUserExtents(minu, maxu);\n\n    // Now add vertical extents\n    //\n    float range[2];\n    _zug.GetRange(range);\n    minu[2] = range[0];\n    maxu[2] = range[1];\n}\n\nvoid UnstructuredGridLayered::GetBoundingBox(const DimsType &min, const DimsType &max, CoordType &minu, CoordType &maxu) const\n{\n    DimsType cMin;\n    ClampIndex(min, cMin);\n\n    DimsType cMax;\n    ClampIndex(max, cMax);\n\n    _ug2d.GetBoundingBox(cMin, cMax, minu, maxu);\n\n    float range[2];\n    _zug.GetRange(min, max, range);\n    minu[2] = range[0];\n    maxu[2] = range[1];\n}\n\nbool UnstructuredGridLayered::GetEnclosingRegion(const CoordType &minu, const CoordType &maxu, DimsType &min, DimsType &max) const\n{\n    VAssert(0 && \"Not implemented\");\n    return (true);\n}\n\nvoid UnstructuredGridLayered::GetUserCoordinates(const DimsType &indices, CoordType &coords) const\n{\n    DimsType cIndices;\n    ClampIndex(indices, cIndices);\n\n    _ug2d.GetUserCoordinates(cIndices, coords);\n\n    coords[2] = _zug.GetValueAtIndex(cIndices);\n}\n\nbool UnstructuredGridLayered::_insideGrid(const CoordType &coords, DimsType &cindices, std::vector<size_t> &nodes2D, std::vector<double> &lambda, float zwgt[2]) const\n{\n    VAssert(_location == NODE);\n\n    nodes2D.clear();\n    lambda.clear();\n\n    CoordType cCoords;\n    ClampCoord(coords, cCoords);\n\n    // Find the 2D horizontal cell containing the X,Y coordinates\n    //\n    std::vector<std::vector<size_t>> nodes;\n\n    bool status = _ug2d.GetIndicesCell(cCoords, cindices, nodes, lambda);\n    if (!status) return (status);\n\n    VAssert(lambda.size() == nodes.size());\n    for (int i = 0; i < nodes.size(); i++) { nodes2D.push_back(nodes[i][0]); }\n\n    // Find k index of cell containing z\n    //\n    vector<double> zcoords;\n\n    size_t nz = GetDimensions()[1];\n    for (int kk = 0; kk < nz; kk++) {\n        float z = 0.0;\n        for (int i = 0; i < lambda.size(); i++) { z += _zug.AccessIJK(nodes2D[i], kk) * lambda[i]; }\n\n        zcoords.push_back(z);\n    }\n\n    size_t k;\n    if (!Wasp::BinarySearchRange(zcoords, cCoords[2], k)) return (false);\n\n    VAssert(k >= 0 && k < nz);\n    cindices[1] = k;\n\n    float z = cCoords[2];\n    zwgt[0] = 1.0 - (z - zcoords[k]) / (zcoords[k + 1] - zcoords[k]);\n    zwgt[1] = 1.0 - zwgt[0];\n\n    return (true);\n}\n\nbool UnstructuredGridLayered::GetIndicesCell(const CoordType &coords, DimsType &indices) const\n{\n    vector<size_t> nodes2D;\n    vector<double> lambda;\n    float          zwgt[2];\n\n    return (_insideGrid(coords, indices, nodes2D, lambda, zwgt));\n}\n\nbool UnstructuredGridLayered::InsideGrid(const CoordType &coords) const\n{\n    DimsType            indices;\n    std::vector<size_t> nodes2D;\n    vector<double>      lambda;\n    float               zwgt[2];\n\n    return (_insideGrid(coords, indices, nodes2D, lambda, zwgt));\n}\n\nfloat UnstructuredGridLayered::GetValueNearestNeighbor(const CoordType &coords) const\n{\n    DimsType            indices;\n    std::vector<size_t> nodes2D;\n    vector<double>      lambda;\n    float               zwgt[2];\n\n    bool inside = _insideGrid(coords, indices, nodes2D, lambda, zwgt);\n    if (!inside) return (GetMissingValue());\n\n    // Find nearest node in XY plane (the curvilinear part of grid)\n    // The nearest node will have largest lambda resampling value.\n    //\n    float max_lambda = 0.0;\n    int   max_nodes2d_index = 0;\n    for (int i = 0; i < lambda.size(); i++) {\n        if (lambda[i] > max_lambda) {\n            max_lambda = lambda[i];\n            max_nodes2d_index = i;\n        }\n    }\n\n    // Now find out which node is closest along vertical axis. We rely on\n    // the Cell index returned in 'indices' being identical to the node ID\n    // along the vertical axis ('cause its a layered grid)\n    //\n    int max_vert_id = indices[1];\n    if (zwgt[1] > zwgt[0]) { max_vert_id += 1; }\n\n    return (AccessIJK(nodes2D[max_nodes2d_index], max_vert_id));\n}\n\nfloat UnstructuredGridLayered::GetValueLinear(const CoordType &coords) const\n{\n    DimsType            indices;\n    std::vector<size_t> nodes2D;\n    vector<double>      lambda;\n    float               zwgt[2];\n\n    bool inside = _insideGrid(coords, indices, nodes2D, lambda, zwgt);\n    if (!inside) return (GetMissingValue());\n\n    // Interpolate value inside bottom face\n    //\n    float mv = GetMissingValue();\n\n    float  z0 = 0.0;\n    size_t k0 = indices[1];\n    for (size_t i = 0; i < lambda.size(); i++) {\n        float v = AccessIJK(nodes2D[i], k0, 0);\n        if (v == mv) {\n            if (lambda[i] != 0.0) {\n                z0 = mv;\n                break;\n            } else\n                v = 0.0;\n        }\n\n        z0 += v * lambda[i];\n    }\n\n    if (z0 == mv) return (mv);\n\n    size_t k1 = k0 + 1;\n    if (k1 >= GetDimensions()[1] || zwgt[1] == 0.0) return (z0);\n\n    // Interpolate value inside top face\n    //\n    float z1 = 0.0;\n    for (int i = 0; i < lambda.size(); i++) {\n        float v = AccessIJK(nodes2D[i], k1, 0);\n        if (v == mv) {\n            if (lambda[i] != 0.0) {\n                z1 = mv;\n                break;\n            } else\n                v = 0.0;\n        }\n\n        z1 += v * lambda[i];\n    }\n\n    if (z1 == mv) return (mv);\n\n    return (z0 * zwgt[0] + z1 * zwgt[1]);\n}\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Iterators\n//\n/////////////////////////////////////////////////////////////////////////////\n\nUnstructuredGridLayered::ConstCoordItrULayered::ConstCoordItrULayered(const UnstructuredGridLayered *ug, bool begin) : ConstCoordItrAbstract()\n{\n    _ug = ug;\n    _coords = {0.0, 0.0, 0.0};\n    _nElements2D = ug->GetDimensions()[0];\n    if (begin) {\n        _itr2D = ug->_ug2d.ConstCoordBegin();\n        _zCoordItr = ug->_zug.cbegin();\n        _index2D = 0;\n        _coords[0] = (*_itr2D)[0];\n        _coords[1] = (*_itr2D)[1];\n        _coords[2] = *_zCoordItr;\n    } else {\n        _itr2D = ug->_ug2d.ConstCoordEnd();\n        _zCoordItr = ug->_zug.cend();\n        _index2D = _nElements2D - 1;\n    }\n}\n\nUnstructuredGridLayered::ConstCoordItrULayered::ConstCoordItrULayered(const ConstCoordItrULayered &rhs) : ConstCoordItrAbstract()\n{\n    _ug = rhs._ug;\n    _itr2D = rhs._itr2D;\n    _zCoordItr = rhs._zCoordItr;\n    _coords = rhs._coords;\n    _nElements2D = rhs._nElements2D;\n    _index2D = rhs._index2D;\n}\n\nUnstructuredGridLayered::ConstCoordItrULayered::ConstCoordItrULayered() : ConstCoordItrAbstract() {}\n\nvoid UnstructuredGridLayered::ConstCoordItrULayered::next()\n{\n    ++_index2D;\n\n    ++_itr2D;\n\n    // Check for overflow\n    //\n    if (_index2D == _nElements2D) {\n        _itr2D = _ug->_ug2d.ConstCoordBegin();\n        _index2D = 0;\n    }\n\n    _coords[0] = (*_itr2D)[0];\n    _coords[1] = (*_itr2D)[1];\n\n    ++_zCoordItr;\n    _coords[2] = *_zCoordItr;\n}\n\nvoid UnstructuredGridLayered::ConstCoordItrULayered::next(const long &offset)\n{\n    VAssert(offset >= 0);\n\n    long offset2D = (_index2D + offset) % _nElements2D;\n\n    _itr2D += (offset2D - _index2D);\n    _index2D += (offset2D - _index2D);\n\n    _coords[0] = (*_itr2D)[0];\n    _coords[1] = (*_itr2D)[1];\n\n    _zCoordItr += offset;\n    _coords[2] = *_zCoordItr;\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const UnstructuredGridLayered &ug)\n{\n    o << \"UnstructuredGridLayered \" << endl;\n    o << (const Grid &)ug;\n\n    return o;\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/VDC.cpp",
    "content": "#include \"vapor/VAssert.h\"\n#include <sstream>\n#include <cfloat>\n#include \"vapor/VDC.h\"\n\nusing namespace VAPoR;\n\nnamespace {\n\n// Product of elements in a vector\n//\nsize_t vproduct(vector<size_t> a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n\nvoid _compute_bs(size_t ndims, const vector<size_t> &default_bs, vector<size_t> &bs)\n{\n    bs.clear();\n\n    // If the default block size exists for a dimension use it.\n    // Otherwise set the bs to 1\n    //\n    for (int i = 0; i < ndims; i++) {\n        if (i < default_bs.size()) {\n            bs.push_back(default_bs[i]);\n        } else {\n            bs.push_back(1);    // slowest varying block size can be one\n        }\n    }\n\n    VAssert(ndims == bs.size());\n}\n\nvoid _compute_periodic(const vector<string> &dim_names, const vector<bool> &default_periodic, vector<bool> &periodic)\n{\n    // If the default periodicity exists for a dimension use it.\n    // Otherwise set the periodicity to false. No periodicity for\n    // time dimensions\n    //\n    for (int i = 0; i < dim_names.size(); i++) {\n        if (i < default_periodic.size()) {\n            periodic.push_back(default_periodic[i]);\n        } else {\n            periodic.push_back(false);\n        }\n    }\n}\n\nstring make_mesh_name(const vector<string> &dim_names)\n{\n    string name;\n    for (int i = 0; i < dim_names.size(); i++) {\n        name += dim_names[i];\n        if (i < (dim_names.size() - 1)) name += \"X\";\n    }\n    return (name);\n}\n\n};    // namespace\n\nVDC::VDC()\n{\n    _master_path.clear();\n    _mode = R;\n    _defineMode = false;\n\n    _bs.clear();\n    for (int i = 0; i < 3; i++) _bs.push_back(64);\n\n    _wname = \"bior4.4\";\n\n    _cratios.clear();\n    _cratios.push_back(500);\n    _cratios.push_back(100);\n    _cratios.push_back(10);\n    _cratios.push_back(1);\n\n    _periodic.clear();\n    for (int i = 0; i < 3; i++) _periodic.push_back(false);\n\n    _coordVars.clear();\n    _dataVars.clear();\n    _dimsMap.clear();\n    _atts.clear();\n    _newUniformVars.clear();\n    _proj4StringOption.clear();\n}\n\nint VDC::initialize(const vector<string> &paths, const vector<string> &options, AccessMode mode, vector<size_t> bs)\n{\n    _proj4StringOption.clear();\n    if (options.size() >= 2) {\n        if (options[0] == \"-proj4\") { _proj4StringOption = options[1]; }\n    }\n\n    if (!paths.size()) {\n        SetErrMsg(\"Invalid argument\");\n        return (-1);\n    }\n    _master_path = paths[0];\n    if (mode == R) {\n        _defineMode = false;\n    } else {\n        _defineMode = true;\n    }\n    _mode = mode;\n\n    if (mode == W) {\n        _bs = bs;\n        while (_bs.size() > 3) _bs.pop_back();\n        while (_bs.size() < 3) _bs.push_back(1);\n    }\n\n    int rc = _udunits.Initialize();\n    if (rc < 0) {\n        SetErrMsg(\"Failed to initialize udunits2 library : %s\", _udunits.GetErrMsg().c_str());\n        return (-1);\n    }\n\n    if (mode == R || mode == A) { return (_ReadMasterMeta()); }\n    return (0);\n}\n\nint VDC::SetCompressionBlock(string wname, vector<size_t> cratios)\n{\n    if (!cratios.size()) cratios.push_back(1);\n\n    sort(cratios.begin(), cratios.end());\n    reverse(cratios.begin(), cratios.end());\n\n    if (!_ValidCompressionBlock(_bs, wname, cratios)) {\n        SetErrMsg(\"Invalid compression settings\");\n        return (-1);\n    }\n\n    _wname = wname;\n    _cratios = cratios;\n\n    return (0);\n}\n\nvoid VDC::GetCompressionBlock(vector<size_t> &bs, string &wname, vector<size_t> &cratios) const\n{\n    bs = _bs;\n    wname = _wname;\n    cratios = _cratios;\n}\n\nint VDC::DefineDimension(string name, size_t length)\n{\n    if (!_defineMode) {\n        SetErrMsg(\"Not in define mode\");\n        return (-1);\n    }\n\n    // Can't redefine existing dimension names in append mode\n    //\n    if (_mode == A) {\n        if (_dimsMap.find(name) != _dimsMap.end()) {\n            SetErrMsg(\"Dimension name %s already defined\", name.c_str());\n            return (-1);\n        }\n    }\n\n    if (!_ValidDefineDimension(name, length)) {\n        SetErrMsg(\"Invalid definition for variable %s\", name.c_str());\n        return (-1);\n    }\n\n    Dimension dimension(name, length);\n\n    //\n    // _dimsMap contains all defined dimensions for the VDC\n    //\n    _dimsMap[name] = dimension;\n\n    return (0);\n}\n\nint VDC::DefineDimension(string name, size_t length, int axis)\n{\n    VAssert(axis >= 0 && axis <= 3);\n\n    int rc = DefineDimension(name, length);\n\n    if (rc < 0) return (rc);\n\n    // Now define a 1D coordinate variable\n    //\n    vector<string> sdimnames;\n    string         time_dim_name;\n    if (axis == 3) {\n        time_dim_name = name;\n    } else {\n        sdimnames.push_back(name);\n    }\n\n    return (DefineCoordVarUniform(name, sdimnames, time_dim_name, \"\", axis, XType::FLOAT, false));\n}\n\nbool VDC::getDimension(string name, Dimension &dimension) const\n{\n    map<string, Dimension>::const_iterator itr = _dimsMap.find(name);\n    if (itr == _dimsMap.end()) return (false);\n\n    dimension = itr->second;\n    return (true);\n}\n\nvector<string> VDC::getDimensionNames() const\n{\n    vector<string>                              dim_names;\n    std::map<string, Dimension>::const_iterator itr = _dimsMap.begin();\n    for (; itr != _dimsMap.end(); ++itr) { dim_names.push_back(itr->first); }\n    return (dim_names);\n}\n\nvector<string> VDC::getMeshNames() const\n{\n    vector<string>                         mesh_names;\n    std::map<string, Mesh>::const_iterator itr = _meshes.begin();\n    for (; itr != _meshes.end(); ++itr) { mesh_names.push_back(itr->first); }\n    return (mesh_names);\n}\n\nbool VDC::getMesh(string mesh_name, DC::Mesh &mesh) const\n{\n    map<string, Mesh>::const_iterator itr = _meshes.find(mesh_name);\n    if (itr == _meshes.end()) return (false);\n\n    mesh = itr->second;\n    return (true);\n}\n\nvector<string> VDC::_GetCoordVarDimNames(const CoordVar &cvar, bool &time_varying) const\n{\n    time_varying = false;\n\n    vector<string> dim_names;\n\n    dim_names = cvar.GetDimNames();\n\n    if (!cvar.GetTimeDimName().empty()) {\n        dim_names.push_back(cvar.GetTimeDimName());\n        time_varying = true;\n    }\n\n    return (dim_names);\n}\n\nvector<string> VDC::_GetDataVarDimNames(const DataVar &dvar, bool &time_varying) const\n{\n    time_varying = false;\n\n    vector<string> dim_names;\n\n    string mesh = dvar.GetMeshName();\n\n    map<string, Mesh>::const_iterator itr = _meshes.find(mesh);\n    VAssert(itr != _meshes.end());\n\n    dim_names = itr->second.GetDimNames();\n\n    // Get time dimension if exists\n    //\n    string time_coord_var = dvar.GetTimeCoordVar();\n    if (time_coord_var.empty()) return (dim_names);\n\n    std::map<string, DC::CoordVar>::const_iterator itr1;\n    itr1 = _coordVars.find(time_coord_var);\n    VAssert(itr1 != _coordVars.end());\n\n    vector<string> dimvec = _GetCoordVarDimNames(itr1->second, time_varying);\n    VAssert(dimvec.size() == 1);\n\n    dim_names.push_back(dimvec[0]);\n\n    return (dim_names);\n}\n\nint VDC::_DefineImplicitCoordVars(vector<string> dim_names, vector<string> coord_vars_in, vector<string> &coord_vars_out)\n{\n    coord_vars_out.clear();\n\n    if (dim_names.size() <= coord_vars_in.size()) {\n        // No need to do anything\n        //\n        coord_vars_out = coord_vars_in;\n        return (0);\n    }\n\n    for (int i = 0; i < dim_names.size(); i++) coord_vars_out.push_back(\"\");\n\n    // figure out which coordinate variables are missing\n    //\n    for (int i = 0; i < coord_vars_in.size(); i++) {\n        string name = coord_vars_in[i];\n\n        map<string, CoordVar>::const_iterator itr = _coordVars.find(name);\n        if (itr == _coordVars.end()) {\n            SetErrMsg(\"Undefined coordinate variable \\\"%s\\\" \", name.c_str());\n            return (-1);\n        }\n\n        int axis = itr->second.GetAxis();\n        VAssert(axis >= 0 && axis <= 3);\n\n        coord_vars_out[axis] = name;\n    }\n\n    // For every coordinate variable that is missing make up a new one\n    //\n    vector<string> new_coord_vars;\n    vector<int>    new_coord_axes;\n    for (int i = 0; i < coord_vars_out.size(); i++) {\n        if (coord_vars_out[i].empty()) {\n            coord_vars_out[i] = dim_names[i];\n\n            // Keep track of the new coordinate variables that we will\n            // create.\n            //\n            new_coord_vars.push_back(coord_vars_out[i]);\n            new_coord_axes.push_back(i);\n        }\n    }\n\n    // Create new, unitless coordinate variables if they don't\n    // already exist\n    //\n    for (int i = 0; i < new_coord_vars.size(); i++) {\n        string name = new_coord_vars[i];\n        int    axis = new_coord_axes[i];\n\n        vector<string> dim_names;\n        string         time_dim_name;\n        if (axis == 3) {\n            time_dim_name = name;\n        } else {\n            dim_names.push_back(name);\n        }\n\n        map<string, CoordVar>::const_iterator itr = _coordVars.find(name);\n        if (itr != _coordVars.end()) continue;\n\n        vector<bool> periodic(1, false);\n        _coordVars[name] = CoordVar(name, \"\", XType::FLOAT, \"\", vector<size_t>(), periodic, dim_names, time_dim_name, axis, false);\n\n        _coordVars[name].SetUniform(true);\n\n        // Keep track of any uniform variables that get defined\n        //\n        _newUniformVars.push_back(name);\n    }\n    return (0);\n}\n\nint VDC::DefineCoordVar(string varname, vector<string> dim_names, string time_dim_name, string units, int axis, XType type, bool compressed)\n{\n    if (!_defineMode) {\n        SetErrMsg(\"Not in define mode\");\n        return (-1);\n    }\n\n    if (_mode == A) {\n        if (_coordVars.find(varname) != _coordVars.end()) {\n            SetErrMsg(\"Variable \\\"%s\\\" already defined\", varname.c_str());\n            return (-1);\n        }\n    }\n\n    if (axis == 3 && units.empty()) units = \"seconds\";\n\n    if (!_ValidDefineCoordVar(varname, dim_names, time_dim_name, units, axis, type, compressed)) { return (-1); }\n\n    vector<bool> periodic;\n    _compute_periodic(dim_names, _periodic, periodic);\n\n    vector<size_t> cratios(1, 1);\n    string         wname;\n    if (compressed) {\n        cratios = _cratios;\n        wname = _wname;\n    }\n\n    // _coordVars contains a table of all the coordinate variables\n    //\n    _coordVars[varname] = CoordVar(varname, units, type, wname, cratios, periodic, dim_names, time_dim_name, axis, false);\n\n    return (0);\n}\n\nint VDC::DefineCoordVarUniform(string varname, vector<string> dim_names, string time_dim_name, string units, int axis, XType type, bool compressed)\n{\n    int rc = VDC::DefineCoordVar(varname, dim_names, time_dim_name, units, axis, type, compressed);\n    if (rc < 0) return (-1);\n\n    VAssert(_coordVars.find(varname) != _coordVars.end());\n\n    _coordVars[varname].SetUniform(true);\n\n    // Keep track of any uniform variables that get defined\n    //\n    _newUniformVars.push_back(varname);\n\n    return (0);\n}\n\nbool VDC::getCoordVarInfo(string varname, DC::CoordVar &cvar) const\n{\n    map<string, CoordVar>::const_iterator itr = _coordVars.find(varname);\n    if (itr == _coordVars.end()) return (false);\n\n    cvar = itr->second;\n    return (true);\n}\n\nbool VDC::getBaseVarInfo(string varname, DC::BaseVar &var) const\n{\n    map<string, CoordVar>::const_iterator itr1 = _coordVars.find(varname);\n    if (itr1 != _coordVars.end()) {\n        var = itr1->second;\n        return (true);\n    }\n\n    map<string, DataVar>::const_iterator itr2 = _dataVars.find(varname);\n    if (itr2 != _dataVars.end()) {\n        var = itr2->second;\n        return (true);\n    }\n    return (false);\n}\n\nvoid VDC::_DefineMesh(string meshname, vector<string> dim_names, vector<string> coord_vars)\n{\n    VAssert(dim_names.size() == coord_vars.size());\n\n    _meshes[meshname] = DC::Mesh(meshname, dim_names, coord_vars);\n}\n\nint VDC::_DefineDataVar(string varname, vector<string> dim_names, vector<string> coord_vars, string units, XType type, bool compressed, bool has_missing, double mv, string maskvar)\n{\n    if (!_defineMode) {\n        SetErrMsg(\"Not in define mode\");\n        return (-1);\n    }\n\n    if (_mode == A) {\n        if (_dataVars.find(varname) != _dataVars.end()) {\n            SetErrMsg(\"Variable \\\"%s\\\" already defined\", varname.c_str());\n            return (-1);\n        }\n    }\n\n    int rc = _DefineImplicitCoordVars(dim_names, coord_vars, coord_vars);\n    if (rc < 0) return (-1);\n\n    if (!_ValidDefineDataVar(varname, dim_names, coord_vars, units, type, compressed, has_missing, maskvar)) { return (-1); }\n\n    //\n    // Dimensions must have previosly been defined\n    //\n    vector<Dimension> dimensions;\n    for (int i = 0; i < dim_names.size(); i++) {\n        Dimension dimension;\n        VDC::getDimension(dim_names[i], dimension);\n        VAssert(!dimension.GetName().empty());\n        dimensions.push_back(dimension);\n    }\n\n    // Check for a time coordinate\n    //\n    string time_coord_var;\n    if (coord_vars.size() > 0) {\n        map<string, CoordVar>::const_iterator itr;\n        itr = _coordVars.find(coord_vars[coord_vars.size() - 1]);\n        if (itr != _coordVars.end() && itr->second.GetAxis() == 3) {\n            time_coord_var = coord_vars[coord_vars.size() - 1];\n            dim_names.pop_back();\n            coord_vars.pop_back();\n        }\n    }\n\n    vector<bool> periodic;\n    _compute_periodic(dim_names, _periodic, periodic);\n\n    vector<size_t> cratios(1, 1);\n    string         wname;\n    if (compressed) {\n        cratios = _cratios;\n        wname = _wname;\n    }\n\n    string meshname = make_mesh_name(dim_names);\n    _DefineMesh(meshname, dim_names, coord_vars);\n\n    if (!maskvar.empty()) {\n        _dataVars[varname] = DataVar(varname, units, type, wname, cratios, periodic, meshname, time_coord_var, DC::Mesh::NODE, mv, maskvar);\n    } else if (has_missing) {\n        _dataVars[varname] = DataVar(varname, units, type, wname, cratios, periodic, meshname, time_coord_var, DC::Mesh::NODE, mv);\n    } else {\n        _dataVars[varname] = DataVar(varname, units, type, wname, cratios, periodic, meshname, time_coord_var, DC::Mesh::NODE);\n    }\n\n    return (0);\n}\n\nint VDC::DefineDataVar(string varname, vector<string> dim_names, vector<string> coord_vars, string units, XType type, bool compressed)\n{\n    return (VDC::_DefineDataVar(varname, dim_names, coord_vars, units, type, compressed, false, 0.0, \"\"));\n}\n\nint VDC::DefineDataVar(string varname, vector<string> dim_names, vector<string> coord_vars, string units, XType type, double mv, string maskvar\n\n)\n{\n    bool compressed = !maskvar.empty();\n    return (VDC::_DefineDataVar(varname, dim_names, coord_vars, units, type, compressed, true, mv, maskvar));\n}\n\nbool VDC::getDataVarInfo(string varname, DC::DataVar &datavar) const\n{\n    map<string, DataVar>::const_iterator itr = _dataVars.find(varname);\n\n    if (itr == _dataVars.end()) return (false);\n\n    datavar = itr->second;\n    return (true);\n}\n\nvector<string> VDC::getDataVarNames() const\n{\n    vector<string> names;\n\n    map<string, DataVar>::const_iterator itr;\n    for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nvector<string> VDC::getCoordVarNames() const\n{\n    vector<string> names;\n\n    map<string, CoordVar>::const_iterator itr;\n    for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) { names.push_back(itr->first); }\n    return (names);\n}\n\nsize_t VDC::getNumRefLevels(string varname) const\n{\n    string wname;\n\n    if (_coordVars.find(varname) != _coordVars.end()) {\n        std::map<string, DC::CoordVar>::const_iterator itr = _coordVars.find(varname);\n        ;\n        if (!itr->second.IsCompressed()) return (1);\n        wname = itr->second.GetWName();\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        std::map<string, DC::DataVar>::const_iterator itr = _dataVars.find(varname);\n        if (!itr->second.IsCompressed()) return (1);\n        ;\n        wname = itr->second.GetWName();\n    } else {\n        // Var doesn't exist. Still return 1\n        return (1);\n    }\n\n    vector<DC::Dimension> mdimensions;\n    bool                  ok = GetVarDimensions(varname, true, mdimensions, -1);\n    if (!ok) return (1);\n\n    // Determine block size\n    //\n    vector<size_t> bs;\n    _compute_bs(mdimensions.size(), _bs, bs);\n\n    size_t nlevels, maxcratio;\n    CompressionInfo(bs, wname, nlevels, maxcratio);\n\n    return (nlevels);\n}\n\nint VDC::PutAtt(string varname, string attname, XType type, const vector<double> &values)\n{\n    Attribute attr(attname, type, values);\n\n    if (varname.empty()) {\n        _atts[attname] = attr;\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        map<string, DataVar>::iterator itr = _dataVars.find(varname);\n        map<string, Attribute>         atts = itr->second.GetAttributes();\n        atts[attname] = attr;\n        itr->second.SetAttributes(atts);\n    } else if (_coordVars.find(varname) != _coordVars.end()) {\n        map<string, CoordVar>::iterator itr = _coordVars.find(varname);\n        map<string, Attribute>          atts = itr->second.GetAttributes();\n        atts[attname] = attr;\n        itr->second.SetAttributes(atts);\n    } else {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n    return (0);\n}\n\nint VDC::PutAtt(string varname, string attname, XType type, const vector<long> &values)\n{\n    Attribute attr(attname, type, values);\n\n    if (varname.empty()) {\n        _atts[attname] = attr;\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        map<string, DataVar>::iterator itr = _dataVars.find(varname);\n        map<string, Attribute>         atts = itr->second.GetAttributes();\n        atts[attname] = attr;\n        itr->second.SetAttributes(atts);\n    } else if (_coordVars.find(varname) != _coordVars.end()) {\n        map<string, CoordVar>::iterator itr = _coordVars.find(varname);\n        map<string, Attribute>          atts = itr->second.GetAttributes();\n        atts[attname] = attr;\n        itr->second.SetAttributes(atts);\n    } else {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n    return (0);\n}\n\nint VDC::PutAtt(string varname, string attname, XType type, const string &values)\n{\n    Attribute attr(attname, type, values);\n\n    if (varname.empty()) {\n        _atts[attname] = attr;\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        map<string, DataVar>::iterator itr = _dataVars.find(varname);\n        map<string, Attribute>         atts = itr->second.GetAttributes();\n        atts[attname] = attr;\n        itr->second.SetAttributes(atts);\n    } else if (_coordVars.find(varname) != _coordVars.end()) {\n        map<string, CoordVar>::iterator itr = _coordVars.find(varname);\n        map<string, Attribute>          atts = itr->second.GetAttributes();\n        atts[attname] = attr;\n        itr->second.SetAttributes(atts);\n    } else {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n    return (0);\n}\n\nbool VDC::getAtt(string varname, string attname, vector<double> &values) const\n{\n    values.clear();\n\n    if (varname.empty() && (_atts.find(attname) != _atts.end())) {\n        map<string, Attribute>::const_iterator itr = _atts.find(attname);\n        VAssert(itr != _atts.end());\n        const Attribute &attr = itr->second;\n        attr.GetValues(values);\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        map<string, DataVar>::const_iterator   itr = _dataVars.find(varname);\n        map<string, Attribute>                 atts = itr->second.GetAttributes();\n        map<string, Attribute>::const_iterator itr1 = atts.find(attname);\n        if (itr1 == atts.end()) { return (false); }\n        const Attribute &attr = itr1->second;\n        attr.GetValues(values);\n\n    } else if (_coordVars.find(varname) != _coordVars.end()) {\n        map<string, CoordVar>::const_iterator  itr = _coordVars.find(varname);\n        map<string, Attribute>                 atts = itr->second.GetAttributes();\n        map<string, Attribute>::const_iterator itr1 = atts.find(attname);\n        if (itr1 == atts.end()) { return (false); }\n        const Attribute &attr = itr1->second;\n        attr.GetValues(values);\n    } else {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (false);\n    }\n    return (true);\n}\n\nbool VDC::getAtt(string varname, string attname, vector<long> &values) const\n{\n    values.clear();\n\n    if (varname.empty() && (_atts.find(attname) != _atts.end())) {\n        map<string, Attribute>::const_iterator itr = _atts.find(attname);\n        VAssert(itr != _atts.end());\n        const Attribute &attr = itr->second;\n        attr.GetValues(values);\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        map<string, DataVar>::const_iterator   itr = _dataVars.find(varname);\n        map<string, Attribute>                 atts = itr->second.GetAttributes();\n        map<string, Attribute>::const_iterator itr1 = atts.find(attname);\n        if (itr1 == atts.end()) { return (false); }\n        const Attribute &attr = itr1->second;\n        attr.GetValues(values);\n\n    } else if (_coordVars.find(varname) != _coordVars.end()) {\n        map<string, CoordVar>::const_iterator  itr = _coordVars.find(varname);\n        map<string, Attribute>                 atts = itr->second.GetAttributes();\n        map<string, Attribute>::const_iterator itr1 = atts.find(attname);\n        if (itr1 == atts.end()) { return (false); }\n        const Attribute &attr = itr1->second;\n        attr.GetValues(values);\n    } else {\n        return (false);\n    }\n    return (true);\n}\n\nbool VDC::getAtt(string varname, string attname, string &values) const\n{\n    values.clear();\n\n    if (varname.empty() && (_atts.find(attname) != _atts.end())) {\n        map<string, Attribute>::const_iterator itr = _atts.find(attname);\n        VAssert(itr != _atts.end());\n        const Attribute &attr = itr->second;\n        attr.GetValues(values);\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        map<string, DataVar>::const_iterator   itr = _dataVars.find(varname);\n        map<string, Attribute>                 atts = itr->second.GetAttributes();\n        map<string, Attribute>::const_iterator itr1 = atts.find(attname);\n        if (itr1 == atts.end()) { return (false); }\n        const Attribute &attr = itr1->second;\n        attr.GetValues(values);\n\n    } else if (_coordVars.find(varname) != _coordVars.end()) {\n        map<string, CoordVar>::const_iterator  itr = _coordVars.find(varname);\n        map<string, Attribute>                 atts = itr->second.GetAttributes();\n        map<string, Attribute>::const_iterator itr1 = atts.find(attname);\n        if (itr1 == atts.end()) { return (false); }\n        const Attribute &attr = itr1->second;\n        attr.GetValues(values);\n    } else {\n        return (false);\n    }\n    return (true);\n}\n\nint VDC::CopyAtt(const DC &src, string varname, string attname)\n{\n    XType type = src.GetAttType(varname, attname);\n    if (type == XType::INT32 || type == XType::INT64) {\n        vector<long> values;\n        if (!src.GetAtt(varname, attname, values)) return -1;\n        return PutAtt(varname, attname, type, values);\n    } else if (type == XType::FLOAT || type == XType::DOUBLE) {\n        vector<double> values;\n        if (!src.GetAtt(varname, attname, values)) return -1;\n        return PutAtt(varname, attname, type, values);\n    } else if (type == XType::TEXT) {\n        string values;\n        if (!src.GetAtt(varname, attname, values)) return -1;\n        return PutAtt(varname, attname, type, values);\n    } else if (type == XType::INVALID) {\n        SetErrMsg(\"Invalid attribute : %s.%s\", varname.c_str(), attname.c_str());\n        return -1;\n    }\n    return 0;\n}\n\nint VDC::CopyAtt(const DC &src, string varname)\n{\n    vector<string> names = src.GetAttNames(varname);\n\n    for (int i = 0; i < names.size(); i++) {\n        int rc = CopyAtt(src, varname, names[i]);\n        if (rc < 0) return (-1);\n    }\n    return (0);\n}\n\nvector<string> VDC::getAttNames(string varname) const\n{\n    vector<string> attnames;\n\n    std::map<string, Attribute>::const_iterator itr;\n\n    if (varname.empty()) {    // global attributes\n        for (itr = _atts.begin(); itr != _atts.end(); ++itr) { attnames.push_back(itr->first); }\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        map<string, DataVar>::const_iterator itr1 = _dataVars.find(varname);\n        map<string, Attribute>               atts = itr1->second.GetAttributes();\n        for (itr = atts.begin(); itr != atts.end(); ++itr) { attnames.push_back(itr->first); }\n    } else if (_coordVars.find(varname) != _coordVars.end()) {\n        map<string, CoordVar>::const_iterator itr1 = _coordVars.find(varname);\n        map<string, Attribute>                atts = itr1->second.GetAttributes();\n        for (itr = atts.begin(); itr != atts.end(); ++itr) { attnames.push_back(itr->first); }\n    }\n    return (attnames);\n}\n\nDC::XType VDC::getAttType(string varname, string attname) const\n{\n    std::map<string, Attribute>::const_iterator itr;\n\n    if (varname.empty()) {    // global attributes\n        itr = _atts.find(attname);\n        if (itr == _atts.end()) return (INVALID);\n\n        return (itr->second.GetXType());\n\n    } else if (_dataVars.find(varname) != _dataVars.end()) {\n        map<string, DataVar>::const_iterator itr1 = _dataVars.find(varname);\n        map<string, Attribute>               atts = itr1->second.GetAttributes();\n        itr = atts.find(attname);\n        if (itr == _atts.end()) return (INVALID);\n\n        return (itr->second.GetXType());\n\n    } else if (_coordVars.find(varname) != _coordVars.end()) {\n        map<string, CoordVar>::const_iterator itr1 = _coordVars.find(varname);\n        map<string, Attribute>                atts = itr1->second.GetAttributes();\n        itr = atts.find(attname);\n        if (itr == _atts.end()) return (INVALID);\n\n        return (itr->second.GetXType());\n    }\n    return (INVALID);\n}\n\nstring VDC::getMapProjection(string varname) const\n{\n    // Shoot. This doens't do anything. I.e. it doesn't force data to\n    // be reprojected\n    //\n    if (!_proj4StringOption.empty()) { return (_proj4StringOption); }\n\n    string attname = \"MapProjection\";\n\n    vector<string> attnames = VDC::getAttNames(varname);\n    if (find(attnames.begin(), attnames.end(), attname) == attnames.end()) {\n        // Return default map projection.\n        //\n        // N.B. WE SHOULD BE VERIFYING THAT THIS IS A GEOREFERENCED\n        // VARIABLE!!!\n        //\n        return (VDC::getMapProjection());\n    }\n\n    string proj4string;\n    bool   status = VDC::getAtt(varname, attname, proj4string);\n    if (status) return (proj4string);\n\n    return (\"\");\n}\n\nstring VDC::getMapProjection() const\n{\n    if (!_proj4StringOption.empty()) { return (_proj4StringOption); }\n\n    string attname = \"MapProjection\";\n\n    vector<string> attnames = VDC::getAttNames(\"\");\n    if (find(attnames.begin(), attnames.end(), attname) == attnames.end()) { return (\"\"); }\n\n    string proj4string;\n    bool   status = VDC::getAtt(\"\", attname, proj4string);\n    if (status) return (proj4string);\n\n    return (\"\");\n}\n\nint VDC::SetMapProjection(string varname, string projstring)\n{\n    string attname = \"MapProjection\";\n\n    return (VDC::PutAtt(varname, attname, TEXT, projstring));\n}\n\nint VDC::SetMapProjection(string projstring)\n{\n    string attname = \"MapProjection\";\n\n    return (VDC::PutAtt(\"\", attname, TEXT, projstring));\n}\n\nint VDC::EndDefine()\n{\n    if (!_defineMode) return (0);\n\n    if (_mode == R) return (0);\n\n    if (_master_path.empty()) {\n        // Initialized() not called\n        //\n        SetErrMsg(\"Master file not specified\");\n        return (-1);\n    }\n\n    if (_WriteMasterMeta() < 0) return (-1);\n\n    _defineMode = false;\n\n    // For any 1D Uniform coordinate variables that\n    // were defined go ahead\n    // and give them default values\n    //\n    for (int i = 0; i < _newUniformVars.size(); i++) {\n        vector<DC::Dimension> dimensions;\n        bool                  ok = GetVarDimensions(_newUniformVars[i], false, dimensions, -1);\n        VAssert(ok);\n\n        if (dimensions.size() != 1) continue;\n\n        size_t l = dimensions[0].GetLength();\n\n        float *buf = new float[l];\n        for (size_t j = 0; j < l; j++) buf[j] = (float)j;\n\n        int rc = PutVar(_newUniformVars[i], -1, buf);\n        if (rc < 0) {\n            delete[] buf;\n            return (rc);\n        }\n        delete[] buf;\n    }\n\n    return (0);\n}\n\nbool VDC::_ValidDefineDimension(string name, size_t length) const\n{\n    if (length < 1) {\n        SetErrMsg(\"Dimension must be of length 1 or more\");\n        return (false);\n    }\n\n    return (true);\n}\n\nbool VDC::_ValidDefineCoordVar(string varname, vector<string> sdim_names, string time_dim_name, string units, int axis, XType type, bool compressed) const\n{\n    if (sdim_names.size() > 3) {\n        SetErrMsg(\"Invalid number of dimensions\");\n        return (false);\n    }\n\n    if (axis == 3 && (sdim_names.size() != 0 || time_dim_name.empty())) {\n        SetErrMsg(\"Time coordinate variables must have exactly one dimension\");\n        return (false);\n    }\n\n    // All space + time dim names\n    //\n    vector<string> dim_names = sdim_names;\n    if (!time_dim_name.empty()) dim_names.push_back(time_dim_name);\n\n    for (int i = 0; i < dim_names.size(); i++) {\n        if (_dimsMap.find(dim_names[i]) == _dimsMap.end()) {\n            SetErrMsg(\"Dimension \\\"%s\\\" not defined\", dim_names[i].c_str());\n            return (false);\n        }\n    }\n\n    if (axis < 0 || axis > 3) {\n        SetErrMsg(\"Invalid axis specification : %d\", axis);\n        return (false);\n    }\n\n    if (!units.empty() && !_udunits.ValidUnit(units)) {\n        SetErrMsg(\"Unrecognized units specification : %s \", units.c_str());\n        return (false);\n    }\n\n#ifdef VAPOR3_0_0_ALPHA\n    if (compressed && type != FLOAT) {\n        SetErrMsg(\"Only FLOAT data supported with compressed variables\");\n        return (false);\n    }\n#endif\n\n    //\n    // IF this is a dimension coordinate variable (a variable with\n    // the same name as any dimension) then the dimensions,\n    // and compression cannot be changed.\n    //\n    map<string, Dimension>::const_iterator itr = _dimsMap.find(varname);\n    if (itr != _dimsMap.end()) {\n        if (dim_names.size() != 1 || varname.compare(dim_names[0]) != 0) {\n            SetErrMsg(\"Invalid dimension coordinate variable definition\");\n            return (false);\n        }\n        if (compressed) {\n            SetErrMsg(\"Invalid dimension coordinate variable definition\");\n            return (false);\n        }\n    }\n\n    return (true);\n}\n\nbool VDC::_ValidCompressionBlock(vector<size_t> bs, string wname, vector<size_t> cratios) const\n{\n    for (int i = 0; i < cratios.size(); i++) {\n        if (cratios[i] < 1) return (false);\n    }\n\n    // No compression if no blocking\n    //\n    if (vproduct(bs) == 1) {\n        if (!wname.empty()) return (false);\n        if (!(cratios.size() == 1 && cratios[0] == 1)) return (false);\n    }\n\n    size_t nlevels, maxcratio;\n    bool   status = CompressionInfo(bs, wname, nlevels, maxcratio);\n    if (!status) return (false);\n\n    if (!wname.empty()) {\n        for (int i = 0; i < cratios.size(); i++) {\n            if (cratios[i] > maxcratio) return (false);\n        }\n    }\n    return (true);\n}\n\n// Verify that dims0 is a subset of dims1, and that they have same block\n// size\n//\nbool VDC::_valid_dims(const vector<DC::Dimension> &dims0, const vector<size_t> &bs0, const vector<DC::Dimension> &dims1, const vector<size_t> &bs1) const\n{\n    VAssert(dims0.size() == bs0.size());\n    VAssert(dims1.size() == bs1.size());\n\n    for (int i = 0; i < dims0.size(); i++) {\n        bool match = false;\n        for (int j = 0; j < dims1.size(); j++) {\n            // Different names ok as long has have same length\n            //\n            // if (dims0[i].GetName() == dims1[j].GetName())\n\n            if (dims0[i].GetLength() == dims1[j].GetLength()) {\n                match = true;\n\n                // Must have same blocking or no blocking\n                //\n                if (!(bs0[i] == bs1[j] || bs0[i] == 1 || bs1[j] == 1)) return (false);\n            }\n        }\n        if (!match) return (false);\n    }\n    return (true);\n}\n\nbool VDC::_valid_mask_var(string varname, vector<DC::Dimension> dimensions, vector<size_t> bs, bool compressed, string maskvar) const\n{\n    map<string, DataVar>::const_iterator itr = _dataVars.find(maskvar);\n    if (itr == _dataVars.end()) {\n        SetErrMsg(\"Mask var \\\"%s\\\" not defined\", maskvar.c_str());\n        return (false);\n    }\n    const DataVar &mvar = itr->second;\n\n    map<string, Mesh>::const_iterator mitr = _meshes.find(mvar.GetMeshName());\n    if (mitr == _meshes.end()) return (false);\n\n    // Fastest varying data variable dimensions must match mask\n    // variable dimensions\n    //\n    vector<DC::Dimension> mdimensions;\n    bool                  ok = GetVarDimensions(maskvar, false, mdimensions, -1);\n    VAssert(ok);\n\n    while (dimensions.size() > mdimensions.size()) dimensions.pop_back();\n    while (bs.size() > mdimensions.size()) bs.pop_back();\n\n    if (dimensions.size() != mdimensions.size()) {\n        SetErrMsg(\"Data variable and mask variable dimensions must match\");\n        return (false);\n    }\n\n    if (compressed) {\n        size_t nlevels, dummy;\n        CompressionInfo(bs, _wname, nlevels, dummy);\n\n        size_t nlevels_m;\n        CompressionInfo(bs, mvar.GetWName(), nlevels_m, dummy);\n\n        if (nlevels > nlevels_m) {\n            SetErrMsg(\"Data variable and mask variable depth must match\");\n            return (false);\n        }\n    }\n\n    return (true);\n}\n\nbool VDC::_ValidDefineDataVar(string varname, vector<string> dim_names, vector<string> coord_vars, string units, XType type, bool compressed, bool has_missing, string maskvar) const\n{\n    if (compressed && has_missing && maskvar.empty()) {\n        SetErrMsg(\"Mask variable required for compressed data with missing values\");\n        return (false);\n    }\n\n    if (dim_names.size() > 4) {\n        SetErrMsg(\"Invalid number of dimensions\");\n        return (false);\n    }\n\n    if (dim_names.size() != coord_vars.size()) {\n        SetErrMsg(\"Number of dimensions and coordinate vars don't match\");\n        return (false);\n    }\n\n    vector<DC::Dimension> dimensions;\n    for (int i = 0; i < dim_names.size(); i++) {\n        DC::Dimension dim;\n\n        bool ok = VDC::GetDimension(dim_names[i], dim, -1);\n        if (!ok) {\n            SetErrMsg(\"Dimension \\\"%s\\\" not defined\", dim_names[i].c_str());\n            return (false);\n        }\n        dimensions.push_back(dim);\n    }\n\n    for (int i = 0; i < coord_vars.size(); i++) {\n        if (_coordVars.find(coord_vars[i]) == _coordVars.end()) {\n            SetErrMsg(\"Coordinate var \\\"%s\\\" not defined\", coord_vars[i].c_str());\n            return (false);\n        }\n    }\n\n    if (!units.empty() && !_udunits.ValidUnit(units)) {\n        SetErrMsg(\"Unrecognized units specification : %s\", units.c_str());\n        return (false);\n    }\n\n#ifdef VAPOR3_0_0_ALPHA\n    if (compressed && type != FLOAT) {\n        SetErrMsg(\"Only FLOAT data supported with compressed variables\");\n        return (false);\n    }\n#endif\n\n    //\n    // If multidimensional the dimensions and coord names must be\n    // ordered X, Y, Z, T\n    //\n\n    if (coord_vars.size() > 1) {\n        map<string, CoordVar>::const_iterator itr;\n        int                                   axis = -1;\n        for (int i = 0; i < coord_vars.size(); i++) {\n            itr = _coordVars.find(coord_vars[i]);\n            VAssert(itr != _coordVars.end());    // already checked for existance\n            if (itr->second.GetAxis() <= axis) {\n                SetErrMsg(\"Dimensions must be ordered X, Y, Z, T\");\n                return (false);\n            }\n            axis = itr->second.GetAxis();\n        }\n    }\n\n    // Check for a time coordinate\n    //\n    if (coord_vars.size() > 0) {\n        map<string, CoordVar>::const_iterator itr;\n        itr = _coordVars.find(coord_vars[coord_vars.size() - 1]);\n        if (itr != _coordVars.end() && itr->second.GetAxis() == 3) {\n            dim_names.pop_back();\n            dimensions.pop_back();\n            coord_vars.pop_back();\n        }\n    }\n\n    // Determine block size\n    //\n    vector<size_t> bs;\n    _compute_bs(dim_names.size(), _bs, bs);\n\n    // Validate mask variable if one exists\n    //\n    if (maskvar.empty()) return (true);\n\n    return (_valid_mask_var(varname, dimensions, bs, compressed, maskvar));\n}\n\nnamespace VAPoR {\n\nstd::ostream &operator<<(std::ostream &o, const VDC &vdc)\n{\n    o << \"VDC\" << endl;\n    o << \" MasterPath: \" << vdc._master_path << endl;\n    o << \" AccessMode: \" << vdc._mode << endl;\n    o << \" DefineMode: \" << vdc._defineMode << endl;\n    o << \" Block Size: \";\n    for (int i = 0; i < vdc._bs.size(); i++) { o << vdc._bs[i] << \" \"; }\n    o << endl;\n    o << \" WName: \" << vdc._wname << endl;\n    o << \" CRatios: \";\n    for (int i = 0; i < vdc._cratios.size(); i++) { o << vdc._cratios[i] << \" \"; }\n    o << endl;\n    o << \" Periodic: \";\n    for (int i = 0; i < vdc._periodic.size(); i++) { o << vdc._periodic[i] << \" \"; }\n    o << endl;\n\n    {\n        o << \" Attributes\" << endl;\n        std::map<string, DC::Attribute>::const_iterator itr;\n        for (itr = vdc._atts.begin(); itr != vdc._atts.end(); ++itr) { o << itr->second; }\n        o << endl;\n    }\n\n    {\n        o << \" Dimensions\" << endl;\n        std::map<string, DC::Dimension>::const_iterator itr;\n        for (itr = vdc._dimsMap.begin(); itr != vdc._dimsMap.end(); ++itr) { o << itr->second; }\n        o << endl;\n    }\n\n    {\n        o << \" CoordVars\" << endl;\n        std::map<string, DC::CoordVar>::const_iterator itr;\n        for (itr = vdc._coordVars.begin(); itr != vdc._coordVars.end(); ++itr) {\n            o << itr->second;\n            o << endl;\n        }\n        o << endl;\n    }\n\n    {\n        o << \" DataVars\" << endl;\n        std::map<string, DC::DataVar>::const_iterator itr;\n        for (itr = vdc._dataVars.begin(); itr != vdc._dataVars.end(); ++itr) {\n            o << itr->second;\n            o << endl;\n        }\n        o << endl;\n    }\n\n    return (o);\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/vdc/VDCNetCDF.cpp",
    "content": "#include \"vapor/VAssert.h\"\n#include <sstream>\n#include <map>\n#include <vector>\n#include <sys/stat.h>\n#include <netcdf.h>\n#include \"vapor/VDCNetCDF.h\"\n#include \"vapor/CFuncs.h\"\n#include \"vapor/Version.h\"\n#include \"vapor/FileUtils.h\"\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nnamespace {\n\n// Map a level specification for a given number of levels into\n// clevel (coarsest level is 0 increasing values corespond to finer\n// levels), and flevel (finest level is -1 and decreasing values\n// correspond to coarser levels)\n//\nvoid levels(int level, int nlevels, int &clevel, int &flevel)\n{\n    if (level > nlevels - 1) level = nlevels - 1;\n    if (level < -nlevels) level = -nlevels;\n\n    if (level >= 0) {\n        clevel = level;\n        flevel = -nlevels + level;\n    } else {\n        clevel = level + nlevels;\n        flevel = level;\n    }\n}\n\nint vdc_xtype2ncdf_xtype(VDC::XType v_xtype)\n{\n    int n_xtype;\n    switch (v_xtype) {\n    case VDC::FLOAT: n_xtype = NC_FLOAT; break;\n    case VDC::DOUBLE: n_xtype = NC_DOUBLE; break;\n    case VDC::INT8: n_xtype = NC_BYTE; break;\n    case VDC::INT32: n_xtype = NC_INT; break;\n    case VDC::INT64: n_xtype = NC_INT64; break;\n    case VDC::UINT8: n_xtype = NC_UBYTE; break;\n    case VDC::TEXT: n_xtype = NC_CHAR; break;\n    default: n_xtype = NC_NAT; break;\n    }\n    return (n_xtype);\n}\n\n#ifdef UNUSED_FUNCTION\nVDC::XType ncdf_xtype2vdc_xtype(int n_xtype)\n{\n    VDC::XType v_xtype;\n    switch (n_xtype) {\n    case NC_FLOAT: v_xtype = VDC::FLOAT; break;\n    case NC_DOUBLE: v_xtype = VDC::DOUBLE; break;\n    case NC_BYTE: v_xtype = VDC::INT8; break;\n    case NC_INT: v_xtype = VDC::INT32; break;\n    case NC_INT64: v_xtype = VDC::INT64; break;\n    case NC_UBYTE: v_xtype = VDC::UINT8; break;\n    case NC_CHAR:\n    case NC_STRING: v_xtype = VDC::TEXT; break;\n    default: v_xtype = VDC::INVALID; break;\n    }\n    return (v_xtype);\n}\n#endif\n\nvoid vdc_2_ncdfcoords(size_t ts0, size_t ts1, bool time_varying, const vector<size_t> &min, const vector<size_t> &max, vector<size_t> &start, vector<size_t> &count)\n{\n    start.clear();\n    count.clear();\n\n    VAssert(min.size() == max.size());\n    ;\n    VAssert(max.size() <= 3);\n    VAssert(ts1 >= ts0);\n\n    if (time_varying) {\n        start.push_back(ts0);\n        count.push_back(ts1 - ts0 + 1);\n    }\n\n    for (int i = min.size() - 1; i >= 0; i--) {\n        VAssert(max[i] >= min[i]);\n        start.push_back(min[i]);\n        count.push_back(max[i] - min[i] + 1);\n    }\n}\n\n// Product of elements in a vector\n//\nsize_t vproduct(vector<size_t> a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n\nsize_t gcd(size_t n1, size_t n2)\n{\n    size_t tmp;\n    while (n2 != 0) {\n        tmp = n1;\n        n1 = n2;\n        n2 = tmp % n2;\n    }\n    return n1;\n}\n\nsize_t lcm(size_t n1, size_t n2) { return ((n1 * n2) / gcd(n1, n2)); }\n\nbool isblocked(vector<size_t> bs)\n{\n    for (int i = 0; i < bs.size(); i++) {\n        if (bs[i] != 1) return (true);\n    }\n    return (false);\n}\n\n};    // namespace\n\nVDCNetCDF::VDCNetCDF(int nthreads, size_t master_threshold, size_t variable_threshold) : VDC()\n{\n    _nthreads = nthreads;\n    _master_threshold = master_threshold;\n    _variable_threshold = variable_threshold;\n    _chunksizehint = 0;\n    _master = new WASP(nthreads);\n    _version = 1;\n}\n\nVDCNetCDF::~VDCNetCDF()\n{\n    vector<int> fds = _fileTable.GetEntries();\n    for (int i = 0; i < fds.size(); i++) { (void)closeVariable(i); }\n\n    if (_master) {\n        _master->Close();\n        delete _master;\n    }\n}\n\nint VDCNetCDF::GetHyperSliceInfo(string varname, int level, std::vector<size_t> &hslice_dims, size_t &nslice)\n{\n    hslice_dims.clear();\n    nslice = 0;\n\n    vector<size_t> dims_at_level;\n    vector<size_t> bs_at_level;\n\n    int rc = GetDimLensAtLevel(varname, level, dims_at_level, bs_at_level, -1);\n    if (rc < 0) return (-1);\n\n    if (dims_at_level.size() == 0) return (0);\n\n    if (!isblocked(bs_at_level)) { return (DC::GetHyperSliceInfo(varname, level, hslice_dims, nslice)); }\n\n    hslice_dims = dims_at_level;\n\n    if (dims_at_level.size() == 1) {\n        nslice = 1;\n        return (0);\n    }\n\n    int dim = hslice_dims.size() - 1;\n\n    // This is where we override the DC::GetHyperSliceInfo() method.\n    // Need to preserve block alignment.\n    //\n    hslice_dims[dim] = bs_at_level[dim];\n    nslice = (dims_at_level[dim] - 1) / hslice_dims[dim] + 1;\n\n    return (0);\n}\n\nint VDCNetCDF::Initialize(const vector<string> &paths, const vector<string> &options, AccessMode mode, vector<size_t> bs, size_t chunksizehint)\n{\n    _chunksizehint = chunksizehint;\n\n    int rc = VDC::initialize(paths, options, mode, bs);\n    if (rc < 0) return (-1);\n\n    if (mode == VDC::W) {\n        size_t chsz = _chunksizehint;\n        rc = _master->Create(_master_path, NC_64BIT_OFFSET | NC_WRITE, 0, chsz, 1);\n    } else if (mode == VDC::A) {\n        rc = _master->Open(_master_path, NC_WRITE);\n    } else {\n        rc = _master->Open(_master_path, NC_NOWRITE);\n    }\n    if (rc < 0) return (-1);\n    return (0);\n}\n\nstring VDCNetCDF::GetDataDir(string master)\n{\n    string path = master;\n    string extension = FileUtils::Extension(path);\n    if (!extension.empty()) path.erase(path.rfind(\".\" + extension));\n    path += \"_data\";\n    return (path);\n}\n\n//\n// Figure out where variable lives. This algorithm will most likely\n// change.\n//\nint VDCNetCDF::GetPath(string varname, size_t ts, string &path, size_t &file_ts, size_t &max_ts) const\n{\n    path.clear();\n    file_ts = 0;\n    max_ts = 0;\n\n    bool time_varying = IsTimeVarying(varname);\n    if (!time_varying) {\n        ts = 0;    // Could be anything if data aren't time varying;\n    }\n\n    VDC::BaseVar var;\n    if (!VDC::GetBaseVarInfo(varname, var)) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (false);\n    }\n\n    vector<Dimension> dimensions;\n    bool              ok = GetVarDimensions(varname, false, dimensions, -1);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (false);\n    }\n\n    // Does this variable live in the master file?\n    //\n    if (_var_in_master(var)) {\n        path = _master_path;\n        file_ts = ts;\n        return (0);\n    }\n\n    path = VDCNetCDF::GetDataDir(_master_path);\n\n    path += \"/\";\n\n    if (VDC::IsDataVar(varname)) {\n        path += \"data\";\n        path += \"/\";\n    } else {\n        path += \"coordinates\";\n        path += \"/\";\n    }\n\n    path += varname;\n    path += \"/\";\n    path += varname;\n\n    if (time_varying) {\n        size_t ngridpoints = 1;\n        for (int i = 0; i < dimensions.size() - 1; i++) {\n            ngridpoints *= dimensions[i].GetLength();\n        }\n\n        int           idx;\n        ostringstream oss;\n        size_t        numts = dimensions[dimensions.size() - 1].GetLength();\n        VAssert(numts > 0);\n        max_ts = _variable_threshold / ngridpoints;\n        if (max_ts > numts) max_ts = numts;\n        if (max_ts == 0) {\n            idx = ts;\n            file_ts = 0;\n            max_ts = 1;\n        } else {\n            idx = ts / max_ts;\n            ;\n            file_ts = ts % max_ts;\n        }\n        int width = (int)log10((double)numts - 1) + 1;\n        if (width < 4) width = 4;\n        oss.width(width);\n        oss.fill('0');\n        oss << idx;\n\n        path += \".\";\n        path += oss.str();\n    }\n\n    path += \".\";\n    path += \"nc\";\n\n    return (0);\n}\n\nint VDCNetCDF::getDimLensAtLevel(string varname, int level, vector<size_t> &dims_at_level, vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    int nlevels = VDC::GetNumRefLevels(varname);\n\n    int clevel, dummy;\n    levels(level, nlevels, clevel, dummy);\n\n    vector<size_t> dimlens;\n    bool           ok = GetVarDimLens(varname, true, dimlens, -1);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    DC::BaseVar varinfo;\n    ok = GetBaseVarInfo(varname, varinfo);\n    if (!ok) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    vector<size_t> bs = _bs;\n    while (bs.size() > dimlens.size()) { bs.pop_back(); }\n    VAssert(bs.size() == dimlens.size());\n\n    if (varinfo.IsCompressed()) {\n        string wname = varinfo.GetWName();\n\n        reverse(bs.begin(), bs.end());\n        reverse(dimlens.begin(), dimlens.end());\n        WASP::InqDimsAtLevel(wname, clevel, dimlens, bs, dims_at_level, bs_at_level);\n        reverse(bs_at_level.begin(), bs_at_level.end());\n        reverse(dims_at_level.begin(), dims_at_level.end());\n    } else {\n        bs_at_level = bs;\n        dims_at_level = dimlens;\n    }\n\n    return (0);\n}\n\nbool VDCNetCDF::DataDirExists(string master)\n{\n    string path = VDCNetCDF::GetDataDir(master);\n\n    struct stat statbuf;\n\n    if (stat(path.c_str(), &statbuf) < 0) return (false);\n\n    return (true);\n}\n\nWASP *VDCNetCDF::_OpenVariableRead(size_t ts, string varname, int clevel, int lod, size_t &file_ts)\n{\n    file_ts = 0;\n\n    DC::BaseVar var;\n    if (!VDC::GetBaseVarInfo(varname, var)) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (NULL);\n    }\n\n    string path;\n    size_t max_ts;\n    int    rc = GetPath(varname, ts, path, file_ts, max_ts);\n    if (rc < 0) return (NULL);\n\n    int ncratios = var.GetCRatios().size();\n\n    if (lod > ncratios - 1) lod = ncratios - 1;\n    if (lod < 0) lod = lod + ncratios;\n    if (lod < 0) lod = 0;\n\n    WASP *wasp = NULL;\n\n    if (path.compare(_master_path) == 0) {\n        wasp = _master;\n    } else {\n        wasp = new WASP(_nthreads);\n        rc = wasp->Open(path, NC_NOWRITE);\n        if (rc < 0) return (NULL);\n    }\n\n    rc = wasp->OpenVarRead(varname, clevel, lod);\n    if (rc < 0) return (NULL);\n\n    return (wasp);\n}\n\nstring VDCNetCDF::_get_mask_varname(string varname, double &mv) const\n{\n    VDC::DataVar dvar;\n    mv = 0.0;\n\n    string mask_varname;\n\n    if (VDC::getDataVarInfo(varname, dvar)) {\n        mask_varname = dvar.GetMaskvar();\n        if (!mask_varname.empty()) { mv = dvar.GetMissingValue(); }\n    }\n    return (mask_varname);\n}\n\nint VDCNetCDF::openVariableRead(size_t ts, string varname, int level, int lod)\n{\n    int nlevels = VDC::GetNumRefLevels(varname);\n\n    int clevel, flevel;\n    levels(level, nlevels, clevel, flevel);\n\n    size_t file_ts;\n    WASP * wasp = _OpenVariableRead(ts, varname, clevel, lod, file_ts);\n    if (!wasp) return (-1);\n\n    double mv;\n    string maskvar = _get_mask_varname(varname, mv);\n\n    //\n    // If there is a mask variable we need to open it.\n    //\n\n    WASP * wasp_mask = NULL;\n    int    clevel_mask = -1;\n    size_t file_ts_mask = 0;\n\n    if (!maskvar.empty()) {\n        //\n        // the level specification can be tricky because the data variable\n        // and the mask variable can have different numbers of levels (if\n        // different wavelets are used). Convert the flevel - which indexes\n        // from finest to coarsest and hence will be the same for both\n        // variables - to a clevel, which is required by WASP API\n        //\n        nlevels = VDC::GetNumRefLevels(maskvar);\n\n        levels(flevel, nlevels, clevel_mask, flevel);\n\n        wasp_mask = _OpenVariableRead(ts, maskvar, clevel_mask, lod, file_ts_mask);\n        if (!wasp_mask) return (-1);\n    }\n\n    VDCFileObject *o = new VDCFileObject(ts, varname, clevel, lod, file_ts, wasp, wasp_mask, maskvar, clevel_mask, file_ts_mask, mv);\n\n    return (_fileTable.AddEntry(o));\n}\n\nint VDCNetCDF::OpenVariableWrite(size_t ts, string varname, int lod)\n{\n    VDC::BaseVar *varptr;\n\n    VDC::DataVar  dvar;\n    VDC::CoordVar cvar;\n    bool          isdvar;\n    if (VDC::getDataVarInfo(varname, dvar)) {\n        varptr = &dvar;\n        isdvar = true;\n    } else if (VDC::getCoordVarInfo(varname, cvar)) {\n        varptr = &cvar;\n        isdvar = false;\n    } else {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (false);\n    }\n\n    string path;\n    size_t file_ts;\n    size_t max_ts;\n    int    rc = GetPath(varname, ts, path, file_ts, max_ts);\n    if (rc < 0) return (-1);\n\n    WASP *wasp = NULL;\n\n    if (path.compare(_master_path) == 0) {\n        wasp = _master;\n    } else if (_master->ValidFile(path)) {\n        wasp = new WASP(_nthreads);\n        rc = wasp->Open(path, NC_WRITE);\n    } else {\n        wasp = new WASP(_nthreads);\n        string dir;\n        dir = FileUtils::Dirname(path);\n        rc = MkDirHier(dir);\n        if (rc < 0) return (-1);\n\n        size_t chsz = _chunksizehint;\n        rc = wasp->Create(path, NC_WRITE | NC_64BIT_OFFSET, 0, chsz, varptr->GetCRatios().size());\n        if (rc < 0) return (-1);\n\n        // Make a copy of attributes contained in master file\n        //\n        rc = _WriteAttributes(wasp, \"\", _atts);\n        if (rc < 0) return (-1);\n\n        if (isdvar) {\n            rc = _DefDataVar(wasp, dvar, max_ts);\n        } else {\n            rc = _DefCoordVar(wasp, cvar, max_ts);\n        }\n        if (rc < 0) return (-1);\n\n        rc = wasp->EndDef();\n        if (rc < 0) return (-1);\n    }\n    rc = wasp->OpenVarWrite(varname, lod);\n    if (rc < 0) return (-1);\n\n    int nlevels = VDC::GetNumRefLevels(varname);\n\n    //\n    // If there is a mask variable we need to open it for **reading**\n    //\n\n    double mv;\n    string maskvar = _get_mask_varname(varname, mv);\n    WASP * wasp_mask = NULL;\n    size_t file_ts_mask = 0;\n    if (!maskvar.empty()) {\n        nlevels = VDC::GetNumRefLevels(maskvar);\n\n        wasp_mask = _OpenVariableRead(ts, maskvar, nlevels - 1, lod, file_ts_mask);\n        if (!wasp_mask) return (-1);\n    }\n\n    VDCFileObject *o = new VDCFileObject(ts, varname, nlevels - 1, lod, file_ts, wasp, wasp_mask, maskvar, nlevels - 1, file_ts_mask, mv);\n\n    return (_fileTable.AddEntry(o));\n}\n\nint VDCNetCDF::closeVariable(int fd)\n{\n    VDCFileObject *o = (VDCFileObject *)_fileTable.GetEntry(fd);\n\n    if (!o) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    WASP *wasp = o->GetWaspData();\n\n    if (wasp) { wasp->CloseVar(); }\n    if (wasp && wasp != _master) {\n        wasp->Close();\n        delete wasp;\n    }\n\n    WASP *wasp_mask = o->GetWaspMask();\n    if (wasp_mask) { wasp_mask->CloseVar(); }\n    if (wasp_mask && wasp_mask != _master) {\n        wasp_mask->Close();\n        delete wasp_mask;\n    }\n\n    _fileTable.RemoveEntry(fd);\n    delete o;\n\n    return (0);\n}\n\nunsigned char *VDCNetCDF::_read_mask_var(WASP *wasp, string varname, string varname_mask, vector<size_t> start, vector<size_t> count)\n{\n    // data variable may be time varying, while mask variable is not.\n    // If so remove the time dimension from start and count\n    //\n    if (VDC::IsTimeVarying(varname) && !VDC::IsTimeVarying(varname_mask)) {\n        start.erase(start.begin());\n        count.erase(count.begin());\n    }\n\n    size_t size = vproduct(count) * sizeof(unsigned char);\n\n    unsigned char *mask = (unsigned char *)_mask_buffer.Alloc(size);\n\n    int rc = wasp->GetVara(start, count, mask);\n    if (rc < 0) return (NULL);\n\n    return (mask);\n}\n\ntemplate<class T> int VDCNetCDF::_writeTemplate(int fd, const T *data)\n{\n    VDCFileObject *o = (VDCFileObject *)_fileTable.GetEntry(fd);\n\n    if (!o) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    WASP * wasp = o->GetWaspData();\n    string varname = o->GetVarname();\n    int    level = o->GetLevel();\n\n    vector<size_t> dims, dummy;\n    int            rc = GetDimLensAtLevel(varname, level, dims, dummy, -1);\n    if (rc < 0) return (rc);\n\n    bool time_varying = VDC::IsTimeVarying(varname);\n\n    vector<size_t> start;\n    vector<size_t> count;\n\n    vector<size_t> mins(dims.size(), 0);\n    vector<size_t> maxs = dims;\n    for (int i = 0; i < maxs.size(); i++) maxs[i] -= 1;\n\n    size_t file_ts = o->GetFileTS();\n    vdc_2_ncdfcoords(file_ts, file_ts, time_varying, mins, maxs, start, count);\n\n    double mv;\n    string maskvar = _get_mask_varname(varname, mv);\n    if (maskvar.empty()) { return (wasp->PutVara(start, count, data)); }\n\n    unsigned char *mask = _read_mask_var(o->GetWaspMask(), varname, maskvar, start, count);\n    if (!mask) return (-1);\n\n    return (wasp->PutVara(start, count, data, mask));\n}\n\ntemplate<class T> int VDCNetCDF::_writeSliceTemplate(int fd, const T *slice)\n{\n    VDCFileObject *o = (VDCFileObject *)_fileTable.GetEntry(fd);\n\n    if (!o) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n    WASP * wasp = o->GetWaspData();\n    string varname = o->GetVarname();\n    int    level = o->GetLevel();\n\n    vector<size_t> dims_at_level;\n    vector<size_t> dummy;\n\n    int rc = GetDimLensAtLevel(varname, level, dims_at_level, dummy, -1);\n    if (rc < 0) return (rc);\n\n    vector<size_t> hslice_dims;\n    size_t         nslice;\n    rc = GetHyperSliceInfo(varname, level, hslice_dims, nslice);\n    if (rc < 0) return (rc);\n    VAssert(hslice_dims.size() == dims_at_level.size());\n\n    int slice_num = o->GetSlice();\n    if (slice_num >= nslice) return (0);    // Done writing;\n\n    vector<size_t> min;\n    vector<size_t> max;\n    int            dim = 0;\n    for (; dim < hslice_dims.size() - 1; dim++) {\n        min.push_back(0);\n        max.push_back(hslice_dims[dim] - 1);\n    };\n    min.push_back(slice_num * hslice_dims[dim]);\n    max.push_back(min[dim] + hslice_dims[dim] - 1);\n\n    // Last slice is a partial read if not block-aligned\n    //\n    if (max[dim] >= dims_at_level[dim]) { max[dim] = dims_at_level[dim] - 1; }\n\n    //\n    // Map from VDC to NetCDF coordinates\n    //\n    vector<size_t> start;\n    vector<size_t> count;\n    size_t         file_ts = o->GetFileTS();\n    vdc_2_ncdfcoords(file_ts, file_ts, IsTimeVarying(varname), min, max, start, count);\n\n    double mv;\n    string maskvar = _get_mask_varname(varname, mv);\n    if (maskvar.empty()) {\n        rc = wasp->PutVara(start, count, slice);\n    } else {\n        unsigned char *mask = _read_mask_var(o->GetWaspMask(), varname, maskvar, start, count);\n        if (!mask) return (-1);\n\n        rc = wasp->PutVara(start, count, slice, mask);\n    }\n    if (rc < 0) return (rc);\n\n    slice_num++;\n    o->SetSlice(slice_num);\n\n    return (0);\n}\n\ntemplate int VDCNetCDF::_writeSliceTemplate<float>(int fd, const float *slice);\n\ntemplate<class T> int VDCNetCDF::_readRegionTemplate(int fd, const vector<size_t> &min, const vector<size_t> &max, T *region)\n{\n    VDCFileObject *o = (VDCFileObject *)_fileTable.GetEntry(fd);\n    if (!o) {\n        SetErrMsg(\"Invalid file descriptor : %d\", fd);\n        return (-1);\n    }\n\n    WASP * wasp = o->GetWaspData();\n    string varname = o->GetVarname();\n    size_t file_ts = o->GetFileTS();\n    WASP * wasp_mask = o->GetWaspMask();\n\n    bool time_varying = VDC::IsTimeVarying(varname);\n\n    vector<size_t> start;\n    vector<size_t> count;\n    vdc_2_ncdfcoords(file_ts, file_ts, time_varying, min, max, start, count);\n\n    int rc = wasp->GetVara(start, count, region);\n    if (rc < 0) return (rc);\n\n    // if no mask we're done\n    //\n    if (!wasp_mask) return (0);\n\n    size_t file_ts_mask = o->GetFileTSMask();\n    double mv = o->GetMissingValue();\n\n    // If there is a mask associated with this variable we need to\n    // restore the missing value\n    //\n    string mask_varname = o->GetVarnameMask();\n    time_varying = VDC::IsTimeVarying(mask_varname);\n    vdc_2_ncdfcoords(file_ts_mask, file_ts_mask, time_varying, min, max, start, count);\n\n    size_t         size = vproduct(count);\n    unsigned char *mask = (unsigned char *)_mask_buffer.Alloc(size);\n    rc = wasp_mask->GetVara(start, count, mask);\n    if (rc < 0) return (rc);\n\n    for (size_t i = 0; i < size; i++) {\n        if (!mask[i]) { region[i] = mv; }\n    }\n    return (0);\n}\n\nint VDCNetCDF::readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, float *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\nint VDCNetCDF::readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, double *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\nint VDCNetCDF::readRegion(int fd, const vector<size_t> &min, const vector<size_t> &max, int *region) { return (_readRegionTemplate(fd, min, max, region)); }\n\n\ntemplate<class T> int VDCNetCDF::_putVarTemplate(string varname, int lod, const T *data)\n{\n    vector<size_t> dims_at_level;\n    vector<size_t> dummy;\n    int            rc = VDCNetCDF::GetDimLensAtLevel(varname, -1, dims_at_level, dummy, -1);\n    if (rc < 0) return (-1);\n\n    // If not a 1D time-varying variable.\n    //\n    if (!(VDC::IsTimeVarying(varname) && dims_at_level.size() == 1)) {\n        // Number of per time step\n        //\n        size_t var_size = 1;\n        for (int i = 0; i < dims_at_level.size(); i++) var_size *= dims_at_level[i];\n\n        int numts = VDC::GetNumTimeSteps(varname);\n\n        const T *ptr = data;\n        for (size_t ts = 0; ts < numts; ts++) {\n            rc = VDCNetCDF::PutVar(ts, varname, lod, ptr);\n            if (rc < 0) return (-1);\n\n            ptr += var_size;\n        }\n\n        return (0);\n    }\n\n    // Write 1D time-varying variables directly with\n    // NetCDFCpp class.\n    //\n\n    VDC::BaseVar var;\n    if (!VDC::GetBaseVarInfo(varname, var)) {\n        SetErrMsg(\"Undefined variable name : %s\", varname.c_str());\n        return (false);\n    }\n\n    // Don't currently handle case where a variable is split across\n    // multiple files.\n    //\n    if (!_var_in_master(var)) {\n        SetErrMsg(\"Distributed variable reads not supported\");\n        return (-1);\n    }\n\n    // N.B. calling NetCDFCpp::PutVar\n    //\n    rc = ((NetCDFCpp *)_master)->PutVar(varname, data);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\ntemplate int VDCNetCDF::_putVarTemplate<float>(string varname, int lod, const float *data);\ntemplate int VDCNetCDF::_putVarTemplate<int>(string varname, int lod, const int *data);\n\ntemplate<class T> int VDCNetCDF::_putVarTemplate(size_t ts, string varname, int lod, const T *data)\n{\n    int fd = VDCNetCDF::OpenVariableWrite(ts, varname, lod);\n    if (fd < 0) return (-1);\n\n    int rc = VDCNetCDF::Write(fd, data);\n    if (rc < 0) return (-1);\n\n    rc = closeVariable(fd);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\ntemplate int VDCNetCDF::_putVarTemplate<float>(size_t ts, string varname, int lod, const float *data);\ntemplate int VDCNetCDF::_putVarTemplate<int>(size_t ts, string varname, int lod, const int *data);\n\nint VDCNetCDF::_copyVar0d(DC &dc, size_t ts, const BaseVar &varInfo)\n{\n    if (varInfo.GetXType() == FLOAT || varInfo.GetXType() == DOUBLE) {\n        float buf;\n\n        int rc = dc.GetVar(ts, varInfo.GetName(), -1, -1, &buf);\n        if (rc < 0) return (rc);\n\n        rc = PutVar(ts, varInfo.GetName(), -1, &buf);\n        if (rc < 0) return (rc);\n    } else {\n        int buf;\n\n        int rc = dc.GetVar(ts, varInfo.GetName(), -1, -1, &buf);\n        if (rc < 0) return (rc);\n\n        rc = PutVar(ts, varInfo.GetName(), -1, &buf);\n        if (rc < 0) return (rc);\n    }\n    return (0);\n}\n\ntemplate<class T>\nint VDCNetCDF::_copyVarHelper(DC &dc, int fdr, int fdw, vector<size_t> &buffer_dims, vector<size_t> &src_hslice_dims, vector<size_t> &dst_hslice_dims, size_t src_nslice, size_t dst_nslice, T *buffer)\n{\n    VAssert(buffer_dims.size() == src_hslice_dims.size());\n    VAssert(buffer_dims.size() == dst_hslice_dims.size());\n\n    size_t dim = buffer_dims.size() - 1;\n\n    size_t src_slice_count = 0;\n    size_t dst_slice_count = 0;\n    while (src_slice_count < src_nslice) {\n        T * bufptr = buffer;\n        int n = buffer_dims[dim] / src_hslice_dims[dim];\n\n        for (int i = 0; i < n && src_slice_count < src_nslice; i++) {\n            int rc = dc.ReadSlice(fdr, bufptr);\n            if (rc < 0) return (-1);\n            bufptr += vproduct(src_hslice_dims);\n\n            src_slice_count++;\n        }\n\n        bufptr = buffer;\n        n = buffer_dims[dim] / dst_hslice_dims[dim];\n\n        for (int i = 0; i < n && dst_slice_count < dst_nslice; i++) {\n            int rc = WriteSlice(fdw, bufptr);\n            if (rc < 0) return (-1);\n\n            bufptr += vproduct(dst_hslice_dims);\n\n            dst_slice_count++;\n        }\n    }\n    return (0);\n}\n\nint VDCNetCDF::CopyVar(DC &dc, size_t ts, string varname, int srclod, int dstlod)\n{\n    BaseVar varInfo;\n    bool    status = dc.GetBaseVarInfo(varname, varInfo);\n    if (!status) {\n        SetErrMsg(\"Invalid source variable name : %s\", varname.c_str());\n        return (-1);\n    }\n\n    // Get the dimensions of a hyper slice for the source and destination\n    // varible\n    //\n    vector<size_t> src_hslice_dims;\n    size_t         src_nslice;\n    int            rc = dc.GetHyperSliceInfo(varname, -1, src_hslice_dims, src_nslice);\n    if (rc < 0) return (rc);\n\n    vector<size_t> dst_hslice_dims;\n    size_t         dst_nslice;\n    rc = GetHyperSliceInfo(varname, -1, dst_hslice_dims, dst_nslice);\n    if (rc < 0) return (rc);\n\n    if (src_hslice_dims.size() != dst_hslice_dims.size()) {\n        SetErrMsg(\"Incompatible source and destination variable definitions\");\n        return (-1);\n    }\n\n    if (src_hslice_dims.size() == 0) { return (_copyVar0d(dc, ts, varInfo)); }\n\n    // n-1 fastest varying dimensions must be the same for both hyper-slices.\n    // Slowest dimension may be different.\n    //\n    int    dim = src_hslice_dims.size() - 1;\n    size_t src_dimlen = src_hslice_dims[dim];\n    size_t dst_dimlen = dst_hslice_dims[dim];\n\n    for (int i = 0; i < src_hslice_dims.size() - 1; i++) {\n        if (src_hslice_dims[i] != dst_hslice_dims[i]) {\n            SetErrMsg(\"Incompatible source and destination variable definitions\");\n            return (-1);\n        }\n    }\n\n    // Find the slice dimension for slowest varying dimension, the Least\n    // Common Multiple for the source and destination\n    //\n    size_t slice_dim = lcm(src_dimlen, dst_dimlen);\n\n    // Common (fastest-varying) dimensions for both variables, plus\n    // the lcm of the slowest varying dimension for the source\n    // and destination.\n    //\n    vector<size_t> buffer_dims = src_hslice_dims;\n    buffer_dims.pop_back();    // Remove slowest varying dimension\n    buffer_dims.push_back(slice_dim);\n\n    int fdr = dc.OpenVariableRead(ts, varname, srclod);\n    if (fdr < 0) return (fdr);\n\n    int fdw = OpenVariableWrite(ts, varname, dstlod);\n    if (fdw < 0) {\n        dc.CloseVariable(fdr);\n        return (fdw);\n    }\n\n    if (varInfo.GetXType() == FLOAT || varInfo.GetXType() == DOUBLE) {\n        size_t bufsize = vproduct(buffer_dims);\n        float *buffer = new float[bufsize];\n\n        rc = _copyVarHelper(dc, fdr, fdw, buffer_dims, src_hslice_dims, dst_hslice_dims, src_nslice, dst_nslice, buffer);\n        delete[] buffer;\n    } else {\n        size_t bufsize = vproduct(buffer_dims);\n        int *  buffer = new int[bufsize];\n\n        rc = _copyVarHelper(dc, fdr, fdw, buffer_dims, src_hslice_dims, dst_hslice_dims, src_nslice, dst_nslice, buffer);\n        delete[] buffer;\n    }\n\n    dc.CloseVariable(fdr);\n    closeVariable(fdw);\n\n    return (rc);\n}\n\nint VDCNetCDF::CopyVar(DC &dc, string varname, int srclod, int dstlod)\n{\n    size_t numTS = dc.GetNumTimeSteps(varname);\n    for (size_t ts = 0; ts < numTS; ts++) {\n        int rc = CopyVar(dc, ts, varname, srclod, dstlod);\n        if (rc < 0) return (rc);\n    }\n    return (0);\n}\n\nbool VDCNetCDF::CompressionInfo(std::vector<size_t> bs, string wname, size_t &nlevels, size_t &maxcratio) const\n{\n    nlevels = 1;\n    maxcratio = 1;\n    if (wname.empty()) return (true);\n\n    std::reverse(bs.begin(), bs.end());    // NetCDF order\n    return (WASP::InqCompressionInfo(bs, wname, nlevels, maxcratio));\n}\n\nbool VDCNetCDF::variableExists(size_t ts, string varname, int level, int lod) const\n{\n    VDC::BaseVar var;\n    if (!VDC::GetBaseVarInfo(varname, var)) return (false);\n\n    string path;\n    size_t file_ts;\n    size_t max_ts;\n    int    rc = GetPath(varname, ts, path, file_ts, max_ts);\n    if (rc < 0) return (-1);\n\n    vector<string> paths;\n    if (!var.IsCompressed()) {\n        paths.push_back(path);\n    } else {\n        int numfiles = var.GetCRatios().size();\n        paths = WASP::GetPaths(path, numfiles);\n    }\n\n    int ncratios = var.GetCRatios().size();\n\n    if (lod > ncratios - 1) lod = ncratios - 1;\n    if (lod < 0) lod = lod + ncratios;\n    if (lod < 0) lod = 0;\n\n    for (int i = 0; i <= lod; i++) {\n        struct stat statbuf;\n        if (stat(paths[i].c_str(), &statbuf) < 0) return (false);\n    }\n    return (true);\n}\n\nint VDCNetCDF::SetFill(int fillmode)\n{\n    int last;\n    int ret = ((NetCDFCpp *)_master)->SetFill(fillmode, last);\n    return ret;\n}\n\nint VDCNetCDF::_WriteMasterMeta()\n{\n    int                                    rc;\n    map<string, Dimension>::const_iterator itr;\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) {\n        const Dimension &dimension = itr->second;\n\n        rc = _master->DefDim(dimension.GetName(), dimension.GetLength());\n        if (rc < 0) return (-1);\n    }\n\n    rc = _master->PutAtt(\"\", \"VDC.Version\", Version::GetVersionString());\n    if (rc < 0) return (rc);\n\n    rc = _master->PutAtt(\"\", \"VDC.BlockSize\", _bs);\n    if (rc < 0) return (rc);\n\n    rc = _master->PutAtt(\"\", \"VDC.WaveName\", _wname);\n    if (rc < 0) return (rc);\n\n    rc = _master->PutAtt(\"\", \"VDC.CompressionRatios\", _cratios);\n    if (rc < 0) return (rc);\n\n    rc = _master->PutAtt(\"\", \"VDC.MasterThreshold\", _master_threshold);\n    if (rc < 0) return (rc);\n\n    rc = _master->PutAtt(\"\", \"VDC.VariableThreshold\", _variable_threshold);\n    if (rc < 0) return (rc);\n\n    vector<int> periodic;\n    for (int i = 0; i < _periodic.size(); i++) { periodic.push_back((int)_periodic[i]); }\n    rc = _master->PutAtt(\"\", \"VDC.Periodic\", periodic);\n    if (rc < 0) return (rc);\n\n    rc = _WriteMasterDimensions();\n    if (rc < 0) return (rc);\n\n    rc = _WriteMasterAttributes();\n    if (rc < 0) return (rc);\n\n    rc = _WriteMasterMeshDefs();\n    if (rc < 0) return (rc);\n\n    rc = _WriteMasterCoordVarsDefs();\n    if (rc < 0) return (rc);\n\n    rc = _WriteMasterDataVarsDefs();\n    if (rc < 0) return (rc);\n\n    rc = _master->EndDef();\n    if (rc < 0) return (rc);\n\n    return (0);\n}\n\nint VDCNetCDF::_ReadMasterMeta()\n{\n    int rc = _master->Open(_master_path, 0);\n    if (rc < 0) return (-1);\n\n    rc = _master->GetAtt(\"\", \"VDC.Version\", _version);\n    if (rc < 0) {\n        SetErrMsg(\"VDC versions prior to 3.0.0 not supported\");\n        return (rc);\n    }\n\n    if (Version::Compare(_version, \"3.0.0\") < 0) {\n        SetErrMsg(\"VDC versions prior to 3.0.0 not supported\");\n        return (-1);\n    }\n\n    rc = _master->GetAtt(\"\", \"VDC.BlockSize\", _bs);\n    if (rc < 0) return (rc);\n\n    rc = _master->GetAtt(\"\", \"VDC.WaveName\", _wname);\n    if (rc < 0) return (rc);\n\n    rc = _master->GetAtt(\"\", \"VDC.CompressionRatios\", _cratios);\n    if (rc < 0) return (rc);\n    sort(_cratios.begin(), _cratios.end());\n    reverse(_cratios.begin(), _cratios.end());\n\n    rc = _master->GetAtt(\"\", \"VDC.MasterThreshold\", _master_threshold);\n    if (rc < 0) return (rc);\n\n    rc = _master->GetAtt(\"\", \"VDC.VariableThreshold\", _variable_threshold);\n    if (rc < 0) return (rc);\n\n    vector<int> periodic;\n    rc = _master->GetAtt(\"\", \"VDC.Periodic\", periodic);\n\n    _periodic.clear();\n    for (int i = 0; i < periodic.size(); i++) { _periodic.push_back((bool)periodic[i]); }\n    if (rc < 0) return (rc);\n\n    rc = _ReadMasterDimensions();\n    if (rc < 0) return (rc);\n\n    rc = _ReadMasterAttributes();\n    if (rc < 0) return (rc);\n\n    rc = _ReadMasterMeshDefs();\n    if (rc < 0) return (rc);\n\n    rc = _ReadMasterCoordVarsDefs();\n    if (rc < 0) return (rc);\n\n    rc = _ReadMasterDataVarsDefs();\n    if (rc < 0) return (rc);\n\n    return (0);\n}\n\nint VDCNetCDF::_ReadMasterDimensions()\n{\n    _dimsMap.clear();\n\n    string         tag = \"VDC.DimensionNames\";\n    vector<string> dimnames;\n    int            rc = _master->GetAtt(\"\", tag, dimnames);\n    if (rc < 0) return (rc);\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        tag = \"VDC.Dimension.\" + dimnames[i] + \".Length\";\n        int length;\n        rc = _master->GetAtt(\"\", tag, length);\n        if (rc < 0) return (rc);\n\n        _dimsMap[dimnames[i]] = VDC::Dimension(dimnames[i], (size_t)length);\n    }\n    return (0);\n}\n\nint VDCNetCDF::_ReadMasterAttributes(string prefix, map<string, Attribute> &atts)\n{\n    atts.clear();\n\n    string         tag = prefix + \".AttributeNames\";\n    vector<string> attnames;\n    int            rc = _master->GetAtt(\"\", tag, attnames);\n    if (rc < 0) return (rc);\n\n    for (int i = 0; i < attnames.size(); i++) {\n        tag = prefix + \".Attribute.\" + attnames[i] + \".XType\";\n        int typetmp = -1;\n        rc = _master->GetAtt(\"\", tag, typetmp);\n        VDC::XType xtype;\n        if (rc < 0)\n            return (rc);\n        else\n            xtype = (VAPoR::DC::XType)typetmp;\n\n        tag = prefix + \".Attribute.\" + attnames[i] + \".Values\";\n        switch (xtype) {\n        case FLOAT:\n        case DOUBLE: {\n            vector<double> values;\n            rc = _master->GetAtt(\"\", tag, values);\n            if (rc < 0) return (rc);\n            VDC::Attribute attr(attnames[i], xtype, values);\n            atts[attnames[i]] = attr;\n\n            break;\n        }\n        case UINT8:\n        case INT8:\n        case INT32:\n        case INT64: {\n            vector<int> values;\n            rc = _master->GetAtt(\"\", tag, values);\n            if (rc < 0) return (rc);\n            VDC::Attribute attr(attnames[i], xtype, values);\n            atts[attnames[i]] = attr;\n            break;\n        }\n        case TEXT: {\n            string values;\n            rc = _master->GetAtt(\"\", tag, values);\n            if (rc < 0) return (rc);\n            VDC::Attribute attr(attnames[i], xtype, values);\n            atts[attnames[i]] = attr;\n            break;\n        }\n        default:\n            SetErrMsg(\"Invalid attribute xtype : %d\", xtype);\n            return (-1);\n            break;\n        }\n    }\n    return (0);\n}\n\nint VDCNetCDF::_ReadMasterAttributes()\n{\n    string prefix = \"VDC\";\n    return (_ReadMasterAttributes(prefix, _atts));\n}\n\nint VDCNetCDF::_ReadMasterMeshDefs()\n{\n    string         tag = \"VDC.MeshNames\";\n    vector<string> mesh_names;\n    int            rc = _master->GetAtt(\"\", tag, mesh_names);\n    if (rc < 0) return (rc);\n\n    // Only support STRUCTURED meshes currently\n    //\n    string prefix = \"VDC.Mesh\";\n    for (int i = 0; i < mesh_names.size(); i++) {\n        tag = prefix + \".\" + mesh_names[i] + \".DimensionNames\";\n        vector<string> dim_names;\n        int            rc = _master->GetAtt(\"\", tag, dim_names);\n        if (rc < 0) return (rc);\n\n        tag = prefix + \".\" + mesh_names[i] + \".CoordVars\";\n        vector<string> coord_vars;\n        rc = _master->GetAtt(\"\", tag, coord_vars);\n        if (rc < 0) return (rc);\n\n        _meshes[mesh_names[i]] = Mesh(mesh_names[i], dim_names, coord_vars);\n    }\n\n    return (0);\n}\n\nint VDCNetCDF::_ReadMasterBaseVarDefs(string prefix, BaseVar &var)\n{\n    string tag;\n\n    tag = prefix + \".\" + var.GetName() + \".Units\";\n    string units;\n    int    rc = _master->GetAtt(\"\", tag, units);\n    if (rc < 0) return (rc);\n    var.SetUnits(units);\n\n    tag = prefix + \".\" + var.GetName() + \".XType\";\n    int xtype;\n    rc = _master->GetAtt(\"\", tag, xtype);\n    if (rc < 0) return (rc);\n    var.SetXType((VAPoR::VDC::XType)xtype);\n\n    tag = prefix + \".\" + var.GetName() + \".Periodic\";\n    vector<int> iperiodic;\n    rc = _master->GetAtt(\"\", tag, iperiodic);\n    vector<bool> periodic;\n    for (int i = 0; i < iperiodic.size(); i++) periodic.push_back(iperiodic[i]);\n    if (rc < 0) return (rc);\n    var.SetPeriodic(periodic);\n\n    tag = prefix + \".\" + var.GetName() + \".WaveName\";\n    string wname;\n    rc = _master->GetAtt(\"\", tag, wname);\n    if (rc < 0) return (rc);\n    var.SetWName(wname);\n\n    tag = prefix + \".\" + var.GetName() + \".CompressionRatios\";\n    vector<size_t> cratios;\n    rc = _master->GetAtt(\"\", tag, cratios);\n    if (rc < 0) return (rc);\n    var.SetCRatios(cratios);\n\n    prefix += \".\" + var.GetName();\n    map<string, Attribute> atts;\n    rc = _ReadMasterAttributes(prefix, atts);\n    if (rc < 0) return (rc);\n\n    var.SetAttributes(atts);\n    return (0);\n}\n\nint VDCNetCDF::_ReadMasterCoordVarsDefs()\n{\n    _coordVars.clear();\n\n    string         tag = \"VDC.CoordVarNames\";\n    vector<string> varnames;\n    int            rc = _master->GetAtt(\"\", tag, varnames);\n    if (rc < 0) return (rc);\n\n    string prefix = \"VDC.CoordVar\";\n    for (int i = 0; i < varnames.size(); i++) {\n        CoordVar cvar;\n        cvar.SetName(varnames[i]);\n\n        tag = prefix + \".\" + cvar.GetName() + \".DimensionNames\";\n        vector<string> dim_names;\n        int            rc = _master->GetAtt(\"\", tag, dim_names);\n        if (rc < 0) return (rc);\n        cvar.SetDimNames(dim_names);\n\n        tag = prefix + \".\" + cvar.GetName() + \".TimeDimName\";\n        string time_dim_name;\n        rc = _master->GetAtt(\"\", tag, time_dim_name);\n        if (rc < 0) return (rc);\n        cvar.SetTimeDimName(time_dim_name);\n\n        tag = prefix + \".\" + cvar.GetName() + \".Axis\";\n        int axis;\n        rc = _master->GetAtt(\"\", tag, axis);\n        if (rc < 0) return (rc);\n        cvar.SetAxis(axis);\n\n        tag = prefix + \".\" + cvar.GetName() + \".UniformHint\";\n        int uniform;\n        rc = _master->GetAtt(\"\", tag, uniform);\n        if (rc < 0) return (rc);\n        cvar.SetUniform(uniform);\n\n        rc = _ReadMasterBaseVarDefs(prefix, cvar);\n        if (rc < 0) return (rc);\n\n        _coordVars[varnames[i]] = cvar;\n    }\n    return (0);\n}\n\nint VDCNetCDF::_ReadMasterDataVarsDefs()\n{\n    string         tag = \"VDC.DataVarNames\";\n    vector<string> varnames;\n    int            rc = _master->GetAtt(\"\", tag, varnames);\n    if (rc < 0) return (rc);\n\n    string prefix = \"VDC.DataVar\";\n    for (int i = 0; i < varnames.size(); i++) {\n        DataVar var;\n        var.SetName(varnames[i]);\n\n        tag = prefix + \".\" + var.GetName() + \".Mesh\";\n        string mesh_name;\n        rc = _master->GetAtt(\"\", tag, mesh_name);\n        if (rc < 0) return (rc);\n        var.SetMeshName(mesh_name);\n\n        tag = prefix + \".\" + var.GetName() + \".TimeCoordVar\";\n        string time_coord_var;\n        int    rc = _master->GetAtt(\"\", tag, time_coord_var);\n        if (rc < 0) return (rc);\n        var.SetTimeCoordVar(time_coord_var);\n\n        tag = prefix + \".\" + var.GetName() + \".MaskVar\";\n        string maskvar;\n        rc = _master->GetAtt(\"\", tag, maskvar);\n        if (rc < 0) return (rc);\n        var.SetMaskvar(maskvar);\n\n        tag = prefix + \".\" + var.GetName() + \".MissingValue\";\n        if (_master->InqAttDefined(\"\", tag)) {\n            double mv;\n            rc = _master->GetAtt(\"\", tag, mv);\n            if (rc < 0) return (rc);\n            var.SetHasMissing(true);\n            var.SetMissingValue(mv);\n        }\n\n        rc = _ReadMasterBaseVarDefs(prefix, var);\n        if (rc < 0) return (rc);\n\n        _dataVars[varnames[i]] = var;\n    }\n    return (0);\n}\n\nint VDCNetCDF::_WriteMasterDimensions()\n{\n    map<string, Dimension>::const_iterator itr;\n    string                                 s;\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) {\n        s += itr->first;\n        s += \" \";\n    }\n    string tag = \"VDC.DimensionNames\";\n    int    rc = _master->PutAtt(\"\", tag, s);\n    if (rc < 0) return (rc);\n\n    for (itr = _dimsMap.begin(); itr != _dimsMap.end(); ++itr) {\n        const Dimension &dimension = itr->second;\n\n        tag = \"VDC.Dimension.\" + dimension.GetName() + \".Length\";\n        rc = _master->PutAtt(\"\", tag, dimension.GetLength());\n        if (rc < 0) return (rc);\n    }\n    return (0);\n}\n\nint VDCNetCDF::_WriteMasterAttributes(string prefix, const map<string, Attribute> &atts)\n{\n    map<string, Attribute>::const_iterator itr;\n    string                                 s;\n    for (itr = atts.begin(); itr != atts.end(); ++itr) {\n        s += itr->first;\n        s += \" \";\n    }\n    string tag = prefix + \".AttributeNames\";\n    int    rc = _master->PutAtt(\"\", tag, s);\n    if (rc < 0) return (rc);\n\n    for (itr = atts.begin(); itr != atts.end(); ++itr) {\n        const Attribute &attr = itr->second;\n\n        tag = prefix + \".Attribute.\" + attr.GetName() + \".XType\";\n        rc = _master->PutAtt(\"\", tag, attr.GetXType());\n        if (rc < 0) return (rc);\n\n        tag = prefix + \".Attribute.\" + attr.GetName() + \".Values\";\n\n        rc = _PutAtt(_master, \"\", tag, attr);\n        if (rc < 0) return (rc);\n    }\n    return (0);\n}\n\nint VDCNetCDF::_WriteMasterAttributes()\n{\n    string prefix = \"VDC\";\n    return (_WriteMasterAttributes(prefix, _atts));\n}\n\nint VDCNetCDF::_WriteMasterBaseVarDefs(string prefix, const BaseVar &var)\n{\n    string tag;\n\n    tag = prefix + \".\" + var.GetName() + \".Units\";\n    int rc = _master->PutAtt(\"\", tag, var.GetUnits());\n    if (rc < 0) return (rc);\n\n    tag = prefix + \".\" + var.GetName() + \".XType\";\n    rc = _master->PutAtt(\"\", tag, (int)var.GetXType());\n    if (rc < 0) return (rc);\n\n    tag = prefix + \".\" + var.GetName() + \".Periodic\";\n    vector<bool> periodic = var.GetPeriodic();\n    vector<int>  iperiodic;\n    for (int i = 0; i < periodic.size(); i++) iperiodic.push_back(periodic[i]);\n    rc = _master->PutAtt(\"\", tag, iperiodic);\n    if (rc < 0) return (rc);\n\n    tag = prefix + \".\" + var.GetName() + \".WaveName\";\n    rc = _master->PutAtt(\"\", tag, var.GetWName());\n    if (rc < 0) return (rc);\n\n    tag = prefix + \".\" + var.GetName() + \".CompressionRatios\";\n    rc = _master->PutAtt(\"\", tag, var.GetCRatios());\n    if (rc < 0) return (rc);\n\n    prefix += \".\" + var.GetName();\n    return (_WriteMasterAttributes(prefix, var.GetAttributes()));\n}\n\nint VDCNetCDF::_WriteMasterMeshDefs()\n{\n    map<string, Mesh>::const_iterator itr;\n    string                            s;\n    for (itr = _meshes.begin(); itr != _meshes.end(); ++itr) {\n        s += itr->first;\n        s += \" \";\n    }\n\n    string tag = \"VDC.MeshNames\";\n    int    rc = _master->PutAtt(\"\", tag, s);\n    if (rc < 0) return (rc);\n\n    string prefix = \"VDC.Mesh\";\n\n    for (itr = _meshes.begin(); itr != _meshes.end(); ++itr) {\n        const Mesh &m = itr->second;\n\n        tag = prefix + \".\" + m.GetName() + \".DimensionNames\";\n        vector<string> dim_names = m.GetDimNames();\n        string         s;\n        for (int i = 0; i < dim_names.size(); i++) {\n            s += dim_names[i];\n            s += \" \";\n        }\n\n        int rc = _master->PutAtt(\"\", tag, s);\n        if (rc < 0) return (rc);\n\n        tag = prefix + \".\" + m.GetName() + \".CoordVars\";\n        vector<string> coord_vars = m.GetCoordVars();\n        s.clear();\n        for (int i = 0; i < coord_vars.size(); i++) {\n            s += coord_vars[i];\n            s += \" \";\n        }\n\n        rc = _master->PutAtt(\"\", tag, s);\n        if (rc < 0) return (rc);\n    }\n\n    return (0);\n}\n\nint VDCNetCDF::_WriteMasterCoordVarsDefs()\n{\n    map<string, CoordVar>::const_iterator itr;\n    string                                s;\n    for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) {\n        s += itr->first;\n        s += \" \";\n    }\n\n    string tag = \"VDC.CoordVarNames\";\n    int    rc = _master->PutAtt(\"\", tag, s);\n    if (rc < 0) return (rc);\n\n    string prefix = \"VDC.CoordVar\";\n    for (itr = _coordVars.begin(); itr != _coordVars.end(); ++itr) {\n        const CoordVar &cvar = itr->second;\n\n        int rc;\n        if (_var_in_master(cvar)) {\n            size_t numts = VDC::GetNumTimeSteps(cvar.GetName());\n            rc = _DefCoordVar(_master, cvar, numts);\n            if (rc < 0) return (-1);\n        }\n\n        tag = prefix + \".\" + cvar.GetName() + \".DimensionNames\";\n        vector<string> dim_names = cvar.GetDimNames();\n        string         s;\n        for (int i = 0; i < dim_names.size(); i++) {\n            s += dim_names[i];\n            s += \" \";\n        }\n\n        rc = _master->PutAtt(\"\", tag, s);\n        if (rc < 0) return (rc);\n\n        tag = prefix + \".\" + cvar.GetName() + \".TimeDimName\";\n        rc = _master->PutAtt(\"\", tag, cvar.GetTimeDimName());\n        if (rc < 0) return (rc);\n\n        tag = prefix + \".\" + cvar.GetName() + \".Axis\";\n        rc = _master->PutAtt(\"\", tag, cvar.GetAxis());\n        if (rc < 0) return (rc);\n\n        tag = prefix + \".\" + cvar.GetName() + \".UniformHint\";\n        rc = _master->PutAtt(\"\", tag, (int)cvar.GetUniform());\n        if (rc < 0) return (rc);\n\n        rc = _WriteMasterBaseVarDefs(prefix, cvar);\n        if (rc < 0) return (rc);\n    }\n    return (0);\n}\n\nint VDCNetCDF::_WriteMasterDataVarsDefs()\n{\n    map<string, DataVar>::const_iterator itr;\n    string                               s;\n    for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) {\n        s += itr->first;\n        s += \" \";\n    }\n\n    string tag = \"VDC.DataVarNames\";\n    int    rc = _master->PutAtt(\"\", tag, s);\n    if (rc < 0) return (rc);\n\n    string prefix = \"VDC.DataVar\";\n    for (itr = _dataVars.begin(); itr != _dataVars.end(); ++itr) {\n        const DataVar &var = itr->second;\n\n        if (_var_in_master(var)) {\n            size_t numts = VDC::GetNumTimeSteps(var.GetName());\n            rc = _DefDataVar(_master, var, numts);\n            if (rc < 0) return (-1);\n        }\n\n        tag = prefix + \".\" + var.GetName() + \".Mesh\";\n        int rc = _master->PutAtt(\"\", tag, var.GetMeshName());\n        if (rc < 0) return (rc);\n\n        tag = prefix + \".\" + var.GetName() + \".TimeCoordVar\";\n        rc = _master->PutAtt(\"\", tag, var.GetTimeCoordVar());\n        if (rc < 0) return (rc);\n\n        tag = prefix + \".\" + var.GetName() + \".MaskVar\";\n        rc = _master->PutAtt(\"\", tag, var.GetMaskvar());\n        if (rc < 0) return (rc);\n\n        if (var.GetHasMissing()) {\n            tag = prefix + \".\" + var.GetName() + \".MissingValue\";\n            rc = _master->PutAtt(\"\", tag, var.GetMissingValue());\n            if (rc < 0) return (rc);\n        }\n\n        rc = _WriteMasterBaseVarDefs(prefix, var);\n        if (rc < 0) return (rc);\n    }\n    return (0);\n}\n\nint VDCNetCDF::_DefBaseVar(WASP *wasp, const VDC::BaseVar &var, size_t max_ts)\n{\n    vector<VDC::Dimension> dims;\n    bool                   status = GetVarDimensions(var.GetName(), false, dims, -1);\n    VAssert(status);\n\n    bool time_varying = IsTimeVarying(var.GetName());\n\n    vector<string> dimnames;\n    for (int i = 0; i < dims.size(); i++) {\n        size_t len = dims[i].GetLength();\n\n        // If data are split across files need to set the time dimension\n        // to the number of time steps in the file\n        //\n        if (i == dims.size() - 1 && time_varying) { len = max_ts; }\n\n        // Don't define same dimension twice\n        //\n        if (!wasp->InqDimDefined(dims[i].GetName())) {\n            int rc = wasp->DefDim(dims[i].GetName(), len);\n            if (rc < 0) return (-1);\n        }\n\n        dimnames.push_back(dims[i].GetName());\n    }\n    reverse(dimnames.begin(), dimnames.end());    // NetCDF order\n\n    size_t nspatial = time_varying ? dimnames.size() - 1 : dimnames.size();\n\n    // Only spatial dimensions are blocked\n    //\n    vector<size_t> bs = _bs;\n    while (bs.size() > nspatial) { bs.pop_back(); }\n    reverse(bs.begin(), bs.end());    // NetCDF order\n    int rc = wasp->DefVar(var.GetName(), vdc_xtype2ncdf_xtype(var.GetXType()), dimnames, var.GetWName(), bs, var.GetCRatios());\n    if (rc < 0) return (-1);\n\n    //\n    // Attributes\n    //\n\n    rc = wasp->PutAtt(var.GetName(), \"Units\", var.GetUnits());\n    if (rc < 0) return (rc);\n\n    rc = wasp->PutAtt(var.GetName(), \"BlockSize\", bs);\n    if (rc < 0) return (rc);\n\n    vector<bool> periodic = var.GetPeriodic();\n    vector<int>  iperiodic;\n    for (int i = 0; i < periodic.size(); i++) iperiodic.push_back(periodic[i]);\n    rc = wasp->PutAtt(var.GetName(), \"Periodic\", iperiodic);\n    if (rc < 0) return (rc);\n\n    const map<string, Attribute> &         atts = var.GetAttributes();\n    map<string, Attribute>::const_iterator itr;\n    for (itr = atts.begin(); itr != atts.end(); ++itr) {\n        const Attribute &attr = itr->second;\n\n        rc = _PutAtt(wasp, var.GetName(), \"\", attr);\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\nint VDCNetCDF::_WriteAttributes(WASP *wasp, string varname, const map<string, Attribute> &atts)\n{\n    map<string, Attribute>::const_iterator itr;\n    for (itr = _atts.begin(); itr != _atts.end(); ++itr) {\n        const Attribute &attr = itr->second;\n\n        int rc = _PutAtt(wasp, varname, attr.GetName(), attr);\n        if (rc < 0) return (rc);\n    }\n    return (0);\n}\n\nint VDCNetCDF::_DefDataVar(WASP *wasp, const VDC::DataVar &var, size_t max_ts)\n{\n    int rc = _DefBaseVar(wasp, var, max_ts);\n    if (rc < 0) return (-1);\n\n    vector<string> coord_vars;\n    bool           status = GetVarCoordVars(var.GetName(), false, coord_vars);\n    VAssert(status);\n\n    rc = wasp->PutAtt(var.GetName(), \"CoordVars\", coord_vars);\n    if (rc < 0) return (-1);\n\n    rc = wasp->PutAtt(var.GetName(), \"MaskVar\", var.GetMaskvar());\n\n    if (var.GetHasMissing()) {\n        rc = wasp->PutAtt(var.GetName(), \"MissingValue\", var.GetMissingValue());\n        if (rc < 0) return (rc);\n    }\n\n    return (rc);\n}\n\nint VDCNetCDF::_DefCoordVar(WASP *wasp, const VDC::CoordVar &var, size_t max_ts)\n{\n    int rc = _DefBaseVar(wasp, var, max_ts);\n    if (rc < 0) return (-1);\n\n    rc = wasp->PutAtt(var.GetName(), \"Axis\", var.GetAxis());\n    if (rc < 0) return (-1);\n\n    rc = wasp->PutAtt(var.GetName(), \"UniformHint\", var.GetUniform());\n\n    return (rc);\n}\n\nint VDCNetCDF::_PutAtt(WASP *wasp, string varname, string tag, const Attribute &attr)\n{\n    if (tag.empty()) tag = attr.GetName();\n\n    DC::XType xtype = attr.GetXType();\n\n    // Ugh. For the special attributes missing_value and _FillValue\n    // the type must match that of the data. Since currently the only\n    // output format we support is float we must force the type of\n    // these attributes to float.\n    //\n    if (tag == \"missing_value\" || tag == \"_FillValue\") { xtype = FLOAT; }\n\n    int rc;\n    switch (xtype) {\n    case FLOAT:\n    case DOUBLE: {\n        vector<double> values;\n        attr.GetValues(values);\n        rc = wasp->PutAtt(varname, tag, values);\n        if (rc < 0) return (rc);\n        break;\n    }\n    case UINT8:\n    case INT8:\n    case INT32:\n    case INT64: {\n        vector<int> values;\n        attr.GetValues(values);\n        rc = wasp->PutAtt(varname, tag, values);\n        if (rc < 0) return (rc);\n        break;\n    }\n    case TEXT: {\n        string values;\n        attr.GetValues(values);\n        rc = wasp->PutAtt(varname, tag, values);\n        if (rc < 0) return (rc);\n        break;\n    }\n    default:\n        SetErrMsg(\"Invalid value, Attribute::GetXType() : %d\", attr.GetXType());\n        return (-1);\n        break;\n    }\n\n    return (0);\n}\n\nbool VDCNetCDF::_var_in_master(const VDC::BaseVar &var) const\n{\n    vector<DC::Dimension> dims;\n    bool                  ok = GetVarDimensions(var.GetName(), false, dims, -1);\n    VAssert(ok);\n\n    bool time_varying = IsTimeVarying(var.GetName());\n\n    if (time_varying && dims.size() > 3) return (false);\n\n    size_t nelements = 1;\n    for (int i = 0; i < dims.size(); i++) {\n        nelements *= dims[i].GetLength();\n    }\n    if (nelements < _master_threshold && !var.IsCompressed()) { return (true); }\n\n    return (false);\n}\n"
  },
  {
    "path": "lib/vdc/VDC_c.cpp",
    "content": "#include <string>\n#include <vector>\n#include <map>\n#include \"vapor/VDC.h\"\n#include \"vapor/VDCNetCDF.h\"\n#include \"vapor/VDC_c.h\"\n#include \"vapor/MyBase.h\"\n\n// __attribute__ not valid in VisualC++\n#ifdef WIN32\n    #define __attribute__(x)\n#endif\n\n// #define VDC_DEBUG\n// #define VDC_DEBUG_CPP_RUN\n// #define VDC_DEBUG_RUN\n// #define VDC_DEBUG_RUN_WRITE_ONLY\n\n#ifdef VDC_DEBUG\n    #include <unistd.h>\n\n    #ifdef VDC_DEBUG_RUN\n        #define VDC_DEBUG_coloredLocation(color) \\\n            {                                    \\\n            }\n    #else\n        #define VDC_DEBUG_coloredLocation(color)                                        \\\n            {                                                                           \\\n                const char *colorPre = \"\", *colorPost = \"\";                             \\\n                if (isatty(fileno(stderr))) {                                           \\\n                    colorPre = \"\\x1b[\" #color \"m\";                                      \\\n                    colorPost = \"\\x1b[0m\";                                              \\\n                }                                                                       \\\n                fprintf(stderr, \"%s[VDC_c.cpp:%03i]%s\", colorPre, __LINE__, colorPost); \\\n            }\n    #endif\n\n    #define VDC_DEBUG_coloredLocation_standard() VDC_DEBUG_coloredLocation(34);\n    #define VDC_DEBUG_coloredLocation_error()    VDC_DEBUG_coloredLocation(31);\n    #define VDC_DEBUG_func()                     fprintf(stderr, \"%s\", __func__);\n    #define VDC_DEBUG_printf(...)                fprintf(stderr, __VA_ARGS__)\n    #define VDC_DEBUG_printff(...)                \\\n        {                                         \\\n            VDC_DEBUG_coloredLocation_standard(); \\\n            VDC_DEBUG_func();                     \\\n            fprintf(stderr, __VA_ARGS__);         \\\n        }\n    #define VDC_DEBUG_printff_error(...)       \\\n        {                                      \\\n            VDC_DEBUG_coloredLocation_error(); \\\n            VDC_DEBUG_func();                  \\\n            fprintf(stderr, __VA_ARGS__);      \\\n        }\n    #define VDC_DEBUG_called() VDC_DEBUG_printff(\"();\\n\")\n\n    #ifdef VDC_DEBUG_RUN\n        #define VDC_DEBUG_printff_nRun(...) \\\n            {                               \\\n            }\n        #define VDC_DEBUG_called_nRun() \\\n            {                           \\\n            }\n    #else\n        #define VDC_DEBUG_printff_nRun(...) VDC_DEBUG_printff(__VA_ARGS__)\n        #define VDC_DEBUG_called_nRun()     VDC_DEBUG_called()\n    #endif\n\n    #ifdef VDC_DEBUG_RUN_WRITE_ONLY\n        #define VDC_DEBUG_printff_readF(...) \\\n            {                                \\\n            }\n        #define VDC_DEBUG_called_readF() \\\n            {                            \\\n            }\n    #else\n        #define VDC_DEBUG_printff_readF(...) VDC_DEBUG_printff(__VA_ARGS__)\n        #define VDC_DEBUG_called_readF()     VDC_DEBUG_called()\n    #endif\n\n    #include <signal.h>\n    #define VDC_DEBUG_break() raise(SIGINT)\n#else\n\n    #define VDC_DEBUG_printf(...) \\\n        {                         \\\n        }\n    #define VDC_DEBUG_printff(...) \\\n        {                          \\\n        }\n    #define VDC_DEBUG_printff_error(...) \\\n        {                                \\\n        }\n    #define VDC_DEBUG_called() \\\n        {                      \\\n        }\n    #define VDC_DEBUG_break() \\\n        {                     \\\n        }\n    #define VDC_DEBUG_printff_readF(...) \\\n        {                                \\\n        }\n    #define VDC_DEBUG_called_readF() \\\n        {                            \\\n        }\n    #define VDC_DEBUG_printff_nRun(...) \\\n        {                               \\\n        }\n    #define VDC_DEBUG_called_nRun() \\\n        {                           \\\n        }\n\n#endif\n\nusing std::string;\nusing std::vector;\n\nvoid        _stringToCString(const string s, char **str);\nvoid        _stringVectorToCStringArray(const vector<string> v, char ***str, int *count);\nvoid        _longVectorToCArray(const vector<long> v, long **data, int *count);\nvoid        _boolVectorToCArray(const vector<bool> v, long **data, int *count);\nvoid        _doubleVectorToCArray(const vector<double> v, double **data, int *count);\nvoid        _size_tVectorToCArray(const vector<size_t> v, size_t **data, int *count);\nint         _XTypeToInt(const VDC::XType type);\nVDC::XType  _IntToXType(int type);\nconst char *_XTypeToString(const VDC::XType type);\nconst char *_XTypeToIntCodeString(const VDC::XType type);\nconst char *_boolToStr(const int b);\nconst char *_AxisToStr(const int a);\nconst char *_accessModeToStr(const int m);\nconst char *_VDCPToStr(const VDC *p);\n\nvector<string> _strArrayToStringVector(const char **a, size_t count);\nstring         _stringVectorToString(const vector<string> v);\nstring         _strArrayToString(const char **a, size_t count);\nvector<size_t> _size_tArrayToSize_tVector(const size_t *a, size_t count);\nstring         _size_tVectorToString(const vector<size_t> v);\nstring         _size_tArrayToString(const size_t *a, size_t count);\n#ifdef VDC_DEBUG\nstatic string valueCArrayToString(const void *a, int l, VDC_XType type) __attribute__((unused));\n#endif\n\n// ########################\n// #    VDC::Dimension    #\n// ########################\n\nVDCDimension *VDCDimension_new() { return new VDCDimension(); }\nvoid          VDCDimension_delete(VDCDimension *p) { delete p; }\nvoid          VDCDimension_GetName(const VDCDimension *p, char **name) { _stringToCString(p->GetName(), name); }\nsize_t        VDCDimension_GetLength(const VDCDimension *p) { return p->GetLength(); }\nint           VDCDimension_IsTimeVarying(const VDCDimension *p) { return p->IsTimeVarying(); }\n\n// ########################\n// #     VDC::BaseVar     #\n// ########################\n\nVDCBaseVar *VDCBaseVar_new() { return new VDCBaseVar(); }\nvoid        VDCBaseVar_delete(VDCBaseVar *p) { delete p; }\nvoid        VDCBaseVar_GetName(const VDCBaseVar *p, char **name) { _stringToCString(p->GetName(), name); }\nvoid        VDCBaseVar_GetUnits(const VDCBaseVar *p, char **units) { _stringToCString(p->GetUnits(), units); }\nint         VDCBaseVar_GetXType(const VDCBaseVar *p) { return _XTypeToInt(p->GetXType()); }\nvoid        VDCBaseVar_GetWName(const VDCBaseVar *p, char **name) { _stringToCString(p->GetWName(), name); }\nvoid        VDCBaseVar_GetCRatios(const VDCBaseVar *p, size_t **ratios, int *count) { _size_tVectorToCArray(p->GetCRatios(), ratios, count); }\nvoid        VDCBaseVar_GetPeriodic(const VDCBaseVar *p, long **periodic, int *count) { _boolVectorToCArray(p->GetPeriodic(), periodic, count); }\nvoid        VDCBaseVar_GetAttributeNames(const VDCBaseVar *p, char ***names, int *count)\n{\n    const std::map<string, VDC::Attribute>           attributes = p->GetAttributes();\n    vector<string>                                   names_v;\n    std::map<string, VDC::Attribute>::const_iterator it;\n    for (it = attributes.begin(); it != attributes.end(); it++) names_v.push_back(it->first);\n    _stringVectorToCStringArray(names_v, names, count);\n}\nint VDCBaseVar_IsCompressed(const VDCBaseVar *p) { return p->IsCompressed(); }\n\n// ########################\n// #     VDC::AuxVar     #\n// ########################\n\nVDCAuxVar *VDCAuxVar_new() { return new VDCAuxVar(); }\nvoid       VDCAuxVar_delete(VDCAuxVar *p) { delete p; }\nvoid       VDCAuxVar_GetDimNames(const VDCAuxVar *p, char ***names, int *count) { _stringVectorToCStringArray(p->GetDimNames(), names, count); }\n\n// ########################\n// #     VDC::DataVar     #\n// ########################\n\nVDCDataVar *VDCDataVar_new() { return new VDCDataVar(); }\nvoid        VDCDataVar_delete(VDCDataVar *p) { delete p; }\nvoid        VDCDataVar_GetMeshName(const VDCDataVar *p, char **name) { _stringToCString(p->GetMeshName(), name); }\nvoid        VDCDataVar_GetTimeCoordVar(const VDCDataVar *p, char **name) { _stringToCString(p->GetTimeCoordVar(), name); }\nvoid        VDCDataVar_GetMaskvar(const VDCDataVar *p, char **name) { _stringToCString(p->GetMaskvar(), name); }\nint         VDCDataVar_GetHasMissing(const VDCDataVar *p) { return p->GetHasMissing(); }\ndouble      VDCDataVar_GetMissingValue(const VDCDataVar *p) { return p->GetMissingValue(); }\n\n// ########################\n// #     VDC::CoordVar    #\n// ########################\n\nVDCCoordVar *VDCCoordVar_new() { return new VDCCoordVar(); }\nvoid         VDCCoordVar_delete(VDCCoordVar *p) { delete p; }\nvoid         VDCCoordVar_GetDimNames(const VDCCoordVar *p, char ***names, int *count) { _stringVectorToCStringArray(p->GetDimNames(), names, count); }\nvoid         VDCCoordVar_GetTimeDimName(const VDCCoordVar *p, char **name) { _stringToCString(p->GetTimeDimName(), name); }\nint          VDCCoordVar_GetAxis(const VDCCoordVar *p) { return p->GetAxis(); }\nint          VDCCoordVar_GetUniform(const VDCCoordVar *p) { return p->GetUniform(); }\n\n// ########################\n// #         VDC          #\n// ########################\n\nVDC *VDC_new()\n{\n    VDC_DEBUG_called_nRun();\n    return new VAPoR::VDCNetCDF();\n}\n\nvoid VDC_delete(VDC *p)\n{\n    VDC_DEBUG_printff_nRun(\"(%s);\\n\", _VDCPToStr(p));\n    delete p;\n}\n\nint VDC_InitializeDefaultBS(VDC *p, const char *path, int mode) { return VDC_Initialize(p, path, mode, NULL, 0); }\n\nint VDC_Initialize(VDC *p, const char *path, int mode, size_t *bs, int bsCount)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    if (bs != NULL && bsCount > 0) {\n        VDC_DEBUG_printff(\"(%s \\\"%s\\\", std::vector<std::string>(), %s, %s, 0);\\n\", _VDCPToStr(p), path, _accessModeToStr(mode), bs ? \"<bs[]>\" : \"NULL\");\n    } else {\n        VDC_DEBUG_printff(\"(%s \\\"%s\\\", std::vector<std::string>(), %s);\\n\", _VDCPToStr(p), path, _accessModeToStr(mode));\n    }\n#else\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %s, %s, %i);\\n\", _VDCPToStr(p), path, _accessModeToStr(mode), bs ? \"<bs[]>\" : \"NULL\", bsCount);\n#endif\n    VDC::AccessMode am = VDC::R;\n    if (mode == VDC_AccessMode_R)\n        am = VDC::R;\n    else if (mode == VDC_AccessMode_W)\n        am = VDC::W;\n    else if (mode == VDC_AccessMode_A)\n        am = VDC::A;\n\n    VAPoR::VDCNetCDF *pnc = (VAPoR::VDCNetCDF *)p;\n    int               ret;\n    if (bs != NULL && bsCount > 0) {\n        vector<size_t> bs_v = _size_tArrayToSize_tVector(bs, bsCount);\n        ret = pnc->Initialize(string(path), vector<string>(), am, bs_v, 0);\n    } else {\n        ret = pnc->Initialize(string(path), vector<string>(), am);\n    }\n    // pnc->SetFill(0x100); // Required to disable set_fill\n    return ret;\n}\n\nint VDC_GetDimension(const VDC *p, const char *dimname, VDCDimension *dimension)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", <VDCDimension *dimension>);\\n\", _VDCPToStr(p), dimname);\n    return p->GetDimension(string(dimname), *dimension, -1);\n}\n\nvoid VDC_GetDimensionNames(const VDC *p, char ***names, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s <***names>, <*count>);\\n\", _VDCPToStr(p));\n    _stringVectorToCStringArray(p->GetDimensionNames(), names, count);\n}\n\nint VDC_GetCoordVarInfo(const VDC *p, const char *varname, VDCCoordVar *var)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", <VDCCoordVar *var>);\\n\", _VDCPToStr(p), varname);\n    return p->GetCoordVarInfo(string(varname), *var);\n}\n\nint VDC_GetDataVarInfo(const VDC *p, const char *varname, VDCDataVar *var)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", <VDCDataVar *var>);\\n\", _VDCPToStr(p), varname);\n    return p->GetDataVarInfo(string(varname), *var);\n}\n\nint VDC_GetBaseVarInfo(const VDC *p, const char *varname, VDCBaseVar *var)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", <VDCBaseVar *var>);\\n\", _VDCPToStr(p), varname);\n    return p->GetBaseVarInfo(string(varname), *var);\n}\n\nvoid VDC_GetDataVarNames(const VDC *p, char ***names, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s <***names>, <*count>);\\n\", _VDCPToStr(p));\n    _stringVectorToCStringArray(p->GetDataVarNames(), names, count);\n}\n\nvoid VDC_GetCoordVarNames(const VDC *p, char ***names, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s <***names>, <*count>);\\n\", _VDCPToStr(p));\n    _stringVectorToCStringArray(p->GetCoordVarNames(), names, count);\n}\n\nint VDC_GetNumRefLevels(const VDC *p, const char *varname)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\");\\n\", _VDCPToStr(p), varname);\n    return p->GetNumRefLevels(string(varname));\n}\n\nint VDC_GetAtt_long(const VDC *p, const char *varname, const char *attname, long **values, int *count)\n{\n    VDC_DEBUG_called_readF();\n    vector<long> values_v;\n    bool         ret = p->GetAtt(string(varname), string(attname), values_v);\n    if (ret) _longVectorToCArray(values_v, values, count);\n\n    return ret;\n}\n\nint VDC_GetAtt_double(const VDC *p, const char *varname, const char *attname, double **values, int *count)\n{\n    VDC_DEBUG_called_readF();\n    vector<double> values_v;\n    bool           ret = p->GetAtt(string(varname), string(attname), values_v);\n    if (ret) _doubleVectorToCArray(values_v, values, count);\n\n    return ret;\n}\n\nint VDC_GetAtt_text(const VDC *p, const char *varname, const char *attname, char **text)\n{\n    VDC_DEBUG_called_readF();\n    string text_s;\n    bool   ret = p->GetAtt(string(varname), string(attname), text_s);\n    if (ret) _stringToCString(text_s, text);\n\n    return ret;\n}\n\nint VDC_GetAtt_Count(const VDC *p, const char *varname, const char *attname, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", \\\"%s\\\", <*count>);\\n\", _VDCPToStr(p), varname, attname);\n    VDC::XType type = p->GetAttType(string(varname), string(attname));\n    if (type < 0 || type == VDC::XType::INVALID) return 0;\n\n    if (type == VDC::XType::TEXT) {\n        *count = 1;\n    } else if (type == VDC::XType::FLOAT || type == VDC::XType::DOUBLE) {\n        vector<double> v;\n        p->GetAtt(string(varname), string(attname), v);\n        *count = v.size();\n    } else if (type == VDC::XType::INT32 || type == VDC::XType::INT64) {\n        vector<long> v;\n        p->GetAtt(string(varname), string(attname), v);\n        *count = v.size();\n    }\n    return 1;\n}\n\nvoid VDC_GetAttNames(const VDC *p, const char *varname, char ***names, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", <***names>, <*count>);\\n\", _VDCPToStr(p), varname);\n    _stringVectorToCStringArray(p->GetAttNames(string(varname)), names, count);\n}\n\nint VDC_GetAttType(const VDC *p, const char *varname, const char *attname)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", \\\"%s\\\");\\n\", _VDCPToStr(p), varname, attname);\n    return _XTypeToInt(p->GetAttType(string(varname), string(attname)));\n}\n\nint VDC_VariableExists(const VDC *p, size_t ts, const char *varname, int reflevel, int lod)\n{\n    VDC_DEBUG_printff_readF(\"(%s %li, \\\"%s\\\", %i, %i);\\n\", _VDCPToStr(p), ts, varname, reflevel, lod);\n    return p->VariableExists(ts, string(varname), reflevel, lod);\n}\n\nint VDC_IsTimeVarying(const VDC *p, const char *varname)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\");\\n\", _VDCPToStr(p), varname);\n    return p->IsTimeVarying(string(varname));\n}\n\nint VDC_CoordVarExists(const VDC *p, const char *varname)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\");\\n\", _VDCPToStr(p), varname);\n    VDCCoordVar v;\n    return p->GetCoordVarInfo(string(varname), v);\n}\n\nint VDC_GetCRatios(const VDC *p, const char *varname, size_t **ratios, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", <**ratios>, <*count>);\\n\", _VDCPToStr(p), varname);\n    VDCBaseVar v;\n    bool       ret = p->GetBaseVarInfo(string(varname), v);\n    if (ret) _size_tVectorToCArray(v.GetCRatios(), ratios, count);\n    return ret;\n}\n\nint VDC_GetCRatiosCount(const VDC *p, const char *varname)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\");\\n\", _VDCPToStr(p), varname);\n    VDCBaseVar v;\n    p->GetBaseVarInfo(string(varname), v);\n    return v.GetCRatios().size();\n}\n\nint VDC_GetVarDimLens(const VDC *p, const char *varname, int spatial, size_t **lens, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", %i, <**lens>, <*count>);\\n\", _VDCPToStr(p), varname, spatial);\n    vector<size_t> lens_v;\n    bool           ret = p->GetVarDimLens(string(varname), spatial, lens_v, -1);\n    if (ret) _size_tVectorToCArray(lens_v, lens, count);\n    return ret;\n}\n\nint VDC_GetVarDimNames(const VDC *p, const char *varname, int spatial, char ***names, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", %i, <***names>, <*count>);\\n\", _VDCPToStr(p), varname, spatial);\n    vector<string> names_v;\n    bool           ret = p->GetVarDimNames(string(varname), spatial, names_v);\n    if (ret) _stringVectorToCStringArray(names_v, names, count);\n\n    return ret;\n}\n\nint VDC_GetVarCoordVars(const VDC *p, const char *varname, int spatial, char ***names, int *count)\n{\n    VDC_DEBUG_printff_readF(\"(%s \\\"%s\\\", %i, <***names>, <*count>);\\n\", _VDCPToStr(p), varname, spatial);\n    vector<string> names_v;\n    bool           ret = p->GetVarCoordVars(string(varname), spatial, names_v);\n    if (ret) _stringVectorToCStringArray(names_v, names, count);\n\n    return ret;\n}\n\nint VDC_GetVarDimLensAtLevel(const VDC *p, const char *varname, int level, size_t **lens, int *count)\n{\n    VDC_DEBUG_called_readF();\n    vector<size_t> lens_v, bs_v;\n    bool           ret = p->GetDimLensAtLevel(string(varname), level, lens_v, bs_v, -1);\n    if (ret == 0) _size_tVectorToCArray(lens_v, lens, count);\n    return ret;\n}\n\nint VDC_OpenVariableRead(VDC *p, size_t ts, const char *varname, int level, int lod)\n{\n    VDC_DEBUG_printff(\"(%s %li, \\\"%s\\\", %i, %i);\\n\", _VDCPToStr(p), ts, varname, level, lod);\n    return p->OpenVariableRead(ts, string(varname), level, lod);\n}\n\nint VDC_CloseVariable(VDC *p, int fd)\n{\n    VDC_DEBUG_called();\n    return p->CloseVariable(fd);\n}\n\nint VDC_Read(VDC *p, int fd, float *region)\n{\n    VDC_DEBUG_called();\n    return p->Read(fd, region);\n}\n\nint VDC_ReadSlice(VDC *p, int fd, float *slice)\n{\n    VDC_DEBUG_called();\n    return p->ReadSlice(fd, slice);\n}\n\nint VDC_ReadRegion(VDC *p, int fd, const size_t *min, const size_t *max, const int dims, float *region)\n{\n    VDC_DEBUG_called();\n    vector<size_t> min_v;\n    vector<size_t> max_v;\n    for (int i = 0; i < dims; i++) {\n        min_v.push_back(min[i]);\n        max_v.push_back(max[i]);\n    }\n    return p->ReadRegion(fd, min_v, max_v, region);\n}\n\nint VDC_GetVar(VDC *p, const char *varname, int level, int lod, float *data)\n{\n    VDC_DEBUG_called();\n    return p->GetVar(string(varname), level, lod, data);\n}\n\nint VDC_GetVarAtTimeStep(VDC *p, size_t ts, const char *varname, int level, int lod, float *data)\n{\n    VDC_DEBUG_called();\n    return p->GetVar(ts, string(varname), level, lod, data);\n}\n\n// ########################\n// #        Write         #\n// ########################\n\nint VDC_SetCompressionBlock(VDC *p, const char *wname, const size_t *cratios, int cratiosCount)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %s);\\n\", _VDCPToStr(p), wname, _size_tArrayToString(cratios, cratiosCount).c_str());\n#else\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %s, %i);\\n\", _VDCPToStr(p), wname, _size_tArrayToString(cratios, cratiosCount).c_str(), cratiosCount);\n#endif\n    vector<size_t> cratios_v = _size_tArrayToSize_tVector(cratios, cratiosCount);\n    int            ret = p->SetCompressionBlock(string(wname), cratios_v);\n    return ret;\n}\n\nint VDC_DefineDimension(VDC *p, const char *dimname, size_t length)\n{\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %li);\\n\", _VDCPToStr(p), dimname, length);\n    return p->DefineDimension(string(dimname), length);\n}\n\nint VDC_DefineDimensionWithAxis(VDC *p, const char *dimname, size_t length, int axis)\n{\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %li, %s);\\n\", _VDCPToStr(p), dimname, length, _AxisToStr(axis));\n    return p->DefineDimension(string(dimname), length, axis);\n}\n\nint VDC_DefineDataVar(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char **coordvars, size_t coordvarsCount, const char *units, VDC_XType xtype, int compressed)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %s, %s, \\\"%s\\\", %s, %s);\\n\", _VDCPToStr(p), varname, _strArrayToString(dimnames, dimnamesCount).c_str(), _strArrayToString(coordvars, coordvarsCount).c_str(), units,\n                      _XTypeToIntCodeString(_IntToXType(xtype)), _boolToStr(compressed));\n#else\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %s, %li, %s, %li, \\\"%s\\\", %s, %s);\\n\", _VDCPToStr(p), varname, _strArrayToString(dimnames, dimnamesCount).c_str(), dimnamesCount,\n                      _strArrayToString(coordvars, coordvarsCount).c_str(), coordvarsCount, units, _XTypeToIntCodeString(_IntToXType(xtype)), _boolToStr(compressed));\n#endif\n    VDC_DEBUG_printff_nRun(\": Current dimensions = %s\\n\", _stringVectorToString(p->GetDimensionNames()).c_str());\n    VDC_DEBUG_printff_nRun(\": Current coordvars = %s\\n\", _stringVectorToString(p->GetCoordVarNames()).c_str());\n    VDC_DEBUG_printff_nRun(\": Current datavars = %s\\n\", _stringVectorToString(p->GetDataVarNames()).c_str());\n\n    for (int i = 0; i < coordvarsCount; i++) {\n        VDCCoordVar cv;\n        p->GetCoordVarInfo(coordvars[i], cv);\n        cout << cv;\n    }\n\n    vector<string> dimnames_v;\n    vector<string> coordvars_v;\n    for (int i = 0; i < dimnamesCount; i++) dimnames_v.push_back(string(dimnames[i]));\n    for (int i = 0; i < coordvarsCount; i++) coordvars_v.push_back(string(coordvars[i]));\n    VDC_DEBUG_printff_nRun(\": calling VDC::DefineDataVar(\\\"%s\\\", %s, %s, \\\"%s\\\", %s, %s);\\n\", varname, _stringVectorToString(dimnames_v).c_str(), _stringVectorToString(coordvars_v).c_str(), units,\n                           _XTypeToString(_IntToXType(xtype)), _boolToStr(compressed));\n    int ret = p->DefineDataVar(string(varname), dimnames_v, coordvars_v, string(units), _IntToXType(xtype), (bool)compressed);\n    VDC_DEBUG_printff_nRun(\": return (%i);\\n\", ret);\n    if (ret < 0) VDC_DEBUG_printff_error(\": Error message = \\\"%s\\\"\\n\", Wasp::MyBase::GetErrMsg());\n    VDC_DEBUG_printff_nRun(\": Current coordvars = %s\\n\", _stringVectorToString(p->GetCoordVarNames()).c_str());\n    return ret;\n}\n\nint VDC_DefineCoordVar(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char *time_dim_name, const char *units, int axis, VDC_XType xtype, int compressed)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %s, \\\"%s\\\", \\\"%s\\\", %s, %s, %s);\\n\", _VDCPToStr(p), varname, _strArrayToString(dimnames, dimnamesCount).c_str(), time_dim_name, units, _AxisToStr(axis),\n                      _XTypeToIntCodeString(_IntToXType(xtype)), _boolToStr(compressed));\n#else\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %s, %li, \\\"%s\\\", \\\"%s\\\", %s, %s, %s);\\n\", _VDCPToStr(p), varname, _strArrayToString(dimnames, dimnamesCount).c_str(), dimnamesCount, time_dim_name, units,\n                      _AxisToStr(axis), _XTypeToIntCodeString(_IntToXType(xtype)), _boolToStr(compressed));\n#endif\n    vector<string> dimnames_v;\n    for (int i = 0; i < dimnamesCount; i++) dimnames_v.push_back(string(dimnames[i]));\n    VDC_DEBUG_printff_nRun(\": calling VDC::DefineCoordVar(\\\"%s\\\", %s, \\\"%s\\\", \\\"%s\\\", %s, %s, %s);\\n\", varname, _stringVectorToString(dimnames_v).c_str(), time_dim_name, units, _AxisToStr(axis),\n                           _XTypeToString(_IntToXType(xtype)), _boolToStr(compressed));\n    return p->DefineCoordVar(string(varname), dimnames_v, string(time_dim_name), string(units), axis, _IntToXType(xtype), compressed);\n}\n\nint VDC_DefineCoordVarUniform(VDC *p, const char *varname, const char **dimnames, size_t dimnamesCount, const char *time_dim_name, const char *units, int axis, VDC_XType xtype, int compressed)\n{\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %s, %li, \\\"%s\\\", \\\"%s\\\", %s, %s, %s);\\n\", _VDCPToStr(p), varname, _stringVectorToString(_strArrayToStringVector(dimnames, dimnamesCount)).c_str(), dimnamesCount,\n                      time_dim_name, units, _AxisToStr(axis), _XTypeToString(_IntToXType(xtype)), _boolToStr(compressed));\n    vector<string> dimnames_v;\n    for (int i = 0; i < dimnamesCount; i++) dimnames_v.push_back(string(dimnames[i]));\n    VDC_DEBUG_printff_nRun(\": calling VDC::DefineCoordVarUniform(\\\"%s\\\", %s, \\\"%s\\\", \\\"%s\\\", %s, %s, %s);\\n\", varname, _stringVectorToString(dimnames_v).c_str(), time_dim_name, units,\n                           _AxisToStr(axis), _XTypeToString(_IntToXType(xtype)), _boolToStr(compressed));\n    return p->DefineCoordVarUniform(string(varname), dimnames_v, string(time_dim_name), string(units), axis, _IntToXType(xtype), compressed);\n}\n\nint VDC_PutAtt(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const void *values, size_t count)\n{\n    VDC_DEBUG_printff_nRun(\"(%s \\\"%s\\\", \\\"%s\\\", %s, <data>, %li);\\n\", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), count);\n    switch (xtype) {\n    case VDC_XType_FLOAT:\n    case VDC_XType_DOUBLE: return VDC_PutAtt_double(p, varname, attname, xtype, (const double *)values, count);\n    case VDC_XType_INT32:\n    case VDC_XType_INT64: return VDC_PutAtt_long(p, varname, attname, xtype, (const long *)values, count);\n    case VDC_XType_TEXT: return VDC_PutAtt_text(p, varname, attname, xtype, (const char *)values);\n    case VDC_XType_INVALID:\n    default: return -2;\n    }\n}\n\n#ifdef VDC_DEBUG\nstatic string valueCArrayToString(const void *a, int l, VDC_XType type)\n{\n    string s;\n    switch (type) {\n    #ifdef VDC_DEBUG_CPP_RUN\n    case VDC_XType_FLOAT: s = \"std::vector<double>{\"; break;\n    // case VDC_XType_FLOAT:  s = \"std::vector<float>{\"; break;\n    case VDC_XType_DOUBLE: s = \"std::vector<double>{\"; break;\n    case VDC_XType_INT32: s = \"std::vector<int>{\"; break;\n    case VDC_XType_INT64: s = \"std::vector<long>{\"; break;\n    #else\n    case VDC_XType_FLOAT: s = \"(float[]){\"; break;\n    case VDC_XType_DOUBLE: s = \"(double[]){\"; break;\n    case VDC_XType_INT32: s = \"(int[]){\"; break;\n    case VDC_XType_INT64: s = \"(long[]){\"; break;\n    #endif\n    }\n    char buffer[128];\n    for (int i = 0; i < l; i++) {\n        switch (type) {\n        case VDC_XType_FLOAT: sprintf(buffer, \"%g\", ((float *)a)[i]); break;\n        case VDC_XType_DOUBLE: sprintf(buffer, \"%g\", ((double *)a)[i]); break;\n        case VDC_XType_INT32: sprintf(buffer, \"%i\", ((int *)a)[i]); break;\n        case VDC_XType_INT64: sprintf(buffer, \"%li\", ((long *)a)[i]); break;\n        }\n        s += string(buffer);\n        if (i != l - 1) s += \", \";\n    }\n    return s + string(\"}\");\n}\n#endif\n\nint VDC_PutAtt_double(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const double *values, size_t count)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    VDC_DEBUG_coloredLocation_standard();\n    VDC_DEBUG_printf(\"VDC_PutAtt(%s \\\"%s\\\", \\\"%s\\\", %s, %s);\\n\", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), valueCArrayToString(values, count, xtype).c_str());\n#else\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", \\\"%s\\\", %s, %s, %li);\\n\", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), valueCArrayToString(values, count, xtype).c_str(), count);\n#endif\n    vector<double> values_v;\n    if (xtype == VDC_XType_FLOAT)\n        for (int i = 0; i < count; i++) values_v.push_back(((float *)values)[i]);\n    else\n        for (int i = 0; i < count; i++) values_v.push_back(values[i]);\n\n    return p->PutAtt(string(varname), string(attname), _IntToXType(xtype), values_v);\n}\n\nint VDC_PutAtt_long(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const long *values, size_t count)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    VDC_DEBUG_coloredLocation_standard();\n    VDC_DEBUG_printf(\"VDC_PutAtt(%s \\\"%s\\\", \\\"%s\\\", %s, %s);\\n\", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), valueCArrayToString(values, count, xtype).c_str());\n#else\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", \\\"%s\\\", %s, %s, %li);\\n\", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), valueCArrayToString(values, count, xtype).c_str(), count);\n#endif\n    vector<long> values_v;\n    if (xtype == VDC_XType_INT32)\n        for (int i = 0; i < count; i++) values_v.push_back(((int *)values)[i]);\n    else\n        for (int i = 0; i < count; i++) values_v.push_back(values[i]);\n\n    return p->PutAtt(string(varname), string(attname), _IntToXType(xtype), values_v);\n}\n\nint VDC_PutAtt_text(VDC *p, const char *varname, const char *attname, VDC_XType xtype, const char *values)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    VDC_DEBUG_coloredLocation_standard();\n    VDC_DEBUG_printf(\"VDC_PutAtt(%s \\\"%s\\\", \\\"%s\\\", %s, \\\"%s\\\");\\n\", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), values);\n#else\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", \\\"%s\\\", %s, \\\"%s\\\");\\n\", _VDCPToStr(p), varname, attname, _XTypeToIntCodeString(_IntToXType(xtype)), values);\n#endif\n    return p->PutAtt(string(varname), string(attname), _IntToXType(xtype), string(values));\n}\n\nint VDC_EndDefine(VDC *p)\n{\n    VDC_DEBUG_printff(\"(%s);\\n\", _VDCPToStr(p));\n    return p->EndDefine();\n}\n\nint VDC_PutVar(VDC *p, const char *varname, int lod, const float *data)\n{\n    VDC_DEBUG_printff(\"(%s \\\"%s\\\", %i, data);\\n\", _VDCPToStr(p), varname, lod);\n    return p->PutVar(string(varname), lod, data);\n}\n\nint VDC_PutVarAtTimeStep(VDC *p, size_t ts, const char *varname, int lod, const float *data)\n{\n    VDC_DEBUG_printff(\"(%s %li, \\\"%s\\\", %i, <data>);\\n\", _VDCPToStr(p), ts, varname, lod);\n    int ret = p->PutVar(ts, string(varname), lod, data);\n    if (ret < 0) VDC_DEBUG_printff_error(\": ERROR: code = %i, message = \\\"%s\\\"\\n\", ret, Wasp::MyBase::GetErrMsg());\n    return ret;\n}\n\n// ########################\n// #       Utility        #\n// ########################\n\nconst char *VDC_GetErrMsg()\n{\n#ifdef VDC_DEBUG_RUN\n    #ifdef VDC_DEBUG_CPP_RUN\n    VDC_DEBUG_printf(\"printf(\\\"ERR \\\\\\\"%%s\\\\\\\" \\\", vdc->GetErrMsg());\\n\");\n    #else\n    VDC_DEBUG_printf(\"printf(\\\"ERR \\\\\\\"%%s\\\\\\\" \\\", VDC_GetErrMsg());\\n\");\n    #endif\n#else\n    VDC_DEBUG_called();\n#endif\n    return Wasp::MyBase::GetErrMsg();\n}\n\nvoid VDC_FreeStringArray(char ***str, int *count)\n{\n    for (int i = 0; i < *count; i++) delete[](*str)[i];\n    delete[] * str;\n    *str = 0;\n    *count = 0;\n}\n\nvoid VDC_FreeString(char **str)\n{\n    delete[] * str;\n    *str = 0;\n}\n\nvoid VDC_FreeLongArray(long **data)\n{\n    delete[] * data;\n    *data = 0;\n}\n\nvoid VDC_FreeDoubleArray(double **data)\n{\n    delete[] * data;\n    *data = 0;\n}\n\nvoid VDC_FreeSize_tArray(size_t **data)\n{\n    delete[] * data;\n    *data = 0;\n}\n\nvoid VDC_ReverseSize_tArray(size_t *data, int count)\n{\n    for (int i = 0; i < count / 2; i++) {\n        size_t temp = data[i];\n        data[i] = data[count - i - 1];\n        data[count - i - 1] = temp;\n    }\n}\n\n// ########################\n// #        Static        #\n// ########################\n\nvoid _stringToCString(const string s, char **str)\n{\n    int size = s.size();\n    *str = new char[size + 1];\n    s.copy(*str, size);\n    (*str)[size] = 0;\n}\n\nvoid _stringVectorToCStringArray(const vector<string> v, char ***str, int *count)\n{\n    *count = v.size();\n    *str = new char *[*count];\n    for (int i = 0; i < *count; i++) {\n        (*str)[i] = new char[v[i].size() + 1];\n        v[i].copy((*str)[i], v[i].size());\n        (*str)[i][v[i].size()] = 0;\n    }\n}\n\nvoid _longVectorToCArray(const vector<long> v, long **data, int *count)\n{\n    *count = v.size();\n    *data = new long[*count];\n    for (int i = 0; i < *count; i++) (*data)[i] = v[i];\n}\n\nvoid _boolVectorToCArray(const vector<bool> v, long **data, int *count)\n{\n    *count = v.size();\n    *data = new long[*count];\n    for (int i = 0; i < *count; i++) (*data)[i] = v[i];\n}\n\nvoid _doubleVectorToCArray(const vector<double> v, double **data, int *count)\n{\n    *count = v.size();\n    *data = new double[*count];\n    for (int i = 0; i < *count; i++) (*data)[i] = v[i];\n}\n\nvoid _size_tVectorToCArray(const vector<size_t> v, size_t **data, int *count)\n{\n    *count = v.size();\n    *data = new size_t[*count];\n    for (int i = 0; i < *count; i++) (*data)[i] = v[i];\n}\n\nint _XTypeToInt(const VDC::XType type)\n{\n    switch (type) {\n    case VDC::XType::INVALID: return VDC_XType_INVALID;\n    case VDC::XType::FLOAT: return VDC_XType_FLOAT;\n    case VDC::XType::DOUBLE: return VDC_XType_DOUBLE;\n    case VDC::XType::INT32: return VDC_XType_INT32;\n    case VDC::XType::INT64: return VDC_XType_INT64;\n    case VDC::XType::TEXT: return VDC_XType_TEXT;\n    default: return -1;\n    }\n}\n\nVDC::XType _IntToXType(int type)\n{\n    switch (type) {\n    case VDC_XType_INVALID: return VDC::XType::INVALID;\n    case VDC_XType_FLOAT: return VDC::XType::FLOAT;\n    case VDC_XType_DOUBLE: return VDC::XType::DOUBLE;\n    case VDC_XType_INT32: return VDC::XType::INT32;\n    case VDC_XType_INT64: return VDC::XType::INT64;\n    case VDC_XType_TEXT: return VDC::XType::TEXT;\n    default: return VDC::XType::INVALID;\n    }\n}\n\nconst char *_XTypeToString(const VDC::XType type)\n{\n    switch (type) {\n    case VDC::XType::INVALID: return \"INVALID\";\n    case VDC::XType::FLOAT: return \"float\";\n    case VDC::XType::DOUBLE: return \"double\";\n    case VDC::XType::INT32: return \"int32\";\n    case VDC::XType::INT64: return \"int64\";\n    case VDC::XType::TEXT: return \"text\";\n    default: return \"<ERROR_TYPE>\";\n    }\n}\n\nconst char *_XTypeToIntCodeString(const VDC::XType type)\n{\n    switch (type) {\n#ifdef VDC_DEBUG_CPP_RUN\n    case VDC::XType::INVALID: return \"VDC::XType::INVALID\";\n    case VDC::XType::FLOAT: return \"VDC::XType::FLOAT\";\n    case VDC::XType::DOUBLE: return \"VDC::XType::DOUBLE\";\n    case VDC::XType::INT32: return \"VDC::XType::INT32\";\n    case VDC::XType::INT64: return \"VDC::XType::INT64\";\n    case VDC::XType::TEXT: return \"VDC::XType::TEXT\";\n#else\n    case VDC::XType::INVALID: return \"VDC_XType_INVALID\";\n    case VDC::XType::FLOAT: return \"VDC_XType_FLOAT\";\n    case VDC::XType::DOUBLE: return \"VDC_XType_DOUBLE\";\n    case VDC::XType::INT32: return \"VDC_XType_INT32\";\n    case VDC::XType::INT64: return \"VDC_XType_INT64\";\n    case VDC::XType::TEXT: return \"VDC_XType_TEXT\";\n#endif\n    default: return \"<ERROR_TYPE>\";\n    }\n}\n\nconst char *_boolToStr(const int b)\n{\n    if (b)\n        return \"true\";\n    else\n        return \"false\";\n}\n\n#define xstr(s) str(s)\n#define str(s)  #s\n\nconst char *_AxisToStr(const int a)\n{\n    switch (a) {\n#ifdef VDC_DEBUG_CPP_RUN\n    case VDCDimension_Axis_X: return xstr(VDCDimension_Axis_X);\n    case VDCDimension_Axis_Y: return xstr(VDCDimension_Axis_Y);\n    case VDCDimension_Axis_Z: return xstr(VDCDimension_Axis_Z);\n    case VDCDimension_Axis_T: return xstr(VDCDimension_Axis_T);\n#else\n    case VDCDimension_Axis_X: return \"VDCDimension_Axis_X\";\n    case VDCDimension_Axis_Y: return \"VDCDimension_Axis_Y\";\n    case VDCDimension_Axis_Z: return \"VDCDimension_Axis_Z\";\n    case VDCDimension_Axis_T: return \"VDCDimension_Axis_T\";\n#endif\n    default: return \"INVALID AXIS\";\n    }\n}\n\nconst char *_accessModeToStr(const int m)\n{\n    switch (m) {\n#ifdef VDC_DEBUG_CPP_RUN\n    case VDC_AccessMode_R: return \"VDC::AccessMode::R\";\n    case VDC_AccessMode_W: return \"VDC::AccessMode::W\";\n    case VDC_AccessMode_A: return \"VDC::AccessMode::A\";\n#else\n    case VDC_AccessMode_R: return \"VDC_AccessMode_R\";\n    case VDC_AccessMode_W: return \"VDC_AccessMode_W\";\n    case VDC_AccessMode_A: return \"VDC_AccessMode_A\";\n#endif\n    default: return \"<INVALID_ACCESS_MODE>\";\n    }\n}\n\nconst char *_VDCPToStr(const VDC *p)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    return \"\";\n#else\n    if (p)\n        return \"vdc,\";\n    else\n        return \"NULL,\";\n#endif\n}\n\nvector<string> _strArrayToStringVector(const char **a, size_t count)\n{\n    vector<string> v;\n    for (int i = 0; i < count; i++) v.push_back(string(a[i]));\n    return v;\n}\n\nstring _stringVectorToString(const vector<string> v)\n{\n    string s;\n#ifndef VDC_DEBUG_CPP_RUN\n    s += \"(const char*[])\";\n#endif\n    s += \"{\";\n    for (int i = 0; i < v.size(); i++) { s += \"\\\"\" + v[i] + \"\\\"\" + (i == v.size() - 1 ? \"\" : \", \"); }\n    s += \"}\";\n    return s;\n}\n\nstring _strArrayToString(const char **a, size_t count)\n{\n#ifdef VDC_DEBUG_CPP_RUN\n    if (!a) return \"std::vector<std::string>()\";\n#else\n    if (!a) return \"NULL\";\n#endif\n    return _stringVectorToString(_strArrayToStringVector(a, count));\n}\n\nvector<size_t> _size_tArrayToSize_tVector(const size_t *a, size_t count)\n{\n    vector<size_t> v;\n    for (int i = 0; i < count; i++) v.push_back(a[i]);\n    return v;\n}\n\nstring _size_tVectorToString(const vector<size_t> v)\n{\n    string s;\n#ifdef VDC_DEBUG_CPP_RUN\n    s += \"std::vector<size_t>\";\n#else\n    s += \"(size_t[])\";\n#endif\n    s += \"{\";\n    for (int i = 0; i < v.size(); i++) { s += std::to_string(v[i]) + (i == v.size() - 1 ? \"\" : \", \"); }\n    s += \"}\";\n    return s;\n}\n\nstring _size_tArrayToString(const size_t *a, size_t count)\n{\n    if (!a) return \"NULL\";\n    return _size_tVectorToString(_size_tArrayToSize_tVector(a, count));\n}\n"
  },
  {
    "path": "lib/vdc/kdtree.c",
    "content": "/*\nThis file is part of ``kdtree'', a library for working with kd-trees.\nCopyright (C) 2007-2011 John Tsiombikas <nuclear@member.fsf.org>\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n3. The name of the author may not be used to endorse or promote products\n   derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\nEVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\nOF SUCH DAMAGE.\n*/\n/* single nearest neighbor search written by Tamas Nepusz <tamas@cs.rhul.ac.uk> */\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n#include \"kdtree.h\"\n#ifdef Linux\n    #include <alloca.h>\n#endif\n#if defined(WIN32) || defined(__WIN32__)\n    #include <malloc.h>\n#endif\n\n#ifdef USE_LIST_NODE_ALLOCATOR\n\n    #ifndef NO_PTHREADS\n        #include <pthread.h>\n    #else\n\n        #ifndef I_WANT_THREAD_BUGS\n            #error \"You are compiling with the fast list node allocator, with pthreads disabled! This WILL break if used from multiple threads.\"\n        #endif /* I want thread bugs */\n\n    #endif /* pthread support */\n#endif     /* use list node allocator */\n\nstruct kdhyperrect {\n    int     dim;\n    double *min, *max; /* minimum/maximum coords */\n};\n\nstruct kdnode {\n    double *pos;\n    int     dir;\n    void *  data;\n\n    struct kdnode *left, *right; /* negative/positive side */\n};\n\nstruct res_node {\n    struct kdnode *  item;\n    double           dist_sq;\n    struct res_node *next;\n};\n\nstruct kdtree {\n    int                 dim;\n    struct kdnode *     root;\n    struct kdhyperrect *rect;\n    void (*destr)(void *);\n};\n\nstruct kdres {\n    struct kdtree *  tree;\n    struct res_node *rlist, *riter;\n    int              size;\n};\n\n#define SQ(x) ((x) * (x))\n\nstatic void clear_rec(struct kdnode *node, void (*destr)(void *));\nstatic int  insert_rec(struct kdnode **node, const double *pos, void *data, int dim);\nstatic int  rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq);\nstatic void clear_results(struct kdres *set);\n\nstatic struct kdhyperrect *hyperrect_create(int dim, const double *min, const double *max);\nstatic void                hyperrect_free(struct kdhyperrect *rect);\nstatic struct kdhyperrect *hyperrect_duplicate(const struct kdhyperrect *rect);\nstatic void                hyperrect_extend(struct kdhyperrect *rect, const double *pos);\nstatic double              hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos);\n\n#ifdef USE_LIST_NODE_ALLOCATOR\nstatic struct res_node *alloc_resnode(void);\nstatic void             free_resnode(struct res_node *);\n#else\n    #define alloc_resnode() malloc(sizeof(struct res_node))\n    #define free_resnode(n) free(n)\n#endif\n\nstruct kdtree *kd_create(int k)\n{\n    struct kdtree *tree;\n\n    if (!(tree = malloc(sizeof *tree))) { return 0; }\n\n    tree->dim = k;\n    tree->root = 0;\n    tree->destr = 0;\n    tree->rect = 0;\n\n    return tree;\n}\n\nvoid kd_free(struct kdtree *tree)\n{\n    if (tree) {\n        kd_clear(tree);\n        free(tree);\n    }\n}\n\nstatic void clear_rec(struct kdnode *node, void (*destr)(void *))\n{\n    if (!node) return;\n\n    clear_rec(node->left, destr);\n    clear_rec(node->right, destr);\n\n    if (destr) { destr(node->data); }\n    free(node->pos);\n    free(node);\n}\n\nvoid kd_clear(struct kdtree *tree)\n{\n    clear_rec(tree->root, tree->destr);\n    tree->root = 0;\n\n    if (tree->rect) {\n        hyperrect_free(tree->rect);\n        tree->rect = 0;\n    }\n}\n\nvoid kd_data_destructor(struct kdtree *tree, void (*destr)(void *)) { tree->destr = destr; }\n\nstatic int insert_rec(struct kdnode **root, const double *pos, void *data, int dim)\n{\n    int new_dir = 0;\n\n    struct kdnode *parent = *root;\n    struct kdnode *node = parent;\n    while (node) {\n        parent = node;\n        new_dir = (node->dir + 1) % dim;\n        if (pos[node->dir] < node->pos[node->dir]) {\n            node = node->left;\n        } else {\n            node = node->right;\n        }\n    }\n\n    if (!(node = malloc(sizeof *node))) { return -1; }\n    if (!(node->pos = malloc(dim * sizeof *node->pos))) {\n        free(node);\n        return -1;\n    }\n\n    memcpy(node->pos, pos, dim * sizeof *node->pos);\n    node->data = data;\n    node->dir = new_dir;\n    node->left = node->right = 0;\n\n    // root of tree?\n    //\n    if (!*root) {\n        *root = node;\n        return 0;\n    }\n\n    if (pos[parent->dir] < parent->pos[parent->dir]) {\n        parent->left = node;\n    } else {\n        parent->right = node;\n    }\n\n    return 0;\n}\n\nint kd_insert(struct kdtree *tree, const double *pos, void *data)\n{\n    if (insert_rec(&tree->root, pos, data, tree->dim)) { return -1; }\n\n    if (tree->rect == 0) {\n        tree->rect = hyperrect_create(tree->dim, pos, pos);\n    } else {\n        hyperrect_extend(tree->rect, pos);\n    }\n\n    return 0;\n}\n\nint kd_insertf(struct kdtree *tree, const float *pos, void *data)\n{\n    static double sbuf[16];\n    double *      bptr, *buf = 0;\n    int           res, dim = tree->dim;\n\n    if (dim > 16) {\n#ifndef NO_ALLOCA\n        if (dim <= 256)\n            bptr = buf = alloca(dim * sizeof *bptr);\n        else\n#endif\n            if (!(bptr = buf = malloc(dim * sizeof *bptr))) {\n            return -1;\n        }\n    } else {\n        bptr = buf = sbuf;\n    }\n\n    while (dim-- > 0) { *bptr++ = *pos++; }\n\n    res = kd_insert(tree, buf, data);\n#ifndef NO_ALLOCA\n    if (tree->dim > 256)\n#else\n    if (tree->dim > 16)\n#endif\n        free(buf);\n    return res;\n}\n\nint kd_insert3(struct kdtree *tree, double x, double y, double z, void *data)\n{\n    double buf[3];\n    buf[0] = x;\n    buf[1] = y;\n    buf[2] = z;\n    return kd_insert(tree, buf, data);\n}\n\nint kd_insert3f(struct kdtree *tree, float x, float y, float z, void *data)\n{\n    double buf[3];\n    buf[0] = x;\n    buf[1] = y;\n    buf[2] = z;\n    return kd_insert(tree, buf, data);\n}\n\nstatic int find_nearest(struct kdnode *node, const double *pos, double range, struct res_node *list, int ordered, int dim)\n{\n    double dist_sq, dx;\n    int    i, ret, added_res = 0;\n\n    if (!node) return 0;\n\n    dist_sq = 0;\n    for (i = 0; i < dim; i++) { dist_sq += SQ(node->pos[i] - pos[i]); }\n    if (dist_sq <= SQ(range)) {\n        if (rlist_insert(list, node, ordered ? dist_sq : -1.0) == -1) { return -1; }\n        added_res = 1;\n    }\n\n    dx = pos[node->dir] - node->pos[node->dir];\n\n    ret = find_nearest(dx <= 0.0 ? node->left : node->right, pos, range, list, ordered, dim);\n    if (ret >= 0 && fabs(dx) < range) {\n        added_res += ret;\n        ret = find_nearest(dx <= 0.0 ? node->right : node->left, pos, range, list, ordered, dim);\n    }\n    if (ret == -1) { return -1; }\n    added_res += ret;\n\n    return added_res;\n}\n\n#if 0\nstatic int find_nearest_n(struct kdnode *node, const double *pos, double range, int num, struct rheap *heap, int dim)\n{\n\tdouble dist_sq, dx;\n\tint i, ret, added_res = 0;\n\n\tif(!node) return 0;\n\t\n\t/* if the photon is close enough, add it to the result heap */\n\tdist_sq = 0;\n\tfor(i=0; i<dim; i++) {\n\t\tdist_sq += SQ(node->pos[i] - pos[i]);\n\t}\n\tif(dist_sq <= range_sq) {\n\t\tif(heap->size >= num) {\n\t\t\t/* get furthest element */\n\t\t\tstruct res_node *maxelem = rheap_get_max(heap);\n\n\t\t\t/* and check if the new one is closer than that */\n\t\t\tif(maxelem->dist_sq > dist_sq) {\n\t\t\t\trheap_remove_max(heap);\n\n\t\t\t\tif(rheap_insert(heap, node, dist_sq) == -1) {\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\tadded_res = 1;\n\n\t\t\t\trange_sq = dist_sq;\n\t\t\t}\n\t\t} else {\n\t\t\tif(rheap_insert(heap, node, dist_sq) == -1) {\n\t\t\t\treturn =1;\n\t\t\t}\n\t\t\tadded_res = 1;\n\t\t}\n\t}\n\n\n\t/* find signed distance from the splitting plane */\n\tdx = pos[node->dir] - node->pos[node->dir];\n\n\tret = find_nearest_n(dx <= 0.0 ? node->left : node->right, pos, range, num, heap, dim);\n\tif(ret >= 0 && fabs(dx) < range) {\n\t\tadded_res += ret;\n\t\tret = find_nearest_n(dx <= 0.0 ? node->right : node->left, pos, range, num, heap, dim);\n\t}\n\n}\n#endif\n\nstatic void kd_nearest_i(struct kdnode *node, const double *pos, struct kdnode **result, double *result_dist_sq, struct kdhyperrect *rect)\n{\n    int            dir = node->dir;\n    int            i;\n    double         dummy, dist_sq;\n    struct kdnode *nearer_subtree, *farther_subtree;\n    double *       nearer_hyperrect_coord, *farther_hyperrect_coord;\n\n    /* Decide whether to go left or right in the tree */\n    dummy = pos[dir] - node->pos[dir];\n    if (dummy <= 0) {\n        nearer_subtree = node->left;\n        farther_subtree = node->right;\n        nearer_hyperrect_coord = rect->max + dir;\n        farther_hyperrect_coord = rect->min + dir;\n    } else {\n        nearer_subtree = node->right;\n        farther_subtree = node->left;\n        nearer_hyperrect_coord = rect->min + dir;\n        farther_hyperrect_coord = rect->max + dir;\n    }\n\n    if (nearer_subtree) {\n        /* Slice the hyperrect to get the hyperrect of the nearer subtree */\n        dummy = *nearer_hyperrect_coord;\n        *nearer_hyperrect_coord = node->pos[dir];\n        /* Recurse down into nearer subtree */\n        kd_nearest_i(nearer_subtree, pos, result, result_dist_sq, rect);\n        /* Undo the slice */\n        *nearer_hyperrect_coord = dummy;\n    }\n\n    /* Check the distance of the point at the current node, compare it\n     * with our best so far */\n    dist_sq = 0;\n    for (i = 0; i < rect->dim; i++) { dist_sq += SQ(node->pos[i] - pos[i]); }\n    if (dist_sq < *result_dist_sq) {\n        *result = node;\n        *result_dist_sq = dist_sq;\n    }\n\n    if (farther_subtree) {\n        /* Get the hyperrect of the farther subtree */\n        dummy = *farther_hyperrect_coord;\n        *farther_hyperrect_coord = node->pos[dir];\n        /* Check if we have to recurse down by calculating the closest\n         * point of the hyperrect and see if it's closer than our\n         * minimum distance in result_dist_sq. */\n        if (hyperrect_dist_sq(rect, pos) < *result_dist_sq) {\n            /* Recurse down into farther subtree */\n            kd_nearest_i(farther_subtree, pos, result, result_dist_sq, rect);\n        }\n        /* Undo the slice on the hyperrect */\n        *farther_hyperrect_coord = dummy;\n    }\n}\n\nstruct kdres *kd_nearest(struct kdtree *kd, const double *pos)\n{\n    struct kdhyperrect *rect;\n    struct kdnode *     result;\n    struct kdres *      rset;\n    double              dist_sq;\n    int                 i;\n\n    if (!kd) return 0;\n    if (!kd->rect) return 0;\n\n    /* Allocate result set */\n    if (!(rset = malloc(sizeof *rset))) { return 0; }\n    if (!(rset->rlist = alloc_resnode())) {\n        free(rset);\n        return 0;\n    }\n    rset->rlist->next = 0;\n    rset->tree = kd;\n\n    /* Duplicate the bounding hyperrectangle, we will work on the copy */\n    if (!(rect = hyperrect_duplicate(kd->rect))) {\n        kd_res_free(rset);\n        return 0;\n    }\n\n    /* Our first guesstimate is the root node */\n    result = kd->root;\n    dist_sq = 0;\n    for (i = 0; i < kd->dim; i++) dist_sq += SQ(result->pos[i] - pos[i]);\n\n    /* Search for the nearest neighbour recursively */\n    kd_nearest_i(kd->root, pos, &result, &dist_sq, rect);\n\n    /* Free the copy of the hyperrect */\n    hyperrect_free(rect);\n\n    /* Store the result */\n    if (result) {\n        if (rlist_insert(rset->rlist, result, -1.0) == -1) {\n            kd_res_free(rset);\n            return 0;\n        }\n        rset->size = 1;\n        kd_res_rewind(rset);\n        return rset;\n    } else {\n        kd_res_free(rset);\n        return 0;\n    }\n}\n\nstruct kdres *kd_nearestf(struct kdtree *tree, const float *pos)\n{\n    static double sbuf[16];\n    double *      bptr, *buf = 0;\n    int           dim = tree->dim;\n    struct kdres *res;\n\n    if (dim > 16) {\n#ifndef NO_ALLOCA\n        if (dim <= 256)\n            bptr = buf = alloca(dim * sizeof *bptr);\n        else\n#endif\n            if (!(bptr = buf = malloc(dim * sizeof *bptr))) {\n            return 0;\n        }\n    } else {\n        bptr = buf = sbuf;\n    }\n\n    while (dim-- > 0) { *bptr++ = *pos++; }\n\n    res = kd_nearest(tree, buf);\n#ifndef NO_ALLOCA\n    if (tree->dim > 256)\n#else\n    if (tree->dim > 16)\n#endif\n        free(buf);\n    return res;\n}\n\nstruct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z)\n{\n    double pos[3];\n    pos[0] = x;\n    pos[1] = y;\n    pos[2] = z;\n    return kd_nearest(tree, pos);\n}\n\nstruct kdres *kd_nearest3f(struct kdtree *tree, float x, float y, float z)\n{\n    double pos[3];\n    pos[0] = x;\n    pos[1] = y;\n    pos[2] = z;\n    return kd_nearest(tree, pos);\n}\n\n/* ---- nearest N search ---- */\n/*\nstatic kdres *kd_nearest_n(struct kdtree *kd, const double *pos, int num)\n{\n    int ret;\n    struct kdres *rset;\n\n    if(!(rset = malloc(sizeof *rset))) {\n        return 0;\n    }\n    if(!(rset->rlist = alloc_resnode())) {\n        free(rset);\n        return 0;\n    }\n    rset->rlist->next = 0;\n    rset->tree = kd;\n\n    if((ret = find_nearest_n(kd->root, pos, range, num, rset->rlist, kd->dim)) == -1) {\n        kd_res_free(rset);\n        return 0;\n    }\n    rset->size = ret;\n    kd_res_rewind(rset);\n    return rset;\n}*/\n\nstruct kdres *kd_nearest_range(struct kdtree *kd, const double *pos, double range)\n{\n    int           ret;\n    struct kdres *rset;\n\n    if (!(rset = malloc(sizeof *rset))) { return 0; }\n    if (!(rset->rlist = alloc_resnode())) {\n        free(rset);\n        return 0;\n    }\n    rset->rlist->next = 0;\n    rset->tree = kd;\n\n    if ((ret = find_nearest(kd->root, pos, range, rset->rlist, 0, kd->dim)) == -1) {\n        kd_res_free(rset);\n        return 0;\n    }\n    rset->size = ret;\n    kd_res_rewind(rset);\n    return rset;\n}\n\nstruct kdres *kd_nearest_rangef(struct kdtree *kd, const float *pos, float range)\n{\n    static double sbuf[16];\n    double *      bptr, *buf = 0;\n    int           dim = kd->dim;\n    struct kdres *res;\n\n    if (dim > 16) {\n#ifndef NO_ALLOCA\n        if (dim <= 256)\n            bptr = buf = alloca(dim * sizeof *bptr);\n        else\n#endif\n            if (!(bptr = buf = malloc(dim * sizeof *bptr))) {\n            return 0;\n        }\n    } else {\n        bptr = buf = sbuf;\n    }\n\n    while (dim-- > 0) { *bptr++ = *pos++; }\n\n    res = kd_nearest_range(kd, buf, range);\n#ifndef NO_ALLOCA\n    if (kd->dim > 256)\n#else\n    if (kd->dim > 16)\n#endif\n        free(buf);\n    return res;\n}\n\nstruct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range)\n{\n    double buf[3];\n    buf[0] = x;\n    buf[1] = y;\n    buf[2] = z;\n    return kd_nearest_range(tree, buf, range);\n}\n\nstruct kdres *kd_nearest_range3f(struct kdtree *tree, float x, float y, float z, float range)\n{\n    double buf[3];\n    buf[0] = x;\n    buf[1] = y;\n    buf[2] = z;\n    return kd_nearest_range(tree, buf, range);\n}\n\nvoid kd_res_free(struct kdres *rset)\n{\n    clear_results(rset);\n    free_resnode(rset->rlist);\n    free(rset);\n}\n\nint kd_res_size(struct kdres *set) { return (set->size); }\n\nvoid kd_res_rewind(struct kdres *rset) { rset->riter = rset->rlist->next; }\n\nint kd_res_end(struct kdres *rset) { return rset->riter == 0; }\n\nint kd_res_next(struct kdres *rset)\n{\n    rset->riter = rset->riter->next;\n    return rset->riter != 0;\n}\n\nvoid *kd_res_item(struct kdres *rset, double *pos)\n{\n    if (rset->riter) {\n        if (pos) { memcpy(pos, rset->riter->item->pos, rset->tree->dim * sizeof *pos); }\n        return rset->riter->item->data;\n    }\n    return 0;\n}\n\nvoid *kd_res_itemf(struct kdres *rset, float *pos)\n{\n    if (rset->riter) {\n        if (pos) {\n            int i;\n            for (i = 0; i < rset->tree->dim; i++) { pos[i] = rset->riter->item->pos[i]; }\n        }\n        return rset->riter->item->data;\n    }\n    return 0;\n}\n\nvoid *kd_res_item3(struct kdres *rset, double *x, double *y, double *z)\n{\n    if (rset->riter) {\n        if (*x) *x = rset->riter->item->pos[0];\n        if (*y) *y = rset->riter->item->pos[1];\n        if (*z) *z = rset->riter->item->pos[2];\n    }\n    return 0;\n}\n\nvoid *kd_res_item3f(struct kdres *rset, float *x, float *y, float *z)\n{\n    if (rset->riter) {\n        if (*x) *x = rset->riter->item->pos[0];\n        if (*y) *y = rset->riter->item->pos[1];\n        if (*z) *z = rset->riter->item->pos[2];\n    }\n    return 0;\n}\n\nvoid *kd_res_item_data(struct kdres *set) { return kd_res_item(set, 0); }\n\n/* ---- hyperrectangle helpers ---- */\nstatic struct kdhyperrect *hyperrect_create(int dim, const double *min, const double *max)\n{\n    size_t              size = dim * sizeof(double);\n    struct kdhyperrect *rect = 0;\n\n    if (!(rect = malloc(sizeof(struct kdhyperrect)))) { return 0; }\n\n    rect->dim = dim;\n    if (!(rect->min = malloc(size))) {\n        free(rect);\n        return 0;\n    }\n    if (!(rect->max = malloc(size))) {\n        free(rect->min);\n        free(rect);\n        return 0;\n    }\n    memcpy(rect->min, min, size);\n    memcpy(rect->max, max, size);\n\n    return rect;\n}\n\nstatic void hyperrect_free(struct kdhyperrect *rect)\n{\n    free(rect->min);\n    free(rect->max);\n    free(rect);\n}\n\nstatic struct kdhyperrect *hyperrect_duplicate(const struct kdhyperrect *rect) { return hyperrect_create(rect->dim, rect->min, rect->max); }\n\nstatic void hyperrect_extend(struct kdhyperrect *rect, const double *pos)\n{\n    int i;\n\n    for (i = 0; i < rect->dim; i++) {\n        if (pos[i] < rect->min[i]) { rect->min[i] = pos[i]; }\n        if (pos[i] > rect->max[i]) { rect->max[i] = pos[i]; }\n    }\n}\n\nstatic double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos)\n{\n    int    i;\n    double result = 0;\n\n    for (i = 0; i < rect->dim; i++) {\n        if (pos[i] < rect->min[i]) {\n            result += SQ(rect->min[i] - pos[i]);\n        } else if (pos[i] > rect->max[i]) {\n            result += SQ(rect->max[i] - pos[i]);\n        }\n    }\n\n    return result;\n}\n\n/* ---- static helpers ---- */\n\n#ifdef USE_LIST_NODE_ALLOCATOR\n/* special list node allocators. */\nstatic struct res_node *free_nodes;\n\n    #ifndef NO_PTHREADS\nstatic pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER;\n    #endif\n\nstatic struct res_node *alloc_resnode(void)\n{\n    struct res_node *node;\n\n    #ifndef NO_PTHREADS\n    pthread_mutex_lock(&alloc_mutex);\n    #endif\n\n    if (!free_nodes) {\n        node = malloc(sizeof *node);\n    } else {\n        node = free_nodes;\n        free_nodes = free_nodes->next;\n        node->next = 0;\n    }\n\n    #ifndef NO_PTHREADS\n    pthread_mutex_unlock(&alloc_mutex);\n    #endif\n\n    return node;\n}\n\nstatic void free_resnode(struct res_node *node)\n{\n    #ifndef NO_PTHREADS\n    pthread_mutex_lock(&alloc_mutex);\n    #endif\n\n    node->next = free_nodes;\n    free_nodes = node;\n\n    #ifndef NO_PTHREADS\n    pthread_mutex_unlock(&alloc_mutex);\n    #endif\n}\n#endif /* list node allocator or not */\n\n/* inserts the item. if dist_sq is >= 0, then do an ordered insert */\n/* TODO make the ordering code use heapsort */\nstatic int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq)\n{\n    struct res_node *rnode;\n\n    if (!(rnode = alloc_resnode())) { return -1; }\n    rnode->item = item;\n    rnode->dist_sq = dist_sq;\n\n    if (dist_sq >= 0.0) {\n        while (list->next && list->next->dist_sq < dist_sq) { list = list->next; }\n    }\n    rnode->next = list->next;\n    list->next = rnode;\n    return 0;\n}\n\nstatic void clear_results(struct kdres *rset)\n{\n    struct res_node *tmp, *node = rset->rlist->next;\n\n    while (node) {\n        tmp = node;\n        node = node->next;\n        free_resnode(tmp);\n    }\n\n    rset->rlist->next = 0;\n}\n"
  },
  {
    "path": "lib/vdc/kdtree.h",
    "content": "/*\nThis file is part of ``kdtree'', a library for working with kd-trees.\nCopyright (C) 2007-2011 John Tsiombikas <nuclear@member.fsf.org>\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n3. The name of the author may not be used to endorse or promote products\n   derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\nWARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\nEVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\nOF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\nOF SUCH DAMAGE.\n*/\n#ifndef _KDTREE_H_\n#define _KDTREE_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nstruct kdtree;\nstruct kdres;\n\n/* create a kd-tree for \"k\"-dimensional data */\nstruct kdtree *kd_create(int k);\n\n/* free the struct kdtree */\nvoid kd_free(struct kdtree *tree);\n\n/* remove all the elements from the tree */\nvoid kd_clear(struct kdtree *tree);\n\n/* if called with non-null 2nd argument, the function provided\n * will be called on data pointers (see kd_insert) when nodes\n * are to be removed from the tree.\n */\nvoid kd_data_destructor(struct kdtree *tree, void (*destr)(void *));\n\n/* insert a node, specifying its position, and optional data */\nint kd_insert(struct kdtree *tree, const double *pos, void *data);\nint kd_insertf(struct kdtree *tree, const float *pos, void *data);\nint kd_insert3(struct kdtree *tree, double x, double y, double z, void *data);\nint kd_insert3f(struct kdtree *tree, float x, float y, float z, void *data);\n\n/* Find the nearest node from a given point.\n *\n * This function returns a pointer to a result set with at most one element.\n */\nstruct kdres *kd_nearest(struct kdtree *tree, const double *pos);\nstruct kdres *kd_nearestf(struct kdtree *tree, const float *pos);\nstruct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z);\nstruct kdres *kd_nearest3f(struct kdtree *tree, float x, float y, float z);\n\n/* Find the N nearest nodes from a given point.\n *\n * This function returns a pointer to a result set, with at most N elements,\n * which can be manipulated with the kd_res_* functions.\n * The returned pointer can be null as an indication of an error. Otherwise\n * a valid result set is always returned which may contain 0 or more elements.\n * The result set must be deallocated with kd_res_free after use.\n */\n/*\nstruct kdres *kd_nearest_n(struct kdtree *tree, const double *pos, int num);\nstruct kdres *kd_nearest_nf(struct kdtree *tree, const float *pos, int num);\nstruct kdres *kd_nearest_n3(struct kdtree *tree, double x, double y, double z);\nstruct kdres *kd_nearest_n3f(struct kdtree *tree, float x, float y, float z);\n*/\n\n/* Find any nearest nodes from a given point within a range.\n *\n * This function returns a pointer to a result set, which can be manipulated\n * by the kd_res_* functions.\n * The returned pointer can be null as an indication of an error. Otherwise\n * a valid result set is always returned which may contain 0 or more elements.\n * The result set must be deallocated with kd_res_free after use.\n */\nstruct kdres *kd_nearest_range(struct kdtree *tree, const double *pos, double range);\nstruct kdres *kd_nearest_rangef(struct kdtree *tree, const float *pos, float range);\nstruct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range);\nstruct kdres *kd_nearest_range3f(struct kdtree *tree, float x, float y, float z, float range);\n\nstruct kdres *kd_region(struct kdtree *kd, const double *min, const double *max);\n\n/* frees a result set returned by kd_nearest_range() */\nvoid kd_res_free(struct kdres *set);\n\n/* returns the size of the result set (in elements) */\nint kd_res_size(struct kdres *set);\n\n/* rewinds the result set iterator */\nvoid kd_res_rewind(struct kdres *set);\n\n/* returns non-zero if the set iterator reached the end after the last element */\nint kd_res_end(struct kdres *set);\n\n/* advances the result set iterator, returns non-zero on success, zero if\n * there are no more elements in the result set.\n */\nint kd_res_next(struct kdres *set);\n\n/* returns the data pointer (can be null) of the current result set item\n * and optionally sets its position to the pointers(s) if not null.\n */\nvoid *kd_res_item(struct kdres *set, double *pos);\nvoid *kd_res_itemf(struct kdres *set, float *pos);\nvoid *kd_res_item3(struct kdres *set, double *x, double *y, double *z);\nvoid *kd_res_item3f(struct kdres *set, float *x, float *y, float *z);\n\n/* equivalent to kd_res_item(set, 0) */\nvoid *kd_res_item_data(struct kdres *set);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _KDTREE_H_ */\n"
  },
  {
    "path": "lib/vdc/vizutil.cpp",
    "content": "#include <cmath>\n#include <iostream>\n#include <limits>\n#include \"vapor/VAssert.h\"\n#include <vapor/vizutil.h>\n\nnamespace {\n\ndouble dot2d(const double a[], const double b[]) { return ((a[0] * b[0]) + (a[1] * b[1])); }\n\n};    // namespace\n\nvoid VAPoR::HexahedronToTets(const int hexahedron[8], int tets[5 * 4])\n{\n    int i = 0;\n    if (hexahedron[0] % 2 == 0) {\n        tets[i++] = hexahedron[0];\n        tets[i++] = hexahedron[1];\n        tets[i++] = hexahedron[5];\n        tets[i++] = hexahedron[3];\n\n        tets[i++] = hexahedron[0];\n        tets[i++] = hexahedron[5];\n        tets[i++] = hexahedron[6];\n        tets[i++] = hexahedron[3];\n\n        tets[i++] = hexahedron[0];\n        tets[i++] = hexahedron[5];\n        tets[i++] = hexahedron[4];\n        tets[i++] = hexahedron[6];\n\n        tets[i++] = hexahedron[0];\n        tets[i++] = hexahedron[3];\n        tets[i++] = hexahedron[6];\n        tets[i++] = hexahedron[2];\n\n        tets[i++] = hexahedron[5];\n        tets[i++] = hexahedron[6];\n        tets[i++] = hexahedron[3];\n        tets[i++] = hexahedron[7];\n    } else {\n        tets[i++] = hexahedron[1];\n        tets[i++] = hexahedron[5];\n        tets[i++] = hexahedron[4];\n        tets[i++] = hexahedron[7];\n\n        tets[i++] = hexahedron[1];\n        tets[i++] = hexahedron[4];\n        tets[i++] = hexahedron[2];\n        tets[i++] = hexahedron[7];\n\n        tets[i++] = hexahedron[1];\n        tets[i++] = hexahedron[4];\n        tets[i++] = hexahedron[0];\n        tets[i++] = hexahedron[2];\n\n        tets[i++] = hexahedron[1];\n        tets[i++] = hexahedron[7];\n        tets[i++] = hexahedron[2];\n        tets[i++] = hexahedron[3];\n\n        tets[i++] = hexahedron[4];\n        tets[i++] = hexahedron[2];\n        tets[i++] = hexahedron[7];\n        tets[i++] = hexahedron[6];\n    }\n}\n\nvoid VAPoR::QuadToTris(const int quad[4], int tris[2 * 3])\n{\n    // Triangle #1\n    //\n    int i = 0;\n    tris[i++] = quad[0];\n    tris[i++] = quad[1];\n    tris[i++] = quad[3];\n\n    // Triangle #2\n    //\n    tris[i++] = quad[0];\n    tris[i++] = quad[3];\n    tris[i++] = quad[2];\n}\n\n#ifdef VAPOR3_0_0_ALPHA\n\nvoid VAPoR::BaryTet(const Point3d &p, const Point3d &a, const Point3d &b, const Point3d &c, const Point3d &d Point3d &ans)\n{\n    Vect3d vap(a, p);\n    Vect3d vbp(b, p);\n    Vect3d vcp(c, p);\n    Vect3d vdp(d, p);\n\n    Vect3d vab(a, b);\n    Vect3d vac(a, c);\n    Vect3d vad(a, d);\n\n    Vect3d vbc(b, c);\n    Vect3d vbd(b, d);\n\n    double va;\n    double vb;\n    double vc;\n    double vd;\n    double v;\n    Vect3d temp;\n\n    const double frecip = 1.0 / 6.0;\n\n    temp = vbd.cross(vbc);\n    va = vbp.dot(temp) * frecip;\n\n    temp = vac.cross(vad);\n    vb = vap.dot(temp) * frecip;\n\n    temp = vad.cross(vab);\n    vc = vap.dot(temp) * frecip;\n\n    temp = vab.cross(vac);\n    vd = vap.dot(temp) * frecip;\n\n    temp = vac.cross(vad);\n    v = vab.dot(temp) * frecip;\n\n    VAssert(v != 0.0);\n    double vrecip = 1.0 / v;\n\n    ans.x = va * vrecip;\n    ans.y = vb * vrecip;\n    ans.z = vc * vrecip;\n    ans.w = vd * vrecip;\n}\n\nvoid VAPoR::BaryTri(const Point3d &p, const Point3d &a, const Point3d &b, const Point3d &c Point3d &ans)\n{\n    Vect3d vap(a, p);\n    Vect3d vbp(b, p);\n    Vect3d vcp(c, p);\n    Vect3d vab(a, b);\n    Vect3d vca(c, a);\n    Vect3d vbc(b, c);\n    Vect3d vac(a, c);\n\n    Vect3d n;\n    Vect3d na;\n    Vect3d nb;\n    Vect3d nc;\n\n    n = vab.cross(vac);\n    na = vbc.cross(vbp);\n    nb = vca.cross(vcp);\n    nc = vab.cross(vap);\n\n    double nrecip = n.dot(n);\n    VAssert(nrecip != 0);\n    nrecip = 1.0 / nrecip;\n\n    ans.x = n.dot(na) * nrecip;\n    ans.y = n.dot(nb) * nrecip;\n    ans.z = n.dot(nc) * nrecip;\n}\n#endif\n\n// Compute signed area of a triangle using the 3x3 determinant. Actually we\n// return 2 * A, where A is area\n//\ndouble VAPoR::SignedTriArea2D(const double a[2], const double b[2], const double c[2])\n{\n    return (a[0] * (b[1] * 1.0 - 1.0 * c[1]) - b[0] * (a[1] * 1.0 - 1.0 * c[1]) + c[0] * (a[1] * 1.0 - 1.0 * b[1]));\n}\n\nbool VAPoR::BarycentricCoordsTri(const double verts[], const double pt[], double lambda[])\n{\n    // Vector v0 = b - a, v1 = c - a, v2 = p - a;\n    //\n    double v0[] = {verts[2] - verts[0], verts[3] - verts[1]};\n    double v1[] = {verts[4] - verts[0], verts[5] - verts[1]};\n    double v2[] = {pt[0] - verts[0], pt[1] - verts[1]};\n\n    double d00 = dot2d(v0, v0);\n    double d01 = dot2d(v0, v1);\n    double d11 = dot2d(v1, v1);\n    double d20 = dot2d(v2, v0);\n    double d21 = dot2d(v2, v1);\n    double denom = d00 * d11 - d01 * d01;\n    lambda[1] = (d11 * d20 - d01 * d21) / denom;\n    lambda[2] = (d00 * d21 - d01 * d20) / denom;\n    lambda[0] = 1.0f - lambda[1] - lambda[2];\n\n    const double epsilon = std::numeric_limits<double>::epsilon();\n    if ((lambda[0] < 0.0) && ((lambda[0] + epsilon) >= 0.0)) lambda[0] = 0.0;\n    if ((lambda[1] < 0.0) && ((lambda[1] + epsilon) >= 0.0)) lambda[1] = 0.0;\n    if ((lambda[2] < 0.0) && ((lambda[2] + epsilon) >= 0.0)) lambda[2] = 0.0;\n\n    return (lambda[0] >= 0.0 && lambda[1] >= 0.0 && lambda[2] >= 0.0);\n}\n\nbool VAPoR::WachspressCoords2D(const double verts[], const double pt[], int n, double lambda[])\n{\n    if (n == 0) return (false);\n\n    if (n == 3) return (BarycentricCoordsTri(verts, pt, lambda));\n\n    for (int i = 0; i < n; i++) lambda[i] = 0.0;\n\n    double       wTotal = 0.0;\n    const double epsilon = 1e-6;\n\n    int    curr = 0;\n    int    prev = (curr + n - 1) % n;\n    int    next = (curr + 1) % n;\n    double Aprev = SignedTriArea2D(pt, &verts[prev * 2], &verts[curr * 2]);\n    bool   onEdge = (Aprev > -epsilon && Aprev < epsilon);\n    for (; curr < n && !onEdge; curr++) {\n        prev = (curr + n - 1) % n;\n        next = (curr + 1) % n;\n\n        double C = SignedTriArea2D(&verts[prev * 2], &verts[curr * 2], &verts[next * 2]);\n        double A = SignedTriArea2D(pt, &verts[curr * 2], &verts[next * 2]);\n        onEdge = (A > -epsilon && A < epsilon);\n\n        if (onEdge) break;    // special handling required\n\n        lambda[curr] = C / (Aprev * A);\n        Aprev = A;\n\n        wTotal += lambda[curr];\n    }\n\n    // Special handling required if point is on an edge: simply linearly\n    // interpolate between the adjacent points\n    //\n    if (onEdge) {\n        for (int i = 0; i < n; i++) lambda[i] = 0.0;\n\n        int i0, i1;\n\n        // Which edge is point on? beteen points prev and curr, or curr\n        // and next ?\n        //\n        if (Aprev > -epsilon && Aprev < epsilon) {\n            i0 = (curr + n - 1) % n;\n            i1 = curr;\n        } else {\n            i0 = curr;\n            i1 = (curr + 1) % n;\n        }\n\n        double w;\n        if (verts[i0 * 2] != verts[i1 * 2]) {\n            w = 1.0 - ((pt[0] - verts[i0 * 2]) / (verts[i1 * 2] - verts[i0 * 2]));\n        } else {\n            w = 1.0 - ((pt[1] - verts[i0 * 2 + 1]) / (verts[i1 * 2 + 1] - verts[i0 * 2 + 1]));\n        }\n\n        lambda[i0] = w;\n        lambda[i1] = 1.0 - w;\n\n        if (w < 0.0 || w > 1.0)\n            return (false);\n        else\n            return (true);\n    }\n\n    // Normalize so sum of weights is 1.0 if point inside;\n    //\n    bool inside = true;\n    wTotal = 1.0 / wTotal;\n    for (int i = 0; i < n; i++) {\n        if (lambda[i] < 0.0) inside = false;\n        lambda[i] *= wTotal;\n    }\n\n    return (inside);\n}\n\nbool VAPoR::InsideConvexPolygon(const double verts[], const double pt[], int n)\n{\n    VAssert(n >= 3);\n\n    // Partition the convex polygon into a triangle fan, testing each triangle\n    // to see if it contains the point\n    //\n    double triverts[6];\n    triverts[0] = verts[0];\n    triverts[1] = verts[1];\n    double dummy[3];\n    for (int i = 2; i < n; i++) {\n        triverts[2] = verts[2 * (i - 1)];\n        triverts[3] = verts[2 * (i - 1) + 1];\n        triverts[4] = verts[2 * (i)];\n        triverts[5] = verts[2 * (i) + 1];\n        if (BarycentricCoordsTri(triverts, pt, dummy)) return (true);\n    }\n\n    return (false);\n}\n"
  },
  {
    "path": "lib/wasp/CMakeLists.txt",
    "content": "set (SRC\n\tCompressor.cpp\n\tMatWaveBase.cpp\n\tMatWaveDwt.cpp\n\tMatWaveWavedec.cpp\n\tNetCDFCpp.cpp\n\tSignificanceMap.cpp\n\tWASP.cpp\n\tWaveFiltBase.cpp\n\tWaveFiltBior.cpp\n\tWaveFiltCoif.cpp\n\tWaveFiltDaub.cpp\n\tWaveFiltHaar.cpp\n\tWaveFiltInt.cpp\n)\n\nset (HEADERS\n\t${PROJECT_SOURCE_DIR}/include/vapor/Compressor.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/MatWaveBase.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/MatWaveDwt.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/MatWaveWavedec.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/NetCDFCpp.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/SignificanceMap.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WASP.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltBase.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltBior.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltCoif.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltDaub.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltHaar.h\n\t${PROJECT_SOURCE_DIR}/include/vapor/WaveFiltInt.h\n)\n\nadd_library (wasp SHARED ${SRC} ${HEADERS})\n\ntarget_link_libraries (wasp PUBLIC common ${NETCDF})\n\nadd_definitions (-DWASP_EXPORTS)\n\ninstall (\n\tTARGETS wasp\n\tDESTINATION ${INSTALL_LIB_DIR}\n\tCOMPONENT Libraries\n\t)\n\ninstall (\n\tFILES ${HEADERS}\n\tDESTINATION ${INSTALL_INCLUDE_DIR}\n\tCOMPONENT Libraries\n\t)\n"
  },
  {
    "path": "lib/wasp/Compressor.cpp",
    "content": "//\n// $Id: Compressor.cpp,v 1.6 2013/05/15 23:05:48 clynejp Exp $\n//\n#include <cstring>\n#include <algorithm>\n#include <iostream>\n#include <cmath>\n#include <vapor/Compressor.h>\n\nusing namespace VAPoR;\nusing namespace std;\n\nvoid Compressor::_Compressor(vector<size_t> dims)\n{\n    if (dims.size() > 3) return;\n\n    _dims.clear();\n    _nlevels = 0;\n    _indexvec.clear();\n    _nx = 1;\n    _ny = 1;\n    _nz = 1;\n    _C = NULL;\n    _CLen = 0;\n    _L = NULL;\n    _LLen = 0;\n    _keepapp = true;\n    _clamp_min_flag = false;\n    _clamp_max_flag = false;\n    _epsilon_flag = false;\n    _clamp_min = 0.0;\n    _clamp_max = 1.0;\n    _epsilon = 0.0;\n\n    for (int i = 0; i < dims.size(); i++) { _dims.push_back(dims[i]); }\n\n    _nx = _ny = _nz = 1;\n    if (_dims.size() >= 1) _nx = _dims[0];\n    if (_dims.size() >= 2) _ny = _dims[1];\n    if (_dims.size() >= 3) _nz = _dims[2];\n\n    //\n    // Create an appropriate filter bank allocate memory for storing\n    // wavelet coefficients\n    //\n    if (_dims.size() == 3) {\n        _nlevels = min(min(wmaxlev(_nx), wmaxlev(_ny)), wmaxlev(_nz));\n\n        size_t clen = coefflength3(_nx, _ny, _nz, _nlevels);\n        _C = new double[clen];\n        _CLen = clen;\n\n        _L = new size_t[(21 * _nlevels) + 6];\n        _LLen = (21 * _nlevels) + 6;\n\n        // Compute the bookkeeping vector, L.\n        //\n        // N.B. L will be recomputed by wavedec(), but not\n        // waverec();\n        //\n        computeL3(_nx, _ny, _nz, _nlevels, _L);\n    } else if (_dims.size() == 2) {\n        _nlevels = min(wmaxlev(_nx), wmaxlev(_ny));\n\n        size_t clen = coefflength2(_nx, _ny, _nlevels);\n        _C = new double[clen];\n        _CLen = clen;\n\n        _L = new size_t[(6 * _nlevels) + 4];\n        _LLen = (6 * _nlevels) + 4;\n        computeL2(_nx, _ny, _nlevels, _L);\n    } else {\n        _nlevels = wmaxlev(_nx);\n\n        size_t clen = coefflength(_nx, _nlevels);\n        _C = new double[clen];\n        _CLen = clen;\n\n        _L = new size_t[_nlevels + 2];\n        _LLen = _nlevels + 2;\n        computeL(_nx, _nlevels, _L);\n    }\n    _indexvec.reserve(_CLen);\n}\n\nCompressor::Compressor(vector<size_t> dims, const string &wavename, const string &mode) : MatWaveWavedec(wavename, mode)\n{\n    _C = NULL;\n    _L = NULL;\n    _CLen = 0;\n    _LLen = 0;\n\n    _Compressor(dims);\n}\n\nCompressor::Compressor(vector<size_t> dims, const string &wavename) : MatWaveWavedec(wavename)\n{\n    _C = NULL;\n    _L = NULL;\n    _CLen = 0;\n    _LLen = 0;\n\n    _Compressor(dims);\n}\n\nCompressor::~Compressor()\n{\n    if (_C) delete[] _C;\n    if (_L) delete[] _L;\n}\n\n//\n// Comparision functions for the C++ Std Lib sort function\n//\ninline bool my_compare_f(const void *x1, const void *x2) { return (fabsf(*(float *)x1) > fabsf(*(float *)x2)); }\n\ninline bool my_compare_d(const void *x1, const void *x2) { return (fabs(*(double *)x1) > fabs(*(double *)x2)); }\n\ninline bool my_compare_i(const void *x1, const void *x2) { return (abs(*(int *)x1) > abs(*(int *)x2)); }\n\ninline bool my_compare_l(const void *x1, const void *x2) { return (labs(*(long *)x1) > labs(*(long *)x2)); }\n\nnamespace {\n\ntemplate<class T>\nint compress_template(Compressor *cmp, const T *src_arr, T *dst_arr, size_t dst_arr_len, T *C, size_t clen, size_t *L, SignificanceMap *sigmap, const vector<size_t> &dims, size_t nlevels,\n                      vector<void *> indexvec, bool my_compare(const void *, const void *))\n{\n    if (!C) {\n        Compressor::SetErrMsg(\"Invalid state\");\n        return (-1);\n    }\n\n    if ((dims.size() < 1) || (dims.size() > 3)) {\n        Compressor::SetErrMsg(\"Invalid array shape\");\n        return (-1);\n    }\n\n    if (dst_arr_len > clen) {\n        Compressor::SetErrMsg(\"Invalid array destination array length : %lu\", dst_arr_len);\n        return (-1);\n    }\n\n    //\n    // Forward wavelet transform the array and compute the number of\n    // approximation coefficients (numkeep).\n    //\n    size_t numkeep = 0;\n    int    rc = 0;\n    if (dims.size() == 3) {\n        if (cmp->KeepAppOnOff()) numkeep = L[0] * L[1] * L[2];\n        rc = cmp->wavedec3(src_arr, dims[0], dims[1], dims[2], nlevels, C, L);\n    } else if (dims.size() == 2) {\n        if (cmp->KeepAppOnOff()) numkeep = L[0] * L[1];\n        rc = cmp->wavedec2(src_arr, dims[0], dims[1], nlevels, C, L);\n    } else if (dims.size() == 1) {\n        if (cmp->KeepAppOnOff()) numkeep = L[0];\n        rc = cmp->wavedec(src_arr, dims[0], nlevels, C, L);\n    }\n    if (rc < 0) return (-1);\n\n    VAssert(dst_arr_len >= numkeep);\n\n    rc = sigmap->Reshape(clen);\n    if (rc < 0) return (-1);\n\n    sigmap->Clear();\n\n    // Data has been transformed. Now we need to sort it and find\n    // the threshold value. Note: we don't actually move the data. We\n    // sort an index array that references the data array.\n\n    for (size_t i = 0; i < dst_arr_len; i++) dst_arr[i] = 0.0;\n\n    if (numkeep) {\n        // If numkeep>0, copy approximation coeffs. verbatim\n        //\n        for (size_t idx = 0; idx < numkeep; idx++) {\n            rc = sigmap->Set(idx);\n            if (rc < 0) return (-1);\n            dst_arr[idx] = C[idx];\n        }\n        if (numkeep == dst_arr_len) return (0);\n        dst_arr += numkeep;\n        dst_arr_len -= numkeep;\n    }\n\n    indexvec.clear();\n    for (size_t i = numkeep; i < clen; i++) indexvec.push_back(&C[i]);\n    sort(indexvec.begin(), indexvec.end(), my_compare);\n\n    // Copy coefficients that are larger than the threshold to\n    // the destination array. Record their location in the significance\n    // map.\n    //\n\n    sort(indexvec.begin(), indexvec.begin() + dst_arr_len);\n    for (size_t idx = numkeep, i = 0; idx < clen && i < dst_arr_len; idx++) {\n        const T *cptr = (T *)indexvec[i];\n        dst_arr[i++] = *cptr;\n        sigmap->Set(cptr - C);\n    }\n    return (0);\n}\n};    // namespace\n\nint Compressor::Compress(const float *src_arr, float *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap)\n{\n    return compress_template(this, src_arr, dst_arr, dst_arr_len, (float *)_C, _CLen, _L, sigmap, _dims, _nlevels, _indexvec, my_compare_f);\n}\n\nint Compressor::Compress(const double *src_arr, double *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap)\n{\n    return compress_template(this, src_arr, dst_arr, dst_arr_len, (double *)_C, _CLen, _L, sigmap, _dims, _nlevels, _indexvec, my_compare_d);\n}\n\nint Compressor::Compress(const int *src_arr, int *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap)\n{\n    return compress_template(this, src_arr, dst_arr, dst_arr_len, (int *)_C, _CLen, _L, sigmap, _dims, _nlevels, _indexvec, my_compare_i);\n}\n\nint Compressor::Compress(const long *src_arr, long *dst_arr, size_t dst_arr_len, SignificanceMap *sigmap)\n{\n    return compress_template(this, src_arr, dst_arr, dst_arr_len, (long *)_C, _CLen, _L, sigmap, _dims, _nlevels, _indexvec, my_compare_l);\n}\n\nnamespace {\ntemplate<class T> int decompress_template(Compressor *cmp, const T *src_arr, T *dst_arr, T *C, size_t clen, const size_t *L, int nlevels, SignificanceMap *sigmap, const vector<size_t> &dims)\n{\n    if (!C) {\n        Compressor::SetErrMsg(\"Invalid state\");\n        return (-1);\n    }\n\n    if ((dims.size() < 1) || (dims.size() > 3)) {\n        Compressor::SetErrMsg(\"Invalid array shape\");\n        return (-1);\n    }\n\n    for (size_t i = 0; i < clen; i++) { C[i] = 0.0; }\n    //\n    // Restore the non-zero wavelet coefficients\n    //\n    sigmap->GetNextEntryRestart();\n\n    size_t nsig = sigmap->GetNumSignificant();\n    for (size_t i = 0; i < nsig; i++) {\n        size_t idx;\n\n        if (!sigmap->GetNextEntry(&idx)) {\n            Compressor::SetErrMsg(\"Invalid significance map\");\n            return (-1);\n        }\n\n        C[idx] = src_arr[i];\n    }\n\n    bool normalize = cmp->wavelet()->IsNormalized();\n\n    int    rc = 0;\n    size_t dst_dim[] = {1, 1, 1};\n    if (dims.size() == 3) {\n        // rc = cmp->waverec3(C, L, nlevels, dst_arr);\n        rc = cmp->appcoef3(C, L, nlevels, nlevels, normalize, dst_arr);\n        cmp->approxlength3(L, nlevels, nlevels, &dst_dim[0], &dst_dim[1], &dst_dim[2]);\n    } else if (dims.size() == 2) {\n        // rc = cmp->waverec2(C, L, nlevels, dst_arr);\n        rc = cmp->appcoef2(C, L, nlevels, nlevels, normalize, dst_arr);\n        cmp->approxlength2(L, nlevels, nlevels, &dst_dim[0], &dst_dim[1]);\n    } else if (dims.size() == 1) {\n        // cmp->waverec(C, L, nlevels, dst_arr);\n        rc = cmp->appcoef(C, L, nlevels, nlevels, normalize, dst_arr);\n        cmp->approxlength(L, nlevels, nlevels, &dst_dim[0]);\n    }\n    if (rc < 0) return (rc);\n\n    if (cmp->ClampMinOnOff() || cmp->ClampMaxOnOff() || cmp->EpsilonOnOff()) {\n        bool   clamp_min_f = cmp->ClampMinOnOff();\n        double clamp_min = cmp->ClampMin();\n        bool   clamp_max_f = cmp->ClampMaxOnOff();\n        double clamp_max = cmp->ClampMax();\n        bool   epsilon_f = cmp->EpsilonOnOff();\n        double epsilon = fabs(cmp->Epsilon());\n\n        size_t sz = dst_dim[0] * dst_dim[1] * dst_dim[2];\n        for (size_t i = 0; i < sz; i++) {\n            if (clamp_min_f && dst_arr[i] < clamp_min) dst_arr[i] = clamp_min;\n            if (clamp_max_f && dst_arr[i] > clamp_max) dst_arr[i] = clamp_max;\n            if (epsilon_f && abs(dst_arr[i]) < epsilon) dst_arr[i] = 0.0;\n        }\n    }\n\n    return (0);\n}\n\n};    // namespace\n\nint Compressor::Decompress(const float *src_arr, float *dst_arr, SignificanceMap *sigmap) { return decompress_template(this, src_arr, dst_arr, (float *)_C, _CLen, _L, _nlevels, sigmap, _dims); }\n\nint Compressor::Decompress(const double *src_arr, double *dst_arr, SignificanceMap *sigmap) { return decompress_template(this, src_arr, dst_arr, (double *)_C, _CLen, _L, _nlevels, sigmap, _dims); }\n\nint Compressor::Decompress(const int *src_arr, int *dst_arr, SignificanceMap *sigmap) { return decompress_template(this, src_arr, dst_arr, (int *)_C, _CLen, _L, _nlevels, sigmap, _dims); }\n\nint Compressor::Decompress(const long *src_arr, long *dst_arr, SignificanceMap *sigmap) { return decompress_template(this, src_arr, dst_arr, (long *)_C, _CLen, _L, _nlevels, sigmap, _dims); }\n\nnamespace {\ntemplate<class T>\nint decompose_template(Compressor *cmp, const T *src_arr, T *dst_arr, const vector<size_t> &dst_arr_lens, T *C, size_t clen, size_t *L, vector<SignificanceMap> &sigmaps, const vector<size_t> &dims,\n                       size_t nlevels, vector<void *> indexvec, bool my_compare(const void *, const void *))\n{\n    if (!C) {\n        Compressor::SetErrMsg(\"Invalid state\");\n        return (-1);\n    }\n\n    if (sigmaps.size() != dst_arr_lens.size()) {\n        Compressor::SetErrMsg(\"Invalid parameter\");\n        return (-1);\n    }\n\n    vector<size_t> my_dst_arr_lens = dst_arr_lens;\n\n    size_t tlen = 0;    // total # of coefficients to retain\n    for (int i = 0; i < my_dst_arr_lens.size(); i++) { tlen += my_dst_arr_lens[i]; }\n    if (tlen > clen) {\n        Compressor::SetErrMsg(\"Invalid decomposition\");\n        return (-1);\n    }\n\n    if ((dims.size() < 1) || (dims.size() > 3)) {\n        Compressor::SetErrMsg(\"Invalid array shape\");\n        return (-1);\n    }\n\n    //\n    // Forward wavelet transform the array and compute the number of\n    // approximation coefficients (numkeep).\n    //\n    size_t numkeep = 0;\n    int    rc = 0;\n    if (dims.size() == 3) {\n        if (cmp->KeepAppOnOff()) numkeep = L[0] * L[1] * L[2];\n        rc = cmp->wavedec3(src_arr, dims[0], dims[1], dims[2], nlevels, C, L);\n    } else if (dims.size() == 2) {\n        if (cmp->KeepAppOnOff()) numkeep = L[0] * L[1];\n        rc = cmp->wavedec2(src_arr, dims[0], dims[1], nlevels, C, L);\n    } else if (dims.size() == 1) {\n        if (cmp->KeepAppOnOff()) numkeep = L[0];\n        rc = cmp->wavedec(src_arr, dims[0], nlevels, C, L);\n    }\n    if (rc < 0) return (-1);\n\n    if (my_dst_arr_lens[0] < numkeep) {\n        Compressor::SetErrMsg(\"Invalid decomposition - not enougth coefficients\");\n        return (-1);\n    }\n\n    for (int i = 0; i < sigmaps.size(); i++) {\n        rc = sigmaps[i].Reshape(clen);\n        if (rc < 0) return (-1);\n        sigmaps[i].Clear();\n    }\n\n    // Data has been transformed. Now we need to sort it and find\n    // the threshold value. Note: we don't actually move the data. We\n    // sort an index array that references the data array.\n\n    for (size_t i = 0; i < tlen; i++) dst_arr[i] = 0.0;\n\n    if (numkeep) {\n        // If numkeep>0, copy approximation coeffs. verbatim\n        //\n        for (size_t idx = 0; idx < numkeep; idx++) {\n            rc = sigmaps[0].Set(idx);\n            if (rc < 0) return (-1);\n            dst_arr[idx] = C[idx];\n        }\n        if (numkeep == tlen) return (0);\n        dst_arr += numkeep;\n        my_dst_arr_lens[0] -= numkeep;\n    }\n\n    //\n    // sort the **indecies** of the coefficients based on the\n    // coefficient's magnitude\n    //\n    indexvec.clear();\n    for (size_t i = numkeep; i < clen; i++) indexvec.push_back(&C[i]);\n    sort(indexvec.begin(), indexvec.end(), my_compare);\n\n    vector<void *>::iterator itr = indexvec.begin();\n    for (int j = 0, idx = 0; j < my_dst_arr_lens.size(); j++) {\n        sort(itr, itr + my_dst_arr_lens[j]);    // sort coefficient's indecies\n        itr += my_dst_arr_lens[j];\n        for (int i = 0; i < my_dst_arr_lens[j]; i++, idx++) {\n            const T *cptr = (T *)indexvec[idx];\n            dst_arr[i] = *cptr;\n            sigmaps[j].Set(cptr - C);\n        }\n        dst_arr += my_dst_arr_lens[j];\n    }\n\n    return (0);\n}\n\ntemplate<class T>\nint reconstruct_template(Compressor *cmp, const T *src_arr, T *dst_arr, T *C, size_t clen, const size_t *L, int nlevels, int l, vector<SignificanceMap> &sigmaps, const vector<size_t> &dims)\n{\n    if (!C) {\n        Compressor::SetErrMsg(\"Invalid state\");\n        return (-1);\n    }\n\n    if ((dims.size() < 1) || (dims.size() > 3)) {\n        Compressor::SetErrMsg(\"Invalid array shape\");\n        return (-1);\n    }\n\n    for (size_t count = 0; count < clen; count++) { C[count] = 0.0; }\n\n    size_t count = 0;\n    size_t idx;\n    for (int j = 0; j < sigmaps.size(); j++) {\n        sigmaps[j].GetNextEntryRestart();\n\n        size_t nsig = sigmaps[j].GetNumSignificant();\n        for (size_t i = 0; i < nsig; i++) {\n            if (!sigmaps[j].GetNextEntry(&idx)) {\n                Compressor::SetErrMsg(\"Invalid significance map\");\n                return (-1);\n            }\n\n            C[idx] = src_arr[count];\n            count++;\n        }\n    }\n\n    bool normalize = cmp->wavelet()->IsNormalized();\n\n    int    rc = 0;\n    size_t dst_dim[] = {1, 1, 1};\n    if (dims.size() == 3) {\n        // cmp->waverec3(C, L, nlevels, dst_arr);\n        rc = cmp->appcoef3(C, L, nlevels, l, normalize, dst_arr);\n        cmp->approxlength3(L, nlevels, l, &dst_dim[0], &dst_dim[1], &dst_dim[2]);\n    } else if (dims.size() == 2) {\n        // cmp->waverec2(C, L, nlevels, dst_arr);\n        rc = cmp->appcoef2(C, L, nlevels, l, normalize, dst_arr);\n        cmp->approxlength2(L, nlevels, l, &dst_dim[0], &dst_dim[1]);\n    } else if (dims.size() == 1) {\n        // cmp->waverec(C, L, nlevels, dst_arr);\n        rc = cmp->appcoef(C, L, nlevels, l, normalize, dst_arr);\n        cmp->approxlength(L, nlevels, l, &dst_dim[0]);\n    }\n    if (rc < 0) return (-1);\n\n    if (cmp->ClampMinOnOff() || cmp->ClampMaxOnOff()) {\n        bool   clamp_min_f = cmp->ClampMinOnOff();\n        double clamp_min = cmp->ClampMin();\n        bool   clamp_max_f = cmp->ClampMaxOnOff();\n        double clamp_max = cmp->ClampMax();\n\n        size_t sz = dst_dim[0] * dst_dim[1] * dst_dim[2];\n        for (size_t i = 0; i < sz; i++) {\n            if (clamp_min_f && dst_arr[i] < clamp_min) dst_arr[i] = clamp_min;\n            if (clamp_max_f && dst_arr[i] > clamp_max) dst_arr[i] = clamp_max;\n        }\n    }\n\n    return (0);\n}\n\n};    // namespace\n\nint Compressor::Decompose(const float *src_arr, float *dst_arr, const vector<size_t> &dst_arr_lens, vector<SignificanceMap> &sigmaps)\n{\n    return decompose_template(this, src_arr, dst_arr, dst_arr_lens, (float *)_C, _CLen, _L, sigmaps, _dims, _nlevels, _indexvec, my_compare_f);\n}\n\nint Compressor::Decompose(const double *src_arr, double *dst_arr, const vector<size_t> &dst_arr_lens, vector<SignificanceMap> &sigmaps)\n{\n    return decompose_template(this, src_arr, dst_arr, dst_arr_lens, (double *)_C, _CLen, _L, sigmaps, _dims, _nlevels, _indexvec, my_compare_d);\n}\n\nint Compressor::Decompose(const int *src_arr, int *dst_arr, const vector<size_t> &dst_arr_lens, vector<SignificanceMap> &sigmaps)\n{\n    return decompose_template(this, src_arr, dst_arr, dst_arr_lens, (int *)_C, _CLen, _L, sigmaps, _dims, _nlevels, _indexvec, my_compare_i);\n}\n\nint Compressor::Decompose(const long *src_arr, long *dst_arr, const vector<size_t> &dst_arr_lens, vector<SignificanceMap> &sigmaps)\n{\n    return decompose_template(this, src_arr, dst_arr, dst_arr_lens, (long *)_C, _CLen, _L, sigmaps, _dims, _nlevels, _indexvec, my_compare_l);\n}\n\nint Compressor::Reconstruct(const float *src_arr, float *dst_arr, vector<SignificanceMap> &sigmaps, int l)\n{\n    if (l == -1) l = GetNumLevels();\n    return reconstruct_template(this, src_arr, dst_arr, (float *)_C, _CLen, _L, _nlevels, l, sigmaps, _dims);\n}\n\nint Compressor::Reconstruct(const double *src_arr, double *dst_arr, vector<SignificanceMap> &sigmaps, int l)\n{\n    if (l == -1) l = GetNumLevels();\n    return reconstruct_template(this, src_arr, dst_arr, (double *)_C, _CLen, _L, _nlevels, l, sigmaps, _dims);\n}\n\nint Compressor::Reconstruct(const int *src_arr, int *dst_arr, vector<SignificanceMap> &sigmaps, int l)\n{\n    if (l == -1) l = GetNumLevels();\n    return reconstruct_template(this, src_arr, dst_arr, (int *)_C, _CLen, _L, _nlevels, l, sigmaps, _dims);\n}\n\nint Compressor::Reconstruct(const long *src_arr, long *dst_arr, vector<SignificanceMap> &sigmaps, int l)\n{\n    if (l == -1) l = GetNumLevels();\n    return reconstruct_template(this, src_arr, dst_arr, (long *)_C, _CLen, _L, _nlevels, l, sigmaps, _dims);\n}\n\n#ifdef VAPOR3_0_0_ALPHA\nbool Compressor::IsCompressible(vector<size_t> dims, const string &wavename, const string &mode)\n{\n    if (dims.size() < 1 || dims.size() > 3) { return (false); }\n\n    size_t nx;\n    size_t ny;\n    size_t nz;\n\n    nx = ny = nz = 1;\n    if (dims.size() >= 1) nx = dims[0];\n    if (dims.size() >= 2) ny = dims[1];\n    if (dims.size() >= 3) nz = dims[2];\n\n    int nlevels;\n    if (dims.size() == 3) {\n        nlevels = min(min(wmaxlev(nx), wmaxlev(ny)), wmaxlev(nz));\n    } else if (dims.size() == 2) {\n        nlevels = min(wmaxlev(nx), wmaxlev(ny));\n    } else {\n        nlevels = wmaxlev(nx);\n    }\n\n    return (nlevels > 0);\n}\n#endif\n\nvoid Compressor::GetDimension(vector<size_t> &dims, int l) const\n{\n    if (l < 0 || l > _nlevels) l = _nlevels;\n\n    dims.clear();\n    for (int i = 0; i < _dims.size(); i++) {\n        size_t len = approxlength(_dims[i], _nlevels - l);\n        dims.push_back(len);\n    }\n}\n\nsize_t Compressor::GetMinCompression() const\n{\n    if (!_keepapp) return (1);\n\n    if (_dims.size() == 3) {\n        return (_L[0] * _L[1] * _L[2]);\n    } else if (_dims.size() == 2) {\n        return (_L[0] * _L[1]);\n    } else if (_dims.size() == 1) {\n        return (_L[0]);\n    }\n    return (0);\n}\n\nbool Compressor::CompressionInfo(vector<size_t> dims, const string wavename, bool keepapp, size_t &nlevels, size_t &maxcratio)\n{\n    nlevels = 0;\n    maxcratio = 0;\n\n    if (dims.size() < 1 || dims.size() > 3) return (false);\n\n    for (int i = 0; i < dims.size(); i++) {\n        if (dims[i] < 1) return (false);\n    }\n\n    MatWaveWavedec mww(wavename);\n\n    size_t ncoeff = 1;\n    for (int i = 0; i < dims.size(); i++) ncoeff *= dims[i];\n\n    size_t mincoeff = 1;\n    if (keepapp) {\n        size_t *L;\n        if (dims.size() == 1) {\n            nlevels = mww.wmaxlev(dims[0]);\n            L = new size_t[nlevels + 2];\n            mww.computeL(dims[0], nlevels, L);\n            mincoeff = L[0];\n        } else if (dims.size() == 2) {\n            nlevels = min(mww.wmaxlev(dims[0]), mww.wmaxlev(dims[1]));\n            L = new size_t[(6 * nlevels) + 4];\n            mww.computeL2(dims[0], dims[1], nlevels, L);\n            mincoeff = L[0] * L[1];\n        } else {    // dims.size() == 3\n            nlevels = min(min(mww.wmaxlev(dims[0]), mww.wmaxlev(dims[1])), mww.wmaxlev(dims[2]));\n            L = new size_t[(21 * nlevels) + 6];\n            mww.computeL3(dims[0], dims[1], dims[2], nlevels, L);\n            mincoeff = L[0] * L[1] * L[2];\n        }\n        delete[] L;\n    }\n    nlevels += 1;\n\n    maxcratio = ncoeff / mincoeff;\n    return (true);\n}\n\nnamespace VAPoR {\nostream &operator<<(std::ostream &o, const Compressor &rhs)\n{\n    o << \"Compressor:\" << endl;\n    o << \" Dimensions:\" << endl;\n    for (int i = 0; i < rhs._dims.size(); i++) { o << \"  \" << rhs._dims[i] << \" \"; }\n    o << endl;\n    o << \" Coefficients length \" << rhs._CLen << endl;\n    o << \" Book keeping length \" << rhs._LLen << endl;\n    o << \" Keep approx flag \" << rhs._keepapp << endl;\n    o << \" Clamp min flag \" << rhs._clamp_min_flag << endl;\n    o << \" Clamp max flag \" << rhs._clamp_max_flag << endl;\n    o << \" Clamp min \" << rhs._clamp_min << endl;\n    o << \" Clamp max \" << rhs._clamp_max << endl;\n    o << \" Epsilon flag \" << rhs._epsilon_flag << endl;\n    o << \" Epsilon \" << rhs._epsilon << endl;\n\n    return (o);\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/wasp/MatWaveBase.cpp",
    "content": "#include <iostream>\n#include <cmath>\n#include \"vapor/VAssert.h\"\n#include <vapor/MatWaveBase.h>\n#include <vapor/WaveFiltDaub.h>\n#include <vapor/WaveFiltCoif.h>\n#include <vapor/WaveFiltBior.h>\n#include <vapor/WaveFiltHaar.h>\n#include <vapor/WaveFiltInt.h>\n\nusing namespace VAPoR;\n\nMatWaveBase::MatWaveBase(const string &wname, const string &mode)\n{\n    _wf = NULL;\n    _mode = PER;\n    _wname = wname;\n\n    _wf = _create_wf(wname);\n    if (!_wf) return;\n\n    if (dwtmode(mode) < 0) {\n        return;    // nothing to do\n    };\n\n    _InvalidFloatAbort = false;\n}\n\nMatWaveBase::MatWaveBase(const string &wname)\n{\n    _wf = NULL;\n    _mode = PER;\n    _wname = wname;\n\n    _wf = _create_wf(wname);\n    if (!_wf) return;\n\n    string wmode;\n    if ((_wname.compare(\"bior1.1\") == 0) || (_wname.compare(\"bior1.3\") == 0) || (_wname.compare(\"bior1.5\") == 0) || (_wname.compare(\"bior3.3\") == 0) || (_wname.compare(\"bior3.5\") == 0)\n        || (_wname.compare(\"bior3.7\") == 0) || (_wname.compare(\"bior3.9\") == 0)) {\n        wmode = \"symh\";\n    } else if ((_wname.compare(\"bior2.2\") == 0) || (_wname.compare(\"bior2.4\") == 0) || (_wname.compare(\"bior2.6\") == 0) || (_wname.compare(\"bior2.8\") == 0) || (_wname.compare(\"bior4.4\") == 0)\n               || (_wname.compare(\"intbior2.2\") == 0)) {\n        wmode = \"symw\";\n    } else {\n        wmode = \"sp0\";\n    }\n    if (dwtmode(wmode) < 0) {\n        return;    // nothing to do\n    };\n\n    _InvalidFloatAbort = false;\n}\n\nMatWaveBase::~MatWaveBase()\n{\n    if (_wf) delete _wf;\n    _wf = NULL;\n}\n\nint MatWaveBase::dwtmode(const string &mode)\n{\n    dwtmode_t imode = _dwtmodestr2enum(mode);\n\n    if (imode == INVALID) {\n        SetErrMsg(\"Invalid boundary handling mode : %s\", mode.c_str());\n        return (-1);\n    }\n\n    _mode = imode;\n    return (0);\n}\n\nint MatWaveBase::dwtmode(dwtmode_t mode)\n{\n    if (mode == INVALID) {\n        SetErrMsg(\"Invalid boundary handling mode : %d\", mode);\n        return (-1);\n    }\n    _mode = mode;\n    return (0);\n}\n\nint MatWaveBase::wavelet(const string &wname)\n{\n    if (_wf) delete _wf;\n\n    _wf = _create_wf(wname);\n    if (!_wf) {\n        SetErrMsg(\"Invalid wavelet : %s\", wname.c_str());\n        return (-1);\n    }\n\n    return (0);\n}\n\nconst string MatWaveBase::dwtmode() const { return (_dwtmodeenum2str(_mode)); }\n\nsize_t MatWaveBase::wmaxlev(size_t s) const\n{\n    size_t lev, val;\n\n    if (!_wf) return (0);\n\n    int waveLength = _wf->GetLength();\n    _wave_len_validate(s, waveLength, &lev, &val);\n\n    if (!val) return (0);\n    return (lev);\n}\n\nsize_t MatWaveBase::detaillength(size_t sigInLen) const\n{\n    if (!_wf) return (0);\n\n    int filterLen = _wf->GetLength();\n\n    if (_mode == PER) {\n        return ((size_t)ceil(((double)(sigInLen)) / 2.0));\n    } else if (_wf->issymmetric()) {\n        if ((_mode == MatWaveBase::SYMW && (filterLen % 2)) || (_mode == MatWaveBase::SYMH && (!(filterLen % 2)))) {\n            if (sigInLen % 2) {\n                return ((sigInLen - 1) / 2);\n            } else {\n                return ((sigInLen) / 2);\n            }\n        }\n    }\n\n    return ((size_t)floor((sigInLen + filterLen - 1.0) / 2.0));\n}\n\nsize_t MatWaveBase::approxlength(size_t sigInLen) const\n{\n    if (!_wf) return (sigInLen);\n\n    int filterLen = _wf->GetLength();\n\n    if (_mode == PER) {\n        return ((size_t)ceil(((double)(sigInLen)) / 2.0));\n    } else if (_wf->issymmetric()) {\n        if ((_mode == MatWaveBase::SYMW && (filterLen % 2)) || (_mode == MatWaveBase::SYMH && (!(filterLen % 2)))) {\n            if (sigInLen % 2) {\n                return ((sigInLen + 1) / 2);\n            } else {\n                return ((sigInLen) / 2);\n            }\n        }\n    }\n\n    return ((size_t)floor((double)((sigInLen + filterLen - 1) / 2)));\n}\n\nvoid MatWaveBase::_wave_len_validate(size_t sigInLen, int waveLength, size_t *lev, size_t *status) const\n{\n    *lev = 0;\n    *status = 1;\n\n    double d = (log((double)sigInLen / (double)(waveLength)) / log(2.0));\n    if (d < 0) {\n        *status = 0;\n        return;\n    }\n    *lev = (int)d + 1;\n}\n\nWaveFiltBase *MatWaveBase::_create_wf(const string &wname) const\n{\n    WaveFiltBase *wf = NULL;\n\n    if (wname.compare(0, 2, \"db\") == 0) {\n        wf = new WaveFiltDaub(wname);\n    } else if (wname.compare(0, 4, \"coif\") == 0) {\n        wf = new WaveFiltCoif(wname);\n    } else if (wname.compare(0, 4, \"bior\") == 0) {\n        wf = new WaveFiltBior(wname);\n    } else if (wname.compare(0, 4, \"haar\") == 0) {\n        wf = new WaveFiltHaar();\n    } else if (wname.compare(0, 3, \"int\") == 0) {\n        wf = new WaveFiltInt(wname);\n    } else {\n        return (NULL);\n    }\n\n    return (wf);\n}\n\nMatWaveBase::dwtmode_t MatWaveBase::_dwtmodestr2enum(const string &mode) const\n{\n    if ((mode.compare(\"zpd\") == 0) || (mode.compare(\"ZPD\") == 0)) {\n        return (ZPD);\n    } else if ((mode.compare(\"symh\") == 0) || (mode.compare(\"SYMH\") == 0)) {\n        return (SYMH);\n    } else if ((mode.compare(\"symw\") == 0) || (mode.compare(\"SYMW\") == 0)) {\n        return (SYMW);\n    } else if ((mode.compare(\"asymh\") == 0) || (mode.compare(\"ASYMH\") == 0)) {\n        return (ASYMH);\n    } else if ((mode.compare(\"asymw\") == 0) || (mode.compare(\"ASYMW\") == 0)) {\n        return (ASYMW);\n    } else if ((mode.compare(\"sp0\") == 0) || (mode.compare(\"SP0\") == 0)) {\n        return (SP0);\n    } else if ((mode.compare(\"sp1\") == 0) || (mode.compare(\"SP1\") == 0)) {\n        return (SP1);\n    } else if ((mode.compare(\"spd\") == 0) || (mode.compare(\"SPD\") == 0)) {\n        return (SP1);\n    } else if ((mode.compare(\"ppd\") == 0) || (mode.compare(\"PPD\") == 0)) {\n        return (PPD);\n    } else if ((mode.compare(\"per\") == 0) || (mode.compare(\"PER\") == 0)) {\n        return (PER);\n    } else {\n        return (INVALID);\n    }\n}\n\nstring MatWaveBase::_dwtmodeenum2str(dwtmode_t mode) const\n{\n    switch (mode) {\n    case ZPD: return (\"zpd\"); break;\n    case SYMH: return (\"symh\"); break;\n    case SYMW: return (\"symw\"); break;\n    case ASYMH: return (\"asymh\"); break;\n    case ASYMW: return (\"asymw\"); break;\n    case SP0: return (\"sp0\"); break;\n    case SP1: return (\"sp1\"); break;\n    case PPD: return (\"ppd\"); break;\n    case PER: return (\"per\"); break;\n    default: return (\"invalid\"); break;\n    }\n}\n"
  },
  {
    "path": "lib/wasp/MatWaveDwt.cpp",
    "content": "#include <iostream>\n#include <limits>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <algorithm>\n#include <cstdio>\n#include <vapor/MatWaveDwt.h>\n#include <vapor/WaveFiltInt.h>\n#ifdef WIN32\n    #include <float.h>\n    #define isfinite _finite\n#endif\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\n// Notes on Symmetric Extension for Symmetric Filters from\n// G. Strang and T. Nguyen, \"Wavelets and Filter Banks\", chapter 8\n//\n// Forward xform\n// -------------\n//\n// Considerations for extention:\n//\n//\t1. When to repeat first and last samples (depends on filter length, N)\n//\t2. Where to start subsampling (depends on signal length, L)\n//\t3. How many subsamples to keep from each channel\n//\n// W extension: reflect about t==0. I.e x(-1) == x(1)\n// H extension: reflect about t==-1/2. I.e x(-1) == x(0)\n//\n// Goal: have symmetric extension after subsampling\n// - Use W extension for odd length filter. I.e. filters symmetric about t==0\n// - Use H extension for even length filter. I.e. filters symm about t==-0.5\n//\n// With W extension the extended signal has a period of 2(L-1). The filtered\n// signals (low-pass and high-pass) will both be symmetric. For even L there\n// will be 1/2(L+1) non-redundant low pass samples, and 1/2(L-1) non-redendant\n// high pass samples.\n//\n//\n// With H extension the extended signal has a period of 2L. The lowpass\n// filter will be symmetric, while high-pass is anti-symmetric.\n//\nnamespace {\n\n#ifdef DEBUG\ntemplate<class T> void printmatrix1d(const char *msg, const T *mat, size_t nx)\n{\n    fprintf(stdout, \"%s\\n\", msg);\n    for (size_t i = 0; i < nx; i++) { fprintf(stdout, \"%-10f\", (float)mat[i]); }\n    fprintf(stdout, \"\\n\");\n}\n\ntemplate<class T> void printmatrix2d(const char *msg, const T *mat, size_t nx, size_t ny)\n{\n    fprintf(stdout, \"%s\\n\", msg);\n    for (size_t j = 0; j < ny; j++) {\n        fprintf(stdout, \"%-4d\", j);\n        for (size_t i = 0; i < nx; i++) { fprintf(stdout, \"%-10f\", (float)mat[j * nx + i]); }\n        fprintf(stdout, \"\\n\");\n    }\n}\n\ntemplate<class T> void printmatrix3d(const char *msg, const T *mat, size_t nx, size_t ny, size_t nz)\n{\n    fprintf(stdout, \"%s\\n\", msg);\n\n    for (size_t k = 0; k < nz; k++) {\n        fprintf(stdout, \"\\n\");\n        for (size_t j = 0; j < ny; j++) {\n            fprintf(stdout, \"%-4d\", k);\n            for (size_t i = 0; i < nx; i++) { fprintf(stdout, \"%-10f\", (float)mat[k * nx * ny + j * nx + i]); }\n            fprintf(stdout, \"\\n\");\n        }\n    }\n}\n\n#else\n\n    #define printmatrix1d(a, b, c)\n    #define printmatrix2d(a, b, c, d)\n    #define printmatrix3d(a, b, c, d, e)\n\n#endif\n\n/*-------------------------------------------\n * Signal Extending\n *-----------------------------------------*/\n\ntemplate<class T> int valid_float(T *a, size_t n, bool invalid_float_abort)\n{\n    for (size_t i = 0; i < n; i++) {\n        if (!isfinite((double)a[i])) {\n            if (invalid_float_abort) {\n                MatWaveDwt::SetErrMsg(\"Invalid floating point value : %lf\", (double)a[i]);\n                return (-1);\n            }\n            a[i] = 0.0;\n        }\n    }\n    return (0);\n}\n\ntemplate<class T, class U> int wextend_1D_center(const T *sigIn, size_t sigInLen, U *sigOut, size_t addLen, MatWaveBase::dwtmode_t leftExtMethod, MatWaveBase::dwtmode_t rightExtMethod)\n{\n    int count = 0;\n\n    for (count = 0; count < addLen; count++) {\n        sigOut[count] = 0;\n        sigOut[count + sigInLen + addLen] = 0;\n    }\n\n    for (count = 0; count < sigInLen; count++) { sigOut[count + addLen] = sigIn[count]; }\n\n    if (!addLen) return (0);\n\n    switch (leftExtMethod) {\n    case MatWaveBase::ZPD: break;\n    case MatWaveBase::SYMH: {\n        for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[addLen - count - 1]; }\n        break;\n    }\n    case MatWaveBase::SYMW: {\n        for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[addLen - count]; }\n        break;\n    }\n    case MatWaveBase::ASYMH: {\n        for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[addLen - count - 1] * (-1); }\n        break;\n    }\n    case MatWaveBase::ASYMW: {\n        for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[addLen - count] * (-1); }\n        break;\n    }\n    case MatWaveBase::SP0: {\n        for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[0]; }\n        break;\n    }\n    case MatWaveBase::SP1: {\n        for (count = (addLen - 1); count >= 0; count--) { sigOut[count] = sigIn[0] - (sigIn[1] - sigIn[0]) * (addLen - count); }\n        break;\n    }\n    case MatWaveBase::PPD: {\n        for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[sigInLen - addLen + count]; }\n        break;\n    }\n    case MatWaveBase::PER: {\n        if (sigInLen % 2 == 0) {\n            for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[sigInLen - addLen + count]; }\n        } else {\n            sigOut[addLen - 1] = sigIn[sigInLen - 1];\n            addLen--;\n            for (count = 0; count < addLen; count++) { sigOut[count] = sigIn[sigInLen - addLen + count]; }\n        }\n        break;\n    }\n    default: break;\n    }\n\n    switch (rightExtMethod) {\n    case MatWaveBase::ZPD: break;\n    case MatWaveBase::SYMH: {\n        for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - count - 1]; }\n        break;\n    }\n    case MatWaveBase::SYMW: {\n        for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - count - 2]; }\n        break;\n    }\n    case MatWaveBase::ASYMH: {\n        for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - count - 1] * (-1); }\n        break;\n    }\n    case MatWaveBase::ASYMW: {\n        for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - count - 2] * (-1); }\n        break;\n    }\n    case MatWaveBase::SP0: {\n        for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[sigInLen - 1]; }\n        break;\n    }\n    case MatWaveBase::SP1: {\n        for (count = (addLen - 1); count >= 0; count--) { sigOut[sigInLen + 2 * addLen - count - 1] = sigIn[sigInLen - 1] - (sigIn[sigInLen - 2] - sigIn[sigInLen - 1]) * (addLen - count); }\n        break;\n    }\n    case MatWaveBase::PPD: {\n        for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[count]; }\n        break;\n    }\n    case MatWaveBase::PER: {\n        if (sigInLen % 2 == 0) {\n            for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen] = sigIn[count]; }\n        } else {\n            sigOut[addLen + sigInLen] = sigIn[sigInLen - 1];\n            addLen--;\n            for (count = 0; count < addLen; count++) { sigOut[count + sigInLen + addLen + 2] = sigIn[count]; }\n        }\n        break;\n    }\n    default: break;\n    }\n\n    return (0);\n}\n\n//\n// Perform single-level, 1D forward wavelet transform\n// (convolution + downsampling)\n//\n//\n// The number of samples computed for both cA and cD is: sigInLen / 2\n//\n// If oddlow is true the odd indexed low pass samples are computed (the first\n// input sample is ignored), else the even samples are computed. This\n// parameter provides control over the centering of the filter. Similar\n// for the oddhigh parameter.\n//\n// sigIn must contain sigInLen + filterLen + 1 samples if oddlow or oddhigh\n// is true, otherwise sigInLen + filterLen samples are required\n//\n// See G. Strang and T. Nguyen, \"Wavelets and Filter Banks\", chap 8, finite\n// length filters\n//\nvoid forward_xform(const double *sigIn, size_t sigInLen, const double *low_filter, const double *high_filter, int filterLen, double *cA, double *cD, bool oddlow, bool oddhigh)\n{\n    //\tVAssert(sigInLen > filterLen);\n\n    size_t xlstart = oddlow ? 1 : 0;\n    size_t xl;\n    size_t xhstart = oddhigh ? 1 : 0;\n    size_t xh;\n\n    for (size_t yi = 0; yi < sigInLen; yi += 2) {\n        cA[yi >> 1] = cD[yi >> 1] = 0.0;\n\n        xl = xlstart;\n        xh = xhstart;\n\n        for (int k = filterLen - 1; k >= 0; k--) {\n            cA[yi >> 1] += low_filter[k] * sigIn[xl];\n            cD[yi >> 1] += high_filter[k] * sigIn[xh];\n            xl++;\n            xh++;\n        }\n        xlstart += 2;\n        xhstart += 2;\n    }\n\n    return;\n}\n\nvoid inverse_xform_even(const double *cA, const double *cD, size_t sigOutLen, const double *low_filter, const double *high_filter, int filterLen, double *sigOut, bool matlab)\n{\n    size_t xi;    // input and out signal indecies\n    int    k;     // filter index\n\n    VAssert((filterLen % 2) == 0);\n\n    for (size_t yi = 0; yi < sigOutLen; yi++) {\n        sigOut[yi] = 0.0;\n\n        if (matlab || (filterLen >> 1) % 2) {    // odd length half filter\n            xi = yi >> 1;\n            if (yi % 2) {\n                k = filterLen - 1;\n            } else {\n                k = filterLen - 2;\n            }\n        } else {\n            xi = (yi + 1) >> 1;\n            if (yi % 2) {\n                k = filterLen - 2;\n            } else {\n                k = filterLen - 1;\n            }\n        }\n\n        for (; k >= 0; k -= 2) {\n            sigOut[yi] += (low_filter[k] * cA[xi]) + (high_filter[k] * cD[xi]);\n            xi++;\n        }\n    }\n\n    return;\n}\n\n//\n// Inverse transform for odd length, symmetric filters. In this case\n// it is assumed that cA coefficients come from even indexed samples\n// and cD coefficients come from odd indexed samples.\n//\n// See G. Strang and T. Nguyen, \"Wavelets and Filter Banks\",\n// chap 8, finite length filters\n//\nvoid inverse_xform_odd(const double *cA, const double *cD, size_t sigOutLen, const double *low_filter, const double *high_filter, int filterLen, double *sigOut)\n{\n    size_t xi;    // input and out signal indecies\n    int    k;     // filter index\n\n    VAssert((filterLen % 2) == 1);\n\n    for (size_t yi = 0; yi < sigOutLen; yi++) {\n        sigOut[yi] = 0.0;\n\n        xi = (yi + 1) >> 1;\n        if (yi % 2) {\n            k = filterLen - 2;\n        } else {\n            k = filterLen - 1;\n        }\n        for (; k >= 0; k -= 2) {\n            sigOut[yi] += (low_filter[k] * cA[xi]);\n            xi++;\n        }\n\n        xi = (yi) >> 1;\n        if (yi % 2) {\n            k = filterLen - 1;\n        } else {\n            k = filterLen - 2;\n        }\n        for (; k >= 0; k -= 2) {\n            sigOut[yi] += (high_filter[k] * cD[xi]);\n            xi++;\n        }\n    }\n\n    return;\n}\n\nvoid inverse_xform(const double *cA, const double *cD, size_t sigOutLen, const double *low_filter, const double *high_filter, int filterLen, double *sigOut, bool matlab)\n{\n    if (filterLen % 2) {\n        inverse_xform_odd(cA, cD, sigOutLen, low_filter, high_filter, filterLen, sigOut);\n    } else {\n        inverse_xform_even(cA, cD, sigOutLen, low_filter, high_filter, filterLen, sigOut, matlab);\n    }\n}\n\n#define Minimum(a, b) ((a < b) ? a : b)\n#define BlockSize     32\n\n//\n// blocked submatrix transpose suitable for multithreading\n//   *a : pointer to input matrix\n//   *b : pointer to output matrix\n//    p1,p2: starting index of submatrix (row,col)\n//    m1,m2: size of submatrix (row,col)\n//    s1,s2: size of entire matrix (row,col)\n//\n\ntemplate<class T, class U> void transpose(const T *a, U *b, size_t p1, size_t p2, size_t m1, size_t m2, size_t s1, size_t s2)\n{\n    size_t       I1, I2;\n    size_t       i1, i2;\n    size_t       q, r;\n    double       c0;\n    const size_t block = BlockSize;\n    for (I2 = p2; I2 < p2 + m2; I2 += block)\n        for (I1 = p1; I1 < p1 + m1; I1 += block)\n            for (i2 = I2; i2 < Minimum(I2 + block, p2 + m2); i2++)\n                for (i1 = I1; i1 < Minimum(I1 + block, p1 + m1); i1++) {\n                    q = i2 * s1 + i1;\n                    r = i1 * s2 + i2;\n                    c0 = a[q];\n                    b[r] = c0;\n                }\n}\n\n// specialization for Real -> Complex\n// note the S1 matrix dimension is for the Real matrix\n// and the size of the Complex output is then s2 x (S1/2+1)\n\n//\n// blocked matrix transpose single threaded\n//   *a : pointer to input matrix\n//   *b : pointer to output matrix\n//    s1,s2: size of entire matrix (row,col)\n//\n\ntemplate<class T, class U> void transpose(const T *a, U *b, size_t s1, size_t s2) { transpose(a, b, 0, 0, s1, s2, s1, s2); }\n\n};    // namespace\n\nMatWaveDwt::MatWaveDwt(const string &wname, const string &mode) : MatWaveBase(wname, mode) {}\n\nMatWaveDwt::MatWaveDwt(const string &wname) : MatWaveBase(wname) {}\n\nMatWaveDwt::~MatWaveDwt() {}\n\ntemplate<class T, class U, class V>\nint dwt_template(MatWaveDwt *dwt, const T *sigIn, size_t sigInLen, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *cA, U *cD, size_t L[3], SmartBuf &sbuf, V dummy)\n{\n    if (!wf) {\n        MatWaveDwt::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    if (dwt->wmaxlev(sigInLen) < 1) {\n        MatWaveDwt::SetErrMsg(\"Can't transform signal of length : %d\", sigInLen);\n        return (-1);\n    }\n    if (mode == MatWaveBase::PER) {\n        MatWaveDwt::SetErrMsg(\"Invalid boundary extension mode: %d\", mode);\n        return (-1);\n    }\n\n    L[0] = dwt->approxlength(sigInLen);\n    L[1] = dwt->detaillength(sigInLen);\n    L[2] = sigInLen;\n\n    int filterLen = wf->GetLength();\n\n    //\n    // See if we can do symmetric convolution\n    //\n    bool do_sym_conv = false;\n    if (wf->issymmetric()) {\n        if ((mode == MatWaveBase::SYMW && (filterLen % 2)) || (mode == MatWaveBase::SYMH && (!(filterLen % 2)))) { do_sym_conv = true; }\n    }\n\n    // cout << \"filter length \" << filterLen << endl;\n    // printmatrix1d(\"dwt: low pass decomp filter\", wf->GetLowDecomFilCoef(), filterLen);\n    // printmatrix1d(\"dwt: high pass decomp filter\", wf->GetHighDecomFilCoef(), filterLen);\n    // cout << endl;\n    printmatrix1d(\"dwt: input signal\", sigIn, sigInLen);\n\n    // length of signal after boundary extension. We extend both\n    // left and right boundary by the width of the filter.\n    //\n    size_t sigConvolvedLen = L[0] + L[1];\n    size_t extendLen;\n\n    bool oddlow = true;\n    bool oddhigh = true;\n    if (filterLen % 2) oddlow = false;\n    if (do_sym_conv) {\n        extendLen = filterLen >> 1;\n        if (sigInLen % 2) sigConvolvedLen += 1;\n    } else {\n        extendLen = filterLen - 1;\n    }\n    size_t sigExtendedLen = sigInLen + (2 * extendLen);\n\n    V *buf = (V *)sbuf.Alloc(sizeof(dummy) * (sigExtendedLen + sigConvolvedLen));\n\n    V *sigExtended = buf;\n    V *sigConvolved = sigExtended + sigExtendedLen;\n\n    // Signal boundary extension\n    //\n    int rc = wextend_1D_center(sigIn, sigInLen, sigExtended, extendLen, mode, mode);\n    if (rc < 0) return (-1);\n\n    //\tif (is_floating_point(*sigExtended)) {\n    if (!std::numeric_limits<V>::is_integer) {\n        int rc = valid_float(sigExtended, sigExtendedLen, dwt->InvalidFloatAbortOnOff());\n        if (rc < 0) return (-1);\n    }\n    printmatrix1d(\"dwt: extended signal\", sigExtended, sigExtendedLen);\n\n    // Peform either conventional or integer DWT. Assumes template V\n    // is either a double or long. Code won't compile for V of any\n    // other type.\n    //\n    if (!std::numeric_limits<V>::is_integer) {\n        const double *s = (double *)sigExtended;\n        double *      cAdbl = (double *)sigConvolved;\n        double *      cDdbl = (double *)sigConvolved + L[0];\n\n        forward_xform(s, L[0] + L[1], wf->GetLowDecomFilCoef(), wf->GetHighDecomFilCoef(), filterLen, cAdbl, cDdbl, oddlow, oddhigh);\n    } else {\n        const WaveFiltInt *wfi = dynamic_cast<const WaveFiltInt *>(wf);\n        VAssert(wfi != NULL);\n\n        const long *s = (const long *)sigExtended;\n        long *      cAlong = (long *)sigConvolved;\n        long *      cDlong = (long *)sigConvolved + L[0];\n\n        wfi->Analysis(s, L[0] + L[1], cAlong, cDlong, oddlow, oddhigh);\n    }\n\n    for (size_t i = 0; i < L[0]; i++) { cA[i] = sigConvolved[i]; }\n    printmatrix1d(\"dwt: convolved lowpass signal\", cA, L[0]);\n\n    for (size_t i = 0; i < L[1]; i++) { cD[i] = sigConvolved[i + L[0]]; }\n    printmatrix1d(\"dwt: convolved high signal\", cD, L[1]);\n\n    return (0);\n}\n\nint MatWaveDwt::dwt(const double *sigIn, size_t sigInLen, double *C, size_t L[3])\n{\n    double *cA = C;\n    double *cD = C + approxlength(sigInLen);\n    double  dummy = 0;\n\n    return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy));\n}\n\nint MatWaveDwt::dwt(const float *sigIn, size_t sigInLen, float *C, size_t L[3])\n{\n    float *cA = C;\n    float *cD = C + approxlength(sigInLen);\n    double dummy = 0;\n\n    return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy));\n}\n\nint MatWaveDwt::dwt(const double *sigIn, size_t sigInLen, double *cA, double *cD, size_t L[3])\n{\n    double dummy = 0;\n\n    return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy));\n}\n\nint MatWaveDwt::dwt(const float *sigIn, size_t sigInLen, float *cA, float *cD, size_t L[3])\n{\n    double dummy = 0;\n\n    return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy));\n}\n\nint MatWaveDwt::dwt(const long *sigIn, size_t sigInLen, long *C, size_t L[3])\n{\n    long *cA = C;\n    long *cD = C + approxlength(sigInLen);\n    long  dummy = 0;\n\n    return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy));\n}\n\nint MatWaveDwt::dwt(const int *sigIn, size_t sigInLen, int *C, size_t L[3])\n{\n    int *cA = C;\n    int *cD = C + approxlength(sigInLen);\n    long dummy = 0;\n\n    return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy));\n}\n\nint MatWaveDwt::dwt(const long *sigIn, size_t sigInLen, long *cA, long *cD, size_t L[3])\n{\n    long dummy = 0;\n\n    return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy));\n}\n\nint MatWaveDwt::dwt(const int *sigIn, size_t sigInLen, int *cA, int *cD, size_t L[3])\n{\n    long dummy = 0;\n\n    return (dwt_template(this, sigIn, sigInLen, wavelet(), dwtmodeenum(), cA, cD, L, _dwt1dSmartBuf, dummy));\n}\n\ntemplate<class T, class U, class V>\nint idwt_template(MatWaveDwt *dwt, const T *cA, const T *cD, const size_t L[3], const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *sigOut, SmartBuf &sbuf, V dummy)\n{\n    if (!wf) {\n        MatWaveDwt::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n    if (mode == MatWaveBase::PER) {\n        MatWaveDwt::SetErrMsg(\"Invalid boundary extension mode: %d\", mode);\n        return (-1);\n    }\n\n    int filterLen = wf->GetLength();\n\n    bool                   do_sym_conv = false;\n    MatWaveBase::dwtmode_t cALeftMode = mode;\n    MatWaveBase::dwtmode_t cARightMode = mode;\n    MatWaveBase::dwtmode_t cDLeftMode = mode;\n    MatWaveBase::dwtmode_t cDRightMode = mode;\n    if (wf->issymmetric()) {\n        if ((mode == MatWaveBase::SYMW && (filterLen % 2)) || (mode == MatWaveBase::SYMH && (!(filterLen % 2)))) {\n            if (mode == MatWaveBase::SYMH) {\n                cDLeftMode = MatWaveBase::ASYMH;\n                if (L[2] % 2) {\n                    cARightMode = MatWaveBase::SYMW;\n                    cDRightMode = MatWaveBase::ASYMW;\n                } else {\n                    cDRightMode = MatWaveBase::ASYMH;\n                }\n            } else {\n                cDLeftMode = MatWaveBase::SYMH;\n                if (L[2] % 2) {\n                    cARightMode = MatWaveBase::SYMW;\n                    cDRightMode = MatWaveBase::SYMH;\n                } else {\n                    cARightMode = MatWaveBase::SYMH;\n                }\n            }\n\n            do_sym_conv = true;\n        }\n    }\n\n    size_t cATempLen, cDTempLen, reconTempLen;\n\n    size_t extendLen = 0;\n    size_t cDPadLen = 0;\n    if (do_sym_conv) {\n        extendLen = filterLen >> 2;\n        if ((L[0] > L[1]) && (mode == MatWaveBase::SYMH)) cDPadLen = L[0];\n\n        cATempLen = L[0] + (2 * extendLen);\n\n        if (filterLen % 2) {\n            cDTempLen = L[1] + (2 * extendLen);\n        } else {\n            // cD length must be same as cA (it's not for odd length signals)\n            // if filter is even length\n            //\n            cDTempLen = cATempLen;\n        }\n#ifdef VAPOR3_0_0_ALPHA\n#endif\n    } else {\n        cATempLen = L[0];\n        cDTempLen = L[1];\n    }\n    reconTempLen = L[2];\n    if (reconTempLen % 2) reconTempLen++;\n\n    V *buf = (V *)sbuf.Alloc(sizeof(dummy) * (cATempLen + cDTempLen + reconTempLen + cDPadLen));\n\n    V *cATemp = buf;\n    V *cDTemp = cATemp + cATempLen;\n    V *reconTemp = cDTemp + cDTempLen;\n    V *cDPad = reconTemp + reconTempLen;\n\n    // printmatrix1d(\"idwt: low pass reconstruct filter\", wf->GetLowReconFilCoef(), filterLen);\n    // printmatrix1d(\"idwt: high pass reconstruct filter\", wf->GetHighReconFilCoef(), filterLen);\n    // cout << endl;\n\n    // For symmetric filters we need to add the boundary coefficients\n    //\n    if (do_sym_conv) {\n        int rc = wextend_1D_center(cA, L[0], cATemp, extendLen, cALeftMode, cARightMode);\n        if (rc < 0) return (-1);\n\n        // For odd length signals we need to add back the missing final cD\n        // coefficient before signal extension.\n        // See G. Strang and T. Nguyen, \"Wavelets and Filter Banks\",\n        // chap 8, finite length filters\n        //\n        if (cDPadLen) {\n            for (size_t i = 0; i < L[1]; i++) cDPad[i] = cD[i];\n            cDPad[L[1]] = 0.0;\n\n            rc = wextend_1D_center(cDPad, L[0], cDTemp, extendLen, cDLeftMode, cDRightMode);\n            if (rc < 0) return (-1);\n        } else {\n            rc = wextend_1D_center(cD, L[1], cDTemp, extendLen, cDLeftMode, cDRightMode);\n            if (rc < 0) return (-1);\n        }\n    } else {\n        for (size_t i = 0; i < L[0]; i++) { cATemp[i] = (V)cA[i]; }\n        for (size_t i = 0; i < L[1]; i++) { cDTemp[i] = (V)cD[i]; }\n    }\n    //\tif (is_floating_point(*cATemp)) {\n    if (!std::numeric_limits<V>::is_integer) {\n        int rc = valid_float(cATemp, cATempLen, dwt->InvalidFloatAbortOnOff());\n        if (rc < 0) return (-1);\n\n        rc = valid_float(cDTemp, cDTempLen, dwt->InvalidFloatAbortOnOff());\n        if (rc < 0) return (-1);\n    }\n\n    printmatrix1d(\"idwt: extended cA signal\", cATemp, cATempLen);\n    printmatrix1d(\"idwt: extended cD signal\", cDTemp, cDTempLen);\n\n    if (!std::numeric_limits<V>::is_integer) {\n        const double *cAdbl = (const double *)cATemp;\n        const double *cDdbl = (const double *)cDTemp;\n        double *      s = (double *)reconTemp;\n\n        inverse_xform(cAdbl, cDdbl, L[2], wf->GetLowReconFilCoef(), wf->GetHighReconFilCoef(), filterLen, s, !do_sym_conv);\n    } else {\n        const WaveFiltInt *wfi = dynamic_cast<const WaveFiltInt *>(wf);\n        VAssert(wfi != NULL);\n\n        const long *cAlong = (const long *)cATemp;\n        const long *cDlong = (const long *)cDTemp;\n        long *      s = (long *)reconTemp;\n\n        wfi->Synthesis(cAlong, cDlong, L[0], s);\n    }\n\n    for (size_t count = 0; count < L[2]; count++) { sigOut[count] = (U)reconTemp[count]; }\n    printmatrix1d(\"idwt: reconstructed signal\", sigOut, L[2]);\n\n    return (0);\n}\n\nint MatWaveDwt::idwt(const double *C, const size_t L[3], double *sigOut)\n{\n    const double *cA = C;\n    const double *cD = C + L[0];\n    double        dummy = 0;\n\n    return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt(const float *C, const size_t L[3], float *sigOut)\n{\n    const float *cA = C;\n    const float *cD = C + L[0];\n    double       dummy = 0;\n\n    return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt(const double *cA, const double *cD, const size_t L[3], double *sigOut)\n{\n    double dummy = 0;\n\n    return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt(const float *cA, const float *cD, const size_t L[3], float *sigOut)\n{\n    double dummy = 0;\n\n    return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt(const long *C, const size_t L[3], long *sigOut)\n{\n    const long *cA = C;\n    const long *cD = C + L[0];\n    long        dummy = 0;\n\n    return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt(const int *C, const size_t L[3], int *sigOut)\n{\n    const int *cA = C;\n    const int *cD = C + L[0];\n    long       dummy = 0;\n\n    return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt(const long *cA, const long *cD, const size_t L[3], long *sigOut)\n{\n    long dummy = 0;\n\n    return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt(const int *cA, const int *cD, const size_t L[3], int *sigOut)\n{\n    long dummy = 0;\n\n    return idwt_template(this, cA, cD, L, wavelet(), dwtmodeenum(), sigOut, _dwt1dSmartBuf, dummy);\n}\n\ntemplate<class T, class U, class V>\nint dwt2d_template(MatWaveDwt *dwt, const T *sigIn, size_t sigInX, size_t sigInY, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *cA, U *cDh, U *cDv, U *cDd, size_t L[10], SmartBuf &sbuf2d,\n                   SmartBuf &sbuf1d, V dummy)\n{\n    if (!wf) {\n        MatWaveDwt::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    //\n    // Store dimensions of cA, cDh, cDv, cDd, and original signal\n    // in book keeping vector, L\n    //\n    // N.B.\n    //\tL[0] == L[2]\n    //\tL[1] == L[5]\n    //\tL[3] == L[7]\n    //\tL[4] == L[6]\n    //\n    //\n    //      ____L[0]_______L[4]____\n    //      |          |          |\n    // L[1] |  cA      |  cDv     | L[5]\n    //      |  (LL)    |  (HL)    |\n    //      |          |          |\n    //      |---------------------|\n    //      |          |          |\n    //      |  cDh     |  cDd     | L[7]\n    // L[3] |  (LH)    |  (HH)    |\n    //      |          |          |\n    //      |__________|__________|\n    //         L[2]       L[6]\n\n    L[0] = dwt->approxlength(sigInX);\n    L[1] = dwt->approxlength(sigInY);    // cA\n    L[2] = dwt->approxlength(sigInX);\n    L[3] = dwt->detaillength(sigInY);    // cDh\n    L[4] = dwt->detaillength(sigInX);\n    L[5] = dwt->approxlength(sigInY);    // cDv\n    L[6] = dwt->detaillength(sigInX);\n    L[7] = dwt->detaillength(sigInY);    // cDd\n    L[8] = sigInX;\n    L[9] = sigInY;\n\n    // First: transform rows\n    //\n    size_t passXLen = (L[0] + L[4]) * sigInY;\n    size_t transposeLen = max(L[0], L[4]) * sigInY;\n    size_t passYLen = max(L[0], L[4]) * (L[1] + L[3]);\n\n    V *buf2d = (V *)sbuf2d.Alloc(sizeof(dummy) * (passXLen + transposeLen + passYLen));\n\n    V *cAXbuf = buf2d;\n    V *cDXbuf = cAXbuf + (L[0] * sigInY);\n\n    V *buftranspose = cAXbuf + passXLen;\n\n    V *cAYbuf = buftranspose + transposeLen;\n    V *cDYbuf = cAYbuf + (max(L[0], L[4]) * L[1]);\n\n    int rc;\n    for (size_t y = 0; y < sigInY; y++) {\n        size_t   xL[3];\n        const T *row = &sigIn[sigInX * y];\n        V *      cAptr = &cAXbuf[L[0] * y];\n        V *      cDptr = &cDXbuf[L[4] * y];\n\n        rc = dwt_template(dwt, row, sigInX, wf, mode, cAptr, cDptr, xL, sbuf1d, dummy);\n        if (rc < 0) return (-1);\n    }\n\n    // Second: transform columns. First approximation coefficients, then\n    // detail coefficients\n    //\n\n    transpose(cAXbuf, buftranspose, L[0], sigInY);\n\n    for (size_t y = 0; y < L[0]; y++) {\n        size_t   yL[3];\n        const V *row = &buftranspose[sigInY * y];\n        V *      cAptr = &cAYbuf[L[1] * y];\n        V *      cDptr = &cDYbuf[L[3] * y];\n\n        rc = dwt_template(dwt, row, sigInY, wf, mode, cAptr, cDptr, yL, sbuf1d, dummy);\n        if (rc < 0) return (-1);\n    }\n\n    transpose(cAYbuf, cA, L[1], L[0]);\n    transpose(cDYbuf, cDh, L[3], L[2]);\n\n    printmatrix2d(\"cA\", cA, L[0], L[1]);\n    printmatrix2d(\"cDh\", cDh, L[2], L[3]);\n\n    // Now detail coefficients\n    //\n    //\n    transpose(cDXbuf, buftranspose, L[4], sigInY);\n\n    for (size_t y = 0; y < L[4]; y++) {\n        size_t   yL[3];\n        const V *row = &buftranspose[sigInY * y];\n        V *      cAptr = &cAYbuf[L[1] * y];\n        V *      cDptr = &cDYbuf[L[3] * y];\n\n        rc = dwt_template(dwt, row, sigInY, wf, mode, cAptr, cDptr, yL, sbuf1d, dummy);\n        if (rc < 0) return (-1);\n    }\n    transpose(cAYbuf, cDv, L[5], L[4]);\n    transpose(cDYbuf, cDd, L[7], L[6]);\n\n    printmatrix2d(\"cDv\", cDv, L[4], L[5]);\n    printmatrix2d(\"cDd\", cDd, L[6], L[7]);\n\n    return (0);\n}\n\nint MatWaveDwt::dwt2d(const double *sigIn, size_t sigInX, size_t sigInY, double *C, size_t L[10])\n{\n    double *cA = C;\n    double *cDh = cA + (approxlength(sigInX) * approxlength(sigInY));\n    double *cDv = cDh + (approxlength(sigInX) * detaillength(sigInY));\n    double *cDd = cDv + (detaillength(sigInX) * approxlength(sigInY));\n    double  dummy = 0;\n\n    return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt2d(const float *sigIn, size_t sigInX, size_t sigInY, float *C, size_t L[10])\n{\n    float *cA = C;\n    float *cDh = cA + (approxlength(sigInX) * approxlength(sigInY));\n    float *cDv = cDh + (approxlength(sigInX) * detaillength(sigInY));\n    float *cDd = cDv + (detaillength(sigInX) * approxlength(sigInY));\n    double dummy = 0;\n\n    return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt2d(const double *sigIn, size_t sigInX, size_t sigInY, double *cA, double *cDh, double *cDv, double *cDd, size_t L[10])\n{\n    double dummy = 0;\n\n    return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt2d(const float *sigIn, size_t sigInX, size_t sigInY, float *cA, float *cDh, float *cDv, float *cDd, size_t L[10])\n{\n    double dummy = 0;\n\n    return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt2d(const long *sigIn, size_t sigInX, size_t sigInY, long *C, size_t L[10])\n{\n    long *cA = C;\n    long *cDh = cA + (approxlength(sigInX) * approxlength(sigInY));\n    long *cDv = cDh + (approxlength(sigInX) * detaillength(sigInY));\n    long *cDd = cDv + (detaillength(sigInX) * approxlength(sigInY));\n    long  dummy = 0;\n\n    return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt2d(const int *sigIn, size_t sigInX, size_t sigInY, int *C, size_t L[10])\n{\n    int *cA = C;\n    int *cDh = cA + (approxlength(sigInX) * approxlength(sigInY));\n    int *cDv = cDh + (approxlength(sigInX) * detaillength(sigInY));\n    int *cDd = cDv + (detaillength(sigInX) * approxlength(sigInY));\n    long dummy = 0;\n\n    return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt2d(const long *sigIn, size_t sigInX, size_t sigInY, long *cA, long *cDh, long *cDv, long *cDd, size_t L[10])\n{\n    long dummy = 0;\n\n    return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt2d(const int *sigIn, size_t sigInX, size_t sigInY, int *cA, int *cDh, int *cDv, int *cDd, size_t L[10])\n{\n    long dummy = 0;\n\n    return dwt2d_template(this, sigIn, sigInX, sigInY, wavelet(), dwtmodeenum(), cA, cDh, cDv, cDd, L, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\ntemplate<class T, class U, class V>\nint idwt2d_template(MatWaveDwt *dwt, const T *cA, const T *cDh, const T *cDv, const T *cDd, const size_t L[10], const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, U *sigOut, SmartBuf &sbuf2d,\n                    SmartBuf &sbuf1d, V dummy)\n{\n    if (!wf) {\n        MatWaveDwt::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    size_t passYLen = max(L[0], L[4]) * (L[1] + L[3]);\n    size_t transposeLen = max(L[0], L[4]) * L[9];\n    size_t passXLen = (L[0] + L[4]) * L[9];\n\n    V *buf2d = (V *)sbuf2d.Alloc(sizeof(dummy) * (passYLen + transposeLen + passXLen));\n\n    V *cAYbuf = buf2d;\n    V *cDYbuf = cAYbuf + (max(L[0], L[4]) * L[1]);\n\n    V *buftranspose = cAYbuf + passYLen;\n\n    V *cAXbuf = buftranspose + transposeLen;\n    V *cDXbuf = cAXbuf + (L[0] * L[9]);\n\n    // First: transform columns. First detail coefficients, then\n    // approximation coefficients\n    //\n\n    // cDv and cDd detail coefficients\n    //\n\n    transpose(cDv, cAYbuf, L[4], L[1]);\n    transpose(cDd, cDYbuf, L[4], L[3]);\n    int rc;\n    for (size_t y = 0; y < L[4]; y++) {\n        size_t   yL[3] = {L[1], L[3], L[9]};\n        const V *cAptr = &cAYbuf[L[1] * y];\n        const V *cDptr = &cDYbuf[L[3] * y];\n        V *      row = &buftranspose[L[9] * y];\n\n        rc = idwt_template(dwt, cAptr, cDptr, yL, wf, mode, row, sbuf1d, dummy);\n        if (rc < 0) return (-1);\n    }\n    transpose(buftranspose, cDXbuf, L[9], L[4]);\n    // printmatrix2d(\"cDXbuf\", cDXbuf, L[4], L[9]);\n\n    // cA approximation and cDh detail coefficients\n    //\n\n    transpose(cA, cAYbuf, L[0], L[1]);\n    transpose(cDh, cDYbuf, L[0], L[3]);\n    for (size_t y = 0; y < L[0]; y++) {\n        size_t   yL[3] = {L[1], L[3], L[9]};\n        const V *cAptr = &cAYbuf[L[1] * y];\n        const V *cDptr = &cDYbuf[L[3] * y];\n        V *      row = &buftranspose[L[9] * y];\n\n        rc = idwt_template(dwt, cAptr, cDptr, yL, wf, mode, row, sbuf1d, dummy);\n        if (rc < 0) return (-1);\n    }\n    transpose(buftranspose, cAXbuf, L[9], L[0]);\n\n    //\n    //  Second: tranform rows\n    //\n    for (size_t y = 0; y < L[9]; y++) {\n        size_t   xL[3] = {L[0], L[4], L[8]};\n        const V *cAptr = &cAXbuf[L[0] * y];\n        const V *cDptr = &cDXbuf[L[4] * y];\n        U *      row = &sigOut[L[8] * y];\n\n        rc = idwt_template(dwt, cAptr, cDptr, xL, wf, mode, row, sbuf1d, dummy);\n        if (rc < 0) return (-1);\n    }\n\n    return (0);\n}\n\nint MatWaveDwt::idwt2d(const double *C, const size_t L[10], double *sigOut)\n{\n    const double *cA = C;\n    const double *cDh = cA + (L[0] * L[1]);\n    const double *cDv = cDh + (L[2] * L[3]);\n    const double *cDd = cDv + (L[4] * L[5]);\n    double        dummy = 0;\n\n    return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt2d(const float *C, const size_t L[10], float *sigOut)\n{\n    const float *cA = C;\n    const float *cDh = cA + (L[0] * L[1]);\n    const float *cDv = cDh + (L[2] * L[3]);\n    const float *cDd = cDv + (L[4] * L[5]);\n    double       dummy = 0;\n\n    return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt2d(const double *cA, const double *cDh, const double *cDv, const double *cDd, const size_t L[10], double *sigOut)\n{\n    double dummy = 0;\n\n    return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt2d(const float *cA, const float *cDh, const float *cDv, const float *cDd, const size_t L[10], float *sigOut)\n{\n    double dummy = 0;\n\n    return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt2d(const long *C, const size_t L[10], long *sigOut)\n{\n    const long *cA = C;\n    const long *cDh = cA + (L[0] * L[1]);\n    const long *cDv = cDh + (L[2] * L[3]);\n    const long *cDd = cDv + (L[4] * L[5]);\n    long        dummy = 0;\n\n    return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt2d(const int *C, const size_t L[10], int *sigOut)\n{\n    const int *cA = C;\n    const int *cDh = cA + (L[0] * L[1]);\n    const int *cDv = cDh + (L[2] * L[3]);\n    const int *cDd = cDv + (L[4] * L[5]);\n    long       dummy = 0;\n\n    return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt2d(const long *cA, const long *cDh, const long *cDv, const long *cDd, const size_t L[10], long *sigOut)\n{\n    long dummy = 0;\n\n    return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt2d(const int *cA, const int *cDh, const int *cDv, const int *cDd, const size_t L[10], int *sigOut)\n{\n    long dummy = 0;\n\n    return idwt2d_template(this, cA, cDh, cDv, cDd, L, wavelet(), dwtmodeenum(), sigOut, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\ntemplate<class T, class V>\nint _dwtz_template(MatWaveDwt *dwt, V *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, T *cA, T *cD, SmartBuf &sbuf3d, SmartBuf &sbuf1d,\n                   V dummy)\n{\n    if (!wf) {\n        MatWaveDwt::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n    size_t cALen = dwt->approxlength(sigInZ);\n    size_t cDLen = dwt->detaillength(sigInZ);\n\n    size_t sigInLen = sigInX * sigInY * sigInZ;\n    size_t sigOutLen = sigInX * sigInY * (cALen + cDLen);\n\n    V *buf3d = (V *)sbuf3d.Alloc(sizeof(dummy) * (sigInLen + sigOutLen));\n\n    V *sigtranspose = buf3d;\n    V *cAbuf = sigtranspose + sigInLen;\n    V *cDbuf = cAbuf + (sigInX * sigInY * cALen);\n\n    // XZ plane transpose\n    //\n    transpose(sigIn, sigtranspose, sigInX * sigInY, sigInZ);\n\n    int rc;\n    for (size_t z = 0; z < sigInX; z++) {\n        for (size_t y = 0; y < sigInY; y++) {\n            size_t   L[3];\n            const V *row = &sigtranspose[sigInY * sigInZ * z + y * sigInZ];\n            V *      cAptr = &cAbuf[sigInY * cALen * z + y * cALen];\n            V *      cDptr = &cDbuf[sigInY * cDLen * z + y * cDLen];\n\n            rc = dwt_template(dwt, row, sigInZ, wf, mode, cAptr, cDptr, L, sbuf1d, dummy);\n            if (rc < 0) return (-1);\n        }\n    }\n\n    //\n    // now inverse transpose to restore original memory order\n    //\n    transpose(cAbuf, cA, cALen, sigInX * sigInY);\n    transpose(cDbuf, cD, cDLen, sigInX * sigInY);\n    return (0);\n}\n\ntemplate<class T, class V>\nint dwt3d_template(MatWaveDwt *dwt, const T *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, T *C, size_t L[27], SmartBuf &sbuf3d1,\n                   SmartBuf &sbuf3d2, SmartBuf &sbuf2d, SmartBuf &sbuf1d, V dummy)\n{\n    if (!wf) {\n        MatWaveDwt::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    //\n    // Store dimensions of  LLL, LLH, LHL, LHH, HLL,\n    // HLH, HHL, HHH\n    // in book keeping vector, L\n    //\n\n    //                  L[3]        L[15]\n    //               -----------------------\n    //              /          /          /|\n    //        L[5] /          /          / |\n    //            /  LLH     /  HLH     /  |\n    //           /          /          /   | L[16]\n    //          -----------------------    |\n    //         /          /          /|    |\n    //   L[2] /          /          / |   /|\n    //       /          /          /  |  / |\n    //      /___L[0]___/___L[12]__/   | /  | L[22]\n    //      |          |          |   |/   |\n    // L[1] |          |          |   /HHH /\n    //      |   LLL    |   HLL    |  /|   /\n    //      |          |          | / |  / L[23]\n    //      |---------------------|/  | /\n    //      |          |          |   |/\n    //      |          |          |   /\n    // L[7] |   LHL    |   HHL    |  /\n    //      |          |          | / L[20]\n    //      |__________|__________|/\n    //          L[6]       L[18]\n\n    // LLL\n    //\n    L[0] = dwt->approxlength(sigInX);\n    L[1] = dwt->approxlength(sigInY);\n    L[2] = dwt->approxlength(sigInZ);\n\n    // LLH\n    //\n    L[3] = dwt->approxlength(sigInX);\n    L[4] = dwt->approxlength(sigInY);\n    L[5] = dwt->detaillength(sigInZ);\n\n    // LHL\n    //\n    L[6] = dwt->approxlength(sigInX);\n    L[7] = dwt->detaillength(sigInY);\n    L[8] = dwt->approxlength(sigInZ);\n\n    // LHH\n    //\n    L[9] = dwt->approxlength(sigInX);\n    L[10] = dwt->detaillength(sigInY);\n    L[11] = dwt->detaillength(sigInZ);\n\n    // HLL\n    //\n    L[12] = dwt->detaillength(sigInX);\n    L[13] = dwt->approxlength(sigInY);\n    L[14] = dwt->approxlength(sigInZ);\n\n    // HLH\n    //\n    L[15] = dwt->detaillength(sigInX);\n    L[16] = dwt->approxlength(sigInY);\n    L[17] = dwt->detaillength(sigInZ);\n\n    // HHL\n    //\n    L[18] = dwt->detaillength(sigInX);\n    L[19] = dwt->detaillength(sigInY);\n    L[20] = dwt->approxlength(sigInZ);\n\n    // HHH\n    //\n    L[21] = dwt->detaillength(sigInX);\n    L[22] = dwt->detaillength(sigInY);\n    L[23] = dwt->detaillength(sigInZ);\n\n    L[24] = sigInX;\n    L[25] = sigInY;\n    L[26] = sigInZ;\n\n    T *cLLL = C;\n    T *cLLH = cLLL + L[0] * L[1] * L[2];\n    T *cLHL = cLLH + L[3] * L[4] * L[5];\n    T *cLHH = cLHL + L[6] * L[7] * L[8];\n    T *cHLL = cLHH + L[9] * L[10] * L[11];\n    T *cHLH = cHLL + L[12] * L[13] * L[14];\n    T *cHHL = cHLH + L[15] * L[16] * L[17];\n    T *cHHH = cHHL + L[18] * L[19] * L[20];\n\n    // First: transform XY planes\n    //\n    size_t passXYLen = (L[0] + L[12]) * (L[1] + L[7]) * sigInZ;\n\n    V *buf3d1 = (V *)sbuf3d1.Alloc(sizeof(dummy) * passXYLen);\n\n    V *xyC = buf3d1;\n    V *cAXYbuf = xyC;\n    V *cDhXYbuf = cAXYbuf + (L[0] * L[1] * sigInZ);\n    V *cDvXYbuf = cDhXYbuf + (L[6] * L[7] * sigInZ);\n    V *cDdXYbuf = cDvXYbuf + (L[12] * L[13] * sigInZ);\n\n    int rc;\n    for (size_t z = 0; z < sigInZ; z++) {\n        size_t   xyL[10];\n        const T *plane = &sigIn[sigInX * sigInY * z];\n        V *      cAptr = &cAXYbuf[L[0] * L[1] * z];\n        V *      cDhptr = &cDhXYbuf[L[6] * L[7] * z];\n        V *      cDvptr = &cDvXYbuf[L[12] * L[13] * z];\n        V *      cDdptr = &cDdXYbuf[L[18] * L[19] * z];\n\n        rc = dwt2d_template(dwt, plane, sigInX, sigInY, wf, mode, cAptr, cDhptr, cDvptr, cDdptr, xyL, sbuf2d, sbuf1d, dummy);\n        if (rc < 0) return (rc);\n    }\n\n    // Second: transform along Z\n    //\n\n    rc = _dwtz_template(dwt, cAXYbuf, L[0], L[1], sigInZ, wf, mode, cLLL, cLLH, sbuf3d2, sbuf1d, dummy);\n    if (rc < 0) return (rc);\n    printmatrix3d(\"cLLL\", cLLL, L[0], L[1], L[2]);\n    printmatrix3d(\"cLLH\", cLLH, L[3], L[4], L[5]);\n    rc = _dwtz_template(dwt, cDhXYbuf, L[6], L[7], sigInZ, wf, mode, cLHL, cLHH, sbuf3d2, sbuf1d, dummy);\n    if (rc < 0) return (rc);\n    printmatrix3d(\"cLHL\", cLHL, L[6], L[7], L[8]);\n    printmatrix3d(\"cLHH\", cLHH, L[9], L[10], L[11]);\n    rc = _dwtz_template(dwt, cDvXYbuf, L[12], L[13], sigInZ, wf, mode, cHLL, cHLH, sbuf3d2, sbuf1d, dummy);\n    if (rc < 0) return (rc);\n    printmatrix3d(\"cHLL\", cHLL, L[12], L[13], L[14]);\n    printmatrix3d(\"cHLH\", cHLH, L[15], L[16], L[17]);\n    rc = _dwtz_template(dwt, cDdXYbuf, L[18], L[19], sigInZ, wf, mode, cHHL, cHHH, sbuf3d2, sbuf1d, dummy);\n    if (rc < 0) return (rc);\n    printmatrix3d(\"cHHL\", cHHL, L[18], L[19], L[20]);\n    printmatrix3d(\"cHHH\", cHHH, L[21], L[22], L[23]);\n\n    return (0);\n}\n\nint MatWaveDwt::dwt3d(const double *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, double *C, size_t L[27])\n{\n    double dummy = 0.0;\n\n    return dwt3d_template(this, sigIn, sigInX, sigInY, sigInZ, wavelet(), dwtmodeenum(), C, L, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt3d(const float *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, float *C, size_t L[27])\n{\n    double dummy = 0.0;\n\n    return dwt3d_template(this, sigIn, sigInX, sigInY, sigInZ, wavelet(), dwtmodeenum(), C, L, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt3d(const long *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, long *C, size_t L[27])\n{\n    long dummy = 0.0;\n\n    return dwt3d_template(this, sigIn, sigInX, sigInY, sigInZ, wavelet(), dwtmodeenum(), C, L, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::dwt3d(const int *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int *C, size_t L[27])\n{\n    long dummy = 0.0;\n\n    return dwt3d_template(this, sigIn, sigInX, sigInY, sigInZ, wavelet(), dwtmodeenum(), C, L, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\ntemplate<class T, class V>\nint _idwtz_template(MatWaveDwt *dwt, T *cA, T *cD, size_t sigInX, size_t sigInY, size_t cALen, size_t cDLen, const WaveFiltBase *wf, MatWaveBase::dwtmode_t mode, V *sigOut, size_t sigOutZ,\n                    SmartBuf &sbuf3d, SmartBuf &sbuf1d, V dummy)\n{\n    if (!wf) {\n        MatWaveDwt::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    size_t sigInLen = sigInX * sigInY * (cALen + cDLen);\n    size_t sigOutLen = sigInX * sigInY * sigOutZ;\n\n    V *buf3d = (V *)sbuf3d.Alloc(sizeof(dummy) * (sigInLen + sigOutLen));\n\n    V *cAtranspose = buf3d;\n    V *cDtranspose = buf3d + (sigInX * sigInY * cALen);\n    V *sigtranspose = cAtranspose + sigInLen;\n\n    //\n    // transpose to Z memory order\n    //\n    transpose(cA, cAtranspose, sigInX * sigInY, cALen);\n    transpose(cD, cDtranspose, sigInX * sigInY, cDLen);\n\n    int rc;\n    for (size_t z = 0; z < sigInX; z++) {\n        for (size_t y = 0; y < sigInY; y++) {\n            size_t   zL[3] = {cALen, cDLen, sigOutZ};\n            const V *cAptr = &cAtranspose[sigInY * cALen * z + y * cALen];\n            const V *cDptr = &cDtranspose[sigInY * cDLen * z + y * cDLen];\n            V *      row = &sigtranspose[sigInY * sigOutZ * z + y * sigOutZ];\n\n            rc = idwt_template(dwt, cAptr, cDptr, zL, wf, mode, row, sbuf1d, dummy);\n            if (rc < 0) return (-1);\n        }\n    }\n\n    // Inverse transpose back to X memory order\n    //\n    transpose(sigtranspose, sigOut, sigOutZ, sigInY * sigInX);\n\n    return (0);\n}\n\ntemplate<class T, class U, class V>\nint idwt3d_template(MatWaveDwt *dwt, const T *cLLL, const T *cLLH, const T *cLHL, const T *cLHH, const T *cHLL, const T *cHLH, const T *cHHL, const T *cHHH, const size_t L[27], const WaveFiltBase *wf,\n                    MatWaveBase::dwtmode_t mode, U *sigOut, SmartBuf &sbuf3d1, SmartBuf &sbuf3d2, SmartBuf &sbuf2d, SmartBuf &sbuf1d, V dummy)\n{\n    if (!wf) {\n        MatWaveDwt::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    size_t passXYLen = (L[0] + L[12]) * (L[1] + L[7]) * L[26];\n\n    V *buf3d1 = (V *)sbuf3d1.Alloc(sizeof(dummy) * passXYLen);\n\n    V *xyC = buf3d1;\n    V *cAXYbuf = xyC;\n    V *cDhXYbuf = cAXYbuf + (L[0] * L[1] * L[26]);\n    V *cDvXYbuf = cDhXYbuf + (L[6] * L[7] * L[26]);\n    V *cDdXYbuf = cDvXYbuf + (L[12] * L[13] * L[26]);\n\n    // First: inverse transform along Z\n    //\n    int rc;\n    rc = _idwtz_template(dwt, cLLL, cLLH, L[0], L[1], L[2], L[5], wf, mode, cAXYbuf, L[26], sbuf3d2, sbuf1d, dummy);\n    if (rc < 0) return (-1);\n    rc = _idwtz_template(dwt, cLHL, cLHH, L[6], L[7], L[8], L[11], wf, mode, cDhXYbuf, L[26], sbuf3d2, sbuf1d, dummy);\n    if (rc < 0) return (-1);\n    rc = _idwtz_template(dwt, cHLL, cHLH, L[12], L[13], L[14], L[17], wf, mode, cDvXYbuf, L[26], sbuf3d2, sbuf1d, dummy);\n    if (rc < 0) return (-1);\n    rc = _idwtz_template(dwt, cHHL, cHHH, L[18], L[19], L[20], L[23], wf, mode, cDdXYbuf, L[26], sbuf3d2, sbuf1d, dummy);\n    if (rc < 0) return (-1);\n\n    // Second: inverse transform XY planes\n    //\n\n    size_t xyL[10] = {L[0], L[1], L[6], L[7], L[12], L[13], L[18], L[19], L[24], L[25]};\n    for (size_t z = 0; z < L[26]; z++) {\n        const V *cAptr = &cAXYbuf[L[0] * L[1] * z];\n        const V *cDhptr = &cDhXYbuf[L[6] * L[7] * z];\n        const V *cDvptr = &cDvXYbuf[L[12] * L[13] * z];\n        const V *cDdptr = &cDdXYbuf[L[18] * L[19] * z];\n        U *      plane = &sigOut[L[24] * L[25] * z];\n\n        rc = idwt2d_template(dwt, cAptr, cDhptr, cDvptr, cDdptr, xyL, wf, mode, plane, sbuf2d, sbuf1d, dummy);\n        if (rc < 0) return (-1);\n    }\n    return (0);\n}\n\nint MatWaveDwt::idwt3d(const double *C, const size_t L[27], double *sigOut)\n{\n    const double *cLLL = C;\n    const double *cLLH = cLLL + L[0] * L[1] * L[2];\n    const double *cLHL = cLLH + L[3] * L[4] * L[5];\n    const double *cLHH = cLHL + L[6] * L[7] * L[8];\n    const double *cHLL = cLHH + L[9] * L[10] * L[11];\n    const double *cHLH = cHLL + L[12] * L[13] * L[14];\n    const double *cHHL = cHLH + L[15] * L[16] * L[17];\n    const double *cHHH = cHHL + L[18] * L[19] * L[20];\n    double        dummy = 0.0;\n\n    return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt3d(const float *C, const size_t L[27], float *sigOut)\n{\n    const float *cLLL = C;\n    const float *cLLH = cLLL + L[0] * L[1] * L[2];\n    const float *cLHL = cLLH + L[3] * L[4] * L[5];\n    const float *cLHH = cLHL + L[6] * L[7] * L[8];\n    const float *cHLL = cLHH + L[9] * L[10] * L[11];\n    const float *cHLH = cHLL + L[12] * L[13] * L[14];\n    const float *cHHL = cHLH + L[15] * L[16] * L[17];\n    const float *cHHH = cHHL + L[18] * L[19] * L[20];\n    double       dummy = 0.0;\n\n    return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt3d(const double *cLLL, const double *cLLH, const double *cLHL, const double *cLHH, const double *cHLL, const double *cHLH, const double *cHHL, const double *cHHH,\n                       const size_t L[27], double *sigOut)\n{\n    double dummy = 0.0;\n\n    return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt3d(const float *cLLL, const float *cLLH, const float *cLHL, const float *cLHH, const float *cHLL, const float *cHLH, const float *cHHL, const float *cHHH, const size_t L[27],\n                       float *sigOut)\n{\n    double dummy = 0.0;\n\n    return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt3d(const long *C, const size_t L[27], long *sigOut)\n{\n    const long *cLLL = C;\n    const long *cLLH = cLLL + L[0] * L[1] * L[2];\n    const long *cLHL = cLLH + L[3] * L[4] * L[5];\n    const long *cLHH = cLHL + L[6] * L[7] * L[8];\n    const long *cHLL = cLHH + L[9] * L[10] * L[11];\n    const long *cHLH = cHLL + L[12] * L[13] * L[14];\n    const long *cHHL = cHLH + L[15] * L[16] * L[17];\n    const long *cHHH = cHHL + L[18] * L[19] * L[20];\n    long        dummy = 0.0;\n\n    return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt3d(const int *C, const size_t L[27], int *sigOut)\n{\n    const int *cLLL = C;\n    const int *cLLH = cLLL + L[0] * L[1] * L[2];\n    const int *cLHL = cLLH + L[3] * L[4] * L[5];\n    const int *cLHH = cLHL + L[6] * L[7] * L[8];\n    const int *cHLL = cLHH + L[9] * L[10] * L[11];\n    const int *cHLH = cHLL + L[12] * L[13] * L[14];\n    const int *cHHL = cHLH + L[15] * L[16] * L[17];\n    const int *cHHH = cHHL + L[18] * L[19] * L[20];\n    long       dummy = 0.0;\n\n    return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt3d(const long *cLLL, const long *cLLH, const long *cLHL, const long *cLHH, const long *cHLL, const long *cHLH, const long *cHHL, const long *cHHH, const size_t L[27], long *sigOut)\n{\n    long dummy = 0.0;\n\n    return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n\nint MatWaveDwt::idwt3d(const int *cLLL, const int *cLLH, const int *cLHL, const int *cLHH, const int *cHLL, const int *cHLH, const int *cHHL, const int *cHHH, const size_t L[27], int *sigOut)\n{\n    long dummy = 0.0;\n\n    return idwt3d_template(this, cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L, wavelet(), dwtmodeenum(), sigOut, _dwt3dSmartBuf1, _dwt3dSmartBuf2, _dwt2dSmartBuf, _dwt1dSmartBuf, dummy);\n}\n"
  },
  {
    "path": "lib/wasp/MatWaveWavedec.cpp",
    "content": "\n#include <iostream>\n#include \"vapor/VAssert.h\"\n#include <cmath>\n#include <algorithm>\n#include <vapor/MatWaveWavedec.h>\n\nusing namespace VAPoR;\n\nMatWaveWavedec::MatWaveWavedec(const string &wname, const string &mode) : MatWaveDwt(wname, mode) {}\n\nMatWaveWavedec::MatWaveWavedec(const string &wname) : MatWaveDwt(wname) {}\n\nMatWaveWavedec::~MatWaveWavedec() {}\n\ntemplate<class T> int wavedec_template(MatWaveWavedec *mww, const T *sigIn, size_t sigInLength, int n, T *C, size_t *L)\n{\n    if (!mww->wavelet()) {\n        MatWaveWavedec::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    if (n < 0 || n > mww->wmaxlev(sigInLength)) {\n        MatWaveWavedec::SetErrMsg(\"Invalid number of transforms : %d\", n);\n        return (-1);\n    }\n\n    //\n    // Compute bookkeeping vector, L, and length of output vector, C\n    //\n    mww->computeL(sigInLength, n, L);\n    size_t CLength = mww->coefflength(L, n);\n\n    if (n == 0) {\n        for (size_t i = 0; i < sigInLength; i++) C[i] = sigIn[i];\n        return (0);\n    }\n\n    int      rc;\n    const T *sigInPtr = sigIn;\n\n    size_t len = sigInLength;\n    size_t cALen = mww->MatWaveBase::approxlength(len);\n    T *    cptr;\n    size_t tlen = 0;\n    size_t L1d[3];\n    for (int i = n; i > 0; i--) {\n        tlen += L[i];\n        cptr = C + CLength - tlen - cALen;\n        rc = mww->dwt(sigInPtr, len, cptr, L1d);\n        if (rc < 0) return (rc);\n\n        len = cALen;\n        cALen = mww->MatWaveBase::approxlength(cALen);\n        sigInPtr = cptr;\n    }\n\n    return (0);\n}\n\nint MatWaveWavedec::wavedec(const double *sigIn, size_t sigInLength, int n, double *C, size_t *L) { return wavedec_template(this, sigIn, sigInLength, n, C, L); }\n\nint MatWaveWavedec::wavedec(const float *sigIn, size_t sigInLength, int n, float *C, size_t *L) { return wavedec_template(this, sigIn, sigInLength, n, C, L); }\n\nint MatWaveWavedec::wavedec(const long *sigIn, size_t sigInLength, int n, long *C, size_t *L) { return wavedec_template(this, sigIn, sigInLength, n, C, L); }\n\nint MatWaveWavedec::wavedec(const int *sigIn, size_t sigInLength, int n, int *C, size_t *L) { return wavedec_template(this, sigIn, sigInLength, n, C, L); }\n\ntemplate<class T> int waverec_template(MatWaveWavedec *mww, const T *C, const size_t *L, int n, int l, bool normal, T *sigOut)\n{\n    if (!mww->wavelet()) {\n        MatWaveWavedec::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n    if (n < 0) {\n        MatWaveWavedec::SetErrMsg(\"Invalid number of transforms : %d\", n);\n        return (-1);\n    }\n\n    if (l < 0 || l > n) l = n;\n    int LLength = n + 2;\n\n    if (l == 0) {\n        double scale = 1.0;\n        if (normal) {\n            for (int i = l; i < n; i++) scale /= sqrt(2.0);\n        }\n        for (size_t i = 0; i < L[0]; i++) sigOut[i] = scale * C[i];\n        return (0);\n    }\n\n    const T *cA = C;\n    const T *cD = cA + L[0];\n    size_t   L1d[3] = {L[0], L[1], 0};\n    for (int i = 1; i <= l; i++) {\n        L1d[2] = mww->approxlength(L[LLength - 1], n - i);\n\n        int rc = mww->idwt(cA, cD, L1d, sigOut);\n        if (rc < 0) return (rc);\n        if (i == l) break;\n\n        cA = sigOut;\n        cD += L[i];\n        L1d[0] = L1d[2];\n        L1d[1] = L[i + 1];\n    }\n\n    if (l != n && normal) {\n        double scale = 1.0;\n        for (int i = l; i < n; i++) scale /= sqrt(2.0);\n        for (size_t i = 0; i < L1d[2]; i++) sigOut[i] *= scale;\n    }\n\n    return (0);\n}\n\nint MatWaveWavedec::waverec(const double *C, const size_t *L, int n, double *sigOut) { return waverec_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec(const float *C, const size_t *L, int n, float *sigOut) { return waverec_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec(const long *C, const size_t *L, int n, long *sigOut) { return waverec_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec(const int *C, const size_t *L, int n, int *sigOut) { return waverec_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::appcoef(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut) { return waverec_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut) { return waverec_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut) { return waverec_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut) { return waverec_template(this, C, L, n, l, normal, sigOut); }\n\ntemplate<class T> int wavedec2_template(MatWaveWavedec *mww, const T *sigIn, size_t sigInX, size_t sigInY, int n, T *C, size_t *L)\n{\n    if (!mww->wavelet()) {\n        MatWaveWavedec::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    if (n < 0 || n > min(mww->wmaxlev(sigInX), mww->wmaxlev(sigInY))) {\n        MatWaveWavedec::SetErrMsg(\"Invalid number of transforms : %d\", n);\n        return (-1);\n    }\n\n    mww->computeL2(sigInX, sigInY, n, L);\n    size_t CLength = mww->coefflength2(L, n);\n\n    if (n == 0) {\n        for (size_t j = 0; j < sigInY; j++) {\n            for (size_t i = 0; i < sigInX; i++) { *C++ = *sigIn++; }\n        }\n        return (0);\n    }\n\n    int      rc;\n    const T *sigInPtr = sigIn;\n\n    size_t lenx = sigInX;\n    size_t leny = sigInY;\n    size_t cALenX = mww->MatWaveBase::approxlength(sigInX);\n    size_t cALenY = mww->MatWaveBase::approxlength(sigInY);\n    T *    cptr;\n    size_t tlen = 0;\n\n    size_t L2d[10];\n    for (int i = n; i > 0; i--) {\n        tlen += (L[(6 * i) - 4] * L[(6 * i) - 3]) +    // cDh\n                (L[(6 * i) - 2] * L[(6 * i) - 1]) +    // cDv\n                (L[(6 * i) + 0] * L[(6 * i) + 1]);     // cDd\n\n        cptr = C + CLength - tlen - (cALenX * cALenY);\n\n        rc = mww->dwt2d(sigInPtr, lenx, leny, cptr, L2d);\n        if (rc < 0) return (rc);\n\n        lenx = cALenX;\n        leny = cALenY;\n        cALenX = mww->MatWaveBase::approxlength(cALenX);\n        cALenY = mww->MatWaveBase::approxlength(cALenY);\n        sigInPtr = cptr;\n    }\n\n    return (0);\n}\n\nint MatWaveWavedec::wavedec2(const double *sigIn, size_t sigInX, size_t sigInY, int n, double *C, size_t *L) { return wavedec2_template(this, sigIn, sigInX, sigInY, n, C, L); }\n\nint MatWaveWavedec::wavedec2(const float *sigIn, size_t sigInX, size_t sigInY, int n, float *C, size_t *L) { return wavedec2_template(this, sigIn, sigInX, sigInY, n, C, L); }\n\nint MatWaveWavedec::wavedec2(const long *sigIn, size_t sigInX, size_t sigInY, int n, long *C, size_t *L) { return wavedec2_template(this, sigIn, sigInX, sigInY, n, C, L); }\n\nint MatWaveWavedec::wavedec2(const int *sigIn, size_t sigInX, size_t sigInY, int n, int *C, size_t *L) { return wavedec2_template(this, sigIn, sigInX, sigInY, n, C, L); }\n\ntemplate<class T> int waverec2_template(MatWaveWavedec *mww, const T *C, const size_t *L, int n, int l, bool normal, T *sigOut)\n{\n    if (!mww->wavelet()) {\n        MatWaveWavedec::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    if (n < 0) {\n        MatWaveWavedec::SetErrMsg(\"Invalid number of transforms : %d\", n);\n        return (-1);\n    }\n\n    if (l < 0 || l > n) l = n;\n    int LLength = 6 * n + 4;\n\n    if (l == 0) {\n        double scale = 1.0;\n        if (normal) {\n            for (int i = l; i < n; i++) scale /= (sqrt(2.0) * sqrt(2.0));\n        }\n        for (size_t j = 0; j < L[3]; j++) {\n            for (size_t i = 0; i < L[2]; i++) { *sigOut++ = scale * *C++; }\n        }\n        return (0);\n    }\n\n    const T *cA = C;\n    const T *cDh = cA + L[0] * L[1];\n    const T *cDv = cDh + L[2] * L[3];\n    const T *cDd = cDv + L[4] * L[5];\n\n    size_t L2d[10] = {L[0], L[1], L[2], L[3], L[4], L[5], L[6], L[7], 0, 0};\n    for (int i = 1; i <= l; i++) {\n        L2d[8] = mww->approxlength(L[LLength - 2], n - i);\n        L2d[9] = mww->approxlength(L[LLength - 1], n - i);\n\n        int rc = mww->idwt2d(cA, cDh, cDv, cDd, L2d, sigOut);\n        if (rc < 0) return (rc);\n        if (i == l) break;\n\n        cA = sigOut;\n        cDh += L[6 * (i - 1) + 2] * L[6 * (i - 1) + 3] + L[6 * (i - 1) + 4] * L[6 * (i - 1) + 5] + L[6 * (i - 1) + 6] * L[6 * (i - 1) + 7];\n\n        cDv = cDh + L[6 * i + 2] * L[6 * i + 3];\n        cDd = cDv + L[6 * i + 4] * L[6 * i + 5];\n\n        L2d[0] = L2d[8];\n        L2d[1] = L2d[9];\n        L2d[2] = L[6 * i + 2];\n        L2d[3] = L[6 * i + 3];\n        L2d[4] = L[6 * i + 4];\n        L2d[5] = L[6 * i + 5];\n        L2d[6] = L[6 * i + 6];\n        L2d[7] = L[6 * i + 7];\n    }\n\n    if (l != n && normal) {\n        double scale = 1.0;\n        for (int i = l; i < n; i++) scale /= (sqrt(2.0) * sqrt(2.0));\n        for (size_t i = 0; i < L2d[8] * L2d[9]; i++) sigOut[i] *= scale;\n    }\n\n    return (0);\n}\n\nint MatWaveWavedec::waverec2(const double *C, const size_t *L, int n, double *sigOut) { return waverec2_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec2(const float *C, const size_t *L, int n, float *sigOut) { return waverec2_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec2(const long *C, const size_t *L, int n, long *sigOut) { return waverec2_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec2(const int *C, const size_t *L, int n, int *sigOut) { return waverec2_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::appcoef2(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut) { return waverec2_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef2(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut) { return waverec2_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef2(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut) { return waverec2_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef2(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut) { return waverec2_template(this, C, L, n, l, normal, sigOut); }\n\ntemplate<class T> int wavedec3_template(MatWaveWavedec *mww, const T *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, T *C, size_t *L)\n{\n    if (!mww->wavelet()) {\n        MatWaveWavedec::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    if (n < 0 || n > min(min(mww->wmaxlev(sigInX), mww->wmaxlev(sigInY)), mww->wmaxlev(sigInZ))) {\n        MatWaveWavedec::SetErrMsg(\"Invalid number of transforms : %d\", n);\n        return (-1);\n    }\n\n    mww->computeL3(sigInX, sigInY, sigInZ, n, L);\n    size_t CLength = mww->coefflength3(L, n);\n\n    if (n == 0) {\n        for (size_t k = 0; k < sigInZ; k++) {\n            for (size_t j = 0; j < sigInY; j++) {\n                for (size_t i = 0; i < sigInX; i++) { *C++ = *sigIn++; }\n            }\n        }\n        return (0);\n    }\n\n    int      rc;\n    const T *sigInPtr = sigIn;\n\n    size_t lenx = sigInX;\n    size_t leny = sigInY;\n    size_t lenz = sigInZ;\n    size_t cALenX = mww->MatWaveBase::approxlength(sigInX);\n    size_t cALenY = mww->MatWaveBase::approxlength(sigInY);\n    size_t cALenZ = mww->MatWaveBase::approxlength(sigInZ);\n    T *    cptr;\n    size_t tlen = 0;\n\n    size_t L3d[27];\n\n    for (int i = n; i > 0; i--) {\n        tlen += (L[(21 * i) - 18] * L[(21 * i) - 17] * L[(21 * i) - 16]) +    // cLLH\n                (L[(21 * i) - 15] * L[(21 * i) - 14] * L[(21 * i) - 13]) +    // cLHL\n                (L[(21 * i) - 12] * L[(21 * i) - 11] * L[(21 * i) - 10]) +    // cLHH\n                (L[(21 * i) - 9] * L[(21 * i) - 8] * L[(21 * i) - 7]) +       // cHLL\n                (L[(21 * i) - 6] * L[(21 * i) - 5] * L[(21 * i) - 4]) +       // cHLH\n                (L[(21 * i) - 3] * L[(21 * i) - 2] * L[(21 * i) - 1]) +       // HHL\n                (L[(21 * i) + 0] * L[(21 * i) + 1] * L[(21 * i) + 2]);        // HHH\n\n        cptr = C + CLength - tlen - (cALenX * cALenY * cALenZ);\n\n        rc = mww->dwt3d(sigInPtr, lenx, leny, lenz, cptr, L3d);\n        if (rc < 0) return (rc);\n\n        lenx = cALenX;\n        leny = cALenY;\n        lenz = cALenZ;\n\n        cALenX = mww->MatWaveBase::approxlength(cALenX);\n        cALenY = mww->MatWaveBase::approxlength(cALenY);\n        cALenZ = mww->MatWaveBase::approxlength(cALenZ);\n\n        sigInPtr = cptr;\n    }\n\n    return (0);\n}\n\nint MatWaveWavedec::wavedec3(const double *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, double *C, size_t *L) { return wavedec3_template(this, sigIn, sigInX, sigInY, sigInZ, n, C, L); }\n\nint MatWaveWavedec::wavedec3(const float *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, float *C, size_t *L) { return wavedec3_template(this, sigIn, sigInX, sigInY, sigInZ, n, C, L); }\n\nint MatWaveWavedec::wavedec3(const long *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, long *C, size_t *L) { return wavedec3_template(this, sigIn, sigInX, sigInY, sigInZ, n, C, L); }\n\nint MatWaveWavedec::wavedec3(const int *sigIn, size_t sigInX, size_t sigInY, size_t sigInZ, int n, int *C, size_t *L) { return wavedec3_template(this, sigIn, sigInX, sigInY, sigInZ, n, C, L); }\n\ntemplate<class T> int waverec3_template(MatWaveWavedec *mww, const T *C, const size_t *L, int n, int l, bool normal, T *sigOut)\n{\n    if (!mww->wavelet()) {\n        MatWaveWavedec::SetErrMsg(\"Invalid state, no wavelet\");\n        return (-1);\n    }\n\n    if (n < 0) {\n        MatWaveWavedec::SetErrMsg(\"Invalid number of transforms : %d\", n);\n        return (-1);\n    }\n\n    if (l < 0 || l > n) l = n;\n\n    int LLength = 21 * n + 6;\n\n    if (l == 0) {\n        double scale = 1.0;\n        if (normal) {\n            for (int i = l; i < n; i++) scale /= (sqrt(2.0) * sqrt(2.0) * sqrt(2.0));\n        }\n        for (size_t k = 0; k < L[5]; k++) {\n            for (size_t j = 0; j < L[4]; j++) {\n                for (size_t i = 0; i < L[3]; i++) { *sigOut++ = scale * *C++; }\n            }\n        }\n        return (0);\n    }\n\n    const T *cLLL = C;\n    const T *cLLH = cLLL + L[0] * L[1] * L[2];\n    const T *cLHL = cLLH + L[3] * L[4] * L[5];\n    const T *cLHH = cLHL + L[6] * L[7] * L[8];\n    const T *cHLL = cLHH + L[9] * L[10] * L[11];\n    const T *cHLH = cHLL + L[12] * L[13] * L[14];\n    const T *cHHL = cHLH + L[15] * L[16] * L[17];\n    const T *cHHH = cHHL + L[18] * L[19] * L[20];\n\n    size_t L3d[27] = {L[0], L[1], L[2], L[3], L[4], L[5], L[6], L[7], L[8], L[9], L[10], L[11], L[12], L[13], L[14], L[15], L[16], L[17], L[18], L[19], L[20], L[21], L[22], L[23], 0, 0, 0};\n\n    for (int i = 1; i <= l; i++) {\n        L3d[24] = mww->approxlength(L[LLength - 3], n - i);\n        L3d[25] = mww->approxlength(L[LLength - 2], n - i);\n        L3d[26] = mww->approxlength(L[LLength - 1], n - i);\n\n        int rc = mww->idwt3d(cLLL, cLLH, cLHL, cLHH, cHLL, cHLH, cHHL, cHHH, L3d, sigOut);\n\n        if (rc < 0) return (rc);\n        if (i == l) break;\n\n        cLLL = sigOut;\n\n        cLLH += (L[21 * (i - 1) + 3] * L[21 * (i - 1) + 4] * L[21 * (i - 1) + 5]) + (L[21 * (i - 1) + 6] * L[21 * (i - 1) + 7] * L[21 * (i - 1) + 8])\n              + (L[21 * (i - 1) + 9] * L[21 * (i - 1) + 10] * L[21 * (i - 1) + 11]) + (L[21 * (i - 1) + 12] * L[21 * (i - 1) + 13] * L[21 * (i - 1) + 14])\n              + (L[21 * (i - 1) + 15] * L[21 * (i - 1) + 16] * L[21 * (i - 1) + 17]) + (L[21 * (i - 1) + 18] * L[21 * (i - 1) + 19] * L[21 * (i - 1) + 20])\n              + (L[21 * (i - 1) + 21] * L[21 * (i - 1) + 22] * L[21 * (i - 1) + 23]);\n\n        cLHL = cLLH + (L[21 * i + 3] * L[21 * i + 4] * L[21 * i + 5]);\n        cLHH = cLHL + (L[21 * i + 6] * L[21 * i + 7] * L[21 * i + 8]);\n        cHLL = cLHH + (L[21 * i + 9] * L[21 * i + 10] * L[21 * i + 11]);\n        cHLH = cHLL + (L[21 * i + 12] * L[21 * i + 13] * L[21 * i + 14]);\n        cHHL = cHLH + (L[21 * i + 15] * L[21 * i + 16] * L[21 * i + 17]);\n        cHHH = cHHL + (L[21 * i + 18] * L[21 * i + 19] * L[21 * i + 20]);\n\n        L3d[0] = L3d[24];\n        L3d[1] = L3d[25];\n        L3d[2] = L3d[26];\n\n        L3d[3] = L[21 * i + 3];\n        L3d[4] = L[21 * i + 4];\n        L3d[5] = L[21 * i + 5];\n        L3d[6] = L[21 * i + 6];\n        L3d[7] = L[21 * i + 7];\n        L3d[8] = L[21 * i + 8];\n        L3d[9] = L[21 * i + 9];\n        L3d[10] = L[21 * i + 10];\n        L3d[11] = L[21 * i + 11];\n        L3d[12] = L[21 * i + 12];\n        L3d[13] = L[21 * i + 13];\n        L3d[14] = L[21 * i + 14];\n        L3d[15] = L[21 * i + 15];\n        L3d[16] = L[21 * i + 16];\n        L3d[17] = L[21 * i + 17];\n        L3d[18] = L[21 * i + 18];\n        L3d[19] = L[21 * i + 19];\n        L3d[20] = L[21 * i + 20];\n        L3d[21] = L[21 * i + 21];\n        L3d[22] = L[21 * i + 22];\n        L3d[23] = L[21 * i + 23];\n    }\n\n    if (l != n && normal) {\n        double scale = 1.0;\n        for (int i = l; i < n; i++) scale /= (sqrt(2.0) * sqrt(2.0) * sqrt(2.0));\n        for (size_t i = 0; i < L3d[24] * L3d[25] * L3d[26]; i++) sigOut[i] *= scale;\n    }\n\n    return (0);\n}\n\nint MatWaveWavedec::waverec3(const double *C, const size_t *L, int n, double *sigOut) { return waverec3_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec3(const float *C, const size_t *L, int n, float *sigOut) { return waverec3_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec3(const long *C, const size_t *L, int n, long *sigOut) { return waverec3_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::waverec3(const int *C, const size_t *L, int n, int *sigOut) { return waverec3_template(this, C, L, n, n, false, sigOut); }\n\nint MatWaveWavedec::appcoef3(const double *C, const size_t *L, int n, int l, bool normal, double *sigOut) { return waverec3_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef3(const float *C, const size_t *L, int n, int l, bool normal, float *sigOut) { return waverec3_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef3(const long *C, const size_t *L, int n, int l, bool normal, long *sigOut) { return waverec3_template(this, C, L, n, l, normal, sigOut); }\n\nint MatWaveWavedec::appcoef3(const int *C, const size_t *L, int n, int l, bool normal, int *sigOut) { return waverec3_template(this, C, L, n, l, normal, sigOut); }\n\nvoid MatWaveWavedec::computeL(size_t sigInLen, int n, size_t *L) const\n{\n    L[n + 1] = sigInLen;\n    L[n] = sigInLen;\n    for (int i = n; i > 0; i--) {\n        L[i - 1] = MatWaveBase::approxlength(L[i]);\n        L[i] = MatWaveBase::detaillength(L[i]);\n    }\n}\n\nvoid MatWaveWavedec::computeL2(size_t sigInX, size_t sigInY, int n, size_t *L) const\n{\n    L[(n * 6) + 4 - 4] = sigInX;\n    L[(n * 6) + 4 - 3] = sigInY;\n    L[(n * 6) + 4 - 2] = sigInX;\n    L[(n * 6) + 4 - 1] = sigInY;\n\n    for (int i = n; i > 0; i--) {\n        // cA\n        L[(i * 6) - 6] = MatWaveBase::approxlength(L[i * 6 + 0]);\n        L[(i * 6) - 5] = MatWaveBase::approxlength(L[i * 6 + 1]);\n\n        // cDh\n        L[(i * 6) - 4] = MatWaveBase::approxlength(L[i * 6 + 0]);\n        L[(i * 6) - 3] = MatWaveBase::detaillength(L[i * 6 + 1]);\n\n        // cDv\n        L[(i * 6) - 2] = MatWaveBase::detaillength(L[i * 6 + 0]);\n        L[(i * 6) - 1] = MatWaveBase::approxlength(L[i * 6 + 1]);\n\n        // cDd - overwrites previous value\n        //\n        L[(i * 6) - 0] = MatWaveBase::detaillength(L[i * 6 + 0]);\n        L[(i * 6) + 1] = MatWaveBase::detaillength(L[i * 6 + 1]);\n    }\n}\n\nvoid MatWaveWavedec::computeL3(size_t sigInX, size_t sigInY, size_t sigInZ, int n, size_t *L) const\n{\n    L[(n * 21) + 6 - 6] = sigInX;\n    L[(n * 21) + 6 - 5] = sigInY;\n    L[(n * 21) + 6 - 4] = sigInZ;\n    L[(n * 21) + 6 - 3] = sigInX;\n    L[(n * 21) + 6 - 2] = sigInY;\n    L[(n * 21) + 6 - 1] = sigInZ;\n\n    for (int i = n; i > 0; i--) {\n        // cLLL\n        L[(i * 21) - 21] = MatWaveBase::approxlength(L[i * 21 + 0]);\n        L[(i * 21) - 20] = MatWaveBase::approxlength(L[i * 21 + 1]);\n        L[(i * 21) - 19] = MatWaveBase::approxlength(L[i * 21 + 2]);\n\n        // cLLH\n        L[(i * 21) - 18] = MatWaveBase::approxlength(L[i * 21 + 0]);\n        L[(i * 21) - 17] = MatWaveBase::approxlength(L[i * 21 + 1]);\n        L[(i * 21) - 16] = MatWaveBase::detaillength(L[i * 21 + 2]);\n\n        // cLHL\n        L[(i * 21) - 15] = MatWaveBase::approxlength(L[i * 21 + 0]);\n        L[(i * 21) - 14] = MatWaveBase::detaillength(L[i * 21 + 1]);\n        L[(i * 21) - 13] = MatWaveBase::approxlength(L[i * 21 + 2]);\n\n        // cLHH\n        L[(i * 21) - 12] = MatWaveBase::approxlength(L[i * 21 + 0]);\n        L[(i * 21) - 11] = MatWaveBase::detaillength(L[i * 21 + 1]);\n        L[(i * 21) - 10] = MatWaveBase::detaillength(L[i * 21 + 2]);\n\n        // cHLL\n        L[(i * 21) - 9] = MatWaveBase::detaillength(L[i * 21 + 0]);\n        L[(i * 21) - 8] = MatWaveBase::approxlength(L[i * 21 + 1]);\n        L[(i * 21) - 7] = MatWaveBase::approxlength(L[i * 21 + 2]);\n\n        // cHLH\n        L[(i * 21) - 6] = MatWaveBase::detaillength(L[i * 21 + 0]);\n        L[(i * 21) - 5] = MatWaveBase::approxlength(L[i * 21 + 1]);\n        L[(i * 21) - 4] = MatWaveBase::detaillength(L[i * 21 + 2]);\n\n        // cHHL\n        L[(i * 21) - 3] = MatWaveBase::detaillength(L[i * 21 + 0]);\n        L[(i * 21) - 2] = MatWaveBase::detaillength(L[i * 21 + 1]);\n        L[(i * 21) - 1] = MatWaveBase::approxlength(L[i * 21 + 2]);\n\n        // cHHH - overwrites previous value\n        //\n        L[(i * 21) + 0] = MatWaveBase::detaillength(L[i * 21 + 0]);\n        L[(i * 21) + 1] = MatWaveBase::detaillength(L[i * 21 + 1]);\n        L[(i * 21) + 2] = MatWaveBase::detaillength(L[i * 21 + 2]);\n    }\n}\n\nsize_t MatWaveWavedec::coefflength(const size_t *L, int n) const\n{\n    size_t tlength = L[0];    // cA coefficients\n\n    for (int i = 1; i <= n; i++) tlength += L[i];\n\n    return (tlength);\n}\n\nsize_t MatWaveWavedec::coefflength(size_t sigInLen, int n) const\n{\n    size_t *L = new size_t[n + 2];\n    computeL(sigInLen, n, L);\n\n    size_t tlength = coefflength(L, n);\n\n    delete[] L;\n    return (tlength);\n}\n\nsize_t MatWaveWavedec::approxlength(size_t sigInLen, int n) const\n{\n    size_t cALen = sigInLen;\n\n    for (int i = 0; i < n; i++) {\n        cALen = MatWaveBase::approxlength(cALen);\n        if (cALen == 0) return (cALen);\n    }\n    return (cALen);\n}\n\nvoid MatWaveWavedec::approxlength(const size_t *L, int n, int l, size_t *len) const\n{\n    if (l > n) l = n;\n\n    int LLength = n + 2;\n\n    *len = approxlength(L[LLength - 1], n - l);\n}\n\nvoid MatWaveWavedec::approxlength2(const size_t *L, int n, int l, size_t *lenx, size_t *leny) const\n{\n    if (l > n) l = n;\n\n    int LLength = n * 6 + 4;\n\n    *lenx = approxlength(L[LLength - 2], n - l);\n    *leny = approxlength(L[LLength - 1], n - l);\n}\n\nvoid MatWaveWavedec::approxlength3(const size_t *L, int n, int l, size_t *lenx, size_t *leny, size_t *lenz) const\n{\n    if (l > n) l = n;\n\n    int LLength = n * 21 + 6;\n\n    *lenx = approxlength(L[LLength - 3], n - l);\n    *leny = approxlength(L[LLength - 2], n - l);\n    *lenz = approxlength(L[LLength - 1], n - l);\n}\n\nsize_t MatWaveWavedec::coefflength2(const size_t *L, int n) const\n{\n    size_t tlength = (L[0] * L[1]);    // cA coefficients;\n\n    for (int i = 1; i <= n; i++) {\n        tlength += L[(i * 6) - 4] * L[(i * 6) - 3];    // cDh\n        tlength += L[(i * 6) - 2] * L[(i * 6) - 1];    // cDv\n        tlength += L[(i * 6) - 0] * L[(i * 6) + 1];    // cDd\n    }\n    return (tlength);\n}\n\nsize_t MatWaveWavedec::coefflength2(size_t sigInX, size_t sigInY, int n) const\n{\n    size_t *L = new size_t[(n * 6) + 4];\n    computeL2(sigInX, sigInY, n, L);\n\n    size_t tlength = coefflength2(L, n);\n\n    delete[] L;\n    return (tlength);\n}\n\nsize_t MatWaveWavedec::coefflength3(const size_t *L, int n) const\n{\n    size_t tlength = (L[0] * L[1] * L[2]);    // cA coefficients;\n\n    for (int i = 1; i <= n; i++) {\n        tlength += L[(i * 21) - 18] * L[(i * 21) - 17] * L[(i * 21) - 16];    // cLLH\n        tlength += L[(i * 21) - 15] * L[(i * 21) - 14] * L[(i * 21) - 13];    // cLHL\n        tlength += L[(i * 21) - 12] * L[(i * 21) - 11] * L[(i * 21) - 10];    // cLHH\n        tlength += L[(i * 21) - 9] * L[(i * 21) - 8] * L[(i * 21) - 7];       // cHLL\n        tlength += L[(i * 21) - 6] * L[(i * 21) - 5] * L[(i * 21) - 4];       // cHLH\n        tlength += L[(i * 21) - 3] * L[(i * 21) - 2] * L[(i * 21) - 1];       // cHHL\n        tlength += L[(i * 21) - 0] * L[(i * 21) + 1] * L[(i * 21) + 2];       // cHHH\n    }\n    return (tlength);\n}\n\nsize_t MatWaveWavedec::coefflength3(size_t sigInX, size_t sigInY, size_t sigInZ, int n) const\n{\n    size_t *L = new size_t[(n * 21) + 6];\n    computeL3(sigInX, sigInY, sigInZ, n, L);\n\n    size_t tlength = coefflength3(L, n);\n\n    delete[] L;\n    return (tlength);\n}\n"
  },
  {
    "path": "lib/wasp/NOTES",
    "content": "\nProposed file placement\n----------------------\n\nAll 1D variables (including time CV) -> master\nstatic && not-compressed && size < max_ele_per_master -> master\neverything else -> /coords or /data as appropriate\n\nNotes\n-----\n\n+ Need to change append definitions to only allow appending of additional\ntime steps (this is what NetCDF supports)\n\n+ For NetCDF implementation the time dim should be unlimited.\n\n+ It might be desirable to copy small CVs (e.g. time) to data and coord\nvariable files, but no way to ensure that these stay in sync with what is\nin master file. Forget this!\n\n+ Highly desirable that files can be operated on without master,\nalbeit with some limitations.\n\n+ PutVar and GetVar() don't have way to specify compression level\n- Does variable need to be opened ?\n\n+ need to test VarBase assignement operator and copy constructor work\nfor derived class i\n\n+ Need to define meaning of \\p reflevel. If it's kept compatible \n with VDC2 then we are precluded from having varying numbers of \n refinement levels along different dimensions\n\nQuestions\n---------\n\n+ How handle masks/missing-values?\n\n+ Only one time CV?\n\n+ When are NetCDF files \"defined\"\n\n+ Can append mode be made more general? I.e. allow for adding new variables\nto the data set? Seems like this would only impact master file, and would\ncreate reading and re-writing the master file.\nSee http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-f90/Adding-New-Dimensions.html#Adding-New-Dimensions.\n \n+ Implications of append mode wrt defining new or changing existing stuff\n\n+ How are uniform coordinate vars handled wrt what is read/written\nand what is actually stored?\n"
  },
  {
    "path": "lib/wasp/NetCDFCpp.cpp",
    "content": "#include \"vapor/VAssert.h\"\n#include <sstream>\n#include <sstream>\n#include <iterator>\n#include \"vapor/NetCDFCpp.h\"\n#include \"vapor/MatWaveBase.h\"\n\nusing namespace VAPoR;\n\n#define MY_NC_ERR(rc, path, func)                                                                                                                        \\\n    if (rc != NC_NOERR) {                                                                                                                                \\\n        string msg = func;                                                                                                                               \\\n        SetErrMsg(\"Error accessing netCDF file \\\"%s\\\", %s : %s -- file (%s), line(%d)\", path.c_str(), msg.c_str(), nc_strerror(rc), __FILE__, __LINE__); \\\n        return (rc);                                                                                                                                     \\\n    }\n\nnamespace {\n\nbool var_defs_match(int ncid, int varid, int dimids[], int ndimids, nc_type xtype)\n{\n    int mydimids[NC_MAX_DIMS];\n    int myndims;\n    (void)nc_inq_varndims(ncid, varid, &myndims);\n    (void)nc_inq_vardimid(ncid, varid, mydimids);\n    for (int i = 0; i < ndimids; i++) {\n        if (mydimids[i] != dimids[i]) return (false);\n    }\n    nc_type myxtype;\n    (void)nc_inq_vartype(ncid, varid, &myxtype);\n    if (myxtype != xtype) return (false);\n\n    return (true);\n}\n\n\n};    // namespace\n\nNetCDFCpp::NetCDFCpp()\n{\n    _ncid = -1;\n    _path.clear();\n}\n\nNetCDFCpp::~NetCDFCpp() {}\n\nint NetCDFCpp::Create(string path, int cmode, size_t initialsz, size_t &bufrsizehintp)\n{\n    NetCDFCpp::Close();\n\n    _ncid = -1;\n    _path.clear();\n\n    int ncid;\n    int rc = nc__create(path.c_str(), cmode, initialsz, &bufrsizehintp, &ncid);\n    MY_NC_ERR(rc, path, \"nc__create()\");\n\n    _path = path;\n    _ncid = ncid;\n\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::Open(string path, int mode)\n{\n    NetCDFCpp::Close();\n\n    _ncid = -1;\n    _path.clear();\n\n    int ncid;\n    int rc = nc_open(path.c_str(), mode, &ncid);\n    MY_NC_ERR(rc, path, \"nc_open()\");\n\n    _path = path;\n    _ncid = ncid;\n\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::SetFill(int fillmode, int &old_modep)\n{\n    int rc = nc_set_fill(_ncid, fillmode, &old_modep);\n    MY_NC_ERR(rc, _path, \"nc_set_fill()\");\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::EndDef() const\n{\n    int rc = nc_enddef(_ncid);\n    MY_NC_ERR(rc, _path, \"nc_enddef()\");\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::ReDef() const\n{\n    int rc = nc_redef(_ncid);\n    MY_NC_ERR(rc, _path, \"nc_redef()\");\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::Close()\n{\n    if (_ncid < 0) return (NC_NOERR);\n\n    int rc = nc_close(_ncid);\n    MY_NC_ERR(rc, _path, \"nc_close()\");\n\n    _ncid = -1;\n    _path.clear();\n\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::DefDim(string name, size_t len) const\n{\n    int dimid;\n    int rc = nc_def_dim(_ncid, name.c_str(), len, &dimid);\n    MY_NC_ERR(rc, _path, \"nc_def_dim(\" + name + \")\");\n\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::DefVar(string name, nc_type xtype, vector<string> dimnames)\n{\n    int dimids[NC_MAX_DIMS];\n\n    for (int i = 0; i < dimnames.size(); i++) {\n        int rc = nc_inq_dimid(_ncid, dimnames[i].c_str(), &dimids[i]);\n        MY_NC_ERR(rc, _path, \"nc_inq_dimid(\" + dimnames[i] + \")\");\n    }\n\n    // Don't error out if variable already exists and has same definition\n    //\n    int varid;\n    int rc = nc_inq_varid(_ncid, name.c_str(), &varid);\n    if (rc == NC_NOERR) {\n        if (!var_defs_match(_ncid, varid, dimids, dimnames.size(), xtype)) {\n            MY_NC_ERR(NC_ENAMEINUSE, _path, \"nc_def_var(\" + name + \")\");\n            return (NC_ENAMEINUSE);\n        }\n        return (NC_NOERR);\n    }\n\n    rc = nc_def_var(_ncid, name.c_str(), xtype, dimnames.size(), dimids, &varid);\n    MY_NC_ERR(rc, _path, \"nc_def_var(\" + name + \")\");\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::InqVarDims(string name, vector<string> &dimnames, vector<size_t> &dims) const\n{\n    dimnames.clear();\n    dims.clear();\n\n    int varid;\n    int rc = NetCDFCpp::InqVarid(name, varid);\n    if (rc < 0) return (rc);\n\n    int ndims;\n    rc = nc_inq_varndims(_ncid, varid, &ndims);\n    MY_NC_ERR(rc, _path, \"nc_inq_varndims()\");\n\n    int dimids[NC_MAX_VAR_DIMS];\n    rc = nc_inq_vardimid(_ncid, varid, dimids);\n    MY_NC_ERR(rc, _path, \"nc_inq_vardimid()\");\n\n    for (int i = 0; i < ndims; i++) {\n        char   dimnamebuf[NC_MAX_NAME + 1];\n        size_t dimlen;\n        rc = nc_inq_dim(_ncid, dimids[i], dimnamebuf, &dimlen);\n        MY_NC_ERR(rc, _path, \"nc_inq_dim()\");\n        dimnames.push_back(dimnamebuf);\n        dims.push_back(dimlen);\n    }\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::InqDims(vector<string> &dimnames, vector<size_t> &dims) const\n{\n    dimnames.clear();\n    dims.clear();\n\n    int dimids[NC_MAX_DIMS];\n\n    int ndims;\n    int rc = nc_inq_dimids(_ncid, &ndims, dimids, 0);\n    MY_NC_ERR(rc, _path, \"nc_inq_dimids()\");\n\n    for (int i = 0; i < ndims; i++) {\n        char   dimnamebuf[NC_MAX_NAME + 1];\n        size_t dimlen;\n        rc = nc_inq_dim(_ncid, dimids[i], dimnamebuf, &dimlen);\n        MY_NC_ERR(rc, _path, \"nc_inq_dim()\");\n        dimnames.push_back(dimnamebuf);\n        dims.push_back(dimlen);\n    }\n\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::InqDimlen(string name, size_t &len) const\n{\n    len = 0;\n\n    int dimid;\n    int rc = nc_inq_dimid(_ncid, name.c_str(), &dimid);\n    MY_NC_ERR(rc, _path, \"nc_inq_dimid(\" + name + \")\");\n\n    rc = nc_inq_dimlen(_ncid, dimid, &len);\n    MY_NC_ERR(rc, _path, \"nc_inq_dimlen()\");\n    return (0);\n}\n\nint NetCDFCpp::InqAttnames(string varname, std::vector<string> &attnames) const\n{\n    attnames.clear();\n\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (-1);\n\n    int natts;\n    if (!varname.empty()) {\n        rc = nc_inq_varnatts(_ncid, varid, &natts);\n        MY_NC_ERR(rc, _path, \"nc_inq_varnatts()\");\n    } else {\n        rc = nc_inq_natts(_ncid, &natts);\n        MY_NC_ERR(rc, _path, \"nc_inq_natts()\");\n    }\n\n    for (int attnum = 0; attnum < natts; attnum++) {\n        char namebuf[NC_MAX_NAME + 1];\n\n        rc = nc_inq_attname(_ncid, varid, attnum, namebuf);\n        MY_NC_ERR(rc, _path, \"nc_inq_attname()\");\n\n        attnames.push_back(namebuf);\n    }\n\n    return (0);\n}\n\nint NetCDFCpp::CopyAtt(string varname_in, string attname, NetCDFCpp &ncdf_out, string varname_out) const\n{\n    int varid_in;\n    int rc = NetCDFCpp::InqVarid(varname_in, varid_in);\n    if (rc < 0) return (rc);\n\n    int varid_out;\n    rc = ncdf_out.InqVarid(varname_out, varid_out);\n    if (rc < 0) return (rc);\n\n    int ncid_out = ncdf_out.GetNCID();\n    if (rc < 0) return (rc);\n\n    rc = nc_copy_att(_ncid, varid_in, attname.c_str(), ncid_out, varid_out);\n    MY_NC_ERR(rc, _path, \"nc_copy_att()\");\n\n    return (NC_NOERR);\n}\n\n//\n// PutAtt - Integer\n//\nint NetCDFCpp::PutAtt(string varname, string attname, int value) const { return (NetCDFCpp::PutAtt(varname, attname, &value, 1)); }\n\nint NetCDFCpp::PutAtt(string varname, string attname, vector<int> values) const\n{\n    size_t n = values.size();\n    int *  buf = new int[n];\n    for (size_t i = 0; i < n; i++) buf[i] = values[i];\n\n    int rc = NetCDFCpp::PutAtt(varname, attname, buf, n);\n    delete[] buf;\n\n    return (rc);\n}\n\nint NetCDFCpp::PutAtt(string varname, string attname, const int values[], size_t n) const\n{\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    if (attname == \"_FillValue\") {\n        nc_type xtype;\n        rc = InqVartype(varname, xtype);\n        if (rc < 0) return (rc);\n\n        if (xtype == NC_BYTE) {\n            unsigned char *valuesB = new unsigned char[n];\n            for (int i = 0; i < n; i++) valuesB[i] = (unsigned char)values[i];\n            rc = nc_put_att_ubyte(_ncid, varid, attname.c_str(), NC_BYTE, n, valuesB);\n            delete[] valuesB;\n        } else if (xtype == NC_SHORT) {\n            short *valuesS = new short[n];\n            for (int i = 0; i < n; i++) valuesS[i] = (short)values[i];\n            rc = nc_put_att_short(_ncid, varid, attname.c_str(), NC_SHORT, n, valuesS);\n            delete[] valuesS;\n        } else if (xtype == NC_INT64) {\n            long *valuesS = new long[n];\n            for (int i = 0; i < n; i++) valuesS[i] = (long)values[i];\n            rc = nc_put_att_long(_ncid, varid, attname.c_str(), NC_INT64, n, valuesS);\n            delete[] valuesS;\n        } else {\n            rc = nc_put_att_int(_ncid, varid, attname.c_str(), NC_INT, n, values);\n        }\n    } else {\n        rc = nc_put_att_int(_ncid, varid, attname.c_str(), NC_INT, n, values);\n    }\n    MY_NC_ERR(rc, _path, \"nc_put_att_int(\" + attname + \")\");\n\n    return (NC_NOERR);\n}\n\n//\n// GetAtt - Integer\n//\nint NetCDFCpp::GetAtt(string varname, string attname, int &value) const { return (NetCDFCpp::GetAtt(varname, attname, &value, 1)); }\n\nint NetCDFCpp::GetAtt(string varname, string attname, vector<int> &values) const\n{\n    values.clear();\n\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t n;\n    rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &n);\n    MY_NC_ERR(rc, _path, \"nc_inq_attlen(\" + attname + \")\");\n\n    int *buf = new int[n];\n\n    rc = NetCDFCpp::GetAtt(varname, attname, buf, n);\n\n    for (int i = 0; i < n; i++) { values.push_back(buf[i]); }\n    delete[] buf;\n\n    return (rc);\n}\n\nint NetCDFCpp::GetAtt(string varname, string attname, int values[], size_t n) const\n{\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t len;\n    rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &len);\n    MY_NC_ERR(rc, _path, \"nc_inq_attlen(\" + attname + \")\");\n\n    int *buf = new int[len];\n\n    rc = nc_get_att_int(_ncid, varid, attname.c_str(), buf);\n    if (rc != NC_NOERR) delete[] buf;\n    MY_NC_ERR(rc, _path, \"nc_get_att_int(\" + attname + \")\");\n\n    for (size_t i = 0; i < len && i < n; i++) { values[i] = buf[i]; }\n    delete[] buf;\n\n    return (NC_NOERR);\n}\n\n//\n// PutAtt - size_t\n//\nint NetCDFCpp::PutAtt(string varname, string attname, size_t value) const { return (NetCDFCpp::PutAtt(varname, attname, &value, 1)); }\n\nint NetCDFCpp::PutAtt(string varname, string attname, vector<size_t> values) const\n{\n    vector<int> ivalues;\n    for (size_t i = 0; i < values.size(); i++) ivalues.push_back(values[i]);\n\n    return (NetCDFCpp::PutAtt(varname, attname, ivalues));\n}\n\nint NetCDFCpp::PutAtt(string varname, string attname, const size_t values[], size_t n) const\n{\n    vector<int> ivalues;\n\n    for (size_t i = 0; i < n; i++) ivalues.push_back(values[i]);\n\n    return (NetCDFCpp::PutAtt(varname, attname, ivalues));\n}\n\n//\n// GetAtt - size_t\n//\nint NetCDFCpp::GetAtt(string varname, string attname, size_t &value) const { return (NetCDFCpp::GetAtt(varname, attname, &value, 1)); }\n\nint NetCDFCpp::GetAtt(string varname, string attname, vector<size_t> &values) const\n{\n    values.clear();\n\n    vector<int> ivalues;\n    int         rc = NetCDFCpp::GetAtt(varname, attname, ivalues);\n    for (int i = 0; i < ivalues.size(); i++) values.push_back(ivalues[i]);\n    return (rc);\n}\n\nint NetCDFCpp::GetAtt(string varname, string attname, size_t values[], size_t n) const\n{\n    vector<int> ivalues;\n    int         rc = NetCDFCpp::GetAtt(varname, attname, ivalues);\n    for (int i = 0; i < ivalues.size() && i < n; i++) values[i] = ivalues[i];\n\n    return (rc);\n}\n\n//\n// PutAtt - Float\n//\nint NetCDFCpp::PutAtt(string varname, string attname, float value) const { return (NetCDFCpp::PutAtt(varname, attname, &value, 1)); }\n\nint NetCDFCpp::PutAtt(string varname, string attname, vector<float> values) const\n{\n    size_t n = values.size();\n    float *buf = new float[n];\n    for (size_t i = 0; i < n; i++) buf[i] = values[i];\n\n    int rc = NetCDFCpp::PutAtt(varname, attname, buf, n);\n    delete[] buf;\n\n    return (rc);\n}\n\nint NetCDFCpp::PutAtt(string varname, string attname, const float values[], size_t n) const\n{\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    rc = nc_put_att_float(_ncid, varid, attname.c_str(), NC_DOUBLE, n, values);\n    MY_NC_ERR(rc, _path, \"nc_put_att_float(\" + attname + \")\");\n\n    return (NC_NOERR);\n}\n\n//\n// PutAtt - Double\n//\nint NetCDFCpp::PutAtt(string varname, string attname, double value) const { return (NetCDFCpp::PutAtt(varname, attname, &value, 1)); }\n\nint NetCDFCpp::PutAtt(string varname, string attname, vector<double> values) const\n{\n    size_t  n = values.size();\n    double *buf = new double[n];\n    for (size_t i = 0; i < n; i++) buf[i] = values[i];\n\n    int rc = NetCDFCpp::PutAtt(varname, attname, buf, n);\n    delete[] buf;\n\n    return (rc);\n}\n\nint NetCDFCpp::PutAtt(string varname, string attname, const double values[], size_t n) const\n{\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    if (attname == \"_FillValue\") {\n        nc_type xtype;\n        rc = InqVartype(varname, xtype);\n        if (rc < 0) return (rc);\n\n        if (xtype == NC_FLOAT) {\n            float *valuesF = new float[n];\n            for (int i = 0; i < n; i++) valuesF[i] = (float)values[i];\n            rc = nc_put_att_float(_ncid, varid, attname.c_str(), NC_FLOAT, n, valuesF);\n            delete[] valuesF;\n        } else {\n            rc = nc_put_att_double(_ncid, varid, attname.c_str(), NC_DOUBLE, n, values);\n        }\n    } else {\n        rc = nc_put_att_double(_ncid, varid, attname.c_str(), NC_DOUBLE, n, values);\n    }\n\n    MY_NC_ERR(rc, _path, \"nc_put_att_double(\" + attname + \")\");\n\n    return (NC_NOERR);\n}\n\n//\n// GetAtt - Float\n//\nint NetCDFCpp::GetAtt(string varname, string attname, float &value) const { return (NetCDFCpp::GetAtt(varname, attname, &value, 1)); }\n\nint NetCDFCpp::GetAtt(string varname, string attname, vector<float> &values) const\n{\n    values.clear();\n\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t n;\n    rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &n);\n    MY_NC_ERR(rc, _path, \"nc_inq_attlen(\" + attname + \")\");\n\n    float *buf = new float[n];\n\n    rc = NetCDFCpp::GetAtt(varname, attname, buf, n);\n\n    for (int i = 0; i < n; i++) { values.push_back(buf[i]); }\n    delete[] buf;\n\n    return (rc);\n}\n\nint NetCDFCpp::GetAtt(string varname, string attname, float values[], size_t n) const\n{\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t len;\n    rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &len);\n    MY_NC_ERR(rc, _path, \"nc_inq_attlen(\" + attname + \")\");\n\n    float *buf = new float[len];\n\n    rc = nc_get_att_float(_ncid, varid, attname.c_str(), buf);\n    if (rc != NC_NOERR) delete[] buf;\n    MY_NC_ERR(rc, _path, \"nc_get_att_float(\" + attname + \")\");\n\n    for (size_t i = 0; i < len && i < n; i++) { values[i] = buf[i]; }\n    delete[] buf;\n\n    return (NC_NOERR);\n}\n\n//\n// GetAtt - Double\n//\nint NetCDFCpp::GetAtt(string varname, string attname, double &value) const { return (NetCDFCpp::GetAtt(varname, attname, &value, 1)); }\n\nint NetCDFCpp::GetAtt(string varname, string attname, vector<double> &values) const\n{\n    values.clear();\n\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t n;\n    rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &n);\n    MY_NC_ERR(rc, _path, \"nc_inq_attlen(\" + attname + \")\");\n\n    double *buf = new double[n];\n\n    rc = NetCDFCpp::GetAtt(varname, attname, buf, n);\n\n    for (int i = 0; i < n; i++) { values.push_back(buf[i]); }\n    delete[] buf;\n\n    return (rc);\n}\n\nint NetCDFCpp::GetAtt(string varname, string attname, double values[], size_t n) const\n{\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t len;\n    rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &len);\n    MY_NC_ERR(rc, _path, \"nc_inq_attlen(\" + attname + \")\");\n\n    double *buf = new double[len];\n\n    rc = nc_get_att_double(_ncid, varid, attname.c_str(), buf);\n    if (rc != NC_NOERR) delete[] buf;\n    MY_NC_ERR(rc, _path, \"nc_get_att_double(\" + attname + \")\");\n\n    for (size_t i = 0; i < len && i < n; i++) { values[i] = buf[i]; }\n    delete[] buf;\n\n    return (NC_NOERR);\n}\n\n//\n// PutAtt - String\n//\n\nint NetCDFCpp::PutAtt(string varname, string attname, string value) const\n{\n    size_t n = value.length();\n    char * buf = new char[n + 1];\n    strcpy(buf, value.c_str());\n    int rc = NetCDFCpp::PutAtt(varname, attname, buf, n);\n    delete[] buf;\n    return (rc);\n}\nint NetCDFCpp::PutAtt(string varname, string attname, vector<string> values) const\n{\n    string s;\n    for (int i = 0; i < values.size(); i++) {\n        s += values[i];\n        s += \" \";\n    }\n    return (NetCDFCpp::PutAtt(varname, attname, s));\n}\n\nint NetCDFCpp::PutAtt(string varname, string attname, const char values[], size_t n) const\n{\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    rc = nc_put_att_text(_ncid, varid, attname.c_str(), n, values);\n    MY_NC_ERR(rc, _path, \"nc_put_att_text(\" + attname + \")\");\n\n    return (NC_NOERR);\n}\n\n//\n// GetAtt - String\n//\nint NetCDFCpp::GetAtt(string varname, string attname, string &value) const\n{\n    value.clear();\n\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t n;\n    rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &n);\n    MY_NC_ERR(rc, _path, \"nc_inq_attlen(\" + attname + \")\");\n\n    char *buf = new char[n + 1];\n\n    rc = NetCDFCpp::GetAtt(varname, attname, buf, n);\n    value = buf;\n\n    delete[] buf;\n\n    return (rc);\n}\n\nint NetCDFCpp::GetAtt(string varname, string attname, char values[], size_t n) const\n{\n    int varid;\n    int rc = InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t len;\n    rc = nc_inq_attlen(_ncid, varid, attname.c_str(), &len);\n    MY_NC_ERR(rc, _path, \"nc_inq_attlen(\" + attname + \")\");\n\n    char *buf = new char[len + 1];\n\n    rc = nc_get_att_text(_ncid, varid, attname.c_str(), buf);\n    if (rc != NC_NOERR) delete[] buf;\n    MY_NC_ERR(rc, _path, \"nc_get_att_text(\" + attname + \")\");\n\n    size_t i;\n    for (i = 0; i < len && i < n; i++) { values[i] = buf[i]; }\n    values[i] = '\\0';\n    delete[] buf;\n\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::GetAtt(string varname, string attname, vector<string> &values) const\n{\n    values.clear();\n\n    string s;\n\n    int rc = NetCDFCpp::GetAtt(varname, attname, s);\n    if (rc < 0) return (rc);\n\n    string       buf;\n    stringstream ss(s);\n    while (ss >> buf) values.push_back(buf);\n\n    return (0);\n}\n\nint NetCDFCpp::InqVarid(string varname, int &varid) const\n{\n    if (varname.empty()) {\n        varid = NC_GLOBAL;\n        return (NC_NOERR);\n    }\n    int my_varid = -1;\n    int rc = nc_inq_varid(_ncid, varname.c_str(), &my_varid);\n    MY_NC_ERR(rc, _path, \"nc_inq_varid(\" + varname + \")\");\n\n    varid = my_varid;\n\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::InqAtt(string varname, string attname, nc_type &xtype, size_t &len) const\n{\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    rc = nc_inq_att(_ncid, varid, attname.c_str(), &xtype, &len);\n    MY_NC_ERR(rc, _path, \"nc_inq_att(\" + attname + \")\");\n\n    return (NC_NOERR);\n}\n\nint NetCDFCpp::InqVartype(string varname, nc_type &xtype) const\n{\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    rc = nc_inq_vartype(_ncid, varid, &xtype);\n    MY_NC_ERR(rc, _path, \"nc_inq_vartype()\");\n\n    return (NC_NOERR);\n}\n\nsize_t NetCDFCpp::SizeOf(nc_type xtype)\n{\n    switch (xtype) {\n    case NC_BYTE:\n    case NC_UBYTE:\n    case NC_CHAR: return (1);\n    case NC_SHORT:\n    case NC_USHORT: return (2);\n    case NC_INT:    // NC_LONG and NC_INT\n    case NC_UINT:\n    case NC_FLOAT: return (4);\n    case NC_INT64:\n    case NC_UINT64:\n    case NC_DOUBLE: return (8);\n    default: return (0);\n    }\n}\n\nbool NetCDFCpp::ValidFile(string path)\n{\n    bool valid = false;\n\n    int ncid;\n    int rc = nc_open(path.c_str(), 0, &ncid);\n    if (rc == NC_NOERR) {\n        valid = true;\n        nc_close(ncid);\n    }\n    return (valid);\n}\n\nint NetCDFCpp::_PutVara(string varname, vector<size_t> start, vector<size_t> count, const void *data, string func)\n{\n    VAssert(start.size() == count.size());\n\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t mystart[NC_MAX_VAR_DIMS];\n    size_t mycount[NC_MAX_VAR_DIMS];\n\n    for (int i = 0; i < start.size(); i++) {\n        mystart[i] = start[i];\n        mycount[i] = count[i];\n    }\n\n    if (func == \"nc_put_vara\") {\n        // The nc_put_var() function will write a variable of any type,\n        // including\n        // user defined type. For this function, the type of the data in memory\n        // must match the type of the variable - no data conversion is done.\n        //\n        rc = nc_put_vara(_ncid, varid, mystart, mycount, (const void *)data);\n    } else if (func == \"nc_put_vara_float\") {\n        rc = nc_put_vara_float(_ncid, varid, mystart, mycount, (const float *)data);\n    } else if (func == \"nc_put_vara_double\") {\n        rc = nc_put_vara_double(_ncid, varid, mystart, mycount, (const double *)data);\n    } else if (func == \"nc_put_vara_int\") {\n        rc = nc_put_vara_int(_ncid, varid, mystart, mycount, (const int *)data);\n    } else if (func == \"nc_put_vara_long\") {\n        rc = nc_put_vara_long(_ncid, varid, mystart, mycount, (const long *)data);\n    } else if (func == \"nc_put_vara_uchar\") {\n        rc = nc_put_vara_uchar(_ncid, varid, mystart, mycount, (const unsigned char *)data);\n    } else {\n        VAssert(func == \"\");\n    }\n    MY_NC_ERR(rc, _path, func);\n\n    return (0);\n}\n\nint NetCDFCpp::PutVara(string varname, vector<size_t> start, vector<size_t> count, const void *data) { return (_PutVara(varname, start, count, (const void *)data, \"nc_put_vara\")); }\n\nint NetCDFCpp::PutVara(string varname, vector<size_t> start, vector<size_t> count, const float *data) { return (_PutVara(varname, start, count, (const void *)data, \"nc_put_vara_float\")); }\n\nint NetCDFCpp::PutVara(string varname, vector<size_t> start, vector<size_t> count, const double *data) { return (_PutVara(varname, start, count, (const void *)data, \"nc_put_vara_double\")); }\n\nint NetCDFCpp::PutVara(string varname, vector<size_t> start, vector<size_t> count, const int *data) { return (_PutVara(varname, start, count, (const void *)data, \"nc_put_vara_int\")); }\n\nint NetCDFCpp::PutVara(string varname, vector<size_t> start, vector<size_t> count, const long *data) { return (_PutVara(varname, start, count, (const void *)data, \"nc_put_vara_long\")); }\n\nint NetCDFCpp::PutVara(string varname, vector<size_t> start, vector<size_t> count, const unsigned char *data) { return (_PutVara(varname, start, count, (const void *)data, \"nc_put_vara_uchar\")); }\n\nint NetCDFCpp::_PutVar(string varname, const void *data, string func)\n{\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    if (func == \"nc_put_var\") {\n        // The nc_put_var() function will write a variable of any type,\n        // including\n        // user defined type. For this function, the type of the data in memory\n        // must match the type of the variable - no data conversion is done.\n        //\n        rc = nc_put_var(_ncid, varid, (const void *)data);\n    } else if (func == \"nc_put_var_float\") {\n        rc = nc_put_var_float(_ncid, varid, (const float *)data);\n    } else if (func == \"nc_put_var_double\") {\n        rc = nc_put_var_double(_ncid, varid, (const double *)data);\n    } else if (func == \"nc_put_var_int\") {\n        rc = nc_put_var_int(_ncid, varid, (const int *)data);\n    } else if (func == \"nc_put_var_long\") {\n        rc = nc_put_var_long(_ncid, varid, (const long *)data);\n    } else if (func == \"nc_put_var_uchar\") {\n        rc = nc_put_var_uchar(_ncid, varid, (const unsigned char *)data);\n    } else {\n        VAssert(func == \"\");\n    }\n    MY_NC_ERR(rc, _path, func);\n\n    return (0);\n}\n\nint NetCDFCpp::PutVar(string varname, const void *data) { return (_PutVar(varname, (const void *)data, \"nc_put_var\")); }\n\nint NetCDFCpp::PutVar(string varname, const float *data) { return (_PutVar(varname, (const void *)data, \"nc_put_var_float\")); }\n\nint NetCDFCpp::PutVar(string varname, const double *data) { return (_PutVar(varname, (const void *)data, \"nc_put_var_double\")); }\n\nint NetCDFCpp::PutVar(string varname, const int *data) { return (_PutVar(varname, (const void *)data, \"nc_put_var_int\")); }\n\nint NetCDFCpp::PutVar(string varname, const long *data) { return (_PutVar(varname, (const void *)data, \"nc_put_var_long\")); }\n\nint NetCDFCpp::PutVar(string varname, const unsigned char *data) { return (_PutVar(varname, (const void *)data, \"nc_put_var_uchar\")); }\n\nint NetCDFCpp::_GetVara(string varname, vector<size_t> start, vector<size_t> count, void *data, string func) const\n{\n    VAssert(start.size() == count.size());\n\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    size_t mystart[NC_MAX_VAR_DIMS];\n    size_t mycount[NC_MAX_VAR_DIMS];\n\n    for (int i = 0; i < start.size(); i++) {\n        mystart[i] = start[i];\n        mycount[i] = count[i];\n    }\n\n    if (func == \"nc_get_vara\") {\n        // The nc_get_var() function will write a variable of any type,\n        // including\n        // user defined type. For this function, the type of the data in memory\n        // must match the type of the variable - no data conversion is done.\n        //\n        rc = nc_get_vara(_ncid, varid, mystart, mycount, (void *)data);\n    } else if (func == \"nc_get_vara_float\") {\n        rc = nc_get_vara_float(_ncid, varid, mystart, mycount, (float *)data);\n    } else if (func == \"nc_get_vara_double\") {\n        rc = nc_get_vara_double(_ncid, varid, mystart, mycount, (double *)data);\n    } else if (func == \"nc_get_vara_int\") {\n        rc = nc_get_vara_int(_ncid, varid, mystart, mycount, (int *)data);\n    } else if (func == \"nc_get_vara_long\") {\n        rc = nc_get_vara_long(_ncid, varid, mystart, mycount, (long *)data);\n    } else if (func == \"nc_get_vara_uchar\") {\n        rc = nc_get_vara_uchar(_ncid, varid, mystart, mycount, (unsigned char *)data);\n    } else {\n        VAssert(func == \"\");\n    }\n    MY_NC_ERR(rc, _path, func);\n\n    return (rc);\n}\n\nint NetCDFCpp::GetVara(string varname, vector<size_t> start, vector<size_t> count, void *data) const { return (_GetVara(varname, start, count, (void *)data, \"nc_get_vara\")); }\n\nint NetCDFCpp::GetVara(string varname, vector<size_t> start, vector<size_t> count, float *data) const { return (_GetVara(varname, start, count, (void *)data, \"nc_get_vara_float\")); }\n\nint NetCDFCpp::GetVara(string varname, vector<size_t> start, vector<size_t> count, double *data) const { return (_GetVara(varname, start, count, (void *)data, \"nc_get_vara_double\")); }\n\nint NetCDFCpp::GetVara(string varname, vector<size_t> start, vector<size_t> count, int *data) const { return (_GetVara(varname, start, count, (void *)data, \"nc_get_vara_int\")); }\n\nint NetCDFCpp::GetVara(string varname, vector<size_t> start, vector<size_t> count, long *data) const { return (_GetVara(varname, start, count, (void *)data, \"nc_get_vara_long\")); }\n\nint NetCDFCpp::GetVara(string varname, vector<size_t> start, vector<size_t> count, unsigned char *data) const { return (_GetVara(varname, start, count, (void *)data, \"nc_get_vara_uchar\")); }\n\nint NetCDFCpp::_GetVar(string varname, void *data, string func) const\n{\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    if (func == \"nc_get_var\") {\n        // The nc_get_var() function will write a variable of any type,\n        // including\n        // user defined type. For this function, the type of the data in memory\n        // must match the type of the variable - no data conversion is done.\n        //\n        rc = nc_get_var(_ncid, varid, (void *)data);\n    } else if (func == \"nc_get_var_float\") {\n        rc = nc_get_var_float(_ncid, varid, (float *)data);\n    } else if (func == \"nc_get_var_double\") {\n        rc = nc_get_var_double(_ncid, varid, (double *)data);\n    } else if (func == \"nc_get_var_int\") {\n        rc = nc_get_var_int(_ncid, varid, (int *)data);\n    } else if (func == \"nc_get_var_long\") {\n        rc = nc_get_var_long(_ncid, varid, (long *)data);\n    } else if (func == \"nc_get_var_uchar\") {\n        rc = nc_get_var_uchar(_ncid, varid, (unsigned char *)data);\n    } else {\n        VAssert(func == \"\");\n    }\n    MY_NC_ERR(rc, _path, func);\n\n    return (0);\n}\n\nint NetCDFCpp::GetVar(string varname, void *data) const { return (_GetVar(varname, (void *)data, \"nc_get_var\")); }\n\nint NetCDFCpp::GetVar(string varname, float *data) const { return (_GetVar(varname, (void *)data, \"nc_get_var_float\")); }\n\nint NetCDFCpp::GetVar(string varname, double *data) const { return (_GetVar(varname, (void *)data, \"nc_get_var_double\")); }\n\nint NetCDFCpp::GetVar(string varname, int *data) const { return (_GetVar(varname, (void *)data, \"nc_get_var_int\")); }\n\nint NetCDFCpp::GetVar(string varname, long *data) const { return (_GetVar(varname, (void *)data, \"nc_get_var_long\")); }\n\nint NetCDFCpp::GetVar(string varname, unsigned char *data) const { return (_GetVar(varname, (void *)data, \"nc_get_var_uchar\")); }\n\nint NetCDFCpp::CopyVar(string varname, NetCDFCpp &ncdf_out) const\n{\n    nc_type xtype;\n    int     rc = NetCDFCpp::InqVartype(varname, xtype);\n    if (rc < 0) return (-1);\n\n    size_t elem_size = NetCDFCpp::SizeOf(xtype);\n    VAssert(elem_size != 0);\n\n    vector<string> dimnames;\n    vector<size_t> dims;\n    rc = NetCDFCpp::InqVarDims(varname, dimnames, dims);\n    if (rc < 0) return (-1);\n\n    size_t nelements = 1;\n    for (int i = 0; i < dims.size(); i++) nelements *= dims[i];\n\n    unsigned char *data = new unsigned char[nelements * elem_size];\n\n    rc = NetCDFCpp::GetVar(varname, (void *)data);\n    if (rc < 0) {\n        delete[] data;\n        return (-1);\n    }\n\n    rc = ncdf_out.PutVar(varname, (void *)data);\n    if (rc < 0) {\n        delete[] data;\n        return (-1);\n    }\n\n    delete[] data;\n    return (NC_NOERR);\n}\n\nbool NetCDFCpp::InqDimDefined(string dimname)\n{\n    int dummy;\n    int rc = nc_inq_dimid(_ncid, dimname.c_str(), &dummy);\n\n    if (rc == NC_NOERR) return (true);\n\n    return (false);\n}\n\nbool NetCDFCpp::InqAttDefined(string varname, string attname)\n{\n    int varid = -1;\n    if (varname.empty()) {\n        varid = NC_GLOBAL;\n    } else {\n        int rc = nc_inq_varid(_ncid, varname.c_str(), &varid);\n        if (rc != NC_NOERR) return (false);\n    }\n\n    int dummy;\n    int rc = nc_inq_attid(_ncid, varid, attname.c_str(), &dummy);\n\n    if (rc == NC_NOERR) return (true);\n\n    return (false);\n}\n\nint NetCDFCpp::InqVarnames(vector<string> &varnames) const\n{\n    varnames.clear();\n\n    int ndims, nvars, natts, unlimitedid;\n\n    int rc = nc_inq(_ncid, &ndims, &nvars, &natts, &unlimitedid);\n    MY_NC_ERR(rc, _path, \"nc_inq()\");\n\n    for (int varid = 0; varid < nvars; varid++) {\n        char    namebuf[NC_MAX_NAME + 1];\n        nc_type xtype;\n        int     dimids[NC_MAX_VAR_DIMS];\n\n        rc = nc_inq_var(_ncid, varid, namebuf, &xtype, &ndims, dimids, &natts);\n        MY_NC_ERR(rc, _path, \"nc_inq_var()\");\n\n        varnames.push_back(namebuf);\n    }\n    return (0);\n}\n"
  },
  {
    "path": "lib/wasp/SignificanceMap.cpp",
    "content": "//\n// $Id: SignificanceMap.cpp,v 1.12 2012/08/29 19:36:37 alannorton Exp $\n//\n#include <iostream>\n#include <cstring>\n#include <vapor/SignificanceMap.h>\n\nusing namespace VAPoR;\n\n// gets the right-adjusted N bits of quantity TARG\n// starting from bit position POSS\n//\n#define GETBITS(TARG, POSS, N) (((TARG) >> ((POSS) + 1 - (N))) & ~(~0ULL << (N)))\n\n// set N bits of quantity TARG starting from position\n// POSS to the right-most N bits in integer SRC\n//\n#define PUTBITS(TARG, POSS, N, SRC)                         \\\n    (TARG) &= ~(~((~0ULL) << (N)) << (((POSS) + 1) - (N))); \\\n    (TARG) |= (((SRC) & ~((~0ULL) << (N))) << (((POSS) + 1) - (N)))\n\nusing namespace std;\n\ntemplate<class T> void swapbytes(T *ptr, size_t nelem)\n{\n    for (size_t i = 0; i < nelem; i++) {\n        unsigned char *uptr = (unsigned char *)&ptr[i];\n\n        unsigned char *p1 = uptr;\n        unsigned char *p2 = uptr + sizeof(T) - 1;\n        unsigned char  t;\n        for (int j = 0; j < (sizeof(T) >> 1); j++) {\n            t = *p1;\n            *p1 = *p2;\n            *p2 = t;\n            p1++;\n            p2--;\n        }\n    }\n}\n\nsize_t SignificanceMap::_GetBitsPerIdx(vector<size_t> dims)\n{\n    size_t size = 1;\n\n    for (int i = 0; i < dims.size(); i++) { size *= dims[i]; }\n\n    // Compute # bits needed per entry for encoded form of sigMapVec\n    //\n    size_t bits_per_idx = 1;\n    size--;\n    while ((size = (size >> 1))) bits_per_idx++;\n\n    return (bits_per_idx);\n}\n\nint SignificanceMap::_SignificanceMap(vector<size_t> dims)\n{\n    _dimsVec.clear();\n    _sigMapVec.clear();\n    _sigMapSize = 1;\n    _sorted = true;\n    for (int i = 0; i < dims.size(); i++) {\n        if (dims[i] < 1) {\n            SetErrMsg(\"Zero length dimensions not permitted\");\n            return (-1);\n        }\n        _sigMapSize *= dims[i];\n        _dimsVec.push_back(dims[i]);\n    }\n    _idxentry = 0;\n\n    _nx = _ny = _nz = _nt = 1;\n    if (dims.size() >= 1) _nx = dims[0];\n    if (dims.size() >= 2) _ny = dims[1];\n    if (dims.size() >= 3) _nz = dims[2];\n    if (dims.size() >= 4) _nt = dims[3];\n\n    // Compute # bits needed per entry for encoded form of sigMapVec\n    //\n    //_bits_per_idx = 1;\n    // size_t tmpsize = _sigMapSize - 1;\n    // while (tmpsize = (tmpsize >> 1)) _bits_per_idx++;\n\n    _bits_per_idx = _GetBitsPerIdx(_dimsVec);\n\n    return (0);\n}\n\nint SignificanceMap::_SignificanceMap(const unsigned char *map, std::vector<size_t> dims)\n{\n    if (_SignificanceMap(dims) < 0) return (-1);\n\n    return (SetMap(map));\n}\n\nSignificanceMap::SignificanceMap()\n{\n    vector<size_t> dims;\n    dims.push_back(1);\n\n    _sigMapEncode = NULL;\n    _sigMapEncodeSize = 0;\n    if (_SignificanceMap(dims) < 0) return;\n}\n\nSignificanceMap::SignificanceMap(size_t nx, size_t ny, size_t nz, size_t nt)\n{\n    vector<size_t> dims;\n\n    dims.push_back(nx);\n    dims.push_back(ny);\n    dims.push_back(nz);\n    dims.push_back(nt);\n\n    _sigMapEncode = NULL;\n    _sigMapEncodeSize = 0;\n    if (_SignificanceMap(dims) < 0) return;\n}\n\nSignificanceMap::SignificanceMap(vector<size_t> dims)\n{\n    _sigMapEncode = NULL;\n    _sigMapEncodeSize = 0;\n    if (_SignificanceMap(dims) < 0) return;\n}\n\n//\n// Significance map constructors for 1D, 2D, 3D, and 4D maps, using\n// a previously created map. I.e. a map returned from GetMap()\n//\nSignificanceMap::SignificanceMap(const unsigned char *map, size_t nx, size_t ny, size_t nz, size_t nt)\n{\n    vector<size_t> dims;\n\n    dims.push_back(nx);\n    dims.push_back(ny);\n    dims.push_back(nz);\n    dims.push_back(nt);\n\n    _sigMapEncode = NULL;\n    _sigMapEncodeSize = 0;\n    if (_SignificanceMap(map, dims) < 0) return;\n}\n\nSignificanceMap::SignificanceMap(const unsigned char *map, vector<size_t> dims)\n{\n    _sigMapEncode = NULL;\n    _sigMapEncodeSize = 0;\n    if (_SignificanceMap(map, dims) < 0) return;\n}\n\nSignificanceMap::SignificanceMap(const SignificanceMap &rhs)\n{\n    if (this == &rhs) return;\n\n    this->_nx = rhs._nx;\n    this->_ny = rhs._ny;\n    this->_nz = rhs._nz;\n    this->_nt = rhs._nt;\n\n    this->_sorted = rhs._sorted;\n\n    this->_dimsVec = rhs._dimsVec;\n    this->_sigMapSize = rhs._sigMapSize;\n    this->_sigMapVec = rhs._sigMapVec;\n\n    this->_bits_per_idx = rhs._bits_per_idx;\n    this->_sigMapEncodeSize = rhs._sigMapEncodeSize;\n    this->_sigMapEncode = NULL;\n\n    this->_idxentry = rhs._idxentry;\n\n    // handle raw pointers\n    //\n    if (rhs._sigMapEncode) {\n        this->_sigMapEncode = new unsigned char[this->_sigMapEncodeSize];\n        memcpy(this->_sigMapEncode, rhs._sigMapEncode, this->_sigMapEncodeSize);\n    }\n}\n\nSignificanceMap &SignificanceMap::operator=(const SignificanceMap &rhs)\n{\n    if (this == &rhs) return (*this);\n\n    this->_nx = rhs._nx;\n    this->_ny = rhs._ny;\n    this->_nz = rhs._nz;\n    this->_nt = rhs._nt;\n\n    this->_sorted = rhs._sorted;\n\n    this->_dimsVec = rhs._dimsVec;\n    this->_sigMapSize = rhs._sigMapSize;\n    this->_sigMapVec = rhs._sigMapVec;\n\n    this->_bits_per_idx = rhs._bits_per_idx;\n    this->_sigMapEncodeSize = rhs._sigMapEncodeSize;\n    this->_sigMapEncode = NULL;\n\n    this->_idxentry = rhs._idxentry;\n\n    // handle raw pointers\n    //\n    if (rhs._sigMapEncode) {\n        this->_sigMapEncode = new unsigned char[this->_sigMapEncodeSize];\n        memcpy(this->_sigMapEncode, rhs._sigMapEncode, this->_sigMapEncodeSize);\n    }\n\n    return *this;\n}\n\nSignificanceMap::~SignificanceMap()\n{\n    if (_sigMapEncode) { delete[] _sigMapEncode; }\n\n    _sigMapEncode = NULL;\n}\n\nint SignificanceMap::Reshape(vector<size_t> dims)\n{\n    _dimsVec.clear();\n\n    if (dims.size() != _dimsVec.size()) {\n        return (_SignificanceMap(dims));\n    } else {\n        for (int i = 0; i < dims.size(); i++) {\n            if (dims[i] != _dimsVec[i]) { return (_SignificanceMap(dims)); }\n        }\n    }\n    return (0);    // nothing to do\n}\n\nint SignificanceMap::Reshape(size_t nx, size_t ny, size_t nz, size_t nt)\n{\n    vector<size_t> dims;\n\n    dims.push_back(nx);\n    dims.push_back(ny);\n    dims.push_back(nz);\n    dims.push_back(nt);\n\n    return Reshape(dims);\n}\n\nint SignificanceMap::Set(size_t idx)\n{\n    if (idx >= _sigMapSize) {\n        SetErrMsg(\"Coordinates out of range\");\n        return (-1);\n    }\n\n    // if (Test(idx)) return(0);\n\n    _sigMapVec.push_back(idx);\n\n    //\n    // See if sig map is still sorted\n    //\n    if (_sorted && (_sigMapVec.size() > 1)) {\n        if (_sigMapVec[_sigMapVec.size() - 1] < _sigMapVec[_sigMapVec.size() - 2]) { _sorted = false; }\n    }\n    return (0);\n}\n\nint SignificanceMap::SetXYZT(size_t x, size_t y, size_t z, size_t t)\n{\n    if (_dimsVec.size() > 4) {\n        SetErrMsg(\"Method not implemented for dimensions greater than 4\");\n        return (-1);\n    }\n    if (x >= _nx || y >= _ny || z >= _nz || t >= _nt) {\n        SetErrMsg(\"Coordinates out of range\");\n        return (-1);\n    }\n\n    size_t idx = (t * _nz * _ny * _nx) + (z * _ny * _nx) + (y * _nx) + x;\n    return (Set(idx));\n}\n\nint SignificanceMap::Clear(size_t idx)\n{\n    if (idx >= _sigMapSize) {\n        SetErrMsg(\"Coordinates out of range\");\n        return (-1);\n    }\n\n    if (!Test(idx)) return (0);\n\n    vector<size_t>::iterator itr;\n    for (itr = _sigMapVec.begin(); itr != _sigMapVec.end();) {\n        if (*itr == idx) {\n            _sigMapVec.erase(itr);\n\n            // We're being overly cautious here - entries should never\n            // be duplicated\n            //\n            itr = _sigMapVec.begin();\n        }\n    }\n    return (0);\n}\n\nint SignificanceMap::ClearXYZT(size_t x, size_t y, size_t z, size_t t)\n{\n    if (_dimsVec.size() > 4) {\n        SetErrMsg(\"Method not implemented for dimensions greater than 4\");\n        return (-1);\n    }\n\n    if (x >= _nx || y >= _ny || z >= _nz || t >= _nt) {\n        SetErrMsg(\"Coordinates out of range\");\n        return (-1);\n    }\n\n    size_t idx = (t * _nz * _ny * _nx) + (z * _ny * _nx) + (y * _nx) + x;\n    return (Clear(idx));\n}\n\nvoid SignificanceMap::Clear() { _sigMapVec.clear(); }\n\nint SignificanceMap::GetCoordinates(size_t offset, size_t *idx) const\n{\n    if (offset >= _sigMapVec.size()) {\n        SetErrMsg(\"Index out of range\");\n        return (-1);\n    }\n    *idx = _sigMapVec[offset];\n    return (0);\n}\n\nint SignificanceMap::GetCoordinatesXYZT(size_t offset, size_t *x, size_t *y, size_t *z, size_t *t) const\n{\n    if (_dimsVec.size() > 4) {\n        SetErrMsg(\"Method not implemented for dimensions greater than 4\");\n        return (-1);\n    }\n\n    size_t idx;\n\n    if (GetCoordinates(offset, &idx) < 0) return (-1);\n\n    *t = idx / (_nz * _ny * _nx);\n    idx -= (*t * _nz * _ny * _nx);\n\n    *z = idx / (_ny * _nx);\n    idx -= (*z * _ny * _nx);\n\n    *y = idx / _nx;\n    idx -= (*y * _nx);\n\n    *x = idx;\n\n    return (0);\n}\n\nvoid SignificanceMap::GetNextEntryRestart()\n{\n    if (!_sorted) SignificanceMap::Sort();\n    _idxentry = 0;\n}\n\nint SignificanceMap::GetNextEntry(size_t *idx)\n{\n    if (_idxentry >= _sigMapVec.size()) return (0);\n\n    *idx = _sigMapVec[_idxentry];\n    _idxentry++;\n\n    return (1);\n}\n\nint SignificanceMap::GetNextEntryXYZT(size_t *xptr, size_t *yptr, size_t *zptr, size_t *tptr)\n{\n    if (_dimsVec.size() > 4) {\n        SetErrMsg(\"Method not implemented for dimensions greater than 4\");\n        return (-1);\n    }\n\n    size_t idx;\n    if (GetNextEntry(&idx)) {\n        size_t t = idx / (_nz * _ny * _nx);\n        idx -= (t * _nz * _ny * _nx);\n\n        size_t z = idx / (_ny * _nx);\n        idx -= (z * _ny * _nx);\n\n        size_t y = idx / _nx;\n        idx -= (y * _nx);\n\n        size_t x = idx;\n\n        if (xptr) *xptr = x;\n        if (yptr) *yptr = y;\n        if (zptr) *zptr = z;\n        if (tptr) *tptr = t;\n        return (1);\n    }\n\n    return (0);\n}\nsize_t SignificanceMap::GetMapSize(vector<size_t> dims, size_t num_entries)\n{\n    // Calculate size of encoded map\n    //\n    size_t mapsize;\n    size_t tbits = num_entries * _GetBitsPerIdx(dims);\n    if (tbits)\n        mapsize = (tbits - 1) / BITSPERBYTE + 1 + HEADER_SIZE;\n    else\n        mapsize = HEADER_SIZE;\n\n    return (mapsize);\n}\n\nsize_t SignificanceMap::GetMapSize(size_t num_entries) const { return (GetMapSize(_dimsVec, num_entries)); }\n\nvoid SignificanceMap::GetMap(unsigned char *encodedMap)\n{\n    unsigned long LSBTest = 1;\n    bool          do_swapbytes = false;\n    if (!(*(char *)&LSBTest)) {\n        // swap to MSBFirst\n        do_swapbytes = true;\n    }\n\n    memset(_sigMapEncode, 0, _sigMapEncodeSize);\n\n    //\n    //  Encode header\n    //\t\tbytes[0-2] : magic\n    //\t\tbytes[3] : version number\n    //\t\tbytes[4-11] : _sigMapVec.size()\n    //\t\tbytes[12-19] : _dimsVec.size()\n    //\t\tbytes[20-] : _dimsVec[i]\n    //\n    encodedMap[0] = encodedMap[1] = encodedMap[2] = 'c';\n    encodedMap[3] = VDF_VERSION;\n\n    vector<size_t> header_data;\n    header_data.push_back(_sigMapVec.size());\n    header_data.push_back(_dimsVec.size());\n    for (int i = 0; i < _dimsVec.size(); i++) header_data.push_back(_dimsVec[i]);\n\n    // encode num entries and sigmap dimens\n    //\n    unsigned char *ucptr = &encodedMap[4];\n\n    for (int i = 0; i < header_data.size(); i++) {\n        size_t entry = header_data[i];\n\n        VAssert(((ucptr + 8) - encodedMap) <= HEADER_SIZE);\n\n        if (do_swapbytes) { swapbytes(&entry, 1); }\n\n        unsigned char *cptr = (unsigned char *)&entry;\n        for (int j = 0; j < sizeof(entry); j++) { ucptr[j] = cptr[j]; }\n        for (int j = sizeof(entry); j < 8; j++) { ucptr[j] = 0; }\n        ucptr += 8;\n    }\n\n    unsigned char *ptr = encodedMap + HEADER_SIZE;\n    int            bib = BITSPERBYTE;    // bits available in current byte\n    int            p = BITSPERBYTE - 1;\n\n    if (!_sorted) SignificanceMap::Sort();\n\n    for (size_t i = 0; i < _sigMapVec.size(); i++) {\n        size_t idx = _sigMapVec[i];\n        int    tbits = _bits_per_idx;\n        while (tbits) {\n            int n = min(tbits, bib);\n            PUTBITS(*ptr, p, n, idx >> (tbits - n));\n            p -= n;\n            tbits -= n;\n            bib -= n;\n            if (bib == 0) {\n                ptr++;\n                bib = BITSPERBYTE;\n                p = BITSPERBYTE - 1;\n            }\n        }\n    }\n}\n\nvoid SignificanceMap::GetMap(const unsigned char **map, size_t *maplen)\n{\n    *map = NULL;\n    *maplen = 0;\n\n    size_t mapsize = GetMapSize();\n\n    if (_sigMapEncodeSize < mapsize) {\n        size_t l = mapsize;    // hack to allow word-size reads\n        while (l % 4) l++;\n\n        if (_sigMapEncode) { delete[] _sigMapEncode; }\n        _sigMapEncode = new unsigned char[l];\n        _sigMapEncodeSize = l;\n    }\n    memset(_sigMapEncode, 0, _sigMapEncodeSize);\n    *map = _sigMapEncode;\n    *maplen = mapsize;\n\n    return (GetMap(_sigMapEncode));\n}\n\nint SignificanceMap::SetMap(const unsigned char *map)\n{\n    if (map[0] != 'c' || map[1] != 'c' || map[2] != 'c') {\n        SetErrMsg(\"Invalid significance map - bogus header\");\n        return (-1);\n    }\n    if (map[3] > VDF_VERSION) {\n        SetErrMsg(\"Invalid significance map - bogus header\");\n        return (-1);\n    }\n\n    unsigned long LSBTest = 1;\n    bool          do_swapbytes = false;\n    if (!(*(char *)&LSBTest)) {\n        // swap to MSBFirst\n        do_swapbytes = true;\n    }\n\n    unsigned char version = map[3];\n\n    const unsigned char *ucptr = &map[4];\n    size_t               numentries = 0;\n\n    unsigned char *cptr = (unsigned char *)&numentries;\n    for (int i = 0; i < sizeof(numentries); i++) { cptr[i] = ucptr[i]; }\n    ucptr += 8;\n    if (do_swapbytes) swapbytes(&numentries, 1);\n\n    size_t header_size = HEADER_SIZE;\n\n    // Check for old style (version 1) encoding\n    //\n    if (version == 01) {\n        if (numentries > _sigMapSize) {\n            SetErrMsg(\"SignificanceMap shape does not match encoded map\");\n            return (-1);\n        }\n        header_size = 16;\n    } else {\n        size_t ndims = 0;\n        cptr = (unsigned char *)&ndims;\n        for (int i = 0; i < sizeof(ndims); i++) { cptr[i] = ucptr[i]; }\n        ucptr += 8;\n        if (do_swapbytes) swapbytes(&ndims, 1);\n\n        vector<size_t> dims;\n        for (int j = 0; j < ndims; j++) {\n            size_t dim = 0;\n\n            cptr = (unsigned char *)&dim;\n            for (int i = 0; i < sizeof(dim); i++) { cptr[i] = ucptr[i]; }\n            ucptr += 8;\n            if (do_swapbytes) swapbytes(&dim, 1);\n\n            dims.push_back(dim);\n        }\n        if (_SignificanceMap(dims) < 0) return (-1);\n    }\n\n    _sigMapVec.clear();\n    _sigMapVec.reserve(numentries);\n\n    const unsigned char *ptr = map + header_size;\n    int                  bib = BITSPERBYTE;    // bits remaining in current byte\n\n    _sorted = true;\n    size_t idxprev = 0;\n    for (size_t i = 0; i < numentries; i++) {\n        size_t idx = 0;\n        int    tbits = _bits_per_idx;\n        int    p = _bits_per_idx - 1;\n        while (tbits) {\n            int n = min(tbits, bib);\n            PUTBITS(idx, p, n, *ptr >> (bib - n));\n            p -= n;\n            tbits -= n;\n            bib -= n;\n            if (bib == 0) {\n                ptr++;\n                bib = BITSPERBYTE;\n            }\n        }\n        //\n        // Should probably call SignificanceMap::Set() here so\n        // that we check for duplicate values. But this is quicker.\n        //\n        _sigMapVec.push_back(idx);\n        if (idx < idxprev) { _sorted = false; }\n        idxprev = idx;\n    }\n    return (0);\n}\n\nint SignificanceMap::Append(const SignificanceMap &smap)\n{\n    if (_sigMapVec.size() == 0) {\n        if (_SignificanceMap(smap._dimsVec) < 0) return (-1);\n    }\n\n    if (_dimsVec.size() != smap._dimsVec.size()) {\n        SetErrMsg(\"Dimension mismatch\");\n        return (-1);\n    }\n\n    for (int i = 0; i < _dimsVec.size(); i++) {\n        if (_dimsVec[i] != smap._dimsVec[i]) {\n            SetErrMsg(\"Dimension mismatch\");\n            return (-1);\n        }\n    }\n\n    for (size_t i = 0; i < smap._sigMapVec.size(); i++) {\n        int rc = this->Set(smap._sigMapVec[i]);\n        if (rc < 0) return (-1);\n    }\n    return (0);\n}\n\nvoid SignificanceMap::Invert()\n{\n    vector<size_t> tmpvec = _sigMapVec;\n    if (!_sorted) SignificanceMap::Sort();\n\n    _sigMapVec.clear();\n\n    size_t idx = 0;\n    for (size_t i = 0; i < tmpvec.size(); i++) {\n        while (idx != tmpvec[i]) {\n            _sigMapVec.push_back(idx);\n            idx++;\n        }\n        idx++;\n    }\n    while (idx < _sigMapSize) {\n        _sigMapVec.push_back(idx);\n        idx++;\n    }\n}\n\nvoid SignificanceMap::Sort()\n{\n    sort(_sigMapVec.begin(), _sigMapVec.end());\n    _sorted = true;\n}\n\nnamespace VAPoR {\nstd::ostream &operator<<(std::ostream &o, const SignificanceMap &sigmap)\n{\n    o << \"SignificanceMap\" << endl;\n    o << \" _nx : \" << sigmap._nx << endl;\n    o << \" _ny : \" << sigmap._ny << endl;\n    o << \" _nz : \" << sigmap._nz << endl;\n    o << \" _nt : \" << sigmap._nt << endl;\n    o << \" _sorted : \" << sigmap._sorted << endl;\n    o << \" _dimsVec : \";\n    for (int i = 0; i < sigmap._dimsVec.size(); i++) { o << sigmap._dimsVec[i] << \" \"; }\n    o << endl;\n    o << \" _sigMapSize : \" << sigmap._sigMapSize << endl;\n    o << \" _bits_per_idx : \" << sigmap._bits_per_idx << endl;\n    o << \" _sigMapEncodeSize : \" << sigmap._sigMapEncodeSize << endl;\n    o << \" _idxentry : \" << sigmap._idxentry << endl;\n    o << \" _sigMapVec : \" << endl;\n    for (int i = 0; i < sigmap._sigMapVec.size(); i++) { o << \"  \" << i << \" \" << sigmap._sigMapVec[i] << endl; }\n\n    return (o);\n}\n};    // namespace VAPoR\n"
  },
  {
    "path": "lib/wasp/TODO",
    "content": "\nWASP\n----\n\n# git-test vapor_3_0\n#\n#\n\ndone - Support Min/Max & clamp in decompression\n\nserialize (order) threaded I/O\n\nShould 'unlimited' dimensions be supported ?\n\ndone - ***If (cratios.size() == 1 and cratios[0] == 1) do not transform\nvariable, but still block it. This facilitates use of coordinate variables\nthat are not compressed with data variables that are.\n\nAPI should be able to operate on conventional netcdf files (files without\nthe WASP attribute). Currently most methods return error (unecessarily)\nif _waspFile is not true.\n\nVDCNetCDF\n--------\n\nRefinement level should be supported for uncompressed variables to\nhandle uncompressed coordinate variables.  Reading a coordinate\nvariable (that was not compressed) should do the appropriate averaging\nbased on the wavelet (symatric vs asymetric)\n\nVDC\n---\n\n\nShould the number of time dimensions be restricted to one? Either\nway needs to be tested\n\nNot sure what Uniform coordinate variables are actually doing. Their\nuniformness is not guaranteed (can be written to), \n\nConsider moving VDC::GetNumTimeSteps() to VarBase (or doing away with it\nentirely - it's redundant).\n\nMake sure open mode (RWA) is handled correctly both for supporting vdccreate\nand 2vdc operations\n\nNeed to be consistent in interpretation of BS (e.b. bs== dimensions, bs=1, etc)\nfor WASP.cpp, VDC*\n\nVerify that DC ensures that dimensions are always in correct order. In \nparticular, uses of DC API don't have to verify order is correct when\ngetting a variables dimensions.\n\nDataMgr\n-------\n\nHandle derived variable coordinates\n\nerror checking\n\nconvert all global time steps to local\n\nRename DataMgrV3 to DataMgr\n\n\nRegularGrid\n-----------\n\nIterator for bounding volume defined in user coords\n\nFILES WE DONT SYNC\nDataMgr.cpp\nDataMgrFactor.cpp\n\nWASP\n----\n\ndone - integer wavelet transforms - haar and cdf5/3.\n\nUse int haar for missing value mask\n\nDCCF\n----\n\nInterpolate structured to regular grid (using weithtable)\nInitialize, if called multipe times, doesn't clean up. Probably true elsewhere.\n\nGetAtt*() are no-ops\n\nderived, cartographic coordinates (e.g. lonX) are not blocked. However, \nthe geographic coordinates (e.g. lon) are.\n\nDCWRF\n----\n\nGetAtt*() are no-ops\n\nIdealized grid (MAP_PROJ = 0) not supported. Conversion of yochen data\nuses XLONG and XLAT, which are set to bogus values (-90 for all points).\nSee vapor-2.x, DCReaderWRF for proper calculation using DX and DY\n\nNo map projection returned\n\n\nALL\n---\nReadSlice should work with 1D data\n\nNetCDFCollection\n----------------\n\nDerivedVar::Open returns a file descriptor which is passed into Read(), and\nClose(). However, most implementations igore the fd. Is it needed?\n\nVariables with reversed coordinates not supported. See\n/glade/p/DASG/VAPOR/Data/UKMet/GEMS*\n\nMISC\n----\n\nverify cratio=1 case works (vdc2raw, raw2vdc)\n\nunitialized memory read with hundred.nc:\n\t../../targets/Linux_x86_64/bin/test_datamgr -nts 1 -loop 1 -memsize 2000 -var v $c/hundred.nc\n\n"
  },
  {
    "path": "lib/wasp/WASP.cpp",
    "content": "#include \"vapor/VAssert.h\"\n#include <sstream>\n#include <sstream>\n#include <iterator>\n#include <sys/stat.h>\n#include \"vapor/utils.h\"\n#include \"vapor/MatWaveBase.h\"\n#include \"vapor/Compressor.h\"\n#include \"vapor/WASP.h\"\n\nusing namespace VAPoR;\nusing namespace Wasp;\n\nnamespace {\n\n// Size of header at beginning of each compression block\n//\nconst size_t BLK_HDR_SZ = 2;\n\nsize_t linearize_coords(vector<size_t> coords, vector<size_t> dims)\n{\n    reverse(coords.begin(), coords.end());\n    reverse(dims.begin(), dims.end());\n    return (LinearizeCoords(coords, dims));\n}\n\n//\n// Map possibly unaligned hyperslab coords (start and count)\n// into block-aligned coordinates\n//\nvoid block_align(const vector<size_t> &start, const vector<size_t> &count, const vector<size_t> &bs, vector<size_t> &astart, vector<size_t> &acount)\n{\n    astart = start;\n    acount = count;\n\n    VAssert(start.size() == count.size());\n    VAssert(start.size() == bs.size());\n\n    for (int i = 0; i < start.size(); i++) {\n        size_t stop = astart[i] + acount[i] - 1;\n        astart[i] = (astart[i] / bs[i] * bs[i]);\n\n        stop = (stop / bs[i]) * bs[i] + (bs[i] - 1);\n        acount[i] = stop - astart[i] + 1;\n    }\n}\n\nvector<size_t> compressor_bs(vector<size_t> bs)\n{\n    vector<size_t> my_bs = bs;\n    reverse(my_bs.begin(), my_bs.end());    // order fastest to slowest\n\n    // Remove slowest varying dimensions of length 1\n    //\n    while (my_bs.size() && my_bs[my_bs.size() - 1] == 1) { my_bs.pop_back(); }\n    return (my_bs);\n}\n\n// vector subtraction. Return a - b\n//\nvector<size_t> vector_sub(const vector<size_t> &a, const vector<size_t> &b)\n{\n    VAssert(a.size() == b.size());\n\n    vector<size_t> c;\n    for (int i = 0; i < a.size(); i++) {\n        VAssert(a[i] >= b[i]);\n        c.push_back(a[i] - b[i]);\n    }\n    return (c);\n}\n\n//\n// Helper class for NetCDF style hyperslab indexing arithmetic\n//\nclass vectorinc {\npublic:\n    // start and count define hyperslab coordinates\n    // dims define overall dimensions of array\n    // inc is the increment step to be added to start\n    //\n    vectorinc(vector<size_t> start, vector<size_t> count, vector<size_t> dims, vector<size_t> inc);\n\n    // Compute next starting coordinates by adding inc to previous\n    // starting coordinates. As a convenience return the linear offset\n    // of the new starting coordinates coordinates.\n    //\n    bool next(vector<size_t> &newstart, size_t &offset);\n\n    // Computh i'th coordinate after 'index' increments by 'inc'\n    //\n    void ith(size_t index, vector<size_t> &start, size_t &offset) const;\n\n    // Number of iterations required to increment 'start' by 'inc'\n    // to get to 'count'\n    //\n    size_t num() const { return (_num); };\n\nprivate:\n    vector<size_t> _start;\n    vector<size_t> _count;\n    vector<size_t> _end;    // ending coordinates (start + count)\n    vector<size_t> _dims;\n    vector<size_t> _next;\n    vector<size_t> _inc;\n    size_t         _num;\n};\n\nvectorinc::vectorinc(vector<size_t> start, vector<size_t> count, vector<size_t> dims, vector<size_t> inc)\n{\n    VAssert(start.size() == count.size());\n    VAssert(start.size() == dims.size());\n    VAssert(start.size() == inc.size());\n\n    for (int i = 0; i < start.size(); i++) {\n        _end.push_back(start[i] + count[i]);\n        // VAssert(_end[i] <= dims[i]);\n    }\n\n    _start = start;\n    _next = start;\n    _count = count;\n    _dims = dims;\n    _inc = inc;\n    _num = 1;\n\n    bool done;\n    do {\n        done = false;\n        int i = start.size() - 1;\n        while (i >= 0 && !done) {\n            start[i] += _inc[i];\n            if (start[i] >= _end[i]) {\n                start[i] = _start[i];\n            } else {\n                done = true;\n                _num++;\n            }\n            i--;\n        }\n    } while (done);\n}\n\nvoid vectorinc::ith(size_t index, vector<size_t> &start, size_t &offset) const\n{\n    VAssert(index < _num);\n\n    start.clear();\n    offset = 0;\n\n    start = _start;\n    for (size_t idx = 0; idx < index; idx++) {\n        int  i = start.size() - 1;\n        bool done = false;\n        while (i >= 0 && !done) {\n            start[i] += _inc[i];\n            if (start[i] >= _end[i]) {\n                start[i] = _start[i];\n            } else {\n                done = true;\n            }\n            i--;\n        }\n    }\n\n    offset = linearize_coords(start, _dims);\n}\n\n#ifdef UNUSED\nbool vectorinc::next(vector<size_t> &start, size_t &offset)\n{\n    offset = 0;\n\n    int  i = _next.size() - 1;\n    bool done = false;\n    while (i >= 0 && !done) {\n        _next[i] += _inc[i];\n        if (_next[i] >= _end[i]) {\n            _next[i] = _start[i];\n        } else {\n            done = true;\n        }\n        i--;\n    }\n    start = _next;\n\n    offset = linearize_coords(start, _dims);\n\n    return (done);\n}\n#endif\n\n// Execution thread state for data reads and writes\n//\nclass thread_state {\npublic:\n    int                  _id;\n    EasyThreads *        _et;    // one per thread\n    int                  _nthreads;\n    string               _varname;\n    vector<NetCDFCpp *>  _ncdfcptrs;    // one for each file\n    vector<size_t>       _start;\n    vector<size_t>       _count;\n    vector<size_t>       _bs;\n    vector<size_t>       _udims;\n    vector<size_t>       _ncoeffs;\n    vector<size_t>       _encoded_dims;\n    vector<Compressor *> _compressors;    // one per thread\n    void *               _data;           // global (shared by all threads)\n    int                  _data_type;      // typeof(*_data)\n    unsigned char *      _mask;           // global (shared by all threads)\n    void *               _block;          // private (not shared)\n    void *               _coeffs;         // private (not shared)\n    int                  _block_type;     // typeof(*_block) and typeof(*_coeffs)\n    int                  _xtype;          // external storage NetCDF storage\n    unsigned char *      _maps;           // private (not shared)\n    int                  _level;\n    bool                 _unblock_flag;    // unblock the data after reconstruction?\n    static int           _status;          // error indicator\n\n    thread_state(int id, EasyThreads *et, int nthreads, string &varname, const vector<NetCDFCpp *> &ncdfcptrs, const vector<size_t> &start, const vector<size_t> &count, const vector<size_t> &bs,\n                 const vector<size_t> &udims, const vector<size_t> &ncoeffs, const vector<size_t> &encoded_dims, const vector<Compressor *> &compressors, void *data, int data_type,\n                 unsigned char *mask, void *block, void *coeffs, int block_type, int xtype, unsigned char *maps, int level, bool unblock_flag)\n    : _id(id), _et(et), _nthreads(nthreads), _varname(varname), _ncdfcptrs(ncdfcptrs), _start(start), _count(count), _bs(bs), _udims(udims), _ncoeffs(ncoeffs), _encoded_dims(encoded_dims),\n      _compressors(compressors), _data(data), _data_type(data_type), _mask(mask), _block(block), _coeffs(coeffs), _block_type(block_type), _xtype(xtype), _maps(maps), _level(level),\n      _unblock_flag(unblock_flag)\n    {\n        _status = 0;\n    }\n};\nint thread_state::_status = 0;\n\n// Convert voxel coordinates, 'vcoords', to block coordinates, 'bcoords',\n// assuming a block size of 'bs'. 'residual' is any offset within\n// the block if 'vcoords' is not block-aligned.\n//\nvoid to_block_coords(vector<size_t> vcoords, vector<size_t> bs, vector<size_t> &bcoords, size_t &residual)\n{\n    VAssert(vcoords.size() == bs.size());\n\n    bcoords = vcoords;\n\n    size_t factor = 1;\n    residual = 0;\n    for (int i = 0; i < vcoords.size(); i++) {\n        residual += factor * (bcoords[i] % bs[i]);\n        factor *= bs[i];\n\n        bcoords[i] /= bs[i];\n    }\n}\n\n//\n// Pad a line using the appropriate boundary extension method\n// based on 'mode'\n//\ntemplate<class T>\nvoid pad_line(string mode, T *line_start,\n              size_t l1,    // length of valid data\n              size_t l2,    // total length of array\n              long   stride)\n{\n    T *ptr = line_start + ((long)l1 * stride);\n\n    long index;\n    int  inc;\n\n    VAssert(l1 > 0 && stride != 0);\n    if (l1 == l2) return;\n\n    if (l1 == 1) {\n        int dir = stride < 0 ? -1 : 1;\n        for (size_t l = l1; l < l2; l += dir) {\n            *ptr = *line_start;\n            ptr += stride;\n        }\n        return;\n    }\n\n    //\n    // Symmetric-halfpoint. If a signal looks like ABCDE, the extended signal\n    // looks like:\n    //\n    //\tEEDCBAABCDEEDCBAA\n    //\t      ^^^^^\n    //\n    if (mode.compare(\"symh\") == 0) {\n        index = (long)l1 - 1;\n        inc = 0;\n\n        for (size_t l = l1; l < l2; l++) {\n            *ptr = line_start[(size_t)index * stride];\n            ptr += stride;\n            if (index == 0) {\n                if (inc == 0)\n                    inc = 1;\n                else\n                    inc = 0;\n            } else if (index == (long)l1 - 1) {\n                if (inc == 0)\n                    inc = -1;\n                else\n                    inc = 0;\n            }\n            index += inc;\n        }\n    }\n    //\n    // Symmetric-wholepoint. If a signal looks like ABCDE, the extended signal\n    // looks like:\n    //\n    //\tDEDCBABCDEDCBAB\n    //\t     ^^^^^\n    else if (mode.compare(\"symw\") == 0) {\n        index = (long)l1 - 2;\n        inc = -1;\n\n        for (size_t l = l1; l < l2; l++) {\n            *ptr = line_start[(size_t)index * stride];\n            ptr += stride;\n            if (index == 0) {\n                inc = 1;\n            } else if (index == (long)l1 - 1) {\n                inc = -1;\n            }\n            index += inc;\n        }\n    }\n    //\n    // Periodic. If a signal looks like ABCDE, the extended signal\n    // looks like:\n    //\n    //\t...ABCDABCDEABCDABCD...\n    //\t       ^^^^^\n    else if (mode.compare(\"per\") == 0) {\n        index = (int)0;\n\n        for (size_t l = l1; l < l2; l++) {\n            *ptr = line_start[(size_t)index * stride];\n            ptr += stride;\n            index++;\n        }\n    }\n    //\n    // SP0. If a signal looks like ABCDE, the extended signal\n    // looks like:\n    //\n    //\t...AAAAABCDEEEEE...\n    //\t       ^^^^^\n    else if (mode.compare(\"sp0\") == 0) {\n        index = (long)l1 - 1;\n\n        for (size_t l = l1; l < l2; l++) {\n            *ptr = line_start[(size_t)index * stride];\n            ptr += stride;\n        }\n    }\n    // Default to sp0\n    //\n    else {\n        index = (long)l1 - 1;\n\n        for (size_t l = l1; l < l2; l++) {\n            *ptr = line_start[(size_t)index * stride];\n            ptr += stride;\n        }\n    }\n}\n\n//\n// Perform in-place byte swapping\n//\nvoid swapbytes(void *ptr, size_t ws, size_t nelem)\n{\n    for (size_t i = 0; i < nelem; i++) {\n        unsigned char *uptr = ((unsigned char *)ptr) + (i * ws);\n\n        unsigned char *p1 = uptr;\n        unsigned char *p2 = uptr + ws - 1;\n        unsigned char  t;\n        for (int j = 0; j < (ws >> 1); j++) {\n            t = *p1;\n            *p1 = *p2;\n            *p2 = t;\n            p1++;\n            p2--;\n        }\n    }\n}\n\n// Sum elements in a vector\n//\nsize_t vsum(vector<size_t> v)\n{\n    size_t ntotal = 0;\n\n    for (int i = 0; i < v.size(); i++) ntotal += v[i];\n    return (ntotal);\n}\n\n// Product of elements in a vector\n//\nsize_t vproduct(vector<size_t> a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n\n#ifdef UNUSED_FUNCTION\n// Elementwise difference between vector a and b (return (a-b));\n//\nvector<size_t> vdiff(vector<size_t> a, vector<size_t> b)\n{\n    VAssert(a.size() == b.size());\n\n    vector<size_t> c(a.size(), 0);\n\n    for (int i = 0; i < a.size(); i++) c[i] = a[i] - b[i];\n    return (c);\n}\n#endif\n\n// Extract a single block of data from an array. Perform padding as\n// needed based on mode value if this is a boundary block\n// Handles 1D, 2D, and 3D arrays\n//\n// data : pointer to start of array\n// dims : dimensions of array 'data'\n// start: starting coordinates of block within array 'data' (need not\n// be block aligned)\n// block : pointer to start of block where data should be copied\n// bs : dimensions of block.\n// min, max : range of data values within block\n//\ntemplate<class T, class U> void Block(const T *data, const unsigned char *mask, vector<size_t> dims, vector<size_t> start, U *block, vector<size_t> bs, string mode, U &min, U &max)\n{\n    min = 0;\n    max = 0;\n\n    VAssert(dims.size() >= 1 && dims.size() <= 4);\n    VAssert(dims.size() == start.size());\n    VAssert(dims.size() == bs.size());\n\n    size_t offset = linearize_coords(start, dims);\n    data += offset;\n\n    if (mask) mask += offset;\n\n    //\n    // Only 1D, 2D, and 3D blocks handled\n    //\n    while (bs.size() && bs[0] == 1) {\n        bs.erase(bs.begin());\n        dims.erase(dims.begin());\n        start.erase(start.begin());\n    }\n\n    int rank = bs.size();\n\n    // dimensions of volume\n    //\n    size_t nx = rank >= 1 ? dims[rank - 1] : 1;\n    size_t ny = rank >= 2 ? dims[rank - 2] : 1;\n    size_t nz = rank >= 3 ? dims[rank - 3] : 1;\n\n    // dimensions of block\n    //\n    size_t nbx = rank >= 1 ? bs[rank - 1] : 1;\n    size_t nby = rank >= 2 ? bs[rank - 2] : 1;\n    size_t nbz = rank >= 3 ? bs[rank - 3] : 1;\n\n    // stopping coordinates within block, handling boundary cases\n    // for non-block-aligned regions\n    //\n\n    size_t xstop = nbx;\n    size_t ystop = nby;\n    size_t zstop = nbz;\n\n    if (rank >= 1 && (start[rank - 1] + nbx) > dims[rank - 1]) { xstop = dims[rank - 1] - start[rank - 1]; }\n    if (rank >= 2 && (start[rank - 2] + nby) > dims[rank - 2]) { ystop = dims[rank - 2] - start[rank - 2]; }\n    if (rank >= 3 && (start[rank - 3] + nbz) > dims[rank - 3]) { zstop = dims[rank - 3] - start[rank - 3]; }\n\n    //\n    // These flags are true if this is a boundary block && the volume\n    // dimensions are not block aligned.\n    //\n    bool xbdry = rank >= 1 && start[rank - 1] + nbx > nx;\n    bool ybdry = rank >= 2 && start[rank - 2] + nby > ny;\n    bool zbdry = rank >= 3 && start[rank - 3] + nbz > nz;\n\n    double ave = 0.0;\n    min = (U)data[0];\n    max = (U)data[0];\n    if (mask) {\n        size_t n = 0;\n        double total = 0.0;\n        for (size_t z = 0; z < zstop; z++) {\n            for (size_t y = 0; y < ystop; y++) {\n                for (size_t x = 0; x < xstop; x++) {\n                    size_t index = nx * ny * z + nx * y + x;\n                    if (!mask[index]) continue;\n                    U v = (U)data[index];\n\n                    if (n == 0) { min = max = (U)v; }\n                    n++;\n                    total += v;\n                }\n            }\n        }\n        if (n) { ave = total / (double)n; }\n    }\n\n    // copy data to block and handle mask if there is one\n    //\n    for (size_t z = 0; z < zstop; z++) {\n        for (size_t y = 0; y < ystop; y++) {\n            for (size_t x = 0; x < xstop; x++) {\n                size_t index = nx * ny * z + nx * y + x;\n                double v;\n\n                if (mask && !mask[index]) {\n                    v = ave;\n                } else {\n                    v = data[index];\n                    if (v < min) min = (U)v;\n                    if (v > max) max = (U)v;\n                }\n\n                block[z * nbx * nby + y * nbx + x] = v;\n            }\n        }\n    }\n\n    if (xbdry) {\n        U *line_start;\n        for (size_t z = 0; z < nbz; z++) {\n            for (size_t y = 0; y < nby; y++) {\n                line_start = block + z * nby * nbx + y * nby;\n\n                pad_line(mode, line_start, xstop, nbx, 1);\n            }\n        }\n    }\n\n    if (ybdry) {\n        U *line_start;\n        for (size_t z = 0; z < nbz; z++) {\n            for (size_t x = 0; x < nbx; x++) {\n                line_start = block + z * nby * nbx + x;\n\n                pad_line(mode, line_start, ystop, nby, nbx);\n            }\n        }\n    }\n\n    if (zbdry) {\n        U *line_start;\n        for (size_t y = 0; y < nby; y++) {\n            for (size_t x = 0; x < nbx; x++) {\n                line_start = block + y * nbx + x;\n\n                pad_line(mode, line_start, zstop, nbz, nby * nbx);\n            }\n        }\n    }\n}\n\n// Copy a block of blocked data into a contiguous array (unblocking\n// the data). Handles 1D, 2D, and 3D arrays\n//\n// block : pointer to start of block where data should be copied from\n// bs : dimensions of block.\n// data : pointer to start of destination array\n// origin : coordinates of origin of data array\n// dims : dimensions of array\n// start: starting coordinates of block within array\n//\ntemplate<class T, class U> void UnBlock(U *block, vector<size_t> bs, T *data, vector<size_t> dims, vector<size_t> origin, vector<size_t> start)\n{\n    VAssert(dims.size() >= 1 && dims.size() <= 4);\n    VAssert(dims.size() == start.size());\n    VAssert(dims.size() == bs.size());\n    VAssert(dims.size() == origin.size());\n\n    // Deal with block dimensions of length 1\n    //\n    while (bs.size() && bs[0] == 1) {\n        bs.erase(bs.begin());\n        origin.erase(origin.begin());\n        dims.erase(dims.begin());\n        start.erase(start.begin());\n    }\n\n    int rank = bs.size();\n\n    // dimensions of volume\n    //\n    size_t nx = rank >= 1 ? dims[rank - 1] : 1;\n    size_t ny = rank >= 2 ? dims[rank - 2] : 1;\n    // size_t nz = rank >= 3 ? dims[rank-3] : 1;\n\n    // dimensions of block\n    //\n    size_t nbx = rank >= 1 ? bs[rank - 1] : 1;\n    size_t nby = rank >= 2 ? bs[rank - 2] : 1;\n    size_t nbz = rank >= 3 ? bs[rank - 3] : 1;\n\n    // starting coordinates within 'data'\n    //\n    size_t x0 = (rank >= 1 && start[rank - 1] > origin[rank - 1]) ? start[rank - 1] - origin[rank - 1] : 0;\n    size_t y0 = (rank >= 2 && start[rank - 2] > origin[rank - 2]) ? start[rank - 2] - origin[rank - 2] : 0;\n    size_t z0 = (rank >= 3 && start[rank - 3] > origin[rank - 3]) ? start[rank - 3] - origin[rank - 3] : 0;\n\n    // starting and stop coordinates within block, handling boundary cases\n    // for non-block-aligned regions\n    //\n    size_t xstart = 0;\n    size_t ystart = 0;\n    size_t zstart = 0;\n\n    if (rank >= 1 && (origin[rank - 1] > start[rank - 1]))    // non-aligned boundary\n        xstart = origin[rank - 1] - start[rank - 1];\n    if (rank >= 2 && (origin[rank - 2] > start[rank - 2]))    // non-aligned boundary\n        ystart = origin[rank - 2] - start[rank - 2];\n    if (rank >= 3 && (origin[rank - 3] > start[rank - 3]))    // non-aligned boundary\n        zstart = origin[rank - 3] - start[rank - 3];\n\n    size_t xstop = nbx;\n    size_t ystop = nby;\n    size_t zstop = nbz;\n\n    if (rank >= 1 && (start[rank - 1] + nbx) > (origin[rank - 1] + dims[rank - 1])) { xstop = origin[rank - 1] + dims[rank - 1] - start[rank - 1]; }\n    if (rank >= 2 && (start[rank - 2] + nby) > (origin[rank - 2] + dims[rank - 2])) { ystop = origin[rank - 2] + dims[rank - 2] - start[rank - 2]; }\n    if (rank >= 3 && (start[rank - 3] + nbz) > (origin[rank - 3] + dims[rank - 3])) { zstop = origin[rank - 3] + dims[rank - 3] - start[rank - 3]; }\n\n    for (size_t z = zstart, zz = 0; z < zstop; z++, zz++) {\n        for (size_t y = ystart, yy = 0; y < ystop; y++, yy++) {\n            for (size_t x = xstart, xx = 0; x < xstop; x++, xx++) { data[nx * ny * (z0 + zz) + nx * (y0 + yy) + (x0 + xx)] = block[z * nbx * nby + y * nbx + x]; }\n        }\n    }\n}\n\n// Apply forward wavelet transfor to a block of data\n//\n// cmp : Compressor for wavelet transform\n// block : block of data\n// n : number of elements in 'block'\n// coeffs : storage for transformed coefficients\n// maps : storage for encoded significance maps\n// ncoeffs : vector describing partitioning of coefficients in 'coeffs'\n// encoded_dims : vector describing dimension of encoded block at\n// each compression level.\n//\ntemplate<class T>\nint DecomposeBlock(Compressor *cmp, const T *block, size_t n, T *coeffs, unsigned char *maps, int xtype, vector<size_t> ncoeffs, vector<size_t> encoded_dims\n\n)\n{\n    vector<SignificanceMap> sigmaps(ncoeffs.size());\n\n    int rc = cmp->Decompose(block, coeffs, ncoeffs, sigmaps);\n    if (rc < 0) return (-1);\n\n    //\n    // Extract signficance maps from 'sigmaps' and copy them to 'maps'\n    //\n    unsigned char *mapptr = maps;\n    for (int i = 0; i < ncoeffs.size(); i++) {\n        size_t dimlen = i == 0 ? encoded_dims[i] - BLK_HDR_SZ : encoded_dims[i];\n\n        if (dimlen != ncoeffs[i]) {    // last map not stored\n            size_t sz = NetCDFCpp::SizeOf(xtype) * (dimlen - ncoeffs[i]);\n\n            memset(mapptr, 0, sz);\n            sigmaps[i].GetMap(mapptr);\n            mapptr += sz;\n        }\n    }\n\n    return (0);\n}\n\n// Apply inverse wavelet transfor to a block of data\n//\n// cmp : Compressor for wavelet transform\n// coeffs : storage for transformed coefficients\n// maps : storage for encoded significance maps\n// ncoeffs : vector describing partitioning of coefficients in 'coeffs'\n// encoded_dims : vector describing dimension of encoded block at\n// each compression level.\n// block : block of data\n// n : num elements in 'block'\n// level : reconstruction level in wavelet hierarchy\n//\ntemplate<class T>\nint ReconstructBlock(Compressor *cmp, const T *coeffs, const T *datarange, const unsigned char *maps, int xtype, vector<size_t> ncoeffs, vector<size_t> encoded_dims, T *block, size_t n, int level)\n{\n    // Clamp reconstructed values to original data range\n    //\n    cmp->ClampMinOnOff() = true;\n    cmp->ClampMaxOnOff() = true;\n    cmp->ClampMin() = (double)datarange[0];\n    cmp->ClampMax() = (double)datarange[1];\n\n    vector<SignificanceMap> sigmaps(ncoeffs.size());\n\n    //\n    // Extract encoded significance maps\n    //\n    const unsigned char *mapptr = maps;\n    bool                 reconstruct_map = false;\n    for (int i = 0; i < ncoeffs.size(); i++) {\n        size_t dimlen = i == 0 ? encoded_dims[i] - BLK_HDR_SZ : encoded_dims[i];\n\n        if (dimlen != ncoeffs[i]) {    // last map not stored\n            int rc = sigmaps[i].SetMap(mapptr);\n            if (rc < 0) return (-1);\n\n            size_t sz = NetCDFCpp::SizeOf(xtype) * (dimlen - ncoeffs[i]);\n            mapptr += sz;\n        } else {\n            reconstruct_map = true;\n        }\n    }\n\n    //\n    // In some cases the significance map need not be explicity stored,\n    // and can be reconstructed from previous sigmaps\n    //\n    if (reconstruct_map) {\n        sigmaps[ncoeffs.size() - 1].Clear();\n\n        // Edge case for when sigmap isn't stored at all\n        //\n        if (ncoeffs.size() == 1 && encoded_dims[0] - BLK_HDR_SZ == ncoeffs[0]) {\n            sigmaps[0].Reshape(ncoeffs[0]);\n            for (int i = 0; i < ncoeffs[0]; i++) { sigmaps[0].Set(i); }\n        } else {\n            for (int i = 0; i < ncoeffs.size() - 1; i++) { sigmaps[ncoeffs.size() - 1].Append(sigmaps[i]); }\n            sigmaps[ncoeffs.size() - 1].Sort();\n            sigmaps[ncoeffs.size() - 1].Invert();\n        }\n    }\n\n    int rc = cmp->Reconstruct(coeffs, block, sigmaps, level);\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\n// Write a single block (no compression) to disk\n//\n// varname : name of variable\n// ncdfcptr : NetCDFCpp file pointer\n// bcoords : coordinates of block in voxel coords relative to start of variable\n// bs : blocksize\n// block : data block\n//\ntemplate<class T>\nint StoreBlock(string varname, NetCDFCpp *ncdfcptr, vector<size_t> bcoords, size_t block_size, const T *block\n\n)\n{\n    vector<size_t> start = bcoords;\n    start.push_back(0);\n\n    vector<size_t> count(start.size(), 1);\n    count[count.size() - 1] = block_size;\n\n    int rc = ncdfcptr->NetCDFCpp::PutVara(varname, start, count, block);\n    if (rc < 0) return (rc);\n\n    return (0);\n}\n\n// Write a single transformed & compressed block to disk\n//\n// varname : name of variable\n// ncdfcptrs : NetCDFCpp file points, one for each compression level\n// bcoords : coordinates of block in voxel coords relative to start of variable\n// ncoeffs : vector describing partitioning of coefficients in 'coeffs'\n// encoded_dims : vector describing dimension of encoded block at\n// each compression level.\n// coeffs : transformed coefficients for each compression level\n// maps : encoded significance maps for each compression level\n//\ntemplate<class T>\nint StoreBlockCompressed(string varname, vector<NetCDFCpp *> ncdfcptrs, vector<size_t> bcoords, vector<size_t> ncoeffs, vector<size_t> encoded_dims, const T *coeffs, const T *datarange,\n                         unsigned char *maps, int xtype\n\n)\n{\n    unsigned long LSBTest = 1;\n    bool          do_swapbytes = false;\n    if (!(*(char *)&LSBTest)) {\n        // swap to MSBFirst\n        do_swapbytes = true;\n    }\n\n    vector<size_t> start = bcoords;\n    start.push_back(0);\n\n    vector<size_t> count;\n    count.resize(start.size(), 1);\n\n    // First write the min and max data value in the header\n    // of the base file\n    //\n    start[start.size() - 1] = 0;\n    count[start.size() - 1] = BLK_HDR_SZ;\n    int rc = ncdfcptrs[0]->NetCDFCpp::PutVara(varname, start, count, datarange);\n    if (rc < 0) return (rc);\n\n    //\n    // Current code assumes each wavelet decomposition is stored in a\n    // different file\n    //\n    VAssert(ncdfcptrs.size() >= ncoeffs.size());\n    for (int i = 0; i < ncoeffs.size(); i++) {\n        start[start.size() - 1] = i == 0 ? BLK_HDR_SZ : 0;    // skip header\n        count[start.size() - 1] = ncoeffs[i];\n\n        int rc = ncdfcptrs[i]->NetCDFCpp::PutVara(varname, start, count, coeffs);\n        if (rc < 0) return (rc);\n\n        coeffs += ncoeffs[i];\n\n        // Sigmap size (in words) is difference between encoded_dims and\n        // number of coefficients\n        //\n        VAssert(encoded_dims[i] >= ncoeffs[i]);\n        size_t n = encoded_dims[i] - ncoeffs[i];\n\n        if (i == 0) n -= BLK_HDR_SZ;    // adjust for header\n\n        //\n        // If sigmap size is zero don't write it!\n        //\n        if (n != 0) {\n            // Using untyped flavor of PutVara, which doesn't do data\n            // conversion, so start & count arguments are in sizes of\n            // external variable type\n            //\n            start[start.size() - 1] = i == 0 ? ncoeffs[i] + BLK_HDR_SZ : ncoeffs[i];\n            count[start.size() - 1] = n;\n\n            //\n            // Should be checking size of external type for var\n            //\n            if (do_swapbytes) { swapbytes((void *)maps, NetCDFCpp::SizeOf(xtype), n); }\n\n            // Signficance map is concatenated to the wavelet coefficients\n            // variable to improve IO performance\n            //\n            int rc = ncdfcptrs[i]->NetCDFCpp::PutVara(varname, start, count, (const void *)maps);\n            if (rc < 0) return (rc);\n\n            maps += n * NetCDFCpp::SizeOf(xtype);\n        }\n    }\n    return (0);\n}\n\n// Read a single block (no compression) from disk\n//\n// varname : name of variable\n// ncdfcptrs : NetCDFCpp file pointer\n// bcoords : coordinates of block\n// bs : block size\n// block : data block\n//\ntemplate<class T> int FetchBlock(string varname, NetCDFCpp *ncdfcptr, vector<size_t> bcoords, size_t block_size, T *block)\n{\n    vector<size_t> start = bcoords;\n    start.push_back(0);\n\n    vector<size_t> count(start.size(), 1);\n    count[count.size() - 1] = block_size;\n\n    int rc = ncdfcptr->NetCDFCpp::GetVara(varname, start, count, (T *)block);\n    if (rc < 0) return (rc);\n\n    return (0);\n}\n\n// Read a single transformed & compressed block from disk\n//\n// varname : name of variable\n// ncdfcptrs : NetCDFCpp file points, one for each compression level\n// bcoords : coordinates of block\n// ncoeffs : vector describing partitioning of coefficients in 'coeffs'\n// encoded_dims : vector describing dimension of encoded block at\n// each compression level.\n// coeffs : transformed coefficients for each compression level\n// maps : encoded significance maps for each compression level\n//\ntemplate<class T>\nint FetchBlockCompressed(string varname, vector<NetCDFCpp *> ncdfcptrs, vector<size_t> bcoords, vector<size_t> ncoeffs, vector<size_t> encoded_dims, T *coeffs, T *datarange, unsigned char *maps,\n                         int xtype\n\n)\n{\n    unsigned long LSBTest = 1;\n    bool          do_swapbytes = false;\n    if (!(*(char *)&LSBTest)) {\n        // swap to MSBFirst\n        do_swapbytes = true;\n    }\n\n    vector<size_t> start = bcoords;\n    start.push_back(0);\n\n    vector<size_t> count;\n    count.resize(start.size(), 1);\n\n    // Read header (first two elements contain data range)\n    //\n    start[start.size() - 1] = 0;\n    count[start.size() - 1] = BLK_HDR_SZ;\n    int rc = ncdfcptrs[0]->NetCDFCpp::GetVara(varname, start, count, datarange);\n    if (rc < 0) return (rc);\n\n    //\n    // Current code assumes each wavelet decomposition is stored in a\n    // different file\n    //\n    VAssert(ncdfcptrs.size() >= ncoeffs.size());\n    for (int i = 0; i < ncoeffs.size(); i++) {\n        start[start.size() - 1] = i == 0 ? BLK_HDR_SZ : 0;    // skip header\n        count[start.size() - 1] = ncoeffs[i];\n\n        int rc = ncdfcptrs[i]->NetCDFCpp::GetVara(varname, start, count, coeffs);\n        if (rc < 0) return (rc);\n\n        coeffs += ncoeffs[i];\n\n        // Sigmap size (in words) is difference between encoded_dims and\n        // number of coefficients\n        //\n        VAssert(encoded_dims[i] >= ncoeffs[i]);\n        size_t n = encoded_dims[i] - ncoeffs[i];\n        if (i == 0) n -= BLK_HDR_SZ;\n\n        //\n        // If sigmap size is zero don't read it!\n        //\n        if (n != 0) {\n            start[start.size() - 1] = i == 0 ? ncoeffs[i] + BLK_HDR_SZ : ncoeffs[i];\n            count[start.size() - 1] = n;\n\n            // Signficance map is concatenated to the wavelet coefficients\n            // variable to improve IO performance\n            //\n            int rc = ncdfcptrs[i]->NetCDFCpp::GetVara(varname, start, count, (void *)maps);\n            if (rc < 0) return (rc);\n\n            //\n            // Should be checking size of external type for var\n            //\n            if (do_swapbytes) { swapbytes((void *)maps, NetCDFCpp::SizeOf(xtype), n); }\n\n            maps += n * NetCDFCpp::SizeOf(xtype);\n        }\n    }\n    return (0);\n}\n\ntemplate<class T> void *RunWriteThreadTemplate(thread_state &s, T dummy)\n{\n    vectorinc vec(s._start, s._count, s._udims, s._bs);\n\n    s._status = 0;\n\n    //\n    // Process blocks of data assigned to this thread\n    //\n    int n = vec.num();\n    for (int i = s._id; i < n; i += s._nthreads) {\n        // Get starting coordinates of i'th block\n        //\n        size_t         offset;\n        vector<size_t> start;\n        vec.ith(i, start, offset);\n\n        // Transform coordinates from global to the region-of-interest\n        //\n        vector<size_t> roi_start = vector_sub(start, s._start);\n\n        //\n        // Extract the block with coordinates 'start' from the\n        // array, 'data'.\n        //\n        T min, max;\n        Block((T *)s._data, NULL, s._count, roi_start, (T *)s._block, s._bs, \"symh\", min, max);\n\n        // Convert from voxel to block coordinates\n        //\n        vector<size_t> bcoords;\n        size_t         residual;\n        to_block_coords(start, s._bs, bcoords, residual);\n        VAssert(residual == 0);\n\n        // Write the transformed block to disk. Need a mutex because\n        // NetCDF library is not thread safe\n        //\n        //\n        s._et->MutexLock();\n        int rc = StoreBlock(s._varname, s._ncdfcptrs[0], bcoords, s._encoded_dims[0], (T *)s._block);\n        if (rc < 0) { s._status = -1; }\n        s._et->MutexUnlock();\n        if (s._status < 0) break;\n    }\n    return (0);\n}\n\nvoid *RunWriteThread(void *arg)\n{\n    thread_state &s = *(thread_state *)arg;\n\n    switch (s._data_type) {\n    case NC_FLOAT: {\n        float dummy = 0.0;\n        return (RunWriteThreadTemplate(s, dummy));\n    }\n    case NC_DOUBLE: {\n        double dummy = 0.0;\n        return (RunWriteThreadTemplate(s, dummy));\n    }\n    case NC_INT: {\n        int dummy = 0.0;\n        return (RunWriteThreadTemplate(s, dummy));\n    }\n    case NC_SHORT: {\n        int16_t dummy = 0.0;\n        return (RunWriteThreadTemplate(s, dummy));\n    }\n    default: VAssert(0); return (NULL);\n    }\n}\n\n// Thread execution help function for data writes\n//\n\ntemplate<class T, class U> void *RunWriteThreadCompressedTemplate(thread_state &s, T dummy1, U dummy2)\n{\n    vectorinc vec(s._start, s._count, s._udims, s._bs);\n\n    s._status = 0;\n\n    //\n    // Process blocks of data assigned to this thread\n    //\n    int n = vec.num();\n    for (int i = s._id; i < n; i += s._nthreads) {\n        // Get starting coordinates of i'th block\n        //\n        size_t         offset;\n        vector<size_t> start;\n        vec.ith(i, start, offset);\n\n        // Transform coordinates from global to the region-of-interest\n        //\n        vector<size_t> roi_start = vector_sub(start, s._start);\n\n        //\n        // Extract the block with coordinates 'start' from the\n        // array, 'data'.\n        //\n        U datarange[2];\n        Block((T *)s._data, s._mask, s._count, roi_start, (U *)s._block, s._bs, s._compressors[s._id]->dwtmode(), datarange[0], datarange[1]);\n\n        //\n        // Wavelet transform the current block\n        //\n        int rc = DecomposeBlock(s._compressors[s._id], (const U *)s._block, vproduct(s._bs), (U *)s._coeffs, s._maps, s._xtype, s._ncoeffs, s._encoded_dims);\n        if (rc < 0) {\n            s._status = -1;\n            break;\n        }\n\n        // Convert from voxel to block coordinates\n        //\n        vector<size_t> bcoords;\n        size_t         residual;\n        to_block_coords(start, s._bs, bcoords, residual);\n        VAssert(residual == 0);\n\n        // Write the transformed block to disk. Need a mutex because\n        // NetCDF library is not thread safe\n        //\n        //\n        s._et->MutexLock();\n        rc = StoreBlockCompressed(s._varname, s._ncdfcptrs, bcoords, s._ncoeffs, s._encoded_dims, (U *)s._coeffs, datarange, s._maps, s._xtype);\n        if (rc < 0) { s._status = -1; }\n        s._et->MutexUnlock();\n        if (s._status < 0) break;\n    }\n    return (0);\n}\n\nvoid *RunWriteThreadCompressed(void *arg)\n{\n    thread_state &s = *(thread_state *)arg;\n\n    VAssert(s._block_type == NC_INT64 || s._block_type == NC_DOUBLE);\n\n    // Establish types for template functions. Data types aren't preserved\n    // when passed in thread_state, which must be cast to void to support\n    // pthread API :-(\n    //\n    switch (s._data_type) {\n    case NC_FLOAT: {\n        float dummy1 = 0.0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    } break;\n    case NC_DOUBLE: {\n        double dummy1 = 0.0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    } break;\n    case NC_INT:\n    case NC_UINT: {\n        int dummy1 = 0.0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    } break;\n    case NC_SHORT:\n    case NC_USHORT: {\n        int16_t dummy1 = 0.0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    }\n    case NC_BYTE:\n    case NC_UBYTE: {\n        int8_t dummy1 = 0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunWriteThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    } break;\n    default:\n        cerr << \"Data type \" << s._data_type << endl;\n        VAssert(0 && s._data_type);\n        return (NULL);\n    }\n}\n\n// Thread execution helper function for data writes\n//\ntemplate<class T> void *RunReadThreadTemplate(thread_state &s, T dummy)\n{\n    bool unblock_flag = s._unblock_flag;    // Need to unblock data?\n    T *  data = (T *)s._data;\n\n    // Align start and count coordinates to block boundaries\n    //\n    vector<size_t> aligned_start;\n    vector<size_t> aligned_count;\n    block_align(s._start, s._count, s._bs, aligned_start, aligned_count);\n\n    vectorinc vec(aligned_start, aligned_count, s._udims, s._bs);\n\n    s._status = 0;\n\n    int n = vec.num();\n    for (int i = s._id; i < n; i += s._nthreads) {\n        size_t         offset;\n        vector<size_t> start;\n\n        vec.ith(i, start, offset);\n\n        vector<size_t> bcoords;\n        size_t         residual;\n        to_block_coords(start, s._bs, bcoords, residual);\n        VAssert(residual == 0);\n\n        // Transform coordinates from global to the region-of-interest\n        //\n        vector<size_t> roi_start = vector_sub(start, aligned_start);\n        vector<size_t> roi_origin = vector_sub(s._start, aligned_start);\n\n        T *blockptr = (T *)s._block;\n\n        // Read wavelet coefficients from disk. Need a mutex because\n        // NetCDF API is not thread safe\n        //\n        s._et->MutexLock();\n        int rc = FetchBlock(s._varname, s._ncdfcptrs[0], bcoords, s._encoded_dims[0], blockptr);\n        if (rc < 0) s._status = -1;\n        s._et->MutexUnlock();\n        if (s._status < 0) break;\n\n        if (unblock_flag) {\n            // Unblock the current block into the destination array\n            //\n            UnBlock(blockptr, s._bs, data, s._count, roi_origin, roi_start);\n        } else {\n            // Don't unblock. Just copy\n            //\n            size_t offset = vproduct(s._bs) * i;\n            for (size_t j = 0; j < vproduct(s._bs); j++) { data[offset + j] = blockptr[j]; }\n        }\n    }\n    return (NULL);\n}\n\nvoid *RunReadThread(void *arg)\n{\n    thread_state &s = *(thread_state *)arg;\n\n    switch (s._data_type) {\n    case NC_FLOAT: {\n        float dummy = 0.0;\n        return (RunReadThreadTemplate(s, dummy));\n    }\n    case NC_DOUBLE: {\n        double dummy = 0.0;\n        return (RunReadThreadTemplate(s, dummy));\n    }\n    case NC_INT: {\n        int dummy = 0.0;\n        return (RunReadThreadTemplate(s, dummy));\n    }\n    case NC_SHORT: {\n        int16_t dummy = 0.0;\n        return (RunReadThreadTemplate(s, dummy));\n    }\n    default: VAssert(0); return (NULL);\n    }\n}\n\n// Thread execution helper function for data writes\n//\n\ntemplate<class T, class U> void *RunReadThreadCompressedTemplate(thread_state &s, T dummy1, U dummy2)\n{\n    bool unblock_flag = s._unblock_flag;    // Need to unblock data?\n    T *  data = (T *)s._data;\n\n    // Align start and count coordinates to block boundaries\n    //\n    vector<size_t> aligned_start;\n    vector<size_t> aligned_count;\n    block_align(s._start, s._count, s._bs, aligned_start, aligned_count);\n\n    vectorinc vec(aligned_start, aligned_count, s._udims, s._bs);\n\n    s._status = 0;\n\n    int n = vec.num();\n    for (int i = s._id; i < n; i += s._nthreads) {\n        size_t         offset;\n        vector<size_t> start;\n\n        vec.ith(i, start, offset);\n\n        vector<size_t> bcoords;\n        size_t         residual;\n        to_block_coords(start, s._bs, bcoords, residual);\n        VAssert(residual == 0);\n\n        // Read wavelet coefficients from disk. Need a mutex because\n        // NetCDF API is not thread safe\n        //\n        U datarange[2];\n        s._et->MutexLock();\n        int rc = FetchBlockCompressed(s._varname, s._ncdfcptrs, bcoords, s._ncoeffs, s._encoded_dims, (U *)s._coeffs, datarange, s._maps, s._xtype);\n        if (rc < 0) s._status = -1;\n        s._et->MutexUnlock();\n        if (s._status < 0) break;\n\n        // Transform coordinates from global to the region-of-interest\n        //\n        vector<size_t> roi_start = vector_sub(start, aligned_start);\n        vector<size_t> roi_origin = vector_sub(s._start, aligned_start);\n\n        U *blockptr = (U *)s._block;\n\n        // Transform from wavelet to physical space\n        //\n        rc = ReconstructBlock(s._compressors[s._id], (U *)s._coeffs, datarange, s._maps, s._xtype, s._ncoeffs, s._encoded_dims, blockptr, vproduct(s._bs), s._level);\n        if (rc < 0) {\n            s._status = -1;\n            break;\n        }\n\n        if (unblock_flag) {\n            // Unblock the current block into the destination array\n            //\n            UnBlock(blockptr, s._bs, data, s._count, roi_origin, roi_start);\n        } else {\n            // Don't unblock. Just copy.\n            //\n            size_t offset = vproduct(s._bs) * i;\n            for (size_t j = 0; j < vproduct(s._bs); j++) { data[offset + j] = (T)blockptr[j]; }\n        }\n    }\n    return (NULL);\n}\n\nvoid *RunReadThreadCompressed(void *arg)\n{\n    thread_state &s = *(thread_state *)arg;\n\n    VAssert(s._block_type == NC_INT64 || s._block_type == NC_DOUBLE);\n\n    // Establish types for template functions. Data types aren't preserved\n    // when passed in thread_state, which must be cast to void to support\n    // pthread API :-(\n    //\n    switch (s._data_type) {\n    case NC_FLOAT: {\n        float dummy1 = 0.0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    }\n    case NC_DOUBLE: {\n        double dummy1 = 0.0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    }\n    case NC_INT: {\n        int dummy1 = 0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    }\n    case NC_SHORT: {\n        int16_t dummy1 = 0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    }\n    case NC_BYTE:\n    case NC_UBYTE: {\n        int8_t dummy1 = 0;\n        if (s._block_type == NC_INT64) {\n            long dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        } else {\n            double dummy2 = 0;\n            return (RunReadThreadCompressedTemplate(s, dummy1, dummy2));\n        }\n    }\n    default: VAssert(0); return (NULL);\n    }\n}\n\n};    // namespace\n\nWASP::WASP(int nthreads)\n{\n    _ncdfcs.clear();\n    _ncdfcptrs.clear();\n\n    _waspFile = false;\n    _nthreads = 1;\n    _currentVersion = 3;\n    _fileVersion = 0;\n\n    _open = false;\n    _open_wname.clear();\n    _open_bs.clear();\n    _open_cratios.clear();\n    _open_udims.clear();\n    _open_dims.clear();\n    _open_lod = 0;\n    _open_level = 0;\n    _open_write = false;\n    _open_varname.clear();\n\n    _et = NULL;\n\n    // Set up execution threads for parallel execution\n    //\n    if (nthreads < 1) nthreads = EasyThreads::NProc();\n    if (nthreads < 1) nthreads = 1;\n\n    _et = new EasyThreads(nthreads);\n\n    _nthreads = _et->GetNumThreads() > 0 ? _et->GetNumThreads() : 1;\n\n    // One Compressor instance for each thread\n    //\n    _open_compressors.resize(nthreads, NULL);\n}\n\nWASP::~WASP()\n{\n    for (int i = 0; i < _open_compressors.size(); i++) {\n        if (_open_compressors[i]) delete _open_compressors[i];\n    }\n    if (_et) delete _et;\n}\n\nint WASP::Create(string path, int cmode, size_t initialsz, size_t &bufrsizehintp, int numfiles)\n{\n    int rc = WASP::Close();\n    if (rc < 0) return (rc);\n\n    numfiles = numfiles > 0 ? numfiles : 1;\n\n    _ncdfcs.clear();\n    _ncdfcptrs.clear();\n    _ncdfcptrs.push_back(this);\n\n    vector<string> paths;\n    if (numfiles > 1) {\n        paths = mkmultipaths(path, numfiles);\n    } else {\n        paths.push_back(path);\n    }\n\n    rc = NetCDFCpp::Create(paths[0], cmode, initialsz, bufrsizehintp);\n    if (rc < 0) return (rc);\n\n    for (int i = 1; i < paths.size(); i++) {\n        NetCDFCpp netcdfcpp;\n\n        rc = netcdfcpp.Create(paths[i], cmode, initialsz, bufrsizehintp);\n        if (rc < 0) return (rc);\n        _ncdfcs.push_back(netcdfcpp);\n    }\n\n    for (int i = 0; i < _ncdfcs.size(); i++) { _ncdfcptrs.push_back(&(_ncdfcs[i])); }\n\n    _numfiles = numfiles;\n\n    // Attributes describing the compressed data\n    //\n    rc = PutAtt(\"\", AttNameWASP(), 1);\n    if (rc < 0) return (rc);\n\n    _waspFile = true;\n\n    rc = PutAtt(\"\", AttNameNumFiles(), numfiles);\n    if (rc < 0) return (rc);\n\n    rc = PutAtt(\"\", AttNameVersion(), _currentVersion);\n    if (rc < 0) return (rc);\n    _fileVersion = _currentVersion;\n\n    return (NC_NOERR);\n}\n\nint WASP::Open(string path, int mode)\n{\n    int rc = WASP::Close();\n    if (rc < 0) return (rc);\n\n    _ncdfcs.clear();\n    _ncdfcptrs.clear();\n    _ncdfcptrs.push_back(this);\n\n    _waspFile = false;\n\n    rc = NetCDFCpp::Open(path.c_str(), mode);\n    if (rc < 0) return (rc);\n\n    // Verify that this is a WASP file\n    //\n    int dummy;\n    rc = GetAtt(\"\", AttNameWASP(), dummy);\n    if (rc < 0) {\n        SetErrMsg(\"Not a WASP file\");\n        NetCDFCpp::Close();\n        return (-1);\n    }\n\n    int    numfiles = 1;\n    string wname;\n\n    rc = GetAtt(\"\", AttNameNumFiles(), numfiles);\n    if (rc < 0) return (rc);\n    _numfiles = numfiles;\n\n    int fileVersion = 0;\n    rc = GetAtt(\"\", AttNameVersion(), fileVersion);\n    if (rc < 0) return (rc);\n    _fileVersion = fileVersion;\n\n    vector<string> paths;\n    if (numfiles > 1) { paths = mkmultipaths(path, numfiles); }\n\n    for (int i = 1; i < paths.size(); i++) {\n        NetCDFCpp netcdfcpp;\n\n        // Not required that all LODs exist if open read-only\n        //\n        struct stat statbuf;\n        if (mode == NC_NOWRITE && stat(paths[i].c_str(), &statbuf) < 0) break;\n\n        rc = netcdfcpp.Open(paths[i], mode);\n        if (rc < 0) return (rc);\n\n        _ncdfcs.push_back(netcdfcpp);\n    }\n\n    for (int i = 0; i < _ncdfcs.size(); i++) { _ncdfcptrs.push_back(&(_ncdfcs[i])); }\n\n    _waspFile = true;\n    return (NC_NOERR);\n}\n\nint WASP::SetFill(int fillmode, int &old_modep)\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    // Set old_modep only for first file\n    //\n    int rc = NetCDFCpp::SetFill(fillmode, old_modep);\n    if (rc < 0) return (rc);\n\n    for (int i = 1; i < _ncdfcptrs.size(); i++) {\n        int my_old_modep;\n\n        rc = _ncdfcptrs[i]->NetCDFCpp::SetFill(fillmode, my_old_modep);\n        if (rc < 0) return (rc);\n    }\n    return (NC_NOERR);\n}\n\nint WASP::EndDef() const\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    for (int i = 0; i < _ncdfcptrs.size(); i++) {\n        int rc = _ncdfcptrs[i]->NetCDFCpp::EndDef();\n        if (rc < 0) return (rc);\n    }\n    return (NC_NOERR);\n}\n\nint WASP::Close()\n{\n    int rc = 0;\n    for (int i = 0; i < _ncdfcptrs.size(); i++) {\n        int my_rc = _ncdfcptrs[i]->NetCDFCpp::Close();\n        if (my_rc < 0) rc = -1;\n    }\n    _ncdfcptrs.clear();\n\n    _waspFile = false;\n\n    return (rc);\n}\n\nint WASP::DefDim(string name, size_t len) const\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    //\n    // Dimensions get defined identically in every file\n    //\n    for (int i = 0; i < _ncdfcptrs.size(); i++) {\n        int rc = _ncdfcptrs[i]->NetCDFCpp::DefDim(name, len);\n        if (rc < 0) return (rc);\n    }\n    return (NC_NOERR);\n}\n\nint WASP::DefVar(string name, int xtype, vector<string> dimnames, string wname, vector<size_t> bs, vector<size_t> cratios)\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    if (bs.size() == 0 || vproduct(bs) == 1) { return (NetCDFCpp::DefVar(name, xtype, dimnames)); }\n\n    // Wavelet coefficients together with the signficance map\n    // are encoded together and ultimately written with the generic\n    // nc_put_var(), which assumes that the data type passed to nc_put_var()\n    // matches that of the external storage type.\n    // Supporting external storage types besides NC_FLOAT will\n    // require changes to the packaging of the wavelet coefficients.\n    //\n    //\tif (! (xtype == NC_FLOAT || xtype == NC_DOUBLE)) {\n    //\tif (! (xtype == NC_FLOAT)) {\n    //\t\tSetErrMsg(\"Unsupported xtype specification\");\n    //\t\treturn(-1);\n    //\t}\n\n    if (!cratios.size()) cratios.push_back(1);\n\n    // No transform => no compression vector\n    //\n    if (wname.empty()) {\n        cratios.clear();\n        cratios.push_back(1);\n    }\n\n    //\n    // Look up dimlens associated with dimnames\n    //\n    vector<size_t> dims;\n    for (int i = 0; i < dimnames.size(); i++) {\n        size_t dimlen;\n        int    rc = NetCDFCpp::InqDimlen(dimnames[i], dimlen);\n        if (rc < 0) return (rc);\n        dims.push_back(dimlen);\n    }\n\n    while (bs.size() > dims.size()) { bs.pop_back(); }\n    while (bs.size() < dims.size()) { bs.insert(bs.begin(), 1); }\n\n    if (!_validate_compression_params(wname, dims, bs, cratios)) {\n        SetErrMsg(\"Invalid compression specification\");\n        return (-1);\n    }\n\n    sort(cratios.begin(), cratios.end());\n    reverse(cratios.begin(), cratios.end());\n\n    // Get dimensions for compressed, or simply blocked, version of\n    // variable. Compressed\n    // variables are decomposed into blocks. The dimension of the compressed\n    // variable in blocks is given by cdimnames and cdims. The dimension\n    // of the blocks themselves varies with compression level and is given\n    // by encoded_dim_names and encoded_dims\n    //\n    // Blocked variables are simply decomposed into blocks, but do not\n    // undergo compression\n    //\n    vector<string> encoded_dim_names;\n    vector<size_t> encoded_dims;\n    vector<string> cdimnames;\n    vector<size_t> cdims;\n\n    int rc;\n    rc = _GetCompressedDims(dimnames, wname, bs, cratios, xtype, cdimnames, cdims, encoded_dim_names, encoded_dims);\n    if (rc < 0) return (rc);\n\n    // Implicitly define dimensions for compressed variable. One set of\n    // dimensions for each compression level. Finally, define\n    // compressed variable itself.\n    //\n    for (int j = 0; j < cdimnames.size(); j++) {\n        size_t len;\n\n        rc = _InqDimlen(cdimnames[j], len);\n        if (len == 0) {\n            rc = WASP::DefDim(cdimnames[j], cdims[j]);\n            if (rc < 0) return (rc);\n        } else if (len != cdims[j]) {\n            SetErrMsg(\"Can't implicitly redefine compression dimensions\");\n            return (-1);\n        }\n    }\n\n    for (int i = 0; i < encoded_dim_names.size(); i++) {\n        size_t len;\n        rc = _InqDimlen(encoded_dim_names[i], len);\n        if (len == 0) {\n            rc = WASP::DefDim(encoded_dim_names[i], encoded_dims[i]);\n            if (rc < 0) return (rc);\n        } else if (len != encoded_dims[i]) {\n            SetErrMsg(\"Can't implicitly redefine compression dimensions\");\n            return (-1);\n        }\n    }\n\n    // Now define the variable, one in each file\n    //\n    for (int i = 0; i < encoded_dim_names.size(); i++) {\n        vector<string> newdimnames;\n        newdimnames = cdimnames;\n        newdimnames.push_back(encoded_dim_names[i]);\n\n        rc = _ncdfcptrs[i]->NetCDFCpp::DefVar(name, xtype, newdimnames);\n        if (rc < 0) return (rc);\n    }\n\n    // Attributes needed to encode or decode the variable later\n    //\n\n    rc = PutAtt(name, AttNameWASP(), 1);\n    if (rc < 0) return (rc);\n\n    rc = PutAtt(name, AttNameDimNames(), dimnames);\n    if (rc < 0) return (rc);\n\n    rc = PutAtt(name, AttNameCRatios(), cratios);\n    if (rc < 0) return (rc);\n\n    rc = PutAtt(name, AttNameWavelet(), wname);\n    if (rc < 0) return (rc);\n\n    rc = PutAtt(name, AttNameBlockSize(), bs);\n    if (rc < 0) return (rc);\n\n    return (NC_NOERR);\n}\n\nint WASP::DefVar(string name, int xtype, vector<string> dimnames, string wname, vector<size_t> bs, vector<size_t> cratios, double missing_value)\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n    if (bs.size() == 0 || vproduct(bs) == 1) { return (NetCDFCpp::DefVar(name, xtype, dimnames)); }\n\n    int rc = WASP::DefVar(name, xtype, dimnames, wname, bs, cratios);\n    if (rc < 0) return (rc);\n\n    rc = PutAtt(name, AttNameMissingValue(), missing_value);\n    if (rc < 0) return (rc);\n\n    return (NC_NOERR);\n}\n\nint WASP::InqVarDims(string name, vector<string> &dimnames, vector<size_t> &dims) const\n{\n    dimnames.clear();\n    dims.clear();\n\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    bool waspvar;\n    int  rc = InqVarWASP(name, waspvar);\n    if (rc < 0) return (rc);\n\n    if (!waspvar) { return (NetCDFCpp::InqVarDims(name, dimnames, dims)); }\n\n    rc = GetAtt(name, AttNameDimNames(), dimnames);\n    if (rc < 0) return (rc);\n    for (int i = 0; i < dimnames.size(); i++) {\n        size_t len;\n\n        rc = NetCDFCpp::InqDimlen(dimnames[i], len);\n        if (rc < 0) return (rc);\n        dims.push_back(len);\n    }\n    return (NC_NOERR);\n}\n\nint WASP::InqVarCompressionParams(string name, string &wname, vector<size_t> &bs, vector<size_t> &cratios) const\n{\n    wname.clear();\n    bs.clear();\n    cratios.clear();\n\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    bool waspvar;\n    int  rc = InqVarWASP(name, waspvar);\n    if (rc < 0) return (rc);\n\n    if (!waspvar) return (0);\n\n    rc = GetAtt(name, AttNameBlockSize(), bs);\n    if (rc < 0) return (rc);\n\n    rc = GetAtt(name, AttNameCRatios(), cratios);\n    if (rc < 0) return (rc);\n\n    rc = GetAtt(name, AttNameWavelet(), wname);\n    if (rc < 0) return (rc);\n\n    return (0);\n}\n\nint WASP::InqVarDimlens(string name, int level, vector<size_t> &dims_at_level, vector<size_t> &bs_at_level) const\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    vector<string> dimnames;\n    vector<size_t> dims;\n    int            rc = WASP::InqVarDims(name, dimnames, dims);\n    if (rc < 0) return (rc);\n\n    vector<size_t> bs;\n    vector<size_t> cratios;\n    string         wname;\n    rc = WASP::InqVarCompressionParams(name, wname, bs, cratios);\n    if (rc < 0) return (rc);\n\n    _dims_at_level(dims, bs, level, wname, dims_at_level, bs_at_level);\n\n    return (0);\n}\n\nint WASP::InqDimsAtLevel(string wname, int level, vector<size_t> dims, vector<size_t> bs, vector<size_t> &dims_at_level, vector<size_t> &bs_at_level)\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    _dims_at_level(dims, bs, level, wname, dims_at_level, bs_at_level);\n\n    return (0);\n}\n\nbool WASP::InqCompressionInfo(vector<size_t> bs, string wname, size_t &nlevels, size_t &maxcratio) { return (Compressor::CompressionInfo(compressor_bs(bs), wname, true, nlevels, maxcratio)); }\n\nint WASP::InqVarNumRefLevels(string name) const\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    bool waspvar;\n    int  rc = InqVarWASP(name, waspvar);\n    if (rc < 0) return (rc);\n\n    if (!waspvar) return (1);\n\n    vector<size_t> bs;\n    vector<size_t> cratios;\n    vector<size_t> udims;\n    vector<size_t> dims;\n    string         wname;\n\n    rc = _get_compression_params(name, bs, cratios, udims, dims, wname);\n    if (rc < 0) return (rc);\n\n    if (cratios.size() == 0) return (1);    // no compression\n\n    size_t nlevels, maxcratio;\n    (void)WASP::InqCompressionInfo(bs, wname, nlevels, maxcratio);\n\n    return (nlevels);\n}\n\n// static method to compute grid dimensions at a specified refinement level\n//\n// dims : dimensions of native (original) grid\n// bs : dimensions of native storage brick.\n// level : hierarchy level\n// wname : name of wavelet used in wavelet transform\n// dims_at_level : grid dimensions at given refinement level\n// bs_at_level : block dimensions dimensions at given refinement level\n//\nvoid WASP::_dims_at_level(vector<size_t> dims, vector<size_t> bs, int level, string wname, vector<size_t> &dims_at_level, vector<size_t> &bs_at_level)\n{\n    dims_at_level.clear();\n    bs_at_level.clear();\n\n    if (wname.empty()) {\n        dims_at_level = dims;\n        bs_at_level = bs;\n        return;\n    }\n\n    Compressor cmp(compressor_bs(bs), wname);\n\n    if (level < 0) level = cmp.GetNumLevels();\n    if (level > cmp.GetNumLevels()) level = cmp.GetNumLevels();\n\n    cmp.GetDimension(bs_at_level, level);\n    reverse(bs_at_level.begin(), bs_at_level.end());\n    while (bs_at_level.size() != dims.size()) { bs_at_level.insert(bs_at_level.begin(), 1); }\n    VAssert(dims.size() == bs_at_level.size());\n\n    dims_at_level = dims;\n    int ldelta = cmp.GetNumLevels() - level;\n\n    for (int i = 0; i < bs.size(); i++) {\n        size_t nblocks = dims[i] / bs[i];\n        size_t residual = dims[i] - (nblocks * bs[i]);\n\n        residual = residual >> ldelta;\n\n        size_t d = nblocks * bs_at_level[i] + residual;\n        if (d < 1) d = 1;\n        dims_at_level[i] = d;\n    }\n}\n\n// Same as NetCDFCpp::InqDimlen(), but returns 0 and sets len to 0\n// if dimension 'name' does not exist\n//\nint WASP::_InqDimlen(string name, size_t &len) const\n{\n    len = 0;\n\n    // disable error reporting\n    //\n    bool enabled = MyBase::EnableErrMsg(false);\n\n    int rc = WASP::InqDimlen(name, len);\n    if (rc == NC_EBADDIM) {\n        WASP::SetErrCode(0);\n        rc = 0;\n    }\n\n    (void)MyBase::EnableErrMsg(enabled);\n\n    return (rc);\n}\n\nint WASP::InqVarWASP(string varname, bool &wasp) const\n{\n    wasp = false;\n\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    int varid;\n    int rc = NetCDFCpp::InqVarid(varname, varid);\n    if (rc < 0) return (rc);\n\n    // disable error reporting otherwise an error is generated\n    // if the attribute doesn't exist\n    //\n    bool enabled = MyBase::EnableErrMsg(false);\n\n    int    xtype;\n    size_t len;\n    rc = NetCDFCpp::InqAtt(varname, AttNameWASP(), xtype, len);\n\n    (void)MyBase::EnableErrMsg(enabled);\n\n    // Assume att doesn't exist if InqAtt fails of if len != 1\n    //\n    if (rc < 0 || len != 1) return (NC_NOERR);\n\n    wasp = true;\n    return (0);\n}\n\nint WASP::InqVarCompressed(string varname, bool &compressed) const\n{\n    compressed = false;\n\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    // Make sure this is a WASP variable\n    //\n    bool wasp;\n    int  rc = WASP::InqVarWASP(varname, wasp);\n    if (rc < 0) return (-1);\n\n    if (!wasp) return (0);\n\n    string wname;\n    rc = GetAtt(varname, AttNameWavelet(), wname);\n    if (rc < 0) return (rc);\n\n    compressed = !wname.empty();\n    return (0);\n}\n\nint WASP::OpenVarWrite(string name, int lod)\n{\n    vector<size_t> bs;\n    vector<size_t> cratios;\n    vector<size_t> udims;\n    vector<size_t> dims;\n    string         wname;\n\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    _open_waspvar = false;\n    int rc = InqVarWASP(name, _open_waspvar);\n    if (rc < 0) return (rc);\n\n    if (!_open_waspvar) {\n        _open_write = true;\n        _open_varname = name;\n        _open = true;\n        return (0);\n    }\n\n    if (_ncdfcptrs.size() < 1) {\n        SetErrMsg(\"Invalid state\");\n        return (-1);\n    }\n    if (_open) {\n        int rc = CloseVar();\n        if (rc < 0) return (rc);\n    }\n    _open_wname.clear();\n    _open_bs.clear();\n    _open_cratios.clear();\n    _open_udims.clear();\n    _open_dims.clear();\n    _open_lod = 0;\n    _open_level = 0;\n    _open_write = false;\n    _open_varname.clear();\n    _open_varxtype = 0;\n    _open = false;\n\n    nc_type xtype;\n    rc = InqVartype(name, xtype);\n    if (rc < 0) return (rc);\n\n    rc = _get_compression_params(name, bs, cratios, udims, dims, wname);\n    if (rc < 0) return (rc);\n\n    if (lod < 0) lod = cratios.size() - 1;\n\n    if (lod >= cratios.size()) {\n        SetErrMsg(\"Invalid level-of-detail : (%d)\", lod);\n        return (-1);\n    }\n\n    // Create one compressor for each execution thread\n    //\n    if (!wname.empty()) {\n        for (int i = 0; i < _nthreads; i++) { _open_compressors[i] = new Compressor(compressor_bs(bs), wname); }\n    }\n\n    _open_wname = wname;\n    _open_bs = bs;\n    _open_cratios = cratios;\n    _open_udims = udims;\n    _open_dims = dims;\n    _open_lod = lod;\n    _open_level = 0;\n    _open_write = true;\n    _open_varname = name;\n    _open_varxtype = xtype;\n    _open = true;\n\n    return (NC_NOERR);\n}\n\nint WASP::OpenVarRead(string name, int level, int lod)\n{\n    vector<size_t> bs;\n    vector<size_t> cratios;\n    vector<size_t> udims;\n    vector<size_t> dims;\n    string         wname;\n\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    _open_waspvar = false;\n    int rc = InqVarWASP(name, _open_waspvar);\n    if (rc < 0) return (rc);\n\n    if (!_open_waspvar) {\n        _open_write = false;\n        _open_varname = name;\n        _open = true;\n        return (0);\n    }\n\n    if (_ncdfcptrs.size() < 1) {\n        SetErrMsg(\"Invalid state\");\n        return (-1);\n    }\n\n    if (_open) {\n        int rc = CloseVar();\n        if (rc < 0) return (rc);\n    }\n\n    _open_wname.clear();\n    _open_bs.clear();\n    _open_cratios.clear();\n    _open_udims.clear();\n    _open_dims.clear();\n    _open_lod = 0;\n    _open_level = 0;\n    _open_write = false;\n    _open_varname.clear();\n    _open_varxtype = 0;\n    _open = false;\n\n    nc_type xtype;\n    rc = InqVartype(name, xtype);\n    if (rc < 0) return (rc);\n\n    rc = _get_compression_params(name, bs, cratios, udims, dims, wname);\n    if (rc < 0) return (rc);\n\n    // For multi-file storage higher-numbered files may be missing\n    // and the max LOD is determined by the number files actually present.\n    // In general cratios.size() == _ncdfcptrs.size()\n    //\n    int maxlod = _numfiles > 1 ? _ncdfcptrs.size() - 1 : cratios.size() - 1;\n    if (lod < 0) lod = maxlod;\n\n    // if (lod > maxlod) {\n    //\tSetErrMsg(\"Invalid level-of-detail : (%d)\", lod);\n    //\treturn(-1);\n    //}\n    if (lod > maxlod) lod = maxlod;\n\n    int numlevels = 1;\n    if (!wname.empty()) {    // May simply be blocked, not compressed\n        for (int i = 0; i < _nthreads; i++) { _open_compressors[i] = new Compressor(compressor_bs(bs), wname); }\n        VAssert(_nthreads >= 1);\n        numlevels = _open_compressors[0]->GetNumLevels();\n    } else {\n        numlevels = 1;\n    }\n    if (level < 0) level = numlevels;\n\n    if (level > numlevels) {\n        SetErrMsg(\"Invalid refinement level: (%d)\", level);\n        for (int i = 0; i < _nthreads; i++) {\n            if (_open_compressors[i]) delete _open_compressors[i];\n            _open_compressors[i] = NULL;\n        }\n        return (-1);\n    }\n\n    _open_wname = wname;\n    _open_bs = bs;\n    _open_cratios = cratios;\n    _open_udims = udims;\n    _open_dims = dims;\n    _open_lod = lod;\n    _open_level = level;\n    _open_write = false;\n    _open_varname = name;\n    _open_varxtype = xtype;\n    _open = true;\n\n    return (NC_NOERR);\n}\n\nint WASP::CloseVar()\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    _open = false;\n    _open_write = false;\n\n    if (!_open_waspvar) return (0);\n\n    for (int i = 0; i < _nthreads; i++) {\n        if (_open_compressors[i]) delete _open_compressors[i];\n        _open_compressors[i] = NULL;\n    }\n\n    return (0);\n}\n\n// Validate parameters to PutVara()\n//\nbool WASP::_validate_put_vara_compressed(vector<size_t> start, vector<size_t> count, vector<size_t> bs, vector<size_t> udims, vector<size_t> cratios) const\n{\n    if (start.size() != udims.size() || count.size() != udims.size()) { return (false); }\n    VAssert(bs.size() == start.size());\n\n    for (int i = 0; i < count.size(); i++) {\n        if (count[i] < 1 || count[i] > udims[i]) return (false);\n    }\n\n    for (int i = 0; i < start.size(); i++) {\n        if (start[i] >= udims[i]) return (false);\n        if ((start[i] + count[i]) > udims[i]) return (false);\n    }\n\n    // Count must be block aligned, or, in the case where an array\n    // dimension is not block aligned, count must align with the\n    // array dimension boundary\n    //\n    for (int i = 0; i < bs.size(); i++) {\n        if (((count[i] % bs[i]) != 0) && (count[i] + start[i] != udims[i])) { return (false); }\n    }\n\n    // Start must *always* be block aligned\n    //\n    for (int i = 0; i < bs.size(); i++) {\n        if ((start[i] % bs[i]) != 0) return (false);\n    }\n\n    return (true);\n}\n\n// Validate parameters to GetVara()\n//\nbool WASP::_validate_get_vara_compressed(vector<size_t> start, vector<size_t> count, vector<size_t> bs, vector<size_t> udims, vector<size_t> cratios, bool unblock) const\n{\n    if (start.size() != udims.size() || count.size() != udims.size()) { return (false); }\n    VAssert(bs.size() == start.size());\n\n    if (unblock) {\n        for (int i = 0; i < count.size(); i++) {\n            if (count[i] < 1 || count[i] > udims[i]) return (false);\n        }\n\n        for (int i = 0; i < start.size(); i++) {\n            if (start[i] >= udims[i]) return (false);\n            if ((start[i] + count[i]) > udims[i]) return (false);\n        }\n    } else {\n        // make sure start and count are block-aligned\n        //\n        vector<size_t> astart, acount;\n        block_align(start, count, bs, astart, acount);\n        for (int i = 0; i < start.size(); i++) {\n            if (start[i] != astart[i]) return (false);\n            if (count[i] != acount[i]) return (false);\n        }\n    }\n\n    return (true);\n}\n\ntemplate<class T, class U> int WASP::_PutVara(vector<size_t> start, vector<size_t> count, const T *data, const unsigned char *mask, U dummy)\n{\n    if (!_validate_put_vara_compressed(start, count, _open_bs, _open_udims, _open_cratios)) {\n        SetErrMsg(\"Invalid parameter\");\n        return (-1);\n    }\n\n    vector<size_t> ncoeffs;\n    vector<size_t> encoded_dims;\n    _get_encoding_vectors(_open_wname, _open_bs, _open_cratios, _open_varxtype, ncoeffs, encoded_dims);\n\n    size_t block_size = vproduct(_open_bs);\n    U *    block = (U *)_blockbuf.Alloc(block_size * _nthreads * sizeof(U));\n\n    // Allocate space for coefficients and sigmap if data are compressed\n    //\n    size_t         coeffs_size = 0;\n    U *            coeffs = NULL;\n    size_t         maps_size = 0;\n    unsigned char *maps = NULL;\n    if (!_open_wname.empty()) {\n        // Handle case where not all coefficients are wanted\n        //\n        while (_open_lod < (ncoeffs.size() - 1)) {\n            ncoeffs.pop_back();\n            encoded_dims.pop_back();\n        }\n\n        coeffs_size = vsum(ncoeffs);\n        coeffs = (U *)_coeffbuf.Alloc(coeffs_size * _nthreads * sizeof(U));\n\n        maps_size = vsum(encoded_dims) - vsum(ncoeffs);\n        maps_size -= BLK_HDR_SZ;\n        maps = (unsigned char *)_sigbuf.Alloc(maps_size * _nthreads * NetCDFCpp::SizeOf(_open_varxtype));\n    }\n\n    // Ugh. Can't preserve type in thread_state, which has to be passed\n    // as a void * to thread library\n    //\n    int data_type = _NetCDFType(*data);\n    int block_type = _NetCDFType(*block);\n\n    //\n    // Set up thread state for parallel (threaded) execution\n    //\n    vector<void *> argvec;\n    for (int i = 0; i < _nthreads; i++) {\n        argvec.push_back((void *)new thread_state(i, _et, _nthreads, _open_varname, _ncdfcptrs, start, count, _open_bs, _open_udims, ncoeffs, encoded_dims, _open_compressors, (void *)data, data_type,\n                                                  (unsigned char *)mask, block + i * block_size, coeffs + i * coeffs_size, block_type, _open_varxtype,\n                                                  maps + i * maps_size * NetCDFCpp::SizeOf(_open_varxtype), 0, true));\n    }\n\n    if (_nthreads == 1) {\n        if (_open_wname.empty()) {\n            RunWriteThread(argvec[0]);\n        } else {\n            RunWriteThreadCompressed(argvec[0]);\n        }\n    } else {\n        int rc;\n        if (_open_wname.empty()) {\n            rc = _et->ParRun(RunWriteThread, argvec);\n        } else {\n            rc = _et->ParRun(RunWriteThreadCompressed, argvec);\n        }\n\n        if (rc < 0) {\n            SetErrMsg(\"Error spawning threads\");\n            return (-1);\n        }\n    }\n    for (int i = 0; i < argvec.size(); i++) delete (thread_state *)argvec[i];\n\n    return (thread_state::_status);\n}\n\ntemplate<class T> int WASP::_PutVara(vector<size_t> start, vector<size_t> count, const T *data, const unsigned char *mask)\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    if (!_open || !_open_write) {\n        SetErrMsg(\"Invalid state\");\n        return (-1);\n    }\n\n    if (!_open_waspvar) { return (NetCDFCpp::PutVara(_open_varname, start, count, data)); }\n\n    VAssert(_open_compressors.size() != 0);\n    if (_open_compressors[0] && _open_compressors[0]->wavelet()->isint()) {\n        long dummy = 0;\n        return (_PutVara(start, count, data, mask, dummy));\n    } else {\n        double dummy = 0.0;\n        return (_PutVara(start, count, data, mask, dummy));\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// PutVar - float\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const float *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); }\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const float *data) { return (WASP::PutVara(start, count, data, NULL)); }\n\nint WASP::PutVar(const float *data) { return (WASP::PutVar(data, NULL)); }\n\nint WASP::PutVar(const float *data, const unsigned char *mask)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::PutVara(start, count, data, mask));\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// PutVar - double\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const double *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); }\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const double *data) { return (WASP::PutVara(start, count, data, NULL)); }\n\nint WASP::PutVar(const double *data) { return (WASP::PutVar(data, NULL)); }\n\nint WASP::PutVar(const double *data, const unsigned char *mask)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::PutVara(start, count, data, mask));\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// PutVar - int\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const int *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); }\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const int *data) { return (WASP::PutVara(start, count, data, NULL)); }\n\nint WASP::PutVar(const int *data) { return (WASP::PutVar(data, NULL)); }\n\nint WASP::PutVar(const int *data, const unsigned char *mask)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::PutVara(start, count, data, mask));\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// PutVar - int16_t\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const int16_t *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); }\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const int16_t *data) { return (WASP::PutVara(start, count, data, NULL)); }\n\nint WASP::PutVar(const int16_t *data) { return (WASP::PutVar(data, NULL)); }\n\nint WASP::PutVar(const int16_t *data, const unsigned char *mask)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::PutVara(start, count, data, mask));\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// PutVar - char\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const unsigned char *data, const unsigned char *mask) { return (WASP::_PutVara(start, count, data, mask)); }\n\nint WASP::PutVara(vector<size_t> start, vector<size_t> count, const unsigned char *data) { return (WASP::PutVara(start, count, data, NULL)); }\n\nint WASP::PutVar(const unsigned char *data) { return (WASP::PutVar(data, NULL)); }\n\nint WASP::PutVar(const unsigned char *data, const unsigned char *mask)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::PutVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::PutVara(start, count, data, mask));\n}\n\ntemplate<class T, class U> int WASP::_GetVara(vector<size_t> start, vector<size_t> count, bool unblock_flag, T *data, U dummy)\n{\n    vector<size_t> ncoeffs;\n    vector<size_t> encoded_dims;\n    _get_encoding_vectors(_open_wname, _open_bs, _open_cratios, _open_varxtype, ncoeffs, encoded_dims);\n\n    // Compute the dimension and block size at the grid hierarchy\n    // level indicated by _open_level\n    //\n    vector<size_t> dims_at_level;\n    vector<size_t> bs_at_level;\n    _dims_at_level(_open_udims, _open_bs, _open_level, _open_wname, dims_at_level, bs_at_level);\n\n    if (!_validate_get_vara_compressed(start, count, bs_at_level, dims_at_level, _open_cratios, unblock_flag)) {\n        SetErrMsg(\"Invalid parameter\");\n        return (-1);\n    }\n\n    size_t block_size = vproduct(bs_at_level);\n\n    // Need temporary space for storing reconstructed data\n    //\n    U *block = NULL;\n    block = (U *)_blockbuf.Alloc(block_size * _nthreads * sizeof(U));\n\n    size_t         coeffs_size = 0;\n    U *            coeffs = NULL;\n    size_t         maps_size = 0;\n    unsigned char *maps = NULL;\n    if (!_open_wname.empty()) {\n        // Handle case where not all coefficients are wanted\n        //\n        while (_open_lod < (ncoeffs.size() - 1)) {\n            ncoeffs.pop_back();\n            encoded_dims.pop_back();\n        }\n\n        coeffs_size = vsum(ncoeffs);\n        coeffs = (U *)_coeffbuf.Alloc(coeffs_size * _nthreads * sizeof(U));\n\n        maps_size = vsum(encoded_dims) - vsum(ncoeffs);\n        maps_size -= BLK_HDR_SZ;\n        maps = (unsigned char *)_sigbuf.Alloc(maps_size * _nthreads * NetCDFCpp::SizeOf(_open_varxtype));\n    }\n\n    // Ugh. Can't preserve type in thread_state, which has to be passed\n    // as a void * to thread library\n    //\n    int data_type = _NetCDFType(*data);\n    int block_type = _NetCDFType(*block);\n\n    //\n    // Set up thread state for parallel (threaded) execution\n    //\n    vector<void *> argvec;\n    for (int i = 0; i < _nthreads; i++) {\n        U *blkptr = block + i * block_size;\n\n        argvec.push_back((void *)new thread_state(i, _et, _nthreads, _open_varname, _ncdfcptrs, start, count, bs_at_level, dims_at_level, ncoeffs, encoded_dims, _open_compressors, data, data_type,\n                                                  NULL, blkptr, coeffs + i * coeffs_size, block_type, _open_varxtype, maps + i * maps_size * NetCDFCpp::SizeOf(_open_varxtype), _open_level,\n                                                  unblock_flag));\n    }\n\n    if (_nthreads == 1) {\n        if (_open_wname.empty()) {\n            RunReadThread(argvec[0]);\n        } else {\n            RunReadThreadCompressed(argvec[0]);\n        }\n    } else {\n        int rc;\n        if (_open_wname.empty()) {\n            rc = _et->ParRun(RunReadThread, argvec);\n        } else {\n            rc = _et->ParRun(RunReadThreadCompressed, argvec);\n        }\n        if (rc < 0) {\n            SetErrMsg(\"Error spawning threads\");\n            return (-1);\n        }\n    }\n\n    for (int i = 0; i < argvec.size(); i++) delete (thread_state *)argvec[i];\n\n    return (thread_state::_status);\n}\n\ntemplate<class T> int WASP::_GetVara(vector<size_t> start, vector<size_t> count, bool unblock_flag, T *data)\n{\n    if (!_waspFile) {\n        SetErrMsg(\"Not a WASP file\");\n        return (-1);\n    }\n\n    if (!_open || _open_write) {\n        SetErrMsg(\"Invalid state\");\n        return (-1);\n    }\n\n    if (!_open_waspvar) { return (NetCDFCpp::GetVara(_open_varname, start, count, data)); }\n\n    VAssert(_open_compressors.size() != 0);\n    if (_open_compressors[0] && _open_compressors[0]->wavelet()->isint()) {\n        long dummy = 0;\n        return (_GetVara(start, count, unblock_flag, data, dummy));\n    } else {\n        double dummy = 0.0;\n        return (_GetVara(start, count, unblock_flag, data, dummy));\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// GetVar - float\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::GetVara(vector<size_t> start, vector<size_t> count, float *data) { return (WASP::_GetVara(start, count, true, data)); }\n\nint WASP::GetVaraBlock(vector<size_t> start, vector<size_t> count, float *data) { return (WASP::_GetVara(start, count, false, data)); }\n\nint WASP::GetVar(float *data)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::GetVara(start, count, data));\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// GetVar - double\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::GetVara(vector<size_t> start, vector<size_t> count, double *data) { return (WASP::_GetVara(start, count, true, data)); }\n\nint WASP::GetVaraBlock(vector<size_t> start, vector<size_t> count, double *data) { return (WASP::_GetVara(start, count, false, data)); }\n\nint WASP::GetVar(double *data)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::GetVara(start, count, data));\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// GetVar - int\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::GetVara(vector<size_t> start, vector<size_t> count, int *data) { return (WASP::_GetVara(start, count, true, data)); }\n\nint WASP::GetVaraBlock(vector<size_t> start, vector<size_t> count, int *data) { return (WASP::_GetVara(start, count, false, data)); }\n\nint WASP::GetVar(int *data)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::GetVara(start, count, data));\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// GetVar - int16_t\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::GetVara(vector<size_t> start, vector<size_t> count, int16_t *data) { return (WASP::_GetVara(start, count, true, data)); }\n\nint WASP::GetVaraBlock(vector<size_t> start, vector<size_t> count, int16_t *data) { return (WASP::_GetVara(start, count, false, data)); }\n\nint WASP::GetVar(int16_t *data)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::GetVara(start, count, data));\n}\n\n////////////////////////////////////////////////////////////////////////////\n//\n// GetVar - char\n//\n////////////////////////////////////////////////////////////////////////////\n\nint WASP::GetVara(vector<size_t> start, vector<size_t> count, unsigned char *data) { return (WASP::_GetVara(start, count, true, data)); }\n\nint WASP::GetVaraBlock(vector<size_t> start, vector<size_t> count, unsigned char *data) { return (WASP::_GetVara(start, count, false, data)); }\n\nint WASP::GetVar(unsigned char *data)\n{\n    if (!_open_waspvar) { return (NetCDFCpp::GetVar(_open_varname, data)); }\n\n    vector<size_t> count = _open_udims;\n    vector<size_t> start(count.size(), 0);\n\n    return (WASP::GetVara(start, count, data));\n}\n\ntemplate<class T> int WASP::_CopyHyperSlice(string varname, NetCDFCpp &src_ncdf, NetCDFCpp &dst_ncdf, vector<size_t> start, vector<size_t> count, T *buf) const\n{\n    int        rc = -1;\n    NetCDFCpp *src_ncdfptr = dynamic_cast<NetCDFCpp *>(&src_ncdf);\n    WASP *     src_waspptr = dynamic_cast<WASP *>(&src_ncdf);\n    if (src_waspptr) {\n        rc = src_waspptr->GetVara(start, count, buf);\n    } else if (src_ncdfptr) {\n        rc = src_ncdfptr->GetVara(varname, start, count, buf);\n    }\n    if (rc < 0) return (-1);\n\n    NetCDFCpp *dst_ncdfptr = dynamic_cast<NetCDFCpp *>(&dst_ncdf);\n    WASP *     dst_waspptr = dynamic_cast<WASP *>(&dst_ncdf);\n    if (dst_waspptr) {\n        rc = dst_waspptr->PutVara(start, count, buf);\n    } else if (dst_ncdfptr) {\n        rc = dst_ncdfptr->PutVara(varname, start, count, buf);\n    }\n    if (rc < 0) return (-1);\n\n    return (0);\n}\n\nint WASP::_CopyVar(string varname, NetCDFCpp &src_ncdf, NetCDFCpp &dst_ncdf) const\n{\n    SmartBuf sbuf;\n\n    nc_type xtype;\n    int     rc = dst_ncdf.InqVartype(varname, xtype);\n    if (rc < 0) return (-1);\n\n    vector<string> dimnames;\n    vector<size_t> dims;\n    rc = src_ncdf.InqVarDims(varname, dimnames, dims);\n    if (rc < 0) return (-1);\n\n    vector<size_t> start, count;\n    for (int i = 0; i < dims.size(); i++) {\n        start.push_back(0);\n        count.push_back(dims[i]);\n    }\n\n    // For variables with 3 or more dimensions process them one\n    // hyperslab at a time.\n    //\n    int nk = 1;\n#ifdef VAPOR3_0_0_ALPHA\n    //\n    // Need to fix this so that count is block-aligned\n    //\n    if (dims.size() >= 3) {\n        count[0] = 1;\n        nk = dims[0];\n    }\n#endif\n\n    size_t elem_sz = max(sizeof(double), sizeof(int));\n    size_t hs_size = vproduct(dims);\n\n    unsigned char *data = (unsigned char *)sbuf.Alloc(elem_sz * hs_size);\n\n    for (int k = 0; k < nk; k++) {\n        if (xtype == NC_FLOAT || xtype == NC_DOUBLE) {\n            rc = _CopyHyperSlice(varname, src_ncdf, dst_ncdf, start, count, (double *)data);\n        } else {\n            rc = _CopyHyperSlice(varname, src_ncdf, dst_ncdf, start, count, (int *)data);\n        }\n\n        if (dims.size() >= 3) start[0] += 1;\n    }\n\n    return (0);\n}\n\nint WASP::CopyVar(string varname, WASP &wasp)\n{\n    bool src_waspvar;\n    int  rc = WASP::InqVarWASP(varname, src_waspvar);\n    if (rc < 0) return (-1);\n\n    bool dst_waspvar;\n    rc = wasp.InqVarWASP(varname, dst_waspvar);\n    if (rc < 0) return (-1);\n\n    if (!src_waspvar && !dst_waspvar) { return (NetCDFCpp::CopyVar(varname, wasp)); }\n\n    if (!src_waspvar) { return (wasp.CopyVarFrom(varname, *this)); }\n\n    if (!dst_waspvar) { return (this->CopyVarTo(varname, wasp)); }\n    VAssert(src_waspvar && dst_waspvar);\n\n    rc = WASP::OpenVarRead(varname, -1, -1);\n    if (rc < 0) return (-1);\n\n    rc = wasp.OpenVarWrite(varname, -1);\n    if (rc < 0) {\n        wasp.CloseVar();\n        return (-1);\n    }\n\n    _CopyVar(varname, *this, wasp);\n\n    WASP::CloseVar();\n    return (wasp.CloseVar());\n}\n\nint WASP::CopyVarFrom(string varname, NetCDFCpp &ncdf)\n{\n    bool waspvar;\n    int  rc = WASP::InqVarWASP(varname, waspvar);\n    if (rc < 0) return (-1);\n\n    if (!waspvar) { return (ncdf.CopyVar(varname, *this)); }\n\n    rc = WASP::OpenVarWrite(varname, -1);\n    if (rc < 0) return (-1);\n\n    _CopyVar(varname, ncdf, *this);\n\n    return (WASP::CloseVar());\n}\n\nint WASP::CopyVarTo(string varname, NetCDFCpp &ncdf)\n{\n    bool waspvar;\n    int  rc = WASP::InqVarWASP(varname, waspvar);\n    if (rc < 0) return (-1);\n\n    if (!waspvar) { return (NetCDFCpp::CopyVar(varname, ncdf)); }\n\n    rc = WASP::OpenVarRead(varname, -1, -1);\n    if (rc < 0) return (-1);\n\n    _CopyVar(varname, *this, ncdf);\n\n    return (WASP::CloseVar());\n}\n\n// For an array with dimensions 'dimnames' and compression ratio\n// vector, cratios, compute the new names and lengths of the dimensions\n// needed to store a compressed version of a variable with dimensions,\n// 'dimnames'\n//\nint WASP::_GetCompressedDims(vector<string> dimnames, string wname, vector<size_t> bs, vector<size_t> cratios, int xtype, vector<string> &cdimnames, vector<size_t> &cdims,\n                             vector<string> &encoded_dim_names, vector<size_t> &encoded_dims) const\n{\n    VAssert(dimnames.size() == bs.size());\n\n    cdimnames.clear();\n    cdims.clear();\n    encoded_dim_names.clear();\n    encoded_dims.clear();\n\n    //\n    // Look up dimlens associated with dimnames\n    //\n    vector<size_t> dims;\n    for (int i = 0; i < dimnames.size(); i++) {\n        size_t dimlen;\n        int    rc = NetCDFCpp::InqDimlen(dimnames[i], dimlen);\n        if (rc < 0) return (rc);\n        dims.push_back(dimlen);\n    }\n\n    //\n    // Compute dimensions of blocked array in terms of blocks. Not all\n    // dimensions are blocked - only n fastest varying, where 'n' is\n    // rank of 'bs'.\n    //\n    cdims = dims;\n    cdimnames = dimnames;\n\n    // See if dimensions are blocked\n    //\n    if (vproduct(bs) == 1) return (0);\n\n    for (int i = 0; i < bs.size(); i++) {\n        if (bs[i] != 1) {\n            size_t bdim = (size_t)ceil((double)dims[i] / (double)bs[i]);\n            string bdimname = \"B_\" + dimnames[i];\n\n            cdims[i] = bdim;\n            cdimnames[i] = bdimname;\n        }\n    }\n\n    //\n    // Now get coefficient dimensions. Coefficient dimensions are\n    // num coefficients + size of significance map needed to address\n    // coefficients. There is one coefficient dimension for each LOD\n    //\n    vector<size_t> ncoeffs;\n    _get_encoding_vectors(wname, bs, cratios, xtype, ncoeffs, encoded_dims);\n\n    string encoded_dim_base;\n    for (int i = 0; i < cdimnames.size(); i++) {\n        if (bs[i] == 1) continue;\n\n        if (i != cdimnames.size() - 1)\n            encoded_dim_base += cdimnames[i] + \"X\";\n        else\n            encoded_dim_base += cdimnames[i];\n    }\n\n    // If not compressed we're done.\n    //\n    //\tif (! wname.empty()) {\n    for (int i = 0; i < encoded_dims.size(); i++) {\n        ostringstream oss;\n        oss << encoded_dim_base << i;\n        encoded_dim_names.push_back(oss.str());\n    }\n    //\t}\n    //\telse {\n    //\t\tencoded_dim_names.push_back(encoded_dim_base);\n    //\t}\n\n    return (NC_NOERR);\n}\n\n// For each compression level (LOD) compute the number of coefficients,\n// ncoeffs, and the dimension of array that will contain both the\n// coefficients and the significance map\n//\n// bs : dimensions of compression block\n// cratio : vector of compression ratios\n// xtype : NetCDF external storage type\n// ncoeffs : number of wavelet coefficients for each compression level\n// encoded_dims : dimension of encoded block for each compression\n// level.  The dimension is ncoeffs + size of encoded sig map\n//\nvoid WASP::_get_encoding_vectors(string wname, vector<size_t> bs, vector<size_t> cratios, int xtype, vector<size_t> &ncoeffs, vector<size_t> &encoded_dims) const\n{\n    ncoeffs.clear();\n    encoded_dims.clear();\n\n    if (wname.empty()) {\n        ncoeffs.push_back(vproduct(bs));\n        encoded_dims.push_back(vproduct(bs));\n        return;\n    }\n\n    Compressor compressor(compressor_bs(bs), wname);\n\n    // Total number of wavelet coefficients generated by a forward transform\n    //\n    size_t ntotal = compressor.GetNumWaveCoeffs();\n\n    long naccum = 0;\n    for (int i = 0; i < cratios.size(); i++) {\n        size_t header_size = 0;\n\n        // Base compression block needs space for data range (min and max)\n        //\n        if (i == 0) header_size = BLK_HDR_SZ;\n\n        size_t n = ntotal / cratios[i];\n\n        // There is a minumum number of coefficients that must be\n        // used in reconstruction that places a lower bound on\n        // the compression rate\n        //\n        if (n < compressor.GetMinCompression()) { n = compressor.GetMinCompression(); }\n\n        n -= naccum;    // only account for new coefficients\n\n        if (n < 1) n = 1;\n        naccum += n;\n\n        ncoeffs.push_back(n);\n\n        // Signifance map is encoded with the wavelet coefficients.\n        // Size of sigmap returned by GetSigMapSize() is in bytes. Need to\n        // convert bytes to word size of POD\n        //\n        if (cratios[i] != 1) {\n            size_t s = compressor.GetSigMapSize(n);\n\n            s = (s + SizeOf(xtype) - 1) / SizeOf(xtype);\n\n            encoded_dims.push_back(header_size + n + s);\n        } else {\n            VAssert(naccum == ntotal);\n\n            // Special case. Don't need to explicitly store sigmap\n            //\n            encoded_dims.push_back(header_size + n + 0);\n        }\n    }\n}\n\n// Make sure compression params are valid:\n// \tcratios vector is monotonic with unique values, no zero\n//\twname is a valide wavelet\n//\tbs supports requested compression ratios\n//\nbool WASP::_validate_compression_params(string wname, vector<size_t> dims, vector<size_t> bs, vector<size_t> cratios) const\n{\n    if (bs.size() < 1 || bs.size() > 4) return (false);\n\n    if (_numfiles > 1) {\n        if (cratios.size() > _numfiles) return (false);\n    }\n\n    if (bs.size() != dims.size()) return (false);\n\n    if (wname.empty()) return (true);\n\n    MatWaveBase mwb(wname);\n    if (!mwb.wavelet()) return (false);\n\n    // Monotonic\n    //\n    for (int i = 0; i < cratios.size() - 1; i++) {\n        if (cratios[i] == cratios[i + 1]) return (false);\n    }\n\n    sort(cratios.begin(), cratios.end());\n    for (int i = 0; i < cratios.size(); i++) {\n        if (cratios[i] == 0) return (false);\n    }\n\n    size_t maxcratio;\n    size_t nlevels;\n    bool   status = WASP::InqCompressionInfo(bs, wname, nlevels, maxcratio);\n    if (!status) return (false);\n\n    for (int i = 0; i < cratios.size(); i++) {\n        if (cratios[i] > maxcratio) return (false);\n    }\n\n    return (true);\n}\n\nint WASP::_get_compression_params(string name, vector<size_t> &bs, vector<size_t> &cratios, vector<size_t> &udims, vector<size_t> &dims, string &wname) const\n{\n    bs.clear();\n    cratios.clear();\n    udims.clear();\n    dims.clear();\n\n    vector<string> udimnames;\n    int            rc = WASP::InqVarDims(name, udimnames, udims);\n    if (rc < 0) return (rc);\n\n    vector<string> dimnames;\n    rc = NetCDFCpp::InqVarDims(name, dimnames, dims);\n    if (rc < 0) return (rc);\n\n    rc = WASP::InqVarCompressionParams(name, wname, bs, cratios);\n    if (rc < 0) return (rc);\n\n    if (!_validate_compression_params(wname, udims, bs, cratios)) {\n        SetErrMsg(\"Invalid cratios specification\");\n        return (-1);\n    }\n\n    return (0);\n}\n\n// Generate the path names for a multipath NetCDF data set\n// containing 'n' paths.\n//\nvector<string> WASP::mkmultipaths(string path, int n)\n{\n    vector<string> paths;\n\n    string basename = path;\n    size_t p = basename.rfind(\".nc\");\n    if (p != std::string::npos) basename = basename.substr(0, p);\n\n    for (int i = 0; i < n; i++) {\n        ostringstream oss;\n        if (i == 0) {\n            oss << basename << \".nc\";\n        } else {\n            oss << basename << \".nc\" << i;\n        }\n        paths.push_back(oss.str());\n    }\n    return (paths);\n}\n"
  },
  {
    "path": "lib/wasp/WaveFiltBase.cpp",
    "content": "\n#include <iostream>\n#include <vapor/WaveFiltBase.h>\n\nusing namespace std;\nusing namespace VAPoR;\n\nWaveFiltBase::WaveFiltBase()\n{\n    _lowDecomFilCoef = new double[MAX_FILTER_SIZE];\n    _lowReconFilCoef = new double[MAX_FILTER_SIZE];\n    _hiDecomFilCoef = new double[MAX_FILTER_SIZE];\n    _hiReconFilCoef = new double[MAX_FILTER_SIZE];\n}\n\nWaveFiltBase::~WaveFiltBase()\n{\n    if (_lowDecomFilCoef) delete[] _lowDecomFilCoef;\n    _lowDecomFilCoef = NULL;\n\n    if (_lowReconFilCoef) delete[] _lowReconFilCoef;\n    _lowReconFilCoef = NULL;\n\n    if (_hiDecomFilCoef) delete[] _hiDecomFilCoef;\n    _hiDecomFilCoef = NULL;\n\n    if (_hiReconFilCoef) delete[] _hiReconFilCoef;\n    _hiReconFilCoef = NULL;\n}\n\n/*-------------------------------------------\n * Flipping Operation\n *-----------------------------------------*/\n\nvoid WaveFiltBase::wrev(const double *sigIn, double *sigOut, int sigLength) const\n{\n    int count = 0;\n    for (count = 0; count < sigLength; count++) sigOut[count] = sigIn[sigLength - count - 1];\n    return;\n}\n\n/*-------------------------------------------\n * Quadrature Mirror Filtering Operation\n *-----------------------------------------*/\nvoid WaveFiltBase::qmf_even(const double *sigIn, double *sigOut, int sigLength) const\n{\n    int count = 0;\n    for (count = 0; count < sigLength; count++) {\n        sigOut[count] = sigIn[sigLength - count - 1];\n\n        if (sigLength % 2 == 0) {\n            if (count % 2 != 0) { sigOut[count] = -1 * sigOut[count]; }\n        } else {\n            if (count % 2 == 0) { sigOut[count] = -1 * sigOut[count]; }\n        }\n    }\n    return;\n}\n\n/*-------------------------------------------\n * Flipping and QMF at the same time\n *-----------------------------------------*/\nvoid WaveFiltBase::qmf_wrev(const double *sigIn, double *sigOut, int sigLength) const\n{\n    int count = 0;\n    for (count = 0; count < sigLength; count++) {\n        sigOut[count] = sigIn[sigLength - count - 1];\n\n        if (sigLength % 2 == 0) {\n            if (count % 2 != 0) { sigOut[count] = -1 * sigOut[count]; }\n        } else {\n            if (count % 2 == 0) { sigOut[count] = -1 * sigOut[count]; }\n        }\n    }\n\n    double tmp;\n    for (count = 0; count < sigLength / 2; count++) {\n        tmp = sigOut[count];\n        sigOut[count] = sigOut[sigLength - count - 1];\n        sigOut[sigLength - count - 1] = tmp;\n    }\n    return;\n}\n\n/*-------------------------------------------\n * Verbatim Copying\n *-----------------------------------------*/\n\nvoid WaveFiltBase::verbatim_copy(const double *sigIn, double *sigOut, int sigLength) const\n{\n    int count = 0;\n    for (count = 0; count < sigLength; count++) sigOut[count] = sigIn[count];\n}\n"
  },
  {
    "path": "lib/wasp/WaveFiltBior.cpp",
    "content": "/*\n * -------------------------------------------------------------------------\n * Biorlet wavelets coefficents.\n * SWT - Scilab wavelet toolbox\n * Copyright (C) 2005-2006  Roger Liu\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n * -------------------------------------------------------------------------\n */\n\n#include <cmath>\n#include \"vapor/VAssert.h\"\n#include <vapor/WaveFiltBior.h>\n\nusing namespace VAPoR;\n\n/*********************************************\n * Local Variable (Filter Coefficent)\n ********************************************/\nnamespace {\n\nconst double h1[10] = {0.0, 0.0, 0.0, 0.0, 0.70710678118654752440084436210, 0.70710678118654752440084436210, 0.0, 0.0, 0.0, 0.0};\n\nconst double hm1_11[2] = {0.70710678118654752440084436210, 0.70710678118654752440084436210};\n\nconst double hm1_13[6] = {-0.0883883476483184405501055452631, 0.0883883476483184405501055452631, 0.70710678118654752440084436210,\n                          0.70710678118654752440084436210,    0.0883883476483184405501055452631, -0.0883883476483184405501055452631};\n\nconst double hm1_15[10] = {0.0165728151840597076031447897368,  -0.0165728151840597076031447897368, -0.1215339780164378557563951247368, 0.1215339780164378557563951247368,\n                           0.70710678118654752440084436210,    0.70710678118654752440084436210,    0.1215339780164378557563951247368,  -0.1215339780164378557563951247368,\n                           -0.0165728151840597076031447897368, 0.0165728151840597076031447897368};\n\nconst double h2[18] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3535533905932737622004221810524, 0.7071067811865475244008443621048, 0.3535533905932737622004221810524, 0.0,\n                       0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};\n\nconst double hm2_22[6] = {-0.1767766952966368811002110905262, 0.3535533905932737622004221810524, 1.0606601717798212866012665431573, 0.3535533905932737622004221810524,\n                          -0.1767766952966368811002110905262};\n\nconst double hm2_24[10] = {0.0331456303681194152062895794737,  -0.0662912607362388304125791589473, -0.1767766952966368811002110905262,\n                           0.4198446513295125926130013399998,  0.9943689110435824561886873842099,  0.4198446513295125926130013399998,\n                           -0.1767766952966368811002110905262, -0.0662912607362388304125791589473, 0.0331456303681194152062895794737};\n\nconst double hm2_26[14] = {-0.0069053396600248781679769957237, 0.0138106793200497563359539914474,  0.0469563096881691715422435709210, -0.1077232986963880994204411332894,\n                           -0.1698713556366120029322340948025, 0.4474660099696121052849093228945,  0.9667475524034829435167794013152, 0.4474660099696121052849093228945,\n                           -0.1698713556366120029322340948025, -0.1077232986963880994204411332894, 0.0469563096881691715422435709210, 0.0138106793200497563359539914474,\n                           -0.0069053396600248781679769957237};\n\nconst double hm2_28[18] = {0.0015105430506304420992449678146, -0.0030210861012608841984899356291, -0.0129475118625466465649568669819, 0.0289161098263541773284036695929,\n                           0.0529984818906909399392234421792, -0.1349130736077360572068505539514, -0.1638291834340902345352542235443, 0.4625714404759165262773590010400,\n                           0.9516421218971785225243297231697, 0.4625714404759165262773590010400,  -0.1638291834340902345352542235443, -0.1349130736077360572068505539514,\n                           0.0529984818906909399392234421792, 0.0289161098263541773284036695929,  -0.0129475118625466465649568669819, -0.0030210861012608841984899356291,\n                           0.0015105430506304420992449678146};\n\nconst double h3[20] = {\n    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1767766952966368811002110905262, 0.5303300858899106433006332715786, 0.5303300858899106433006332715786, 0.1767766952966368811002110905262,\n    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};\n\nconst double hm3_31[4] = {-0.3535533905932737622004221810524, 1.0606601717798212866012665431573, 1.0606601717798212866012665431573, -0.3535533905932737622004221810524};\n\nconst double hm3_33[8] = {0.0662912607362388304125791589473, -0.1988737822087164912377374768420, -0.1546796083845572709626847042104, 0.9943689110435824561886873842099,\n                          0.9943689110435824561886873842099, -0.1546796083845572709626847042104, -0.1988737822087164912377374768420, 0.0662912607362388304125791589473};\n\nconst double hm3_35[12] = {-0.0138106793200497563359539914474, 0.0414320379601492690078619743421, 0.0524805814161890740766251675000, -0.2679271788089652729175074340788,\n                           -0.0718155324642587329469607555263, 0.9667475524034829435167794013152, 0.9667475524034829435167794013152, -0.0718155324642587329469607555263,\n                           -0.2679271788089652729175074340788, 0.0524805814161890740766251675000, 0.0414320379601492690078619743421, -0.0138106793200497563359539914474};\n\nconst double hm3_37[16] = {0.0030210861012608841984899356291, -0.0090632583037826525954698068873, -0.0168317654213106405344439270765, 0.0746639850740189951912512662623,\n                           0.0313329787073628846871956180962, -0.3011591259228349991008967259990, -0.0264992409453454699696117210896, 0.9516421218971785225243297231697,\n                           0.9516421218971785225243297231697, -0.0264992409453454699696117210896, -0.3011591259228349991008967259990, 0.0313329787073628846871956180962,\n                           0.0746639850740189951912512662623, -0.0168317654213106405344439270765, -0.0090632583037826525954698068873, 0.0030210861012608841984899356291};\n\nconst double hm3_39[20] = {-0.0006797443727836989446602355165, 0.0020392331183510968339807065496, 0.0050603192196119810324706421788, -0.0206189126411055346546938106687,\n                           -0.0141127879301758447558029850103, 0.0991347824942321571990197448581, 0.0123001362694193142367090236328, -0.3201919683607785695513833204624,\n                           0.0020500227115698857061181706055,  0.9421257006782067372990864259380, 0.9421257006782067372990864259380, 0.0020500227115698857061181706055,\n                           -0.3201919683607785695513833204624, 0.0123001362694193142367090236328, 0.0991347824942321571990197448581, -0.0141127879301758447558029850103,\n                           -0.0206189126411055346546938106687, 0.0050603192196119810324706421788, 0.0020392331183510968339807065496, -0.0006797443727836989446602355165};\n\nconst double hm4_44[] = {0.037828455507264, -0.023849465019557, -0.110624404418437, 0.377402855612831, 0.852698679008894, 0.377402855612831, -0.110624404418437, -0.023849465019557, 0.037828455507264};\n\nconst double h4[] = {0.0, -0.064538882628697, -0.040689417609164, 0.418092273221617, 0.788485616405583, 0.418092273221617, -0.0406894176091641, -0.0645388826286971, 0.0};\n\n};    // namespace\n\nvoid WaveFiltBior::_analysis_initialize(int member)\n{\n    const double *pFilterCoef = NULL;\n    const double *pFilterCoefMirror = NULL;\n\n    _filterLength = 6 * member;\n\n    switch (member) {\n    case 11:\n        _filterLength = 2;\n        pFilterCoef = hm1_11;\n        pFilterCoefMirror = h1 + 4;\n        break;\n    case 13:\n        _filterLength = 6;\n        pFilterCoef = hm1_13;\n        pFilterCoefMirror = h1 + 2;\n        break;\n    case 15:\n        _filterLength = 10;\n        pFilterCoef = hm1_15;\n        pFilterCoefMirror = h1;\n        break;\n    case 22:\n        _filterLength = 5;\n        pFilterCoef = hm2_22;\n        pFilterCoefMirror = h2 + 6;\n        break;\n    case 24:\n        _filterLength = 9;\n        pFilterCoef = hm2_24;\n        pFilterCoefMirror = h2 + 4;\n        break;\n    case 26:\n        _filterLength = 13;\n        pFilterCoef = hm2_26;\n        pFilterCoefMirror = h2 + 2;\n        break;\n    case 28:\n        _filterLength = 17;\n        pFilterCoef = hm2_28;\n        pFilterCoefMirror = h2;\n        break;\n    case 31:\n        _filterLength = 4;\n        pFilterCoef = hm3_31;\n        pFilterCoefMirror = h3 + 8;\n        break;\n    case 33:\n        _filterLength = 8;\n        pFilterCoef = hm3_33;\n        pFilterCoefMirror = h3 + 6;\n        break;\n    case 35:\n        _filterLength = 12;\n        pFilterCoef = hm3_35;\n        pFilterCoefMirror = h3 + 4;\n        break;\n    case 37:\n        _filterLength = 16;\n        pFilterCoef = hm3_37;\n        pFilterCoefMirror = h3 + 2;\n        break;\n    case 39:\n        _filterLength = 20;\n        pFilterCoef = hm3_39;\n        pFilterCoefMirror = h3;\n        break;\n\n    case 44:\n        _filterLength = 9;\n        pFilterCoef = hm4_44;\n        pFilterCoefMirror = h4;\n        break;\n\n    default: VAssert(pFilterCoef != NULL);\n    };\n\n    wrev(pFilterCoef, _lowDecomFilCoef, _filterLength);\n    qmf_wrev(pFilterCoefMirror, _hiDecomFilCoef, _filterLength);\n\n    return;\n}\n\nvoid WaveFiltBior::_synthesis_initialize(int member)\n{\n    const double *pFilterCoef = NULL;\n    const double *pFilterCoefMirror = NULL;\n\n    switch (member) {\n    case 11:\n        _filterLength = 2;\n        pFilterCoef = h1 + 4;\n        pFilterCoefMirror = hm1_11;\n        break;\n    case 13:\n        _filterLength = 6;\n        pFilterCoef = h1 + 2;\n        pFilterCoefMirror = hm1_13;\n        break;\n    case 15:\n        _filterLength = 10;\n        pFilterCoef = h1;\n        pFilterCoefMirror = hm1_15;\n        break;\n    case 22:\n        _filterLength = 5;\n        pFilterCoef = h2 + 6;\n        pFilterCoefMirror = hm2_22;\n        break;\n    case 24:\n        _filterLength = 9;\n        pFilterCoef = h2 + 4;\n        pFilterCoefMirror = hm2_24;\n        break;\n    case 26:\n        _filterLength = 13;\n        pFilterCoef = h2 + 2;\n        pFilterCoefMirror = hm2_26;\n        break;\n    case 28:\n        _filterLength = 17;\n        pFilterCoef = h2;\n        pFilterCoefMirror = hm2_28;\n        break;\n    case 31:\n        _filterLength = 4;\n        pFilterCoef = h3 + 8;\n        pFilterCoefMirror = hm3_31;\n        break;\n    case 33:\n        _filterLength = 8;\n        pFilterCoef = h3 + 6;\n        pFilterCoefMirror = hm3_33;\n        break;\n    case 35:\n        _filterLength = 12;\n        pFilterCoef = h3 + 4;\n        pFilterCoefMirror = hm3_35;\n        break;\n    case 37:\n        _filterLength = 16;\n        pFilterCoef = h3 + 2;\n        pFilterCoefMirror = hm3_37;\n        break;\n    case 39:\n        _filterLength = 20;\n        pFilterCoef = h3;\n        pFilterCoefMirror = hm3_39;\n        break;\n\n    case 44:\n        _filterLength = 9;\n        pFilterCoef = h4;\n        pFilterCoefMirror = hm4_44;\n        break;\n\n    default: VAssert(pFilterCoef != NULL);\n    };\n\n    verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength);\n    qmf_even(pFilterCoefMirror, _hiReconFilCoef, _filterLength);\n}\n\nWaveFiltBior::WaveFiltBior(const string &wavename) : WaveFiltBase()\n{\n    int member = -1;\n\n    if (wavename.compare(\"bior1.1\") == 0) {\n        member = 11;\n    } else if (wavename.compare(\"bior1.3\") == 0) {\n        member = 13;\n    } else if (wavename.compare(\"bior1.5\") == 0) {\n        member = 15;\n    } else if (wavename.compare(\"bior2.2\") == 0) {\n        member = 22;\n    } else if (wavename.compare(\"bior2.4\") == 0) {\n        member = 24;\n    } else if (wavename.compare(\"bior2.6\") == 0) {\n        member = 26;\n    } else if (wavename.compare(\"bior2.8\") == 0) {\n        member = 28;\n    } else if (wavename.compare(\"bior3.1\") == 0) {\n        member = 31;\n    } else if (wavename.compare(\"bior3.3\") == 0) {\n        member = 33;\n    } else if (wavename.compare(\"bior3.5\") == 0) {\n        member = 35;\n    } else if (wavename.compare(\"bior3.7\") == 0) {\n        member = 37;\n    } else if (wavename.compare(\"bior3.9\") == 0) {\n        member = 39;\n    } else if (wavename.compare(\"bior4.4\") == 0) {\n        member = 44;\n    } else {\n        member = 11;    // default to bior1.1\n    }\n\n    _analysis_initialize(member);\n    _synthesis_initialize(member);\n}\n\nWaveFiltBior::~WaveFiltBior() {}\n"
  },
  {
    "path": "lib/wasp/WaveFiltCoif.cpp",
    "content": "/*\n * -------------------------------------------------------------------------\n * Coiflet wavelets coefficents.\n * SWT - Scilab wavelet toolbox\n * Copyright (C) 2005-2006  Roger Liu\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n * -------------------------------------------------------------------------\n */\n\n#include <cmath>\n#include \"vapor/VAssert.h\"\n#include <vapor/WaveFiltCoif.h>\n\nusing namespace VAPoR;\n\n/*********************************************\n * Local Variable (Filter Coefficent)\n ********************************************/\nnamespace {\n\nconst double coif1[6] = {-0.051429728471000, 0.238929728471000, 0.602859456942000, 0.272140543058000, -0.051429728471000, -0.011070271529000};\n\nconst double coif2[12] = {0.011587596739000,  -0.029320137980000, -0.047639590310000, 0.273021046535000, 0.574682393857000,  0.294867193696000,\n                          -0.054085607092000, -0.042026480461000, 0.016744410163000,  0.003967883613000, -0.001289203356000, -0.000509505399000};\n\nconst double coif3[18] = {\n    -0.002682418671000, 0.005503126709000, 0.016583560479000, -0.046507764479000, -0.043220763560000, 0.286503335274000, 0.561285256870000, 0.302983571773000,  -0.050770140755000,\n    -0.058196250762000, 0.024434094321000, 0.011229240962000, -0.006369601011000, -0.001820458916000, 0.000790205101000, 0.000329665174000, -0.000050192775000, -0.000024465734000,\n};\n\nconst double coif4[24] = {0.000630961046000, -0.001152224852000, -0.005194524026000, 0.011362459244000,  0.018867235378000, -0.057464234429000, -0.039652648517000, 0.293667390895000,\n                          0.553126452562000, 0.307157326198000,  -0.047112738865000, -0.068038127051000, 0.027813640153000, 0.017735837438000,  -0.010756318517000, -0.004001012886000,\n                          0.002652665946000, 0.000895594529000,  -0.000416500571000, -0.000183829769000, 0.000044080354000, 0.000022082857000,  -0.000002304942000, -0.000001262175000};\n\nconst double coif5[30] = {-0.000149963800000, 0.000253561200000,  0.001540245700000, -0.002941110800000, -0.007163781900000, 0.016552066400000,  0.019917804300000, -0.064997262800000,\n                          -0.036800073600000, 0.298092323500000,  0.547505429400000, 0.309706849000000,  -0.043866050800000, -0.074652238900000, 0.029195879500000, 0.023110777000000,\n                          -0.013973687900000, -0.006480090000000, 0.004783001400000, 0.001720654700000,  -0.001175822200000, -0.000451227000000, 0.000213729800000, 0.000099377600000,\n                          -0.000029232100000, -0.000015072000000, 0.000002640800000, 0.000001459300000,  -0.000000118400000, -0.000000067300000};\n\n};    // namespace\n\nvoid WaveFiltCoif::_analysis_initialize(int member)\n{\n    const double *pFilterCoef = NULL;\n\n    _filterLength = 6 * member;\n\n    switch (member) {\n    case 1: pFilterCoef = coif1; break;\n    case 2: pFilterCoef = coif2; break;\n    case 3: pFilterCoef = coif3; break;\n    case 4: pFilterCoef = coif4; break;\n    case 5: pFilterCoef = coif5; break;\n    default: VAssert(pFilterCoef != NULL);\n    }\n\n    wrev(pFilterCoef, _lowDecomFilCoef, _filterLength);\n    qmf_wrev(pFilterCoef, _hiDecomFilCoef, _filterLength);\n    for (int count = 0; count < _filterLength; count++) _lowDecomFilCoef[count] *= sqrt(2.0);\n    for (int count = 0; count < _filterLength; count++) _hiDecomFilCoef[count] *= sqrt(2.0);\n\n    return;\n}\n\nvoid WaveFiltCoif::_synthesis_initialize(int member)\n{\n    const double *pFilterCoef = NULL;\n\n    _filterLength = 6 * member;\n\n    switch (member) {\n    case 1: pFilterCoef = coif1; break;\n    case 2: pFilterCoef = coif2; break;\n    case 3: pFilterCoef = coif3; break;\n    case 4: pFilterCoef = coif4; break;\n    case 5: pFilterCoef = coif5; break;\n    default: VAssert(pFilterCoef != NULL);\n    }\n\n    verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength);\n    qmf_even(pFilterCoef, _hiReconFilCoef, _filterLength);\n\n    for (int count = 0; count < _filterLength; count++) _lowReconFilCoef[count] *= sqrt(2.0);\n    for (int count = 0; count < _filterLength; count++) _hiReconFilCoef[count] *= sqrt(2.0);\n\n    return;\n}\n\nWaveFiltCoif::WaveFiltCoif(const string &wavename) : WaveFiltBase()\n{\n    int member = -1;\n\n    if (wavename.compare(\"coif1\") == 0) {\n        member = 1;\n    } else if (wavename.compare(\"coif2\") == 0) {\n        member = 2;\n    } else if (wavename.compare(\"coif3\") == 0) {\n        member = 3;\n    } else if (wavename.compare(\"coif4\") == 0) {\n        member = 4;\n    } else if (wavename.compare(\"coif5\") == 0) {\n        member = 5;\n    } else {\n        member = 1;    // default coif1\n    }\n\n    _analysis_initialize(member);\n    _synthesis_initialize(member);\n}\n\nWaveFiltCoif::~WaveFiltCoif() {}\n"
  },
  {
    "path": "lib/wasp/WaveFiltDaub.cpp",
    "content": "/*\n * -------------------------------------------------------------------------\n * Daublet wavelets coefficents.\n * SWT - Scilab wavelet toolbox\n * Copyright (C) 2005-2006  Roger Liu\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n * -------------------------------------------------------------------------\n */\n\n#include <cmath>\n#include \"vapor/VAssert.h\"\n#include <vapor/WaveFiltDaub.h>\n\nusing namespace VAPoR;\n\n/*********************************************\n * Local Variable (Filter Coefficent)\n ********************************************/\nnamespace {\n\n// const double db1[2] = { 0.70710678, 0.70710678 };\nconst double db1[2] = {sqrt(2.0) / 2.0, sqrt(2.0) / 2.0};\n\nconst double db2[4] = {0.48296291314453414337487159986, 0.83651630373780790557529378092, 0.22414386804201338102597276224, -0.12940952255126038117444941881};\n\nconst double db3[6] = {0.33267055295008261599851158914,  0.80689150931109257649449360409,  0.45987750211849157009515194215,\n                       -0.13501102001025458869638990670, -0.08544127388202666169281916918, 0.03522629188570953660274066472};\n\nconst double db4[8] = {0.23037781330889650086329118304,  0.71484657055291564708992195527, 0.63088076792985890788171633830, -0.02798376941685985421141374718,\n                       -0.18703481171909308407957067279, 0.03084138183556076362721936253, 0.03288301166688519973540751355, -0.01059740178506903210488320852};\n\nconst double db5[10] = {0.16010239797419291448072374802,  0.60382926979718967054011930653, 0.72430852843777292772807124410,  0.13842814590132073150539714634,  -0.24229488706638203186257137947,\n                        -0.03224486958463837464847975506, 0.07757149384004571352313048939, -0.00624149021279827427419051911, -0.01258075199908199946850973993, 0.00333572528547377127799818342};\n\nconst double db6[12] = {0.11154074335010946362132391724,  0.49462389039845308567720417688,  0.75113390802109535067893449844, 0.31525035170919762908598965481,\n                        -0.22626469396543982007631450066, -0.12976686756726193556228960588, 0.09750160558732304910234355254, 0.02752286553030572862554083950,\n                        -0.03158203931748602956507908070, 0.00055384220116149613925191840,  0.00477725751094551063963597525, -0.00107730108530847956485262161};\n\nconst double db7[14] = {0.07785205408500917901996352196,  0.39653931948191730653900039094, 0.72913209084623511991694307034,  0.46978228740519312247159116097,  -0.14390600392856497540506836221,\n                        -0.22403618499387498263814042023, 0.07130921926683026475087657050, 0.08061260915108307191292248036,  -0.03802993693501441357959206160, -0.01657454163066688065410767489,\n                        0.01255099855609984061298988603,  0.00042957797292136652113212912, -0.00180164070404749091526826291, 0.00035371379997452024844629584\n\n};\n\nconst double db8[16] = {0.05441584224310400995500940520,  0.31287159091429997065916237551,  0.67563073629728980680780076705, 0.58535468365420671277126552005,\n                        -0.01582910525634930566738054788, -0.28401554296154692651620313237, 0.00047248457391328277036059001, 0.12874742662047845885702928751,\n                        -0.01736930100180754616961614887, -0.04408825393079475150676372324, 0.01398102791739828164872293057, 0.00874609404740577671638274325,\n                        -0.00487035299345157431042218156, -0.00039174037337694704629808036, 0.00067544940645056936636954757, -0.00011747678412476953373062823};\n\nconst double db9[18] = {0.03807794736387834658869765888,  0.24383467461259035373204158165,  0.60482312369011111190307686743,  0.65728807805130053807821263905,  0.13319738582500757619095494590,\n                        -0.29327378327917490880640319524, -0.09684078322297646051350813354, 0.14854074933810638013507271751,  0.03072568147933337921231740072,  -0.06763282906132997367564227483,\n                        0.00025094711483145195758718975,  0.02236166212367909720537378270,  -0.00472320475775139727792570785, -0.00428150368246342983449679500, 0.00184764688305622647661912949,\n                        0.00023038576352319596720521639,  -0.00025196318894271013697498868, 0.00003934732031627159948068988};\n\nconst double db10[20] = {0.02667005790055555358661744877,  0.18817680007769148902089297368,  0.52720118893172558648174482796,  0.68845903945360356574187178255,  0.28117234366057746074872699845,\n                         -0.24984642432731537941610189792, -0.19594627437737704350429925432, 0.12736934033579326008267723320,  0.09305736460357235116035228984,  -0.07139414716639708714533609308,\n                         -0.02945753682187581285828323760, 0.03321267405934100173976365318,  0.00360655356695616965542329142,  -0.01073317548333057504431811411, 0.00139535174705290116578931845,\n                         0.00199240529518505611715874224,  -0.00068585669495971162656137098, -0.00011646685512928545095148097, 0.00009358867032006959133405013,  -0.00001326420289452124481243668};\n\n};    // namespace\n\nvoid WaveFiltDaub::_analysis_initialize(int member)\n{\n    const double *pFilterCoef = NULL;\n\n    _filterLength = 2 * member;\n\n    switch (member) {\n    case 1: pFilterCoef = db1; break;\n    case 2: pFilterCoef = db2; break;\n    case 3: pFilterCoef = db3; break;\n    case 4: pFilterCoef = db4; break;\n    case 5: pFilterCoef = db5; break;\n    case 6: pFilterCoef = db6; break;\n    case 7: pFilterCoef = db7; break;\n    case 8: pFilterCoef = db8; break;\n    case 9: pFilterCoef = db9; break;\n    case 10: pFilterCoef = db10; break;\n    default: VAssert(pFilterCoef != NULL);\n    }\n\n    wrev(pFilterCoef, _lowDecomFilCoef, _filterLength);\n    qmf_wrev(pFilterCoef, _hiDecomFilCoef, _filterLength);\n\n    return;\n}\n\nvoid WaveFiltDaub::_synthesis_initialize(int member)\n{\n    const double *pFilterCoef = NULL;\n\n    _filterLength = 2 * member;\n\n    switch (member) {\n    case 1: pFilterCoef = db1; break;\n    case 2: pFilterCoef = db2; break;\n    case 3: pFilterCoef = db3; break;\n    case 4: pFilterCoef = db4; break;\n    case 5: pFilterCoef = db5; break;\n    case 6: pFilterCoef = db6; break;\n    case 7: pFilterCoef = db7; break;\n    case 8: pFilterCoef = db8; break;\n    case 9: pFilterCoef = db9; break;\n    case 10: pFilterCoef = db10; break;\n    default: VAssert(pFilterCoef != NULL);\n    }\n\n    verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength);\n    qmf_even(pFilterCoef, _hiReconFilCoef, _filterLength);\n\n    return;\n}\n\nWaveFiltDaub::WaveFiltDaub(const string &wavename) : WaveFiltBase()\n{\n    int member = -1;\n\n    if (wavename.compare(\"db1\") == 0) {\n        member = 1;\n    } else if (wavename.compare(\"db2\") == 0) {\n        member = 2;\n    } else if (wavename.compare(\"db3\") == 0) {\n        member = 3;\n    } else if (wavename.compare(\"db4\") == 0) {\n        member = 4;\n    } else if (wavename.compare(\"db5\") == 0) {\n        member = 5;\n    } else if (wavename.compare(\"db6\") == 0) {\n        member = 6;\n    } else if (wavename.compare(\"db7\") == 0) {\n        member = 7;\n    } else if (wavename.compare(\"db8\") == 0) {\n        member = 8;\n    } else if (wavename.compare(\"db9\") == 0) {\n        member = 9;\n    } else if (wavename.compare(\"db10\") == 0) {\n        member = 10;\n    } else {\n        member = 1;    // default db1\n    }\n\n    _analysis_initialize(member);\n    _synthesis_initialize(member);\n}\n\nWaveFiltDaub::~WaveFiltDaub() {}\n"
  },
  {
    "path": "lib/wasp/WaveFiltHaar.cpp",
    "content": "/*\n * -------------------------------------------------------------------------\n * Haar wavelets coefficents.\n * SWT - Scilab wavelet toolbox\n * Copyright (C) 2005-2006  Roger Liu\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n * -------------------------------------------------------------------------\n */\n\n#include <cmath>\n#include <vapor/WaveFiltBase.h>\n#include <vapor/WaveFiltHaar.h>\n\nusing namespace VAPoR;\n\n/*********************************************\n * Local Variable (Filter Coefficent)\n ********************************************/\nnamespace {\n\n// const double haar[2] = { 0.707106781186548, 0.707106781186548 };\nconst double haar[2] = {sqrt(2.0) / 2.0, sqrt(2.0) / 2.0};\n\n};    // namespace\n\nvoid WaveFiltHaar::_analysis_initialize()\n{\n    const double *pFilterCoef;\n\n    pFilterCoef = haar;\n    _filterLength = 2;\n\n    wrev(pFilterCoef, _lowDecomFilCoef, _filterLength);\n    qmf_wrev(pFilterCoef, _hiDecomFilCoef, _filterLength);\n    return;\n}\n\nvoid WaveFiltHaar::_synthesis_initialize()\n{\n    const double *pFilterCoef;\n\n    pFilterCoef = haar;\n\n    _filterLength = 2;\n\n    verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength);\n    qmf_even(pFilterCoef, _hiReconFilCoef, _filterLength);\n    return;\n}\n\nWaveFiltHaar::WaveFiltHaar() : WaveFiltBase()\n{\n    _analysis_initialize();\n    _synthesis_initialize();\n}\n\nWaveFiltHaar::~WaveFiltHaar() {}\n"
  },
  {
    "path": "lib/wasp/WaveFiltInt.cpp",
    "content": "/*\n * -------------------------------------------------------------------------\n * Haar wavelets coefficents.\n * SWT - Scilab wavelet toolbox\n * Copyright (C) 2005-2006  Roger Liu\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n * -------------------------------------------------------------------------\n */\n\n#include <cmath>\n#include <vapor/WaveFiltBase.h>\n#include <vapor/WaveFiltInt.h>\n\nusing namespace VAPoR;\n\n/*********************************************\n * Local Variable (Filter Coefficent)\n ********************************************/\nnamespace {\n\nconst double h2_2[] = {-1 / 8, 1 / 4, 3 / 4, 1 / 4, -1 / 8};\nconst double hm2_2[] = {0, -1 / 2, 1, -1 / 2, 0};\n};    // namespace\n\nvoid WaveFiltInt::_analysis_initialize()\n{\n    const double *pFilterCoef = NULL;\n    const double *pFilterCoefMirror = NULL;\n\n    if (_wavename == \"intbior2.2\" || _wavename == \"intcdf5/3\") {\n        _filterLength = 5;\n        pFilterCoef = h2_2;\n        pFilterCoefMirror = hm2_2;\n    } else {\n        _filterLength = 5;\n        pFilterCoef = h2_2;\n        pFilterCoefMirror = hm2_2;\n    }\n\n    wrev(pFilterCoef, _lowDecomFilCoef, _filterLength);\n    qmf_wrev(pFilterCoefMirror, _hiDecomFilCoef, _filterLength);\n}\n\nvoid WaveFiltInt::_synthesis_initialize()\n{\n    const double *pFilterCoef = NULL;\n    const double *pFilterCoefMirror = NULL;\n\n    if (_wavename == \"intbior2.2\" || _wavename == \"intcdf5/3\") {\n        _filterLength = 5;\n        pFilterCoef = hm2_2;\n        pFilterCoefMirror = h2_2;\n    } else {\n        _filterLength = 5;\n        pFilterCoef = hm2_2;\n        pFilterCoefMirror = h2_2;\n    }\n\n    verbatim_copy(pFilterCoef, _lowReconFilCoef, _filterLength);\n    qmf_even(pFilterCoefMirror, _hiReconFilCoef, _filterLength);\n\n    return;\n}\n\nWaveFiltInt::WaveFiltInt(const string &wavename) : WaveFiltBase()\n{\n    _wavename = wavename;\n\n    _analysis_initialize();\n    _synthesis_initialize();\n}\n\nWaveFiltInt::~WaveFiltInt() {}\n\nvoid WaveFiltInt::Analysis(const long *sigIn, size_t sigInLen, long *cA, long *cD, bool oddlow, bool oddhigh) const\n{\n    if (_wavename == \"intbior2.2\" || _wavename == \"intcdf5/3\") {\n        _AnalysisCDF5_3(sigIn, sigInLen, cA, cD);\n    } else {\n        _AnalysisCDF5_3(sigIn, sigInLen, cA, cD);\n    }\n}\n\nvoid WaveFiltInt::_AnalysisCDF5_3(const long *sigIn, size_t sigInLen, long *cA, long *cD) const\n{\n    const long *x = sigIn + 2;    // skip signal extension\n\n    size_t nD = sigInLen >> 1;    // num detail coefficients\n    size_t nC = sigInLen >> 1;    // num approximation coefficients\n    if (sigInLen % 2) nC++;\n\n    for (size_t i = 0; i < nD; i++) { cD[i] = x[2 * i + 1] - floor(0.5 * (x[2 * (i + 1)] + x[2 * i])); }\n\n    // Left boundary of approximation coefficients requires special\n    // handling (we don't have cD[i] for i==-1\n    //\n    long cDm1 = x[-1] - floor(0.5 * (x[0] + x[-2]));\n    cA[0] = x[0] + floor(0.25 * (cD[0] + cDm1) + 0.5);\n\n    // For even length signals nD=nC. For odd, nD=nC-1 and we need\n    // special handling for right boundary\n    //\n    for (size_t i = 1; i < nD; i++) { cA[i] = x[2 * i] + floor(0.25 * (cD[i] + cD[i - 1]) + 0.5); }\n\n    // Boundary handling for odd length signals\n    //\n    if (sigInLen % 2) {\n        size_t i = nC - 1;\n        long   cDp1 = x[2 * i + 1] - floor(0.5 * (x[2 * (i + 1)] + x[2 * i]));\n        cA[i] = x[2 * i] + floor(0.25 * (cDp1 + cD[i - 1]) + 0.5);\n    }\n}\n\nvoid WaveFiltInt::Synthesis(const long *cA, const long *cD, size_t sigInLen, long *sigOut) const\n{\n    if (_wavename == \"intbior2.2\" || _wavename == \"intcdf5/3\") {\n        _SynthesisCDF5_3(cA, cD, sigInLen, sigOut);\n    } else {\n        _SynthesisCDF5_3(cA, cD, sigInLen, sigOut);\n    }\n}\n\nvoid WaveFiltInt::_SynthesisCDF5_3(const long *cA, const long *cD, size_t sigInLen, long *sigOut) const\n{\n    cA += 1;    // skip signal extension\n    cD += 1;    // skip signal extension\n\n    size_t n = sigInLen;\n\n    // Even samples\n    //\n    for (size_t i = 0; i < n; i++) { sigOut[2 * i] = cA[i] - floor(0.25 * (cD[i - 1] + cD[i]) + 0.5); }\n\n    // Odd  samples\n    //\n    for (size_t i = 0; i < n - 1; i++) { sigOut[2 * i + 1] = cD[i] + floor(0.5 * (sigOut[2 * (i + 1)] + sigOut[2 * i])); }\n\n    // Right boundary requires special handling - we don't have\n    // even sample for sigOut[2*(i+1)] when i==n-1\n    //\n    size_t i = n - 1;\n    long   sp1 = cA[n] - floor(0.25 * (cD[n - 1] + cD[n]) + 0.5);\n    sigOut[2 * i + 1] = cD[i] + floor(0.5 * (sp1 + sigOut[2 * i]));\n}\n"
  },
  {
    "path": "plugins/paraview/CMakeLists.txt",
    "content": "PROJECT(VDFReader)\n\n# Plugin that uses the Vapor libraries to read VDF files into ParaView\n\ncmake_minimum_required(VERSION 2.8)\nIF( COMMAND CMAKE_POLICY )\n  CMAKE_POLICY( SET CMP0003 NEW )\nENDIF( COMMAND CMAKE_POLICY )\n\nIF (ParaView_SOURCE_DIR)\n  INCLUDE_DIRECTORIES(\n    ${PARAVIEW_INCLUDE_DIRS}\n    ${PARAVIEW_GUI_INCLUDE_DIRS}\n    ${PARAVIEW_KWSYS_INCLUDE_DIRS}\n  )\nELSE (ParaView_SOURCE_DIR)\n  FIND_PACKAGE(ParaView REQUIRED)\n  INCLUDE(${PARAVIEW_USE_FILE})\nENDIF (ParaView_SOURCE_DIR)\n\n#find where all vapor header files live (especially vaporinternal/common.h)\nFIND_PATH (VAPOR_HEADERS\n  vaporinternal/common.h\n  PATHS /ThirdPartyLibraries/VAPOR/source/vapor-1.5.2/vapor/include\n  DOC \"NCAR Vapor source directory, where include/vaporinternal/common.h can be found\"\n  )\n\n#include the parts of vapor that we need to compile the reader\n#both vapor/ and vaporinternal/ are underneath this\nINCLUDE_DIRECTORIES(${VAPOR_HEADERS})\n\n#link to the parts of vapor lib that we need to run/compile the reader\nFIND_LIBRARY(VAPOR_VDF_LIB vdf DOC \"NCAR Vapor Data Format library\")\nFIND_LIBRARY(VAPOR_COMMON_LIB common DOC \"NCAR Vapor common libary\")\n\n#find expat and netcdf libs that vapor library itself uses\nFIND_PACKAGE(EXPAT REQUIRED)\nINCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIRS})\nFIND_LIBRARY(VAPOR_NETCDF_LIB netcdf DOC \"NetCDF library required for VAPOR plugin\")\n\nADD_PARAVIEW_PLUGIN(VDFReaderPlugin \"1.0\"\n  SERVER_MANAGER_XML VDFReader.xml\n  SERVER_MANAGER_SOURCES vtkVDFReader.cxx\n  GUI_RESOURCE_FILES VDFReaderGUI.xml)\n\nTARGET_LINK_LIBRARIES(VDFReaderPlugin\n  ${VAPOR_VDF_LIB} ${VAPOR_COMMON_LIB}\n  ${EXPAT_LIBRARIES} ${VAPOR_NETCDF_LIB} )\n\n"
  },
  {
    "path": "plugins/paraview/README",
    "content": "===============\n How To Build\n===============\n\nFrom the source folder, run:\n  ccmake .\n  \nThen press 'c' to configure, CMake will attempt to find ParaView and the Vapor libraries and include directory. You may need to specify these variables manually:\n\nParaView_DIR      path to your local ParaView build directory\nVAPOR_COMMON_LIB  path to libcommon.so (from Vapor binaries) \nVAPOR_HEADERS     path to Vapor include directory (from Vapor Source)\nVAPOR_NETCDF_LIB  path to libnetcdf.so \nVAPOR_VDF_LIB     path to libvdf.so    (from Vapor binaries)\n\nThen press 'c' to configure again. If there are no errors, press 'g' to generate a Makefile and exit ccmake. To build the shared object (plugin) run:\n  make \n\n"
  },
  {
    "path": "plugins/paraview/VDFReader.xml",
    "content": "<ServerManagerConfiguration>\n  <!-- Begin VDFReader -->\n  <ProxyGroup name=\"sources\">\n    <SourceProxy name=\"VDFReader\" class=\"vtkVDFReader\" label=\"VDF Reader\">\n      <Documentation\n        short_help=\"Read NCAR Vapor files.\"\n        long_help=\"Read NCAR Vapor format atmospheric, oceanic, and solar research format files.\">\n        The Vapor Data Format (VDF) reader loads wavelet compressed data files. The refinement parameter controls the resolution of the data that is read in which gives you a speed/fidelity tradeoff control. See http://www.vapor.ucar.edu.\n      </Documentation>\n\n      <StringVectorProperty\n        name=\"FileName\"\n        command=\"SetFileName\"\n        number_of_elements=\"1\">\n        <FileListDomain name=\"files\"/>\n      </StringVectorProperty>\n\n      <IntVectorProperty\n         name=\"RefinementRangeInfo\"\n         command=\"GetRefinementRange\"\n         number_of_elements=\"2\"\n         default_values=\"0 0\"\n         information_only=\"1\">\n         <SimpleIntInformationHelper/>\n      </IntVectorProperty>\n\n      <IntVectorProperty\n         name=\"Refinement\"\n         command=\"SetRefinement\"\n         number_of_elements=\"1\"\n         default_values=\"0\"\n         animateable=\"0\"\n         information_property=\"RefinementRangeInfo\" >\n        <IntRangeDomain name=\"range\">\n           <RequiredProperties>\n              <Property name=\"RefinementRangeInfo\" function=\"Range\"/>\n           </RequiredProperties>\n        </IntRangeDomain>\n        <Documentation>\n          This property controls the maximum refinement level\n        </Documentation>\n      </IntVectorProperty> \n\n      <IntVectorProperty\n    \tname=\"Variable Type\"\n    \tcommand=\"SetVariableType\"\n    \tnumber_of_elements=\"1\"\n    \tdefault_values=\"0\">\n\t\t<EnumerationDomain name=\"enum\">\n\t\t  <Entry value=\"0\" text=\"3D XYZ\" />\n\t\t  <Entry value=\"1\" text=\"2D  XY\" />\n\t\t  <Entry value=\"2\" text=\"2D  XZ\" />\n\t\t  <Entry value=\"3\" text=\"2D  YZ\" />\n\t\t</EnumerationDomain>\n      </IntVectorProperty>\n\n\t  <StringVectorProperty\n\t    name=\"PointArrayInfo\"\n\t\tinformation_only=\"1\" >\n\t\t<ArraySelectionInformationHelper\n\t\t  attribute_name=\"Point\" />\n\t  </StringVectorProperty>\n\n\t  <StringVectorProperty\n\t    name=\"PointArrayStatus\" command=\"SetPointArrayStatus\"\n\t\tnumber_of_elements=\"0\"\n\t\trepeat_command=\"1\" number_of_elements_per_command=\"2\"\n\t\telement_types=\"2 0\"\n\t\tinformation_property=\"PointArrayInfo\"\n\t\tlabel=\"Point Arrays\">\n\t\t<ArraySelectionDomain name=\"array_list\">\n\t\t  <RequiredProperties>\n\t\t  \t<Property name=\"PointArrayInfo\"\n\t\t\t          function=\"ArrayList\" />\n\t\t  </RequiredProperties>\n\t\t</ArraySelectionDomain>\n\t  </StringVectorProperty>\n\t\n      <IntVectorProperty\n    \tname=\"Cache size (MB)\"\n    \tcommand=\"SetCacheSize\"\n    \tnumber_of_elements=\"1\"\n    \tdefault_values=\"1024\">\n      </IntVectorProperty>\n\n      <DoubleVectorProperty\n\t    name=\"TimeRange\"\n\t\tinformation_only=\"1\" >\n\t\t<TimeRangeInformationHelper/>\n      </DoubleVectorProperty>\n\n      <DoubleVectorProperty\n\t    \tname=\"TimestepValues\"\n\t\tinformation_only=\"1\" >\n\t\t<TimeStepsInformationHelper/>\n      </DoubleVectorProperty>\n\n      <Hints>\n        <ReaderFactory extensions=\"vdf\"\n           file_description=\"Vapor Data File\"/>\n      </Hints>\n\n    </SourceProxy>\n  </ProxyGroup>\n  <!-- End VDFReader -->\n</ServerManagerConfiguration>\n"
  },
  {
    "path": "plugins/paraview/VDFReaderGUI.xml",
    "content": "<ParaViewReaders>\n  <Reader name=\"VDFReader\"\n    extensions=\"vdf\"\n    file_description=\"Vapor Data File\">\n  </Reader>\n</ParaViewReaders>\n"
  },
  {
    "path": "plugins/paraview/vtkVDFReader.cxx",
    "content": "/*========================================================================= Visualization and Analysis Platform for Ocean, Atmosphere, and Solar Researchers (VAPOR)\n  Terms of Use\n\n  This VAPOR (the Software ) was developed by the University\n  Corporation for Atmospheric Research.\n\n  PLEASE READ THIS SOFTWARE LICENSE AGREEMENT (\"AGREEMENT\") CAREFULLY.\n  INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE  I ACCEPT\n  BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE\n  TERMS OF THIS AGREEMENT, SELECT THE  I DON?T ACCEPT? BUTTON AND THE\n  INSTALLATION PROCESS WILL NOT CONTINUE.\n\n  1.      License.  The University Corporation for Atmospheric Research\n  (UCAR) grants you a non-exclusive right to use, create derivative\n  works, publish, distribute, disseminate, transfer, modify, revise and\n  copy the Software.\n\n  2.      Proprietary Rights.  Title, ownership rights, and intellectual\n  property rights in the Software shall remain in UCAR.\n\n  3.      Disclaimer of Warranty on Software. You expressly acknowledge\n  and agree that use of the Software is at your sole risk. The Software\n  is provided \"AS IS\" and without warranty of any kind and UCAR\n  EXPRESSLY DISCLAIMS ALL WARRANTIES AND/OR CONDITIONS OF ANY KIND,\n  EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OR\n  CONDITIONS OF TITLE, NON-INFRINGEMENT OF A THIRD PARTY?S INTELLECTUAL\n  PROPERTY, MERCHANTABILITY OR SATISFACTORY QUALITY AND FITNESS FOR A\n  PARTICULAR PURPOSE. UCAR DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED\n  IN THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF\n  THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN\n  THE SOFTWARE WILL BE CORRECTED. FURTHERMORE, UCAR DOES NOT WARRANT OR\n  MAKE ANY REPRESENTATIONS AND YOU ASSUME ALL RISK REGARDING THE USE OR\n  THE RESULTS OF THE USE OF THE SOFTWARE OR RELATED DOCUMENTATION IN\n  TERMS OF THEIR CORRECTNESS, ACCURACY, RELIABILITY, OR OTHERWISE. THE\n  PARTIES EXPRESSLY DISCLAIM THAT THE UNIFORM COMPUTER INFORMATION\n  TRANSACTIONS ACT (UCITA) APPLIES TO OR GOVERNS THIS AGREEMENT.  No\n  oral or written information or advice given by UCAR or a UCAR\n  authorized representative shall create a warranty or in any way\n  increase the scope of this warranty. Should the Software prove\n  defective, you (and not UCAR or any UCAR representative) assume the\n  cost of all necessary correction.\n\n  4.      Limitation of Liability.  UNDER NO CIRCUMSTANCES, INCLUDING\n  NEGLIGENCE, SHALL UCAR OR ITS COLLABORATORS, INCLUDING OHIO STATE\n  UNIVERSITY, BE LIABLE FOR ANY DIRECT, INCIDENTAL, SPECIAL, INDIRECT OR\n  CONSEQUENTIAL DAMAGES INCLUDING LOST REVENUE, PROFIT OR DATA, WHETHER\n  IN AN ACTION IN CONTRACT OR TORT ARISING OUT OF OR RELATING TO THE USE\n  OF OR INABILITY TO USE THE SOFTWARE, EVEN IF UCAR HAS BEEN ADVISED OF\n  THE POSSIBILITY OF SUCH DAMAGES.\n\n  5.      Compliance with Law. All Software and any technical data\n  delivered under this Agreement are subject to U.S. export control laws\n  and may be subject to export or import regulations in other countries.\n  You agree to comply strictly with all applicable laws and regulations\n  in connection with use and distribution of the Software, including\n  export control laws, and you acknowledge that you have responsibility\n  to obtain any required license to export, re-export, or import as may\n  be required.\n\n  6.      No Support/Modifications. The names UCAR/NCAR and SCD may not\n  be used in any advertising or publicity to endorse or promote any\n  products or commercial entity unless specific written permission is\n  obtained from UCAR.  The Software is provided without any support or\n  maintenance, and without any obligation to provide you with\n  modifications, improvements, enhancements, or updates of the Software.\n\n  7.      Controlling Law and Severability.  This Agreement shall be\n  governed by the laws of the United States and the State of Colorado.\n  If for any reason a court of competent jurisdiction finds any\n  provision, or portion thereof, to be unenforceable, the remainder of\n  this Agreement shall continue in full force and effect. This Agreement\n  shall not be governed by the United Nations Convention on Contracts\n  for the International Sale of Goods, the application of which is\n  hereby expressly excluded.\n\n  8.      Termination.  Your rights under this Agreement will terminate\n  automatically without notice from UCAR if you fail to comply with any\n  term(s) of this Agreement.   You may terminate this Agreement at any\n  time by destroying the Software and any related documentation and any\n  complete or partial copies thereof.  Upon termination, all rights\n  granted under this Agreement shall terminate.  The following\n  provisions shall survive termination: Sections 2, 3, 4, 7 and 10.\n\n  9.      Complete Agreement. This Agreement constitutes the entire\n  agreement between the parties with respect to the use of the Software\n  and supersedes all prior or contemporaneous understandings regarding\n  such subject matter. No amendment to or modification of this Agreement\n  will be binding unless in a writing and signed by UCAR.\n\n  10.  Notices and Additional Terms.  Each copy of the Software shall\n  include a copy of this Agreement and the following notice:\n\n  \"The source of this material is the Science Computing Division of the\n  National Center for Atmospheric Research, a program of the University\n  Corporation for Atmospheric Research (UCAR) pursuant to a Cooperative\n  Agreement with the National Science Foundation; Copyright (c)2006 University\n  Corporation for Atmospheric Research. All Rights Reserved.\"\n\n  This notice shall be displayed on any documents, media, printouts, and\n  visualizations or on any other electronic or tangible expressions\n  associated with, related to or derived from the Software or associated\n  documentation.\n\n  The Software includes certain copyrighted, segregable components\n  listed below (the Third Party Code?), including software developed by\n  Ohio State University.  For this reason, you must check the source\n  identified below for additional notice requirements and terms of use\n  that apply to your use of this Software.\n\n--------------------------------------------------------------------------\n\n  Program:   Visualization Toolkit\n  Module:    vtkVDFReader.cxx\n\n  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen\n  All rights reserved.\n  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.\n\n  This software is distributed WITHOUT ANY WARRANTY; without even\n  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n  PURPOSE.  See the above copyright notice for more information.\n\n=========================================================================*/\n\n#include \"vtkVDFReader.h\"\n#include \"vtkInformation.h\"\n#include \"vtkInformationVector.h\"\n#include \"vtkObjectFactory.h\"\n#include \"vtkImageAlgorithm.h\"\n#include \"vtkImageData.h\"\n#include \"vtkDataArray.h\"\n#include \"vtkFloatArray.h\"\n#include \"vtkPointData.h\"\n#include \"vtkCellData.h\"\n#include \"vtkStreamingDemandDrivenPipeline.h\"\n\nusing namespace VAPoR;\n\nvtkStandardNewMacro(vtkVDFReader);\n\n//-----------------------------------------------------------------------------\nvtkVDFReader::vtkVDFReader()\n{\n\n  this->FileName = 0;\n  this->SetNumberOfInputPorts(0);\n  this->SetNumberOfOutputPorts(1);\n  this->Refinement = 0;\n  this->nTimeSteps = 0;\n  this->TimeSteps = NULL;\n  this->TimeStep = 0;\n  this->vdc_md = NULL;\n  this->data_mgr = NULL;\n  this->vdfiobase = NULL;\n\n  this->CacheSize = 1000;\n  this->height_factor = 4;\n  this->RefinementRange[0]=0;\n  this->RefinementRange[1]=5;\n}\n\n//-----------------------------------------------------------------------------\nvtkVDFReader::~vtkVDFReader()\n{\n  this->SetFileName(0);\n  delete data_mgr;\n  delete vdfiobase;\n  delete vdc_md;\n  delete TimeSteps;\n}\n\n\n//-----------------------------------------------------------------------------\nint vtkVDFReader::RequestData(vtkInformation *request,\n                              vtkInformationVector **inputVector,\n                              vtkInformationVector *outputVector)\n{\n  // extract data objects\n  vtkImageData *image = vtkImageData::GetData(outputVector);\n  vtkInformation *info = outputVector->GetInformationObject(0);\n\n  // setup initial boundaries\n  int ext[6] = {0, (int)ext_p[0], 0, (int)ext_p[1], 0, (int)ext_p[2]};\n  int ext_minus_one[6] = {0, (int)ext_p[0]-1,\n                          0, (int)ext_p[1]-1,\n                          0, (int)ext_p[2]-1};\n  int *updateExt, front_pad[] = {0,0,0};\n\n  size_t bdim[3], udim[3];\n  GetVarDims(udim, bdim);\n  const size_t *bmsize=vdc_md->GetBlockSize();\n\n  size_t data_size[3] = {bmsize[0]*bdim[0],\n                         bmsize[1]*bdim[1],\n                         bmsize[2]*bdim[2]};\n  size_t v_min[3] = {0,0,0};\n  size_t v_max[3] = {bdim[0]-1, bdim[1]-1, bdim[2]-1};\n\n  // update boundaries to only load the needed data from disk\n  updateExt = info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());\n  if (/*true*/! extentsMatch(updateExt, ext))\n    {\n    //printf(\"Recived sub-block of extents: %d %d %d %d %d %d\\n\",\n    //        updateExt[0], updateExt[1], updateExt[2],\n    //        updateExt[3], updateExt[4], updateExt[5]);\n\n    size_t v0[]={updateExt[0],updateExt[2],updateExt[4]};\n    size_t v1[]={updateExt[1],updateExt[3],updateExt[5]};\n    vdfiobase->MapVoxToBlk(v0, v_min);\n    vdfiobase->MapVoxToBlk(v1, v_max);\n\n    for (int i=0; i<6; i+=2)\n      {\n      ext_minus_one[i] = updateExt[i]; ext_minus_one[i+1] = updateExt[i+1];\n      ext[i] = updateExt[i]; ext[i+1] = updateExt[i+1]+1;\n      data_size[i/2] = (1 + v_max[i/2] - v_min[i/2]) * bmsize[i/2];\n      front_pad[i/2] = v_min[i/2] * bmsize[i/2];\n      }\n    }\n\n  // setup image memory\n  image->SetExtent(ext_minus_one);\n  image->SetScalarTypeToFloat();\n  image->AllocateScalars();\n\n  // get the correct timestep\n  if (info->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS()))\n    {\n    double *TimeStepsReq =\n      info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS());\n    TimeStep = (int)floor(TimeStepsReq[0]);\n    SetExtents(info);\n    //printf(\"Recieved updated timestep: %d\\n\", TimeStep);\n    }\n\n  // load data for all enabled point arrays\n  for (vtkstd::map<vtkstd::string,int>::iterator it = data.begin(); it !=data.end(); ++it)\n    {\n    if (it->second == 0)\n      {\n      continue;\n      }\n\n    vtkFloatArray* scalars = vtkFloatArray::New();\n    scalars->SetName(it->first.c_str());\n    scalars->SetNumberOfValues((ext[1]-ext[0])*(ext[3]-ext[2])*(ext[5]-ext[4]));\n\n    SetProgressText(\"Loading VDC Data\");\n    //check that data exists on disk for this var/ref/time\n    if (!vdfiobase->VariableExists(TimeStep, it->first.c_str(), this->Refinement))\n      {\n      vtkErrorMacro(<< it->first << \" data does not exist at time: \"\n                    << TimeStep);\n      return 0;\n      }\n    //load data into memory\n    float *vapor_data = data_mgr->GetRegion(TimeStep, it->first.c_str(),\n                                            this->Refinement, v_min, v_max);\n    //verify data pointer\n    if (vapor_data == NULL)\n      {\n      vtkErrorMacro(<< \"Data manager returned NULL pointer.\");\n      return 0;\n      }\n\n    //copy data to return memory (stripping block-padding)\n    vtkIdType iReal=0;\n    for (vtkIdType z = ext[4]; z < ext[5]; z++)\n      {\n      for (vtkIdType y = ext[2]; y < ext[3]; y++)\n        {\n        for (vtkIdType x = ext[0]; x < ext[1]; x++)\n          {\n          scalars->SetValue\n            (iReal,\n             vapor_data[(z-front_pad[2]) *data_size[1]*data_size[0] +\n                        (y-front_pad[1]) *data_size[0] +\n                        (x-front_pad[0]) ]\n             );\n          iReal++;\n          }\n        }\n      this->UpdateProgress((float)z/(1+ext[5]));\n      }\n\n    image->GetPointData()->AddArray(scalars);\n    if (!image->GetPointData()->GetScalars())\n      {\n      image->GetPointData()->SetScalars(scalars);\n      }\n    scalars->Delete();\n    }\n\n  return 1;\n}\n\n//-----------------------------------------------------------------------------\nint vtkVDFReader::RequestInformation(vtkInformation *request,\n                                     vtkInformationVector **inputVector,\n                                     vtkInformationVector *outputVector)\n{\n  vtkInformation *outInfo = outputVector->GetInformationObject(0);\n\n  //only perform the initial allocations once\n  if (vdc_md == NULL)\n    {\n    //create metadataVDC for this file\n    vdc_md = new Metadata(FileName);\n    RefinementRange[1] = vdc_md->GetNumTransforms();\n\n    //create vdf base class from metadata\n    vdfiobase = new WaveletBlock3DRegionReader(vdc_md);\n    //create data manager from metadata\n    data_mgr = new DataMgr(vdc_md, this->CacheSize);\n\n    //add each variable to the list, intially off (i.e 0)\n    const vtkstd::vector<vtkstd::string> NamesAll = vdc_md->GetVariableNames();\n    for (size_t i=0; i<NamesAll.size(); i++)\n      {\n      data[NamesAll[i]] = 0;\n      }\n\n    //Find valid timesteps, communicate through pipeline\n    FillTimeSteps();\n    double TimeRange[2] = {TimeSteps[0], TimeSteps[nTimeSteps-1]};\n    outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(),\n                 TimeSteps, nTimeSteps);\n    outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(),\n                 TimeRange, 2);\n    }\n\n  SetExtents(outInfo);\n\n  return 1;\n}\n\n//-----------------------------------------------------------------------------\nvoid vtkVDFReader::PrintSelf(ostream& os, vtkIndent indent)\n{\n  this->Superclass::PrintSelf(os, indent);\n  os << indent << \"FileName: \"\n     << (this->FileName ? this->FileName : \"(NULL)\") << endl;\n\n  os << indent << \"VariableType \" << this->VariableType << endl;\n  os << indent << \"Refinement \" << this->Refinement << endl;\n  os << indent << \"CacheSize \" << this->CacheSize << endl;\n}\n\n//-----------------------------------------------------------------------------\nint vtkVDFReader::CanReadFile(const char *fname)\n{\n  //TODO: Do some quick check on whether the file actually is in VDF format\n  return 1;\n}\n\n//-----------------------------------------------------------------------------\nvoid vtkVDFReader::SetRefinement(int newref)\n{\n  if (newref == this->Refinement)\n    {\n    return;\n    }\n\n  //printf(\"refinement level changed to: %d\\n\", newref);\n  this->Refinement = newref;\n  this->Modified();\n}\n\n//-----------------------------------------------------------------------------\nvoid vtkVDFReader::SetCacheSize(int newSize)\n{\n  if (newSize == this->CacheSize)\n    {\n    return;\n    }\n\n  //printf(\"cache size changed to: %d\\n\", newSize);\n  this->CacheSize = newSize;\n\n  if (data_mgr != NULL) {\n      delete data_mgr;\n      data_mgr  = new DataMgr(vdc_md, this->CacheSize);\n      this->Modified();\n  }\n\n}\n\n//-----------------------------------------------------------------------------\nvoid vtkVDFReader::SetVariableType(int newtype)\n{\n  if (newtype == this->VariableType)\n    {\n    return;\n    }\n\n  //printf(\"var type changed to: %d\\n\", newtype);\n  this->VariableType = newtype;\n  data.clear();\n  this->Modified();\n}\n\n//-----------------------------------------------------------------------------\nint vtkVDFReader::FillTimeSteps()\n{\n  //get list of all possible variables in metadata\n  const vtkstd::vector<vtkstd::string> nms = vdc_md->GetVariableNames();\n\n  //get all possible timesteps\n  int tmp_nTimeSteps = vdc_md->GetNumTimeSteps();\n  TimeSteps = new double[tmp_nTimeSteps];\n\n  //number of valid timesteps, start a 0\n  nTimeSteps = 0;\n  for (int i=0; i<tmp_nTimeSteps; i++)\n    {\n    bool good = false;\n    for (size_t j=0; j<nms.size() && !good; j++)\n      {\n      //find at least one variable existing to validate timestep\n      if (vdfiobase->VariableExists(i, nms[j].c_str()) != 0)\n        {\n        TimeSteps[nTimeSteps++] = (double)i;\n        good=true;  //exit inner loop on first valid var\n        }\n      }\n    }\n\n  //set current timestep to first valid time\n  TimeStep = (int) TimeSteps[0];\n\n  return nTimeSteps;\n}\n\n//-----------------------------------------------------------------------------\nbool vtkVDFReader::extentsMatch(int *a, int *b)\n{\n  for (int i=0; i<6; i++)\n    {\n    if (a[i] != b[i]) return false;\n    }\n  return true;\n}\n\n//-----------------------------------------------------------------------------\nint vtkVDFReader::GetNumberOfPointArrays()\n{\n  return current_var_list.size();\n}\n\n//-----------------------------------------------------------------------------\nconst char *vtkVDFReader::GetPointArrayName(int index)\n{\n  return current_var_list[index].c_str();\n}\n\n//-----------------------------------------------------------------------------\nint vtkVDFReader::GetPointArrayStatus(const char* name)\n{\n  return data[vtkstd::string(name)];\n}\n\n//-----------------------------------------------------------------------------\nvoid vtkVDFReader::SetPointArrayStatus(const char* name, int en)\n{\n  if (en != data[vtkstd::string(name)])\n    {\n    data[vtkstd::string(name)] = en;\n    this->Modified();\n    }\n}\n\n//-----------------------------------------------------------------------------\nvoid vtkVDFReader::GetVarDims(size_t *udims, size_t *bdims)\n{\n  vdfiobase->GetDim(udims, this->Refinement);\n  vdfiobase->GetDimBlk(bdims, this->Refinement);\n}\n\n//-----------------------------------------------------------------------------\nvoid vtkVDFReader::SetExtents(vtkInformation *outInfo)\n{\n\n  //Get user extents for this variable, refinement level, and timestep\n  const vtkstd::vector<double> glExt = vdc_md->GetExtents(),\n    tsExt = vdc_md->GetTSExtents(TimeStep);\n  uExt = (vtkstd::vector<double>) (tsExt.empty()? glExt: tsExt);\n\n  vdfiobase->GetDim(ext_p, this->Refinement);\n  int ext[6] = {0, (int)ext_p[0]-1, 0, (int)ext_p[1]-1, 0, (int)ext_p[2]-1};\n\n  vtkstd::vector<vtkstd::string> var_list;\n  switch (this->VariableType) {\n  case 0:\n    var_list = (vtkstd::vector<vtkstd::string>) vdc_md->GetVariables3D();\n    break;\n  case 1:\n    var_list = (vtkstd::vector<vtkstd::string>) vdc_md->GetVariables2DXY();\n    ext[5] = 0;\n    break;\n  case 2:\n    var_list = (vtkstd::vector<vtkstd::string>) vdc_md->GetVariables2DXZ();\n    ext[3] = 0;\n    break;\n  case 3:\n    var_list = (vtkstd::vector<vtkstd::string>) vdc_md->GetVariables2DYZ();\n    ext[1] = 0;\n    break;\n  default :\n    vtkErrorMacro(<< \" FATAL: bad type: \" << this->VariableType);\n    break;\n  }\n\n  //rearrange user extents to expected array formats, communicate down pipeline\n  double origin[3] = {uExt[0], uExt[1], uExt[2]};\n  //double bbox[6] = {uExt[0], uExt[3], uExt[1], uExt[4], uExt[2], uExt[5]};\n  double spacing[3] = {(uExt[3]-uExt[0])/(ext[1]+1),\n                       (uExt[4]-uExt[1])/(ext[3]+1),\n                       (uExt[5]-uExt[2])/(ext[5]+1)};\n\n  outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), ext, 6);\n  //outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_BOUNDING_BOX(),\n  //bbox, 6);\n  outInfo->Set(vtkDataObject::ORIGIN(), origin, 3);\n  outInfo->Set(vtkDataObject::SPACING(), spacing, 3);\n\n  //copy list of vars, excluding those for which no data exists:\n  current_var_list.clear();\n  for (size_t i=0; i<var_list.size(); ++i)\n    {\n    if (vdfiobase->VariableExists(TimeStep,\n                                  var_list[i].c_str(), this->Refinement) != 0)\n      {\n      current_var_list.push_back(var_list[i]);\n      }\n    }\n}\n"
  },
  {
    "path": "plugins/paraview/vtkVDFReader.h",
    "content": "/*=========================================================================\n\n  Visualization and Analysis Platform for Ocean, Atmosphere, and Solar\n  Researchers (VAPOR)\n  Terms of Use\n\n  This VAPOR (the Software ) was developed by the University\n  Corporation for Atmospheric Research.\n\n  PLEASE READ THIS SOFTWARE LICENSE AGREEMENT (\"AGREEMENT\") CAREFULLY.\n  INDICATE YOUR ACCEPTANCE OF THESE TERMS BY SELECTING THE  I ACCEPT\n  BUTTON AT THE END OF THIS AGREEMENT. IF YOU DO NOT AGREE TO ALL OF THE\n  TERMS OF THIS AGREEMENT, SELECT THE  I DON?T ACCEPT? BUTTON AND THE\n  INSTALLATION PROCESS WILL NOT CONTINUE.\n\n  1.      License.  The University Corporation for Atmospheric Research\n  (UCAR) grants you a non-exclusive right to use, create derivative\n  works, publish, distribute, disseminate, transfer, modify, revise and\n  copy the Software.\n\n  2.      Proprietary Rights.  Title, ownership rights, and intellectual\n  property rights in the Software shall remain in UCAR.\n\n  3.      Disclaimer of Warranty on Software. You expressly acknowledge\n  and agree that use of the Software is at your sole risk. The Software\n  is provided \"AS IS\" and without warranty of any kind and UCAR\n  EXPRESSLY DISCLAIMS ALL WARRANTIES AND/OR CONDITIONS OF ANY KIND,\n  EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OR\n  CONDITIONS OF TITLE, NON-INFRINGEMENT OF A THIRD PARTY?S INTELLECTUAL\n  PROPERTY, MERCHANTABILITY OR SATISFACTORY QUALITY AND FITNESS FOR A\n  PARTICULAR PURPOSE. UCAR DOES NOT WARRANT THAT THE FUNCTIONS CONTAINED\n  IN THE SOFTWARE WILL MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF\n  THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN\n  THE SOFTWARE WILL BE CORRECTED. FURTHERMORE, UCAR DOES NOT WARRANT OR\n  MAKE ANY REPRESENTATIONS AND YOU ASSUME ALL RISK REGARDING THE USE OR\n  THE RESULTS OF THE USE OF THE SOFTWARE OR RELATED DOCUMENTATION IN\n  TERMS OF THEIR CORRECTNESS, ACCURACY, RELIABILITY, OR OTHERWISE. THE\n  PARTIES EXPRESSLY DISCLAIM THAT THE UNIFORM COMPUTER INFORMATION\n  TRANSACTIONS ACT (UCITA) APPLIES TO OR GOVERNS THIS AGREEMENT.  No\n  oral or written information or advice given by UCAR or a UCAR\n  authorized representative shall create a warranty or in any way\n  increase the scope of this warranty. Should the Software prove\n  defective, you (and not UCAR or any UCAR representative) assume the\n  cost of all necessary correction.\n\n  4.      Limitation of Liability.  UNDER NO CIRCUMSTANCES, INCLUDING\n  NEGLIGENCE, SHALL UCAR OR ITS COLLABORATORS, INCLUDING OHIO STATE\n  UNIVERSITY, BE LIABLE FOR ANY DIRECT, INCIDENTAL, SPECIAL, INDIRECT OR\n  CONSEQUENTIAL DAMAGES INCLUDING LOST REVENUE, PROFIT OR DATA, WHETHER\n  IN AN ACTION IN CONTRACT OR TORT ARISING OUT OF OR RELATING TO THE USE\n  OF OR INABILITY TO USE THE SOFTWARE, EVEN IF UCAR HAS BEEN ADVISED OF\n  THE POSSIBILITY OF SUCH DAMAGES.\n\n  5.      Compliance with Law. All Software and any technical data\n  delivered under this Agreement are subject to U.S. export control laws\n  and may be subject to export or import regulations in other countries.\n  You agree to comply strictly with all applicable laws and regulations\n  in connection with use and distribution of the Software, including\n  export control laws, and you acknowledge that you have responsibility\n  to obtain any required license to export, re-export, or import as may\n  be required.\n\n  6.      No Support/Modifications. The names UCAR/NCAR and SCD may not\n  be used in any advertising or publicity to endorse or promote any\n  products or commercial entity unless specific written permission is\n  obtained from UCAR.  The Software is provided without any support or\n  maintenance, and without any obligation to provide you with\n  modifications, improvements, enhancements, or updates of the Software.\n\n  7.      Controlling Law and Severability.  This Agreement shall be\n  governed by the laws of the United States and the State of Colorado.\n  If for any reason a court of competent jurisdiction finds any\n  provision, or portion thereof, to be unenforceable, the remainder of\n  this Agreement shall continue in full force and effect. This Agreement\n  shall not be governed by the United Nations Convention on Contracts\n  for the International Sale of Goods, the application of which is\n  hereby expressly excluded.\n\n  8.      Termination.  Your rights under this Agreement will terminate\n  automatically without notice from UCAR if you fail to comply with any\n  term(s) of this Agreement.   You may terminate this Agreement at any\n  time by destroying the Software and any related documentation and any\n  complete or partial copies thereof.  Upon termination, all rights\n  granted under this Agreement shall terminate.  The following\n  provisions shall survive termination: Sections 2, 3, 4, 7 and 10.\n\n  9.      Complete Agreement. This Agreement constitutes the entire\n  agreement between the parties with respect to the use of the Software\n  and supersedes all prior or contemporaneous understandings regarding\n  such subject matter. No amendment to or modification of this Agreement\n  will be binding unless in a writing and signed by UCAR.\n\n  10.  Notices and Additional Terms.  Each copy of the Software shall\n  include a copy of this Agreement and the following notice:\n\n  \"The source of this material is the Science Computing Division of the\n  National Center for Atmospheric Research, a program of the University\n  Corporation for Atmospheric Research (UCAR) pursuant to a Cooperative\n  Agreement with the National Science Foundation; Copyright (c)2006 University\n  Corporation for Atmospheric Research. All Rights Reserved.\"\n\n  This notice shall be displayed on any documents, media, printouts, and\n  visualizations or on any other electronic or tangible expressions\n  associated with, related to or derived from the Software or associated\n  documentation.\n\n  The Software includes certain copyrighted, segregable components\n  listed below (the Third Party Code?), including software developed by\n  Ohio State University.  For this reason, you must check the source\n  identified below for additional notice requirements and terms of use\n  that apply to your use of this Software.\n\n--------------------------------------------------------------------------\n\n  Program:   Visualization Toolkit\n  Module:    vtkVDFReader.cxx\n\n  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen\n  All rights reserved.\n  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.\n\n  This software is distributed WITHOUT ANY WARRANTY; without even\n  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n  PURPOSE.  See the above copyright notice for more information.\n\n=========================================================================*/\n// .NAME vtkVDFReader - class for reader Vapor Data Format files\n// .Section Description\n// vtkVDFReader uses the Vapor library to read wavelet compressed VDF files\n// and produce VTK data image data. The resolution of the image data is\n// controlled by the refinement parameter.\n//\n\n#ifndef _vtkVDFReader_h\n#define _vtkVDFReader_h\n\n#include \"vtkImageAlgorithm.h\"\n\n#include \"vapor/DataMgr.h\"                       //needed for vapor datastructures\n#include \"vapor/WaveletBlock3DRegionReader.h\"    //needed for vapor datastructures\n\n#include <vtkstd/map>       //needed for protected ivars\n#include <vtkstd/vector>    //needed for protected ivars\n#include <vtkstd/string>    //needed for protected ivars\n\n// using namespace std;\nusing namespace VAPoR;\n\nclass VTK_EXPORT vtkVDFReader : public vtkImageAlgorithm {\npublic:\n    static vtkVDFReader *New();\n    vtkTypeMacro(vtkVDFReader, vtkImageAlgorithm);\n    void PrintSelf(ostream &os, vtkIndent indent);\n\n    // Description:\n    // Choose file to read\n    vtkSetStringMacro(FileName);\n    vtkGetStringMacro(FileName);\n\n    // Description:\n    // Check file for suitability to this reader\n    int CanReadFile(const char *fname);\n\n    // Description:\n    // Set resolution within range provided by data.\n    void SetRefinement(int);\n    vtkGetMacro(Refinement, int);\n    vtkGetVector2Macro(RefinementRange, int);\n\n    // Description:\n    void SetVariableType(int);\n    vtkGetMacro(VariableType, int);\n\n    // Description:\n    void SetCacheSize(int);\n    vtkGetMacro(CacheSize, int);\n\n    // Description:\n    // Choose which arrays to load\n    int         GetPointArrayStatus(const char *);\n    void        SetPointArrayStatus(const char *, int);\n    int         GetNumberOfPointArrays();\n    const char *GetPointArrayName(int);\n\nprotected:\n    vtkVDFReader();\n    ~vtkVDFReader();\n    int RequestInformation(vtkInformation *, vtkInformationVector **, vtkInformationVector *);\n    int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *);\n    int FillTimeSteps();\n\n    char *FileName;\n\n    Metadata * vdc_md;\n    DataMgr *  data_mgr;\n    VDFIOBase *vdfiobase;\n\n    bool    is_layered;\n    int     height_factor;\n    int     num_levels;\n    size_t  ext_p[3];\n    int     Refinement;\n    int     VariableType;\n    int     CacheSize;\n    double *TimeSteps;\n    int     nTimeSteps;\n    int     TimeStep;\n    int     RefinementRange[2];\n\n    // BTX\n    vtkstd::map<vtkstd::string, int> data;\n    vtkstd::vector<double>           uExt;\n    vtkstd::vector<vtkstd::string>   current_var_list;\n    // ETX\n\nprivate:\n    vtkVDFReader(const vtkVDFReader &);\n    void operator=(const vtkVDFReader &);\n    bool extentsMatch(int *, int *);\n    void GetVarDims(size_t *, size_t *);\n    void SetExtents(vtkInformation *);\n};\n#endif\n"
  },
  {
    "path": "plugins/visit/VDC/README",
    "content": "VisIt VDC Reader Plugin\n\nThe contents of this directory provide a VAPOR Data Collection (VDC) import\nplugin for VisIt (https://wci.llnl.gov/codes/visit/home.html). \n\n\n===============\n How To Build\n===============\n\nNote:  That you do not need to have built your own version of Visit\nor VAPoR, this will work with downloaded binary version.  This code has\nbeen tested Mac and Linux platforms for VisIt 2.3.0 and VAPOR 2.1\n\n----------------------\n\n1) Install VisIt and VAPOR on your system.\n\n2) Edit the vdf.xml file and make sure that the libray and include\npaths are correct for your installation of Vapor.  You will need to\nset the CFLAGS and LDFLAGS elements as appropriate. \n\nAlso, make sure that you include paths to any other dependent\nlibraries (i.e libcurl for netcdf4).\n\nYou may also need to edit the LIBS element (for linux the 'rt'\nlibrary is required).\n\nFor more information see \"Getting Data Into VisIT\" available from:\nhttps://wci.llnl.gov/codes/visit/manuals.html\n\n3) Remove the file CMakeCache.txt if it exists.\n\n4) You may need to edit the option file\n\nVISITARCHHOME/<version>/<arch>/include/PluginVsInstall.cmake\n   There is a section called \"VisIt options\" which controls options\n   like parallel execution and java.\n\n5) Next to generate the CMakeLists.txt by running:\n\n\txml2cmake -clobber vdf.xml\n\nThis command is found in VISITARCHHOME/bin .\n\n6) Use cmake to generate a Makefile, run:\n\n\tcmake .\n\n7) Finally, build the binaries by running:\n\n\tmake clean all\n\nThis will build the 4 shared objects which make up the plugin (3\nif MPI is not used). The plugin will be installed in the directory\n~/.visit/<arch>/plugins/database/\n\n==============================\n Platform Specific Notes\n==============================\n\nMac OS\n------\n\nPrior to executing visit the environment variable\nDYLD_FALLBACK_LIBRARY_PATH must be set to the path where VAPOR's\nlibraries were installed. For a binary installation of VAPOR this\nwill be /Applications/VAPOR.app/Contents/MacOS :\n\n\tsetenv DYLD_FALLBACK_LIBRARY_PATH /Applications/VAPOR.app/Contents/MacOS\n\nLinux\n-----\n\nOn linux systems the library 'rt' must be added to the LIBS element of the \nvdf.xml configuration file.\n"
  },
  {
    "path": "plugins/visit/VDC/avtvdfFileFormat.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2009, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-400124\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n// ************************************************************************* //\n//                            avtvdfFileFormat.C                           //\n// ************************************************************************* //\n\n#include <avtvdfFileFormat.h>\n#include <avtGhostData.h>\n#include <avtLogicalSelection.h>\n#include <avtDatabaseMetaData.h>\n#include <avtIntervalTree.h>\n\n#include <vtkCellData.h>\n#include <vtkFloatArray.h>\n#include <vtkUnsignedCharArray.h>\n#include <vtkRectilinearGrid.h>\n#include <vtkStructuredGrid.h>\n#include <vtkUnstructuredGrid.h>\n\n#include <InvalidVariableException.h>\n#include <InvalidDBTypeException.h>\n#include <DBOptionsAttributes.h>\n#include <Expression.h>\n#include <string>\n\n#include <vapor/MyBase.h>\n#include <vapor/WaveletBlock3DRegionReader.h>\n#include <vapor/DataMgrWB.h>\n#include <vapor/DataMgrLayered.h>\n\n#include <snprintf.h> //used by VisIt for Windows workaround \n\nusing     std::string;\nusing     std::vector;\nusing     std::map;\n\nvoid debug_callback(const char *msg) { printf(\"debug: %s\\n\",msg); }\nvoid err_callback(const char *msg, int n) { printf(\"err{%d}: %s\\n\",n,msg); }\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat constructor\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Feb 24 15:32:35 PST 2010\n//\n// ****************************************************************************\n\navtvdfFileFormat::avtvdfFileFormat(const char *filename, \n\tDBOptionsAttributes *readOpts) : avtMTMDFileFormat(filename)\n{\n\tsize_t maxts;\n\tint buffer_size = readOpts->GetInt(\"Cache size [MB]\");\n\tdouble heightMult_layered = readOpts->GetDouble(\n\t\t\"Layered data resampling factor\");\n\tmultiDom = readOpts->GetBool(\"MultiDomain\");\n\n\tif (heightMult_layered <= 0.f || buffer_size <= 0)\n\t\tEXCEPTION1(InvalidDBTypeException, \"Invalid Option, must be >0.\"); \n\n\tvdc_md = new VAPoR::MetadataVDC(string(filename));\n\tvdfiobase = new VAPoR::WaveletBlock3DRegionReader(string(filename));\n\tif (vdc_md == NULL) printf (\"NULL VDC!\\n\");\n\n\t// instantiate the correct data manager sub-type.\n\tisLayered = (vdc_md->GetGridType().compare(\"layered\") == 0);\n\tif (isLayered) {\n\t\tVAPoR::DataMgrLayered *dmLayered_inst = new VAPoR::DataMgrLayered(string(filename),\n\t\t\tbuffer_size );\n\t\tdata_mgr = dmLayered_inst;\n\t} else {\n\t\tVAPoR::DataMgrWB *dmWB_inst = new VAPoR::DataMgrWB(*vdc_md, buffer_size );\n\t\tdata_mgr = dmWB_inst;\n\t}\n\tif (data_mgr == NULL) printf(\"NULL Datamanager!\\n\");\n\n//\tMyBase::SetErrMsgCB(err_callback);\n//\tMyBase::SetDiagMsgCB(debug_callback);\n\n\tnum_levels = vdc_md->GetNumTransforms() + 1; \n\tmaxts = vdc_md->GetNumTimeSteps() - 1;\n\ttsteps = new int[maxts];\n\tntsteps = 0;\n\n\tlevels3D = levelsXY = levelsXZ = levelsYZ = -1;\n\tNames3D = (vector<string>) (vdc_md->GetVariables3D());\n\txyNames = (vector<string>) (vdc_md->GetVariables2DXY());\n\txzNames = (vector<string>) (vdc_md->GetVariables2DXZ());\n\tyzNames = (vector<string>) (vdc_md->GetVariables2DYZ());\n\n\t// search through all possible variables, refinement levels, \n\t//   and timesteps to eliminate timesteps with no valid data, and \n\t//   find the max valid refinement level for each variable (for\n\t//   scalar var metadta) and variable type (for mesh metadata).\n\tfor (int t=0; t<maxts; t++) {\n\t\tbool thisTimeIsValid = false;\n\n\t\tfor (int l=0; l<num_levels; l++) {\n\n\t\t\tfor (int n=0; n<Names3D.size(); n++){\n\t\t\t\tif (vdfiobase->VariableExists((size_t)t, Names3D[n].c_str(), l) !=0) {\n\t\t\t\t\tvarTypes[Names3D[n]] = 0;\n\t\t\t\t\tlevels3D = (l > levels3D)? l: levels3D;\n\t\t\t\t\trefLevel[Names3D[n]] = levels3D;\n\t\t\t\t\tthisTimeIsValid = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (int n=0; n<xyNames.size(); n++){\n\t\t\t\tif (vdfiobase->VariableExists((size_t)t, xyNames[n].c_str(), l) !=0) {\n\t\t\t\t\tvarTypes[xyNames[n]] = 1;\n\t\t\t\t\tlevelsXY = (l > levelsXY)? l: levelsXY;\n\t\t\t\t\trefLevel[xyNames[n]] = levelsXY;\n\t\t\t\t\tthisTimeIsValid = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (int n=0; n<xzNames.size(); n++){\n\t\t\t\tif (vdfiobase->VariableExists((size_t)t, xzNames[n].c_str(), l) !=0) {\n\t\t\t\t\tvarTypes[xzNames[n]] = 2;\n\t\t\t\t\tlevelsXZ = (l > levelsXZ)? l: levelsXZ;\n\t\t\t\t\trefLevel[xzNames[n]] = levelsXZ;\n\t\t\t\t\tthisTimeIsValid = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (int n=0; n<yzNames.size(); n++){\n\t\t\t\tif (vdfiobase->VariableExists((size_t)t, yzNames[n].c_str(), l) !=0) {\n\t\t\t\t\tvarTypes[yzNames[n]] = 3;\n\t\t\t\t\tlevelsYZ = (l > levelsYZ)? l: levelsYZ;\n\t\t\t\t\trefLevel[yzNames[n]] = levelsYZ;\n\t\t\t\t\tthisTimeIsValid = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (thisTimeIsValid) {\n\t\t\ttsteps[ntsteps] = t;\n\t\t\tntsteps++;\n\t\t}\n\n\t}\n\n\tif (ntsteps == 0 || data_mgr == NULL)\n\t\tEXCEPTION1(InvalidDBTypeException, \"No valid data.\"); \n\n}\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat destructor\n//\n//  Programmer: dlagreca \n//  Creation:   Wed Feb 24 14:12:30 PST 2010\n//\n// ****************************************************************************\n\navtvdfFileFormat::~avtvdfFileFormat()\n{\n\t// clean up memory\n\tdelete   data_mgr; \n\tdelete   vdfiobase; \n\tdelete   vdc_md; \n\tdelete[] tsteps;\n}\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat::FreeUpResources\n//\n//  Purpose:\n//      When VisIt is done focusing on a particular timestep, it asks that\n//      timestep to free up any resources (memory, file descriptors) that\n//      it has associated with it.  This method is the mechanism for doing\n//      that.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Feb 24 15:32:35 PST 2010\n//\n// ****************************************************************************\n\nvoid\navtvdfFileFormat::FreeUpResources(void)\n{\n\t//data_mgr->Clear();\n}\n\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat::PopulateDatabaseMetaData\n//\n//  Purpose:\n//      This database meta-data object is like a table of contents for the\n//      file.  By populating it, you are telling the rest of VisIt what\n//      information it can request from you.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Feb 24 15:32:35 PST 2010\n//\n// ****************************************************************************\n\nvoid\navtvdfFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md, int timeState)\n{\n\t//clear any old error messages before we start\n\tvdfiobase->SetErrCode(0);\n\n\tsize_t ldim[3], bdim[num_levels][3];\n\tchar refNames[num_levels][20];\n\tfor (int l=0; l<num_levels; l++) {\n\t\tgetVarDims(l, ldim, bdim[l]);\n\t\tSNPRINTF(refNames[l], 20, \"%dx%dx%d\", (int)ldim[0], (int)ldim[1], (int)ldim[2]);\n\t}\n\n\tdouble *extents = NULL;\n\n\tchar Mname3D[num_levels][50], \n         XYMname[num_levels][50], \n         XZMname[num_levels][50], \n         YZMname[num_levels][50];\n\t// meshes describe the positions of datapoints in 3D space, add one for\n\t// each type of Vapor data variable and refinement level, for which at\n\t// least one valid variable exists to use it.\n\n\tfor (int j=0; j<=levels3D; j++) {\n\t\tSNPRINTF(Mname3D[j], 50, \"3D_%s\", refNames[j]);\n\t\tAddMeshToMetaData(md, Mname3D[j], AVT_RECTILINEAR_MESH, extents, \n\t\t\tmultiDom? bdim[j][0]*bdim[j][1]*bdim[j][2]: 1, 0,3,3);\n\t\tmd->SetContainsGhostZones(string(Mname3D[j]),AVT_CREATED_GHOSTS);\n\t\tmd->SetContainsOriginalCells(string(Mname3D[j]),true);\n\t\trefLevel[Mname3D[j]] = j;\n\t}\n\n\tfor (int j=0; j<=levelsXY; j++) {\n\t\tSNPRINTF(XYMname[j], 50, \"XY_%s\", refNames[j]);\n\t\tAddMeshToMetaData(md, XYMname[j], AVT_RECTILINEAR_MESH, extents, \n\t\t\tmultiDom? bdim[j][0]*bdim[j][1]: 1, 0,2,2);\n\t\trefLevel[XYMname[j]] = j;\n\t}\n\n\tfor (int j=0; j<=levelsXZ; j++) {\n\t\tSNPRINTF(XZMname[j], 50, \"XZ_%s\", refNames[j]);\n\t\tAddMeshToMetaData(md, XZMname[j], AVT_RECTILINEAR_MESH, extents, \n\t\t\tmultiDom? bdim[j][0]*bdim[j][2]: 1, 0,2,2);\n\t\trefLevel[XZMname[j]] = j;\n\t}\n\n\tfor (int j=0; j<=levelsYZ; j++) {\n\t\tSNPRINTF(YZMname[j], 50, \"YZ_%s\", refNames[j]);\n\t\tAddMeshToMetaData(md, YZMname[j], AVT_RECTILINEAR_MESH, extents, \n\t\t\tmultiDom? bdim[j][1]*bdim[j][2]: 1, 0,2,2);\n\t\trefLevel[YZMname[j]] = j;\n\t}\n\n\tchar vname[100];\n\t// create a visit variable for each valid refinement level for each\n\t// valid Vapor variable. Name it <MeshType>/XxYxZ/<Vapor variable name>\n\t// the '/' char tells visit to create a submenu.  Attach to the correct \n\t// mesh based on dimensional type and refinement level \n\n\tfor (int i=0; i<Names3D.size(); i++) {\n\t\tfor (int l=0; l<=refLevel[Names3D[i]]; l++) {\n\t\t\tSNPRINTF(vname, 100, \"3D/%s/%s\", refNames[l], Names3D[i].c_str());\n\t\t\tAddScalarVarToMetaData(md, vname, Mname3D[l], AVT_ZONECENT);\n\t\t\tvarTypes[vname] = 0;\n\t\t\trefLevel[vname] = l;\n\t\t}\n\t}\n\tfor (int i=0; i<xyNames.size(); i++) {\n\t\tfor (int l=0; l<=refLevel[xyNames[i]]; l++) {\n\t\t\tSNPRINTF(vname, 100, \"2D/%s/%s\", refNames[l], xyNames[i].c_str());\n\t\t\tAddScalarVarToMetaData(md, vname, XYMname[l], AVT_ZONECENT);\n\t\t\tvarTypes[vname] = 1;\n\t\t\trefLevel[vname] = l;\n\t\t}\n\t}\n\tfor (int i=0; i<xzNames.size(); i++) {\n\t\tfor (int l=0; l<=refLevel[xzNames[i]]; l++) {\n\t\t\tSNPRINTF(vname, 100, \"2D/%s/%s\", refNames[l], xzNames[i].c_str());\n\t\t\tAddScalarVarToMetaData(md, vname, XZMname[l], AVT_ZONECENT);\n\t\t\tvarTypes[vname] = 2;\n\t\t\trefLevel[vname] = l;\n\t\t}\n\t}\n\tfor (int i=0; i<yzNames.size(); i++) {\n\t\tfor (int l=0; l<=refLevel[yzNames[i]]; l++) {\n\t\t\tSNPRINTF(vname, 100, \"2D/%s/%s\", refNames[l], yzNames[i].c_str());\n\t\t\tAddScalarVarToMetaData(md, vname, YZMname[l], AVT_ZONECENT);\n\t\t\tvarTypes[vname] = 3;\n\t\t\trefLevel[vname] = l;\n\t\t}\n\t}\n\n}\n\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat::GetMesh\n//\n//  Purpose:\n//      Gets the mesh associated with this file.  The mesh is returned as a\n//      derived type of vtkDataSet (ie vtkRectilinearGrid, vtkStructuredGrid,\n//      vtkUnstructuredGrid, etc).\n//\n//  Arguments:\n//      timestate   The index of the timestate.  If GetNTimesteps returned\n//                  'N' time steps, this is guaranteed to be between 0 and N-1.\n//      domain      The index of the domain.  If there are NDomains, this\n//                  value is guaranteed to be between 0 and NDomains-1,\n//                  regardless of block origin.\n//      meshname    The name of the mesh of interest.  This can be ignored if\n//                  there is only one mesh.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Feb 24 15:32:35 PST 2010\n//\n// ****************************************************************************\n\nvtkDataSet *\navtvdfFileFormat::GetMesh(int timestate, int domain, const char *meshname)\n{\n\t//clear any old error messages before we start\n\tvdfiobase->SetErrCode(0);\n\n\t// Build the 3D mesh, and refactor appropriately for 2D meshes \n\tsize_t dims_st[3], bdims[3];\n\tconst size_t *block_size = vdc_md->GetBlockSize();\n\tint dim_start[3];\n\n\tgetVarDims(string(meshname), dims_st, bdims);\n\n\tsize_t coordsB[3], dims_real[3];\n\tif (multiDom){\n\t\tgetCoordsFromIndex(coordsB, bdims, domain);\n\t\tgetVoxelsInBlock(dims_real, dims_st, bdims, coordsB);\n\t\tfor (int i=0; i<3; i++) {\n\t\t\tdims_real[i] ++;\n\t\t\tdim_start[i] = (block_size[i])*(coordsB[i])-(coordsB[i]==0?0:1);\n\t\t}\n\t} \n\telse {\n\t\tfor (int i=0; i<3; i++) {\n\t\t\tdim_start[i] = 0;\n\t\t\tdims_real[i] = dims_st[i] + 1;\n\t\t}\n\t}\n\n\tconst vector<double> glExtents = vdc_md->GetExtents(),\n\t      tsExtents = vdc_md->GetTSExtents((size_t)tsteps[timestate]),\n\t      uExtents = tsExtents.empty()? glExtents: tsExtents;\n\n\t// find user delta value for each dimension \n\tfloat dx = ((float)uExtents[3] - (float)uExtents[0])/(float)dims_st[0], \n\t      dy = ((float)uExtents[4] - (float)uExtents[1])/(float)dims_st[1],\n\t      dz = ((float)uExtents[5] - (float)uExtents[2])/(float)dims_st[2];\n\n\t// these arrays map data coords to user coords \n\tvtkFloatArray *coordsX = vtkFloatArray::New();\n\tvtkFloatArray *coordsY = vtkFloatArray::New();\n\tvtkFloatArray *coordsZ = vtkFloatArray::New();\n\n\tcoordsX->SetNumberOfTuples(dims_real[0]);\n\tcoordsY->SetNumberOfTuples(dims_real[1]);\n\tcoordsZ->SetNumberOfTuples(dims_real[2]);\n\n\t// compute user coords for each data coord \n\tfor (int i=(dim_start[0]), j=0; j<dims_real[0]; i++, j++) { \n\t\tcoordsX->SetValue(j, (float)i*dx + uExtents[0]);\n\t}\n\tfor (int i=(dim_start[1]), j=0; j<dims_real[1]; i++, j++) { \n\t\tcoordsY->SetValue(j, (float)i*dy + uExtents[1]);\n\t}\n\tfor (int i=(dim_start[2]), j=0; j<dims_real[2]; i++, j++) { \n\t\tcoordsZ->SetValue(j, (float)i*dz + uExtents[2]);\n\t}\n\n\t// adjust array dimensions if var is only 2D \n\tif (!strncmp(meshname, \"3D\", 2)) {\n\t\t//already done!\n\n\t} else if (!strncmp(meshname, \"XY\", 2)) {\n\t\tdims_real[2] = 1;\n\t\tcoordsZ->SetNumberOfTuples(1);\n\t\tcoordsZ->SetValue(0, 0.f);\n\n\t} else if (!strncmp(meshname, \"XZ\", 2)) {\n\t\tdims_real[1] = 1;\n\t\tcoordsY->SetNumberOfTuples(1);\n\t\tcoordsY->SetValue(0, 0.f);\n\n\t} else if (!strncmp(meshname, \"YZ\", 2)) {\n\t\tdims_real[0] = 1;\n\t\tcoordsX->SetNumberOfTuples(1);\n\t\tcoordsX->SetValue(0, 0.f);\n\n\t} else {\n\t\t// No mesh name that we recognize. \n\t\tcoordsX->Delete(); coordsY->Delete(); coordsZ->Delete();\n\t\tEXCEPTION1(InvalidVariableException, meshname); \n\t}\n\n\t// apply coordinate maps and return rgrid\n\tvtkRectilinearGrid *rgrid = vtkRectilinearGrid::New();\n\trgrid->SetDimensions(dims_real[0], dims_real[1], dims_real[2]);\n\trgrid->SetXCoordinates(coordsX);\n\trgrid->SetYCoordinates(coordsY);\n\trgrid->SetZCoordinates(coordsZ);\n\n\tif (multiDom) { //only add ghost data for multi-domain\n\t\t// Now that you have your mesh, figure out which cells need \n\t\t// to be removed. \n\t\tint nCells = rgrid->GetNumberOfCells(); \n\n\t\t// Now that we have the blanks array, create avtGhostZones. \n\t\tunsigned char realVal = 0, ghost = 0; \n\t\tsize_t cell[3], cellMax[3]; \n\t\tfor(int i=0; i<3; i++) cellMax[i] = dims_real[i]-1;\n\t\tavtGhostData::AddGhostZoneType(ghost, DUPLICATED_ZONE_INTERNAL_TO_PROBLEM); \n\n\t\tvtkUnsignedCharArray *ghostCells = vtkUnsignedCharArray::New(); \n\t\tghostCells->SetName(\"avtGhostZones\"); \n\t\tghostCells->Allocate(nCells); \n\n\t\tfor(int i = 0; i < nCells; ++i) \n\t\t{ \n\t\t\tgetCoordsFromIndex(cell, cellMax, i);\n\t\t\tbool isGhost = ((cell[0] == 0) && (coordsB[0] != 0)) || \n\t\t\t\t ((cell[0] == cellMax[0]-1) && (coordsB[0] != bdims[0]-1 )) ||  \n\t\t\t\t ((cell[1] == 0) && (coordsB[1] != 0)) || \n\t\t\t\t ((cell[1] == cellMax[1]-1) && (coordsB[1] != bdims[1]-1 )) ||  \n\t\t\t\t ((cell[2] == 0) && (coordsB[2] != 0)) || \n\t\t\t\t ((cell[2] == cellMax[2]-1) && (coordsB[2] != bdims[2]-1 )); \n\n\t\t\tif (isGhost) {\n\t\t\t\tghostCells->InsertNextValue(ghost);\n\t\t\t} else {\n\t\t\t\tghostCells->InsertNextValue(realVal); \n\t\t\t}\n\t\t} \n\t\trgrid->GetCellData()->AddArray(ghostCells); \n\t\trgrid->SetUpdateGhostLevel(0); \n\t\tghostCells->Delete();\n\n\t\t// Clean up \n\t\tcoordsX->Delete();\n\t\tcoordsY->Delete();\n\t\tcoordsZ->Delete();\n\t}\n\n\treturn rgrid;\n}\n\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat::GetVar\n//\n//  Purpose:\n//      Gets a scalar variable associated with this file.  Although VTK has\n//      support for many different types, the best bet is vtkFloatArray, since\n//      that is supported everywhere through VisIt.\n//\n//  Arguments:\n//      timestate  The index of the timestate.  If GetNTimesteps returned\n//                 'N' time steps, this is guaranteed to be between 0 and N-1.\n//      domain     The index of the domain.  If there are NDomains, this\n//                 value is guaranteed to be between 0 and NDomains-1,\n//                 regardless of block origin.\n//      varname    The name of the variable requested.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Feb 24 15:32:35 PST 2010\n//\n// ****************************************************************************\n\nvtkDataArray *\navtvdfFileFormat::GetVar(int timestate_in, int domain, const char *varname)\n{\n\t//clear any old error messages before we start\n\tvdfiobase->SetErrCode(0);\n\n\t// Get actual timestep/varname used in vdf \n\tstring varstring(varname);\n\tchar *varname_clean = cleanVarname(varname);\n\tsize_t timestate = (size_t) tsteps[timestate_in];\n\n\t// Need to add lod value for GetRegion call for VAPOR 2.0.2 api.\n\t// Setting the value to zero, not sure if correct.\n\tint lod = 0; \n\n\t// Verifty that data for this var at this time and refinement exists \n\tif (!vdfiobase->VariableExists(timestate, varname_clean, refLevel[varstring])) { \n\t\tstringstream mesg;\n\t\tmesg << \"Data for \" << varname_clean << \" does not exist in timestep \" \n\t\t     << timestate << \" at refinement level \" << refLevel[varstring] << \"].\";\n\n\t\tEXCEPTION1(InvalidVariableException, mesg.str().c_str());\n\t}\n\n\t// Get blocksize and data bounds to calculate padding \n\tdatasize_t ds;\n\tsize_t dmin[3], dmax[3], bdims[3], udims[3];\n\tconst size_t *bmsize = vdc_md->GetBlockSize();\n\tgetVarDims(varstring, udims, bdims);\n\n\t// figure out which data we need to request from data_mgr \n\tif (multiDom) {\n\t\tgetCoordsFromIndex(dmin, bdims, domain);\n\t\tgetDatasizeFromCoords(&ds, udims, bdims, dmin, dmax);\n\t}\n\telse {\n\t\tfor (int i=0; i<3; i++) {\n\t\t\tdmin[i] = 0;\n\t\t\tdmax[i]=bdims[i]-1;\n\n\t\t\tds.frontPad[i] = 0;\n\t\t\tds.padded[i] = bmsize[i]*bdims[i];\n\t\t\tds.backPad[i] = ds.padded[i] - udims[i];\n\t\t\tds.real[i] = ds.padded[i] - ds.backPad[i];\n\t\t}\n\t} // else\n\n\t// get pointer to actual data (may be padded), thow execption on error\n\tfloat *data_floats = data_mgr->GetRegion(timestate, varname_clean, \n\t\trefLevel[varstring], lod, dmin, dmax);\n\n\tif (data_floats == NULL) { \n\t\tEXCEPTION1(InvalidVariableException, \"Data manager returned NULL pointer.\");\n\t}\n\n\t// set up extents for return vector based on data type\n\tint which_dim;\n\tswitch(varTypes[varstring]) {\n\t\tcase 0: which_dim = -1; break;\n\t\tcase 1: which_dim =  2; break;\n\t\tcase 2: which_dim =  1; break;\n\t\tcase 3: which_dim =  0; break;\n\t\tdefault:\n\t\t\tEXCEPTION1(InvalidVariableException, \"Variable type undefined.\");\n\t\t\tbreak;\n\t}\n\tif (which_dim != -1) {\n\t\tds.frontPad[which_dim] = 0;\n\t\tds.backPad[which_dim] = 0;\n\t\tds.padded[which_dim] = 1;\n\t\tds.real[which_dim] = 1;\n\t}\n\n\t// create return vector, filling with only valid data \n\tint idx = 0, numdata = ds.real[0] * ds.real[1] * ds.real[2];\n\tvtkFloatArray *rv = vtkFloatArray::New();\n\trv->SetNumberOfValues(numdata);\n\n\tfor (int z=ds.frontPad[2]; z< (ds.padded[2] - ds.backPad[2]); z++) {\n\t\tfor (int y=ds.frontPad[1]; y< (ds.padded[1] - ds.backPad[1]); y++) {\n\t\t\tfor (int x=ds.frontPad[0]; x< (ds.padded[0] - ds.backPad[0]); x++) {\n\n\t\t\t\trv->SetValue(idx, data_floats[ z*ds.padded[1]*ds.padded[0] + \n\t\t\t\t                               y*ds.padded[0] + \n\t\t\t\t\t                           x ]);\n\n\t\t\t\tidx++;\n\t\t\t}\n\t\t}\n\t}\n\n\tdelete varname_clean;\n\treturn rv;\n}\n\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat::GetVectorVar\n//\n//  Purpose:\n//      Gets a vector variable associated with this file.  Although VTK has\n//      support for many different types, the best bet is vtkFloatArray, since\n//      that is supported everywhere through VisIt.\n//\n//  Arguments:\n//      timestate  The index of the timestate.  If GetNTimesteps returned\n//                 'N' time steps, this is guaranteed to be between 0 and N-1.\n//      domain     The index of the domain.  If there are NDomains, this\n//                 value is guaranteed to be between 0 and NDomains-1,\n//                 regardless of block origin.\n//      varname    The name of the variable requested.\n//\n//  Note: \n//      although vapor data sets often contain vector data, there is no \n//      standard representation. VisIt allows for the creation of vecotor\n//      variables based on multiple scalar variables, so no 'vector type'\n//      variables are reported to VisIt\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Feb 24 15:32:35 PST 2010\n//\n// ****************************************************************************\n\nvtkDataArray *\navtvdfFileFormat::GetVectorVar(int timestate, int domain,const char *varname)\n{\n\treturn 0;\n}\n\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat::GetTimes\n//\n//  Purpose:\n//      Sets the time numbers to match the VDF user-time\n//\n//  Arguments:\n//      times    double precision float vector to be filled with user time for \n//               each valid timestep.\n//\n//  Note:\n//      I am unsure why, but reporting the vapor TSUserTime breaks streamlines\n//      for WRF-based Vapor datasets.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Thu Feb 11 14:12:30 PST 2010\n//\n// ****************************************************************************\n\nvoid \navtvdfFileFormat::GetTimes(vector<double> &times) \n{\n\tfor (int i=0; i<ntsteps; i++) \n\t\ttimes.push_back(tsteps[i]);\n\t\t//times.push_back(data_mgr->GetTSUserTime((size_t)tsteps[i])[0]);\n}\n\n\n// ****************************************************************************\n//  Method: avtvdfFileFormat::GetCycles\n//\n//  Purpose:\n//      Sets the cycle numbers to match the timestate numbers for valid time-\n//      states. This allows the correct 'timestep' to be shown even though\n//      the invalid timesteps are not counted.\n//\n//  Arguments:\n//      cycles   integer vector to be filled with correct cycle number for each\n//               timestep\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Thu Feb 11 14:12:30 PST 2010\n//\n// ****************************************************************************\n\nvoid \navtvdfFileFormat::GetCycles(vector<int> &cycles) \n{\n\tfor (int i=0; i<ntsteps; i++) \n\t\tcycles.push_back(tsteps[i]);\n}\n\n\n// ********************************************************\n// Method: avtvdfFileFormat::getVoxelsInBlock \n//\n// Purpose: \n//   Given a certian data block, return the dimensions (in voxels) of that\n//   block. Need to repeat the data on forward block edges, only if that block\n//   is adjcent to another block (i.e. not the end of the dataset), therefore\n//   add one voxel to dimension if this block is not an end-block.\n//\n// Arguments:\n//   udims: 3-element array of total valid data dimensions (voxels)\n//\t bdims: 3-element array of total blocks in data\n//\t dmin : 3-element array of current block coords\n//\t numel: 3-element array to place results in\n//\n// Returns: nothing\n//   numel is filled.\n//\n// Note:\n//   The original functionality of this method has been integrated into\n//   getDatasizeFromCoords(), so this method simply calls that it,\n//   returning the appropriate component. This is done for consistancy. \n//\n// Programmer: dlagreca -- generated by xml2avt\n// Creation:   Thu Feb 11 14:12:30 PST 2010\n//\n// Modifications:\n//\n// ********************************************************\n\nvoid \navtvdfFileFormat::getVoxelsInBlock(size_t *numel, size_t *udims, \n\tsize_t *bdims, size_t* coord) \n{\n\n\tsize_t mn[3]={coord[0], coord[1], coord[2]}, mx[3];\n\tdatasize_t dss;\n\tgetDatasizeFromCoords(&dss, udims, bdims, mn, mx);\n\tfor (int i=0; i<3; i++) numel[i] = dss.real[i];\n\n}\n\n\n// ********************************************************\n// Method: avtvdfFileFormat::getCoordsFromIndex\n//\n// Purpose: \n//   Given a block index in a dataset, find the 'x,y,z' coordinates of said block \n//\n// Arguments:\n//   coords: 3-element array containing the x,y,z coordinates of the block at index\n//   bdims: total block dimensions of dataset\n//   index: index of block in the dataset\n//\n// Returns: nothing\n//   coors is filled.\n//\n// Programmer: dlagreca -- generated by xml2avt\n// Creation:   Thu Feb 11 14:12:30 PST 2010\n//\n// Modifications:\n//\n// ********************************************************\n\nvoid \navtvdfFileFormat::getCoordsFromIndex(size_t *coords, size_t* bdims, int index)\n{\n\n\tcoords[2] = index/(bdims[0] * bdims[1]);\n\tindex -= coords[2] * (bdims[0] * bdims[1]);\n\tcoords[1] = index/bdims[0];\n\tindex -= coords[1] * bdims[0];\n\tcoords[0] = index;\n\n}\n\n\n// ********************************************************\n// Method: avtvdfFileFormat::getDataSizeFromCoords\n//\n// Purpose: \n//   given the coordinates of a block, return the nuber of elements in each dimension\n//   that should be pulled from the data manager, including ghost zones for non-\n//   boundary edges:\n//\n// Arguments:\n//   datasize: return structure for padding information \n//   udims : 3-element array of total blocks in data\n//   bdims : 3-element array of total blocks in data\n//   dmin  : 3-element array of starting data block coords\n//   dmax  : 3-element array of ending data block coords\n//\n// Returns: nothing\n//   datasize is filled.\n//\n// Programmer: dlagreca -- generated by xml2avt\n// Creation:   Thu Feb 11 14:12:30 PST 2010\n//\n// Modifications:\n//\n// ********************************************************\n\nvoid \navtvdfFileFormat::getDatasizeFromCoords(datasize_t *datasize, \n     size_t *udims, size_t *bdims, size_t *dmin, size_t* dmax) \n{\n\tconst size_t *bmsize = vdc_md->GetBlockSize();\n\n\tfor (int i=0; i<3; i++) {\n\t\tdmax[i] = dmin[i];\n\t\tif (dmin[i] == bdims[i]-1) { //last block\n\t\t\tint p = bdims[i]*bmsize[i] - udims[i];\n\t\t\tif (dmin[i] > 0) {\t\t//other blocks before it\n\t\t\t\tdmin[i]--;\n\t\t\t\tdatasize->padded[i]   = bmsize[i]*2;\n\t\t\t\tdatasize->frontPad[i] = bmsize[i]-1;\n\t\t\t\tdatasize->backPad[i]  = p;\n\n\t\t\t} else {\t\t\t\t//only one block in this dim\n\t\t\t\tdatasize->padded[i]   = bmsize[i];\n\t\t\t\tdatasize->frontPad[i] = 0;\n\t\t\t\tdatasize->backPad[i]  = p;\n\t\t\t}\n\n\t\t} else if (dmin[i] == 0) {\n\t\t\tdmax[i]++;\n\t\t\tdatasize->padded[i]   = bmsize[i]*2;\n\t\t\tdatasize->frontPad[i] = 0;\n\t\t\tdatasize->backPad[i]  = bmsize[i]-1;\n\n\t\t} else {\n\t\t\tdmax[i]++;\n\t\t\tdmin[i]--;\n\t\t\tdatasize->padded[i]   = bmsize[i]*3;\n\t\t\tdatasize->frontPad[i] = bmsize[i]-1;\n\t\t\tdatasize->backPad[i]  = bmsize[i]-1; \n\t\t}\n\t\tdatasize->real[i] = datasize->padded[i] - datasize->backPad[i]\n\t\t\t- datasize->frontPad[i];\n\t}\n\n}\n\n\n// ********************************************************\n// Method: avtvdfFileFormat::cleanVarname\n//\n// Purpose: \n//   Removes the leading characters that were added to the varname\n//   to specifiy its correct mesh. Only the clean varname can be used to \n//   interface with the data_mgr. \n//\n// Arguments:\n//\t varname: c-string variable name, contianing unwanted chars\n//\n// Returns: \n//   pointer to new c-string. Be sure to call delete() when you're done\n//   with it\n//\n// Programmer: dlagreca -- generated by xml2avt\n// Creation:   Thu Feb 11 14:12:30 PST 2010\n//\n// Modifications:\n//\n// ********************************************************\n\nchar* \navtvdfFileFormat::cleanVarname(const char *varname)\n{\n\t// remove refinement tag from varname - find clean length\n\tint length = strlen(varname), start = length;\n\twhile (varname[start--] != '/');\n\tlength = length-start-2;\n\n\t// copy applicaple part of varname to _clean \n\tchar *varname_clean = new char[length];\n\tfor (int i=0; i<length; i++) varname_clean[i] = varname[start+i+2];\n\tvarname_clean[length] = '\\0';\n\t\n\treturn varname_clean;\n}\n\n\n// ********************************************************\n// Method: avtvdfFileFormat::getVarDims\n//\n// Purpose: \n//   This function will fill the two arrays passed in (udims and bdims) with \n//   the size of data at the specified refinement level in voxels, and blocks,\n//   respectively. If the first arguement is a string, its refinement level\n//   is first decided based on the refLevel map produced in the ctor.\n//\n// Arguments:\n//\t level: refinement level to retrieve blocksize for. \n//   - OR -\n//   varstring: index into refLevel map to choose refinement level.\n//   udims: 3-element array of total valid data dimensions (voxels)\n//\t bdims: 3-element array of total blocks in data\n//\n// Returns: nothing\n//   udims and bdims are filled.\n//\n// Programmer: dlagreca -- generated by xml2avt\n// Creation:   Thu Feb 11 14:12:30 PST 2010\n//\n// Modifications:\n//\n// ********************************************************\n\ninline void \navtvdfFileFormat::getVarDims(string varstring, size_t *udims, size_t *bdims) \n{\n\tgetVarDims(refLevel[varstring], udims, bdims);\n}\n\nvoid \navtvdfFileFormat::getVarDims(int level, size_t *udims, size_t *bdims) \n{\n\tvdfiobase->GetDim(udims, level);\n\tvdfiobase->GetDimBlk(bdims, level);\n}\n\n\n// ********************************************************\n// Method: avtvdfFileFormat::GetAuxiliaryData\n//\n// Purpose: \n//   used by visit to access extents for each domain. This\n//   allows visit to request only those data blocks that \n//   are requred for rendering.\n//\n// Arguments:\n//\t var: variable for wich to return extent. \n//\n// Returns: \n//   itree with spatial extents for each domain. \n//\n// Programmer: dlagreca -- generated by xml2avt\n// Creation:   Thu Feb 11 14:12:30 PST 2010\n//\n// Modifications:\n//\n// ********************************************************\n\nvoid * \navtvdfFileFormat::GetAuxiliaryData(const char *var, \n\tint timestate, int domain, const char *type, void *, \n\tDestructorFunction &df) \n{ \n\tvoid *retval = 0; \n\tif(strcmp(type, AUXILIARY_DATA_SPATIAL_EXTENTS) == 0) \n\t{ \n\t\tif (!multiDom) return retval;\n\t\t//printf(\"Returning spatial extents for %s @ %d in domain %d, \", var, timestate, domain);\n\t\tsize_t dims[3], bdims[3], bcoords[3];\n\t\tfloat delta[3];\n\t\tconst size_t *bsize = vdc_md->GetBlockSize();\n\t\tconst vector<double> glExt = vdc_md->GetExtents(),\n\t\t\t  tsExt = vdc_md->GetTSExtents((size_t)tsteps[timestate]),\n\t\t\t  uExt = tsExt.empty()? glExt: tsExt;\n\n\t\t// Read the number of domains for the mesh. \n\t\t// Read the spatial extents for each domain of the \n\t\t// mesh. This information should be in a single \n\t\t// and should be available without having to \n\t\t// read the real data. The expected format for \n\t\t// the data in the spatialextents array is to \n\t\t// repeat the following pattern for each domain: \n\t\t// xmin, xmax, ymin, ymax, zmin, zmax. \n\t\tgetVarDims(string(var), dims, bdims);\n\n\t\tint ndoms = multiDom? bdims[0]*bdims[1]*bdims[2]: 1;\n\t\tdouble *spatialextents = new double[ndoms * 6]; \n\n\t\tfor (int i=0; i<3; i++)\n\t\t\t\tdelta[i] = ((float)uExt[i+3] - (float)uExt[i])/(float)dims[i];\n\n\t\t//READ ndoms*6 DOUBLE VALUES INTO spatialextents ARRAY. \n\t\tfor (int curDom = 0; curDom < ndoms; curDom++) {\n\t\t\tgetCoordsFromIndex(bcoords, bdims, curDom);\n\n\t\t\t//Spatial dims go from (block_start)*(voxels/block)*(units/voxel) \n\t\t\t//  to (block_start + 1)*(voxels/block)*(units/voxel)\n\t\t\tfor (int i=0; i<3; i++) {\n\t\t\t\tspatialextents[(6*curDom) + 2*i] = (float)(bcoords[i]*bsize[i])*delta[i];\n\t\t\t\tspatialextents[(6*curDom) + 2*i+1] = (float)((bcoords[i]+1)*bsize[i])*delta[i];\n\t\t\t}\n\t\t}\n\n\t\t// Create an interval tree \n\t\tavtIntervalTree *itree = new avtIntervalTree(ndoms, 3); \n\t\tdouble *extents = spatialextents; \n\t\tfor(int dom = 0; dom < ndoms; ++dom) \n\t\t{ \n\t\t\titree->AddElement(dom, extents); \n\t\t\textents += 6; \n\t\t} \n\t\titree->Calculate(true); \n\t\t// Delete temporary array. \n\t\tdelete [] spatialextents; \n\t\t// Set return values \n\t\tretval = (void *)itree; \n\t\tdf = avtIntervalTree::Destruct; \n\t} \n\n\treturn retval;\n}\n"
  },
  {
    "path": "plugins/visit/VDC/avtvdfFileFormat.h",
    "content": "/*****************************************************************************\n *\n * Copyright (c) 2000 - 2009, Lawrence Livermore National Security, LLC\n * Produced at the Lawrence Livermore National Laboratory\n * LLNL-CODE-400124\n * All rights reserved.\n *\n * This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n * full copyright notice is contained in the file COPYRIGHT located at the root\n * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n *\n * Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n * modification, are permitted provided that the following conditions are met:\n *\n *  - Redistributions of  source code must  retain the above  copyright notice,\n *    this list of conditions and the disclaimer below.\n *  - Redistributions in binary form must reproduce the above copyright notice,\n *    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n *    documentation and/or other materials provided with the distribution.\n *  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n *    be used to endorse or promote products derived from this software without\n *    specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n * ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n * LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n * DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n * CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n * LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n * OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n * DAMAGE.\n *\n *****************************************************************************/\n\n// ************************************************************************* //\n//                            avtvdfFileFormat.h                           //\n// ************************************************************************* //\n\n#ifndef AVT_vdf_FILE_FORMAT_H\n#define AVT_vdf_FILE_FORMAT_H\n\n#include <avtMTMDFileFormat.h>\n#include <avtDataSelection.h>\n#include <avtMeshMetaData.h>\n\n#include <vector>\n#include <map>\n\n#include \"vapor/DataMgr.h\"\n#include \"vapor/VDFIOBase.h\"\n#include \"vapor/WaveletBlockIOBase.h\"\n#include \"vapor/WaveletBlock3DRegionReader.h\"\n\nclass DBOptionsAttributes;\n\n// ****************************************************************************\n//  Class: avtvdfFileFormat\n//\n//  Purpose:\n//      Reads in vdf files as a plugin to VisIt.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Feb 24 15:32:35 PST 2010\n//\n// ****************************************************************************\n\nclass avtvdfFileFormat : public avtMTMDFileFormat {\npublic:\n    avtvdfFileFormat(const char *, DBOptionsAttributes *);\n    virtual ~avtvdfFileFormat();\n\n    //\n    // This is used to return unconvention data -- ranging from material\n    // information to information about block connectivity.\n    //\n    virtual void *GetAuxiliaryData(const char *var, int timestep, int domain, const char *type, void *args, DestructorFunction &);\n    //\n\n    //\n    // If you know the times and cycle numbers, overload this function.\n    // Otherwise, VisIt will make up some reasonable ones for you.\n    //\n    virtual void GetCycles(std::vector<int> &);\n    virtual void GetTimes(std::vector<double> &);\n    virtual int  GetNTimesteps(void) { return ntsteps; };\n\n    virtual const char *GetType(void) { return \"vdf\"; };\n    virtual void        FreeUpResources(void);\n\n    virtual vtkDataSet *  GetMesh(int, int, const char *);\n    virtual vtkDataArray *GetVar(int, int, const char *);\n    virtual vtkDataArray *GetVectorVar(int, int, const char *);\n\nprotected:\n    // structure used to pass info about ghost boundaries (padding)\n    typedef struct datasize_t {\n        size_t real[3];        // dimensions of actual voxel data\n        size_t padded[3];      // dimensions of data with padding\n        size_t frontPad[3];    // padding before real data\n        size_t backPad[3];     // padding after real data\n    };\n\n    bool isLayered,    // weather or not the VDF contains layered a dataset\n        multiDom;      // weather or not we expose multiple domains to VisIt\n    int num_levels,    // max # of refinement levels\n        ntsteps,       // number of valid timesteps\n        *tsteps,       // map valid timestate (0-indexed) to dataset timestep\n        levels3D,      // Highest refinement level 3D mesh needed\n        levelsXY,      // Highest refinement level 2D XY mesh needed\n        levelsXZ,      // Highest refinement level 2D XZ mesh needed\n        levelsYZ;      // Highest refinement level 2D YZ mesh needed\n\n    VAPoR::MetadataVDC *       vdc_md;       // determines type of datamanger is needed\n    VAPoR::WaveletBlockIOBase *vdfiobase;    // determines type of datamanger is needed\n    VAPoR::DataMgr *           data_mgr;     // Pointer to subclass\n\n    // relate var name to dimensional type (3D,XY,XZ,YZ)\n    map<string, int> varTypes;\n\n    // relate var name to refinement level\n    map<string, int> refLevel;\n\n    // Hold names of all vars in dataset, per type\n    vector<string> Names3D, xyNames, xzNames, yzNames, meshNames;\n\n    virtual void PopulateDatabaseMetaData(avtDatabaseMetaData *, int);\n    bool         CanCacheVariable(const char *var) { return false; };\n\n    void        getVoxelsInBlock(size_t *, size_t *, size_t *, size_t *);\n    void        getCoordsFromIndex(size_t *, size_t *, int);\n    void        getDatasizeFromCoords(datasize_t *, size_t *, size_t *, size_t *, size_t *);\n    char *      cleanVarname(const char *);\n    void        getVarDims(string, size_t *, size_t *);\n    inline void getVarDims(int, size_t *, size_t *);\n};\n\n#endif\n"
  },
  {
    "path": "plugins/visit/VDC/avtvdfOptions.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2009, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-400124\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n// ************************************************************************* //\n//                             avtvdfOptions.C                              //\n// ************************************************************************* //\n\n#include <avtvdfOptions.h>\n\n#include <DBOptionsAttributes.h>\n\n#include <vector>\n#include <string>\n\n\n// ****************************************************************************\n//  Function: GetvdfReadOptions\n//\n//  Purpose:\n//      Creates the options for vdf readers.\n//\n//  Important Note:\n//      The code below sets up empty options.  If your format \n//      does not require read options, no modifications are \n//      necessary.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Apr 7 14:43:06 PST 2010\n//\n// ****************************************************************************\n\nDBOptionsAttributes *\nGetvdfReadOptions(void)\n{\n    DBOptionsAttributes *rv = new DBOptionsAttributes;\n\n\t// The cache size parameter which will be passed the VDF Data Manager\n    rv->SetInt(\"Cache size [MB]\", 1000);\n\n\t// Resapmling factor for WRF (layered) data, which is passed to VDF Data Manager\n    rv->SetDouble(\"Layered data resampling factor\", 4.0);\n\n\t// Weather or not to report each VDC Block as it's own domain\n    rv->SetBool(\"MultiDomain\", false);\n\n    return rv;\n/* EXAMPLE OF OPTIONS\n    rv->SetBool(\"Binary format\", true);\n    rv->SetBool(\"Big Endian\", false);\n    rv->SetEnum(\"Dimension\", 1);\n    vector<string> dims;\n    dims.push_back(\"0D\");\n    dims.push_back(\"1D\");\n    dims.push_back(\"2D\");\n    dims.push_back(\"3D\");\n    rv->SetEnumStrings(\"Dimension\", dims);\n    rv->SetInt(\"Number of variables\", 5);\n    rv->SetString(\"Name of auxiliary file\", );\n    rv->SetDouble(\"Displacement factor\", 1.0);\n\n    // When reading or writing the file, you can get the options out of this object like:\n    rv->GetDouble(\"Displacement factor\");\n*/\n}\n\n\n// ****************************************************************************\n//  Function: GetvdfWriteOptions\n//\n//  Purpose:\n//      Creates the options for vdf writers.\n//\n//  Important Note:\n//      The code below sets up empty options.  If your format \n//      does not require write options, no modifications are \n//      necessary.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Apr 7 14:43:06 PST 2010\n//\n// ****************************************************************************\n\nDBOptionsAttributes *\nGetvdfWriteOptions(void)\n{\n    DBOptionsAttributes *rv = new DBOptionsAttributes;\n    return rv;\n}\n"
  },
  {
    "path": "plugins/visit/VDC/avtvdfOptions.h",
    "content": "/*****************************************************************************\n *\n * Copyright (c) 2000 - 2009, Lawrence Livermore National Security, LLC\n * Produced at the Lawrence Livermore National Laboratory\n * LLNL-CODE-400124\n * All rights reserved.\n *\n * This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n * full copyright notice is contained in the file COPYRIGHT located at the root\n * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n *\n * Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n * modification, are permitted provided that the following conditions are met:\n *\n *  - Redistributions of  source code must  retain the above  copyright notice,\n *    this list of conditions and the disclaimer below.\n *  - Redistributions in binary form must reproduce the above copyright notice,\n *    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n *    documentation and/or other materials provided with the distribution.\n *  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n *    be used to endorse or promote products derived from this software without\n *    specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n * ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n * LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n * DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n * CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n * LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n * OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n * DAMAGE.\n *\n *****************************************************************************/\n\n// ************************************************************************* //\n//                             avtvdfOptions.h                              //\n// ************************************************************************* //\n\n#ifndef AVT_vdf_OPTIONS_H\n#define AVT_vdf_OPTIONS_H\n\nclass DBOptionsAttributes;\n\n#include <string>\n\n// ****************************************************************************\n//  Functions: avtvdfOptions\n//\n//  Purpose:\n//      Creates the options for  vdf readers and/or writers.\n//\n//  Programmer: dlagreca -- generated by xml2avt\n//  Creation:   Wed Apr 7 14:43:06 PST 2010\n//\n// ****************************************************************************\n\nDBOptionsAttributes *GetvdfReadOptions(void);\nDBOptionsAttributes *GetvdfWriteOptions(void);\n\n#endif\n"
  },
  {
    "path": "plugins/visit/VDC/vdf.xml",
    "content": "<?xml version=\"1.0\"?>\n  <Plugin name=\"vdf\" type=\"database\" label=\"Vapor Data File\" version=\"1.01\" enabled=\"true\" mdspecificcode=\"false\" engspecificcode=\"false\" onlyengine=\"false\" noengine=\"false\" dbtype=\"MTMD\" haswriter=\"false\" hasoptions=\"true\" filePatternsStrict=\"false\" opensWholeDirectory=\"false\">\n    <CXXFLAGS>\n      -I/Applications/VAPOR.app/Contents/Frameworks/Headers\n      -I/glade/proj3/DASG/VAPOR/third-party/apps-2.0.2/Darwin_x86_64/include\n    </CXXFLAGS>\n    <LDFLAGS>\n      -L/Applications/VAPOR.app/Contents/MacOS\n      -L/glade/proj3/DASG/VAPOR/third-party/apps-2.0.2/Darwin_x86_64/lib\n    </LDFLAGS>\n    <LIBS>\n       vdf\n       common\n       netcdf\n       expat\n    </LIBS>\n    <FilePatterns>\n      *.vdf\n    </FilePatterns>\n    <Attribute name=\"\" purpose=\"\" persistent=\"false\" keyframe=\"true\" exportAPI=\"\" exportInclude=\"\">\n    </Attribute>\n  </Plugin>\n"
  },
  {
    "path": "plugins/visit/VDC/vdf2.xml",
    "content": "<?xml version=\"1.0\"?>\n  <Plugin name=\"vdf\" type=\"database\" label=\"Vapor Data File\" version=\"1.01\" enabled=\"true\" mdspecificcode=\"false\" engspecificcode=\"false\" onlyengine=\"false\" noengine=\"false\" dbtype=\"MTMD\" haswriter=\"false\" hasoptions=\"true\" filePatternsStrict=\"false\" opensWholeDirectory=\"false\">\n    <CXXFLAGS>\n      -I/Applications/VAPOR.app/Contents/Frameworks/Headers\n      -I/glade/proj3/DASG/VAPOR/third-party/apps-2.0.2/Darwin_x86_64/include\n      -I/Users/pearse/vapor30/include\n      -I/opt/local/include\n    </CXXFLAGS>\n    <LDFLAGS>\n      -L/Applications/VAPOR.app/Contents/MacOS\n      -L/glade/proj3/DASG/VAPOR/third-party/apps-2.0.2/Darwin_x86_64/lib\n      -L/Users/pearse/vapor30/targets/Darwin_x86_64/bin\n      -L/Applications/VAPOR/VAPOR.app/Contents/MacOS\n    </LDFLAGS>\n    <LIBS>\n       vdf\n       common\n       netcdf\n       expat\n    </LIBS>\n    <FilePatterns>\n      *.vdf\n    </FilePatterns>\n    <Attribute name=\"\" purpose=\"\" persistent=\"false\" keyframe=\"true\" exportAPI=\"\" exportInclude=\"\">\n    </Attribute>\n  </Plugin>\n"
  },
  {
    "path": "plugins/visit/VDC/vdfCommonPluginInfo.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-400124\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n#include <vdfPluginInfo.h>\n#include <avtvdfFileFormat.h>\n#include <avtMTMDFileFormatInterface.h>\n#include <avtGenericDatabase.h>\n#include <avtvdfOptions.h>\n\n// ****************************************************************************\n//  Method:  vdfCommonPluginInfo::GetDatabaseType\n//\n//  Purpose:\n//    Returns the type of a vdf database.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nDatabaseType\nvdfCommonPluginInfo::GetDatabaseType()\n{\n    return DB_TYPE_MTMD;\n}\n\n// ****************************************************************************\n//  Method: vdfCommonPluginInfo::SetupDatabase\n//\n//  Purpose:\n//      Sets up a vdf database.\n//\n//  Arguments:\n//      list    A list of file names.\n//      nList   The number of timesteps in list.\n//      nBlocks The number of blocks in the list.\n//\n//  Returns:    A vdf database from list.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\navtDatabase *\nvdfCommonPluginInfo::SetupDatabase(const char *const *list,\n                                   int nList, int nBlock)\n{\n    // ignore any nBlocks past 1\n    int nTimestepGroups = nList / nBlock;\n    avtMTMDFileFormat **ffl = new avtMTMDFileFormat*[nTimestepGroups];\n    for (int i = 0 ; i < nTimestepGroups ; i++)\n    {\n        ffl[i] = new avtvdfFileFormat(list[i*nBlock], readOptions);\n    }\n    avtMTMDFileFormatInterface *inter \n           = new avtMTMDFileFormatInterface(ffl, nTimestepGroups);\n    return new avtGenericDatabase(inter);\n}\n\n// ****************************************************************************\n//  Method: vdfCommonPluginInfo::GetReadOptions\n//\n//  Purpose:\n//      Gets the read options.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nDBOptionsAttributes *\nvdfCommonPluginInfo::GetReadOptions() const\n{\n    return GetvdfReadOptions();\n}\n// ****************************************************************************\n//  Method: vdfCommonPluginInfo::GetWriteOptions\n//\n//  Purpose:\n//      Gets the write options.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nDBOptionsAttributes *\nvdfCommonPluginInfo::GetWriteOptions() const\n{\n    return GetvdfWriteOptions();\n}\n"
  },
  {
    "path": "plugins/visit/VDC/vdfEnginePluginInfo.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-400124\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n#include <vdfPluginInfo.h>\n\n// ****************************************************************************\n//  Function:  GetEngineInfo\n//\n//  Purpose:\n//    Return a new EnginePluginInfo for the vdf database.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\nextern \"C\" DBP_EXPORT EngineDatabasePluginInfo* vdf_GetEngineInfo()\n{\n    return new vdfEnginePluginInfo;\n}\n\n// ****************************************************************************\n//  Method: vdfEnginePluginInfo::GetWriter\n//\n//  Purpose:\n//      Sets up a vdf writer.\n//\n//  Returns:    A vdf writer.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\navtDatabaseWriter *\nvdfEnginePluginInfo::GetWriter(void)\n{\n    return NULL;\n}\n\n"
  },
  {
    "path": "plugins/visit/VDC/vdfMDServerPluginInfo.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-400124\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n#include <vdfPluginInfo.h>\n\n// ****************************************************************************\n//  Function:  GetMDServerInfo\n//\n//  Purpose:\n//    Return a new MDServerPluginInfo for the vdf database.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\nextern \"C\" DBP_EXPORT MDServerDatabasePluginInfo* vdf_GetMDServerInfo()\n{\n    return new vdfMDServerPluginInfo;\n}\n\n// this makes compilers happy... remove if we ever have functions here\nvoid vdfMDServerPluginInfo::dummy()\n{\n}\n\n"
  },
  {
    "path": "plugins/visit/VDC/vdfPluginInfo.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-400124\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n// ************************************************************************* //\n//  File: vdfPluginInfo.C\n// ************************************************************************* //\n\n#include <vdfPluginInfo.h>\n\n#include <visit-config.h>\nextern \"C\" DBP_EXPORT const char *vdfVisItPluginVersion = VISIT_VERSION;\n\n// ****************************************************************************\n//  Function:  GetGeneralInfo\n//\n//  Purpose:\n//    Return a new GeneralPluginInfo for the vdf database.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nextern \"C\" DBP_EXPORT GeneralDatabasePluginInfo* vdf_GetGeneralInfo()\n{\n    return new vdfGeneralPluginInfo;\n}\n\n// ****************************************************************************\n//  Method: vdfGeneralPluginInfo::GetName\n//\n//  Purpose:\n//    Return the name of the database plugin.\n//\n//  Returns:    A pointer to the name of the database plugin.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nconst char *\nvdfGeneralPluginInfo::GetName() const\n{\n    return \"vdf\";\n}\n\n// ****************************************************************************\n//  Method: vdfGeneralPluginInfo::GetVersion\n//\n//  Purpose:\n//    Return the version of the database plugin.\n//\n//  Returns:    A pointer to the version of the database plugin.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nconst char *\nvdfGeneralPluginInfo::GetVersion() const\n{\n    return \"1.0\";\n}\n\n// ****************************************************************************\n//  Method: vdfGeneralPluginInfo::GetID\n//\n//  Purpose:\n//    Return the id of the database plugin.\n//\n//  Returns:    A pointer to the id of the database plugin.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nconst char *\nvdfGeneralPluginInfo::GetID() const\n{\n    return \"vdf_1.0\";\n}\n// ****************************************************************************\n//  Method: vdfGeneralPluginInfo::EnabledByDefault\n//\n//  Purpose:\n//    Return true if this plugin should be enabled by default; false otherwise.\n//\n//  Returns:    true/false\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nbool\nvdfGeneralPluginInfo::EnabledByDefault() const\n{\n    return true;\n}\n// ****************************************************************************\n//  Method: vdfGeneralPluginInfo::HasWriter\n//\n//  Purpose:\n//    Return true if this plugin has a database writer.\n//\n//  Returns:    true/false\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nbool\nvdfGeneralPluginInfo::HasWriter() const\n{\n    return false;\n}\n// ****************************************************************************\n//  Method:  vdfGeneralPluginInfo::GetDefaultFilePatterns\n//\n//  Purpose:\n//    Returns the default patterns for a vdf database.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nstd::vector<std::string>\nvdfGeneralPluginInfo::GetDefaultFilePatterns() const\n{\n    std::vector<std::string> defaultPatterns;\n    defaultPatterns.push_back(\"*.vdf\");\n\n    return defaultPatterns;\n}\n\n// ****************************************************************************\n//  Method:  vdfGeneralPluginInfo::AreDefaultFilePatternsStrict\n//\n//  Purpose:\n//    Returns if the file patterns for a vdf database are\n//    intended to be interpreted strictly by default.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nbool\nvdfGeneralPluginInfo::AreDefaultFilePatternsStrict() const\n{\n    return false;\n}\n\n// ****************************************************************************\n//  Method:  vdfGeneralPluginInfo::OpensWholeDirectory\n//\n//  Purpose:\n//    Returns if the vdf plugin opens a whole directory name\n//    instead of a single file.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nbool\nvdfGeneralPluginInfo::OpensWholeDirectory() const\n{\n    return false;\n}\n"
  },
  {
    "path": "plugins/visit/VDC/vdfPluginInfo.h",
    "content": "/*****************************************************************************\n *\n * Copyright (c) 2000 - 2010, Lawrence Livermore National Security, LLC\n * Produced at the Lawrence Livermore National Laboratory\n * LLNL-CODE-400124\n * All rights reserved.\n *\n * This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n * full copyright notice is contained in the file COPYRIGHT located at the root\n * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n *\n * Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n * modification, are permitted provided that the following conditions are met:\n *\n *  - Redistributions of  source code must  retain the above  copyright notice,\n *    this list of conditions and the disclaimer below.\n *  - Redistributions in binary form must reproduce the above copyright notice,\n *    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n *    documentation and/or other materials provided with the distribution.\n *  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n *    be used to endorse or promote products derived from this software without\n *    specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n * ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n * LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n * DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n * CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n * LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n * OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n * DAMAGE.\n *\n *****************************************************************************/\n\n// ****************************************************************************\n//                               vdfPluginInfo.h\n// ****************************************************************************\n\n#ifndef VDF_PLUGIN_INFO_H\n#define VDF_PLUGIN_INFO_H\n#include <DatabasePluginInfo.h>\n#include <database_plugin_exports.h>\n\nclass avtDatabase;\nclass avtDatabaseWriter;\n\n// ****************************************************************************\n//  Class: vdfDatabasePluginInfo\n//\n//  Purpose:\n//    Classes that provide all the information about the vdf plugin.\n//    Portions are separated into pieces relevant to the appropriate\n//    components of VisIt.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n//  Modifications:\n//\n// ****************************************************************************\n\nclass vdfGeneralPluginInfo : public virtual GeneralDatabasePluginInfo {\npublic:\n    virtual const char *             GetName() const;\n    virtual const char *             GetVersion() const;\n    virtual const char *             GetID() const;\n    virtual bool                     EnabledByDefault() const;\n    virtual bool                     HasWriter() const;\n    virtual std::vector<std::string> GetDefaultFilePatterns() const;\n    virtual bool                     AreDefaultFilePatternsStrict() const;\n    virtual bool                     OpensWholeDirectory() const;\n};\n\nclass vdfCommonPluginInfo : public virtual CommonDatabasePluginInfo, public virtual vdfGeneralPluginInfo {\npublic:\n    virtual DatabaseType         GetDatabaseType();\n    virtual avtDatabase *        SetupDatabase(const char *const *list, int nList, int nBlock);\n    virtual DBOptionsAttributes *GetReadOptions() const;\n    virtual DBOptionsAttributes *GetWriteOptions() const;\n};\n\nclass vdfMDServerPluginInfo : public virtual MDServerDatabasePluginInfo, public virtual vdfCommonPluginInfo {\npublic:\n    // this makes compilers happy... remove if we ever have functions here\n    virtual void dummy();\n};\n\nclass vdfEnginePluginInfo : public virtual EngineDatabasePluginInfo, public virtual vdfCommonPluginInfo {\npublic:\n    virtual avtDatabaseWriter *GetWriter(void);\n};\n\n#endif\n"
  },
  {
    "path": "plugins/visit/WASP/README",
    "content": "VisIt VDC Reader Plugin\n\nThe contents of this directory provide a WASP import\nplugin for VisIt (https://wci.llnl.gov/codes/visit/home.html). \n\n\n===============\n How To Build\n===============\n\nNote:  That you do not need to have built your own version of Visit\nor VAPoR, this will work with downloaded binary version.  This code has\nbeen tested Mac and Linux platforms for VisIt 2.9.2 and VAPOR 3.0\n\n----------------------\n\n1) Install VisIt and VAPOR on your system.\n\n2) Edit the WASP.xml file and make sure that the libray and include\npaths are correct for your installation of Vapor.  This file is \nlocated in $VAPOR_HOME/plugins/visit/WASP.  \n\nYou will need to set the CXXFLAGS to include:\n\tWASP.h\n\nThe LDFLAGS elements will need to point to the following vapor libs:\n\tcommon\n\tnetcdf\n\twasp\n\nYou may also need to edit the LIBS element (for linux the 'rt'\nlibrary is required).\n\nFor more information see \"Getting Data Into VisIT\" available from:\nhttps://wci.llnl.gov/codes/visit/manuals.html\n\n3) Navigate to $VAPOR_HOME/plugins/visit/WASP.  Remove the file \nCMakeCache.txt if it exists.\n\n4) Next to generate the CMakeLists.txt by running:\n\n\txml2cmake -clobber WASP.xml\n\nThis command is found in VISITARCHHOME/bin .\n\n6) Use cmake to generate a Makefile, run:\n\n\tcmake .\n\n7) Finally, build the binaries by running:\n\n\tmake clean all\n\nThis will build the 4 shared objects which make up the plugin (3\nif MPI is not used). The plugin will be installed in the directory\n~/.visit/<arch>/plugins/database/\n\n==============================\n Platform Specific Notes\n==============================\n\nMac OS\n------\n\nPrior to executing visit the environment variable\nDYLD_FALLBACK_LIBRARY_PATH must be set to the path where VAPOR's\nlibraries were installed. For a binary installation of VAPOR this\nwill be /Applications/VAPOR.app/Contents/MacOS :\n\n\tsetenv DYLD_FALLBACK_LIBRARY_PATH /Applications/VAPOR.app/Contents/MacOS\n\nLinux\n-----\n\nOn linux systems the library 'rt' must be added to the LIBS element of the \nWASP.xml configuration file.\n"
  },
  {
    "path": "plugins/visit/WASP/WASP.xml",
    "content": "<?xml version=\"1.0\"?>\n  <Plugin name=\"WASP\" type=\"database\" label=\"Wavelet-enabled progressive data Access and Storage Protocol\" version=\"1.0\" enabled=\"true\" mdspecificcode=\"false\" engspecificcode=\"false\" onlyengine=\"false\" noengine=\"false\" dbtype=\"MTMD\" haswriter=\"false\" hasoptions=\"false\" filePatternsStrict=\"false\" opensWholeDirectory=\"false\">\n    <CXXFLAGS>\n\t-I/Users/pearse/vapor3/include\n\t-I/opt/local/include\n\t</CXXFLAGS>\n    <LDFLAGS>\n      -L/Users/pearse/vapor3/targets/Darwin_x86_64/bin\n      -L/Applications/VAPOR3/VAPOR.app/Contents/MacOS\n    </LDFLAGS>\n    <LIBS>\n       common\n       netcdf\n       wasp\n    </LIBS>\n    <FilePatterns>\n\t\t*.nc\n    </FilePatterns>\n    <Attribute name=\"\" purpose=\"\" persistent=\"true\" keyframe=\"true\" exportAPI=\"\" exportInclude=\"\">\n    </Attribute>\n  </Plugin>\n"
  },
  {
    "path": "plugins/visit/WASP/WASPCommonPluginInfo.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-442911\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n#include <WASPPluginInfo.h>\n#include <avtWASPFileFormat.h>\n#include <avtMTMDFileFormatInterface.h>\n#include <avtGenericDatabase.h>\n\n// ****************************************************************************\n//  Method:  WASPCommonPluginInfo::GetDatabaseType\n//\n//  Purpose:\n//    Returns the type of a WASP database.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nDatabaseType\nWASPCommonPluginInfo::GetDatabaseType()\n{\n    return DB_TYPE_MTMD;\n}\n\n// ****************************************************************************\n//  Method: WASPCommonPluginInfo::SetupDatabase\n//\n//  Purpose:\n//      Sets up a WASP database.\n//\n//  Arguments:\n//      list    A list of file names.\n//      nList   The number of timesteps in list.\n//      nBlocks The number of blocks in the list.\n//\n//  Returns:    A WASP database from list.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\navtDatabase *\nWASPCommonPluginInfo::SetupDatabase(const char *const *list,\n                                   int nList, int nBlock)\n{\n    // ignore any nBlocks past 1\n    int nTimestepGroups = nList / nBlock;\n    avtMTMDFileFormat **ffl = new avtMTMDFileFormat*[nTimestepGroups];\n    for (int i = 0 ; i < nTimestepGroups ; i++)\n    {\n        ffl[i] = new avtWASPFileFormat(list[i*nBlock]);\n    }\n    avtMTMDFileFormatInterface *inter \n           = new avtMTMDFileFormatInterface(ffl, nTimestepGroups);\n    return new avtGenericDatabase(inter);\n}\n// ****************************************************************************\n//  Method: WASPCommonPluginInfo::GetLicense\n//\n//  Purpose:\n//      Gets the write options.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nstd::string\nWASPCommonPluginInfo::GetLicense() const\n{\n    return std::string();\n}\n"
  },
  {
    "path": "plugins/visit/WASP/WASPEnginePluginInfo.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-442911\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n#include <WASPPluginInfo.h>\n\n// ****************************************************************************\n//  Function:  GetEngineInfo\n//\n//  Purpose:\n//    Return a new EnginePluginInfo for the WASP database.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\nextern \"C\" DBP_EXPORT EngineDatabasePluginInfo* WASP_GetEngineInfo()\n{\n    return new WASPEnginePluginInfo;\n}\n\n// ****************************************************************************\n//  Method: WASPEnginePluginInfo::GetWriter\n//\n//  Purpose:\n//      Sets up a WASP writer.\n//\n//  Returns:    A WASP writer.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\navtDatabaseWriter *\nWASPEnginePluginInfo::GetWriter(void)\n{\n    return NULL;\n}\n\n"
  },
  {
    "path": "plugins/visit/WASP/WASPMDServerPluginInfo.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-442911\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n#include <WASPPluginInfo.h>\n\n// ****************************************************************************\n//  Function:  GetMDServerInfo\n//\n//  Purpose:\n//    Return a new MDServerPluginInfo for the WASP database.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\nextern \"C\" DBP_EXPORT MDServerDatabasePluginInfo* WASP_GetMDServerInfo()\n{\n    return new WASPMDServerPluginInfo;\n}\n\n// this makes compilers happy... remove if we ever have functions here\nvoid WASPMDServerPluginInfo::dummy()\n{\n}\n\n"
  },
  {
    "path": "plugins/visit/WASP/WASPPluginInfo.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-442911\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n// ************************************************************************* //\n//  File: WASPPluginInfo.C\n// ************************************************************************* //\n\n#include <WASPPluginInfo.h>\n\n#include <visit-config.h>\nVISIT_PLUGIN_VERSION(WASP,DBP_EXPORT)\n\n// ****************************************************************************\n//  Function:  GetGeneralInfo\n//\n//  Purpose:\n//    Return a new GeneralPluginInfo for the WASP database.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nextern \"C\" DBP_EXPORT GeneralDatabasePluginInfo* WASP_GetGeneralInfo()\n{\n    return new WASPGeneralPluginInfo;\n}\n\n// ****************************************************************************\n//  Method: WASPGeneralPluginInfo::GetName\n//\n//  Purpose:\n//    Return the name of the database plugin.\n//\n//  Returns:    A pointer to the name of the database plugin.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nconst char *\nWASPGeneralPluginInfo::GetName() const\n{\n    return \"WASP\";\n}\n\n// ****************************************************************************\n//  Method: WASPGeneralPluginInfo::GetVersion\n//\n//  Purpose:\n//    Return the version of the database plugin.\n//\n//  Returns:    A pointer to the version of the database plugin.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nconst char *\nWASPGeneralPluginInfo::GetVersion() const\n{\n    return \"1.0\";\n}\n\n// ****************************************************************************\n//  Method: WASPGeneralPluginInfo::GetID\n//\n//  Purpose:\n//    Return the id of the database plugin.\n//\n//  Returns:    A pointer to the id of the database plugin.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nconst char *\nWASPGeneralPluginInfo::GetID() const\n{\n    return \"WASP_1.0\";\n}\n// ****************************************************************************\n//  Method: WASPGeneralPluginInfo::EnabledByDefault\n//\n//  Purpose:\n//    Return true if this plugin should be enabled by default; false otherwise.\n//\n//  Returns:    true/false\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nbool\nWASPGeneralPluginInfo::EnabledByDefault() const\n{\n    return true;\n}\n// ****************************************************************************\n//  Method: WASPGeneralPluginInfo::HasWriter\n//\n//  Purpose:\n//    Return true if this plugin has a database writer.\n//\n//  Returns:    true/false\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n// ****************************************************************************\n\nbool\nWASPGeneralPluginInfo::HasWriter() const\n{\n    return false;\n}\n// ****************************************************************************\n//  Method:  WASPGeneralPluginInfo::GetDefaultFilePatterns\n//\n//  Purpose:\n//    Returns the default patterns for a WASP database.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nstd::vector<std::string>\nWASPGeneralPluginInfo::GetDefaultFilePatterns() const\n{\n    std::vector<std::string> defaultPatterns;\n    defaultPatterns.push_back(\"*.nc\");\n\n    return defaultPatterns;\n}\n\n// ****************************************************************************\n//  Method:  WASPGeneralPluginInfo::AreDefaultFilePatternsStrict\n//\n//  Purpose:\n//    Returns if the file patterns for a WASP database are\n//    intended to be interpreted strictly by default.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nbool\nWASPGeneralPluginInfo::AreDefaultFilePatternsStrict() const\n{\n    return false;\n}\n\n// ****************************************************************************\n//  Method:  WASPGeneralPluginInfo::OpensWholeDirectory\n//\n//  Purpose:\n//    Returns if the WASP plugin opens a whole directory name\n//    instead of a single file.\n//\n//  Programmer:  generated by xml2info\n//  Creation:    omitted\n//\n// ****************************************************************************\nbool\nWASPGeneralPluginInfo::OpensWholeDirectory() const\n{\n    return false;\n}\n"
  },
  {
    "path": "plugins/visit/WASP/WASPPluginInfo.h",
    "content": "/*****************************************************************************\n *\n * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC\n * Produced at the Lawrence Livermore National Laboratory\n * LLNL-CODE-442911\n * All rights reserved.\n *\n * This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n * full copyright notice is contained in the file COPYRIGHT located at the root\n * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n *\n * Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n * modification, are permitted provided that the following conditions are met:\n *\n *  - Redistributions of  source code must  retain the above  copyright notice,\n *    this list of conditions and the disclaimer below.\n *  - Redistributions in binary form must reproduce the above copyright notice,\n *    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n *    documentation and/or other materials provided with the distribution.\n *  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n *    be used to endorse or promote products derived from this software without\n *    specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n * ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n * LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n * DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n * CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n * LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n * OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n * DAMAGE.\n *\n *****************************************************************************/\n\n// ****************************************************************************\n//                               WASPPluginInfo.h\n// ****************************************************************************\n\n#ifndef WASP_PLUGIN_INFO_H\n#define WASP_PLUGIN_INFO_H\n#include <DatabasePluginInfo.h>\n#include <database_plugin_exports.h>\n\nclass avtDatabase;\nclass avtDatabaseWriter;\n\n// ****************************************************************************\n//  Class: WASPDatabasePluginInfo\n//\n//  Purpose:\n//    Classes that provide all the information about the WASP plugin.\n//    Portions are separated into pieces relevant to the appropriate\n//    components of VisIt.\n//\n//  Programmer: generated by xml2info\n//  Creation:   omitted\n//\n//  Modifications:\n//\n// ****************************************************************************\n\nclass WASPGeneralPluginInfo : public virtual GeneralDatabasePluginInfo {\npublic:\n    virtual const char *             GetName() const;\n    virtual const char *             GetVersion() const;\n    virtual const char *             GetID() const;\n    virtual bool                     EnabledByDefault() const;\n    virtual bool                     HasWriter() const;\n    virtual std::vector<std::string> GetDefaultFilePatterns() const;\n    virtual bool                     AreDefaultFilePatternsStrict() const;\n    virtual bool                     OpensWholeDirectory() const;\n};\n\nclass WASPCommonPluginInfo : public virtual CommonDatabasePluginInfo, public virtual WASPGeneralPluginInfo {\npublic:\n    virtual DatabaseType GetDatabaseType();\n    virtual avtDatabase *SetupDatabase(const char *const *list, int nList, int nBlock);\n    virtual std::string  GetLicense() const;\n};\n\nclass WASPMDServerPluginInfo : public virtual MDServerDatabasePluginInfo, public virtual WASPCommonPluginInfo {\npublic:\n    // this makes compilers happy... remove if we ever have functions here\n    virtual void dummy();\n};\n\nclass WASPEnginePluginInfo : public virtual EngineDatabasePluginInfo, public virtual WASPCommonPluginInfo {\npublic:\n    virtual avtDatabaseWriter *GetWriter(void);\n};\n\n#endif\n"
  },
  {
    "path": "plugins/visit/WASP/avtWASPFileFormat.C",
    "content": "/*****************************************************************************\n*\n* Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC\n* Produced at the Lawrence Livermore National Laboratory\n* LLNL-CODE-442911\n* All rights reserved.\n*\n* This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n* full copyright notice is contained in the file COPYRIGHT located at the root\n* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n*\n* Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n* modification, are permitted provided that the following conditions are met:\n*\n*  - Redistributions of  source code must  retain the above  copyright notice,\n*    this list of conditions and the disclaimer below.\n*  - Redistributions in binary form must reproduce the above copyright notice,\n*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n*    documentation and/or other materials provided with the distribution.\n*  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n*    be used to endorse or promote products derived from this software without\n*    specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n* ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n* LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n* DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n* DAMAGE.\n*\n*****************************************************************************/\n\n// ************************************************************************* //\n//                            avtWASPFileFormat.C                           //\n// ************************************************************************* //\n\n#include <avtWASPFileFormat.h>\n#include <avtIntervalTree.h>\n\n#include <string>\n\n#include <vtkFloatArray.h>\n#include <vtkRectilinearGrid.h>\n#include <vtkStructuredGrid.h>\n#include <vtkUnstructuredGrid.h>\n\n#include <avtDatabaseMetaData.h>\n\n#include <DBOptionsAttributes.h>\n#include <Expression.h>\n\n#include <InvalidVariableException.h>\n#include <InvalidDBTypeException.h>\n#include <DebugStream.h>\n\n#include <string>\n#include <sstream>\n#include <stdlib.h>\n\nbool useBlocks=1;\n\ntemplate <typename T>\nstring ToString(T val)\n{\n    stringstream stream;\n    stream << val;\n    return stream.str();\n}\n\nstd::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {\n    std::stringstream ss(s);\n    std::string item;\n    while (std::getline(ss, item, delim)) {\n        elems.push_back(item);\n    }\n    return elems;\n}\n\n// ****************************************************************************\n//  Method: avtWASPFileFormat constructor\n//\n//  Programmer: pearse -- generated by xml2avt\n//  Creation:   Wed Jan 20 15:04:04 PST 2016\n//\n// ****************************************************************************\n\navtWASPFileFormat::avtWASPFileFormat(const char *filename)\n: avtMTMDFileFormat(filename){\n\tinitialized = false;\n\tinFile = filename;\n\twasp = new VAPoR::WASP(1);\n}\n\navtWASPFileFormat::~avtWASPFileFormat(){\n\tif (wasp) delete wasp;\n}\n\t\nvoid avtWASPFileFormat::ActivateTimestep() {\n\tInitialize();\n}\n\t\nvoid avtWASPFileFormat::Initialize() {\n\tsize_t nlevels, maxcratio;\n\tvector<size_t> dims,bs;\n\n\tif(!initialized){\n\t\tbool okay = false;\n\t\tstd::vector <std::string> allVars;\n\t\t\n\t\twasp->Open(inFile,0);\n\t\twasp->InqVarnames(allVars);\n\t\tstd::vector<std::string>::iterator it;\n\t\tfor (it=allVars.begin(); it != allVars.end(); ++it){\n\t\t\twasp->InqVarWASP(*it,okay);\n\t\t\tif (okay){\n\t\t\t\twasp->InqVarDimlens(*it,0,dims,bs);\n\t\t\t\tif (dims.size() > 2) {\n\t\t\t\t\tvarNames.push_back(*it);\n\t\t\t\t\tdebug1 << \"WASP says \" << *it << \" is ok!\" << endl;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdebug1 << \"Ommitting 2D variable \" << *it << endl;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\t\n\t\t\t\tdebug1 << \"WASP says \" << *it << \" is NOT ok!\" << endl;\n\t\t}\n\n\t\tinitialized = true;\n\t}\n\telse {\n\t\tdebug1 << \"We've already initialized\" << endl;\n\t}\n}\n\n// ****************************************************************************\n//  Method: avtEMSTDFileFormat::GetNTimesteps\n//\n//  Purpose:\n//      Tells the rest of the code how many timesteps there are in this file.\n//\n//  Programmer: pearse -- generated by xml2avt\n//  Creation:   Wed Jan 20 15:04:04 PST 2016\n//\n// ****************************************************************************\n\nint\navtWASPFileFormat::GetNTimesteps(void)\n{\n\t// We are only supporting one timestep at a time\n\treturn 1;\n}\n\n\n// ****************************************************************************\n//  Method: avtWASPFileFormat::FreeUpResources\n//\n//  Purpose:\n//      When VisIt is done focusing on a particular timestep, it asks that\n//      timestep to free up any resources (memory, file descriptors) that\n//      it has associated with it.  This method is the mechanism for doing\n//      that.\n//\n//  Programmer: pearse -- generated by xml2avt\n//  Creation:   Wed Jan 20 15:04:04 PST 2016\n//\n// ****************************************************************************\n\nvoid\navtWASPFileFormat::FreeUpResources(void)\n{\n}\n\n\n// ****************************************************************************\n//  Method: avtWASPFileFormat::PopulateDatabaseMetaData\n//\n//  Purpose:\n//      This database meta-data object is like a table of contents for the\n//      file.  By populating it, you are telling the rest of VisIt what\n//      information it can request from you.\n//\n//  Programmer: pearse -- generated by xml2avt\n//  Creation:   Wed Jan 20 15:04:04 PST 2016\n//\n// ****************************************************************************\n\nvoid\navtWASPFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md, int timeState)\n{\n\tInitialize(); \n\n\n\tstring wname;\n\tint refLevels;\n\tstring varName;\n\tvector <size_t> dims, bs;\n\tstd::vector<std::string>::iterator it;\n\tint blockedDims[3];\n\n\t// Iterate over each variable\n\tfor (it=varNames.begin(); it != varNames.end(); ++it){\n\n\t\tvarName = *it;\n\t\tint rc = wasp->OpenVarRead(varName,0,3);\n\t\tif (rc!=0) {\n\t\t\tdebug1 << \"Unable to open variable \" << varName << endl;\n\t\t\tdebug1 << \"rc: \" << rc << endl;\n\t\t}\n\n\t\t// Iterate over each refinement level and lod\n\t\trefLevels = wasp->InqVarNumRefLevels(varName);\n\t\tfor (int i=0; i<refLevels; i++){\n\t\n\t\t\t// Calculate the dimensions of our set of blocks at current ref. level\n\t\t\tint rc = wasp->InqVarDimlens(varName,i,dims,bs);\n\t\t\tif (bs.empty()){\n\t\t\t\tbs = dims;\n\t\t\t}\n\n\t\t\t// Swap Z and X dimension axes\t\t\t\n\t\t\tint tmp = bs[0];\n\t\t\tbs[0] = bs[2];\n\t\t\tbs[2] = tmp;\n\t\t\ttmp = dims[0];\n\t\t\tdims[0] = dims[2];\n\t\t\tdims[2] = tmp;\n\n\t\t\tif (rc) EXCEPTION1(InvalidDBTypeException,\"The WASP file's dimensionality could not be read.\");\n\n\t\t\t// Calculate number of blocks on each axis\n\t\t\tfor (int j=0; j<3; j++){\n\t\t\t\tblockedDims[j] = dims[j]/bs[j];\n\t\t\t\tif (dims[j]%bs[j] > 0) blockedDims[j]+=1;\t\n\t\t\t}\n\n\t\t\t// Aggregate remaining metadata\n\t\t\tavtMeshType meshType = AVT_RECTILINEAR_MESH;\n\t\t\tint numBlocks = 1;\n\t\t\tif (useBlocks) numBlocks = blockedDims[0] * blockedDims[1] * blockedDims[2];\n\n\t\t\tint blockOrigin = 0;\n\t\t\tint spatialDimension = dims.size();\n\t\t\tint topologicalDimension = 3;\n\t\t\tdouble *extents = NULL;\n\t\n\t\t\tstring meshName = varName + \"-mesh-\" + ToString(i);\n\t\t\tAddMeshToMetaData(md, meshName, meshType, extents, numBlocks, blockOrigin,\n\t\t\t\t\t\t\tspatialDimension, topologicalDimension);\n\n\t\t\tvector<size_t> cratios;\n\t\t\twasp->InqVarCompressionParams(*it,wname,bs,cratios);\n\n\t\t\tstring visitVarName;\n\t\t\tfor (size_t j=0; j<cratios.size(); j++){\n\t\t\t\tvisitVarName = varName + \"/ref\" + ToString(i) + \"/lod\" + ToString(cratios[j]);\n\t\t\t\tAddScalarVarToMetaData(md, visitVarName, meshName, AVT_ZONECENT);\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n// ****************************************************************************\n//  Method: avtWASPFileFormat::GetMesh\n//\n//  Purpose:\n//      Gets the mesh associated with this file.  The mesh is returned as a\n//      derived type of vtkDataSet (ie vtkRectilinearGrid, vtkStructuredGrid,\n//      vtkUnstructuredGrid, etc).\n//\n//  Arguments:\n//      timestate   The index of the timestate.  If GetNTimesteps returned\n//                  'N' time steps, this is guaranteed to be between 0 and N-1.\n//      domain      The index of the domain.  If there are NDomains, this\n//                  value is guaranteed to be between 0 and NDomains-1,\n//                  regardless of block origin.\n//      meshname    The name of the mesh of interest.  This can be ignored if\n//                  there is only one mesh.\n//\n//  Programmer: pearse -- generated by xml2avt\n//  Creation:   Wed Jan 20 15:04:04 PST 2016\n//\n// ****************************************************************************\n\nvtkDataSet *\navtWASPFileFormat::GetMesh(int timestate, int domain, const char *meshname)\n{\n\t// Split up meshname to get level and variable information\n\tstring meshName2 = meshname;\n\tvector<string> components;\n\tsplit(meshName2, '-', components);\n\tstring varName = components[0];\n\tint level = atoi(components[2].c_str());\n\t\n\tint rc = wasp->OpenVarRead(varName,level,1);\n\tif (rc!=0) {\n\t\tdebug1 << \"Unable to open variable \" << varName << endl;\n\t\tdebug1 << \"rc: \" << rc << endl;\n\t}\n\n\tvector <size_t> dims, bs;\n\twasp->InqVarDimlens(varName,level,dims,bs);\n\tif (bs.empty()){\n\t\tbs = dims;\n\t}\n\t\n\t// Swap Z and X dimension axes\t\t\t\n\tint tmp = bs[0];\n\tbs[0] = bs[2];\n\tbs[2] = tmp;\n\ttmp = dims[0];\n\tdims[0] = dims[2];\n\tdims[2] = tmp;\n\n\tvtkFloatArray *coords[3] = {0,0,0};\n\tint blockedDims[3], meshDims[3];\n\n\tif (useBlocks) {\n\t\tfor (int i=0; i<3; i++) meshDims[i] = bs[i]+1;\n\t}\n\telse {\n\t\tfor (int i=0; i<3; i++) meshDims[i] = dims[i]+1;\n\t}\n\n\tint xStart=0, yStart=0, zStart=0;\n\tint xEnd=dims[0]+1;\n\tint yEnd=dims[1]+1;\n\tint zEnd=dims[2]+1;\n\n\tif (useBlocks){\n\t\tfor (int j=0; j<3; j++){\n\t\t\tblockedDims[j] = dims[j]/bs[j];\n\t\t\tif (dims[j]%bs[j] > 0) blockedDims[j] = blockedDims[j]+1;\t\n\t\t}\n\t\t\n\t\tint xBlock = domain % blockedDims[0];\n\t\tint yBlock = (domain%(blockedDims[0]*blockedDims[1]))/blockedDims[0];\n\t\tint zBlock = domain/(blockedDims[0]*blockedDims[1]);\n\t\n\t\txStart = bs[0]*xBlock;\n\t\tyStart = bs[1]*yBlock;\n\t\tzStart = bs[2]*zBlock;\n\t\txEnd = bs[0]*(xBlock+1);\n\t\tyEnd = bs[1]*(yBlock+1);\n\t\tzEnd = bs[2]*(zBlock+1);\n\n\t\t// If we are looking at the last block on either the x, y, or z axis,\n\t\t// we may need to trim the end point if the domain is not a multiple\n\t\t// of our block size (in other words, or blocks overshoot our domain)\n\t\tif ((xBlock == blockedDims[0]-1)&&(dims[0]%bs[0]!=0)){\n\t\t\txEnd -= bs[0] - dims[0]%bs[0];\n\t\t\tmeshDims[0] -= bs[0] - dims[0]%bs[0];\n\t\t}\n\t\tif ((yBlock == blockedDims[1]-1)&&(dims[1]%bs[1]!=0)){\n\t\t\tyEnd -= bs[1] - dims[1]%bs[1];\n\t\t\tmeshDims[1] -= bs[1] - dims[1]%bs[1];\n\t\t}\n\t\tif ((zBlock == blockedDims[2]-1)&&(dims[2]%bs[2]!=0)){\n\t\t\tzEnd -= bs[2] - dims[2]%bs[2];\n\t\t\tmeshDims[2] -= bs[2] - dims[2]%bs[2];\n\t\t}\n\t}\n\n\tint xCount = xEnd-xStart+1;\n\tint yCount = yEnd-yStart+1;\n\tint zCount = zEnd-zStart+1;\n\n\t// Read the X coordinates from the file.\n\tcoords[0] = vtkFloatArray::New();\n\tcoords[0]->SetNumberOfTuples(xCount);\n\tfloat *xarray = (float *)coords[0]->GetVoidPointer(0);\n\tfor (int i=0; i<xCount; i++){\n\t\txarray[i] = (float)(xStart+i)/dims[0];\n\t}\n\n\t// Read the Y coordinates from the file.\n\tcoords[1] = vtkFloatArray::New();\n\tcoords[1]->SetNumberOfTuples(yCount);\n\tfloat *yarray = (float *)coords[1]->GetVoidPointer(0);\n\tfor (int i=0; i<yCount; i++){\n\t\tyarray[i] = (float)(yStart+i)/dims[1];\n\t}\n\n\t// Read the Z coordinates from the file.\n\tcoords[2] = vtkFloatArray::New();\n\tif(dims.size() > 2)\n\t{\n\t\tcoords[2]->SetNumberOfTuples(zCount);\n\t\tfloat *zarray = (float *)coords[2]->GetVoidPointer(0);\n\t\tfor (int i=0; i<zCount; i++){\n\t\t\tzarray[i] = (float)(zStart+i)/dims[2];\n\t\t}\n\t}\n\telse\n\t{\n\t\tcoords[2]->SetNumberOfTuples(1);\n\t\tcoords[2]->SetComponent(0, 0, 0.);\n\t}\t\n\n\t// Create the vtkRectilinearGrid object and set its dimensions\n\t// and coordinates.\n\tvtkRectilinearGrid *rgrid = vtkRectilinearGrid::New();\n\trgrid->SetDimensions(meshDims);\n\trgrid->SetXCoordinates(coords[0]);\n\tcoords[0]->Delete();\n\trgrid->SetYCoordinates(coords[1]);\n\tcoords[1]->Delete();\n\trgrid->SetZCoordinates(coords[2]);\n\tcoords[2]->Delete();\n\treturn rgrid;\n}\n\n\n// ****************************************************************************\n//  Method: avtWASPFileFormat::GetVar\n//\n//  Purpose:\n//      Gets a scalar variable associated with this file.  Although VTK has\n//      support for many different types, the best bet is vtkFloatArray, since\n//      that is supported everywhere through VisIt.\n//\n//  Arguments:\n//      timestate  The index of the timestate.  If GetNTimesteps returned\n//                 'N' time steps, this is guaranteed to be between 0 and N-1.\n//      domain     The index of the domain.  If there are NDomains, this\n//                 value is guaranteed to be between 0 and NDomains-1,\n//                 regardless of block origin.\n//      varname    The name of the variable requested.\n//\n//  Programmer: pearse -- generated by xml2avt\n//  Creation:   Wed Jan 20 15:04:04 PST 2016\n//\n// ****************************************************************************\n\nvtkDataArray *\navtWASPFileFormat::GetVar(int timestate, int domain, const char *varname)\n{\n\t// Split varname to get level and lod info\n\tstring inName = varname;\n\tvector<string> components;\n\tsplit(inName, '/', components);\n\tstring varName = components[0];\n\tstring tmpLevel = components[1].erase(0,3);\n\tstring tmpLod = components[2].erase(0,3);\n\tint level = atoi(tmpLevel.c_str());\n\tint lod = atoi(tmpLod.c_str());\n\tsize_t blockedDims[3];\t\n\n\t// Find the index of our compression ratio\t\n\tstd::string temp;\n\tvector<size_t> cratios, temp2;\n\twasp->InqVarCompressionParams(varName,temp,temp2,cratios);\n\tfor (int i=0; i<cratios.size(); i++){\n\t\tif (lod == cratios[i]) lod = i;\n\t}\n\n\tint rc = wasp->OpenVarRead(varName,level,lod);\n\tif (rc!=0) {\n\t\tdebug1 << \"Unable to open variable \" << varName << endl;\n\t\tdebug1 << \"rc: \" << rc << endl;\n\t}\n\n\tvector <size_t> dims, vaporDims, bs, start, count;\n\trc = wasp->InqVarDimlens(varName,level,vaporDims,bs);\n\tif (bs.empty()){\n\t\tbs = dims;\n\t}\n\n\tint tmp = bs[0];\n\tbs[0] = bs[2];\n\tbs[2] = tmp;\n\tdims.push_back(vaporDims[2]);\n\tdims.push_back(vaporDims[1]);\n\tdims.push_back(vaporDims[0]);\n\n\n\tif (rc!=0) {\n\t\tdebug1 << \"Unable to inquire variable \" << varName << endl;\n\t\tdebug1 << \"rc: \" << rc << endl;\n\t}\n\n\tfloat* data;\n\tint xBlock, yBlock, zBlock;\n\tint numVaporDataPoints = 1;\n\tint numVisitDataPoints = 1;\n\tcount = bs;\t\t\t// Number of elements in current block\n\tif (useBlocks) {\n\t\n\t\t// blockedDims is xyz indexed\t\n\t\tfor (int j=0; j<3; j++){\n\t\t\tblockedDims[j] = dims[j]/bs[j];\n\t\t\tif (dims[j]%bs[j] > 0) blockedDims[j] = blockedDims[j]+1;\t\n\t\t}\n\n\t\tint xySize = blockedDims[0] * blockedDims[1];\n\t\txBlock = domain % blockedDims[0];\n\t\tyBlock = (domain % xySize) / blockedDims[0];\n\t\tzBlock = domain / xySize;\n\n\t\tstart.push_back(bs[2]*zBlock);\n\t\tstart.push_back(bs[1]*yBlock);\n\t\tstart.push_back(bs[0]*xBlock);\n\n\t\t// If we are looking at the last block on either the x, y, or z axis,\n\t\t// we may need to trim the end point if the domain is not a multiple\n\t\t// of our block size (in other words, or blocks overshoot our domain)\n\t\tif ((xBlock == blockedDims[0]-1)&&(dims[0]%bs[0]!=0)){\n\t\t\tcount[0] -= count[0]-dims[0]%count[0];\n\t\t}\n\t\tif ((yBlock == blockedDims[1]-1)&&(dims[1]%bs[1]!=0)){\n\t\t\tcount[1] -= count[1]-dims[1]%count[1];\n\t\t}\n\t\tif ((zBlock == blockedDims[2]-1)&&(dims[2]%bs[2]!=0)){\n\t\t\tcount[2] -= count[2]-dims[2]%count[2];\n\t\t}\n\t\t\n\t\tfor (int i=0; i<bs.size(); i++)\t{\n\t\t\tnumVaporDataPoints *= bs[i];\n\t\t\tnumVisitDataPoints *= count[i];\n\t\t}\n\n\t}\n\telse {\n\t\tcount = dims;\n\t\tstart.push_back(0);\n\t\tstart.push_back(0);\n\t\tstart.push_back(0);\n\t\tfor (int i=0; i<dims.size(); i++) numVaporDataPoints *= dims[i];\n\t\tnumVisitDataPoints = numVaporDataPoints;\n\t}\n\n\tdata = new float[numVaporDataPoints];\n\n\tvector<size_t> vaporCount;\n\tvaporCount.push_back(count[2]);\n\tvaporCount.push_back(count[1]);\n\tvaporCount.push_back(count[0]);\n\n\tif (useBlocks) rc = wasp->GetVara(start,vaporCount,data);\n\telse rc = wasp->GetVara(start,vaporDims,data);\n\n\t// Populate visit data array\n\tvtkFloatArray *rv = vtkFloatArray::New();\n\trv->SetNumberOfTuples(numVisitDataPoints);\n\tint visitIndex, vaporIndex, x, y, z;\n\tfor (int i = 0 ; i < numVisitDataPoints ; i++){\n\t\trv->SetTuple1(i,data[i]);\n\t}\n\t\n\tif (data) delete [] data;\n\treturn rv;\n}\n\nvoid* avtWASPFileFormat::GetAuxiliaryData(const char *var, int timestep,\n                                    int domain, const char *type, void *,\n                                    DestructorFunction &df) {\n\tvoid *retval = 0;\n\n\tif(strcmp(type, AUXILIARY_DATA_SPATIAL_EXTENTS) == 0) {\n\t\tvector<size_t> dims,bs;\n\t\tstring inName = var;\n\t\tvector<string> components;\n\t\tsplit(inName, '-', components);\n\t\tstring varName = components[0];\n\t\tint level = atoi(components[2].c_str());\n\t\twasp->InqVarDimlens(varName,level,dims,bs);\n\t\tif (bs.empty() || !useBlocks){\n\t\t\tbs = dims;\n\t\t}\n\t\tint tmp = bs[0];\n\t\tbs[0] = bs[2];\n\t\tbs[2] = tmp;\n\t\ttmp = dims[0];\n\t\tdims[0] = dims[2];\n\t\tdims[2] = tmp;\n\n\t\tint ndoms = 1;\n\t\tvector<size_t> blockedDims;\n\t\tblockedDims.push_back(1);\n\t\tblockedDims.push_back(1);\n\t\tblockedDims.push_back(1);\n\t\tif (useBlocks){\n\t\t\tfor (int j=0; j<3; j++){\n\t\t\t\tblockedDims[j]= dims[j]/bs[j];\n\t\t\t\tif (dims[j]%bs[j] > 0) blockedDims[j] +=1;\t\n\t\t\t}\n\t\t\tndoms = blockedDims[0] * blockedDims[1] * blockedDims[2];\n\t\t}\n\n\n\t\t// Read the spatial extents for each domain of the\n\t\t// mesh. This information should be in a single\n\t\t// and should be available without having to\n\t\t// read the real data. The expected format for\n\t\t// the data in the spatialextents array is to\n\t\t// repeat the following pattern for each domain:\n\t\t// xmin, xmax, ymin, ymax, zmin, zmax.\n\t\tdouble *spatialextents = new double[ndoms * 6];\n\t\tint xMin, xMax, yMin, yMax, zMin, zMax;\n\n\t\t// Create an interval tree\n\t\tavtIntervalTree *itree = new avtIntervalTree(ndoms, 3);\n\t\tdouble extents[6];\n\t\tfor(int dom = 0; dom < ndoms; dom++)\n\t\t{\n\n\t\t\tint xBlock, yBlock, zBlock;\n\t\t\txBlock = dom % blockedDims[0];\n\t\t\tyBlock = (dom % (blockedDims[0]*blockedDims[1])) / blockedDims[0];\n\t\t\tzBlock = dom / (blockedDims[0]*blockedDims[1]);\n\t\t\txMin = xBlock*bs[0];\n\t\t\tyMin = yBlock*bs[1];\n\t\t\tzMin = zBlock*bs[2];\n\t\t\txMax = (xBlock+1)*bs[0];\n\t\t\tyMax = (yBlock+1)*bs[1];\n\t\t\tzMax = (zBlock+1)*bs[2];\n\n\t\t\t// If we are looking at the last block on either the x, y, or z axis,\n\t\t\t// we may need to trim the end point if the domain is not a multiple\n\t\t\t// of our block size (in other words, or blocks overshoot our domain)\n\t\t\tif ((xBlock == blockedDims[0]-1) && (dims[0]%bs[0]!=0))\n\t\t\t\txMax -= bs[0] - dims[0]%bs[0];\n\t\t\tif ((yBlock == blockedDims[1]-1) && (dims[1]%bs[1]!=0))\n\t\t\t\tyMax -= bs[1] - dims[1]%bs[1];\n\t\t\tif ((zBlock == blockedDims[2]-1) && (dims[2]%bs[2]!=0))\n\t\t\t\tzMax -= bs[2] - dims[2]%bs[2];\n\n\t\t\textents[0] = xMin/(float)dims[0];\n\t\t\textents[1] = xMax/(float)dims[0];\n\t\t\textents[2] = yMin/(float)dims[1];\n\t\t\textents[3] = yMax/(float)dims[1];\n\t\t\textents[4] = zMin/(float)dims[2];\n\t\t\textents[5] = zMax/(float)dims[2];\n\n\t\t\titree->AddElement(dom, extents);\n\t\t}\n\t\titree->Calculate(true);\n\t\t\n\t\t// Delete temporary array.\n\t\tif (spatialextents) delete [] spatialextents;\n\t\t\n\t\t// Set return values\n\t\tretval = (void *)itree;\n\t\tdf = avtIntervalTree::Destruct;\n\t}\n\treturn retval;\n}\n"
  },
  {
    "path": "plugins/visit/WASP/avtWASPFileFormat.h",
    "content": "/*****************************************************************************\n *\n * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC\n * Produced at the Lawrence Livermore National Laboratory\n * LLNL-CODE-442911\n * All rights reserved.\n *\n * This file is  part of VisIt. For  details, see https://visit.llnl.gov/.  The\n * full copyright notice is contained in the file COPYRIGHT located at the root\n * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.\n *\n * Redistribution  and  use  in  source  and  binary  forms,  with  or  without\n * modification, are permitted provided that the following conditions are met:\n *\n *  - Redistributions of  source code must  retain the above  copyright notice,\n *    this list of conditions and the disclaimer below.\n *  - Redistributions in binary form must reproduce the above copyright notice,\n *    this  list of  conditions  and  the  disclaimer (as noted below)  in  the\n *    documentation and/or other materials provided with the distribution.\n *  - Neither the name of  the LLNS/LLNL nor the names of  its contributors may\n *    be used to endorse or promote products derived from this software without\n *    specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE\n * ARE  DISCLAIMED. IN  NO EVENT  SHALL LAWRENCE  LIVERMORE NATIONAL  SECURITY,\n * LLC, THE  U.S.  DEPARTMENT OF  ENERGY  OR  CONTRIBUTORS BE  LIABLE  FOR  ANY\n * DIRECT,  INDIRECT,   INCIDENTAL,   SPECIAL,   EXEMPLARY,  OR   CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER\n * CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT\n * LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY\n * OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\n * DAMAGE.\n *\n *****************************************************************************/\n\n// ************************************************************************* //\n//                            avtWASPFileFormat.h                           //\n// ************************************************************************* //\n\n#ifndef AVT_WASP_FILE_FORMAT_H\n#define AVT_WASP_FILE_FORMAT_H\n\n#include <avtMTMDFileFormat.h>\n\n#include <vector>\n\n#include <vapor/WASP.h>\n\n// ****************************************************************************\n//  Class: avtWASPFileFormat\n//\n//  Purpose:\n//      Reads in WASP files as a plugin to VisIt.\n//\n//  Programmer: pearse -- generated by xml2avt\n//  Creation:   Fri Jan 22 12:20:20 PDT 2016\n//\n// ****************************************************************************\n\nclass avtWASPFileFormat : public avtMTMDFileFormat {\npublic:\n    avtWASPFileFormat(const char *);\n    virtual ~avtWASPFileFormat();\n\n    //\n    // This is used to return unconvention data -- ranging from material\n    // information to information about block connectivity.\n    //\n    virtual void *GetAuxiliaryData(const char *var, int timestep, int domain, const char *type, void *args, DestructorFunction &);\n    //\n\n    //\n    // If you know the times and cycle numbers, overload this function.\n    // Otherwise, VisIt will make up some reasonable ones for you.\n    //\n    // virtual void        GetCycles(std::vector<int> &);\n    // virtual void        GetTimes(std::vector<double> &);\n    //\n\n    virtual int GetNTimesteps(void);\n\n    virtual const char *GetType(void) { return \"WASP\"; };\n    virtual void        FreeUpResources(void);\n\n    virtual vtkDataSet *  GetMesh(int, int, const char *);\n    virtual vtkDataArray *GetVar(int, int, const char *);\n    // virtual void* GetAuxiliaryData(const char* var, int ts, const char* type,\n    //                                 void* args, DestructorFunction &);\n\n    void ActivateTimestep();\n    void Initialize();\n\nprotected:\n    VAPoR::WASP *            wasp;\n    const char *             inFile;\n    std::vector<std::string> varNames;\n    std::vector<std::string> meshNames;\n    size_t                   nlevels, maxcratio;\n\n    // DATA MEMBERS\n    bool initialized;\n\n    virtual void PopulateDatabaseMetaData(avtDatabaseMetaData *, int);\n};\n\n#endif\n"
  },
  {
    "path": "scripts/CMakeLists.txt",
    "content": "if (BUILD_VDC)\n\tinstall (\n\t\tFILES vdccp\n\t\tDESTINATION ${INSTALL_BIN_DIR}\n\t\tCOMPONENT Utilites\n\t)\nendif ()\n"
  },
  {
    "path": "scripts/build3rdParty.sh",
    "content": "#!/bin/bash\n\n# To install:           Uncomment 'prerequisites' and the library name you'd like, \n#                       listed at the bottom of this file.  Then run build.sh.\n#\n# To uninstall:         Re-install your target library, then run the following\n#                       command from the build directory.\n#\n#                       xargs rm < install_manifest.txt\n\nset -xe\n\nwhile getopts \"o:b:\" flag; do\n    case \"${flag}\" in\n        o) OS=${OPTARG};;\n        b) baseDir=${OPTARG};;\n    esac\ndone\n\nif [ -z \"$OS\" ]; then\n    echo \"Error: -o flag is required to specify the target operating system [macOSx86, appleSilicon, Ubuntu]\"\n    exit 1\nelif [ -z \"$baseDir\" ]; then\n    echo \"No -b (base directory) option given.  Defaulting to /usr/local/VAPOR-Deps\"\n    baseDir='/usr/local/VAPOR-Deps'\nfi\n#baseDir='/glade/campaign/cisl/vast/vapor/third-party'\n\nsrcDir=\"$baseDir/2024-Sept-src\"\narchiveName=\"2025-July-${OS}\"\ninstallDir=\"$baseDir/current\"\n\necho OS ${OS}\necho baseDir $baseDir\necho srcDir $srcDir\necho installDir $installDir\n\nmacOSMinVersion=\"\"\nshopt -s expand_aliases\nalias make='make -j8'\nalias configure='./configure'\nalias config='./config'\nif [[ \"$OS\" == \"macOSx86\" ]]; then\n    alias configure='./configure --host=x86_64-apple-darwin'\n    alias config='./config darwin64-x86_64-cc'\n    alias brew='arch -x86_64 /usr/local/bin/brew'\n    export PATH=\"/usr/local/bin:$PATH\"\n    macOSMinVersion=\"10.15.0\"\n    echo \"Homebrew alias:\"\n    alias brew\n    echo \"PATH ${PATH}\"\nelif [[ \"$OS\" == \"appleSilicon\" ]]; then\n    macOSMinVersion=\"12.0.0\"\n    alias brew='/opt/homebrew/bin/brew'\n    export PATH=\"/opt/homebrew/bin:$PATH\"\n    echo \"Homebrew alias:\"\n    alias brew\n    echo \"PATH ${PATH}\"\nfi\n\nmacOSx86Prerequisites() {\n    brew uninstall python@3.9 || true\n    export CMAKE_OSX_ARCHITECTURES=x86_64\n    export CFLAGS=\"-arch x86_64\"\n    export LDFLAGS=\"-arch x86_64\"\n    macOSPrerequisites\n}\n\nmacOSPrerequisites() {\n    export MACOSX_DEPLOYMENT_TARGET=$macOSMinVersion\n    export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)\n\n    export CC=\"/opt/local/bin/clang\"\n    export CXX=\"/opt/local/bin/clang++\"\n    export CFLAGS=\"$CFLAGS -isysroot $(xcrun --sdk macosx --show-sdk-path)\"\n    export LDFLAGS=\"$LDFLAGS -isysroot $(xcrun --sdk macosx --show-sdk-path)\"\n    export CXXFLAGS=\"$CFLAGS\"\n    export CPPFLAGS=\"$CFLAGS\"\n\n    brew doctor\n    brew cleanup\n    brew install cmake autoconf atool libtool automake\n    brew install libxml2 xz\n    brew install pkg-config gdbm tcl-tk \n    brew install gettext\n    brew uninstall --ignore-dependencies gettext\n\n    #port install clang-17 +universal\n    #sudo port select --set clang mp-clang-17\n    #xcode-select --install\n}\n\nubuntuPrerequisites() {\n    CC='gcc'\n    CXX='g++'\n    apt update -y\n    apt upgrade -y\n\n    # all for cmake\n    apt-get update\n    apt-get install -y gpg wget\n    wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb\n    dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb\n    wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null\n    echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null\n    DEBIAN_FRONTEND=noninteractive apt install -y software-properties-common\n    apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ focal main'\n    apt install -y cmake --allow-unauthenticated\n\n    apt install -y \\\n        build-essential \\\n        libgl1-mesa-dev \\\n        qtbase5-dev \\\n        libicu-dev \\\n        m4 \\\n        libcurl4-openssl-dev \\\n        libxau-dev \\\n        autoconf \\\n        libtool \\\n        libxcb-xinerama0 \\\n        libxcb-xinerama0-dev \\\n        pkg-config \\\n        unzip \\\n        libssl-dev \\\n        libffi-dev\n    \n    # Qt\n    apt-get install -y \\\n        '^libxcb.*-dev' \\\n        libx11-xcb-dev \\\n        freeglut3-dev \\\n        libglu1-mesa-dev \\\n        libxrender-dev \\\n        libxi-dev \\\n        libxkbcommon-dev \\\n        libxkbcommon-x11-dev\n}\n\nwindowsPrerequisites() {\n    CC='i686-w64-mingw-gcc'\n    CXX='i686-w64-mingw-g++'\n    apt update -y\n    apt upgrade -y\n\n    # all for cmake\n    apt-get update\n    apt-get install -y gpg wget\n    wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null\n    echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null\n    DEBIAN_FRONTEND=noninteractive apt install -y software-properties-common\n    apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main'\n    apt install -y cmake --allow-unauthenticated\n\n    apt install mingw-64\n\n    #choco install visualstudio2019-workload-vctools python cmake -y\n    #setx /M PATH \"%PATH%;C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\MSBuild\\Current\\Bin\"\n    #python -m pip install gdown\n}\n\nlibpng() {\n    cd $srcDir\n    local library='libpng-1.6.39'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.xz \n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n\n    args=(\n        -DCMAKE_INSTALL_PREFIX=$installDir\n        -DCMAKE_BUILD_TYPE=Release\n        -DCMAKE_INSTALL_LIBDIR=lib\n    )\n    if [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" = \"appleSilicon\" ]; then\n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n    fi\n    if [ \"$OS\" == \"macOSx86\" ]; then \n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n\n    cmake \"${args[@]}\" ..\n    make && make install\n}\n\nassimp() {\n    cd $srcDir\n    local library='assimp-5.2.5' #requires c++17 compiler\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz\n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n\n    args=(\n        -DCMAKE_INSTALL_PREFIX=$installDir\n        -DCMAKE_BUILD_TYPE=Release\n        -DCMAKE_INSTALL_LIBDIR=lib\n        -DCMAKE_CXX_FLAGS=\"-O3 -Wno-error=deprecated-declarations\"\n        -DASSIMP_BUILD_TESTS=OFF\n    )\n    if [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" = \"appleSilicon\" ]; then\n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n    fi\n    if [ \"$OS\" == \"macOSx86\" ]; then \n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n\n    cmake \"${args[@]}\" ..\n    make && make install\n}\n\nzlib() {\n    cd $srcDir\n    local library='zlib-1.2.13'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz\n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n\n    args=(\n        -DCMAKE_INSTALL_PREFIX=$installDir\n        -DCMAKE_BUILD_TYPE=Release \n    )\n    if [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" = \"appleSilicon\" ]; then\n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n    fi\n    if [ \"$OS\" == \"macOSx86\" ]; then \n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n\n\n    cmake \"${args[@]}\" ..\n    make && make install\n}\n\n#Note: After configuration, we need to make sure both zlib and szlib are enabled.\nszip() {\n    cd $srcDir\n    local library='szip-2.1.1'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz\n    cd $srcDir/$library\n    args=(\n        --prefix=$installDir\n    )\n    ./configure \"${args[@]}\"\n\n    make && make install\n}\n\n#hdfVersion='1.14.0'\n#hdfVersion='1.13.3'\nhdfVersion='1.12.2'\nhdf5() {\n    cd $srcDir\n    if [ \"$OS\" == \"macOSx86\" ]; then\n        tar xvf hdf5/hdf5-$hdfVersion-Std-macos11_64-clang.tar.gz && cd hdf\n        ./HDF5-$hdfVersion-Darwin.sh --prefix=$installDir --exclude-subdir --skip-license\n    elif [ \"$OS\" == \"appleSilicon\" ]; then\n        tar xvf hdf5/hdf5-$hdfVersion-Std-macos11m1_64-clang.tar.gz && cd hdf\n        ./HDF5-$hdfVersion-Darwin.sh --prefix=$installDir --exclude-subdir --skip-license\n    else\n        tar xvf hdf5/hdf5-$hdfVersion-Std-centos7_64-7.2.0.tar.gz && cd hdf\n        ./HDF5-$hdfVersion-Linux.sh --prefix=$installDir --exclude-subdir --skip-license\n    fi\n\n    ln -fs $installDir/HDF_Group/HDF5/$hdfVersion/lib/plugin/ $installDir/share/plugins\n}\n\nhdf5src() {\n    cd $srcDir\n    local library=\"hdf5-${hdfVersion}\"\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz\n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n    export CMAKE_INCLUDE_PATH=/path/to/libsz/include\n    export CMAKE_LIBRARY_PATH=/path/to/libsz/lib\n\n    args=(\n    -DCMAKE_INSTALL_PREFIX=$installDir\n    -DCMAKE_BUILD_TYPE=Release\n    -DCMAKE_INSTALL_RPATH=$installDir\n    -DCMAKE_PREFIX_PATH=$installDir\n    -DZLIB_DIR=$installDir\n    -DUSE_SHARED_LIBS:BOOL=ON\n    -DBUILD_SHARED_LIBS:BOOL=ON\n    -DHDF5_ENABLE_RPATH:BOOL=ON\n    -DHDF5_BUILD_WITH_INSTALL_NAME:BOOL=ON\n    -DHDF5_ENABLE_THREADSAFE:BOOL=ON\n    -DHDF5_ENABLE_SZIP_SUPPORT:BOOL=ON\n    -DHDF5_ENABLE_Z_LIB_SUPPORT:BOOL=ON\n    -DHDF5_BUILD_HL_LIB:BOOL=ON\n    -DHDF5_BUILD_TOOLS:BOOL=ON\n    -DALLOW_UNSUPPORTED:BOOL=ON\n    )\n    if [ \"$OS\" == \"macOSx86\" ]; then \n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n    cmake \"${args[@]}\" ..\n    make\n    make install\n}\n\nzstd() {\n    cd $srcDir\n    local library='zstd-1.5.6'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar\n    mkdir -p $srcDir/$library/build/cmake/build && cd $srcDir/$library/build/cmake/build\n\n    args=(\n        -DCMAKE_INSTALL_PREFIX=$installDir\n    )\n\n    if [ \"$OS\" == \"macOSx86\" ]; then \n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n    if [ \"$OS\" == \"appleSilicon\" ]; then \n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n        args+=(-DCMAKE_OSX_ARCHITECTURES=arm64)\n    fi\n\n    cmake \"${args[@]}\" ..\n    make && make install\n}\n\nnetcdf() {\n    cd $srcDir\n    local library='netcdf-c-4.9.1'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz\n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n\n    args=(\n        -DCMAKE_INSTALL_PREFIX=$installDir\n        -DCMAKE_PREFIX_PATH=$installDir/HDF_Group/HDF5/$hdfVersion\n        -DHDF5_DIR=$installDir/HDF_Group/HDF5/$hdfVersion\n        -DHDF5_ROOT=$installDir/HDF_Group/HDF5/$hdfVersion\n        -DCMAKE_INSTALL_LIBDIR=lib\n        -DENABLE_BYTERANGE=False\n        -DENABLE_DAP=False\n        -DCMAKE_BUILD_TYPE=Release\n    )\n    if [ \"$OS\" == \"macOSx86\" ]; then \n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n    if [ \"$OS\" == \"appleSilicon\" ]; then \n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n        args+=(-DCMAKE_OSX_ARCHITECTURES=arm64)\n    fi\n\n    export HDF5_ROOT=$installDir/HDF_Group/HDF5/$hdfVersion\n    export LD_LIBRARY_PATH=$HDF5_ROOT/lib\n    export CPPFLAGS=-I$HDF5_ROOT/include\n    export LDFLAGS=-L$HDF5_ROOT/lib\n    cmake \"${args[@]}\" ..\n    make && make install\n}\n\nexpat() {\n    cd $srcDir\n    local library='expat-2.5.0'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.xz \n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n\n    args=(\n        -DCMAKE_INSTALL_PREFIX=$installDir\n        -DCMAKE_BUILD_TYPE=Release\n        -DCMAKE_INSTALL_LIBDIR=lib\n    )\n    if [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" = \"appleSilicon\" ]; then\n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n    fi\n    if [ \"$OS\" == \"macOSx86\" ]; then \n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n\n\n    cmake \"${args[@]}\" ..\n    make && make install\n}\n\nudunits() {\n    cd $srcDir\n    local library='udunits-2.2.28'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library\n\n    args=(\n        --prefix=$installDir\n    )\n    LDFLAGS=-L$installDir/lib/ \\\n    CPPFLAGS=-I$installDir/include/ \\\n    CC=$CC CXX=$CXX \\\n    ./configure \"${args[@]}\"\n    make && make install\n}\n\nfreetype() {\n    cd $srcDir\n    local library='freetype-2.13.0'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.xz\n    cd $srcDir/$library\n\n    args=(\n        --prefix=$installDir\n        --with-brotli=no\n        --with-bzip2=no\n    )\n\n    configure \"${args[@]}\"\n    make && make install\n}\n\n#CC=clang CXX=clang++ ./configure --prefix=/usr/local/VAPOR-Deps/2019-Aug\njpeg() {\n    cd $srcDir\n    rm -rf $srcDir/jpeg-9e || true\n    tar xvf $srcDir/jpegsrc.v9e.tar.gz\n    cd $srcDir/jpeg-9e\n\n    echo target $MACOSX_DEPLOYMENT_TARGET\n\n    args=(\n        --prefix=$installDir\n    )\n    if [ \"$OS\" == \"macOSx86\" ]; then\n        args+=(--host=x86_64-apple-darwin)\n    fi\n    CC=$CC CXX=$CXX \\\n    ./configure \"${args[@]}\"\n    make && make install\n}\n\ntiff() {\n    cd $srcDir\n    local library='libtiff-v4.5.0'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz\n    cd $srcDir/$library\n    if [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" == \"appleSilicon\" ]; then\n        glibtoolize --force\n    else\n        libtoolize --force\n    fi\n    aclocal\n    autoheader\n    automake --force-missing --add-missing\n    autoconf\n    args=(\n        --prefix=$installDir\n        --disable-dap\n    )\n    LDFLAGS=-L$installDir/lib \\\n    CPPFLAGS=-I$installDir/include \\\n    CC=$CC CXX=$CXX \\\n    ./configure \"${args[@]}\"\n    make && make install\n}\n\nsqlite() {\n    cd $srcDir\n    local library='sqlite-autoconf-3410000'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz\n    cd $srcDir/$library\n    \n    args=(\n        --prefix=$installDir\n    )\n    CC=$CC CXX=$CXX \\\n    ./configure \"${args[@]}\"\n    make && make install\n}\n\ncurl() {\n    cd $srcDir\n    local library='curl-8.2.1' # works\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.xz\n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n    \n    args=(\n        -DCMAKE_PREFIX_PATH=$installDir\n        -DCMAKE_INSTALL_LIBDIR=lib\n        -DCMAKE_INSTALL_PREFIX=$installDir\n        -DCMAKE_LIBRARY_PATH=$installDir/lib\n        -DCMAKE_INCLUDE_PATH=$installDir/include\n        -DCMAKE_INSTALL_RPATH=$installDir/lib\n    )\n\n    if [ \"$OS\" == \"macOSx86\" ]; then\n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n\n\n    cmake \"${args[@]}\" ..\n\n    make && make install\n}\n\nssh() {\n    cd $srcDir\n    local library='libssh-0.11.0'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.xz\n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n    \n    args=(\n        -DCMAKE_PREFIX_PATH=$installDir\n        -DCMAKE_INSTALL_LIBDIR=lib\n        -DCMAKE_INSTALL_PREFIX=$installDir\n        -DCMAKE_LIBRARY_PATH=$installDir/lib\n        -DCMAKE_INCLUDE_PATH=$installDir/include\n    )\n\n    if [ \"$OS\" == \"macOSx86\" ]; then\n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n\n    cmake \"${args[@]}\" ..\n\n    make && make install\n}\n\nproj() {\n    cd $srcDir\n    #local library='proj-9.1.0' # does not work\n    #local library='proj-6.3.1' # works\n    local library='proj-7.2.1' # works\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz\n    tar xvf proj-datumgrid-1.8.tar.gz -C $library/data\n    mkdir -p $srcDir/$library/build && cd $srcDir/$library/build\n    \n    if [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" == \"appleSilicon\" ]; then\n        local sqliteLib=\"-DSQLITE3_LIBRARY=$installDir/lib/libsqlite3.dylib\"\n    else\n        local sqliteLib=\"-DSQLITE3_LIBRARY=$installDir/lib/libsqlite3.so\"\n    fi\n    if [ \"$OS\" == \"macOSx86\" ]; then \n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n    fi\n\n\n    args=(\n        -DCMAKE_PREFIX_PATH=$installDir\n        -DEXE_SQLITE3=$installDir/bin/sqlite3\n        -DSQLITE3_INCLUDE_DIR=$installDir/include\n        $sqliteLib \\\n        -DCMAKE_INSTALL_LIBDIR=lib\n        -DCMAKE_INSTALL_PREFIX=$installDir\n        -DPROJ_COMPILER_NAME=$CXX\n        -DCMAKE_LIBRARY_PATH=$installDir/lib\n        -DCMAKE_INCLUDE_PATH=$installDir/include\n    )\n    if [ \"$OS\" == \"appleSilicon\" ]; then\n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n    elif [ \"$OS\" == \"macOSx86\" ]; then\n        args+=(-DCMAKE_OSX_ARCHITECTURES=x86_64)\n        args+=(-DCMAKE_OSX_DEPLOYMENT_TARGET=$macOSMinVersion)\n    fi\n    cmake \"${args[@]}\" ..\n\n    make && make install\n}\n\ngeotiff() {\n    cd $srcDir\n    local library='libgeotiff-1.7.1'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library\n\n    echo $CC\n    echo $CXX\n    echo $CFLAGS\n    echo $LDFLAGS\n    echo $SDKROOT\n\n    args=(\n        --prefix=$installDir\n        --with-zlib=yes\n        --with-jpeg=yes\n        --with-proj=$installDir\n        --with-libtiff=$installDir\n    )\n\n    configure \"${args[@]}\"\n\n    make && make install\n}\n\nxinerama() {\n    cd $srcDir\n    local library='xcb-proto-1.15.2'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library\n    ./configure --prefix=$installDir\n    make && make install\n\n    cd $srcDir\n    library='libxcb-1.15'\n    export PYTHONPATH=$installDir/local/lib/python3.10/dist-packages\n    tar xvf $srcDir/$library.tar.xz && cd $srcDir/$library\n    PYTHON=python3 PKG_CONFIG_PATH=$installDir/share/pkgconfig ./configure --without-doxygen --docdir='${datadir}'/doc/libxcb-1.15 --prefix=$installDir\n    make && make install\n}\n\nopenssl() {\n    cd $srcDir\n    local library='openssl-1.1.1w'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library\n\n    echo $CFLAGS\n    echo $CXXFLAGS\n    echo $LDFLAGS\n    echo $CPPFLAGS\n\n    args=(\n        --prefix=$installDir\n        --openssldir=$installDir\n    )\n    if [ \"$OS\" = \"macOSx86\" ]; then\n        args+=(darwin64-x86_64-cc)\n    elif [ \"$OS\" = \"appleSilicon\" ]; then\n        args+=(darwin64-arm64-cc)\n    fi\n    ./Configure shared \"${args[@]}\"\n    make && make install\n}\n\npythonVapor() {\n    cd $srcDir\n    local library='cpython-3.9.16'\n    rm -rf $library || true\n    tar xvf $srcDir/$library.tar.gz && cd $srcDir/$library\n\n    args=(\n        --prefix=$installDir\n        --enable-shared\n        --with-ensurepip=install\n        --with-suffix=.vapor\n        --enable-optimizations\n    )\n\n    if [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" == \"appleSilicon\" ]; then\n        export PKG_CONFIG_PATH=\"$(brew --prefix tcl-tk)/lib/pkgconfig\"\n        args+=(--prefix=/usr/local/VAPOR-Deps/current/Resources)\n        args+=(--with-openssl=$installDir)\n        args+=(--with-tcltk-libs=\"$(pkg-config --libs tcl tk)\")\n        args+=(--with-tcltk-includes=\"$(pkg-config --cflags tcl tk)\")\n        export LDFLAGS=\"$LDFLAGS -L$installDir/lib\"\n        export CPPFLAGS=\"$CPPFLAGS -I$installDir/include\"\n        export LLVM_PROFDATA=\"/opt/local/bin/llvm-profdata-mp-17\"\n        export LD_LIBRARY_PATH=\"$installDir/Resources\"\n\n    \tif [ \"$OS\" == \"macOSx86\" ]; then\n\t    export CFLAGS=\"$CFLAGS -I/usr/local/include\"\n\t    export LDFLAGS=\"$LDFLAGS -L/usr/local/lib\"\n            args+=(--build=x86_64-apple-darwin)\n        configure \"${args[@]}\"\n\tfi\n    else\n        args+=(--with-openssl=$installDir)\n        args+=(--with-system-ffi)\n        CC=$CC \\\n        CXX=$CXX \\\n        CPPFLAGS=-I$installDir/include \\\n        LDFLAGS=\"-L$installDir/lib -Wl,-rpath=$installDir/lib\" \\\n        ./configure \"${args[@]}\"\n    fi\n\n    make && make install\n\n    $installDir/bin/python3.9.vapor -m pip install --upgrade pip\n\n    $installDir/bin/python3.9.vapor -m pip install numpy scipy matplotlib\n}\n\nospray() {\n    cd $srcDir\n    if [ \"$OS\" == \"appleSilicon\" ]; then\n        cd $srcDir/ospray/osprayM1\n    elif [ \"$OS\" == \"macOSx86\" ]; then\n        local library='ospray-2.11.0.x86_64.macosx'\n        rm -rf ospray/$library || true\n        unzip -o $srcDir/ospray/$library && cd $srcDir/$library\n    else\n        local library='ospray-2.11.0.x86_64.linux'\n        rm -rf ospray/$library || true\n        tar xvf $srcDir/ospray/$library.tar.gz && cd $srcDir/$library\n    fi\n    mkdir -p $installDir/Ospray\n    cp -rfP * $installDir/Ospray\n}\n\nglm() {\n    cd $srcDir\n    local library='glm-0.9.9.8'\n    rm -rf glm || true\n    unzip $srcDir/$library.zip \n    cp -r $srcDir/glm/glm $installDir/include\n}\n\ngte() {\n    cd $srcDir\n    tar xvf GTE.tar.xz\n    rsync -a GTE $installDir/include\n}\n\nimages() {\n    cd $srcDir\n    tar xvf images.tar.xz\n    rsync -a images $installDir/share\n}\n\nqt() {\n    cd $srcDir\n    rm -rf qt-everywhere-src-5.15.8 || true\n    tar xf $srcDir/qt-everywhere-opensource-src-5.15.8.tar.xz\n    mkdir -p $srcDir/qt-everywhere-src-5.15.8/build\n    cd $srcDir/qt-everywhere-src-5.15.8/build\n \n    if [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" == \"appleSilicon\" ]; then\n        brew install gettext\n        brew link gettext --force\n    fi\n\n    args=(\n        -v\n        -prefix $installDir\n        -opensource\n        -confirm-license\n        -release\n        -nomake examples\n        -nomake tests\n    )\n    if [ \"$OS\" == \"Ubuntu\" ]; then\n        args+=(-feature-freetype)\n        args+=(-qt-freetype)\n        args+=(-opengl desktop)\n        # opensuse new args\n        args+=(-xcb)\n        args+=(-xcb-xlib)\n        args+=(-bundled-xcb-xinput)\n    fi\n\n    CPPFLAGS=\"$CPPFLAGS -I$installDir/include\" \\\n    LDFLAGS=\"$LDFLAGS -L$installDir/lib -Wl,-rpath=$installDir/lib\" \\\n    ../configure \\\n    \"${args[@]}\" > qtConfig.txt\n\n    make > qtMake.txt\n    make install > qtInstall.txt\n}\n\nadd_rpath() {\n    for lib in $installDir/lib/*.dylib $installDir/Resources/lib/*.dylib; do\n        fileName=\"$(basename $lib)\"\n        echo install_name_tool -id @rpath/$fileName $lib\n        install_name_tool -id @rpath/$fileName $lib\n\n        # Get the list of dependencies\n        dependencies=$(otool -L \"$lib\" | awk '{print $1}' | grep -v \":\")\n\n        # Iterate over each dependency and replace the path with rpath\n        for dep in $dependencies; do\n            depName=$(basename \"$dep\")\n            newPath=\"@rpath/$depName\"\n            if [ \"$(dirname \"$dep\")\" == \"$installDir/lib\" ]; then\n                echo install_name_tool -change \"$dep\" \"$newPath\" \"$installDir/lib/$lib\"\n                install_name_tool -change \"$dep\" \"$newPath\" \"$lib\"\n            fi\n            if [ \"$(dirname \"$dep\")\" == \"$installDir/Resources/lib\" ]; then\n                echo install_name_tool -change \"$dep\" \"$newPath\" \"$installDir/Resources/$lib\"\n                install_name_tool -change \"$dep\" \"$newPath\" \"$installDir/Resources/$lib\"\n            fi\n        done\n        codesign --force -s - $lib\n    done\n}\n\nrenameAndCompress() {\n    pwd\n    cd $baseDir\n    mv $installDir $archiveName\n    tar cfJ $archiveName.tar.xz $archiveName\n}\n\nif [ \"$OS\" == \"macOSx86\" ]; then\n    macOSx86Prerequisites\nelif [ \"$OS\" == \"appleSilicon\" ]; then\n    macOSPrerequisites\nelif [ \"$OS\" == \"Ubuntu\" ]; then\n    ubuntuPrerequisites\nelif [ \"$OS\" == \"Windows\" ]; then\n    windowsPrerequisites\nfi\n\nopenssl\nzlib\nlibpng\njpeg\ntiff\nsqlite\nssh\n\n### m1 needs curl for proj?\n#curl\n###\n\nproj\ngeotiff\nassimp\nszip\nhdf5\n\n#zstd\nnetcdf\nexpat\nudunits\nfreetype\nif [ \"$OS\" == \"Ubuntu\" ] ; then\n   xinerama\nfi         \nospray\nglm\ngte\nimages\npythonVapor\nqt\nif [ \"$OS\" == \"macOSx86\" ] || [ \"$OS\" == \"appleSilicon\" ]; then\n    add_rpath\nfi         \nrenameAndCompress\n"
  },
  {
    "path": "scripts/getWMSImage.sh",
    "content": "#!/bin/bash\n#\n\n\n# defaults\nminLon=\"\"\nmaxLon=\"\"\nminLat=\"\"\nmaxLat=\"\"\nxres=1024\nyres=768\nstyles=\"default\"\nversion=\"1.1\"\nimageFile=\"\"\nimageFormat=\"image/tiff\"\ntempFile=\"tmpImage\"\nlayer=\"bmng200406\"\nhost=\"http://data.worldwind.arc.nasa.gov/wms\"\namp=\"&\"\ndecLLRegEx=^[\\-+]?[0-9]+[\\.]?[0-9]*$\ntransparent=\"FALSE\"\ndebugMode=0\nmap=\"\"\ncompression=\"-compress none\"\ndepth=\"\"\n\n\nprintUsage() {\n      echo \"Usage: \" $0 \"{optional parameters} minLon minLat maxLon maxLat\"\n      echo \"Optional parameters:\"\n      echo \"    -r xres yres\"\n      echo \"          resolution of requested image; default is \" ${xres}\"x\"${yres}\n      echo \"    -o imageFilename\"\n      echo \"          name for the requested image file; default is named after requested image layer\"\n      echo \"    -m map_name\"\n      echo \"          Requests a predefined map from a well-known server (overrides any expert options).\"\n      echo \"          Available map names:\"\n      echo \"              \\\"BMNG\\\"         (NASA BlueMarble, the default)\"\n      echo \"              \\\"landsat\\\"      (Landsat imagery)\"\n      echo \"              \\\"USstates\\\"     (US state boundaries)\"\n      echo \"              \\\"UScounties\\\"   (US state and county boundaries)\"\n      echo \"              \\\"world\\\"        (world political boundaries)\"\n      echo \"              \\\"rivers\\\"       (major rivers)\"\n      echo \"    -t\"\n      echo \"          request a transparent background\"\n      echo \"\"\n      echo \"Expert-only parameters (see documentation):\"\n      echo \"    -s URL\"\n      echo \"          URL for WMS server\"\n      echo \"    -l layerName\"\n      echo \"          arbitrary image-layer name to fetch\"\n      echo \"    -f format\"\n      echo \"          image format; default is \\\"image/tiff\\\"\"\n      echo \"    -z\"\n      echo \"          compress the resultant geotiff file\"\n      echo \"          (may not work on all platforms)\"\n      echo \"    -d\"\n      echo \"          debug mode; do not delete temporary files\"\n}\n\n\nrealValGT() {\n    a=`bc <<EOF\n      $1 > $2\nEOF\n`\n    echo $a\n}\n\nrealRange() {\n    a=`bc <<EOF\n       $2 - $1\nEOF\n`\n    echo $a\n}\n\nrealSub() {\n    a=`bc <<EOF\n       $1 - $2\nEOF\n`\n    echo $a\n}\n\n##########################\n\nif [ $# -lt 4 ]\nthen\n    printUsage\n    exit 1\nfi\n\n# Make sure we have the utilities we'll need...\nfetchProg=\"\"\nnosave=`which curl 2>/dev/null`\nif  [ $? -eq 0 ]; then\n    fetchProg=\"curl -w HTTP_RESPONSE:%{http_code}\\n -L -o\"\nfi\n\nnosave=`which wget 2>/dev/null`\nif  [ $? -eq 0 ]; then\n    fetchProg=\"wget -O\"\nfi\n\nif [ \"$fetchProg\" = \"\" ]; then\n    echo \"Could not find \\\"wget\\\" or \\\"curl\\\"; needed to retrieve requested images.\"\n    exit 1\nfi\n\nnosave=`which tiff2geotiff 2>/dev/null`\nif ! [ $? -eq 0 ]; then\n    echo \"Could not find \\\"tiff2geotiff\\\"; needed to convert requested image into geotiff.\"\n    exit 1\nfi\n\n\n# parse command-line options...\n#\nwhile [ $# -gt 4 ]\ndo\n  case $1 in\n\n  -r) if ! ( [[ $2 =~ ^[0-9]+$ ]] && [[ $3 =~ ^[0-9]+$ ]]) ; then\n          echo \"bad resolution values given: \" $2 \" x \" $3\n          exit 1\n      fi\n      xres=$2\n      yres=$3\n      shift; shift\n      ;;\n\n  -s) host=$2\n      shift\n      ;;\n\n  -o) imageFile=$2\n      shift\n      ;;\n\n  -l) layer=$2\n      shift\n      ;;\n\n  -m) map=$2\n      shift\n      ;;\n\n  -f) imageFormat=$2\n      shift\n      ;;\n\n  -d) debugMode=1\n      ;;\n\n  -t) transparent=\"TRUE\"\n      ;;\n\n  -z) compression=\"-compress lzw\"\n      ;;\n\n  -8) depth=\"-depth 8\"\n      ;;\n\n  *)\n      printUsage\n      exit 0\n  esac\n  shift\ndone\n\n# remaining parameters form a possible bounding box?\n#\nfor i in $1 $2 $3 $4\ndo\n    if ! [[ $i =~ ${decLLRegEx} ]] ; then\n        echo $i \" is not a valid decimal lon/lat string\"\n        exit 1\n    fi\ndone\nminLon=$1\nminLat=$2\nmaxLon=$3\nmaxLat=$4\n\n# further test bounds for sanity...\n#\nif [ `realValGT ${minLon} ${maxLon}` -eq 1 ]\nthen\n    echo \"Invalid bounding box: minLon > maxLon\"\n    exit 1\nfi\nif [ `realValGT ${minLon} 180` -eq 1 ] || [ `realValGT ${maxLon} 180` -eq 1 ]\nthen\n  minLon=`realSub ${minLon} 180`\n  maxLon=`realSub ${maxLon} 180`\n  echo \"min/max lon remapped to: \" ${minLon} ${maxLon}\nfi \nif [ `realValGT -180 ${minLon}` -eq 1 ] || [ `realValGT ${maxLon} 180` -eq 1 ] \nthen\n    echo \"Invalid bounding box:\"\n    echo \"  longitudes must range from -180 to 180, or 0 to 360\"\n    exit 1\nfi\n\nif [ `realValGT -90 ${minLat}` -eq 1 ] || [ `realValGT ${maxLat} 90` -eq 1 ] || \\\n   [ `realValGT ${minLat} ${maxLat}` -eq 1 ]\nthen\n    echo \"Invalid bounding box:\"\n    echo \"  latitudes must range from -90 to 90, with minLat < maxLat\"\n    exit 1\nfi\n\nwmsLayer=${layer}\n\n# Did the user specify a predefined map?\n#\nif [ \"${map}\" = \"BMNG\" ] ; then\n    wmsLayer=\"bmng200406\"\n    host=\"http://www.nasa.network.com/wms\"\n    imageFormat=\"image/tiff\"\n\nelif [ \"${map}\" = \"landsat\" ] ; then\n    wmsLayer=\"esat\"\n    host=\"http://www.nasa.network.com/wms\"\n    imageFormat=\"image/tiff\"\n\nelif [ \"${map}\" = \"USstates\" ] ; then\n    # these range vs. scale factors are empirically determined!\n# This server has been deemed unreliable; substituting the worldwind server below...\n#    lonRange=`realRange ${minLon} ${maxLon}`\n#    if [ `realValGT ${lonRange} 59` -eq 1 ] ; then        \n#        wmsLayer=\"ATLAS_STATES_150\"\n#    elif [ `realValGT ${lonRange} 25` -eq 1 ] ; then\n#        wmsLayer=\"ATLAS_STATES_075\"\n#    else\n#        wmsLayer=\"ATLAS_STATES\"\n#    fi\n#    host=\"http://imsref.cr.usgs.gov:80/wmsconnector/com.esri.wms.Esrimap/USGS_EDC_National_Atlas\"\n#    imageFormat=\"image/png\"\n#    depth=\"-depth 8\"\n    wmsLayer=\"topp:states\"\n    host=\"http://worldwind22.arc.nasa.gov/geoserver/wms\"\n    styles=\"countryboundaries\"\n    transparent=\"TRUE\"\n\nelif [ \"${map}\" = \"UScounties\" ] ; then\n    # these range vs. scale factors are empirically determined!\n    lonRange=`realRange ${minLon} ${maxLon}`\n    if [ `realValGT ${lonRange} 59` -eq 1 ] ; then        \n        wmsLayer=\"ATLAS_STATES_150\"\n    elif [ `realValGT ${lonRange} 25` -eq 1 ] ; then\n        wmsLayer=\"ATLAS_STATES_075\"\n    else\n        wmsLayer=\"ATLAS_STATES\"\n    fi\n    wmsLayer=\"ATLAS_COUNTIES_2000,\"${wmsLayer}\n    host=\"http://imsref.cr.usgs.gov:80/wmsconnector/com.esri.wms.Esrimap/USGS_EDC_National_Atlas\"\n    imageFormat=\"image/png\"\n    depth=\"-depth 8\"\n\nelif [ \"${map}\" = \"world\" ] ; then \n# This server has been ddeemed unreliable; substituting the worldwind server instead --RLB\n#    wmsLayer=\"1:1\"\n#    host=\"http://columbo.nrlssc.navy.mil/ogcwms/servlet/WMSServlet/Earth_Satellite_Corp_Maps.wms\"\n#    imageFormat=\"image/png\"\n#    version=\"1.1.0\"\n#    styles=\"\"\n    wmsLayer=\"topp:cia\"\n    host=\"http://worldwind22.arc.nasa.gov/geoserver/wms\"\n    styles=\"countryboundaries\"\n    transparent=\"TRUE\"\n    \nelif [ \"${map}\" = \"rivers\" ] ; then\n    wmsLayer=\"RIVERS\"\n    host=\"http://viz.globe.gov/viz-bin/wmt.cgi\"\n    imageFormat=\"image/png\"\n\nelif [ \"${map}\" != \"\" ] ; then\n    echo \"unknown map name: \" ${map}\n    exit 1\nfi\n\n# If image-format is not tiff, we'll need the convert utility from \n# Imagemagick...\nif [ \"${imageFormat}\" != \"image/tiff\" ] ; then\n    nosave=`which convert 2>/dev/null`\n    if ! [ $? -eq 0 ]; then\n        echo \"Could not find Imagemagick's \\\"convert\\\" utility, which is required when requesting non-tiff images.\"\n        echo \"See http://www.imagemagick.org\"\n        exit 1\n    fi\nfi\n\n# If no image filename specified, name it after the layer...\n#\nif [ \"${imageFile}\" = \"\" ] ; then\n    if [ \"${map}\" != \"\" ] ; then\n        imageFile=${map}.tiff\n    else\n        imageFile=${layer}.tiff\n    fi\nfi          \n\necho \"Extent:           \" $minLon\",\"$minLat \" (LL)  \" $maxLon\",\"$maxLat \"(UR)\"\necho \"Image resolution: \" $xres \"X\" $yres\necho \"Image filename:   \" $imageFile\necho \"Image layer:      \" $wmsLayer\necho \"WMS URL:          \" $host\n\n# compose the URL\n#\nurl1=${host}\"?\"\"request=GetMap\"${amp}\"service=wms\"${amp}\"version=\"${version}${amp}\"layers=\"${wmsLayer}\nurl2=\"styles=\"${styles}${amp}\"bbox=\"${minLon}\",\"${minLat}\",\"${maxLon}\",\"${maxLat}\nurl3=\"format=\"${imageFormat}${amp}\"height=\"${yres}${amp}\"width=\"${xres}${amp}\"srs=epsg:4326\"${amp}\"transparent=\"${transparent}\nurl=${url1}${amp}${url2}${amp}${url3}\n\ncmd=\"${fetchProg} ${tempFile} ${url}\"\necho ${cmd}\n${cmd}\n\nif  ( grep -s \"ServiceException\" ${tempFile} ); then\n    echo \"Received WMS ServiceException:\"\n    cat ${tempFile}\n    exit 1\nfi\n\n# Need to convert non-tiffs into tiff;  this is where the dependency on\n# Imagemagick comes from\n#\nif [ \"${imageFormat}\" != \"image/tiff\" ] ; then\n    mv ${tempFile} ${tempFile}2\n    cmd=\"convert ${compression} ${depth} ${tempFile}2 tiff:${tempFile}\"\n    echo ${cmd}\n    ${cmd}\n    if [ ${debugMode} -ne 1 ] ; then\n        rm ${tempFile}2\n    fi\nfi\n\n# build this command in pieces -- the lon/lat min/max parameters need to appear\n# as one logical token on the command-line\n#\ncmd1=\"tiff2geotiff -4 +proj=longlat -n\"\ncmd2=\"${minLon} ${minLat} ${maxLon} ${maxLat}\"\ncmd3=\"${tempFile} ${imageFile}\"\necho ${cmd1} ${cmd2} ${cmd3}\n${cmd1} \"${cmd2}\" ${cmd3}\n\nif [ -f ${imageFile} ] ; then\n    echo \"Image filename is: \" ${imageFile}\nelse\n    echo \"Image fetch seems to have failed.\"\nfi\n\nif [ ${debugMode} -ne 1 ] ; then \n    rm -f ${tempFile}\nfi\n"
  },
  {
    "path": "scripts/ptcl2vms.py",
    "content": "#!/usr/bin/python\n#imports\nimport string\nimport sys\nimport os\nimport shutil\nimport copy\nimport math\n#the usage string, printed when the user is abusing our tool, lol\nusage =  \"\"\"usage: ptcl2vms.py [options] <infile1> [[options] <infile2>] ... <outfile>\nvalid options are...\n    -stride (int) adjusts with what stride we read and generate points\n    -radius (float) adjusts the diameter of the generated point meshes\n    -ref (int) adjusts tesselation level of point meshes\n    -startts (int) sets the starting timestep of the output\n\"\"\"\n#TODO: try it with more than one timestep\n#TODO: fix stride problem\n#a bunch of vector manipulation functions! :D\ndef dot(a, b):\n    return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2])\ndef mag2(v):\n    return dot(v, v)\ndef mag(v):\n    return math.sqrt(mag2(v))\ndef div(v, n):\n    return v[0] / n, v[1] / n, v[2] / n\ndef mul(v, n):\n    return v[0] * n, v[1] * n, v[2] * n\ndef add(a, b):\n    return a[0] + b[0], a[1] + b[1], a[2] + b[2]\ndef sub(a, b):\n    return a[0] - b[0], a[1] - b[1], a[2] - b[2]\ndef norm(a):\n    return div(a, mag(a))\ndef resize(a, n):\n    return mul(a, n / mag(a))\ndef centroid(points):\n    c = (0.0, 0.0, 0.0)\n    for p in points:\n        c = add(c, p)\n    c = div(c, len(points))\n    return c\n#A tetrahedron for subdivision by subdivnorm\noverts = [ \\\n    norm((-1, -1,  1)),\n    norm(( 1,  1,  1)),\n    norm((-1,  1, -1)),\n    norm(( 1, -1, -1))]\nofaces = [ \\\n    (0, 1, 2),\n    (3, 2, 1),\n    (0, 3, 1),\n    (3, 0, 2)]\ndef subdivnorm(verts, faces):\n    nfaces = len(faces)\n    for faceIndex in range(0, nfaces) :\n        face = faces[faceIndex] #choose a face to subdivide\n        fverts = [] #get the vertices of the face\n        for i in face:\n            fverts.append(verts[i])\n        #ctr = norm(centroid(fverts)) #get the centroid of the face\n        everts = [] #get and normalize the new edge vertices\n        for i in range(0, len(fverts)):\n            ni = (i + 1) % len(fverts)\n            everts.append(norm(centroid([fverts[i], fverts[ni]])))\n        #add all the new vertices, remembering where we stored them\n        eidx = len(verts)\n        verts.extend(everts)\n        #replace the existing face with the first new face\n        faces[faceIndex] = (eidx, eidx + 1, eidx + 2)\n        #build new faces, appending them to the faces array\n        for i in range(0, len(face)):\n            ni = (i + 1) % len(face)\n            faces.append((eidx + i, face[ni], eidx + ni))\ndef catmullnorm(verts, faces) :\n    nfaces = len(faces)\n    for faceIndex in xrange(nfaces) :\n        face = faces[faceIndex] #choose a face to subdivide\n        fverts = [] #get the vertices of the face\n        for i in face:\n            fverts.append(verts[i])\n        ctr = norm(centroid(fverts)) #get the centroid of the face\n        everts = [] #get and normalize the new edge vertices\n        for i in range(0, len(fverts)):\n            ni = (i + 1) % len(fverts)\n            everts.append(norm(centroid([fverts[i], fverts[ni]])))\n        #add all the new vertices, remembering where we stored them\n        cidx = len(verts)\n        verts.append(ctr)\n        eidx = len(verts)\n        verts.extend(everts)\n        #rebuild the existing face as the first new face\n        faces[faceIndex] = (eidx, face[1], eidx + 1, cidx)\n        #build new quads, appending them to the faces array\n        for i in range(1, len(face)):\n            ni = (i + 1) % len(face)\n            faces.append((eidx + i, face[ni], eidx + ni, cidx))\ndef showMesh(verts, faces):\n    for v in verts:\n        print(\"v \" + str(v[0]) + \" \" + str(v[1]) + \" \" + str(v[2]))\n    for f in faces:\n        if len(f) == 3:\n            print(\"f \"+str(f[0]+1)+\" \"+str(f[1]+1)+\" \"+str(f[2]+1))\n        else:\n            print(\"f \"+str(f[0]+1)+\" \"+str(f[1]+1)+\" \"+str(f[2]+1)+\" \"+str(f[3]+1))\n    print(\"\")\n#remove the scriptname from argv, but store it just in case :P\nscriptname = sys.argv.pop(0)\n\n#check for valid number of arguments\nif len(sys.argv) < 2 :\n    print(\">>>ERROR: not enough arguments!\\n\" + usage)\n    exit(-1)\n#get the name of output file and directory\nvmsname = sys.argv.pop()\nprint(\">>>OUTFILE: \" + vmsname)\ndirname = vmsname[0:vmsname.rfind('.')] + \"_data\"\n#remove any preexisting data by the same name\nif os.path.exists(dirname) :\n    shutil.rmtree(dirname, ignore_errors=False, onerror=None)\nif os.path.exists(vmsname) :\n    os.remove(vmsname)\n#make data directory\nos.mkdir(dirname)\n#process each option or file\nstride = 1\nref = 0\nradius = 1\nstartts = 0\nplylist = []\nwhile len(sys.argv) > 0 :\n    #get the next argument\n    arg = sys.argv.pop(0)\n    #handle options\n    if arg[:1] == \"-\" :\n        if arg == \"-stride\" :\n            stride = int(sys.argv.pop(0))\n            print(\"stride = \" + str(stride))\n        elif arg == \"-radius\" :\n            radius = float(sys.argv.pop(0))\n            print(\"radius = \" + str(radius))\n        elif arg == \"-ref\" :\n            ref = int(sys.argv.pop(0))\n            print(\"refinement = \" + str(ref))\n        elif arg == \"-startts\" :\n            startts = int(sys.argv.pop(0))\n            print(\"startts = \" + str(startts))\n        else:\n            print(\">>>ERROR: unknown option: '\" + arg + \"'\\n\" + usage)\n            exit(-1)\n        continue\n    #open input and output files\n    print(\">>>READING: \" + arg)\n    infile = open(arg)\n    #get input from input file\n    counter = 1\n    points = []\n    for line in infile.readlines() :\n        strc = line.split()\n        if len(strc) < 3:\n            continue\n        coords = []\n        for i in strc:\n            coords.append(float(i))\n        counter += 1\n        if counter >= stride :\n            points.append(coords)\n            counter = 1\n    infile.close()\n    #generate a sphere with specified refinement, starting with our tetrahedron\n    lverts = copy.deepcopy(overts)\n    lfaces = copy.deepcopy(ofaces)\n    for i in range(ref) :\n        subdivnorm(lverts, lfaces)\n    lnorms = copy.deepcopy(lverts)\n    for i in range(0, len(lverts)) :\n        lverts[i] = resize(lverts[i], radius)\n    #copy the sphere to various positions! :D\n    verts = []\n    faces = []\n    norms = []\n    offset = 0\n    #this loop runs once for each copy (each must be at a different position)\n    for pos in range(0, len(points), stride) :\n        #add the current position to each point before appending it to verts\n        for vert in lverts :\n            verts.append(add(vert, points[pos]))\n        for nm in lnorms :\n            norms.append(nm)\n        for face in lfaces :\n            faces.append((face[0] + offset,\n                          face[1] + offset,\n                          face[2] + offset))\n        #the next face will index its verts from the next starting position\n        offset = len(verts)\n    #write the model to a file!\n    plyname = dirname+\"/\"+os.path.basename(arg[0:arg.rfind(\".\")])+\".ply\"\n    print(\">>>WRITING: \" + plyname)\n    ply = open(plyname, \"w\")\n    ply.write('ply\\nformat ascii 1.0\\nelement vertex ' + str(len(verts)) + '\\nproperty float x\\nproperty float y\\nproperty float z\\nproperty float nx\\nproperty float ny\\nproperty float nz\\nelement face ' +  str(len(faces)) + '\\nproperty list uchar int vertex_indices\\nend_header\\n')\n    for vi in range(len(verts)):\n        v = verts[vi]\n        n = norms[vi]\n        ply.write(str(v[0])+\" \"+str(v[1])+\" \"+str(v[2])+\" \"\\\n                 +str(n[0])+\" \"+str(n[1])+\" \"+str(n[2])+\"\\n\")\n    for f in faces:\n        ply.write(\"3 \"+str(f[0])+\" \"+str(f[1])+\" \"+str(f[2])+\"\\n\")\n    ply.close()\n    plylist.append(plyname)\n#write the VMS file, listing all our outputs in it!\nif len(plylist) < 1:\n    print(\"ERROR: No input files specified,\\n       or one input and no outputs!\\n\")\n    exit(1)\nvms = open(vmsname, \"w\")\ncounter = 0\nvms.write('<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\\n<ModelScene>\\n')\nfor i in range(startts) :\n    vms.write('<!-- ts ' + str(counter) + ' -->\\n')\n    vms.write('<TimeStep>\\n')\n    vms.write('</TimeStep>\\n')\n    counter += 1\nfor ply in plylist :\n    vms.write('<!-- ts ' + str(counter) + ' -->\\n')\n    vms.write('<TimeStep>\\n')\n    vms.write('<File>' + ply + '</File>\\n')\n    vms.write('</TimeStep>\\n')\n    counter += 1\nvms.write('</ModelScene>\\n')\nvms.close()\n\n"
  },
  {
    "path": "scripts/vapor-setup-win32.csh",
    "content": "#!/bin/csh -f\r\n\r\nif !($?VAPOR3_HOME) then\r\n\techo \"VAPOR3_HOME enviroment variable not set\"\r\n\texit 1\r\nendif\r\n\r\nif !($?PATH) then\r\n    setenv PATH \"${VAPOR3_HOME}\\bin\"\r\nelse\r\n    setenv PATH \"${VAPOR3_HOME}\\bin:$PATH\"\r\nendif\r\n\r\n"
  },
  {
    "path": "scripts/vapor-setup-win32.sh",
    "content": "#!/bin/sh\n\nif [ -z \"${VAPOR3_HOME}\" ]\nthen\n\techo \"VAPOR3_HOME enviroment variable not set\"\n\texit 1\nfi\n\nif [ -z \"${PATH}\" ]\nthen\n    PATH=\"${VAPOR3_HOME}\\\\bin\"; export PATH\nelse\n    PATH=\"${VAPOR3_HOME}\\\\bin:$PATH\"; export PATH\nfi\n\n\n"
  },
  {
    "path": "scripts/vapor-setup.bat",
    "content": "@ECHO OFF\r\nSET PATH=\"%VAPOR3_HOME%/bin\";%PATH%\r\n"
  },
  {
    "path": "scripts/vapor-setup.csh.sed",
    "content": "#! /bin/csh -f\n\nset arch = SYSTEM_ARCH\nset root = INSTALL_PREFIX_DIR\nset idl = BUILD_IDL_WRAPPERS\nset bindir = INSTALL_BINDIR\nset mandir = INSTALL_MANDIR\nset lib_search_dirs = LIB_SEARCH_DIRS\n\nsetenv VAPOR_HOME $root\n\nif !($?PATH) then\n    setenv PATH \"$bindir\"\nelse\n    setenv PATH \"${bindir}:$PATH\"\nendif\n\nif ( \"$arch\" == \"Darwin\" ) then\n\tif !($?DYLD_FALLBACK_LIBRARY_PATH) then\n\t    setenv DYLD_FALLBACK_LIBRARY_PATH \"$lib_search_dirs\"\n\telse\n\t    setenv DYLD_FALLBACK_LIBRARY_PATH \"${lib_search_dirs}:$DYLD_FALLBACK_LIBRARY_PATH\"\n\tendif\nelse if ( \"$arch\" == \"AIX\" ) then\n\tif !($?LIBPATH) then\n\t    setenv LIBPATH \"$lib_search_dirs\"\n\telse\n\t    setenv LIBPATH \"${lib_search_dirs}:$LIBPATH\"\n\tendif\nelse\n\tif !($?LD_LIBRARY_PATH) then\n\t    setenv LD_LIBRARY_PATH \"$lib_search_dirs\"\n\telse\n\t    setenv LD_LIBRARY_PATH \"${lib_search_dirs}:$LD_LIBRARY_PATH\"\n\tendif\nendif\n\nif !($?MANPATH) then\n\tif ( \"$arch\" == \"AIX\" ) then\n\t\tsetenv MANPATH \"$mandir\"\n\telse\n\t\tsetenv MANPATH \"${mandir}\":`man -w`\n\tendif\nelse\n    setenv MANPATH \"${mandir}:${MANPATH}\"\nendif\n\nif ( \"$idl\" == 1 ) then\n\tif !($?IDL_DLM_PATH) then\n\t\tsetenv IDL_DLM_PATH \"${lib_search_dirs}:<IDL_DEFAULT>\"\n\telse\n\t\tsetenv IDL_DLM_PATH \"${lib_search_dirs}:$IDL_DLM_PATH\"\n\tendif\nendif\n"
  },
  {
    "path": "scripts/vapor-setup.sh.sed",
    "content": "#! /bin/sh \n\narch=SYSTEM_ARCH\nroot=INSTALL_PREFIX_DIR\nidl=BUILD_IDL_WRAPPERS\nbindir=INSTALL_BINDIR\nmandir=INSTALL_MANDIR\nlib_search_dirs=LIB_SEARCH_DIRS\n\nVAPOR_HOME=\"$root\"; export VAPOR_HOME\n\nif [ -z \"${PATH}\" ]\nthen\n    PATH=\"$bindir\"; export PATH\nelse\n    PATH=\"$bindir:$PATH\"; export PATH\nfi\n\nif [ \"$arch\" = \"Darwin\" ]\nthen\n\tif [ -z \"${DYLD_FALLBACK_LIBRARY_PATH}\" ]\n\tthen\n\t    DYLD_FALLBACK_LIBRARY_PATH=\"${lib_search_dirs}\"; export DYLD_FALLBACK_LIBRARY_PATH\n\telse\n\t    DYLD_FALLBACK_LIBRARY_PATH=\"${lib_search_dirs}:$DYLD_FALLBACK_LIBRARY_PATH\"; export DYLD_FALLBACK_LIBRARY_PATH\n\tfi\nelse\nif [ \"$arch\" = \"AIX\" ]\nthen\n\tif [ -z \"${LIBPATH}\" ]\n\tthen\n\t    LIBPATH=\"${lib_search_dirs}\"; export LIBPATH\n\telse\n\t    LIBPATH=\"${lib_search_dirs}:$LIBPATH\"; export LIBPATH\n\tfi\nelse\n\tif [ -z \"${LD_LIBRARY_PATH}\" ]\n\tthen\n\t    LD_LIBRARY_PATH=\"${lib_search_dirs}\"; export LD_LIBRARY_PATH\n\telse\n\t    LD_LIBRARY_PATH=\"${lib_search_dirs}:$LD_LIBRARY_PATH\"; export LD_LIBRARY_PATH\n\tfi\nfi\nfi\n\n\nif [ -z \"${MANPATH}\" ]\nthen\n\tif [ \"$arch\" = \"AIX\" ]\n\tthen\n\t\tMANPATH=\"$mandir\"; export MANPATH\n\telse\n\t\tMANPATH=\"$mandir\":$(man -w); export MANPATH\n\tfi\nelse\n    MANPATH=\"$mandir:${MANPATH}\"; export MANPATH\nfi\n\nif [ \"$idl\" -eq 1 ]\nthen\n\tif [ -z \"${IDL_DLM_PATH}\" ]\n\tthen\n\t\tIDL_DLM_PATH=\"${lib_search_dirs}:<IDL_DEFAULT>\"; export IDL_DLM_PATH\n\telse\n\t\tIDL_DLM_PATH=\"${lib_search_dirs}:$IDL_DLM_PATH\"; export IDL_DLM_PATH\n\tfi\nfi\n"
  },
  {
    "path": "scripts/vaporBatchFuncs.py",
    "content": "#!/bin/python\n\n#$ -S /bin/python\n# -m bes\n# -noshell /bin/python\n\nimport os\nimport sys\nimport subprocess\n\ndef usage():\n\tprint \"Usage:\"\n\tprint \"[scheduler options] parallelScript vaporTool : [vaporToolFlags] [-files fileList.txt] : [inputFiles vdfFile]\"\n\tprint \"\"\n\tprint \"[scheduler options]    - Options taken by the scheduler (SGE, LSF, etc)\"\n\tprint \"                         to set up the environment for the array job.\"\n\tprint \"vaporTool              - One of Vapor's data conversion tools, such as\"\n\tprint \"                         wrf2vdf, grib2vdf, etc.\"\n\tprint \"[vaporToolFlags]       - Vapor's data conversion tools each have their\"\n\tprint \"                         own set of options that can be applied for \"\n\tprint \"                         data conversion (such as -numts to specify the\"\n\tprint \"                         number of timesteps to convert).  These options\"\n\tprint \"                         may be also be applied here to be used by the\"\n\tprint \"                         parallel script.\"\n\tprint \"[-files, fileList]     - Users can specify a text-file that contains a\"\n\tprint \"                         list of data-files (fileList) they want to\"\n\tprint \"                         perform their conversion on.  If used, the .vdf\"\n\tprint \"                         file needs to be included as well.\"\n\tprint \"[-grid, gridFile]      - (For ROMS datasets only) ROMS requires a grid\"\n\tprint \"                         file for each individual conversion that is run.\"\n\tprint \"\t\t\t\tROMS conversions must specify that grid file here.\"\n\tprint \"[inputFiles, .vdfFile] - If the -files flag is not applied, users may\"\n\tprint \"                         list their data files on the command line.\"\n\n\ndef parseVapor(args):\n\n\tvaporFlags = []\n\tgrid = ''\n\n\t# remove vapor[tool].py from argument list\n\targs.pop(0)\n\tmyTool = ''\n\tif args.count(\":\") != 2:\n\t\tprint \"Command line must contain two ':' delimiters\"\n\t\treturn -1,[],'',[]\n\n\n\t# remove the vapor tool and its delimiting ':' from argument list\n\ti = args.index(':')\n\tmyTool = args[i-1]\n\targs.pop(i)\n\ti = args.index(myTool)\n\targs.pop(i)\n\n\t# parse all command-line flags that are going to be applied\n\t# to the *2vdf script.\tA ':' can separate user flags from \n\t# user files.  If the '-inputFiles' flag is used, then files\n\t# are listed in a single text file and any ':' will be ignored\n\ttry:\n\t\ti = args.index(':')\n\t\tvaporFlags = args[0:i]\n\t\tmyFiles = args[i+1:]\n\texcept:\n\t\tvaporFlags = args\n\n\tif \"-files\" in vaporFlags:\n\t\ti = args.index('-files')\n\t\tinFile = args[i+1]\n\t\tf = open(inFile,'r')\n\t\tmyFiles = f.read().splitlines()\n\t\tvaporFlags.remove('-files')\n\t\tvaporFlags.remove(inFile)\n\n\tif \"-grid\" in vaporFlags:\n\t\ti = args.index('-grid')\n\t\tgrid = args[i+1]\n\t\tvaporFlags.remove('-grid')\n\t\tvaporFlags.remove(grid)\n\n\tvaporFlags = ' '.join(vaporFlags)\n\n\tif len(myFiles) < 2:\n\t\tprint \"No input files specified.\"\n\t\treturn -1, [],'',[]\n\n\t# 'args' is now just a list of our input files\n\treturn 1, vaporFlags, myTool, myFiles, grid\n\ndef allocateFiles(files,first,last,myId):\n\t# identify our .vdf file within our 'files' list\n\tmyVDF = ''\n\tr = range(0,len(files))\n\tfor i in r:\n\t\tif '.vdf' in files[i]:\n\t\t\tmyVDF = files[i]\n\t\t\tfiles.pop(i)\n\t\t\tbreak\n\n\tstride = (len(files)) / (last - first + 1)\n\tif stride == 0: stride = 1\n\tmyFiles = files[myId*stride : (myId+1)*stride]\n\tleftovers = (len(files))%stride\n\n\tif (myId == last) and (leftovers != 0):\n\t\tmyFiles = myFiles + files[(leftovers*-1):]\n\treturn myFiles, myVDF\n\ndef generateCall(myVDF, myFiles, myTool, flags, binDir):\n\tcommand = myTool + ' ' + flags + ' ' \n\tif 'wrf2vdf' in myTool:\n\t\tcommand += ' ' + myVDF + ' ' + ' '.join(myFiles)\n\telse:\n\t\tcommand += ' '.join(myFiles) + ' ' + myVDF\n\n\tsourceString = \"sh;. \" + binDir + r\"/vapor-setup.sh;\"\n\tcall = sourceString + command\n\tprint call\n\treturn call\n"
  },
  {
    "path": "scripts/vaporLSF.py",
    "content": "#!/usr/bin/python\n\n####################################################################\n#\n#         Copyright (C)  2015                                      \n#   University Corporation for Atmospheric Research                \n#         All Rights Reserved                                      \n#\n#  File:        vaporLSF.py\n#\n#  Author:      Scott Pearse\n#               National Center for Atmospheric Research\n#               PO 3000, Boulder, Colorado\n#\n#  Date:        July 2015\n#\n####################################################################\n\nimport os\nimport sys\nimport subprocess\nsys.path.append(\"..\")\nfrom vaporBatchFuncs import *\n\n##################### USER DEFINED VARIABLES #######################\n\n\n# The variable 'vaporBinDir' needs to point to where vapor's binary\n# applications have been installed\nvaporBinDir = '/glade/p/DASG/pearse/parallelConverter/vapor-2.4.2/bin'\n\n# The variables first, last, and myId are used to divide a set\n# of files amongst the tasks in a given batch job.  These are \n# derived from environment variables that are assigned by the\n# scheduler being used.  These variables must be indexed starting\n# at zero.\n# first - the index of the first task in the batch submission\n# last - the index of the last task in the batch submission\n# myId - the index of the current task\ntry:\n\tfirst = 0\n\tlast = int(os.environ[\"LSB_JOBINDEX_END\"]) -1\n\tmyId = int(os.environ[\"LSB_JOBINDEX\"]) -1\nexcept:\n\tprint \"Unable to locate array job environment variables.  Aboring.\"\n\tusage()\n\tsys.exit(-1)\n\t\n###################################################################\n\n\ndef main():\n\targs = sys.argv\n\tmyVDF = ''\n\tgrid = ''\n\n\trc, vaporFlags, myTool, files, grid = parseVapor(args)\n\tif rc != 1:\n\t\tprint \"Input error.  Aborting.\"\n\t\tusage()\n\t\treturn\n\n\tmyFiles, myVDF = allocateFiles(files,first,last,myId)\n\tif myVDF == '':\n\t\tprint \"Could not locate .vdf metadata file.  Aborting.\"\n\t\treturn\n\tif grid != '':\n\t\tmyFiles.append(grid)\n \n\tcall = generateCall(myVDF, myFiles, myTool, vaporFlags, vaporBinDir)\n\tsubprocess.call(call, shell=True)\n\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "scripts/vaporSGE.py",
    "content": "#!/usr/bin/python\n#$ -S /bin/python\n\n####################################################################\n#\n#         Copyright (C)  2015                                      \n#   University Corporation for Atmospheric Research                \n#         All Rights Reserved                                      \n#\n#  File:        vaporSGE.py\n#\n#  Author:      Scott Pearse\n#               National Center for Atmospheric Research\n#               PO 3000, Boulder, Colorado\n#\n#  Date:        July 2015\n#\n####################################################################\n\n\nimport os\nimport sys\nimport subprocess\nsys.path.insert(0,'.')\nfrom vaporBatchFuncs import *\n\n##################### USER DEFINED VARIABLES #######################\n\n# The variable 'vaporBinDir' needs to point to where vapor's binary\n# applications have been installed\nvaporBinDir = '/users/pearse/vapor/vapor-2.4.2/bin' \n\n# The variables first, last, and myId are used to divide a set\n# of files amongst the tasks in a given batch job.  These are \n# derived from environment variables that are assigned by the\n# scheduler being used.\n# first - the index of the first task in the batch submission\n# last - the index of the last task in the batch submission\n# myId - the index of the current task\ntry:\n\tfirst = 0\n\tlast  = int(os.environ[\"SGE_TASK_LAST\"]) - int(os.environ[\"SGE_TASK_FIRST\"])\n\tmyId  = int(os.environ[\"SGE_TASK_ID\"]) - int(os.environ[\"SGE_TASK_FIRST\"])\nexcept:\n\tprint \"Unable to locate array job environment variables.  Aboring.\"\n\tusage()\n\tsys.exit(-1)\n###################################################################\n\ndef main():\n\targs = sys.argv\n\tmyVDF = ''\n\tgrid = ''\n\n\trc, vaporFlags, myTool, files, grid = parseVapor(args)\n\tif rc != 1:\n\t\tprint \"Input error.  Aborting.\"\n\t\tusage()\n\t\treturn\n\n\tmyFiles, myVDF = allocateFiles(files,first,last,myId)\n\tif myVDF == '':\n\t\tprint \"Could not locate .vdf metadata file.  Aborting.\"\n\t\treturn\n \n\tcall = generateCall(myVDF, myFiles, myTool, vaporFlags, vaporBinDir)\n\tsubprocess.call(call, shell=True)\n\nif __name__ == '__main__':\n\tmain()\n"
  },
  {
    "path": "scripts/vdccp",
    "content": "#!/usr/bin/env python2\n\n####################################################################\n#                                                                  #\n#         Copyright (C)  2016                                      #\n#         University Corporation for Atmospheric Research          #\n#         All Rights Reserved                                      #\n#                                                                  #\n#  File:        vdccp.py                                           #\n#                                                                  #\n#  Author:      Stanislaw Jaroszynski                              #\n#               National Center for Atmospheric Research           #\n#               PO 3000, Boulder, Colorado                         #\n#                                                                  #\n#  Date:        June  2016                                         #\n#                                                                  #\n####################################################################\n\nimport os\nimport sys\nimport argparse\nimport shutil\nimport errno\n\n################## Utility Functions and Classes ###################\n\n#\n# Prints error message and exits program if condition fails\n#\ndef Assert(cond, mesg):\n    if not cond:\n        print \"vdccp.py:\", mesg\n        quit()\n\n#\n# Holds information about a single variable or coordinate\n#\nclass VDCVar():\n    def __init__(s, name):\n        s.name = name\n        s.timesteps = []\n        s.minFrame = -1\n        s.maxFrame = -1\n        s.minCompression = -1\n        s.maxCompression = -1\n\n#\n# Holds information about a file's path relative to the database and its size in bytes\n#\nclass File():\n    def __init__(s, relPath):\n        global srcDir\n        s.relPath = relPath\n        s.size = os.path.getsize(os.path.join(srcDir, relPath))\n\n######################## Global Variables ##########################\n#\n# Variables and coordinates are stored seperately because they have\n# different options and follow different rules for copying.\n# Min/max frames and compression is stored both for each variable\n# as well as a global min/max.\n#\n\nminFrameGlobal = sys.maxint\nmaxFrameGlobal = -sys.maxint - 1\nminCompressionGlobal = sys.maxint\nmaxCompressionGlobal = -sys.maxint - 1\ntotalSizeGlobal = 0\ntotalCopySize = 0\n\nallVars = []\nallCoords = []\ncopyVars = []\ncopyCoords = []\nfilesToCopy = []\n\n######################## Primary Functions #########################\n\n#\n# Returns object containing argument strings and flags\n#\ndef SetupAndParseArgs():\n    ap = argparse.ArgumentParser(prog=\"vdccp.py\", description=\"Copies a user defined portion of a vdc database.\")\n    ap.add_argument(\"source\", type=argparse.FileType(\"r\"), help=\"Source database.nc file.\")\n    ap.add_argument(\"destination\", nargs=\"?\", help=\"Destination directory.\")\n    ap.add_argument(\"-v\", \"--var\", action=\"append\", help=\"Variable(s) to be copied. All coordinates selected by default and can be removed with -x. Multiple can be grouped together if colon separated. If none specified, all variables selected.\")\n    ap.add_argument(\"-x\", \"--exclude\", action=\"append\", help=\"Variable(s) or coordinate(s) to be excluded. Multiple can be grouped together if colon separated. Overrides any variables added with -v.\")\n    ap.add_argument(\"-s\", \"--start-frame\", default=0, type=int, help=\"Start frame. Default first frame. (Frames do not correspond directly to time steps. A single frame can contain multiple time steps.\")\n    ap.add_argument(\"-e\", \"--end-frame\", type=int, help=\"End frame. Default last frame. Overrides -d. If neither -e or -d is specified, the entire data set after the start is copied.\")\n    ap.add_argument(\"-d\", \"--frame-count\", type=int, help=\"Number of time frames from Start to copy. Overridden by -e.\")\n    ap.add_argument(\"-c\", \"--compression\", type=int, help=\"Compression level to copy. Default maximum detail.\")\n    ap.add_argument(\"-f\", \"--force\", action=\"store_true\", help=\"Overwrites existing data if necessary.\")\n    ap.add_argument(\"-n\", \"--dry-run\", action=\"store_true\", help=\"Show what would have been transferred.\")\n    ap.add_argument(\"--coord-start-frame\", default=0, type=int, help=\"Start frame for coordinates. All coordinate frames copied by default. -s does not affect coordinate frames.\")\n    ap.add_argument(\"--coord-end-frame\", default=sys.maxint, type=int, help=\"End frame for coordinates. All coordinate frames copied by default. -s does not affect coordinate frames.\")\n    ap.add_argument(\"--info\", action=\"store_true\", help=\"Prints available variables, coordinates, compression levels, and maximum/minimum timesteps for data set and exits.\")\n    ap.add_argument(\"--info-var\", nargs=1, action=\"append\", help=\"Prints available variables, coordinates, compression levels, and maximum/minimum timesteps for a specific variable and exits.\")\n    ap.add_argument(\"--version\", action=\"version\", version=\"%(prog)s 0.9\")\n    return ap.parse_args()\n\n#\n# Create utility strings with relative and absolute paths to folders\n# used. Assert that the expected database folders exist.\n#\ndef GeneratePertinentPaths():\n    global vdcName\n    global srcDir\n    global relDataDir\n    global relVarDir\n    global relCoordDir\n    global dataDir\n    global varDir\n    global coordDir\n    global destDir\n    global hasVarDir\n    global hasCoordDir\n\n    vdcName = os.path.splitext(os.path.basename(args.source.name))[0]\n    srcDir = os.path.dirname(os.path.realpath(args.source.name))\n    relDataDir = vdcName + \"_data\"\n    relVarDir = os.path.join(relDataDir, \"data\")\n    relCoordDir = os.path.join(relDataDir, \"coordinates\")\n    dataDir = os.path.join(srcDir, relDataDir)\n    varDir = os.path.join(srcDir, relVarDir)\n    coordDir = os.path.join(srcDir, relCoordDir)\n    destDir = args.destination\n    hasVarDir = False\n    hasCoordDir = False\n    \n    if os.path.isdir(dataDir) and os.path.isdir(varDir): hasVarDir = True\n    else: print \"vdccpy.py: Warning: Data is missing\"\n    if os.path.isdir(coordDir): hasCoordDir = True\n\n#\n# Obtains the min/max frame and compressions for a var and updates\n# global values if necessary. Information is determined only from\n# file names.\n# Variable directory argument is to allow the same function to be\n# used for both variables and coordinates.\n#\ndef getVarInfo(var, directory):\n    global minFrameGlobal\n    global maxFrameGlobal\n    global minCompressionGlobal\n    global maxCompressionGlobal\n    global totalSizeGlobal\n    for fn in os.listdir(os.path.join(directory, var.name)):\n        if fn[0] == \".\": continue # Ignores Finder metadata in OS X\n        totalSizeGlobal += os.path.getsize(os.path.join(directory, var.name, fn))\n        fn, comp = os.path.splitext(fn)\n        comp = comp[3:]\n        if comp == \"\": comp = 0\n        else: comp = int(comp)\n        time = int(os.path.splitext(fn)[1][1:])\n\n        if not time in var.timesteps:\n            var.timesteps.append(time)\n        if var.minFrame == -1 or var.minFrame > time: var.minFrame = time\n        if var.maxFrame == -1 or var.maxFrame < time: var.maxFrame = time\n        if var.minCompression == -1 or var.minCompression > comp: var.minCompression = comp\n        if var.maxCompression == -1 or var.maxCompression < comp: var.maxCompression = comp\n    minFrameGlobal = min(minFrameGlobal, var.minFrame)\n    maxFrameGlobal = max(maxFrameGlobal, var.maxFrame)\n    minCompressionGlobal = min(minCompressionGlobal, var.minCompression)\n    maxCompressionGlobal = max(maxCompressionGlobal, var.maxCompression)\n\n#\n# Obtains variable metadata for all variables and coordinates\n#\ndef ScanVariableMetadata():\n    global allVars\n    global allCoords\n    global totalSizeGlobal\n\n    global varDir\n    global coordDir\n    global hasVarDir\n    global hasCoordDir\n\n    if hasVarDir:\n        for fn in os.listdir(varDir):\n            if fn[0] == \".\": continue\n            var = VDCVar(fn)\n            getVarInfo(var, varDir)\n            allVars.append(var)\n    \n    if hasCoordDir:\n        for fn in os.listdir(coordDir):\n            if fn[0] == \".\": continue\n            var = VDCVar(fn)\n            getVarInfo(var, coordDir)\n            allCoords.append(var)\n    \n    totalSizeGlobal /= (2**30) * 1.0 # Convert from bytes to GB\n\n#\n# Bound frames to available and set to bounds if not specified.\n#\ndef CheckArgumentValidity(args):\n    if args.end_frame == None:\n        if args.frame_count != None:\n            args.end_frame = args.start_frame + args.frame_count\n        else:\n            args.end_frame = maxFrameGlobal\n    if args.start_frame < minFrameGlobal: args.start_frame = minFrameGlobal\n    if args.end_frame > maxFrameGlobal: args.end_frame = maxFrameGlobal\n    if args.compression == None: args.compression = maxCompressionGlobal\n    if args.coord_start_frame < minFrameGlobal: args.coord_start_frame = minFrameGlobal\n    if args.coord_end_frame > maxFrameGlobal: args.coord_end_frame = maxFrameGlobal\n    if destDir == None and not args.info and not args.info_var:\n        Assert(0, \"Error: Copy destination not set.\")\n\n#\n# Create list of variables to be copied from args. If none specified,\n# add all variables.\n# All coordinates are added by default.\n#\ndef AddVariablesFromArguments():\n    global args\n    global copyVars\n    global copyCoords\n\n    copyCoords = allCoords[:] # All coordinates copied by default\n    copyVarsNames = []\n    if args.var != None:\n        for varName in args.var:\n            if ':' in varName:\n                copyVarsNames += varName.split(':')\n            else:\n                copyVarsNames.append(varName)\n        copyVarsNames = list(set(copyVarsNames))\n        for var in allVars:\n            for name in copyVarsNames:\n                if var.name == name:\n                    copyVars.append(var)\n                    copyVarsNames.remove(name)\n                    break\n        Assert(len(copyVarsNames) == 0, \"Error: Variable(s) {0} not found.\".format('\"'+copyVarsNames[0]+'\"' if len(copyVarsNames) == 1 else copyVarsNames))\n    else:\n        copyVars = allVars[:]\n\n#\n# Remove any excluded variables or coordinates from list.\n#\ndef ExcludeVariablesFromArguments():\n    global args\n    global copyVars\n    global copyCoords\n\n    excludeVarsNames = []\n    if args.exclude != None:\n        for varName in args.exclude:\n            if ':' in varName:\n                excludeVarsNames += varName.split(':')\n            else:\n                excludeVarsNames += varName.split(':')\n        excludeVarsNames = list(set(excludeVarsNames))\n        checkList = excludeVarsNames[:]\n        for var in allVars + allCoords:\n            for name in checkList:\n                if var.name == name:\n                    checkList.remove(name)\n                    break\n        Assert(len(checkList) == 0, \"Error: Variable(s) {0} not found.\".format('\"'+checkList[0]+'\"' if len(checkList) == 1 else checkList))\n        for name in excludeVarsNames:\n            for var in copyVars:\n                if var.name == name:\n                    copyVars.remove(var)\n                    break\n            for coord in copyCoords:\n                if coord.name == name:\n                    copyCoords.remove(coord)\n                    break\n\ndef PrintDatabaseInfo():\n        print \"name:\", vdcName\n        print \"time frames:\", minFrameGlobal, \"-\", maxFrameGlobal\n        print \"compression levels:\", minCompressionGlobal, \"-\", maxCompressionGlobal\n        print \"total size: {0:.2f}Gb\".format(totalSizeGlobal)\n        print \"variables:\", [var.name for var in allVars]\n        print \"coordinates:\", [var.name for var in allCoords]\n\ndef PrintVariableInfo(name):\n        search = [x for x in allVars + allCoords if x.name == name]\n        Assert(len(search) == 1, \"Error: variable \\\"{0}\\\" not found.\".format(name))\n        var = search[0]\n        print \"Variable \\\"{0}\\\":\".format(var.name)\n        print \"\\ttime frames: {0} - {1}\".format(var.minFrame, var.maxFrame)\n\ndef CreateCopyFileList():\n    global copyVars\n    global copyCoords\n    global vdcName\n    global relVarDir\n    global relCoordDir\n    global totalCopySize\n\n    # Add .nc database metadata file.\n    filesToCopy.append(File(vdcName + \".nc\"))\n\n    # Add variable files\n    for var in copyVars:\n        for frame in xrange(max(var.minFrame, args.start_frame), min(var.maxFrame, args.end_frame) + 1):\n            for level in xrange(var.minCompression, min(args.compression, var.maxCompression) + 1):\n                relPath = os.path.join(relVarDir, var.name, \"{0}.{1:04}.nc{2}\".format(var.name, frame, \"\" if level == 0 else level))\n                if os.path.exists(os.path.join(srcDir, relPath)):\n                    filesToCopy.append(File(relPath))\n    \n    # Add coordinate files\n    for coord in copyCoords:\n        for frame in xrange(max(coord.minFrame, args.coord_start_frame), min(coord.maxFrame, args.coord_end_frame) + 1):\n            for level in xrange(coord.minCompression, coord.maxCompression + 1):\n                relPath = os.path.join(relCoordDir, coord.name, \"{0}.{1:04}.nc{2}\".format(coord.name, frame, \"\" if level == 0 else level))\n                if os.path.exists(os.path.join(srcDir, relPath)):\n                    filesToCopy.append(File(relPath))\n    \n    # Get total size of files to copy to show progress.\n    for x in filesToCopy: totalCopySize += x.size\n\n#\n# Copy all files from list. If --dry-run specified, only print file\n# copy info. If file already exists, show prompt to overwrite unless\n# --force. Any missing directories are created. After a file is\n# copied, its size is added to copiedSize and this is used to show\n# a percent copied.\n#\ndef CopyFiles():\n    global filesToCopy\n    global srcDir\n    global destDir\n    global totalCopySize\n    global args\n\n    copiedSize = 0\n    for f in filesToCopy:\n        destPath = os.path.join(destDir, f.relPath)\n        if not os.path.exists(os.path.dirname(destPath)) and not args.dry_run:\n                # Race condition where folder is created\n                try: os.makedirs(os.path.dirname(destPath))\n                except OSError as err:\n                    if err.errno != errno.EEXIST:\n                        raise\n        if os.path.exists(destPath) and not args.force and not args.dry_run:\n            response = raw_input(\"File \\\"{0}\\\" already exists. Overwrite? (y/n)\".format(destPath))\n            if not (response == \"y\" or response == \"Y\"):\n                copiedSize += f.size\n                continue\n        sys.stdout.write(\"{0:3d}% Copying {1}\\n\".format(copiedSize * 100 / totalCopySize, f.relPath))\n        if not args.dry_run:\n            shutil.copy(os.path.join(srcDir, f.relPath), destPath)\n        copiedSize += f.size\n    \n    print \"100%\"\n\n############################### Main ############################### \n\ndef main():\n    global args\n    args = SetupAndParseArgs()\n    GeneratePertinentPaths()\n    ScanVariableMetadata()\n    CheckArgumentValidity(args)\n    AddVariablesFromArguments()\n    ExcludeVariablesFromArguments()\n\n    if args.info or args.info_var != None:\n        if args.info:\n            PrintDatabaseInfo()\n        if args.info_var != None:\n            for name in [x[0] for x in args.info_var]:\n                PrintVariableInfo(name)\n        quit()\n\n    CreateCopyFileList()\n    CopyFiles()\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "scripts/vdfbkup.pl",
    "content": "#!/usr/bin/perl\n#\n#      $Id$\n#\n#########################################################################\n#\t\t\t\t\t\t\t\t\t#\n#\t\t\t   Copyright (C)  2007                          #\n#\t     University Corporation for Atmospheric Research\t\t#\n#\t\t\t   All Rights Reserved\t\t\t\t#\n#\t\t\t\t\t\t\t\t\t#\n#########################################################################\n#\n#\tFile:\t\tvdfbkup.pl\n#\n#\tAuthor:\t\tJohn Clyne\n#\t\t\tNational Center for Atmospheric Research\n#\t\t\tPO 3000, Boulder, Colorado\n#\n#\tDate:\t\tFri Jan 13 18:00:32 MST 1995\n#\n#\tDescription:\t\n#\n#\tUsage:\n#\n#\tEnvironment:\n#\n#\tFiles:\n#\n#\n#\tOptions:\n\nuse English;\nuse POSIX;\nuse File::Basename;\nuse File::Spec;\nuse File::Copy;\nuse Cwd 'abs_path';\nuse Cwd;\n\n\n$tmpdirdef = defined($ENV{'TMPDIR'}) ? $ENV{'TMPDIR'} : \"/tmp\";\n#\n#\tOptions is a table of *configurable* options supported by\n#\tvdfbkup.pl. The fields contained within are: option name, perl variable\n#\tname, default option values, number of option arguments (0 or 1), and\n#\ta description of the option.\n#\n@Options = (\n\"maxtarsize\",\t\"MaxTarSize\",\t\"5000\",\t'1', \"Max size of tar file(MBytes)\",\n\"maxsize\",\t\"MaxSize\",\t\"500\",\t'1', \"Max size of file to tar (MBytes)\",\n\"maxarg\",\t\"MaxArg\",\t\"70000\",'1', \"Max size of unix cmd line(bytes)\",\n\"bs\",\t\"BS\",\t\"512\",'1', \"Tar blocking factor (bs*512 bytes)\",\n\"nr\",\t\t\"NotReally\",\t\"0\",\t'0', \"Echo, but do not execute cmds\",\n\"quiet\",\t\"Quiet\",\t\"0\",\t'0', \"Operate quitely\",\n\"nolog\",\t\"NoLog\",\t\"0\",\t'0', \"Do not create a log file\",\n\"restart\",\t\"Restart\",\t\"0\",\t'0', \"Restart using the ./vdfbkup_restart.txt restart file\",\n);\n\n\nsub     usage {\n\tlocal($s) = @_;\n\n\tlocal($format) = \"\\t%-12.12s  %-12.12s  %-5.5s %s\\n\";\n\n\tif (defined ($s)) {\n\t\tprint STDERR \"$ProgName: $s\\n\";\n\t}\n\n\tprint STDERR \"Usage: $ProgName [options] vdffile (directory|command)\\n\";\n\tprint STDERR \"Usage: $ProgName -restart\\n\";\n\tprint STDERR \"\\nWhere \\\"options\\\" are:\\n\\n\";\n\tprintf STDERR $format, \"Option name\", \"Default\", '#args', \"Description\";\n\tprintf STDERR $format, \"------ ----\", \"-------\", '-----', \"-----------\";\n\tprint STDERR \"\\n\";\n\n\tfor($i=0; $i<=$#Options; $i+=5) {\n\t\tprintf STDERR $format,\t\"-$Options[$i]\", $Options[$i+2], $Options[$i+3], $Options[$i+4];\n\t}\n\texit(1);\n}\n\n#\n#\tSet a variable, whose name is given by `$name', to the value\n#\tgiven by `$value'\n#\nsub set_var_by_name {\n\tlocal($name, $value) = @_;\n\n\teval \t'$' . $name . \" = \\'$value\\'\";\n}\n\nsub get_var_by_name {\n\tlocal($name) = @_;\n\tlocal($value);\n\n\teval '$value = ' . '$' . \"$name\";\n\n\treturn($value);\n}\n\nsub configure {\n\tmy (@argv) = @_;\n\tmy ($i);\n\tmy ($match);\n\n        #\n        #       Set defaults\n        #\n        #       This nonsense creates a variable named by the second\n        #       field of @Options (the option name) and assigns it\n        #       the value of the third field of @Options (the default option\n        #       argument). \n        #\n        for($i=0; $i<=$#Options; $i+=5) {\n                do set_var_by_name($Options[$i+1], $Options[$i+2]);\n        }\n\n\n\t#\n\t#\tNext, parse the command line, overriding anything\n\t#\tset by default above.\n\t#\n\twhile ($argv[0] =~ /^-/) {\n\t\t$opt = shift @argv;\n\n\t\t$match = -1;\t# index of matching option\n\n\t\t#\n\t\t#\tLook for an option name that matches the \n\t\t#\toption specifier given on the command line. Exact\n\t\t#\tmatches aren't required. The shortes unique string\n\t\t#\tis sufficient\n\t\t#\n\t\tfor($i=0; $i<=$#Options; $i+=5) {\n\t\t\t$_ = \"-\" . $Options[$i];\t# option name\n\n\n\t\t\tif (/^$opt/) {\n\n\t\t\t\t#\n\t\t\t\t# Do we already have a match? If so the \n\t\t\t\t# option specifier is ambiguous\n\t\t\t\t#\n\t\t\t\tif ($match >= 0) {\n\t\t\t\t\tdo usage(\"Ambiguous option: \\\"$opt\\\"\");\n\t\t\t\t}\n\t\t\t\t$match = $i;\n\t\t\t}\n\n\t\t}\n\t\tif ($match < 0) {\n\t\t\tdo usage (\"Unknown option: \\\"$opt\\\"\");\n\t\t}\n\n\t\t#\n\t\t# does the option take an argument? If not the option's \n\t\t# value is given by the table, \"Options\"\n\t\t#\n\t\tif ($Options[$match+3]) {\n\t\t\tdefined($value = shift @argv) || do usage(\"Missing offset\");\n\t\t}\n\t\telse {\n\t\t\t$value = ! $Options[$match+2];\n\t\t}\n\n\t\tdo set_var_by_name($Options[$match+1], $value);\n\n\t}\n\treturn(@argv);\n}\n\nsub mysystem {\n    my(@cmd) = @_;\n\n\tif (! $Quiet) {\n\t\tsmsg(*STDOUT, \"Executing -> @cmd\");\n\t}\n\t\n\tif (! $NotReally) {\n\t\tsystem(@cmd);\n\t\tif ($? != 0) {\n\t\t\tsmsg(*STDERR, \"Command \\\"@cmd\\\" exited with error\");\n\t\t\texit(1);\n\t\t}\n\t}\n}\n\nsub\tCleanup {\n\tmy($sig) = @_;\n\n\tclose RESTART;\n\tprint STDERR \"$ProgName: Caught a SIG$sig -- Shutting down\\n\";\n\texit(0);\n}\n\n\nsub\ttimestamp {\n\tmy($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();\n\n\t$year -= 100;\t# y2k\n\treturn(sprintf(\n\t\t\"%2.2d%2.2d%2.2d%2.2d%2.2d%2.2d\",\n\t\t$year, $mon, $mday, $hour, $min, $sec)\n\t);\n}\n\t\n\n\nsub \tsmsg {\n\tmy($fh, $msg) = @_;\n\tmy($str);\n\n\tmy($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();\n\t$timestr = POSIX::strftime(\n\t\t\"%a, %b %d %H:%M:%S\", $sec, $min, $hour, $mday, $mon, $year, $wday, \n\t\t$yday, $isdst\n\t);\n\n\t$msg = sprintf(\"$ProgName: ($timestr): %s\\n\", $msg);\n\n\tif (length($msg) < $MaxMsg) {\n\t\tprintf $fh \"%s\\n\", \"$msg\";\n\t}\n\telse {\n\t\tmy($maxmsg);\n\t\tmy($elipses) = \"...\";\n\n\t\t$maxmsg = $MaxMsg - length($elipses);\n\t\tprintf $fh \"%-${MaxMsg}.${MaxMsg}s\", \"$msg\";\n\t\tprintf $fh \"%s\\n\", $elipses;\n\t}\n}\n\nsub\tcopyit {\n\tlocal($src, $dst) = @_;\n\n\t#if (-d $dst) {\n\t#\t$dst = File::Spec->catfile($dst, $src);\n\t#}\n\n\tif (! $Quiet) {\n\t\tprintf STDOUT \"Copying file $src to $dst\\n\";\n\t}\n\n\tif (! $NotReally) {\n\t\tif (! copy($src, $dst)) {\n\t\t\tsmsg (*STDERR, \"Can't copy $src to $dst\");\n\t\t\texit(1);\n\t\t}\n\t}\n\n   if (! $NoLog) {\n\t\tif (-f $src) {\n\t\t\t($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($src);\n\n\t\t\tprint FILE \"$src   -   $size\\n\";\n\t\t}\n\t}\n}\n\nsub vdfsplit {\n\tmy($file) = @_;\n\n\tmy($dummy1, $varname) = File::Spec->splitdir($file);\n\tmy($dummy1, $dummy2, $filebase) = File::Spec->splitpath($file);\n\n\tmy($dummy, $ts, $level) = split(/\\./, $filebase);\n\t$level =~s/nc//;\n\n\treturn($varname, $ts, $level);\n}\n\nsub\ttarit {\n\tlocal($tarfile, @files) = @_;\n\n\tmy(@cmd) = (\"tar\", \"-c\", \"-b\", $BS, \"-f\", $tarfile, @files);\n\n\tmysystem(@cmd);\n\n   if (! $NoLog) {\n\t\t\tprint FILE \"\\n------------------\\n$tarfile contents\\n------------------\\n\";\n\t\tforeach $file (@files) {\n\t\t\tif (-f $file) {\n\t\t\t\t($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($file);\n\n\t\t\t\tprint FILE \"$file   -   $size\\n\";\n\t\t\t}\n\t\t}\n\t}\n}\n\n#\n# Save state of @CmdLineArgs, $VDFFile, @FilesToTar, @TarNames, and \n# @FilesToCopy variables\n#\nsub save_state {\n\n\tif (! open (RESTART, \"> $RestartFile\")) { \n\t\tprint STDERR \"Can't open state file $RestartFile\\n\";\n\t\treturn;\n\t}\n\n\tforeach $arg (@CmdLineArgs) {\n\t\tprint RESTART \"$arg\\n\";\n\t}\n\tprint RESTART \"END_CMD_LINE_ARGS\\n\";\n\n\t$vdffile = abs_path($VDFFile);\n\tprint RESTART \"$vdffile\\n\";\n\n\tforeach $file (@FilesToCopy) {\n\t\tprint RESTART \"$file\\n\";\n\t}\n\n\tmy(@tar_names) = @TarNames;\n\tforeach $listref (@FilesToTar) {\n\t\t@a = @$listref;\n\t\t$tarfile = shift @tar_names;\n\t\tprint RESTART \"$tarfile\\n\";\n\t\tforeach $file (@a) {\n\t\t\tprint RESTART \"$file\\n\";\n\t\t}\n\t}\n\tclose RESTART;\n}\n\n#\n# Restore state of @CmdLineArgs, $VDFFile, @FilesToTar, @TarNames, and \n# @FilesToCopy variables\n#\nsub restore_state {\n\n\tif (! open (RESTART, \"< $RestartFile\")) { \n\t\tprint STDERR \"Can't open state file $RestartFile\\n\";\n\t\treturn ();\n\t}\n\n\tmy($done) = 0;\n\twhile ((!$done) && ($_ = <RESTART>)) {\n\t\tchop $_;\n\n\t\tif ($_ =~ /^END_CMD_LINE_ARGS$/) {\n\t\t\t$done = 1;\n\t\t\tnext;\n\t\t}\n\t\tpush @CmdLineArgs, $_;\n\t}\n\n\tif (! defined($VDFFile = <RESTART>)) {\n\t\tprint STDERR \"Bogus restart file\\n\";\n\t\treturn();\n\t}\n\tchop $VDFFile;\n\n\t@FilesToCopy = ();\n\t@TarNames = ();\n\tmy($done) = 0;\n\twhile ((!$done) && ($_ = <RESTART>)) {\n\t\tchop $_;\n\n\t\tif ($_ =~ /\\.tar$/) {\n\t\t\tpush @TarNames, $_;\n\t\t\t$done = 1;\n\t\t\tnext;\n\t\t}\n\t\tpush @FilesToCopy, $_;\n\t}\n\t@FilesToTar = ();\n\n\t@list = ();\n\twhile ($_ = <RESTART>) {\n\t\tchop $_;\n\n\t\tif ($_ =~ /\\.tar$/) {\n\t\t\tpush @TarNames, $_;\n\t\t\tpush @FilesToTar, [@list];\n\t\t\t@list = ();\n\t\t\tnext;\n\t\t}\n\t\tpush @list, $_;\n\t}\n\n\tif (@list) {\n\t\tpush @FilesToTar, [@list];\n\t}\n\n\tclose RESTART;\n\n}\n\nsub tar_create {\n\tmy($vdfbase) = @_;\n\n\tif (! $Quiet) {\n\t\tprintf \"%-30.30s: %s\\n\", \"Max tar file size (MB's)\", $MaxTarSize;\n\t\tprintf \"%-30.30s: %s\\n\", \"Max tar file element size (MB's)\", $MaxSize;\n\t\tprintf \"%-30.30s: %s\\n\", \"Max arg length (bytes)\", $MaxArg;\n\t\tprintf \"\\n\";\n\t}\n\n\t$MaxTarSize *= 0.95;\t# allow for tar overhead.\n\n\n\n\tif (! $Restart) {\n\n\t\t$data_dir = $vdfbase;\n\t\t$data_dir =~ s/\\.vdf/_data/;\n\n\t\t$cmd = join(' ', @VDFLSCmd, $vdfbase);\n\t\tif (! $Quiet) {\n\t\t\tsmsg(*STDOUT, \"Executing -> $cmd\");\n\t\t}\n\t\t$_ = `$cmd`;\n\t\tif ($?>>8) { \n\t\t\tprintf STDERR \"$ProgName: Command \\\"$cmd\\\" failed\\n\";\n\t\t\texit(1);\n\t\t}\n\n\t\tmy(@files) = ();\n\t\t@lines = split /\\n/, $_;\n\t\tforeach $_ (@lines) {\n\t\t\tpush @files, $data_dir . \"/\" . $_;\n\t\t}\n\n\n\t\t@FilesToTar = ();\t# list of lists of files to tar\n\t\t@FilesToCopy = ();# list of files to copy without tarring\n\t\t$targlen = 0;\n\t\t$tsize = $tsize_all = 0;\n\t\t@list = ();\n\t\t@TarNames = ();\n\t\tforeach $file (@files) {\n\t\t\tif (-f $file) {\n\t\t\t\t($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat($file);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnext;\n\t\t\t}\n\t\t\t$size = $blocks / 2048;\t# convert from 512-byte blocks to mbytes\n\n\t\t\t$arglen = length(\"$file \");\n\n\t\t\tif ($size > $MaxSize) {\n\t\t\t\tpush @FilesToCopy, $file;\n\t\t\t\t$tsize_all += $size;\n\t\t\t\tnext;\n\t\t\t}\n\n\t\t\tif (! @list) {\n\t\t\t\t($varname0, $ts0, $level0) = vdfsplit($file);\n\t\t\t\t($varname1, $ts1, $level1) = vdfsplit($file);\n\t\t\t}\n\t\t\t($varname, $ts, $level) = vdfsplit($file);\n\t\t\t\n\t\t\tif (\n\t\t\t\t(($targlen + $arglen) >= $MaxArg) || \n\t\t\t\t(($tsize + $size) >= $MaxTarSize) ||\n\t\t\t\t($varname0 ne $varname) ||\n\t\t\t\t($level0 != $level)) {\n\n\t\t\t\tpush @FilesToTar, [@list];\n\t\t\t\tpush @TarNames, sprintf(\"%s_%4.4d-%4.4d.nc%d.tar\", $varname0, $ts0, $ts1, $level0);\n\t\t\t\t@list = ();\n\t\t\t\t($varname0, $ts0, $level0) = vdfsplit($file);\n\t\t\t\t($varname1, $ts1, $level1) = vdfsplit($file);\n\t\t\t\t$targlen = 0;\n\t\t\t\t$tsize = 0;\n\t\t\t}\n\n\t\t\t($varname1, $ts1, $level1) = vdfsplit($file);\n\n\t\t\tpush @list, $file;\n\t\t\t$targlen += $arglen;\n\t\t\t$tsize += $size;\n\t\t\t$tsize_all += $size\n\t\t}\n\n\t\tif (@list) {\n\t\t\tpush @FilesToTar, [@list];\n\t\t\tpush @TarNames, sprintf(\"%s_%4.4d-%4.4d.nc%d.tar\", $varname0, $ts0, $ts1, $level0);\n\t\t}\n\t}\n\n\t#\n\t# back up the vdf file\n\t#\n\tif (defined ($TargetDirectory)) {\n\t\tcopyit($vdfbase, $TargetDirectory);\n\t}\n\telse {\n\t\tmy(@cmd) = (@BackupCmd);\n\t\tforeach $_ (@cmd) {\n\t\t\tmy($dummy1, $dummy2, $filebase) = File::Spec->splitpath($vdfbase);\n\t\t\t$_ =~ s/%s/$vdfbase/;\n\t\t\t$_ =~ s/%b/$filebase/;\n\t\t}\n\t\tmysystem(@cmd);\n\t}\n\n\n\tsave_state();\n\n\twhile ($file = shift(@FilesToCopy)) {\n\t\tif (defined ($TargetDirectory)) {\n\t\t\tcopyit($file, $TargetDirectory);\n\t\t}\n\t\telse {\n\t\t\tmy(@cmd) = (@BackupCmd);\n\t\t\tforeach $_ (@cmd) {\n\t\t\t\tmy($dummy1, $dummy2, $filebase) = File::Spec->splitpath($file);\n\t\t\t\t$_ =~ s/%s/$file/;\n\t\t\t\t$_ =~ s/%b/$filebase/;\n\t\t\t}\n\t\t\tmysystem(@cmd);\n\t\t}\n\t\tsave_state();\n\t}\n\n\twhile ($listref = shift(@FilesToTar)) {\n\t\t$tarbase = shift(@TarNames);\n\t\tif (defined ($TargetDirectory)) {\n\t\t\t$tarfile = File::Spec->catfile($TargetDirectory, $tarbase);\n\t\t}\n\t\telse {\n\t\t\t$tarfile = $tarbase;\n\t\t}\n\t\t@files = @$listref;\n\t\ttarit($tarfile, @files);\n\t\tif (defined (@BackupCmd)) {\n\t\t\tmy(@cmd) = (@BackupCmd);\n\t\t\tforeach $_ (@cmd) {\n\t\t\t\tmy($dummy1, $dummy2, $filebase) = File::Spec->splitpath($tarfile);\n\t\t\t\t$_ =~ s/%s/$tarfile/;\n\t\t\t\t$_ =~ s/%b/$filebase/;\n\t\t\t}\n\t\t\tmysystem(@cmd);\n\n\t\t\tunlink $tarfile;\n\t\t}\n\t\tsave_state();\n\t}\n}\n\n#################################################################\n##\n##\tM A I N   P R O G R A M\n##\n#################################################################\n\n\n$0              =~ s/.*\\///;\n$ProgName       = $0;\n$MBYTE\t\t= 1024 * 1024;\n$MaxMsg\t\t= \"256\";\n@VDFLSCmd\t= (\"vdfls\", \"-sort\", \"varname\");\n$RestartFile = File::Spec->catfile(cwd(), \".vdfbkup_restart.txt\");\n\n@CmdLineArgs = @ARGV;\n@ARGV = configure(@ARGV);\n\n\nif ($Restart) {\n\tif (@ARGV != 0) {\n\t\tusage(\"Wrong # of arguments\");\n\t}\n\trestore_state();\n\t@ARGV = @CmdLineArgs;\n\t@ARGV = configure(@ARGV);\n\n} else {\n\tif (-f $RestartFile) {\n\t\tprint STDERR \"A restart file, $RestartFile,\\n\"; \n\t\tprint STDERR \"was found from a previous\\n\";\n\t\tprint STDERR \"session, but the -restart option was not present. You \\n\";\n\t\tprint STDERR \"must remove the restart file or use the -restart option.\\n\";\n\t\texit (1);\n\t}\n}\n\nif (@ARGV < 2) {\n\tusage(\"Wrong # of arguments - no files specified\");\n}\n\n$VDFFile = shift @ARGV;\n\nif (defined $TargetDirectory) {undef $TargetDirectory;}\nif (defined @BackupCmd) {undef @BackupCmd;}\n\nif (-d $ARGV[0]) {\n\t$TargetDirectory = abs_path(shift @ARGV);\n} else {\n\t@BackupCmd = @ARGV;\n}\n\n\n$SIG{INT} = 'Cleanup';\n\nif (defined $TargetDirectory) {\n\t$LogFile = File::Spec->catfile($TargetDirectory, \"vdfbkup.log\");\n}\nelse  {\n\t$LogFile = \"vdfbkup.log\";\n}\n\t\n\nmy($volume, $directory, $vdfbase) = File::Spec->splitpath($VDFFile);\nif ($directory ne \"\") {\n\tchdir $directory or die \"$ProgName: Can't cd to $directory: $!\\n\";\n}\n\nif (! $NoLog) {\n\topen (FILE, \"> $LogFile\") || die \"Can't open log file $LogFile for writing!\";\n}\n\n\ntar_create($vdfbase);\n\nif (! $NoLog) {\n\tclose FILE;\n}\n\nif (defined @BackupCmd && ! $NoLog) {\n\tmy(@cmd) = (@BackupCmd);\n\tforeach $_ (@cmd) {\n\t\tmy($dummy1, $dummy2, $filebase) = File::Spec->splitpath($LogFile);\n\t\t$_ =~ s/%s/$LogFile/;\n\t\t$_ =~ s/%b/$filebase/;\n\t}\n\tmysystem(@cmd);\n\tunlink $LogFile if (! $NotReally);\n}\n\nunlink $RestartFile;\n"
  },
  {
    "path": "scripts/wrf2vdfbatch",
    "content": "#!/usr/bin/perl\n\n# This variable will be most of the command we execute\n$stub = \"wrf2vdf\";\n\n# This is a switch to say how much output to make\n$quietScript = 0;\n\n# This variable holds the entire help screen\n$helpScreen = \"\nUsage: wrf2vdfbatch [options] metafile wrfFiles\nwrfFiles may be a single WRF netCDF output file, a list of such files, or a\n    file name containing wildcards.\nOptions are:\n    -varnames arg    Colon delimited list of variable names in metadata to\n                         convert\n    -atypvars arg    Colon delimited list of atypical names for variables\n                         U:V:W:PH:PHB:P:PB:T that appear in WRF file(s)\n    -dervars  arg    Colon delimited list of derived variables to convert.\n                         Choices are:\n                         phnorm: normalized geopotential (PH+PHB)/PHB\n                         wind3d: 3D wind speed (U^2+V^2+W^2)^1/2\n                         wind2d: 2D wind speed (U^2+V^2)^1/2\n                         pfull: full pressure P+PB\n                         pnorm: normalized pressure (P+PB)/PB\n                         theta: potential temperature T+300\n                         tk: temperature in Kelvin 0.037(T+300)(P+PB)^0.29\n    -tsincr   arg    Increment between Vapor time steps to convert (e.g.,\n                         3=every third), from Vapor time step 0\n    -tsstart  arg    Starting time stamp for conversion, in format\n                         yyyy-mm-dd_hh:mm:ss\n    -tsend    arg    Last time stamp to convert, in format\n                         yyyy-mm-dd_hh:mm:ss\n    -level    arg    Refinement levels saved.  0=coarsest, 1=next refinement,\n                         etc.  -1=finest (full resolution).\n    -quiet           Only output suggested vertical extents at end of\n                         conversion\n    -help            Print this help screen and exit\n\n\";\n\nif ( $#ARGV == -1 ) # Print help and exit if no arguments are given\n{\n\tprint( \"$helpScreen\" );\n\texit 0;\n}\n\n# Parse command line arguments\n$i = 0;\nfor ( ; $i <= $#ARGV ; $i++ )\n{\n\tif ( $ARGV[$i] eq \"-varnames\" )\n\t{\n\t\t$i++;\n\t\tif ( $ARGV[$i] =~ /^-/ )\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: -varnames option requires argument\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\t$stub = $stub . \" -varnames $ARGV[$i]\";\n\t\tnext;\n\t}\n\tif ( $ARGV[$i] eq \"-atypvars\" )\n\t{\n\t\t$i++;\n\t\tif ( $ARGV[$i] =~ /^-/ )\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: -atypvars option requires argument\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\t$stub = $stub . \" -atypvars $ARGV[$i]\";\n\t\tnext;\n\t}\n\tif ( $ARGV[$i] eq \"-dervars\" )\n\t{\n\t\t$i++;\n\t\tif ( $ARGV[$i] =~ /^-/ )\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: -dervars option requires argument\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\t$stub = $stub . \" -dervars $ARGV[$i]\";\n\t\tnext;\n\t}\n\tif ( $ARGV[$i] eq \"-tsincr\" )\n\t{\n\t\t$i++;\n\t\tif ( $ARGV[$i] =~ /^-/ )\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: -tsincr option requires argument\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\t$stub = $stub . \" -tsincr $ARGV[$i]\";\n\t\tnext;\n\t}\n\tif ( $ARGV[$i] eq \"-tsstart\" )\n\t{\n\t\t$i++;\n\t\tif ( $ARGV[$i] =~ /^-/ )\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: -tsstart option requires argument\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\t$stub = $stub . \" -tsstart $ARGV[$i]\";\n\t\tnext;\n\t}\n\tif ( $ARGV[$i] eq \"-tsend\" )\n\t{\n\t\t$i++;\n\t\tif ( $ARGV[$i] =~ /^-/ )\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: -tsend option requires argument\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\t$stub = $stub . \" -tsend $ARGV[$i]\";\n\t\tnext;\n\t}\n\tif ( $ARGV[$i] eq \"-level\" )\n\t{\n\t\t$i++;\n\t\tif ( $ARGV[$i] =~ /^-/ && $ARGV[$i] ne \"-1\" )\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: -level option requires argument\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\t$stub = $stub . \" -level $ARGV[$i]\";\n\t\tnext;\n\t}\n\tif ( $ARGV[$i] eq \"-quiet\" )\n\t{\n\t\t$quietScript = 1;\n\t\t$stub = $stub . \" -quiet\";\n\t\tnext;\n\t}\n\tif ( $ARGV[$i] eq \"-help\" || $ARGV[$i] eq \"-h\" || $ARGV[$i] eq \"--h\"\n\t\t || $ARGV[$i] eq \"--help\" )\n\t{\n\t\tprint( \"$helpScreen\" );\n\t\texit 0;\n\t}\n\tif ( $ARGV[$i] =~ /^-/ )\n\t{\n\t\tprint( \"wrf2vdfbatch: Unrecognized option $ARGV[$i]\\n\" );\n\t\texit 1;\n\t}\n\tlast; # If we get down here, we're done with options and we've moved on\n\t\t  # to files\n}\n\n# Get the metafile name\n$stub = $stub . \" $ARGV[$i]\";\n\n# These are the bottom of the bottom and top layers.  Start with high values\n# so that they are sure to change.\n$bottomBottom = 400000.0;\n$bottomTop = 400000.0;\n\n# These are the total number of time steps actually converted and the total\n# number of time steps in the WRF files.\n$tsConverted = 0;\n$tsInFiles = 0;\n\n# The starting index of the WRF file list\n$i++;\n$firstWrfIndex = $i;\n\n# Loop over WRF files\nfor ( ; $i <= $#ARGV ; $i++ )\n{\n\t$command = $stub . \" $ARGV[$i]\";\n\n\t# Normal output\n\tif ( $quietScript != 1 )\n\t{\n\t\tprint( \"For WRF output file $ARGV[$i]:\\n\" );\n\t}\n\n\t$result = `$command`;\n\t$exitStat = `echo $?`;\n\t\n\t# Handle errors\n\tif ( $exitStat != 0 )\n\t{\n\t\tprint( \"wrf2vdfbatch: wrf2vdf exited with non-zero exit status\\n\" );\n\t\tprint( \"Command executed was: $command\\n\" );\n\t\texit 1;\n\t}\n\n\t# Normal output\n\tif ( $quietScript != 1 )\n\t{\n\t\tprint( \"$result\\n\" );\n\t}\n\n\t# Extract the most restrictive vertical extents and maybe the number of\n\t# time steps converted. Two different formats to deal with, depending on the\n\t# -quiet option\n\tif ( $quietScript == 1 ) # What to do if quiet option is on\n\t{\n\t\t@newExts = split( / /, $result );\n\t}\n\telse # What to do if quiet option is off\n\t{\n\t\t# This gathers the extents\n\n\t\t# Index where a key phrase begins\n\t\t$mostIndex = index( $result, \"Most restrictive vertical extents: \" );\n\t\tif ( $mostIndex < 0 ) # Handle errors\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: Problem finding most restrictive vertical \" );\n\t\t\tprint( \"extents\\nin wrf2vdf output\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\t\n\t\t# Index of the first newline found after that index\n\t\t$nIndex = index( $result, \"\\n\", $mostIndex );\n\t\tif ( $nIndex < $mostIndex ) # Handle errors\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: Problem finding newline after most \");\n\t\t\tprint( \"restrictive\\nvertical extents\\n\" );\n\t\t\texit 1;\n\t\t}\n\n\t\t# Length of substring to take\n\t\t$strLength = $nIndex - $mostIndex - 35;\n\t\t\n\t\t# Take the extents\n\t\t$extsStr = substr( $result, $mostIndex + 35, $strLength );\n\n\t\t# Split them up\n\t\t@newExts = split( / to /, $extsStr );\n\n\n\t\t# Done getting extents.  Now get time step info.\n\n\t\t# Index where a key phrase begins\n\t\t$timeIndex = index( $result, \"Time steps converted: \" );\n\t\tif ( $timeIndex < 0 ) # Handle errors\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: Problem finding time step information in\\n\" );\n\t\t\tprint( \"wrf2vdf output\\n\" );\n\t\t\texit 1;\n\t\t}\n\t\n\t\t# Index of the first newline found after that index\n\t\t$nIndex = index( $result, \"\\n\", $timeIndex );\n\t\tif ( $nIndex < $timeIndex ) # Handle errors\n\t\t{\n\t\t\tprint( \"wrf2vdfbatch: Problem finding newline after time steps \" );\n\t\t\tprint( \"converted\\n\" );\n\t\t\texit 1;\n\t\t}\n\n\t\t# Length of the substring to take\n\t\t$strLength = $nIndex - $timeIndex - 22;\n\n\t\t# Take the time step info\n\t\t$tsInfoStr = substr( $result, $timeIndex + 22, $strLength );\n\n\t\t# Split up it up and add to the tally\n\t\t@tsInfo = split( / of /, $tsInfoStr );\t\n\t\t$tsConverted += $tsInfo[0];\n\t\t$tsInFiles += $tsInfo[1];\n\t}\n\n\t# Compare old and new extents\n\tif ( $newExts[0] < $bottomBottom )\n\t{\n\t\t$bottomBottom = $newExts[0];\n\t}\n\tif ( $newExts[1] < $bottomTop )\n\t{\n\t\t$bottomTop = $newExts[1];\n\t}\n\n\n\n\n}\n\n# Report how many time steps were converted and number of files, if desired\nif ( $quietScript != 1 )\n{\n\tprint( \"Time steps converted: $tsConverted\\n\" );\n\tprint( \"Total time steps in files: $tsInFiles\\n\" );\n\tprint( \"Total number of WRF files \\(converted or not\\): \" );\n\t$totalFiles = $#ARGV + 1 - $firstWrfIndex;\n\tprint( \"$totalFiles\\n\" );\n}\n\n# Report most restrictive extents\nprint( \"Bottom of bottom layer: $bottomBottom\\n\" );\nprint( \"Bottom of top layer: $bottomTop\\n\" );\nprint( \"You may want to change the vertical extents in your .vdf file.\\n\" );\n"
  },
  {
    "path": "share/CMakeLists.txt",
    "content": "add_subdirectory (Doxygen)\n\nif (BUILD_VDC)\n\tfile (GLOB SHADERS_SRC shaders/*.vert shaders/*.frag shaders/*.geom)\n\tadd_custom_target (\n\t\tshaders ALL\n\t\tSOURCES ${SHADERS_SRC}\n\t)\nendif ()\n\nif (BUILD_VDC AND ${GENERATE_FULL_INSTALLER})\n\tset (SHARE_DIRS\n\t\tdoc\n\t\tfonts\n\t\timages\n\t\tshaders\n\t\tudunits\n\t\tpython\n\t\tpalettes\n\t\texamples\n\t)\n    if (NOT INSTALLER_OMIT_MAPS)\n\t    set (SHARE_DIRS ${SHARE_DIRS} \"${MAP_IMAGES_PATH}\")\n    endif()\n\tinstall (\n\t\tDIRECTORY ${SHARE_DIRS}\n\t\tDESTINATION ${INSTALL_SHARE_DIR}\n\t\tCOMPONENT Share\n\t)\nendif ()\n"
  },
  {
    "path": "share/Doxygen/.gitignore",
    "content": "Doxyfile\n"
  },
  {
    "path": "share/Doxygen/CMakeLists.txt",
    "content": "\nset (DOC_DEST_DIR ${PROJECT_BINARY_DIR}/doc)\n\nif (BUILD_DOC)\n\tfind_package (Doxygen)\n\tif (DOXYGEN_FOUND)\n\n        if (BUILD_PYTHON)\n            set (DOXYGEN_GENERATE_XML \"YES\")\n            set (DOXYGEN_GENERATE_HTML \"NO\")\n        else()\n            set (DOXYGEN_GENERATE_XML \"NO\")\n            set (DOXYGEN_GENERATE_HTML \"YES\")\n        endif ()\n\n\t\tconfigure_file (Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)\n\t\tadd_custom_target(doc\n\t\t\t${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile\n\t\t\tDEPENDS Doxyfile.in\n\t\t\tCOMMENT \"Generating API documentation with Doxygen\"\n\t\t)\n\n\t\tadd_custom_command(\n\t\tOUTPUT ${DOC_DEST_DIR}\n\t\tCOMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile\n\t\tCOMMENT \"Generating API documentation with Doxygen\" VERBATIM\n\t\t)\n\n\t# add_custom_command(\n\t# TARGET ${DOC_DEST_DIR}\n\t# COMMAND ${DOXYGEN_EXECUTABLE} \n\t# ARGS ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile\n\t# )\n\n        if (BUILD_PYTHON)\n\t        install (\n\t\t        DIRECTORY ${DOC_DEST_DIR}\n\t\t        DESTINATION ${INSTALL_SHARE_DIR}\n\t\t        COMPONENT Share\n\t        )\n        endif ()\n\t\t\n\n\tendif (DOXYGEN_FOUND)\nendif (BUILD_DOC)\n"
  },
  {
    "path": "share/Doxygen/Doxyfile.in",
    "content": "# Doxyfile 1.3.9.1\r\n\r\n# This file describes the settings to be used by the documentation system\r\n# doxygen (www.doxygen.org) for a project\r\n#\r\n# All text after a hash (#) is considered a comment and will be ignored\r\n# The format is:\r\n#       TAG = value [value, ...]\r\n# For lists items can also be appended using:\r\n#       TAG += value [value, ...]\r\n# Values that contain spaces should be placed between quotes (\" \")\r\n\r\n#---------------------------------------------------------------------------\r\n# Project related configuration options\r\n#---------------------------------------------------------------------------\r\n\r\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded \r\n# by quotes) that should identify the project.\r\n\r\nPROJECT_NAME           =  @PROJECT_NAME@\r\n\r\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. \r\n# This could be handy for archiving the generated documentation or \r\n# if some version control system is used.\r\n\r\nPROJECT_NUMBER         = @VERSION_STRING@\r\n\r\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) \r\n# base path where the generated documentation will be put. \r\n# If a relative path is entered, it will be relative to the location \r\n# where doxygen was started. If left blank the current directory will be used.\r\n\r\nOUTPUT_DIRECTORY       = @DOC_DEST_DIR@\r\n\r\n# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create \r\n# 4096 sub-directories (in 2 levels) under the output directory of each output \r\n# format and will distribute the generated files over these directories. \r\n# Enabling this option can be useful when feeding doxygen a huge amount of source \r\n# files, where putting all generated files in the same directory would otherwise \r\n# cause performance problems for the file system.\r\n\r\nCREATE_SUBDIRS         = YES\r\n\r\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all \r\n# documentation generated by doxygen is written. Doxygen will use this \r\n# information to generate all constant output in the proper language. \r\n# The default language is English, other supported languages are: \r\n# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, \r\n# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, \r\n# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, \r\n# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, \r\n# Swedish, and Ukrainian.\r\n\r\nOUTPUT_LANGUAGE        = English\r\n\r\n# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will \r\n# include brief member descriptions after the members that are listed in \r\n# the file and class documentation (similar to JavaDoc). \r\n# Set to NO to disable this.\r\n\r\nBRIEF_MEMBER_DESC      = YES\r\n\r\n# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend \r\n# the brief description of a member or function before the detailed description. \r\n# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the \r\n# brief descriptions will be completely suppressed.\r\n\r\nREPEAT_BRIEF           = YES\r\n\r\n# This tag implements a quasi-intelligent brief description abbreviator \r\n# that is used to form the text in various listings. Each string \r\n# in this list, if found as the leading text of the brief description, will be \r\n# stripped from the text and the result after processing the whole list, is used \r\n# as the annotated text. Otherwise, the brief description is used as-is. If left \r\n# blank, the following values are used (\"$name\" is automatically replaced with the \r\n# name of the entity): \"The $name class\" \"The $name widget\" \"The $name file\" \r\n# \"is\" \"provides\" \"specifies\" \"contains\" \"represents\" \"a\" \"an\" \"the\"\r\n\r\nABBREVIATE_BRIEF       = \r\n\r\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then \r\n# Doxygen will generate a detailed section even if there is only a brief \r\n# description.\r\n\r\nALWAYS_DETAILED_SEC    = NO\r\n\r\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited \r\n# members of a class in the documentation of that class as if those members were \r\n# ordinary class members. Constructors, destructors and assignment operators of \r\n# the base classes will not be shown.\r\n\r\nINLINE_INHERITED_MEMB  = NO\r\n\r\n# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full \r\n# path before files name in the file list and in the header files. If set \r\n# to NO the shortest path that makes the file name unique will be used.\r\n\r\nFULL_PATH_NAMES        = YES\r\n\r\n# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag \r\n# can be used to strip a user-defined part of the path. Stripping is \r\n# only done if one of the specified strings matches the left-hand part of \r\n# the path. The tag can be used to show relative paths in the file list. \r\n# If left blank the directory from which doxygen is run is used as the \r\n# path to strip.\r\n\r\nSTRIP_FROM_PATH        = \r\n\r\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of \r\n# the path mentioned in the documentation of a class, which tells \r\n# the reader which header file to include in order to use a class. \r\n# If left blank only the name of the header file containing the class \r\n# definition is used. Otherwise one should specify the include paths that \r\n# are normally passed to the compiler using the -I flag.\r\n\r\nSTRIP_FROM_INC_PATH    = \r\n\r\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter \r\n# (but less readable) file names. This can be useful is your file systems \r\n# doesn't support long names like on DOS, Mac, or CD-ROM.\r\n\r\nSHORT_NAMES            = NO\r\n\r\n# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen \r\n# will interpret the first line (until the first dot) of a JavaDoc-style \r\n# comment as the brief description. If set to NO, the JavaDoc \r\n# comments will behave just like the Qt-style comments (thus requiring an \r\n# explicit @brief command for a brief description.\r\n\r\nJAVADOC_AUTOBRIEF      = NO\r\n\r\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen \r\n# treat a multi-line C++ special comment block (i.e. a block of //! or /// \r\n# comments) as a brief description. This used to be the default behaviour. \r\n# The new default is to treat a multi-line C++ comment block as a detailed \r\n# description. Set this tag to YES if you prefer the old behaviour instead.\r\n\r\nMULTILINE_CPP_IS_BRIEF = NO\r\n\r\n# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented \r\n# member inherits the documentation from any documented member that it \r\n# re-implements.\r\n\r\nINHERIT_DOCS           = YES\r\n\r\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC \r\n# tag is set to YES, then doxygen will reuse the documentation of the first \r\n# member in the group (if any) for the other members of the group. By default \r\n# all members of a group must be documented explicitly.\r\n\r\nDISTRIBUTE_GROUP_DOC   = NO\r\n\r\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. \r\n# Doxygen uses this value to replace tabs by spaces in code fragments.\r\n\r\nTAB_SIZE               = 4\r\n\r\n# This tag can be used to specify a number of aliases that acts \r\n# as commands in the documentation. An alias has the form \"name=value\". \r\n# For example adding \"sideeffect=\\par Side Effects:\\n\" will allow you to \r\n# put the command \\sideeffect (or @sideeffect) in the documentation, which \r\n# will result in a user-defined paragraph with heading \"Side Effects:\". \r\n# You can put \\n's in the value part of an alias to insert newlines.\r\n\r\nALIASES                = \r\n\r\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources \r\n# only. Doxygen will then generate output that is more tailored for C. \r\n# For instance, some of the names that are used will be different. The list \r\n# of all members will be omitted, etc.\r\n\r\nOPTIMIZE_OUTPUT_FOR_C  = NO\r\n\r\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources \r\n# only. Doxygen will then generate output that is more tailored for Java. \r\n# For instance, namespaces will be presented as packages, qualified scopes \r\n# will look different, etc.\r\n\r\nOPTIMIZE_OUTPUT_JAVA   = NO\r\n\r\n# Set the SUBGROUPING tag to YES (the default) to allow class member groups of \r\n# the same type (for instance a group of public functions) to be put as a \r\n# subgroup of that type (e.g. under the Public Functions section). Set it to \r\n# NO to prevent subgrouping. Alternatively, this can be done per class using \r\n# the \\nosubgrouping command.\r\n\r\nSUBGROUPING            = YES\r\n\r\n#---------------------------------------------------------------------------\r\n# Build related configuration options\r\n#---------------------------------------------------------------------------\r\n\r\n# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in \r\n# documentation are documented, even if no documentation was available. \r\n# Private class members and static file members will be hidden unless \r\n# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\r\n\r\nEXTRACT_ALL            = YES\r\n\r\n# If the EXTRACT_PRIVATE tag is set to YES all private members of a class \r\n# will be included in the documentation.\r\n\r\nEXTRACT_PRIVATE        = NO\r\n\r\n# If the EXTRACT_STATIC tag is set to YES all static members of a file \r\n# will be included in the documentation.\r\n\r\nEXTRACT_STATIC         = YES\r\n\r\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) \r\n# defined locally in source files will be included in the documentation. \r\n# If set to NO only classes defined in header files are included.\r\n\r\nEXTRACT_LOCAL_CLASSES  = NO\r\n\r\n# This flag is only useful for Objective-C code. When set to YES local \r\n# methods, which are defined in the implementation section but not in \r\n# the interface are included in the documentation. \r\n# If set to NO (the default) only methods in the interface are included.\r\n\r\nEXTRACT_LOCAL_METHODS  = NO\r\n\r\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all \r\n# undocumented members of documented classes, files or namespaces. \r\n# If set to NO (the default) these members will be included in the \r\n# various overviews, but no documentation section is generated. \r\n# This option has no effect if EXTRACT_ALL is enabled.\r\n\r\nHIDE_UNDOC_MEMBERS     = NO\r\n\r\n# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all \r\n# undocumented classes that are normally visible in the class hierarchy. \r\n# If set to NO (the default) these classes will be included in the various \r\n# overviews. This option has no effect if EXTRACT_ALL is enabled.\r\n\r\nHIDE_UNDOC_CLASSES     = NO\r\n\r\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all \r\n# friend (class|struct|union) declarations. \r\n# If set to NO (the default) these declarations will be included in the \r\n# documentation.\r\n\r\nHIDE_FRIEND_COMPOUNDS  = NO\r\n\r\n# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any \r\n# documentation blocks found inside the body of a function. \r\n# If set to NO (the default) these blocks will be appended to the \r\n# function's detailed documentation block.\r\n\r\nHIDE_IN_BODY_DOCS      = NO\r\n\r\n# The INTERNAL_DOCS tag determines if documentation \r\n# that is typed after a \\internal command is included. If the tag is set \r\n# to NO (the default) then the documentation will be excluded. \r\n# Set it to YES to include the internal documentation.\r\n\r\nINTERNAL_DOCS          = NO\r\n\r\n# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate \r\n# file names in lower-case letters. If set to YES upper-case letters are also \r\n# allowed. This is useful if you have classes or files whose names only differ \r\n# in case and if your file system supports case sensitive file names. Windows \r\n# and Mac users are advised to set this option to NO.\r\n\r\nCASE_SENSE_NAMES       = YES\r\n\r\n# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen \r\n# will show members with their full class and namespace scopes in the \r\n# documentation. If set to YES the scope will be hidden.\r\n\r\nHIDE_SCOPE_NAMES       = NO\r\n\r\n# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen \r\n# will put a list of the files that are included by a file in the documentation \r\n# of that file.\r\n\r\nSHOW_INCLUDE_FILES     = YES\r\n\r\n# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] \r\n# is inserted in the documentation for inline members.\r\n\r\nINLINE_INFO            = YES\r\n\r\n# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen \r\n# will sort the (detailed) documentation of file and class members \r\n# alphabetically by member name. If set to NO the members will appear in \r\n# declaration order.\r\n\r\nSORT_MEMBER_DOCS       = YES\r\n\r\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the \r\n# brief documentation of file, namespace and class members alphabetically \r\n# by member name. If set to NO (the default) the members will appear in \r\n# declaration order.\r\n\r\nSORT_BRIEF_DOCS        = NO\r\n\r\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be \r\n# sorted by fully-qualified names, including namespaces. If set to \r\n# NO (the default), the class list will be sorted only by class name, \r\n# not including the namespace part. \r\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\r\n# Note: This option applies only to the class list, not to the \r\n# alphabetical list.\r\n\r\nSORT_BY_SCOPE_NAME     = NO\r\n\r\n# The GENERATE_TODOLIST tag can be used to enable (YES) or \r\n# disable (NO) the todo list. This list is created by putting \\todo \r\n# commands in the documentation.\r\n\r\nGENERATE_TODOLIST      = YES\r\n\r\n# The GENERATE_TESTLIST tag can be used to enable (YES) or \r\n# disable (NO) the test list. This list is created by putting \\test \r\n# commands in the documentation.\r\n\r\nGENERATE_TESTLIST      = YES\r\n\r\n# The GENERATE_BUGLIST tag can be used to enable (YES) or \r\n# disable (NO) the bug list. This list is created by putting \\bug \r\n# commands in the documentation.\r\n\r\nGENERATE_BUGLIST       = YES\r\n\r\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or \r\n# disable (NO) the deprecated list. This list is created by putting \r\n# \\deprecated commands in the documentation.\r\n\r\nGENERATE_DEPRECATEDLIST= YES\r\n\r\n# The ENABLED_SECTIONS tag can be used to enable conditional \r\n# documentation sections, marked by \\if sectionname ... \\endif.\r\n\r\nENABLED_SECTIONS       = \r\n\r\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines \r\n# the initial value of a variable or define consists of for it to appear in \r\n# the documentation. If the initializer consists of more lines than specified \r\n# here it will be hidden. Use a value of 0 to hide initializers completely. \r\n# The appearance of the initializer of individual variables and defines in the \r\n# documentation can be controlled using \\showinitializer or \\hideinitializer \r\n# command in the documentation regardless of this setting.\r\n\r\nMAX_INITIALIZER_LINES  = 30\r\n\r\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated \r\n# at the bottom of the documentation of classes and structs. If set to YES the \r\n# list will mention the files that were used to generate the documentation.\r\n\r\nSHOW_USED_FILES        = YES\r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to warning and progress messages\r\n#---------------------------------------------------------------------------\r\n\r\n# The QUIET tag can be used to turn on/off the messages that are generated \r\n# by doxygen. Possible values are YES and NO. If left blank NO is used.\r\n\r\nQUIET                  = YES\r\n\r\n# The WARNINGS tag can be used to turn on/off the warning messages that are \r\n# generated by doxygen. Possible values are YES and NO. If left blank \r\n# NO is used.\r\n\r\nWARNINGS               = YES\r\n\r\n# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings \r\n# for undocumented members. If EXTRACT_ALL is set to YES then this flag will \r\n# automatically be disabled.\r\n\r\nWARN_IF_UNDOCUMENTED   = NO\r\n\r\n# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for \r\n# potential errors in the documentation, such as not documenting some \r\n# parameters in a documented function, or documenting parameters that \r\n# don't exist or using markup commands wrongly.\r\n\r\nWARN_IF_DOC_ERROR      = NO\r\n\r\n# The WARN_FORMAT tag determines the format of the warning messages that \r\n# doxygen can produce. The string should contain the $file, $line, and $text \r\n# tags, which will be replaced by the file and line number from which the \r\n# warning originated and the warning text.\r\n\r\nWARN_FORMAT            = \"$file:$line: $text\"\r\n\r\n# The WARN_LOGFILE tag can be used to specify a file to which warning \r\n# and error messages should be written. If left blank the output is written \r\n# to stderr.\r\n\r\nWARN_LOGFILE           = \r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to the input files\r\n#---------------------------------------------------------------------------\r\n\r\n# The INPUT tag can be used to specify the files and/or directories that contain \r\n# documented source files. You may enter file names like \"myfile.cpp\" or \r\n# directories like \"/usr/src/myproject\". Separate the files or directories \r\n# with spaces.\r\n\r\nINPUT = @CMAKE_CURRENT_SOURCE_DIR@/mainpage.dox \\\r\n\t\t@PROJECT_SOURCE_DIR@/include/vapor \\\r\n\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/VizWinMgr.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/TabManager.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/VizWin.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/EventRouter.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/BarbEventRouter.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/HelloEventRouter.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/MappingFrame.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/VariablesWidget.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/RenderHolder.h \\\r\n#\t\t@PROJECT_SOURCE_DIR@/apps/vaporgui/ErrorReporter.h\r\n\r\n# If the value of the INPUT tag contains directories, you can use the \r\n# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \r\n# and *.h) to filter out the source-files in the directories. If left \r\n# blank the following patterns are tested: \r\n# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp \r\n# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm\r\n\r\nFILE_PATTERNS          = *.h\r\n\r\n# The RECURSIVE tag can be used to turn specify whether or not subdirectories \r\n# should be searched for input files as well. Possible values are YES and NO. \r\n# If left blank NO is used.\r\n\r\nRECURSIVE              = NO\r\n\r\n# The EXCLUDE tag can be used to specify files and/or directories that should \r\n# excluded from the INPUT source files. This way you can easily exclude a \r\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\r\n\r\nEXCLUDE                = \r\n\r\n# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories \r\n# that are symbolic links (a Unix filesystem feature) are excluded from the input.\r\n\r\nEXCLUDE_SYMLINKS       = NO\r\n\r\n# If the value of the INPUT tag contains directories, you can use the \r\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude \r\n# certain files from those directories.\r\n\r\nEXCLUDE_PATTERNS       = \r\n\r\n# The EXAMPLE_PATH tag can be used to specify one or more files or \r\n# directories that contain example code fragments that are included (see \r\n# the \\include command).\r\n\r\nEXAMPLE_PATH           = \r\n\r\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the \r\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp \r\n# and *.h) to filter out the source-files in the directories. If left \r\n# blank all files are included.\r\n\r\nEXAMPLE_PATTERNS       = \r\n\r\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be \r\n# searched for input files to be used with the \\include or \\dontinclude \r\n# commands irrespective of the value of the RECURSIVE tag. \r\n# Possible values are YES and NO. If left blank NO is used.\r\n\r\nEXAMPLE_RECURSIVE      = NO\r\n\r\n# The IMAGE_PATH tag can be used to specify one or more files or \r\n# directories that contain image that are included in the documentation (see \r\n# the \\image command).\r\n\r\nIMAGE_PATH             = \r\n\r\n# The INPUT_FILTER tag can be used to specify a program that doxygen should \r\n# invoke to filter for each input file. Doxygen will invoke the filter program \r\n# by executing (via popen()) the command <filter> <input-file>, where <filter> \r\n# is the value of the INPUT_FILTER tag, and <input-file> is the name of an \r\n# input file. Doxygen will then use the output that the filter program writes \r\n# to standard output.  If FILTER_PATTERNS is specified, this tag will be \r\n# ignored.\r\n\r\nINPUT_FILTER           = \r\n\r\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern \r\n# basis.  Doxygen will compare the file name with each pattern and apply the \r\n# filter if there is a match.  The filters are a list of the form: \r\n# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further \r\n# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER \r\n# is applied to all files.\r\n\r\nFILTER_PATTERNS        = \r\n\r\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using \r\n# INPUT_FILTER) will be used to filter the input files when producing source \r\n# files to browse (i.e. when SOURCE_BROWSER is set to YES).\r\n\r\nFILTER_SOURCE_FILES    = NO\r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to source browsing\r\n#---------------------------------------------------------------------------\r\n\r\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will \r\n# be generated. Documented entities will be cross-referenced with these sources. \r\n# Note: To get rid of all source code in the generated output, make sure also \r\n# VERBATIM_HEADERS is set to NO.\r\n\r\nSOURCE_BROWSER         = YES\r\n\r\n# Setting the INLINE_SOURCES tag to YES will include the body \r\n# of functions and classes directly in the documentation.\r\n\r\nINLINE_SOURCES         = NO\r\n\r\n# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct \r\n# doxygen to hide any special comment blocks from generated source code \r\n# fragments. Normal C and C++ comments will always remain visible.\r\n\r\nSTRIP_CODE_COMMENTS    = YES\r\n\r\n# If the REFERENCED_BY_RELATION tag is set to YES (the default) \r\n# then for each documented function all documented \r\n# functions referencing it will be listed.\r\n\r\nREFERENCED_BY_RELATION = YES\r\n\r\n# If the REFERENCES_RELATION tag is set to YES (the default) \r\n# then for each documented function all documented entities \r\n# called/used by that function will be listed.\r\n\r\nREFERENCES_RELATION    = YES\r\n\r\n# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen \r\n# will generate a verbatim copy of the header file for each class for \r\n# which an include is specified. Set to NO to disable this.\r\n\r\nVERBATIM_HEADERS       = YES\r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to the alphabetical class index\r\n#---------------------------------------------------------------------------\r\n\r\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index \r\n# of all compounds will be generated. Enable this if the project \r\n# contains a lot of classes, structs, unions or interfaces.\r\n\r\nALPHABETICAL_INDEX     = YES\r\n\r\n# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then \r\n# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns \r\n# in which this list will be split (can be a number in the range [1..20])\r\n\r\nCOLS_IN_ALPHA_INDEX    = 3\r\n\r\n# In case all classes in a project start with a common prefix, all \r\n# classes will be put under the same header in the alphabetical index. \r\n# The IGNORE_PREFIX tag can be used to specify one or more prefixes that \r\n# should be ignored while generating the index headers.\r\n\r\nIGNORE_PREFIX          = \r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to the HTML output\r\n#---------------------------------------------------------------------------\r\n\r\n# If the GENERATE_HTML tag is set to YES (the default) Doxygen will \r\n# generate HTML output.\r\n\r\nGENERATE_HTML          = @DOXYGEN_GENERATE_HTML@\r\n\r\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. \r\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r\n# put in front of it. If left blank `html' will be used as the default path.\r\n\r\nHTML_OUTPUT            = html\r\n\r\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for \r\n# each generated HTML page (for example: .htm,.php,.asp). If it is left blank \r\n# doxygen will generate files with .html extension.\r\n\r\nHTML_FILE_EXTENSION    = .html\r\n\r\n# The HTML_HEADER tag can be used to specify a personal HTML header for \r\n# each generated HTML page. If it is left blank doxygen will generate a \r\n# standard header.\r\n\r\nHTML_HEADER            = \r\n\r\n# The HTML_FOOTER tag can be used to specify a personal HTML footer for \r\n# each generated HTML page. If it is left blank doxygen will generate a \r\n# standard footer.\r\n\r\nHTML_FOOTER            = \r\n\r\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading \r\n# style sheet that is used by each HTML page. It can be used to \r\n# fine-tune the look of the HTML output. If the tag is left blank doxygen \r\n# will generate a default style sheet. Note that doxygen will try to copy \r\n# the style sheet file to the HTML output directory, so don't put your own \r\n# stylesheet in the HTML output directory as well, or it will be erased!\r\n\r\nHTML_STYLESHEET        = \r\n\r\n# If the GENERATE_HTMLHELP tag is set to YES, additional index files \r\n# will be generated that can be used as input for tools like the \r\n# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) \r\n# of the generated HTML documentation.\r\n\r\nGENERATE_HTMLHELP      = NO\r\n\r\n# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can \r\n# be used to specify the file name of the resulting .chm file. You \r\n# can add a path in front of the file if the result should not be \r\n# written to the html output directory.\r\n\r\nCHM_FILE               = \r\n\r\n# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can \r\n# be used to specify the location (absolute path including file name) of \r\n# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run \r\n# the HTML help compiler on the generated index.hhp.\r\n\r\nHHC_LOCATION           = \r\n\r\n# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag \r\n# controls if a separate .chi index file is generated (YES) or that \r\n# it should be included in the master .chm file (NO).\r\n\r\nGENERATE_CHI           = NO\r\n\r\n# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag \r\n# controls whether a binary table of contents is generated (YES) or a \r\n# normal table of contents (NO) in the .chm file.\r\n\r\nBINARY_TOC             = NO\r\n\r\n# The TOC_EXPAND flag can be set to YES to add extra items for group members \r\n# to the contents of the HTML help documentation and to the tree view.\r\n\r\nTOC_EXPAND             = NO\r\n\r\n# The DISABLE_INDEX tag can be used to turn on/off the condensed index at \r\n# top of each HTML page. The value NO (the default) enables the index and \r\n# the value YES disables it.\r\n\r\nDISABLE_INDEX          = NO\r\n\r\n# This tag can be used to set the number of enum values (range [1..20]) \r\n# that doxygen will group on one line in the generated HTML documentation.\r\n\r\nENUM_VALUES_PER_LINE   = 4\r\n\r\n# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be\r\n# generated containing a tree-like index structure (just like the one that \r\n# is generated for HTML Help). For this to work a browser that supports \r\n# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, \r\n# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are \r\n# probably better off using the HTML help feature.\r\n\r\nGENERATE_TREEVIEW      = NO\r\n\r\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be \r\n# used to set the initial width (in pixels) of the frame in which the tree \r\n# is shown.\r\n\r\nTREEVIEW_WIDTH         = 250\r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to the LaTeX output\r\n#---------------------------------------------------------------------------\r\n\r\n# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will \r\n# generate Latex output.\r\n\r\nGENERATE_LATEX         = NO\r\n\r\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. \r\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r\n# put in front of it. If left blank `latex' will be used as the default path.\r\n\r\nLATEX_OUTPUT           = latex\r\n\r\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be \r\n# invoked. If left blank `latex' will be used as the default command name.\r\n\r\nLATEX_CMD_NAME         = latex\r\n\r\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to \r\n# generate index for LaTeX. If left blank `makeindex' will be used as the \r\n# default command name.\r\n\r\nMAKEINDEX_CMD_NAME     = makeindex\r\n\r\n# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact \r\n# LaTeX documents. This may be useful for small projects and may help to \r\n# save some trees in general.\r\n\r\nCOMPACT_LATEX          = NO\r\n\r\n# The PAPER_TYPE tag can be used to set the paper type that is used \r\n# by the printer. Possible values are: a4, a4wide, letter, legal and \r\n# executive. If left blank a4wide will be used.\r\n\r\nPAPER_TYPE             = a4wide\r\n\r\n# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX \r\n# packages that should be included in the LaTeX output.\r\n\r\nEXTRA_PACKAGES         = \r\n\r\n# The LATEX_HEADER tag can be used to specify a personal LaTeX header for \r\n# the generated latex document. The header should contain everything until \r\n# the first chapter. If it is left blank doxygen will generate a \r\n# standard header. Notice: only use this tag if you know what you are doing!\r\n\r\nLATEX_HEADER           = \r\n\r\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated \r\n# is prepared for conversion to pdf (using ps2pdf). The pdf file will \r\n# contain links (just like the HTML output) instead of page references \r\n# This makes the output suitable for online browsing using a pdf viewer.\r\n\r\nPDF_HYPERLINKS         = NO\r\n\r\n# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of \r\n# plain latex in the generated Makefile. Set this option to YES to get a \r\n# higher quality PDF documentation.\r\n\r\nUSE_PDFLATEX           = NO\r\n\r\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\\\batchmode. \r\n# command to the generated LaTeX files. This will instruct LaTeX to keep \r\n# running if errors occur, instead of asking the user for help. \r\n# This option is also used when generating formulas in HTML.\r\n\r\nLATEX_BATCHMODE        = NO\r\n\r\n# If LATEX_HIDE_INDICES is set to YES then doxygen will not \r\n# include the index chapters (such as File Index, Compound Index, etc.) \r\n# in the output.\r\n\r\nLATEX_HIDE_INDICES     = NO\r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to the RTF output\r\n#---------------------------------------------------------------------------\r\n\r\n# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output \r\n# The RTF output is optimized for Word 97 and may not look very pretty with \r\n# other RTF readers or editors.\r\n\r\nGENERATE_RTF           = NO\r\n\r\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. \r\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r\n# put in front of it. If left blank `rtf' will be used as the default path.\r\n\r\nRTF_OUTPUT             = rtf\r\n\r\n# If the COMPACT_RTF tag is set to YES Doxygen generates more compact \r\n# RTF documents. This may be useful for small projects and may help to \r\n# save some trees in general.\r\n\r\nCOMPACT_RTF            = NO\r\n\r\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated \r\n# will contain hyperlink fields. The RTF file will \r\n# contain links (just like the HTML output) instead of page references. \r\n# This makes the output suitable for online browsing using WORD or other \r\n# programs which support those fields. \r\n# Note: wordpad (write) and others do not support links.\r\n\r\nRTF_HYPERLINKS         = NO\r\n\r\n# Load stylesheet definitions from file. Syntax is similar to doxygen's \r\n# config file, i.e. a series of assignments. You only have to provide \r\n# replacements, missing definitions are set to their default value.\r\n\r\nRTF_STYLESHEET_FILE    = \r\n\r\n# Set optional variables used in the generation of an rtf document. \r\n# Syntax is similar to doxygen's config file.\r\n\r\nRTF_EXTENSIONS_FILE    = \r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to the man page output\r\n#---------------------------------------------------------------------------\r\n\r\n# If the GENERATE_MAN tag is set to YES (the default) Doxygen will \r\n# generate man pages\r\n\r\nGENERATE_MAN           = NO\r\n\r\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. \r\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r\n# put in front of it. If left blank `man' will be used as the default path.\r\n\r\nMAN_OUTPUT             = man\r\n\r\n# The MAN_EXTENSION tag determines the extension that is added to \r\n# the generated man pages (default is the subroutine's section .3)\r\n\r\nMAN_EXTENSION          = .3\r\n\r\n# If the MAN_LINKS tag is set to YES and Doxygen generates man output, \r\n# then it will generate one additional man file for each entity \r\n# documented in the real man page(s). These additional files \r\n# only source the real man page, but without them the man command \r\n# would be unable to find the correct page. The default is NO.\r\n\r\nMAN_LINKS              = NO\r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to the XML output\r\n#---------------------------------------------------------------------------\r\n\r\n# If the GENERATE_XML tag is set to YES Doxygen will \r\n# generate an XML file that captures the structure of \r\n# the code including all documentation.\r\n\r\nGENERATE_XML           = @DOXYGEN_GENERATE_XML@\r\n\r\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. \r\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be \r\n# put in front of it. If left blank `xml' will be used as the default path.\r\n\r\nXML_OUTPUT             = xml\r\n\r\n# If the XML_PROGRAMLISTING tag is set to YES Doxygen will \r\n# dump the program listings (including syntax highlighting \r\n# and cross-referencing information) to the XML output. Note that \r\n# enabling this will significantly increase the size of the XML output.\r\n\r\nXML_PROGRAMLISTING     = YES\r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options for the AutoGen Definitions output\r\n#---------------------------------------------------------------------------\r\n\r\n# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will \r\n# generate an AutoGen Definitions (see autogen.sf.net) file \r\n# that captures the structure of the code including all \r\n# documentation. Note that this feature is still experimental \r\n# and incomplete at the moment.\r\n\r\nGENERATE_AUTOGEN_DEF   = NO\r\n\r\n#---------------------------------------------------------------------------\r\n# configuration options related to the Perl module output\r\n#---------------------------------------------------------------------------\r\n\r\n# If the GENERATE_PERLMOD tag is set to YES Doxygen will \r\n# generate a Perl module file that captures the structure of \r\n# the code including all documentation. Note that this \r\n# feature is still experimental and incomplete at the \r\n# moment.\r\n\r\nGENERATE_PERLMOD       = NO\r\n\r\n# If the PERLMOD_LATEX tag is set to YES Doxygen will generate \r\n# the necessary Makefile rules, Perl scripts and LaTeX code to be able \r\n# to generate PDF and DVI output from the Perl module output.\r\n\r\nPERLMOD_LATEX          = NO\r\n\r\n# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be \r\n# nicely formatted so it can be parsed by a human reader.  This is useful \r\n# if you want to understand what is going on.  On the other hand, if this \r\n# tag is set to NO the size of the Perl module output will be much smaller \r\n# and Perl will parse it just the same.\r\n\r\nPERLMOD_PRETTY         = YES\r\n\r\n# The names of the make variables in the generated doxyrules.make file \r\n# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. \r\n# This is useful so different doxyrules.make files included by the same \r\n# Makefile don't overwrite each other's variables.\r\n\r\nPERLMOD_MAKEVAR_PREFIX = \r\n\r\n#---------------------------------------------------------------------------\r\n# Configuration options related to the preprocessor   \r\n#---------------------------------------------------------------------------\r\n\r\n# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will \r\n# evaluate all C-preprocessor directives found in the sources and include \r\n# files.\r\n\r\nENABLE_PREPROCESSING   = YES\r\n\r\n# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro \r\n# names in the source code. If set to NO (the default) only conditional \r\n# compilation will be performed. Macro expansion can be done in a controlled \r\n# way by setting EXPAND_ONLY_PREDEF to YES.\r\n\r\nMACRO_EXPANSION        = NO\r\n\r\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES \r\n# then the macro expansion is limited to the macros specified with the \r\n# PREDEFINED and EXPAND_AS_PREDEFINED tags.\r\n\r\nEXPAND_ONLY_PREDEF     = NO\r\n\r\n# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files \r\n# in the INCLUDE_PATH (see below) will be search if a #include is found.\r\n\r\nSEARCH_INCLUDES        = YES\r\n\r\n# The INCLUDE_PATH tag can be used to specify one or more directories that \r\n# contain include files that are not input files but should be processed by \r\n# the preprocessor.\r\n\r\nINCLUDE_PATH           = \r\n\r\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard \r\n# patterns (like *.h and *.hpp) to filter out the header-files in the \r\n# directories. If left blank, the patterns specified with FILE_PATTERNS will \r\n# be used.\r\n\r\nINCLUDE_FILE_PATTERNS  = \r\n\r\n# The PREDEFINED tag can be used to specify one or more macro names that \r\n# are defined before the preprocessor is started (similar to the -D option of \r\n# gcc). The argument of the tag is a list of macros of the form: name \r\n# or name=definition (no spaces). If the definition and the = are \r\n# omitted =1 is assumed. To prevent a macro definition from being \r\n# undefined via #undef or recursively expanded use the := operator \r\n# instead of the = operator.\r\n\r\nPREDEFINED             = DOXYGEN_SKIP_THIS \r\n\r\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then \r\n# this tag can be used to specify a list of macro names that should be expanded. \r\n# The macro definition that is found in the sources will be used. \r\n# Use the PREDEFINED tag if you want to use a different macro definition.\r\n\r\nEXPAND_AS_DEFINED      = \r\n\r\n# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then \r\n# doxygen's preprocessor will remove all function-like macros that are alone \r\n# on a line, have an all uppercase name, and do not end with a semicolon. Such \r\n# function macros are typically used for boiler-plate code, and will confuse the \r\n# parser if not removed.\r\n\r\nSKIP_FUNCTION_MACROS   = YES\r\n\r\n#---------------------------------------------------------------------------\r\n# Configuration::additions related to external references   \r\n#---------------------------------------------------------------------------\r\n\r\n# The TAGFILES option can be used to specify one or more tagfiles. \r\n# Optionally an initial location of the external documentation \r\n# can be added for each tagfile. The format of a tag file without \r\n# this location is as follows: \r\n#   TAGFILES = file1 file2 ... \r\n# Adding location for the tag files is done as follows: \r\n#   TAGFILES = file1=loc1 \"file2 = loc2\" ... \r\n# where \"loc1\" and \"loc2\" can be relative or absolute paths or \r\n# URLs. If a location is present for each tag, the installdox tool \r\n# does not have to be run to correct the links.\r\n# Note that each tag file must have a unique name\r\n# (where the name does NOT include the path)\r\n# If a tag file is not located in the directory in which doxygen \r\n# is run, you must also specify the path to the tagfile here.\r\n\r\nTAGFILES               = \r\n\r\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create \r\n# a tag file that is based on the input files it reads.\r\n\r\nGENERATE_TAGFILE       = \r\n\r\n# If the ALLEXTERNALS tag is set to YES all external classes will be listed \r\n# in the class index. If set to NO only the inherited external classes \r\n# will be listed.\r\n\r\nALLEXTERNALS           = NO\r\n\r\n# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed \r\n# in the modules index. If set to NO, only the current project's groups will \r\n# be listed.\r\n\r\nEXTERNAL_GROUPS        = YES\r\n\r\n# The PERL_PATH should be the absolute path and name of the perl script \r\n# interpreter (i.e. the result of `which perl').\r\n\r\nPERL_PATH              = /usr/bin/perl\r\n\r\n#---------------------------------------------------------------------------\r\n# Configuration options related to the dot tool   \r\n#---------------------------------------------------------------------------\r\n\r\n# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will \r\n# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or \r\n# super classes. Setting the tag to NO turns the diagrams off. Note that this \r\n# option is superseded by the HAVE_DOT option below. This is only a fallback. It is \r\n# recommended to install and use dot, since it yields more powerful graphs.\r\n\r\nCLASS_DIAGRAMS         = YES\r\n\r\n# If set to YES, the inheritance and collaboration graphs will hide \r\n# inheritance and usage relations if the target is undocumented \r\n# or is not a class.\r\n\r\nHIDE_UNDOC_RELATIONS   = YES\r\n\r\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is \r\n# available from the path. This tool is part of Graphviz, a graph visualization \r\n# toolkit from AT&T and Lucent Bell Labs. The other options in this section \r\n# have no effect if this option is set to NO (the default)\r\n\r\nHAVE_DOT               = NO\r\n\r\n# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen \r\n# will generate a graph for each documented class showing the direct and \r\n# indirect inheritance relations. Setting this tag to YES will force the \r\n# the CLASS_DIAGRAMS tag to NO.\r\n\r\nCLASS_GRAPH            = YES\r\n\r\n# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen \r\n# will generate a graph for each documented class showing the direct and \r\n# indirect implementation dependencies (inheritance, containment, and \r\n# class references variables) of the class with other documented classes.\r\n\r\nCOLLABORATION_GRAPH    = YES\r\n\r\n# If the UML_LOOK tag is set to YES doxygen will generate inheritance and \r\n# collaboration diagrams in a style similar to the OMG's Unified Modeling \r\n# Language.\r\n\r\nUML_LOOK               = NO\r\n\r\n# If set to YES, the inheritance and collaboration graphs will show the \r\n# relations between templates and their instances.\r\n\r\nTEMPLATE_RELATIONS     = YES\r\n\r\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT \r\n# tags are set to YES then doxygen will generate a graph for each documented \r\n# file showing the direct and indirect include dependencies of the file with \r\n# other documented files.\r\n\r\nINCLUDE_GRAPH          = YES\r\n\r\n# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and \r\n# HAVE_DOT tags are set to YES then doxygen will generate a graph for each \r\n# documented header file showing the documented files that directly or \r\n# indirectly include this file.\r\n\r\nINCLUDED_BY_GRAPH      = YES\r\n\r\n# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will \r\n# generate a call dependency graph for every global function or class method. \r\n# Note that enabling this option will significantly increase the time of a run. \r\n# So in most cases it will be better to enable call graphs for selected \r\n# functions only using the \\callgraph command.\r\n\r\nCALL_GRAPH             = NO\r\n\r\n# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen \r\n# will graphical hierarchy of all classes instead of a textual one.\r\n\r\nGRAPHICAL_HIERARCHY    = YES\r\n\r\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images \r\n# generated by dot. Possible values are png, jpg, or gif\r\n# If left blank png will be used.\r\n\r\nDOT_IMAGE_FORMAT       = png\r\n\r\n# The tag DOT_PATH can be used to specify the path where the dot tool can be \r\n# found. If left blank, it is assumed the dot tool can be found on the path.\r\n\r\nDOT_PATH               = \r\n\r\n# The DOTFILE_DIRS tag can be used to specify one or more directories that \r\n# contain dot files that are included in the documentation (see the \r\n# \\dotfile command).\r\n\r\nDOTFILE_DIRS           = \r\n\r\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the \r\n# graphs generated by dot. A depth value of 3 means that only nodes reachable \r\n# from the root by following a path via at most 3 edges will be shown. Nodes that \r\n# lay further from the root node will be omitted. Note that setting this option to \r\n# 1 or 2 may greatly reduce the computation time needed for large code bases. Also \r\n# note that a graph may be further truncated if the graph's image dimensions are \r\n# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). \r\n# If 0 is used for the depth value (the default), the graph is not depth-constrained.\r\n\r\nMAX_DOT_GRAPH_DEPTH    = 0\r\n\r\n# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will \r\n# generate a legend page explaining the meaning of the various boxes and \r\n# arrows in the dot generated graphs.\r\n\r\nGENERATE_LEGEND        = YES\r\n\r\n# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will \r\n# remove the intermediate dot files that are used to generate \r\n# the various graphs.\r\n\r\nDOT_CLEANUP            = YES\r\n\r\n#---------------------------------------------------------------------------\r\n# Configuration::additions related to the search engine   \r\n#---------------------------------------------------------------------------\r\n\r\n# The SEARCHENGINE tag specifies whether or not a search engine should be \r\n# used. If set to NO the values of all tags below this one will be ignored.\r\n\r\nSEARCHENGINE           = NO\r\n"
  },
  {
    "path": "share/Doxygen/TODO",
    "content": "Autogenerate config file to contain correct paths\n"
  },
  {
    "path": "share/Doxygen/mainpage.dox",
    "content": "//!\n//! \\mainpage The VAPOR project developer API\n//!\n//! Documentation for the VAPOR project's C++ API\n//!\n//! \\defgroup Public_Params VAPOR Params Developer API\n//! \\defgroup Public_Render VAPOR Render Developer API\n//! \\defgroup Public_VDC VAPOR VDC Developer API\n//! \\defgroup Public_GUI VAPOR GUI Developer API\n"
  },
  {
    "path": "share/doc/DCP_Format.md",
    "content": "# DCP Particle Data Format\n\n**D**ata **C**ollection **P**articles is a simple data format built upon NetCDF for importing particle data into VAPoR.\n\n## Dimensions\n\n### P\nP is on only required dimension. The size of the dimension P represents the number of particles at this timestep. If the number of particles varies between timesteps, every timestep must be in its own file since each NetCDF file can only define a single length for a dimension.\n\n### T\nT is the time dimension and it is required for time-varying data. It should be set to *unlimited*.\n### axis\nThis optional dimension is must have a length of 3 and it is used to pack 3 component values such as position or velocity into a single variable for convenience.\n\n## Variables\n\nThe only required variable is Position. Non-time-varying data should have a single dimension of `P`. If the data is time-varying, it should have the dimensions `(T, P)`. 3D particles will often have 3-component data associated with them, for example their velocity would have 3 components, one for each dimension. Since this is a common use case, variables can have 3 components per particle and this is done by setting the fastest-varying dimension to `axis` which as a size of 3. For an example, look at the position variable description below.\n\n### Position\n\nThis variable contains the position data for the particles. The data can be stored in either of the below methods:\n```\nfloat Position(T, P, axis) ;\n```\n```\nfloat Position_x(T, P) ;\nfloat Position_y(T, P) ;\nfloat Position_z(T, P) ;\n```\n\n\n## Examples\n\n### Python Script\n\n`vapor/share/examples/generateExampleDCP.py` shows how to generate a DCP dataset from a particle simulation. \n\n\n### Basic NetCDF File\n\nThis is an example of a NetCDF file containing 2 particles with time-varying position and particle speed data.\n\n```\nnetcdf particles_000 {\ndimensions:\n\tP = 2 ;\n\tT = UNLIMITED ; // (1 currently)\n\taxis = 3 ;\nvariables:\n\tdouble T(T) ;\n\t\tT:units = \"seconds\" ;\n\tfloat Position(T, P, axis) ;\n\tfloat speed(T, P) ;\ndata:\n\n T = 0 ;\n\n Position =\n  9.762701, 43.03787, 20.55268,\n  8.976637, -15.26904, 29.17882 ;\n\n speed =\n  26.02757, 18.87516 ;\n}\n```\n\n"
  },
  {
    "path": "share/doc/help/FieldLineAdvectionHelp.html",
    "content": "<html>\r\n<head>\r\n<title>Field Line Advection Setup</title>\r\n</head>\r\n<body>\r\n<font size=\"+2\">\r\n<h2 style=\"text-align: center;\">How to Set Up Field\r\nLine Advection</h2>\r\n<ol>\r\n  <li> Load a Metadata file (*.vdf file) into VAPOR.</li>\r\n  <li>In the Basic Flow Settings: \r\n    <ol>\r\n      <li>Specify \"Field Line Advection\" as the flow type </li>\r\n      <li>Specify three variables for the unsteady (e.g. velocity) field</li>\r\n      <li>Specify three variables for the steady (e.g. magnetic) field</li>\r\n      <li>Specify the \"Unsteady field scale factor\".&nbsp; (Normally with\r\nWRF datasets this factor is 1.) This\r\ndepends on the space and time scales that were used when the data was\r\ngenerated.&nbsp; It is the product:\r\n(spatial-correction-factor)*(time-correction-factor), where:</li>\r\n      <ul>\r\n        <li>(time-correction-factor) is the number of\r\nsimulation time units (e.g. seconds) per Vapor (.vdf) time step.  If the user times are correctly set in the metadata (vdf file) \r\nthen this factor should be 1.</li>\r\n\r\n        <li>(spatial-correction-factor) is the ratio\r\nof the full\r\ndomain size in VAPOR (see the VAPOR region panel) to the actual user\r\ndomain extent that was used in the simulation.  If the data extents in the \r\nmetadata (vdf file)\r\nare correctly set to the actual user coordinates then this factor should be 1.</li>\r\n      </ul>\r\n    </ol>\r\n    </li>\r\n  <li>Set up flow seeding as follows:</li>\r\n  <ol>\r\n    <li>Decide whether to use a random rake, nonrandom\r\nrake, or a\r\nlist of seeds, as the starting seed points for the field lines to be advected.</li>\r\n    <ul>\r\n      <li>If you are using a rake,&nbsp; the position\r\nand size of\r\nthe rake can be established by using sliders, typing in numerical\r\nvalues, or by using the rake tool in the visualizer window.</li>\r\n      <li>To use a list of seeds, either type it in\r\n(using the \"edit seed list\" button), or read the seeds from a text file, or\r\nspecify the seed points with the probe tool.&nbsp; Each\r\nseed in the list has (x,y,z)-coordinates, as well as a time.&nbsp; If\r\nthe time is negative, that seed point is valid for any time step;\r\notherwise it will only be used to seed the flow at the specified\r\ntime step.</li>\r\n    </ul>\r\n    <li>Under the \"Unsteady Flow Time Settings\",\r\nSpecify the one time step when the seed points are to be\r\ninjected into the flow, using the first of the three values labeled\r\n\"Seed time start, end, increment\".&nbsp; Only one time step is used\r\nfor seed injection.<br>\r\n      </li>\r\n    <ul>\r\n      <li>If the unsteady field data is not available at every\r\ntime step, you must specify the time steps that will be sampled, using\r\nthe &#8220;Unsteady Flow Time Settings.\"&nbsp; By default, every\r\ntime step is sampled from beginning to end, using values in &#8220;Time step\r\nsample start, end, increment\".&nbsp; Check the optional &#8220;Use time step\r\nlist\" to specify an arbitrary set of time steps that will be sampled.</li>\r\n    </ul>\r\n  </ol>\r\n</ol>\r\n<div style=\"text-align: center;\">\r\n<h2>Optional Settings to Consider</h2>\r\n</div>\r\n<br>\r\n<span style=\"font-weight: bold;\">Nonuniform random seed placement:</span><br>\r\n&nbsp;&nbsp;&nbsp; If you are using the &#8220;Random Rake\" for seed\r\nplacement, the distribution of random seeds can be biased by a field\r\nmagnitude in the &#8220;Flow Seeding Settings.\r\n\" &nbsp;&nbsp;&nbsp; As you increase the bias (above 0), the\r\nseeds are chosen at larger field magnitude values, approaching the\r\nmaximum field magnitude within the rake bounds.&nbsp; Bias values below\r\nzero result in seed points having field magnitude nearer\r\nzero.&nbsp; The three variables labeled &#8220;Seed Distrib. Field\" identify\r\nthe vector field whose magnitude is used to determine the seed\r\ndistribution.<br>\r\n&nbsp;<br>\r\n<span style=\"font-weight: bold;\">Seed Prioritization:</span><br>\r\n&nbsp;&nbsp;&nbsp; The field line advection algorithm\r\nmaximizes a field magnitude along each field line to determine\r\nthe points that will be advected to the next time step.&nbsp; The field\r\nthat is used for this prioritization is specified as the \"Seed Priority Field\".&nbsp; \r\nAlso, values labeled \"Priority Field Min, Max\" can be\r\nspecified.&nbsp;&nbsp; The search for the largest field value is\r\nterminated when field magnitude exceeds the value of &#8220;Priority Field Max\".  If the \r\npriority field magnitude at a point is less than its magnitude at the seed point\r\nmultiplied by the &#8220;Priority Field Min,\" then the search is terminated and\r\nthe field line is truncated at that point.\r\n<br>\r\nYou can choose whether the seed prioritization occurs before or after the time-advection.\r\nIf you select \"Prioritize before advection\", then the seed for a field line at the next time\r\nstep is chosen by maximizing the priority field along the field line at the current time step.\r\nIf you select \"Prioritize after advection\", then several points (their number is specified as \r\nthe No. of samples) along the field line at the\r\ncurrent time step are all advected to the next time step, and the seed to be used at the next\r\ntime step is selected by maximizing the priority field among the points that were advected to \r\nthe next time step.  The second approach, \"Prioritize after advection\" is useful when the seeds\r\nfrom the first approach exit the current region, resulting in early termination of the \r\nfield line advection.\r\n<br>\r\n<br>\r\n<span style=\"font-weight: bold;\">Color and opacity settings:</span><br>\r\n&nbsp;&nbsp;&nbsp; By default, path lines have a constant color and\r\nopacity.&nbsp;&nbsp; Using the Color/Opacity mapping, you can make the\r\ncolor and opacity depend on any of the following:<br>\r\n<br>\r\n<ol>\r\n  <ol>\r\n    <li>Position along Flow (This is a value between 0\r\nand 1 along\r\na steady field line indicating the integration position at that point\r\nrelative to the full integration) <br>\r\n      </li>\r\n    <li>Field Magnitude (The magnitude of the steady\r\nfield at the\r\nposition along the path line)</li>\r\n    <li>Seed Index.&nbsp; The seeds are numbered from 0\r\nto N-1\r\nwhere N is the number of different seed points.&nbsp; If this option is\r\nselected, each field line has color or opacity determined by its seed\r\npoint.</li>\r\n    <li>&nbsp;Variable.&nbsp; The color or opacity is a\r\nmapping of\r\nan arbitrary variable at the position of the point in the current VAPOR\r\ndata collection.</li>\r\n  </ol>\r\n</ol>\r\nWhen one of these mappings is selected, be sure to\r\nspecify the color\r\n(or opacity) map endpoints to include the range of values to be\r\nmapped.&nbsp; Then use the color editor or the opacity editor to\r\nspecify the color or opacity at specific points along that range.<br>\r\n<br>\r\n</font>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "share/doc/help/UnsteadyHelp.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\r\n<html>\r\n<head>\r\n  <meta content=\"text/html; charset=ISO-8859-1\"\r\n http-equiv=\"content-type\">\r\n  <title>Field Line Advection Setup</title>\r\n</head>\r\n<body>\r\n<div style=\"text-align: center;\">\r\n<h3 style=\"text-align: center;\"><font size=\"+2\">How to Set Up Unsteady\r\nFlow<br>\r\n</font></h3>\r\n</div>\r\n<ol>\r\n  <li><font size=\"+2\"> Load a Metadata file (*.vdf file) into VAPOR. </font></li>\r\n  <li><font size=\"+2\">In the Basic Flow Settings: </font>\r\n    <ol>\r\n      <li><font size=\"+2\">Specify \"Unsteady\" as the\r\nflow type </font></li>\r\n      <li><font size=\"+2\"> Specify three variables for the unsteady\r\n(e.g. velocity)\r\nfield</font></li>\r\n      <font size=\"+2\"> </font><li><font size=\"+2\">Specify the\r\n\"Unsteady Integration Direction\" as either \"Forward\" or\r\n\"Backward\".&nbsp; Seeds will be advected in the specified\r\ndirection by integrating the unsteady field either forwards or\r\nbackwards in time.<br>\r\n        </font></li>\r\n      <li><font size=\"+2\">Specify the \"Unsteady field scale\r\nfactor\".&nbsp; (Normally with WRF datasets this factor is 1.)  This\r\ndepends on the space and time scales that were used when the data was\r\ngenerated.&nbsp; It is the product:\r\n(spatial-correction-factor)*(time-correction-factor), where:</font></li>\r\n      <ul>\r\n        <li><font size=\"+2\">(time-correction-factor) is the number of\r\nsimulation time units (e.g. seconds) per vapor (.vdf) time step.  If\r\nthe user times are correctly specified in the metadata (vdf file) then this \r\nfactor should be 1.\r\n</font></li>\r\n        <li><font size=\"+2\">(spatial-correction-factor) is the ratio\r\nof the full\r\ndomain size in VAPOR (see the VAPOR region panel) to the actual user\r\ndomain extents that were used in the simulation.  If the data extents in\r\nthe metadata (vdf file)\r\nare correctly specified to the actual user coordinates, then this factor should be 1.</font></li>\r\n      </ul>\r\n    </ol>\r\n    <font size=\"+2\"> </font></li>\r\n  <li><font size=\"+2\">Set up flow seeding as follows:</font></li>\r\n  <ol>\r\n    <li><font size=\"+2\">Decide whether to use a random rake, nonrandom\r\nrake, or a\r\nlist of seeds, as the starting seeds for the field lines to be advected.</font></li>\r\n    <ul>\r\n      <li><font size=\"+2\">If you are using a rake,&nbsp; the position\r\nand size of\r\nthe rake can be established by using sliders, by typing in numerical\r\nvalues, or by using the rake tool in the visualizer window.</font></li>\r\n      <li><font size=\"+2\">To use a list of seeds, either type it in\r\n(using the\r\n\"edit seed list\" button), read the seeds from a text file,\r\nor insert them using the probe tool.&nbsp; Each\r\nseed in the list has (x,y,z)-coordinates, as well as a time.&nbsp; If\r\nthe time is negative, that seed point is valid for all seed time steps.</font></li>\r\n    </ul>\r\n    <li><font size=\"+2\">Under the \"Unsteady Flow Time Settings\", specify the time\r\nsteps when the seed points are to be\r\ninjected into the flow, using the three values labeled\r\n\"Seed time start, end, increment\".&nbsp; These determine an increasing\r\nsequence of integers evenly spaced in time, of the form: a, a+b,\r\na+2b,...,a+kb, where a is the \"Seed Time\r\nStart\", b is the \"increment\" and the largest injection time, a+kb, is\r\nno greater than the \"Seed Time End\".&nbsp; If the seeds are from a seed\r\nlist, and the seed time is nonnegative, then that seed is only injected\r\nat its specified time step.</font></li>\r\n    <li><font size=\"+2\">In the Unsteady Flow Time Settings:</font></li>\r\n    <ol>\r\n      <li><font size=\"+2\">Set the \"Unsteady\r\nsamples per time step\" to be the number of separate positions along a\r\npath line that will be displayed in the interval from one time step to\r\nthe next.<span style=\"\">&nbsp; </span>Increase this to get a smoother\r\npath line.</font></li>\r\n      <li class=\"MsoNormal\" style=\"\"><font size=\"+2\">&#8220;Display interval\r\nmin, max&#8221; determines the portion of each path that is displayed at a\r\ngiven time.<span style=\"\">&nbsp; </span>If T is the current time step\r\n(as specified in the Animation Panel), then the portion of the flow\r\nline from T+min to T+max will be displayed.<span style=\"\">&nbsp; </span>For\r\nexample:</font></li>\r\n      <ul>\r\n        <li><font size=\"+2\"><font size=\"+2\">&nbsp;To see the entire\r\npath\r\nline at once, make min\r\nvery negative and max very positive (e.g. -1000 and +1000).\r\n          </font></font></li>\r\n        <li><font size=\"+2\"><font size=\"+2\">To see the path line evolve\r\n(grow) over time, with the\r\nunsteady integration = forward, set min to be very negative (e.g. min =\r\n-1000)\r\nand set max = 0. The animation panel can\r\nlater be used to animate the path line evolution.</font></font></li>\r\n        <font size=\"+2\"><font size=\"+2\"> </font></font>\r\n      </ul>\r\n      <font size=\"+2\"><font size=\"+2\"> </font></font>\r\n    </ol>\r\n    <font size=\"+2\"><font size=\"+2\"> <li><font size=\"+2\">If the\r\nunsteady field data is not available at every\r\ntime step, you must specify the time steps that will be sampled, using\r\nthe \"Unsteady Flow Time Settings\".&nbsp; By default, every\r\ntime step is sampled from beginning to end, using values in \"Time step\r\nsample start, end, increment\".&nbsp; Check the optional \"Use time step\r\nlist\" to specify an arbitrary set of time steps that will be sampled.</font></li>\r\n    </font><br>\r\n</font>\r\n  </ol>\r\n  <div style=\"text-align: center;\">\r\n  <h3><big></big></h3>\r\n     </div>\r\n  <font size=\"+2\"><font size=\"+2\"><font size=\"+2\"><span\r\n style=\"font-weight: bold;\">Nonuniform random seed\r\nplacement:</span><br>\r\n&nbsp;&nbsp;&nbsp; If you are using the &#8220;Random Rake&#8221; for seed\r\nplacement, the distribution of random seeds can be biased by a field\r\nmagnitude using bias settings in the \"Flow Seeding Settings\".\r\n&nbsp;&nbsp; As you increase the bias (above 0), the\r\nseeds are chosen at larger field magnitude values, approaching the\r\nmaximum field magnitude within the rake bounds.&nbsp; Bias values below\r\nzero result in seeds to be distributed with field magnitudes nearer\r\nzero.&nbsp; The three variables labeled \"Seed Distrib. Field\" identify\r\nthe vector field whose magnitude is used to determine the seed\r\ndistribution.<br>\r\n&nbsp;<br>\r\n  <span style=\"font-weight: bold;\">Color and opacity settings</span><br>\r\n&nbsp;&nbsp;&nbsp; By default, path lines have a constant color and\r\nopacity.&nbsp;&nbsp; Using the Color/Opacity mapping, you can make the\r\ncolor and opacity depend on any of the following:<br>\r\n  </font>\r\n  </font></font>\r\n  <ol>\r\n    <font size=\"+2\"><font size=\"+2\"> </font></font>\r\n    <ol>\r\n      <font size=\"+2\"><font size=\"+2\"> </font></font>\r\n    </ol>\r\n  </ol>\r\n  <ul>\r\n    <font size=\"+2\"><font size=\"+2\"> <li><font size=\"+2\">Time Step<span\r\n style=\"font-family: &quot;times new roman&quot;;\"> </span></font><span\r\n style=\"font-size: 12pt; font-family: &quot;Times New Roman&quot;;\"><font\r\n size=\"+2\">(i.e. the specific time step associated\r\nwith a particle as it moves along the path line)</font> </span></li>\r\n    <li><font size=\"+2\">Field Magnitude (The magnitude of the unsteady\r\nfield at the\r\nposition along the path line)</font></li>\r\n    <li><font size=\"+2\">Seed Index.&nbsp; The seeds are numbered from 0\r\nto N-1\r\nwhere N is the number of different seed points.&nbsp; If this option is\r\nselected, each field line has color or opacity determined by its seed\r\npoint.</font></li>\r\n    <li><font size=\"+2\">&nbsp;Variable.&nbsp; The color or opacity is a\r\nmapping of\r\nan arbitrary variable at the position of the point in the current VAPOR\r\ndata collection.</font></li>\r\n    </font></font>\r\n  </ul>\r\n  <ol>\r\n    <font size=\"+2\"><font size=\"+2\"> </font></font>\r\n    <ol>\r\n      <font size=\"+2\"><font size=\"+2\"> </font></font>\r\n    </ol>\r\n  </ol>\r\n  <font size=\"+2\"><font size=\"+2\"><font size=\"+2\">When one of these\r\nmappings is selected, be sure to\r\nspecify the\r\ncolor\r\n(or opacity) map endpoints to include the range of values to be\r\nmapped.&nbsp; Then use the color editor or the opacity editor to\r\nspecify the color or opacity at specific points along that range.<br>\r\n  <br>\r\n  </font>\r\n  </font></font>\r\n</ol>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "share/doc/man/asciitf2vtf.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\nasciitf2vtf - Convert an ASCII description of a Lookup Transfer table\nto VAPOR's vtf format\n\n=head1 SYNOPSIS\n\nB<asciitf2vtf> [options] I<vtffile>\n\n=head1 DESCRIPTION\n\nB<asciitf2vtf> is a translator for converting an ASACII representation\nof a color and opacity transfer funciton into VAPOR's .vtf format. The\nresulting .vtf file may be loaded into a VAPOR session. The ASCII\ntransfer function files input into B<asciitf2vf> are whitespace-separted\nlists of n-tuples of floating point values. The first element of each\ntuple specifies the data value that the opacity or color will be mapped\nto. The domain of the first tuple element is the set of real numbers,\nbut most typically set to the user data domain.  The remaining tuple\nelements specify opacity or color values in the normalized range [0.0..1.0].\n\nThe translated file is written to the path specified by I<vtffile>.\n\n=head1 OPTIONS\n\n=over 4\n\n=item -cmap E<lt>cmap_fileE<gt>\n\nPath to an ASCII file containing a color transfer function\ndescription. Presently only the Hue-Saturation-Value (HSV) color model\nis supported: each tuple is of the form (D, H, S, V), where I<D> is the\ndata value, I<H> is the normalized hue, I<S> is normalized color saturation,\nand I<V> is normalized color value.\n\n=item -omap E<lt>omap_fileE<gt>\n\nPath to an ASCII file containing an opacity transfer function description.\nEach tuple is of the form (D, O), where I<D> is the data value and I<O>\nis the normalized opacity: a value of 0.0 is fully transparent, and a\nvalue of 1.0 is fully opaque.\n\n=item -help \n\nPrint a help message and then exit.\n\n=back\n\n=head1 EXAMPLES\n\nTo create a linear opacity ramp with a fully transparent opacity at\nthe data value 0.0 and a fully opaque opacity at the data value 100.0,\nan ASCII opacity transfer function file named \"opacity.txt\" would contain:\n\n=over 4\n\n0.0 0.0\n\n100.0 1.0\n\n=back\n\nTo convert B<opacity.txt> to a .vtf file named \"map.vtf\", the following invocation would be used:\n\n=over 4\n\nasciitf2vtf -omap opacity.txt map.vtf\n\n=back\n\nIf in addition to an opacity transfer function a color transfer function\nis to be included that linearly ramps the Hue from 0 to 360 degrees,\nand has constant, full saturation and value, an ASCII transfer function\nfile named \"color.txt\" would contain:\n\n=over 4\n\n0.0 0.0 1.0 1.0\n\n100.0 1.0 1.0 1.0\n\n=back\n\nNote that all HSV elements are normalized.  The following invocation would be used to convert both opacity and color transfer function files:\n\n=over 4\n\nasciitf2vtf -cmap color.txt -omap opacity.txt map.vtf\n\n=back\n\n\n=head1 SEE ALSO\n\n=head1 NOTES\n\n=head1 HISTORY\n\nLast updated on $Date$\n"
  },
  {
    "path": "share/doc/man/getWMSImage.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\ngetWMSImage.sh - Retrieve maps and imagery from a Web Mapping Server\n\n=head1 SYNOPSIS\n\nB<getWMSImage.sh> [options] I<minLon minLat maxLon maxLat>\n\n=head1 DESCRIPTION\n\n\nB<getWMSImage.sh> is a bash-shell script for retrieving maps and imagery from \nan OGC-compliant Web Mapping Server (WMS). It operates in two modes: default mode\nand expert mode. The default mode is intended to help most users acquire typical base-map\nimages, choosing from a small set of predefined map types. The existing map types include\nNASA Blue Marble and Landsat imagery, maps of political boundaries, rivers, etc. \n\nExpert mode can be used to extract arbitrary imagery from any OGC-compliant server. It is \nintended only for users who are highly knowledgeable about WMS protocol and servers. In general, \nthis requires knowing how to acquire and interpret the so-called \"GetCapabilities\" document for\na server, and using the information to determine the \"GetMap\" URL, the map layers that are \navailable, and the image formats that are supported. Consult the WMS specifications for details\n(http://www.opengeospatial.org/standards/wms).\n\nIn either mode, the bounding box of the area of interest must be specified through the \nI<minLon minLat maxLon maxLat> parameters. These are given in decimal-degrees, and must be\nin the range og [-180..180] for longitudinal values, and [-90..90] for latitudes. To specify\na region encompassing one of the poles, use -180 and 180 for I<minLon, maxLon>, and either -90\nas I<minLat> for the south pole, or 90 as I<maxLat> for the north pole.\n\nBy default, if the script is run without options, an image of NASA's Blue Marble Next-Generation imagery\nis downloaded for the area of interest, at a resolution of 1025x768 pixels, and placed in a file\nnamed BMNG.tiff. A number of options can be used in both modes to override this behavior.\n\n=head1 OPTIONS\n\n=head2 Default Mode Options\n\n=over 4\n\n=item -m I<map_name>\n\nSpecifies which of the predetermined map-types to download. Must be one of:\n\n    BMNG        : Blue Marble Next-Generation; the default\n    landsat     : Landsat imagery\n    USstates    : US state boundaries\n    UScounties  : US state and county boundaries\n    world       : World political boundaries\n    rivers      : major world rivers (scale-dependent)\n\nUse of this option overrides expert options.\n\n=item -r I<xres yres>\n\nSpecify the pixel resolution of the requested image/map. The default is 1024x768.\n\n=item -o I<outImageFile>\n\nSpecify the name for the request image/map file. By default, it is I<map_name>.tiff.\n\n=item -t\n\nRequest that the image background should be transparent. This may or may not be \nhonored by a given WMS. Note that foreground colors are determined by the server.\n\n=back \n\n=head2 Expert Mode Options\n\nExpert mode operates in lieu of the B<-m map_name> option of default mode, where the server URL, \nimage layer name(s), and image format must be explictly specified. \n\n=over 4\n\n=item -s I<WMS_URL>\n\nSpecifies the URL for the desired WMS \"GetMap\" request.\n\n=item -l I<layer_name>\n\nSpecifies the layer name (or comma-separated names) of the map/image feature(s) to be retrieved.\n\n=item -f I<image_format>\n\nSpecifies the format for the requested image, as advertised by the WMS server.\n\n=item -r I<xres yres>\n\nSpecify the pixel resolution of the requested image/map. The default is 1024x768.\n\n=item -o I<outImageFile>\n\nSpecify the name for the request image/map file. By default, it is I<layer_name>.tiff.\n\n=item -t\n\nRequest that the image background should be transparent. This may or may not be \nhonored by a given WMS. Note that foreground colors are determined by the server.\n\n=item -z\n\nRequest that the resultant image file is compressed (not supported on all platforms).\n\n=item -d\n\nDebug mode; does not delete intermediate files.\n\n=back\n\n=head1 EXAMPLES\n\n\nC<getWMSImage.sh -m world 0 0 90 90>\n\nwill return an image file named I<world.tiff> that is a Blue Marble image of Europe, part of Eurasia, and\nthe north pole.\n\nC<getWMSImage.sh -m UScounties -o westernUS.tiff -r 500 500 -125 25 -100 50>\n\nwill return an image file named I<westernUS.tiff> that depicts state and county boundaries \nof the western half of the United States.\n\n=head1 HISTORY\n\nLast updated on $Date$\n\n"
  },
  {
    "path": "share/doc/man/ptcl2vms.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\nptcl2vms - Transform lists of points into vms model files\n\n=head1 SYNOPSIS\n\nB<ptcl2vms> [options] I<point_files...> I<vmsfile> \n\n=head1 DESCRIPTION\n\nB<ptcl2vms> reads newline-delimited 3D points from text files, where\ncoordinates are delimited with spaces, and stores a sequence of sphere\nmodels in I<vmsfile>. The file I<vmsfile> will be created if it doesn't\nalready exist. Each sphere in the output represents a single point from\nthe inputs. Each input file is placed in its own timestep of the output\nvms.\n\n=head1 OPTIONS\n\n=over 4\n\n=item -radius E<lt>sizeE<gt>\n\nRadius of spheres to produce (default 0.5)\n\n=item -ref E<lt>numberE<gt>\n\nSpecify the number of refinement passes to do on sphere models (default 0)\n\n=item -startts E<lt>tsE<gt>\n\nInteger offset of first time step to produce in vms file. (default 0)\n\n=item -stride E<lt>countE<gt>\n\nRead one in every E<lt>countE<gt> points from the input files. (default 1)\n\n=item -help \n\nPrint a usage statement and then exit.\n\n=item -quiet \n\nOperate quietly, only reporting fatal errors.\n\n=back\n\n=head1 EXAMPLES\n\nptcl2vms -help\n\nptcl2vms -radius 300 -ref 2 ts0points ts1points ts2points points.vms\n\nptcl2vms -startts 1 -radius 300 -ref 2 ts1points ts2points points.vms\n\nptcl2vms -stride 3 ts0points ts2points ts3points ts4points points.vms\n\nptcl2vms -quiet -startts 1 -radius 300 -ref 2 -stride 3 ts1points points.vms\n\n=head1 SEE ALSO\n\nI<Generation of model files which are sequences of points>\n\n=head1 HISTORY\n\nLast updated on $Date$\n"
  },
  {
    "path": "share/doc/man/raw2wasp.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\nraw2wasp - Transform and write a raw data volume into a NetCDF WASP file.\n\n=head1 SYNOPSIS\n\nB<raw2wasp> [options] I<waspfile> I<datafile>\n\n=head1 DESCRIPTION\n\nB<raw2wasp> reads a 3D or 2D volume of data from disk, wavelet transforms\nthe data, and stores it in file I<waspfile>.\nThe data volume must be stored on disk as a contiguous array of\nunformatted binary floating point values (32bit precision by default)\nwith no header or trailer information. The dimensions of the raw data\nvolume must match those specified in I<waspfile>. The file indicated by\nI<waspfile> must be a valid WASP file created, for example, by the \nB<waspcreate> command.\n\n=head1 OPTIONS\n\n=over 4\n\n=item -debug\n\nEnable diagnostics.\n\n=item -varname E<lt>nameE<gt>\n\nThis option specifies name of the variable that the raw data volume \ncorresponds too. The name must match either a 2D or 3D variable name\nin the WASP indicated by I<waspfile>. If I<name> matches a 2D variable, \na 2D slice of data expected to be contained in I<datafile>. If I<name> \nmatches a 3D variable, B<raw2wasp>\nwill attempt to read a 3D data volume from I<datafile>. The dimensions of\nthe volume/slice contained in I<datafile> must match those of the\ncorresponding variable defined in I<waspfile>.\n\n=item -type E<lt>typeE<gt>\n\nPrimitive data type of the data stored in I<datafile>. Supported values\nare 'float32', 'float64', and 'int32'.\n\n=item -lod E<lt>nE<gt>\n\nCompressed variables are stored with a finite number of fixed refinement\nlevels determined by the number of compression ratios specified in the \nI<waspfile> file. By default all refinement levels are output. This \noption can be used to reduce the refinement levels output. \nA value 0 implies coarsest, 1 => next refinement, and so on. The value -1\nis synonymous with the highest refinement level available.\n\n=item -nthreads E<lt>nE<gt>\n\nThis option can be used to specify the number of execution threads to be\nemployed when transforming data. The default value of I<n> is 0, which\ncauses the application to query the operating system to find the number\nof processors available, and then use that value. For most platforms\nthe number of processors available is the result of the system call,\nsysconf(_SC_NPROCESSORS_ONLN).\n\n=back\n\n=head1 EXAMPLES\n\nThe command \n\nC<waspcreate -dimlens 256:256:256 -dimnames Nz:Ny:Nx vx:NC_FLOAT:3:Nz:Ny:Nx>\n\nfollowed by \n\nC<raw2wasp -varname vx test.nc vx.float>\n\nwould transform the volume stored in the file B<vx.float> and write it into \nthe WASP file associated with the B<test.nc> file. This assumes that\nthe array stored in file B<vx.float> has dimensions 256x256x256 and the\nelements are stored as 32-bit floats.\n\n=head1 SEE ALSO\n\nwaspcreate, wasp2raw\n\n=head1 HISTORY\n\nLast updated on $Date$\n\n"
  },
  {
    "path": "share/doc/man/tiff2geotiff.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\ntiff2geotiff - Insert georeferencing and dates into a tiff file\n\n=head1 SYNOPSIS\n\nB<tiff2geotiff> [options] I<inputFile> I<outputFile>\n\n=head1 DESCRIPTION\n\nB<tiff2geotiff> reads a tiff file and converts it to a geotiff\n(georeferenced tiff) file.  B<tiff2geotiff> can insert geo-referencing\nas well as date/time stamps into the input file.  The geo-referencing and\ndate information can be specified for a single image, or for a sequence of images\nin a multi-directory tiff file.\n\nB<tiff2geotiff> is modified from the geo-tiff application geotifcp, and it supports\nmany options of that program.  Type \"tiff2geotiff -h\" to see all the \navailable command-line options. Below are listed all the options needed for \ndoing the tiff to geotiff conversion needed by VAPOR.    \n\n=head1 OPTIONS\n\n=over 4\n\n=item -4 E<lt>\"proj string\"E<gt>\n\nThis option specifies a map projection using a PROJ4 projection string.  This\nstring must be enclosed in quotes, and consists of several keyword/value pairs \nof the form \"+key=value\".  The full set of PROJ4 key/value pairs can be found at the \nPROJ4 wiki http://trac.osgeo.org/proj/wiki . For example, a longitude/latitude projection on\na spherical earth is specified as \"+proj=latlong +ellps=sphere\".  B<tiff2geotiff> \nsupports Lambert conformal conic, Mercator, Longitude/Latitude, and polar stereographic projections.\n\n=item -m E<lt>date/time-position_filenameE<gt> \n\nThis option requires option -4 above.\nThis option specifies a file that contains georeferencing information and date/time stamps\nfor each of the directories in the tiff file.  Each line of the file B<date/time-position_filename> is of the form:\n\n\tDate/Time llx lly urx ury pllx plly purx pury\n \nWhere: \n\n \tDate/Time \n\nis a WRF-style date/time stamp in the form yyyy-mm-dd_hh:mm:ss  \n\n \tllx lly urx ury \n\nare the longitude (x) and latitude (y) of the lower-left and \nupper-right corners of the plot area in the image.  This supports georeferencing of images that consist of a plot area surrounded by additional annotation, enabling the latitude and longitude of the plot area to be specified.  \n\n \tpllx plly purx pury \n\nare the relative positions of the plot area corners in the full page, \nand are values between 0.0 and 1.0 .  The georeferencing is such that the \nplot area will fit exactly at the specified latitude and longitude; \nhowever the image will extend further than the plot area if pllx, plly, purx, and pury are not 0.0, 0.0, 1.0, and 1.0 respectively. \n\n\n=item -M E<lt>date/time_filenameE<gt> \n\nThis option specifies a file that contains a date/time stamp for each\ndirectory in the tiff file.  The option \"-4\" must not be specified. \nEach line of the file B<date/time_filename> is a WRF-style date time stamp of the form: \n\n\tyyyy-mm-dd_hh:mm:ss\n\n=item -n E<lt>\"llx lly urx ury\"E<gt>\n\nThis option requires four values in quotes.  This specifies the same latitude and longitude extents for all directories in the file.\nOption -4 must be specified.  This option is ignored if option -m is specified.\n\n=item -c compressOption\n\nThis option (inherited from geotifcp) is useful in controlling the compression of the resulting geotiff file.  \nUseful values of B<compressOption>, for use with VAPOR, include:\n\n\tnone\twill result in no compression in the output file\n\tlzw\twill result in Lempel-Ziv & Welch encoding\n\n=item -h \n\nPrint a usage statement and then exit.\n\n=back\n\n=head1 EXAMPLES\n\nThe command \n\nC<tiff2geotiff -4 \"+proj=latlong +ellps=sphere\" -n \"0 -60 90 -30\" infile.tif outfile.gtif>\n\nwill produce an output geotiff file outfile.gtif that will have the same images as infile.tif, but will in addition be geo-referenced to use a long/lat map projection, and will\nmap the images to the rectangle with lon/lat corners at (0,-60) and (90,-30).\n\nC<tiff2geotiff -4 \"+proj=lcc +lon_0=-30 +lat_1=40 +lat2=60 +ellps=sphere\" -m datetimecoordfile.txt infile.tif outfile.gtif>\n\nwill produce an output geotiff file outfile.gtif that will contain the same image or images as infile.tif, \nbut will in addition be geo-referenced to use a Lambert conformal conic map projection.  \nThe Lambert projection will be centered at longitude -30, with the projection being true at latitudes 40 and 60. \nThe resulting geotiff image will have date/time stamps and lon/lat extents as specified in the file datetimecoordfile.txt.  \nThe file datetimecoordfile.txt must have one line for each image in the tiff file, and each line must consist of a date/time stamp followed by 8 floating point values as in the following:\n\n\t2009-07-21_13:30:00 -100 30 -50 50 0.1 0.1 0.9 0.9\n\nIn the above line the first value is a date/time stamp.  The next four values indicate that the longitude of the plot area of the image goes from -100 to -50 and the latitude goes from 30 to 50.\nThe last four values indicate that the actual image is larger than the plot area, with the plot area going from 10% inside the lower-left corner of the image to 10% inside the upper-right corner.\n\n=head1 SEE ALSO\n\nThe PROJ4 wiki http://trac.osgeo.org/proj/wiki\n\n=head1 HISTORY\n\nLast updated on $Date$\n\n"
  },
  {
    "path": "share/doc/man/vdccp.py.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\nvdccp.py - Copies a user defined portion of a vdc database.\n\n=head1 SYNOPSIS\n\nB<vdfcp.pl> [options] I<srcvdf> I<destination>\nB<vdfcp.pl> -list I<srcvdf>\nB<vdfcp.pl> -info I<srcvdf>\n\nB<vdccp.py> [-h] [-v VAR] [-x EXCLUDE] [-s START_FRAME] [-e END_FRAME] [-d FRAME_COUNT] [-c COMPRESSION] [-f] [-n] [--coord-start-frame COORD_START_FRAME] [--coord-end-frame COORD_END_FRAME] [--info] [--info-var INFO_VAR] [--version] -I<source> [-I<destination>]\n\n=head1 DESCRIPTION\n\nB<vdfcp.pl> copies I<srcvdf>, or part of I<srcvdf>, to I<destination>. The first\nform does this. The second form is used to obtain a list of the files that\nwould be copied if the first form were used on I<srcvdf>. The third form prints\na human-readable message detailing the available ranges of timesteps, variables\nand refinement available in I<srcvdf>.\n\nB<vdccp.py> copies a user defined portion of a VDC database, -I<source>, to I<destination>. With no options set, the entire database is copied. If a variable is chosen with -v, only those chosen are copied. All coordinates are copied unless excluded with -x. This utility can also show information about the database or a specific variable/coordinate by passing the option --info and --info-var respectively.\n\n=head1 OPTIONS\n\n=over 4\n\n=item -v, --var\n\nVariable(s) to be copied. All coordinates selected by default and can be removed with -x. Multiple can be grouped together if colon separated. If none specified, all variables selected.\n\n=item -x, --exclude\n\nVariable(s) or coordinate(s) to be excluded. Multiple can be grouped together if colon separated. Overrides any variables added with -v.\n\n=item -s, --start-frame\n\nStart frame. Default first frame. (Frames do not correspond directly to time steps. A single frame can contain multiple time steps.\n\n=item -e, --end-frame\n\nEnd frame. Default last frame. Overrides -d. If neither -e or -d is specified, the entire data set after the start is copied.\n\n=item -d, --frame-count\n\nNumber of time frames from Start to copy. Overridden by -e.\n\n=item -c, --compression\n\nCompression level to copy. Default maximum detail.\n\n=item -f, --force\n\nOverwrites existing data if necessary.\n\n=item -n, --dry-run\n\nShow what would have been transferred.\n\n=item --coord-start-frame\n\nStart frame for coordinates. All coordinate frames copied by default. -s does not affect coordinate frames.\n\n=item --coord-end-frame\n\nEnd frame for coordinates. All coordinate frames copied by default. -s does not affect coordinate frames.\n\n=item --info\n\nPrints available variables, coordinates, compression levels, and maximum/minimum timesteps for data set and exits.\n\n=item --info-var\n\nPrints available variables, coordinates, compression levels, and maximum/minimum timesteps for a specific variable and exits.\n\n=item --version\n\nPrints version number and exits\n\n=item -h, --help\n\nShows usage and description and exits.\n\n=back\n\n=head1 EXAMPLES\n\n\nThe command...\n\nC<vdccp.py -v P:T -c 2 -s 10 -d 20 path/to/source.vdc path/to/dest>\n\n...will copy source.vdc and its associated dataset to the path/to/data directory.  Only the variables P and T will be copied, only levels 0, 1 and 2, and timesteps 10 through 30 will be copied to the new dataset.\n\n\nThis command...\n\nC<vdccp.py --info --info-var bx --info-var bz path/to/source.vdf>\n\n...will show the range of levels in source.vdf's dataset, as well as all timesteps, variables and coordinates. It will also list information specific to the variables bx and bz.\n\n=head1 SEE ALSO\n\nvdfcreate, wrf2vdf, \n\nI<Copy a VDC to a new location>\n\n=head1 HISTORY\n\nLast updated on $Date$\n\n"
  },
  {
    "path": "share/doc/man/vdcdump.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\nvdcdump - Outputs information about a VDC Database\n\n=head1 SYNOPSIS\n\nB<vdcdump> [options] I<source.nc> \n\nB<vdcdump> [-h] [-v] [-nc-order] -I<source.nc>\n\n=head1 DESCRIPTION\n\nB<vdcdump> prints information about data stored in a VDC database, I<source.nc>. By default, \nit prints coordinates, dimensions, and user-defined attributes. Additional information pertaining \nto the VDC data format can be outputted with the -v verbose option.\n\n=head1 OPTIONS\n\n=over 4\n\n=item -v\n\nVerbose output. Prints additional information specific to the VDC data format.\n\n=item -nc-order\n\nReverses order of dimensions to match that of the NetCDF format (slowest to fastest varying). \nBy default, dimensions are ordered from fastest to slowest varying.\n\n\n=head1 EXAMPLES\n\n\nC<vdcdump path/to/source.nc>\n\n\n=head1 SEE ALSO\n\n\nI<Output information >\n\n=head1 HISTORY\n\nLast updated on $Date$\n\n"
  },
  {
    "path": "share/doc/man/wasp2raw.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\nwasp2raw - Inverse transform a variable found in a NetCDF WASP file and store\nthe results in output file as a raw binary array.\n\n=head1 SYNOPSIS\n\nB<wasp2raw> [options] I<waspfile> I<datafile>\n\n=head1 DESCRIPTION\n\nB<wasp2raw> extracts a variable from the \nWASP file I<waspfile>, decompresses the variable (if compressed),\nand stores the results in the file indicated by I<datafile>.\nThe data are written as a contiguous array of unformatted binary\nfloating point values. The X dimension varies fastest, followed by Y, then Z.\nData are written at 32 bit precision in the native format of the \nmachine where B<wasp2raw> is run.\n\n=head1 OPTIONS\n\n=over 4\n\n=item -varname E<lt>nameE<gt>\n\nThis option specifies name of the variable to extract. \n\n=item -lod E<lt>nE<gt>\n\nCompressed variables are stored with a finite number of fixed refinement\nlevels determined by the number of compression ratios specified in the\nI<waspfile> file. By default the maximum refinement level is output. This\noption can be used to reduce the refinement level output.\nA value 0 implies coarsest, 1 => next refinement, and so on. The value -1\nis synonymous with the highest refinement level available.\n\n=item -level E<lt>levelE<gt>\n\nCompressed variables in a WASP file are represented by a multiresolution\nhierarchy. This option specifies which level in the hierarchy to\nextract the variable from. A value of 0, the default, indicates the\ncoarsest level in hierarchy. A value of 1 implies the first refinement\nlevel, and so on. The special value, -1, is synonymous with the\nnative data resolution, whatever level that may be.\n\n\n=item -nthreads E<lt>nE<gt>\n\nThis option can be used to specify the number of execution threads to be\nemployed when transforming data. The default value of I<n> is 0, which\ncauses the application to query the operating system to find the number\nof processors available, and then use that value. For most platformsthe number of processors available is the result of the system call,\nsysconf(_SC_NPROCESSORS_ONLN).\n\n=item -start E<lt>startE<gt>\n\nA colon-delimited NetCDF style I<start> coordinate vector used to select\nan offset into the array. This option together with the I<-count> option\ncan be used to restrict output to a rectangular subset of the array.\n\n=item -count E<lt>countE<gt>\n\nA colon-delimited NetCDF style I<count> coordinate vector used to\nspecify dimensions of a subset of the array to output. This option\ntogether with the I<-count> option can be used to restrict output\nto a rectangular subset of the array.\n\n=item -type E<lt>typeE<gt>\n\nPrimitive data type of the data to be output to I<datafile>. Supported values\nare 'float32', 'float64', and 'int32'.\n\n=back\n\n=head1 EXAMPLES\n\nThe command \n\nC<wasp2raw -varname vx test.nc vx.float>\n\nwould reconstruct the variable with name B<vx> \nfrom the file indicated by B<foo.nc>, and write the results\nto the file B<vx.float>. The data would be extracted at their native\ngrid resolution, and maximum refinement level.\n\nThe command \n\nC<wasp2raw -lod 0 -varname vx foo.wasp vx.float>\n\nwould perform identically to the one above except that the \ncoarsest approximation would be extracted for variable B<vx>.\n\n\n=head1 SEE ALSO\n\nwaspcreate, raw2wasp\n\nI<An Overview of VAPOR Data Collections>\n\n\n=head1 HISTORY\n\nLast updated on $Date$\n\n"
  },
  {
    "path": "share/doc/man/waspcreate.pod",
    "content": "=begin comment\n\n$Id$\n\n=end comment\n\n=head1 NAME\n\nwaspcreate - Generate a WASP file\n\n=head1 SYNOPSIS\n\nB<waspcreate> [options] [name:xtype:count[:dimname]+]+\n\n=head1 DESCRIPTION\n\nB<waspcreate> generates an empty NetCDF file,\nsuitable for containing compressed arrays (NetCDF variables) following\nthe WASP conventions. The resulting file contains the definitions\nof NetCDF dimensions, and 1D, 2D, and 3D variables that may\nsubsequently be populated using, for example, the B<raw2wasp>\ncommand. Variable names, external storage type, and associated\ndimension names are specified by repeated instances of the pattern:\n[name:xtype:count[:dimname]+], defined as follows:\n\n=over 4\n\n=item name \n\nThe variable's name. Any string permitted by NetCDF.\n\n=item xtype \n\nA valid NetCDF external data type (e.g NC_FLOAT, NC_DOUBLE).\n\n=item ncdims \n\nThe number of compressed dimensions. If the number of compressed dimensions\nis less than the total number of variable dimensions then compression\nwill take place along only the I<ncdims> fastest-varying dimensions.\nIf I<ncdims> is zero the variable will not be compressed. The maximum \nvalue for I<ncdims> is 3.\n\n=item [:dimname]\n\nA colon-seperated list\nof the variable's dimension names. The dimension names are specified in the\norder from slowest to fastest varying. The dimension names must be defined\nwith the B<-dimlens> option.\n\n=back\n\n=head1 OPTIONS\n\n=over 4\n\n=item -dimlens\n\nA Colon delimited list of dimension lengths.\n\n=item -dimnames\n\nA Colon delimited list of dimension names for the dimension lengths \nspecified by I<-dimlens>. The number of elements specified by I<-dimlens>\nand I<-dimnames> must be identical.\n\n=item -help\n\nPrint a usage statement and then exit.\n\n=item -help\n\nPrint a usage statement and then exit.\n\n=item -ofile \n\nSpecify an alternate NetCDF output file name. The default\nis to create a file names B<test.nc>.\n\n=item -wname E<lt>wave_nameE<gt>\n\nSpecify the name of the wavelet to use for the wavelet transform. Valid\nvalues are: bior1.1, bior1.3, bior1.5, bior2.2, bior2.4 ,bior2.6,\nbior2.8, bior3.1, bior3.3, bior3.5, bior3.7, bior3.9, bior4.4.\n\nThe default is bior 4.4 (aka CDF 9/7).\n\n=back\n\n=head1 EXAMPLES\n\nThe command \n\nC<waspcreate -dimlens 256:256:256 -dimnames Nz:Ny:Nx temp:NC_FLOAT:3:Nz:Ny:Nx>\n\nwill create a file named test.nc containing the definition of a single\ncompressed variable named 'temp', with dimensions 256x256x256.\n\n=head1 SEE ALSO\n\nraw2wasp, wasp2raw\n\n\n=head1 HISTORY\n\nLast updated on $Date$\n\n"
  },
  {
    "path": "share/docker/centos7/Dockerfile",
    "content": "# To build:\n#   docker image build -t centos7:1.0 .\n\nFROM centos:7.4.1708\nMAINTAINER The CentOS Project <cloud-ops@centos.org>\n\nCMD [ \"/bin/bash\" ]\n\n# Do not update yum!  updating system libraries renders Vapor incompatible on older\n# CentOS versions, such as those run on Casper and Hera\n#RUN yum -y clean all \\\n#    && yum -y clean metadata \\\n#    && yum -y update\n\nRUN yum -y install epel-release \\\n    && yum -y install dbus \\\n    && yum -y install cmake3 \\\n    && yum -y install make \\\n    && yum -y install bsdtar \\\n    && yum -y install gcc-c++ \\\n    && yum -y install curl \\\n    && yum -y install xz-devel \\\n    && yum -y install git \\\n    && yum -y install freeglut-devel \\\n# Aren't we supposed to be distributing libexpat in our third-party tar???\n    && yum -y install expat-devel \\\n    && yum -y install libquadmath-devel \\\n    && yum -y install python3-pip \\\n    && yum -y install libXrender-devel \\\n    && yum -y install libSM-devel \\\n    && yum -y install fontconfig-devel \\\n    && pip3 install gdown\n\n# All this to default to CMake3\nRUN alternatives --install /usr/local/bin/cmake cmake /usr/bin/cmake 10 \\\n    --slave /usr/local/bin/ctest ctest /usr/bin/ctest \\\n    --slave /usr/local/bin/cpack cpack /usr/bin/cpack \\\n    --slave /usr/local/bin/ccmake ccmake /usr/bin/ccmake \\\n    --family cmake\n\nRUN alternatives --install /usr/local/bin/cmake cmake /usr/bin/cmake3 20 \\\n    --slave /usr/local/bin/ctest ctest /usr/bin/ctest3 \\\n    --slave /usr/local/bin/cpack cpack /usr/bin/cpack3 \\\n    --slave /usr/local/bin/ccmake ccmake /usr/bin/ccmake3 \\\n    --family cmake\n\nRUN mkdir -p /usr/local/VAPOR-Deps\n\n# Qt 5.12.4\n#RUN fileid=\"1q9U5FJIvWLvwNbKLVluCiSH-uAnQVgU1\" \\\n\n# Qt 5.13.2\n#RUN fileid=\"1e7F3kDoKctBmB3NOF4dES2395oScb9_0\" \\\n\n# Ospray\nRUN fileid=\"1S9DwySMnQrBuUUZGKolD__WQrjTmLgyn\" \\\n    && filename=\"/usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz\" \\\n    && curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=${fileid}\" > /dev/null \\\n    && curl -Lb ./cookie \\\n    \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}\" \\\n    -o ${filename}\n\nRUN ls -lrth /usr/local/VAPOR-Deps/\n\n#RUN bsdtar -xf /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz -C /usr/local/VAPOR-Deps\n\nRUN chown -R root:root /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz\nRUN chmod -R 777 /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz\n\nRUN bsdtar -xf /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz -C /usr/local/VAPOR-Deps\nRUN rm /usr/local/VAPOR-Deps/2019-Aug-CentOS.tar.xz\n\nRUN chown -R root:root /usr/local/VAPOR-Deps\nRUN chmod -R 777 /usr/local/VAPOR-Deps\n\nRUN git clone https://github.com/NCAR/VAPOR.git /root/project\nRUN chown -R root:root /root/project\nRUN chmod -R 777 /root/project\n\nRUN cp /root/project/site_files/site.NCAR /root/project/site.local \\\nRUN chown -R root:root /root/project\nRUN chmod -R 777 /root/project\n    && mkdir -p /root/project/build\nRUN chown -R root:root /root/project\nRUN chmod -R 777 /root/project\n    && export CMAKE_CXX_COMPILER=g++ \\\n    && cd /root/project/build \\\n    && cmake3 .. \\\n    && make && pwd && ls && ls bin\n\nWORKDIR /root/project\n"
  },
  {
    "path": "share/docker/ubuntu18/Dockerfile",
    "content": "from ubuntu:18.04\n\n#################################\n#                               #\n# Vapor configuration and build #\n#                               #\n#################################\n\nRUN apt-get update \\\n    && apt-get install -y curl \\\n    && apt-get install -y xz-utils \\\n    && apt-get install -y git \\\n    && apt-get install -y cmake \\\n    && apt-get install -y g++ \\\n# need freglut3-dev due to error Could NOT find OpenGL (missing: OPENGL_gl_LIBRARY OPENGL_INCLUDE_DIR)\n# https://stackoverflow.com/questions/31170869/cmake-could-not-find-opengl-in-ubuntu\n    && apt-get install -y freeglut3-dev \\\n# Aren't we supposed to be distributing libexpat in our third-party tar???\n    && apt-get install -y libexpat1-dev \\\n    && apt-get install -y libglib2.0-0 \\\n    && apt-get install -y libdbus-1-3 \\\n    && apt-get install -y valgrind \\\n    && apt-get install -y clang-tidy \\\n    && apt-get clean \\\n    && rm -rf /var/lib/apt/lists/*\n\n# Acquire 3rd party libraries\n#\nRUN mkdir -p /usr/local/VAPOR-Deps\nRUN fileid=\"1v0AwfOnDsf8hMzBqg4OcEtcEyH5YpnIn\" \\\n    && filename=\"/usr/local/VAPOR-Deps/2019-Aug-Ubuntu.tar.xz\" \\\n    && curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=${fileid}\" > /dev/null \\\n    && curl -Lb ./cookie \\\n    \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}\" \\\n    -o ${filename}\nRUN chmod -R 777 /usr\nRUN chown -R root:root /usr\nRUN tar -xf /usr/local/VAPOR-Deps/2019-Aug-Ubuntu.tar.xz \\ \n    -C /usr/local/VAPOR-Deps \\\n    && chown -R root:root /usr\nRUN chmod -R 777 /usr\n\n#RUN ls -lrth /usr/local/VAPOR-Deps/2019-Aug\n\n# Acquire smokeTest data\n#\nRUN mkdir -p /smokeTestData\nRUN fileid=\"1w8CLOohQuVrhcDbmIyU68whvqaoiCx9t\" \\\n    && filename=\"/tmp/smokeTestData.tar.gz\" \\\n    && curl -c ./cookie -s -L \"https://drive.google.com/uc?export=download&id=${fileid}\" > /dev/null \\\n    && curl -Lb ./cookie \\\n    \"https://drive.google.com/uc?export=download&confirm=`awk '/download/ {print $NF}' ./cookie`&id=${fileid}\" \\\n    -o ${filename}\nRUN tar -xf /tmp/smokeTestData.tar.gz \\ \n    -C /smokeTestData \\\n    && chown -R root:root /smokeTestData\nRUN chmod -R 777 /smokeTestData\n\nRUN cd / \\\n    && git clone https://github.com/NCAR/VAPOR.git /root/project \\\n    && cd /root/project \\\n    && cp site_files/site.NCAR site.local \\\n    && mkdir build\n\nRUN cd /root/project/build \\\n    && export CMAKE_CXX_COMPILER=g++ \\\n    && cmake .. && make\n\nWORKDIR /root/project\n"
  },
  {
    "path": "share/examples/.vapor3_prefs",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\r\n<VaporPreferences>\r\n<StartupParams>\r\n<AutoStretch Type=\"Long\">\r\n  0 \r\n</AutoStretch>\r\n<CacheMBs Type=\"Long\">\r\n  2000 \r\n</CacheMBs>\r\n<Local Type=\"Long\">\r\n  0 \r\n</Local>\r\n<TexSize Type=\"Long\">\r\n  128 \r\n</TexSize>\r\n<TexSizeEnabled Type=\"Long\">\r\n  0 \r\n</TexSizeEnabled>\r\n<VisualizerNum Type=\"Long\">\r\n  -1 \r\n</VisualizerNum>\r\n<WinSize Type=\"Long\">\r\n  1280 1024 \r\n</WinSize>\r\n<WinSizeLocked Type=\"Long\">\r\n  0 \r\n</WinSizeLocked>\r\n<Fidelity2DDefault Type=\"Double\">\r\n  2 2 \r\n</Fidelity2DDefault>\r\n<Fidelity3DDefault Type=\"Double\">\r\n  4 4 \r\n</Fidelity3DDefault>\r\n<CurrentPrefsPath Type=\"String\">\r\n  C:\\Vapor\\vapor3-0Release\\share\\examples\\\\.vapor3_prefs\r\n</CurrentPrefsPath>\r\n<FlowDir Type=\"String\">\r\n  .\r\n</FlowDir>\r\n<ImageDir Type=\"String\">\r\n  .\r\n</ImageDir>\r\n<MetadataDir Type=\"String\">\r\n  .\r\n</MetadataDir>\r\n<PythonDir Type=\"String\">\r\n  .\r\n</PythonDir>\r\n<SessionDir Type=\"String\">\r\n  .\r\n</SessionDir>\r\n<TFDir Type=\"String\">\r\n  .\r\n</TFDir>\r\n</StartupParams>\r\n<AppSettingsParams>\r\n<AutosaveEnabled Type=\"Long\">\r\n  1 \r\n</AutosaveEnabled>\r\n<AutosaveInterval Type=\"Long\">\r\n  10 \r\n</AutosaveInterval>\r\n<CurrentAutosaveEnabled Type=\"Long\">\r\n  1 \r\n</CurrentAutosaveEnabled>\r\n<CurrentAutosaveInterval Type=\"Long\">\r\n  10 \r\n</CurrentAutosaveInterval>\r\n<CurrentJpegQuality Type=\"Long\">\r\n  99 \r\n</CurrentJpegQuality>\r\n<CurrentLogfileEnabled Type=\"Long\">\r\n  0 \r\n</CurrentLogfileEnabled>\r\n<CurrentMessageSilence Type=\"Long\">\r\n  0 \r\n</CurrentMessageSilence>\r\n<CurrentShowCitation Type=\"Long\">\r\n  1 \r\n</CurrentShowCitation>\r\n<CurrentTrackMouse Type=\"Long\">\r\n  1 \r\n</CurrentTrackMouse>\r\n<CurrentUseLessAccurateData Type=\"Long\">\r\n  1 \r\n</CurrentUseLessAccurateData>\r\n<CurrentWarnMissingData Type=\"Long\">\r\n  0 \r\n</CurrentWarnMissingData>\r\n<JpegQuality Type=\"Long\">\r\n  99 \r\n</JpegQuality>\r\n<Local Type=\"Long\">\r\n  0 \r\n</Local>\r\n<LogfileEnabled Type=\"Long\">\r\n  0 \r\n</LogfileEnabled>\r\n<MessageSilence Type=\"Long\">\r\n  0 \r\n</MessageSilence>\r\n<ShowCitation Type=\"Long\">\r\n  1 \r\n</ShowCitation>\r\n<TrackMouse Type=\"Long\">\r\n  1 \r\n</TrackMouse>\r\n<UseLessAccurateData Type=\"Long\">\r\n  1 \r\n</UseLessAccurateData>\r\n<VisualizerNum Type=\"Long\">\r\n  -1 \r\n</VisualizerNum>\r\n<WarnMissingData Type=\"Long\">\r\n  0 \r\n</WarnMissingData>\r\n<AutosaveName Type=\"String\">\r\n  /tmp/vapor_autosave.vs3\r\n</AutosaveName>\r\n<CurrentAutosaveName Type=\"String\">\r\n  /tmp/vapor_autosave.vs3\r\n</CurrentAutosaveName>\r\n<CurrentLogfileName Type=\"String\">\r\n  /tmp/vaporLog.txt\r\n</CurrentLogfileName>\r\n<LogfileName Type=\"String\">\r\n  /tmp/vaporLog.txt\r\n</LogfileName>\r\n</AppSettingsParams>\r\n</VaporPreferences>\r\n"
  },
  {
    "path": "share/examples/.vapor_prefs",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\r\n<UserPreferences AutoSaveInterval=\"10\"  CacheSize=\"1024\"  JpegQuality=\"100\"  SpecifiedTextureSize=\"0\"  SpecifyTextureSize=\"false\"  VaporVersion=\"1.4.0\" >\r\n<AutoSaveFilename Type=\"String\">\r\n  vaporAutosave.vss\r\n</AutoSaveFilename>\r\n<ExportFileName Type=\"String\">\r\n  /tmp/vapor.003911.xml\r\n</ExportFileName>\r\n<FlowPath Type=\"String\">\r\n  .\r\n</FlowPath>\r\n<ImageCapturePath Type=\"String\">\r\n  .\r\n</ImageCapturePath>\r\n<LogFileName Type=\"String\">\r\n  vaporlog.txt\r\n</LogFileName>\r\n<MetadataPath Type=\"String\">\r\n  .\r\n</MetadataPath>\r\n<SessionPath Type=\"String\">\r\n  .\r\n</SessionPath>\r\n<TransferFunctionPath Type=\"String\">\r\n  .\r\n</TransferFunctionPath>\r\n<MessageSettings MaxLogMsgs=\"0 10 20\"  MaxPopups=\"0 3 3\"  UseLowerRefinementLevel=\"false\"  WarnDataMissing=\"true\" >\r\n</MessageSettings>\r\n<SceneColors BackgroundColor=\"0 0 0\"  DomainFrameColor=\"255 255 255\"  DomainFrameEnabled=\"true\"  SubregionFrameColor=\"255 0 0\"  SubregionFrameEnabled=\"false\" >\r\n</SceneColors>\r\n<ProbeDefaults DefaultAlpha=\"0.12\"  DefaultPhi=\"0\"  DefaultPsi=\"0\"  DefaultScale=\"1\"  DefaultTheta=\"0\" >\r\n</ProbeDefaults>\r\n<ViewpointDefaults DefaultAmbientCoeff=\"0.1\"  DefaultDiffuseCoeff=\"0.8 0.8 0.8\"  DefaultLightDirections=\"0 0 1 0 1 0 1 0 0 \"  DefaultSpecularCoeff=\"0.3 0.3 0.3\"  DefaultSpecularExp=\"20\"  DefaultUpVec=\"0 1 0\"  DefaultViewDir=\"0 0 -1\" >\r\n</ViewpointDefaults>\r\n<FlowDefaults DefaultArrowSize=\"2\"  DefaultDiamondSize=\"2\"  DefaultFlowDiameter=\"1\"  DefaultFlowLength=\"1\"  DefaultGeometryType=\"0\"  DefaultIntegrationAccuracy=\"0.5\"  DefaultSmoothness=\"20\" >\r\n</FlowDefaults>\r\n<IsoDefaults DefaultIsoBitsPerVoxel=\"8\" >\r\n</IsoDefaults>\r\n<DVRDefaults DefaultDvrBitsPerVoxel=\"8\"  DefaultDvrLighting=\"false\"  DefaultDvrPreIntegration=\"false\" >\r\n</DVRDefaults>\r\n<AnimationDefaults DefaultAnimationMaxFPS=\"10\"  DefaultAnimationMaxWait=\"6000\" >\r\n</AnimationDefaults>\r\n<VizFeatureDefaults DefaultShowAxisArrows=\"false\"  DefaultShowTerrain=\"false\" >\r\n</VizFeatureDefaults>\r\n</UserPreferences>\r\n"
  },
  {
    "path": "share/examples/NCL/USFilled.ncl",
    "content": ";\n; This NCL script generates a global, geo-referenced map image with color\n; filled political boundaries. The resulting image can be correctly \n; registered and displayed by vaporgui using the \"Image\" tab\n;\n; N.B. as of version 6.0 of NCL support for rendering to a raster\n; image is limited. Hence, we have to render to postscript, and then\n; rasterize the image. Getting the process right is somewhat tricky,\n; and the reason for much of the complexity of this code.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl\"\n\nbegin\n\n wks_type = \"ps\"\n wks_type@wkForegroundColor = \"white\"\n\n\n wks = gsn_open_wks(wks_type,\"temp\")\n\n;\n; Set up some map resources.\n;\n mpres = True\n;\n; Take up as much of viewport as possible.\n;\n; This is not really necessary since we're going to remove\n; the white space later with \"convert\".\n;\n mpres@vpXF = 0.0\n mpres@vpYF = 1.0\n mpres@vpWidthF = 1.0\n mpres@vpHeightF = 1.0\n\n ;\n ; The perimeter boarder is necessary so that later we can use \n ; \"convert's\", -trim option to remove PostScripts page margins\n ;\n mpres@gsnTickMarksOn = False\n mpres@mpPerimDrawOrder = \"PostDraw\"\n mpres@mpPerimLineColor = \"blue\"\n mpres@mpPerimOn = True\n\n ;\n ; Select the map projection. This must match the \"+proj\" option we\n ; use later when we call tiff2geotif. Note, an NCL CylindricalEquidistant\n ; projection is a \"latlong\" projection in tiff2geotiff speak\n ;\n mpres@mpProjection = \"CylindricalEquidistant\"\n mpres@mpLimitMode = \"LatLon\"\n\n ;\n ; Select the map database\n ;\n mpres@mpDataBaseVersion = \"MediumRes\"    ; Use the high-res database\n mpres@mpDataSetName = \"Earth..4\"    ; Use the high-res database\n mpres@mpDataResolution = \"Fine\"\n\n\n ;\n ; turn on country filling\n ;\n mpres@mpFillOn = True\n mpres@mpFillBoundarySets = \"AllBoundaries\"   ; turn on country boundaries\n\n mpres@mpOutlineOn = True\n mpres@mpOutlineBoundarySets = \"USStates\"   ; turn on country boundaries\n\n ;\n ; Specify the map coordinates. The whole world\n ;\n ; N.B. There is a bug in vaporgui that prevents true periodic boundaries. I.e\n ; MaxLon cannot equal MinLat + 360, for example\n ; \n mpres@mpMinLonF             =  -180.0\n mpres@mpMaxLonF             =  -60.0\n mpres@mpMinLatF             =  15.0\n mpres@mpMaxLatF             =  80.0\n\n\n\n map = gsn_csm_map(wks,mpres)\n\n;---Close workstation (PS file) so we can convert to png\n  delete(wks)\n\n ;\n ; Convert to png with no margins. You might need to increase \n ; the -density value if you increase the size of the image.\n ;\n cmd = \"convert -trim -density 600 -compress lzw temp.ps temp.tif\"\n system(cmd)\n\n ;\n ; Now insert the projection string into the tiff image. Note, the \n ; coordinates specified here should match those specified above\n ;\n cmd = \"tiff2geotiff -4 +proj=latlong -n'-180.0 15.0 -60.0 80.0' temp.tif USFilled.tif\"\n\n system(cmd)\n\nend\n"
  },
  {
    "path": "share/examples/NCL/USOutline.ncl",
    "content": ";\n; This NCL script generates a global, geo-referenced map image with color\n; filled political boundaries. The resulting image can be correctly \n; registered and displayed by vaporgui using the \"Image\" tab\n;\n; N.B. as of version 6.0 of NCL support for rendering to a raster\n; image is limited. Hence, we have to render to postscript, and then\n; rasterize the image. Getting the process right is somewhat tricky,\n; and the reason for much of the complexity of this code.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl\"\n\nbegin\n\n wks_type = \"ps\"\n wks_type@wkForegroundColor = \"white\"\n\n\n wks = gsn_open_wks(wks_type,\"temp\")\n\n;\n; Set up some map resources.\n;\n mpres = True\n;\n; Take up as much of viewport as possible.\n;\n; This is not really necessary since we're going to remove\n; the white space later with \"convert\".\n;\n mpres@vpXF = 0.0\n mpres@vpYF = 1.0\n mpres@vpWidthF = 1.0\n mpres@vpHeightF = 1.0\n\n ;\n ; The perimeter boarder is necessary so that later we can use \n ; \"convert's\", -trim option to remove PostScripts page margins\n ;\n mpres@gsnTickMarksOn = False\n mpres@mpPerimDrawOrder = \"PostDraw\"\n mpres@mpPerimLineColor = \"blue\"\n mpres@mpPerimOn = True\n\n ;\n ; Select the map projection. This must match the \"+proj\" option we\n ; use later when we call tiff2geotif. Note, an NCL CylindricalEquidistant\n ; projection is a \"latlong\" projection in tiff2geotiff speak\n ;\n mpres@mpProjection = \"CylindricalEquidistant\"\n mpres@mpLimitMode = \"LatLon\"\n\n ;\n ; Select the map database\n ;\n mpres@mpDataBaseVersion = \"MediumRes\"    ; Use the high-res database\n mpres@mpDataSetName = \"Earth..4\"    ; Use the high-res database\n mpres@mpDataResolution = \"Fine\"\n\n\n mpres@mpFillOn = False\n mpres@mpOutlineOn = True\n mpres@mpOutlineBoundarySets = \"AllBoundaries\"   ; turn on country boundaries\n mpres@mpUSStateLineColor = \"yellow\"\n mpres@mpGeophysicalLineColor = \"yellow\"\n\n ;\n ; Specify the map coordinates. The whole world\n ;\n ; N.B. There is a bug in vaporgui that prevents true periodic boundaries. I.e\n ; MaxLon cannot equal MinLat + 360, for example\n ; \n mpres@mpMinLonF             =  -180.0\n mpres@mpMaxLonF             =  -60.0\n mpres@mpMinLatF             =  15.0\n mpres@mpMaxLatF             =  80.0\n\n\n\n map = gsn_csm_map(wks,mpres)\n\n;---Close workstation (PS file) so we can convert to png\n  delete(wks)\n\n ;\n ; Convert to png with no margins. You might need to increase \n ; the -density value if you increase the size of the image.\n ;\n cmd = \"convert -trim -density 600 -compress lzw temp.ps temp.tif\"\n system(cmd)\n\n ;\n ; Now insert the projection string into the tiff image. Note, the \n ; coordinates specified here should match those specified above\n ;\n cmd = \"tiff2geotiff -4 +proj=latlong -n'-180.0 15.0 -60.0 80.0' temp.tif USOutline.tif\"\n\n system(cmd)\n\nend\n"
  },
  {
    "path": "share/examples/NCL/WrfTestScripts.Notes",
    "content": "The following NCL scripts where taken directly from the WRF NCL-Examples page and adapted to \noutput a geotiff image of their plot output:\n\n  1. wrf_cloud.ncl\n  2. wrf_Surface1.ncl\n  3. wrf_EtaLevels.ncl\n  4. wrf_pv.ncl\n  5. wrf_crossSection4.ncl\n\nEach was modified to:\n  - output to a geotiff file\n  - generate only one plot per time stamp (several originally iterated over a \"level\" and/or\n    generated several distinct plots per time stamp\n  - accept an optional command-line parameter to crop/nocrop at the plot frame in the\n    resultant geotiff;  plots are cropped by default\n        ex. usage:\n          ncl \"cropPlot=False\" wrf_cloud.ncl\n\n\nTypically these must be edited further to reflect the location of the WRF file(s) of interest.\n\nwrf_crossSection4.ncl produces plot that are vertical slices through the data.  For these plots, only \ntimestamps are placed into the resultant tiff file (i.e., there is no explicit georeferencing).\n"
  },
  {
    "path": "share/examples/NCL/worldFilled.ncl",
    "content": ";\n; This NCL script generates a global, geo-referenced map image with color\n; filled political boundaries. The resulting image can be correctly \n; registered and displayed by vaporgui using the \"Image\" tab\n;\n; N.B. as of version 6.0 of NCL support for rendering to a raster\n; image is limited. Hence, we have to render to postscript, and then\n; rasterize the image. Getting the process right is somewhat tricky,\n; and the reason for much of the complexity of this code.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl\"\n\nbegin\n\n wks_type = \"ps\"\n wks_type@wkForegroundColor = \"white\"\n\n\n wks = gsn_open_wks(wks_type,\"temp\")\n\n;\n; Set up some map resources.\n;\n mpres = True\n;\n; Take up as much of viewport as possible.\n;\n; This is not really necessary since we're going to remove\n; the white space later with \"convert\".\n;\n mpres@vpXF = 0.0\n mpres@vpYF = 1.0\n mpres@vpWidthF = 1.0\n mpres@vpHeightF = 1.0\n\n ;\n ; The perimeter boarder is necessary so that later we can use \n ; \"convert's\", -trim option to remove PostScripts page margins\n ;\n mpres@gsnTickMarksOn = False\n mpres@mpPerimDrawOrder = \"PostDraw\"\n mpres@mpPerimLineColor = \"blue\"\n mpres@mpPerimOn = True\n\n ;\n ; Select the map projection. This must match the \"+proj\" option we\n ; use later when we call tiff2geotif. Note, an NCL CylindricalEquidistant\n ; projection is a \"latlong\" projection in tiff2geotiff speak\n ;\n mpres@mpProjection = \"CylindricalEquidistant\"\n mpres@mpLimitMode = \"LatLon\"\n\n ;\n ; Select the map database\n ;\n mpres@mpDataBaseVersion = \"MediumRes\"    ; Use the high-res database\n mpres@mpDataSetName = \"Earth..4\"    ; Use the high-res database\n mpres@mpDataResolution = \"Fine\"\n\n\n ;\n ; turn on country filling\n ;\n mpres@mpFillOn = True\n mpres@mpFillBoundarySets = \"National\"   ; turn on country boundaries\n mpres@mpFillAreaSpecifiers = (/\"Mexico:states\", \"canada:states\", \"china:states\", \"australia:states\", \"brazil:states\", \"india:states\", \"united states:states\" /)   \n\n ;\n ; Specify the map coordinates. The whole world\n ;\n ; N.B. There is a bug in vaporgui that prevents true periodic boundaries. I.e\n ; MaxLon cannot equal MinLat + 360, for example\n ; \n mpres@mpMinLonF             =  -179.99\n mpres@mpMaxLonF             =  179.99\n mpres@mpMinLatF             =  -89.99\n mpres@mpMaxLatF             =  89.99\n\n\n\n map = gsn_csm_map(wks,mpres)\n\n;---Close workstation (PS file) so we can convert to png\n  delete(wks)\n\n ;\n ; Convert to png with no margins. You might need to increase \n ; the -density value if you increase the size of the image.\n ;\n cmd = \"convert -trim -density 600 -compress lzw temp.ps temp.tif\"\n system(cmd)\n\n ;\n ; Now insert the projection string into the tiff image. Note, the \n ; coordinates specified here should match those specified above\n ;\n cmd = \"tiff2geotiff -4 +proj=latlong -n'-179.99 -89.99 179.99 89.99' temp.tif worldFilled.tif\"\n\n system(cmd)\n\nend\n"
  },
  {
    "path": "share/examples/NCL/worldOutline.ncl",
    "content": ";\n; This NCL script generates a global, geo-referenced map image with color\n; filled political boundaries. The resulting image can be correctly \n; registered and displayed by vaporgui using the \"Image\" tab\n;\n; N.B. as of version 6.0 of NCL support for rendering to a raster\n; image is limited. Hence, we have to render to postscript, and then\n; rasterize the image. Getting the process right is somewhat tricky,\n; and the reason for much of the complexity of this code.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl\"\n\nbegin\n\n wks_type = \"ps\"\n wks_type@wkForegroundColor = \"white\"\n\n\n wks = gsn_open_wks(wks_type,\"temp\")\n\n;\n; Set up some map resources.\n;\n mpres = True\n;\n; Take up as much of viewport as possible.\n;\n; This is not really necessary since we're going to remove\n; the white space later with \"convert\".\n;\n mpres@vpXF = 0.0\n mpres@vpYF = 1.0\n mpres@vpWidthF = 1.0\n mpres@vpHeightF = 1.0\n\n ;\n ; The perimeter boarder is necessary so that later we can use \n ; \"convert's\", -trim option to remove PostScripts page margins\n ;\n mpres@gsnTickMarksOn = False\n mpres@mpPerimDrawOrder = \"PostDraw\"\n mpres@mpPerimLineColor = \"blue\"\n mpres@mpPerimOn = True\n\n ;\n ; Select the map projection. This must match the \"+proj\" option we\n ; use later when we call tiff2geotif. Note, an NCL CylindricalEquidistant\n ; projection is a \"latlong\" projection in tiff2geotiff speak\n ;\n mpres@mpProjection = \"CylindricalEquidistant\"\n mpres@mpLimitMode = \"LatLon\"\n\n ;\n ; Select the map database\n ;\n mpres@mpDataBaseVersion = \"MediumRes\"    ; Use the high-res database\n mpres@mpDataSetName = \"Earth..4\"    ; Use the high-res database\n mpres@mpDataResolution = \"Fine\"\n\n\n\n ;\n ; turn on boundaries\n ;\n mpres@mpFillOn = False ; apparently we need to turn off area fill\n mpres@mpOutlineOn = True\n mpres@mpOutlineBoundarySets = \"National\"   ; turn on country boundaries\n mpres@mpOutlineSpecifiers = (/\"Mexico:states\", \"canada:states\", \"china:states\", \"australia:states\", \"brazil:states\", \"india:states\", \"united states:states\" /)\n\n ;\n ; Specify the map coordinates. The whole world\n ;\n ; N.B. There is a bug in vaporgui that prevents true periodic boundaries. I.e\n ; MaxLon cannot equal MinLat + 360, for example\n ; \n mpres@mpMinLonF             =  -179.99\n mpres@mpMaxLonF             =  179.99\n mpres@mpMinLatF             =  -89.99\n mpres@mpMaxLatF             =  89.99\n\n\n\n map = gsn_csm_map(wks,mpres)\n\n;---Close workstation (PS file) so we can convert to png\n  delete(wks)\n\n ;\n ; Convert to png with no margins. You might need to increase \n ; the -density value if you increase the size of the image.\n ;\n cmd = \"convert -trim -density 600 -compress lzw temp.ps temp.tif\"\n system(cmd)\n\n ;\n ; Now insert the projection string into the tiff image. Note, the \n ; coordinates specified here should match those specified above\n ;\n cmd = \"tiff2geotiff -4 +proj=latlong -n'-179.99 -89.99 179.99 89.99' temp.tif worldOutline.tif\"\n\n system(cmd)\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf2geotiff.ncl",
    "content": "load \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl\"\n\n; Set this to true to save intermediate files...\n_wrf2geotiff_DEBUG = False\n\n; Some symbolic constants (hopefully these don't collide with anything else!)\n_wrf2geotiff_LANDSCAPE = 6\n_wrf2geotiff_PSMINXY = 0\n_wrf2geotiff_PSMAXX = 612   ; 8.5\"\n_wrf2geotiff_PSMAXY = 792   ; 11\"\n_wrf2geotiff_GROWSIZE = 10\n\n; ------------------------------------------------------------------------------------\n; \n; wrf2geotiff_open()\n;\n; Called once to prime the plot capture process.\n;\n;\n; NOTE: at present, only postscript workstations are supported. We'd like to support\n; either PS or PDF, but are currently lacking a means to split a multi-page plotfile\n; into separate pages for PDF (Imagemagick's convert program introduces noise and minor\n; translations per-page).\n;\nundef(\"wrf2geotiff_open\")\nfunction wrf2geotiff_open(wks)\nlocal class\nbegin\n    if (_wrf2geotiff_DEBUG .eq. True) then\n        print(\"wrf2geotiff_open\")\n    end if\n     \n    ; make sure we're dealing with postscript...\n    class = NhlClassName(wks)\n    if (class.ne.\"psWorkstationClass\") then\n         print(\"wrf2geotiff_open(): Workstation type not PS\")\n         print(\"wrf2geotiff processes will fail\")\n         return False\n    end if\n\n    ; We create this \"opaque\" state variable that gets returned to the client code that then uses\n    ; it on subsequent calls to this API. All of the per-plot state is kept in array attributes, which\n    ; are sized initially and expand dynamically as needed.\n\n    tcVar = True\n    tcVar@numPlots = 0\n    if (class.eq.\"pdfWorkstationClass\") then\n        getvalues wks\n            \"wkPDFFileName\":  filename\n        end getvalues\n    else\n        getvalues wks\n            \"wkPSFileName\":  filename\n        end getvalues\n    end if\n    tcVar@plotFilename = filename\n    tcVar@outputScale = 2   ; default scaling factor for tiff images made from postscript versions\n    tcVar@disableGeoTags = False\n\n    ; array attributes...\n    tcVar@times = new(_wrf2geotiff_GROWSIZE, string)\n    tcVar@orient = new(_wrf2geotiff_GROWSIZE, string)\n    tcVar@proj4Str = new(_wrf2geotiff_GROWSIZE, string)\n    tcVar@pageMinX = new(_wrf2geotiff_GROWSIZE, float)\n    tcVar@pageMaxX = new(_wrf2geotiff_GROWSIZE, float)\n    tcVar@pageMinY = new(_wrf2geotiff_GROWSIZE, float)\n    tcVar@pageMaxY = new(_wrf2geotiff_GROWSIZE, float)\n    tcVar@minLon = new(_wrf2geotiff_GROWSIZE, float)\n    tcVar@maxLon = new(_wrf2geotiff_GROWSIZE, float)\n    tcVar@minLat = new(_wrf2geotiff_GROWSIZE, float)\n    tcVar@maxLat = new(_wrf2geotiff_GROWSIZE, float)\n    tcVar@cropFrame = new(_wrf2geotiff_GROWSIZE, logical)\n\n    return tcVar\nend\n\n; --------------------------------------------------------------------\n;\n; _wrf2geotiff_growArrays\n;\n; Intended as a private function;  used to resize the array attributes that keep track of\n; per-plot state.\n;\nundef(\"_wrf2geotiff_growArrays\")\nprocedure _wrf2geotiff_growArrays(tcVar)\nlocal atts, i, currSize, newSize, tmp\nbegin\n  if (_wrf2geotiff_DEBUG .eq. True) then\n      print(\"_wrf2geotiff_growArrays(): growing arrays sizes...\")\n  end if \n  atts = getvaratts(tcVar)\n  do i=0,dimsizes(atts)-1\n    currSize = dimsizes( tcVar@$atts(i)$ )\n    ; By design, anything that reports a dimsize of \"1\" is a scalar attribute,\n    ; and we won't attempt to grow it.\n    if (currSize .ne. 1) then\n        newSize = currSize + _wrf2geotiff_GROWSIZE\n        tmp = new(newSize, typeof( tcVar@$atts(i)$ ))\n        tmp(0:currSize-1) = tcVar@$atts(i)$\n        delete(tcVar@$atts(i)$)\n        tcVar@$atts(i)$ = tmp\n        delete(tmp)  ; very important to \"clear\" this for next time through the loop...\n    end if\n  end do\nend\n\n; ------------------------------------------------------------------------------\n;\n; _wrf2geotiff_getProj4Str()\n;\n; Intended as a private function;  given a wrf filevariable, extracts the\n; geographical projection information and returns it as a PROJ4 string.\n;\nundef(\"_wrf2geotiff_getProj4Str\")\nfunction _wrf2geotiff_getProj4Str(wrfFile)\nlocal proj, lon0, lat0, lat1, lat2, projStr, northSouth, stdLon, trueLat, poleLat\nbegin\n    proj = wrfFile@MAP_PROJ\n\n    if (proj .eq. 1) then  ; Lambert Conformal\n        lon0 = \" +lon_0=\" + wrfFile@STAND_LON\n        lat0 = \" +lat_0=\" + wrfFile@MOAD_CEN_LAT\n        lat1 = \" +lat_1=\" + wrfFile@TRUELAT1\n        lat2 = \" +lat_2=\" + wrfFile@TRUELAT2\n        projStr = \" +proj=lcc +ellps=sphere\" + lon0 + lat0 + lat1 + lat2\n        return projStr\n    end if\n\n    if (proj .eq. 3) then  ; Mercator\n        latTs = \" +lat_ts=\" + wrfFile@TRUELAT1\n        lon0 = \" +lon_0=\" + wrfFile@STAND_LON\n        projStr = \" +proj=merc +ellps=sphere\" + lon0 + latTs\n        return projStr\n    end if\n\n    if (proj .eq. 2) then ; Polar Stereographic\n       if (wrfFile@MOAD_CEN_LAT .lt. 0) then\n          northSouth = \" +lat_0=-90\"\n       else\n          northSouth = \" +lat_0=90\"\n       end if\n       stdLon = \" +lon_0=\" + wrfFile@STAND_LON\n       trueLat = \" +lat_ts=\" + wrfFile@TRUELAT1\n       projStr = \" +proj=stere +ellps=sphere\" + stdLon + northSouth + trueLat\n       return projStr\n    end if\n\n    if (proj .eq. 6) then  ; rotated Cassini\n       ;: as of 4/29/2009, WRF files are not yet wired with these attributes.\n       ;;poleLat = \" +o_lat_p=\" + wrfFile@POLE_LAT\n       ;;poleLon = \" +o_lon_p=\" + wrfFile@POLE_LON\n\n       ; Hardcode values for testing...\n       poleLat = \" +o_lat_p=50\"\n       poleLon = \" +o_lon_p=180\"\n       lon0 = \" +lon_0=\" + wrfFile@STAND_LON\n       projStr = \" +proj=ob_tran +ellps=sphere +o_proj=cass \" +  poleLon + poleLat + lon0\n       return projStr\n    end if\n\n    print(\"wrf2geotiff: Unknown map projection: \" + proj)\n    print(\"wrf2geotiff: georeferencing will fail \");\n    return \"\"\nend\n\n; ----------------------------------------------------------------------------------\n;\n; _wrf2geotiff_validateProj4String()\n;\n; Intended as a private function. Perhaps a sanity check on our assumptions by\n; looping though the various proj4 strings collected during process, and verifying\n; that they are all the same. A warning is printed if they are not, and in any case\n; the first such instance is returned as a quoted string.\n;\nundef(\"_wrf2geotiff_validateProj4String\")\nfunction _wrf2geotiff_validateProj4String(tcVar)\nlocal quote, proj4Str\nbegin\n   quote = inttochar(34)\n   if (tcVar@numPlots .eq. 0) then\n       return \" \"\n   end if\n\n   proj4Str = tcVar@proj4Str(0)\n   do i=1,tcVar@numPlots-1\n       if (tcVar@proj4Str(i) .ne. proj4Str) then\n           print(\"WARNING: inconsistent projections across image collection: \" + \\\n               proj4Str + \"  --versus--  \" + tcVar@proj4Str(i))\n       end if\n   end do\n\n   return quote + proj4Str + quote\nend\n\n; --------------------------------------------------------------------\n;\n; _wrf2geotiff_getDevVP()\n;\n; This function was contributed by Dave Brown (originally named get_dev_vp()).\n; Gets the location of the viewport in a workstation-independent fashion.\n; Intended as a private function.\n;\nundef(\"_wrf2geotiff_getDevVP\")\nfunction _wrf2geotiff_getDevVP(wks:graphic,plot:graphic)\nlocal class, vp, dc, orient, dvp\nbegin\n\n  vp = new(4,float)\n  getvalues plot\n        \"vpXF\"      : vp(0)\n        \"vpYF\"      : vp(1)\n        \"vpWidthF\"  : vp(2)\n        \"vpHeightF\" : vp(3)\n  end getvalues\n  dc = new(4,integer)\n\n  orient = 0\n  class = NhlClassName(wks)\n  if((class.eq.\"psWorkstationClass\").or. \\\n     (class.eq.\"pdfWorkstationClass\")) then\n\n       getvalues wks\n          \"wkDeviceLowerX\" : dc(0)\n          \"wkDeviceLowerY\" : dc(1)\n          \"wkDeviceUpperX\" : dc(2)\n          \"wkDeviceUpperY\" : dc(3)\n          \"wkOrientation\"  : orient\n       end getvalues\n  else if class .eq. \"ncgmWorkstationClass\" then\n       dc(0) = 0\n       dc(1) = 0\n       dc(2) = 1\n       dc(3) = 1\n  else\n       dc(0) = 0\n       dc(1) = 0\n       getvalues wks\n          \"wkVSWidthDevUnits\" : dc(2)\n       end getvalues\n      \n       dc(3) = dc(2)\n  end if\n  end if       \n\n  if (_wrf2geotiff_DEBUG .eq. True) then\n      print(vp)\n      print(dc)\n      print(orient)\n  end if\n\n  dvp = new(4,float)\n  if (orient .eq. 0) then\n      dvp(0) = dc(0) + vp(0) * (dc(2) - dc(0))\n      dvp(1) = dc(1) + (vp(1) - vp(3)) * (dc(3) - dc(1))\n      dvp(2) = dc(0) + (vp(0) + vp(2)) * (dc(2) - dc(0))\n      dvp(3) = dc(1) + vp(1) * (dc(3) - dc(1))\n  else\n      dvp(0) = dc(1) + (1.0 - vp(0)) * (dc(3) - dc(1))\n      dvp(1) = dc(0) + (vp(1) - vp(3)) * (dc(2) - dc(0))\n      dvp(2) = dc(1) + (1.0 - (vp(0) + vp(2))) * (dc(3) - dc(1))\n      dvp(3) = dc(0) + vp(1) * (dc(2) - dc(0))\n  end if\n\n  if (_wrf2geotiff_DEBUG .eq. True) then\n      print(dvp)\n  end if\n  dvp@orientation = orient\n   \n  return (dvp)\nend\n\n; ------------------------------------------------------------------------------\n;\n; wrf2geotiff_write()\n;\n; Called by client code on a per-plot basis. This method captures information about the\n; plot in an opaque state-variable created by a call to \"wrf2geotiff_open()\".\n;\nundef(\"wrf2geotiff_write\")\nprocedure wrf2geotiff_write(tcVar, wrfFile, time, wks:graphic, plot:graphic, crop:logical)\nlocal plotNum, currSizes, vp, xy, yf, width, height, xNDC, yNDC, xWorld, yWorld, slop\nbegin\n   if (_wrf2geotiff_DEBUG .eq. True) then\n       print(\"wrf2geotiff_write\")\n   end if\n\n   plotNum = tcVar@numPlots  ; dereference this for convenient use below\n\n   currSizes = dimsizes(tcVar@times)\n   if (plotNum .ge. currSizes(0)) then\n       _wrf2geotiff_growArrays(tcVar)\n   end if\n\n   ; get the location of the viewport on the page...\n   vp = _wrf2geotiff_getDevVP(wks,plot)\n\n   ; We want the page coords that correspond to LL,LR,UR,UL corners in\n   ; world coordinates; this depends on orientation of the plot on the page.\n    tcVar@orient(plotNum) = vp@orientation\n    if (vp@orientation .eq. _wrf2geotiff_LANDSCAPE) then\n       tcVar@pageMinX(plotNum) = vp(1)\n       tcVar@pageMaxX(plotNum) = vp(3)\n       tcVar@pageMinY(plotNum) = vp(2)\n       tcVar@pageMaxY(plotNum) = vp(0)\n   else\n       tcVar@pageMinX(plotNum) = vp(0)   ;min x\n       tcVar@pageMaxX(plotNum) = vp(2)   ;max x\n       tcVar@pageMinY(plotNum) = vp(1)   ;min y\n       tcVar@pageMaxY(plotNum) = vp(3)   ;max y\n   end if \n\n   ; get the world-coords of the view port. Note that if we use the viewport\n   ; extremes exactly, ndctodata() fails. So we add some slop to make sure the \n   ; values passed in are inside the viewport. OBVIOUSLY A STOP-GAP MEASURE!\n   getvalues plot\n       \"vpXF\":  xf;\n       \"vpYF\":  yf;\n       \"vpWidthF\": width;\n       \"vpHeightF\":  height;\n   end getvalues\n\n   slop = .0000005  ; NOTE: one more decimal-place right is too much\n   xNDC = (/ xf+slop, xf+width-slop, xf+width-slop, xf+slop /)\n   yNDC = (/ yf-slop, yf-slop, yf-height+slop, yf-height+slop /)\n   xWorld = new(dimsizes(xNDC), float)\n   yWorld = new(dimsizes(yNDC), float)\n   ndctodata(plot, xNDC, yNDC, xWorld, yWorld)\n\n   tcVar@minLon(plotNum) = xWorld(3)\n   tcVar@maxLon(plotNum) = xWorld(1)\n   tcVar@minLat(plotNum) = yWorld(3)\n   tcVar@maxLat(plotNum) = yWorld(1)\n\n   tcVar@proj4Str(plotNum) = _wrf2geotiff_getProj4Str(wrfFile)\n\n   tcVar@times(plotNum) = time\n   tcVar@cropFrame(plotNum) = crop\n\n   tcVar@numPlots = plotNum + 1\nend\n\n; ------------------------------------------------------------------------------\n;\n; wrf2geotiff_setOutputScale()\n;\n; Called by client code to change the default scale-factor for the tiff images.\n; The default is 2-times the resolution of the postscript image. \n;\nundef(\"wrf2geotiff_setOutputScale\")\nprocedure wrf2geotiff_setOutputScale(tcVar, scaleFactor:float)\nbegin\n    tcVar@outputScale = scaleFactor \nend\n\n; ------------------------------------------------------------------------------\n;\n; wrf2geotiff_disableGeoTags()\n;\n; Called by client code to disable writing of geotags in the tiff image; only timestamps\n; are written. This is useful for plots that are vertical cross-sections through the data.\n;\nundef(\"wrf2geotiff_disableGeoTags\")\nprocedure wrf2geotiff_disableGeoTags(tcVar)\nbegin\n    tcVar@disableGeoTags = True\nend\n\n; --------------------------------------------------------------------\n;\n; wrf2geotiff_close()\n;\n; Called by client code after all plots have been captured and/or sent to\n; the workstation. Using the information contained in the opaque state variable\n; \"tcVar\", the following tasks are performed:\n;   1. splits a potentially multi-page plot file into separate pages\n;   2. Converts each postscript page into a tiff file.\n;   3. Computes georeferencing info for each tiff file.\n;   4. Injects georeferencing and the timestamp into each tiff file\n;   5. Copies individual geotiffs into one multi-image geotiff.\n;\n; NOTE: this function causes the workstation to be closed and the plot output\n; to be flushed to the filesystem.\n;\nundef(\"wrf2geotiff_close\")\nprocedure wrf2geotiff_close(tcVar, wks:graphic)\nlocal plotFile, outputScale, wksId, tmpfile, tmpfileRoot, cmd, outStrings, quote, numPages, i, rotation, \\\n      cropStr, w, h, x, y, pageLX, pageRX, pageTY, pageBY, \\\n      outFilesRoot, suffix, plotFileLen, chr, multiTiff, multiGTiff, dataFile, proj4String\nbegin\n   if (_wrf2geotiff_DEBUG .eq. True) then\n       print(\"wrf2geotiff_close\")\n       print(tcVar)\n    end if \n\n   plotFile = tcVar@plotFilename\n   outputScale = tcVar@outputScale\n\n   ; generate a filename root for a set of tmp files, based on the workstation ID...\n   getvalues wks\n       \"wkGksWorkId\": wksId\n   end getvalues\n\n   ; We need to ensure the plotfile is closed before attempting to split it up; \n   ; otherwise, the \"psplit\" command fails.\n   destroy(wks)\n\n   ; split the postscript plotfile into multiple pieces...\n   tmpfileRoot = \"/tmp/tiffcap\" + wksId + \"_\"\n   cmd = \"psplit \" + plotFile + \" \" + tmpfileRoot\n   print(cmd)\n   system(cmd)\n\n     ;;; Attempts to use Imagemagick's tools to split PS file, or to perform operations\n     ;;; on frames within a multi=page file have generally been unsuccessful (perhaps missing\n     ;;; something?)\n     ;;; tmpfileRoot = \"/tmp/tiffcap\" + wksId + \"_\"\n     ;;; cmd = \"convert -page letter +adjoin \" + plotFile + \" ps:\" + tmpfileRoot + \"%04d.ps\"\n     ;;; system(cmd)\n\n   ; Container for the strings to be written to the vapor-data file...\n   outStrings = new(tcVar@numPlots, string)\n   quote = inttochar(34)\n\n   numPages = tcVar@numPlots\n   do i=0,numPages-1\n\n      ;\n      ; pick up the next postscript page a convert to a tiff, rotating if necessary...\n      ;\n      tmpfile = tmpfileRoot + sprinti(\"%0.4i\", i+1)\n      rotation = 0\n      if (tcVar@orient(i) .ne. 0) then\n          rotation = -90\n      end if\n\n      cropStr = \"\"\n      if (tcVar@cropFrame(i) .eq.True) then\n          w = (tcVar@pageMaxX(i) - tcVar@pageMinX(i)) * outputScale\n          h = (tcVar@pageMaxY(i) - tcVar@pageMinY(i)) * outputScale\n          x = tcVar@pageMinX(i) * outputScale\n          y = (_wrf2geotiff_PSMAXY - tcVar@pageMaxY(i)) * outputScale\n          cropStr = \" -crop \" + w + \"x\" + h + \"+\" + x + \"+\" + y + \" \"\n      end if\n\n      ; Note the ordering of the -density and -crop arguments is important in older versions\n      ; of Imagemagick (e.g., 6.0.7 04/20/08).  As of vers. 6.2.8 06/10/08, the ordering does not\n      ; matter.\n      cmd = \"convert  -depth 8 -rotate \" + rotation + \" -density \" + (72*outputScale) + \" \" + cropStr + \" \" \n      cmd = cmd +  \" \" + tmpfile + \".ps tiff:\" + tmpfile + \".tiff\"\n      print(cmd)\n      system(cmd)\n\n      if (tcVar@cropFrame(i) .eq. True) then\n         pageLX = 0.\n         pageRX = 1.\n         pageBY = 0.\n         pageTY = 1.\n      else\n         ; compute \"normalized\" page coordinates of the plot corners...\n         pageLX = tcVar@pageMinX(i) / _wrf2geotiff_PSMAXX \n         pageRX = tcVar@pageMaxX(i) / _wrf2geotiff_PSMAXX\n         pageBY = tcVar@pageMinY(i) / _wrf2geotiff_PSMAXY\n         pageTY = tcVar@pageMaxY(i) / _wrf2geotiff_PSMAXY\n      end if \n\n      if (tcVar@disableGeoTags) then\n          outStrings(i) = tcVar@times(i)\n      else\n          outStrings(i) = tcVar@times(i) + \" \" + tcVar@minLon(i) + \" \" + tcVar@minLat(i) + \" \" + \\\n             tcVar@maxLon(i) + \" \" + tcVar@maxLat(i) + \" \" + pageLX + \" \" + pageBY + \" \" + \\\n             pageRX + \" \" + pageTY\n      end if\n   end do\n\n   ; need a filename root for naming several files in the following...\n   outFilesRoot = plotFile\n   suffix = indStrSubset(str_lower(plotFile), \".ps\") \n   ; furthermore, make sure our substring is indeed a suffix...\n   plotFileLen = strlen(plotFile)\n   if (.not.any(ismissing(suffix)) .and. ((plotFileLen-1) .eq. suffix(dimsizes(suffix)-1))) then\n       ; a bit messy; is there a better way to do these string ops?\n       chr = stringtocharacter(plotFile)\n       outFilesRoot = charactertostring( chr(0:suffix(0)-1) )\n   end if\n\n   multiTiff = outFilesRoot + \"_temp.tiff\"\n   multiGTiff = outFilesRoot + \".tiff\"\n   dataFile = outFilesRoot + \".dat\"\n\n   ; append all the intermediate tiff files into one multi-image tiff...\n   cmd = \"convert -adjoin \" + tmpfileRoot + \"[0-9]*.tiff \" + multiTiff\n   print(cmd)\n   system(cmd)\n\n   ; write the georeferencing info into a temporary file...\n   asciiwrite(dataFile, outStrings)\n   \n   ; call a custom utility to create a geotiff...\n\n   if (tcVar@disableGeoTags) then\n       cmd = \"tiff2geotiff  -M \" + dataFile + \" \" + multiTiff + \" \" + multiGTiff\n   else\n       proj4String = _wrf2geotiff_validateProj4String(tcVar)\n       cmd = \"tiff2geotiff -4 \" + proj4String + \" -m \" + dataFile + \" \" + \\\n           multiTiff + \" \" + multiGTiff\n   end if\n   print(cmd)\n   system(cmd)\n\n   ; cleanup\n   cmd = \"rm -f \" + tmpfileRoot + \"[0-9]*.* \" + dataFile + \" \" + multiTiff\n   print(cmd)\n   if (_wrf2geotiff_DEBUG .ne. True) then  \n       system(cmd)\n   end if\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_CrossSection2.ncl",
    "content": "\n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n;   Plot data on a cross section\n;   This script will plot data from a a given point A to point B\n;   Vertical coordinate is height\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\nbegin\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n  a = addfile(\"./wrfout_d01_2000-01-24_12:00:00.nc\",\"r\")\n\n\n; We generate plots, but what kind do we prefer?\n  type = \"x11\"\n; type = \"pdf\"\n; type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_CrossSection2\")\n\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n\n  pltres = True \n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  FirstTime = True\n  times  = wrf_user_list_times(a)  ; get times in the file\n  ntimes = dimsizes(times)         ; number of times in the file\n\n  mdims = getfilevardimsizes(a,\"P\") ; get some dimension sizes for the file\n  nd = dimsizes(mdims)\n\n;---------------------------------------------------------------\n\n  do it = 0,ntimes-1,2             ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n    tc  = wrf_user_getvar(a,\"tc\",it)     ; T in C\n    rh = wrf_user_getvar(a,\"rh\",it)      ; relative humidity\n    z   = wrf_user_getvar(a, \"z\",it)     ; grid point height\n\n    if ( FirstTime ) then                ; get height info for labels\n      zmin = 0.\n      zmax = max(z)/1000.\n      nz   = floattoint(zmax/2 + 1)\n      FirstTime = False\n    end if\n\n;---------------------------------------------------------------\n\n    do ip = 1, 3      \t; we are doing 3 plots, specifying different start and end points\n\n        opts = True            ; setting start and end times\n        plane = new(4,float)\n\n        if(ip .eq. 1) then\n          plane = (/  40,81,  259,81  /) ; start x;y & end x;y point\n        end if\n        if(ip .eq. 2) then\n          plane = (/  130,1, 130,162  /) ; start x;y & end x;y point\n        end if\n        if(ip .eq. 3) then\n          plane = (/   49,1, 210,162  /) ; start x;y & end x;y point\n        end if\n\n\n        rh_plane = wrf_user_intrp3d(rh,z,\"v\",plane,0.,opts)\n        tc_plane = wrf_user_intrp3d(tc,z,\"v\",plane,0.,opts)\n\n        dim = dimsizes(rh_plane)                      ; Find the data span - for use in labels\n        zspan = dim(0)\n\n\n      ; Options for XY Plots\n        opts_xy                         = res\n        opts_xy@tiYAxisString           = \"Height (km)\"\n        opts_xy@AspectRatio             = 0.75\n        opts_xy@cnMissingValPerimOn     = True\n        opts_xy@cnMissingValFillColor   = 0\n        opts_xy@cnMissingValFillPattern = 11\n        opts_xy@tmYLMode                = \"Explicit\"\n        opts_xy@tmYLValues              = fspan(0,zspan,nz)                    ; Create tick marks\n        opts_xy@tmYLLabels              = sprintf(\"%.1f\",fspan(zmin,zmax,nz))  ; Create labels\n        opts_xy@tiXAxisFontHeightF      = 0.020\n        opts_xy@tiYAxisFontHeightF      = 0.020\n        opts_xy@tmXBMajorLengthF        = 0.02\n        opts_xy@tmYLMajorLengthF        = 0.02\n        opts_xy@tmYLLabelFontHeightF    = 0.015\n        opts_xy@PlotOrientation         = tc_plane@Orientation\n\n\n      ; Plotting options for RH\n        opts_rh = opts_xy\n        opts_rh@pmLabelBarOrthogonalPosF = -0.07\n        opts_rh@ContourParameters       = (/ 10., 90., 10. /)\n        opts_rh@cnFillOn                = True\n        opts_rh@cnFillColors            = (/\"White\",\"White\",\"White\", \\\n                                            \"White\",\"Chartreuse\",\"Green\", \\\n                                            \"Green3\",\"Green4\", \\\n                                            \"ForestGreen\",\"PaleGreen4\"/)\n\n      ; Plotting options for Temperature\n        opts_tc = opts_xy\n        opts_tc@cnInfoLabelOrthogonalPosF = 0.00\n        opts_tc@ContourParameters  = (/ 5. /)\n\n\n      ; Get the contour info for the rh and temp\n        contour_tc = wrf_contour(a,wks,tc_plane,opts_tc)\n        contour_rh = wrf_contour(a,wks,rh_plane,opts_rh)\n\n\n      ; MAKE PLOTS         \n        plot = wrf_overlays(a,wks,(/contour_rh,contour_tc/),pltres)\n\n      ; Delete options and fields, so we don't have carry over\n        delete(opts_tc)\n        delete(opts_rh)\n        delete(tc_plane)\n        delete(rh_plane)\n\n    end do  ; make next cross section\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  end do        ; END OF TIME LOOP\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_CrossSection2_Final.ncl",
    "content": "\n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n;   Plot data on a cross section\n;   This script will plot data from a a given point A to point B\n;   Modified to produce only one vertical plot, in the X-Z plane\n;   at grid y-coordinate 84\n;   Vertical coordinate is height\n\n; From the \"Using NCL with VAPOR to Visualize WRF-ARW data\"\n; tutorial.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\n; Load the wrf2geotiff.ncl library from VAPOR installation:\nload \"$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl\"\n\nbegin\n;\n; The WRF ARW input file.  \n; Use all the Jangmi typhoon files:\n  wrffiles = systemfunc(\"ls wrfout_d02_2008-09-28*\")\n  numFiles = dimsizes(wrffiles)\n  do i = 0, numFiles -1\n    wrffiles(i) = wrffiles(i)+\".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; We generate plots, but what kind do we prefer?\n; type = \"x11\"\n; type = \"pdf\"\n  type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_CrossSection2\")\n\n; Create the opaque pointer for wrf2geotiff:\n  wrf2gtiff = wrf2geotiff_open(wks)\n\n; Since this is a vertical plot, turn off georeferencing:\n  wrf2geotiff_disableGeoTags(wrf2gtiff)\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n\n  pltres = True \n\n; Control the frame advance manually:\n  pltres@gsnFrame = False\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  FirstTime = True\n; What times and how many time steps are in the data set?\n  do ifile = 0, numFiles-1 ; LOOP OVER FILES\n\n    a = inpFiles[ifile]\n    times  = wrf_user_list_times(a)  ; get times in the file\n    ntimes = dimsizes(times)         ; number of times in the file\n\n    mdims = getfilevardimsizes(a,\"P\") ; get some dimension sizes for the file\n    nd = dimsizes(mdims)\n\n;---------------------------------------------------------------\n; Modify time loop to loop over all times in the files:\n  do it = 0,ntimes-1               ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n    tc  = wrf_user_getvar(a,\"tc\",it)     ; T in C\n    rh = wrf_user_getvar(a,\"rh\",it)      ; relative humidity\n    z   = wrf_user_getvar(a, \"z\",it)     ; grid point height\n\n    if ( FirstTime ) then                ; get height info for labels\n      zmin = 0.\n      zmax = max(z)/1000.\n      nz   = floattoint(zmax/2 + 1)\n      FirstTime = False\n    end if\n\n;---------------------------------------------------------------\n; Modify loop over plots to just do one plot\n    ip = 1 ; Just do the one (constant y coord) plot\n\n        opts = True            ; setting start and end times\n        plane = new(4,float)\n\n        if(ip .eq. 1) then\n\n; Modify start and end x coordinates to match WRF D02 grid size:\n; The jangmi data is on a grid from 0 to 200\n          plane = (/ 0,84, 200,84 /) ; start x;y & end x;y point\n\n        end if\n        if(ip .eq. 2) then\n          plane = (/  130,1, 130,162  /) ; start x;y & end x;y point\n        end if\n        if(ip .eq. 3) then\n          plane = (/   49,1, 210,162  /) ; start x;y & end x;y point\n        end if\n\n\n        rh_plane = wrf_user_intrp3d(rh,z,\"v\",plane,0.,opts)\n        tc_plane = wrf_user_intrp3d(tc,z,\"v\",plane,0.,opts)\n\n        dim = dimsizes(rh_plane)                      ; Find the data span - for use in labels\n        zspan = dim(0)\n\n\n      ; Options for XY Plots\n        opts_xy                         = res\n        opts_xy@tiYAxisString           = \"Height (km)\"\n        opts_xy@AspectRatio             = 0.75\n        opts_xy@cnMissingValPerimOn     = True\n        opts_xy@cnMissingValFillColor   = 0\n        opts_xy@cnMissingValFillPattern = 11\n        opts_xy@tmYLMode                = \"Explicit\"\n        opts_xy@tmYLValues              = fspan(0,zspan,nz)                    ; Create tick marks\n        opts_xy@tmYLLabels              = sprintf(\"%.1f\",fspan(zmin,zmax,nz))  ; Create labels\n        opts_xy@tiXAxisFontHeightF      = 0.020\n        opts_xy@tiYAxisFontHeightF      = 0.020\n        opts_xy@tmXBMajorLengthF        = 0.02\n        opts_xy@tmYLMajorLengthF        = 0.02\n        opts_xy@tmYLLabelFontHeightF    = 0.015\n        opts_xy@PlotOrientation         = tc_plane@Orientation\n\n\n      ; Plotting options for RH\n        opts_rh = opts_xy\n        opts_rh@pmLabelBarOrthogonalPosF = -0.07\n        opts_rh@ContourParameters       = (/ 10., 90., 10. /)\n        opts_rh@cnFillOn                = True\n        opts_rh@cnFillColors            = (/\"White\",\"White\",\"White\", \\\n                                            \"White\",\"Chartreuse\",\"Green\", \\\n                                            \"Green3\",\"Green4\", \\\n                                            \"ForestGreen\",\"darkorchid3\"/)\n\n      ; Plotting options for Temperature\n        opts_tc = opts_xy\n        opts_tc@cnInfoLabelOrthogonalPosF = 0.00\n        opts_tc@ContourParameters  = (/ 5. /)\n\n\n      ; Get the contour info for the rh and temp\n        contour_tc = wrf_contour(a,wks,tc_plane,opts_tc)\n        contour_rh = wrf_contour(a,wks,rh_plane,opts_rh)\n\n\n      ; MAKE PLOTS         \n        plot = wrf_overlays(a,wks,(/contour_rh,contour_tc/),pltres)\n\n      ; save the info for the geotiff, and end the frame.\n      ; Do crop to bounds\n        wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, True)\n        frame(wks)\n\n      ; Delete options and fields, so we don't have carry over\n        delete(opts_tc)\n        delete(opts_rh)\n        delete(tc_plane)\n        delete(rh_plane)\n\n; Comment out the loop over ip:\n;  end do ; make next cross section\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    end do        ; END OF TIME LOOP\n  end do        ; END OF FILE LOOP\n\n; Close wrf2geotiff:\n  wrf2geotiff_close(wrf2gtiff,wks)\n\nend\n\n"
  },
  {
    "path": "share/examples/NCL/wrf_CrossSection2_FirstMod.ncl",
    "content": "\n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n;   Plot data on a cross section\n;   This script will plot data from a a given point A to point B\n;   Modified to produce only one vertical plot, in the X-Z plane\n;   at grid y-coordinate 84\n;   Vertical coordinate is height\n\n; From the \"Using NCL with VAPOR to Visualize WRF-ARW data\"\n; tutorial.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\nbegin\n;\n; The WRF ARW input file.  \n; Use all the Jangmi typhoon files:\n  wrffiles = systemfunc(\"ls wrfout_d02_2008-09-28*\")\n  numFiles = dimsizes(wrffiles)\n  do i = 0, numFiles -1\n    wrffiles(i) = wrffiles(i)+\".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; We generate plots, but what kind do we prefer?\n  type = \"x11\"\n; type = \"pdf\"\n; type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_CrossSection2\")\n\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n\n  pltres = True \n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  FirstTime = True\n; What times and how many time steps are in the data set?\n  do ifile = 0, numFiles-1 ; LOOP OVER FILES\n\n    a = inpFiles[ifile]\n    times  = wrf_user_list_times(a)  ; get times in the file\n    ntimes = dimsizes(times)         ; number of times in the file\n\n    mdims = getfilevardimsizes(a,\"P\") ; get some dimension sizes for the file\n    nd = dimsizes(mdims)\n\n;---------------------------------------------------------------\n; Modify time loop to loop over all times in the files:\n  do it = 0,ntimes-1               ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n    tc  = wrf_user_getvar(a,\"tc\",it)     ; T in C\n    rh = wrf_user_getvar(a,\"rh\",it)      ; relative humidity\n    z   = wrf_user_getvar(a, \"z\",it)     ; grid point height\n\n    if ( FirstTime ) then                ; get height info for labels\n      zmin = 0.\n      zmax = max(z)/1000.\n      nz   = floattoint(zmax/2 + 1)\n      FirstTime = False\n    end if\n\n;---------------------------------------------------------------\n; Modify loop over plots to just do one plot\n    ip = 1 ; Just do the one (constant y coord) plot\n\n        opts = True            ; setting start and end times\n        plane = new(4,float)\n\n        if(ip .eq. 1) then\n\n; Modify start and end x coordinates to match WRF D02 grid size:\n; The jangmi data is on a grid from 0 to 200\n          plane = (/ 0,84, 200,84 /) ; start x;y & end x;y point\n\n        end if\n        if(ip .eq. 2) then\n          plane = (/  130,1, 130,162  /) ; start x;y & end x;y point\n        end if\n        if(ip .eq. 3) then\n          plane = (/   49,1, 210,162  /) ; start x;y & end x;y point\n        end if\n\n\n        rh_plane = wrf_user_intrp3d(rh,z,\"v\",plane,0.,opts)\n        tc_plane = wrf_user_intrp3d(tc,z,\"v\",plane,0.,opts)\n\n        dim = dimsizes(rh_plane)                      ; Find the data span - for use in labels\n        zspan = dim(0)\n\n\n      ; Options for XY Plots\n        opts_xy                         = res\n        opts_xy@tiYAxisString           = \"Height (km)\"\n        opts_xy@AspectRatio             = 0.75\n        opts_xy@cnMissingValPerimOn     = True\n        opts_xy@cnMissingValFillColor   = 0\n        opts_xy@cnMissingValFillPattern = 11\n        opts_xy@tmYLMode                = \"Explicit\"\n        opts_xy@tmYLValues              = fspan(0,zspan,nz)                    ; Create tick marks\n        opts_xy@tmYLLabels              = sprintf(\"%.1f\",fspan(zmin,zmax,nz))  ; Create labels\n        opts_xy@tiXAxisFontHeightF      = 0.020\n        opts_xy@tiYAxisFontHeightF      = 0.020\n        opts_xy@tmXBMajorLengthF        = 0.02\n        opts_xy@tmYLMajorLengthF        = 0.02\n        opts_xy@tmYLLabelFontHeightF    = 0.015\n        opts_xy@PlotOrientation         = tc_plane@Orientation\n\n\n      ; Plotting options for RH\n        opts_rh = opts_xy\n        opts_rh@pmLabelBarOrthogonalPosF = -0.07\n        opts_rh@ContourParameters       = (/ 10., 90., 10. /)\n        opts_rh@cnFillOn                = True\n        opts_rh@cnFillColors            = (/\"White\",\"White\",\"White\", \\\n                                            \"White\",\"Chartreuse\",\"Green\", \\\n                                            \"Green3\",\"Green4\", \\\n                                            \"ForestGreen\",\"darkorchid3\"/)\n\n      ; Plotting options for Temperature\n        opts_tc = opts_xy\n        opts_tc@cnInfoLabelOrthogonalPosF = 0.00\n        opts_tc@ContourParameters  = (/ 5. /)\n\n\n      ; Get the contour info for the rh and temp\n        contour_tc = wrf_contour(a,wks,tc_plane,opts_tc)\n        contour_rh = wrf_contour(a,wks,rh_plane,opts_rh)\n\n\n      ; MAKE PLOTS         \n        plot = wrf_overlays(a,wks,(/contour_rh,contour_tc/),pltres)\n\n      ; Delete options and fields, so we don't have carry over\n        delete(opts_tc)\n        delete(opts_rh)\n        delete(tc_plane)\n        delete(rh_plane)\n\n; Comment out the loop over ip:\n;  end do ; make next cross section\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    end do        ; END OF TIME LOOP\n  end do        ; END OF FILE LOOP\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_EtaLevels.ncl",
    "content": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Adapted from the script \"wrf_EtaLevels.ncl\" at:\n;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/LEVELS_MODEL/wrf_EtaLevels.htm\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n \n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\nload \"$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl\"\n\nbegin\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; Add your own data here....\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n  ;;;a = addfile(\"./wrfout_d01_2000-01-24_12:00:00.nc\",\"r\")\n  wrffiles = systemfunc(\"ls ./HurricaneIKE/wrfout_d03_2008*\")\n  numFiles = dimsizes(wrffiles)\n  do i=0,numFiles-1\n    wrffiles(i) = wrffiles(i) + \".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; Output type must be postscript...\n  type = \"ps\"    \n  wks = gsn_open_wks(type,\"plt_EtaLevels\")\n\n  ; Do we want the Geotiffs cropped?\n  if (.not.isdefined(\"cropPlot\")) then\n      cropPlot = True\n  end if\n\n  ; initialize our tiff-capture process...\n  wrf2gtiff = wrf2geotiff_open(wks)\n\n; Set some Basic Plot options\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n\n  pltres = True\n  pltres@FramePlot = False\n  mpres = True\n  mpres0 = True\n  mpres0@mpGeophysicalLineColor = \"Black\"\n  mpres0@mpNationalLineColor    = \"Black\"\n  mpres0@mpUSStateLineColor     = \"Black\"\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n\n; loop over files...\ndo ifile=0, numFiles-1\n  a = inpFiles[ifile]\n  ; What times and how many time steps are in the data set?\n  times  = wrf_user_list_times(a)  ; get times in the file\n  ntimes = dimsizes(times)         ; number of times in the file\n  \n  do it = 0,ntimes-1,2             ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need        \n\n    th  = wrf_user_getvar(a,\"theta\",it)   ; theta\n    qv  = wrf_user_getvar(a,\"QVAPOR\",it)  ; Qv\n      qv = qv*1000.\n      qv@units = \"g/kg\"\n\n    u   = wrf_user_getvar(a,\"ua\",it)      ; u averaged to mass points\n    v   = wrf_user_getvar(a,\"va\",it)      ; v averaged to mass points\n      spd = (u*u + v*v)^(0.5)             ; speed in m/sec\n      spd@description = \"Wind Speed\"\n      spd@units = \"m/s\"\n      u = u*1.94386                       ; winds now in kts\n      v = v*1.94386                       ; winds now in kts\n      u@units = \"kts\"\n      v@units = \"kts\"\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    dimsv = dimsizes(th)          ; Get levels\n    ;; original script looped over levels...\n    ;;;do level =0,dimsv(0)-1,5      ; LOOP OVER LEVELS\n       level = 9\n\n       display_level = level + 1\n       res@PlotLevelID = \"Eta Level  \" + display_level\n\n\n     ; Theta\n       ;opts = res\n       ;opts@cnLineColor         = \"Red\"\n       ;opts@cnInfoLabelOn       = False\n       ;opts@lbLabelsOn          = False\n       ;opts@ContourParameters   = (/ 5.0 /)\n       ;opts@gsnContourLineThicknessesScale = 2.0\n       ;contour = wrf_contour(a,wks,th(level,:,:),opts)\n       ;plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres0)\n       ;delete(opts)\n   \n     ; Qv\n       ;opts = res\n       ;opts@cnLineColor         = \"Blue\"\n       ;opts@cnFillOn            = True\n       ;opts@lbLabelsOn          = False\n       ;contour = wrf_contour(a,wks,qv(level,:,:),opts)\n       ;plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres)\n       ;delete(opts)\n   \n     ; Wind Vectors and Speed\n       opts = res\n       opts@ContourParameters = (/ 15., 60., 5. /)\n       opts@cnFillOn          = True\n       contour = wrf_contour(a,wks,spd(level,:,:),opts)\n       delete(opts)\n   \n       opts = res\n       opts@FieldTitle        = \"Wind\"       ; Overwrite Field Title\n       opts@NumVectors        = 47           ; wind barb density\n       vector =  wrf_vector(a,wks,u(level,:,:),v(level,:,:),opts)\n       delete(opts)\n\n       plot = wrf_map_overlays(a,wks,(/contour, vector/),pltres,mpres)\n       wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, cropPlot)\n       frame(wks)  ; Now that we are done drawing, draw the frame\n\n\n    ;;;;end do      ; END OF LEVEL LOOP\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  end do        ; END OF TIME LOOP\nend do          ; END OF FILES LOOP\n\nwrf2geotiff_close(wrf2gtiff, wks)   \nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_Height.ncl",
    "content": "; The following NCL script was copied from the WRF/NCL site:\n; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/NCL_examples.htm\n\n; Example script to produce plots for a WRF real-data run,\n; with the ARW coordinate dynamics option.\n; Interpolating to specified height levels\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\nbegin\n;\n; The WRF ARW input file.\n; This needs to have a \".nc\" appended, so just do it.\n  a = addfile(\"./wrfout_d01_2000-01-24_12:00:00.nc\",\"r\")\n\n; We generate plots, but what kind do we prefer?\n  type = \"x11\"\n; type = \"pdf\"\n; type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_HeightLevel\")\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n  res@Footer = False\n\n  pltres = True\n  mpres = True\n  mpres@mpGeophysicalLineColor = \"Black\"\n  mpres@mpNationalLineColor = \"Black\"\n  mpres@mpUSStateLineColor = \"Black\"\n  mpres@mpGridLineColor = \"Black\"\n  mpres@mpLimbLineColor = \"Black\"\n  mpres@mpPerimLineColor = \"Black\"\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; What times and how many time steps are in the data set?\n\n  times = wrf_user_list_times(a) ; get times in the file\n  ntimes = dimsizes(times) ; number of times in the file\n\n; The specific height levels that we want the data interpolated to.\n  height_levels = (/ 250., 2000./) ; height levels to plot - in meter\n  nlevels = dimsizes(height_levels) ; number of height levels\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  do it = 0,ntimes-1,2 ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it) ; Set Valid time to use on plots\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need\n\n    tc = wrf_user_getvar(a,\"tc\",it) ; T in C\n    u = wrf_user_getvar(a,\"ua\",it) ; u averaged to mass points\n    v = wrf_user_getvar(a,\"va\",it) ; v averaged to mass points\n    p = wrf_user_getvar(a, \"pressure\",it) ; pressure is our vertical coordinate\n    z = wrf_user_getvar(a, \"z\",it) ; grid point height\n    rh = wrf_user_getvar(a,\"rh\",it) ; relative humidity\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    do level = 0,nlevels-1 ; LOOP OVER LEVELS\n\n      height = height_levels(level)\n\n      p_plane = wrf_user_intrp3d( p,z,\"h\",height,0.,False)\n      tc_plane = wrf_user_intrp3d(tc,z,\"h\",height,0.,False)\n      rh_plane = wrf_user_intrp3d(rh,z,\"h\",height,0.,False)\n      u_plane = wrf_user_intrp3d( u,z,\"h\",height,0.,False)\n      v_plane = wrf_user_intrp3d( v,z,\"h\",height,0.,False)\n\n      u_plane = u_plane*1.94386 ; kts\n      v_plane = v_plane*1.94386 ; kts\n      u_plane@units = \"kts\"\n      v_plane@units = \"kts\"\n\n; Plotting options for T\n      opts = res\n      opts@cnLineColor = \"Red\"\n      opts@ContourParameters = (/ 5.0 /)\n      opts@cnInfoLabelOrthogonalPosF = 0.07 ; offset second label info\n      opts@gsnContourLineThicknessesScale = 2.0\n      contour_tc = wrf_contour(a,wks,tc_plane,opts)\n      delete(opts)\n\n; Plotting options for Pressure\n      opts = res\n      opts@cnLineColor = \"Blue\"\n      opts@gsnContourLineThicknessesScale = 3.0\n      contour_p = wrf_contour(a,wks,p_plane,opts)\n      delete(opts)\n\n; Plotting options for RH\n      opts = res\n      opts@cnFillOn = True\n      opts@ContourParameters = (/ 10., 90., 10./)\n      opts@cnFillColors = (/\"White\",\"White\",\"White\", \\\n\t\t\"White\",\"Chartreuse\",\"Green\",\\\n\t\t\"Green3\",\"Green4\", \\\n\t\t\"ForestGreen\",\"PaleGreen4\"/)\n      contour_rh = wrf_contour(a,wks,rh_plane,opts)\n      delete(opts)\n\n; Plotting options for Wind Vectors\n      opts = res\n      opts@FieldTitle = \"Wind\" ; overwrite Field Title\n      opts@NumVectors = 47 ; wind barb density\n      vector = wrf_vector(a,wks,u_plane,v_plane,opts)\n      delete(opts)\n\n; MAKE PLOTS\n      plot = wrf_map_overlays(a,wks,(/contour_rh,contour_tc,contour_p, \\\n                   vector/),pltres,mpres)\n\n    end do ; END OF LEVEL LOOP\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  end do ; END OF TIME LOOP\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_Height_Final.ncl",
    "content": "\n; Example script to produce plots for a WRF real-data run,\n; with the ARW coordinate dynamics option.\n; Interpolating to specified height levels\n\n; From the \"Using NCL with VAPOR to Visualize WRF-ARW data\"\n; tutorial.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\n; Load the wrf2geotiff library.\n; The wrf2geotiff library is installed with VAPOR:\nload \"$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl\"\nbegin\n;\n; The WRF ARW input file.\n; This needs to have a \".nc\" appended, so just do it.\n\n; Create a list of all the WRF output files we are using\n; from the typhoon Jangmi simulation:\n  wrffiles = systemfunc(\"ls wrfout_d02_2008-09-28*\")\n  numFiles = dimsizes(wrffiles)\n  do i = 0, numFiles-1\n    wrffiles(i) = wrffiles(i) + \".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; We generate plots, but what kind do we prefer?\n\n; When using wrf2geotiff, type must be ps\n; type = \"x11\"\n; type = \"pdf\"\n  type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_HeightLevel\")\n; Create the wrf2gtiff opaque pointer, which will\n; be referenced in all geotiff changes\n  wrf2gtiff = wrf2geotiff_open(wks)\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n  res@Footer = False\n\n; For wrf2geotiff we need to control frame advance:\n  pltres = True\n  pltres@gsnFrame = False\n \n  pltres = True\n  mpres = True\n  mpres@mpGeophysicalLineColor = \"Black\"\n  mpres@mpNationalLineColor = \"Black\"\n  mpres@mpUSStateLineColor = \"Black\"\n  mpres@mpGridLineColor = \"Black\"\n  mpres@mpLimbLineColor = \"Black\"\n  mpres@mpPerimLineColor = \"Black\"\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; What times and how many time steps are in the data set?\n  do ifile = 0, numFiles-1 ; LOOP OVER FILES\n    a = inpFiles[ifile]\n    times = wrf_user_list_times(a) ; get times in the file\n    ntimes = dimsizes(times) ; number of times in the file\n\n; The specific height levels that we want the data interpolated to.\n\n; We use height of 5000m in the plot for VAPOR\n; That height is near the top of the typhoon\n   height_levels = (/ 250., 5000./) ; height levels to plot - in meter\n   nlevels = dimsizes(height_levels) ; number of height levels\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Modify the time loop to include all time steps, not just every odd one\n    do it = 0,ntimes-1 ; TIME LOOP\n\n      print(\"Working on time: \" + times(it) )\n      res@TimeLabel = times(it) ; Set Valid time to use on plots\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need\n\n     tc = wrf_user_getvar(a,\"tc\",it) ; T in C\n     u = wrf_user_getvar(a,\"ua\",it) ; u averaged to mass points\n     v = wrf_user_getvar(a,\"va\",it) ; v averaged to mass points\n     p = wrf_user_getvar(a, \"pressure\",it) ; pressure is our vertical coordinate\n     z = wrf_user_getvar(a, \"z\",it) ; grid point height\n     rh = wrf_user_getvar(a,\"rh\",it) ; relative humidity\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Modify loop over level to just do one level = 1\n     level = 1 ; just one level for the georeferenced plot\n\n      height = height_levels(level)\n\n      p_plane = wrf_user_intrp3d( p,z,\"h\",height,0.,False)\n      tc_plane = wrf_user_intrp3d(tc,z,\"h\",height,0.,False)\n      rh_plane = wrf_user_intrp3d(rh,z,\"h\",height,0.,False)\n      u_plane = wrf_user_intrp3d( u,z,\"h\",height,0.,False)\n      v_plane = wrf_user_intrp3d( v,z,\"h\",height,0.,False)\n\n      u_plane = u_plane*1.94386 ; kts\n      v_plane = v_plane*1.94386 ; kts\n      u_plane@units = \"kts\"\n      v_plane@units = \"kts\"\n\n; Plotting options for T\n      opts = res\n      opts@cnLineColor = \"Red\"\n      opts@ContourParameters = (/ 5.0 /)\n      opts@cnInfoLabelOrthogonalPosF = 0.07 ; offset second label info\n      opts@gsnContourLineThicknessesScale = 2.0\n      contour_tc = wrf_contour(a,wks,tc_plane,opts)\n      delete(opts)\n\n; Plotting options for Pressure\n      opts = res\n      opts@cnLineColor = \"Blue\"\n      opts@gsnContourLineThicknessesScale = 3.0\n      contour_p = wrf_contour(a,wks,p_plane,opts)\n      delete(opts)\n\n; Plotting options for RH\n      opts = res\n      opts@cnFillOn = True\n      opts@ContourParameters = (/ 10., 90., 10./)\n      opts@cnFillColors = (/\"White\",\"White\",\"White\", \\\n\t\t\"White\",\"Chartreuse\",\"Green\",\\\n\t\t\"Green3\",\"Green4\", \\\n\t\t\"ForestGreen\",\"darkorchid3\"/)\n      contour_rh = wrf_contour(a,wks,rh_plane,opts)\n      delete(opts)\n\n; Plotting options for Wind Vectors\n      opts = res\n      opts@FieldTitle = \"Wind\" ; overwrite Field Title\n      opts@NumVectors = 47 ; wind barb density\n      vector = wrf_vector(a,wks,u_plane,v_plane,opts)\n      delete(opts)\n\n; MAKE PLOTS\n      plot = wrf_map_overlays(a,wks,(/contour_rh,contour_tc,contour_p, \\\n            vector/),pltres,mpres)\n\n; capture plot georeferencing information\n; then change the frame\n; Don’t crop (leave annotation intact)\n      wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, False)\n      frame(wks)\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    end do ; END OF TIME LOOP\n  end do ; END OF LEVEL LOOP\n\n; Call wrf2geotiff_close at the end\n  wrf2geotiff_close(wrf2gtiff, wks)\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_Height_FirstMod.ncl",
    "content": "\n; Example script to produce plots for a WRF real-data run,\n; with the ARW coordinate dynamics option.\n; Interpolating to specified height levels\n\n; From the \"Using NCL with VAPOR to Visualize WRF-ARW data\"\n; tutorial.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\nbegin\n;\n; The WRF ARW input file.\n; This needs to have a \".nc\" appended, so just do it.\n\n; Create a list of all the WRF output files we are using\n; from the typhoon Jangmi simulation:\n  wrffiles = systemfunc(\"ls wrfout_d02_2008-09-28*\")\n  numFiles = dimsizes(wrffiles)\n  do i = 0, numFiles-1\n    wrffiles(i) = wrffiles(i) + \".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; We generate plots, but what kind do we prefer?\n  type = \"x11\"\n; type = \"pdf\"\n; type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_HeightLevel\")\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n  res@Footer = False\n\n  pltres = True\n  mpres = True\n  mpres@mpGeophysicalLineColor = \"Black\"\n  mpres@mpNationalLineColor = \"Black\"\n  mpres@mpUSStateLineColor = \"Black\"\n  mpres@mpGridLineColor = \"Black\"\n  mpres@mpLimbLineColor = \"Black\"\n  mpres@mpPerimLineColor = \"Black\"\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; What times and how many time steps are in the data set?\n  do ifile = 0, numFiles-1 ; LOOP OVER FILES\n    a = inpFiles[ifile]\n    times = wrf_user_list_times(a) ; get times in the file\n    ntimes = dimsizes(times) ; number of times in the file\n\n; The specific height levels that we want the data interpolated to.\n\n; We use height of 5000m in the plot for VAPOR\n; That height is near the top of the typhoon\n   height_levels = (/ 250., 5000./) ; height levels to plot - in meter\n   nlevels = dimsizes(height_levels) ; number of height levels\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Modify the time loop to include all time steps, not just every odd one\n    do it = 0,ntimes-1 ; TIME LOOP\n\n      print(\"Working on time: \" + times(it) )\n      res@TimeLabel = times(it) ; Set Valid time to use on plots\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need\n\n     tc = wrf_user_getvar(a,\"tc\",it) ; T in C\n     u = wrf_user_getvar(a,\"ua\",it) ; u averaged to mass points\n     v = wrf_user_getvar(a,\"va\",it) ; v averaged to mass points\n     p = wrf_user_getvar(a, \"pressure\",it) ; pressure is our vertical coordinate\n     z = wrf_user_getvar(a, \"z\",it) ; grid point height\n     rh = wrf_user_getvar(a,\"rh\",it) ; relative humidity\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Modify loop over level to just do one level = 1\n     level = 1 ; just one level for the georeferenced plot\n\n      height = height_levels(level)\n\n      p_plane = wrf_user_intrp3d( p,z,\"h\",height,0.,False)\n      tc_plane = wrf_user_intrp3d(tc,z,\"h\",height,0.,False)\n      rh_plane = wrf_user_intrp3d(rh,z,\"h\",height,0.,False)\n      u_plane = wrf_user_intrp3d( u,z,\"h\",height,0.,False)\n      v_plane = wrf_user_intrp3d( v,z,\"h\",height,0.,False)\n\n      u_plane = u_plane*1.94386 ; kts\n      v_plane = v_plane*1.94386 ; kts\n      u_plane@units = \"kts\"\n      v_plane@units = \"kts\"\n\n; Plotting options for T\n      opts = res\n      opts@cnLineColor = \"Red\"\n      opts@ContourParameters = (/ 5.0 /)\n      opts@cnInfoLabelOrthogonalPosF = 0.07 ; offset second label info\n      opts@gsnContourLineThicknessesScale = 2.0\n      contour_tc = wrf_contour(a,wks,tc_plane,opts)\n      delete(opts)\n\n; Plotting options for Pressure\n      opts = res\n      opts@cnLineColor = \"Blue\"\n      opts@gsnContourLineThicknessesScale = 3.0\n      contour_p = wrf_contour(a,wks,p_plane,opts)\n      delete(opts)\n\n; Plotting options for RH\n      opts = res\n      opts@cnFillOn = True\n      opts@ContourParameters = (/ 10., 90., 10./)\n      opts@cnFillColors = (/\"White\",\"White\",\"White\", \\\n\t\t\"White\",\"Chartreuse\",\"Green\",\\\n\t\t\"Green3\",\"Green4\", \\\n\t\t\"ForestGreen\",\"darkorchid3\"/)\n      contour_rh = wrf_contour(a,wks,rh_plane,opts)\n      delete(opts)\n\n; Plotting options for Wind Vectors\n      opts = res\n      opts@FieldTitle = \"Wind\" ; overwrite Field Title\n      opts@NumVectors = 47 ; wind barb density\n      vector = wrf_vector(a,wks,u_plane,v_plane,opts)\n      delete(opts)\n\n; MAKE PLOTS\n      plot = wrf_map_overlays(a,wks,(/contour_rh,contour_tc,contour_p, \\\n            vector/),pltres,mpres)\n\n; comment out the end of the level loop:\n;end do ; END OF LEVEL LOOP\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    end do ; END OF TIME LOOP\n\n; End loop over files that we introduced:\n  end do ; END OF LEVEL LOOP\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_Precip.ncl",
    "content": "\n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\nbegin\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n  a = addfile(\"./wrfout_d01_2000-01-24_12:00:00.nc\",\"r\")\n\n\n; We generate plots, but what kind do we prefer?\n  type = \"x11\"\n  type = \"pdf\"\n; type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_Precip\")\n\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n\n  pltres = True\n  mpres = True\n  mpres@mpGeophysicalLineColor = \"Black\"\n  mpres@mpNationalLineColor    = \"Black\"\n  mpres@mpUSStateLineColor     = \"Black\"\n  mpres@mpGridLineColor        = \"Black\"\n  mpres@mpLimbLineColor        = \"Black\"\n  mpres@mpPerimLineColor       = \"Black\"\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; What times and how many time steps are in the data set?\n  FirstTime = True\n  times  = wrf_user_list_times(a)  ; get times in the file\n  ntimes = dimsizes(times)         ; number of times in the file\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  do it = 0,ntimes-1,2             ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    if (FirstTime) then            ; Save some times for tracking tendencies\n      times_sav = times(it)\n    end if\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need        \n\n    slp = wrf_user_getvar(a,\"slp\",it)  ; slp\n      wrf_smooth_2d( slp, 3 )            ; smooth slp\n\n  ; Get non-convective, convective and total precipitation\n  ; Calculate tendency values                               \n    rain_exp = wrf_user_getvar(a,\"RAINNC\",it)\n    rain_con = wrf_user_getvar(a,\"RAINC\",it)\n    rain_tot = rain_exp + rain_con\n    rain_tot@description = \"Total Precipitation\"\n\n    if( FirstTime ) then\n      if ( it .eq. 0 ) then\n        rain_exp_save = rain_exp\n        rain_con_save = rain_con\n        rain_tot_save = rain_tot\n      else\n        rain_exp_save = wrf_user_getvar(a,\"RAINNC\",it-1)\n        rain_con_save = wrf_user_getvar(a,\"RAINC\",it-1)\n        rain_tot_save = rain_exp_save + rain_con_save\n        FirstTime = False\n        times_sav = times(it-1)\n      end if\n    end if\n\n    rain_exp_tend = rain_exp - rain_exp_save\n    rain_con_tend = rain_con - rain_con_save\n    rain_tot_tend = rain_tot - rain_tot_save\n    rain_exp_tend@description = \"Explicit Precipitation Tendency\"\n    rain_con_tend@description = \"Param  Precipitation Tendency\"\n    rain_tot_tend@description = \"Precipitation Tendency\"\n\n  ; Bookkeeping, just to allow the tendency at the next time step\n    rain_exp_save = rain_exp\n    rain_con_save = rain_con\n    rain_tot_save = rain_tot\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    if( .not. FirstTime ) then     ; We will skip the first time\n\n      ; Plotting options for Sea Level Pressure\n        opts_psl = res          \n        opts_psl@ContourParameters = (/ 900., 1100., 2. /)\n        opts_psl@cnLineColor       = \"Blue\"\n        opts_psl@cnInfoLabelOn     = False\n        opts_psl@cnLineLabelFontHeightF = 0.01\n        opts_psl@cnLineLabelPerimOn = False\n        opts_psl@gsnContourLineThicknessesScale = 1.5\n        contour_psl = wrf_contour(a,wks,slp,opts_psl)\n        delete(opts_psl)\n    \n\n      ; Plotting options for Precipitation\n        opts_r = res                        \n        opts_r@UnitLabel            = \"mm\"\n        opts_r@cnLevelSelectionMode = \"ExplicitLevels\"\n        opts_r@cnLevels             = (/ .1, .2, .4, .8, 1.6, 3.2, 6.4, \\\n                                        12.8, 25.6, 51.2, 102.4/)\n        opts_r@cnFillColors         = (/\"White\",\"White\",\"DarkOliveGreen1\", \\\n                                        \"DarkOliveGreen3\",\"Chartreuse\", \\\n                                        \"Chartreuse3\",\"Green\",\"ForestGreen\", \\\n                                        \"Yellow\",\"Orange\",\"Red\",\"Violet\"/)\n        opts_r@cnInfoLabelOn        = False\n        opts_r@cnConstFLabelOn      = False\n        opts_r@cnFillOn             = True\n    \n\n      ; Total Precipitation (color fill)\n        contour_tot = wrf_contour(a,wks, rain_tot, opts_r)\n    \n      ; Precipitation Tendencies \n        opts_r@SubFieldTitle = \"from \" + times_sav + \" to \" + times(it)\n    \n        contour_tend = wrf_contour(a,wks, rain_tot_tend,opts_r) ; total (color)\n        contour_res = wrf_contour(a,wks,rain_exp_tend,opts_r)   ; exp (color)\n        opts_r@cnFillOn = False\n        opts_r@cnLineColor = \"Red4\"\n        contour_prm = wrf_contour(a,wks,rain_con_tend,opts_r)   ; con (red lines)\n        delete(opts_r)\n\n\n\n      ; MAKE PLOTS                                       \n\n        ; Total Precipitation \n          plot = wrf_map_overlays(a,wks,contour_tot,pltres,mpres)\n\n        ; Total Precipitation Tendency + SLP\n          plot = wrf_map_overlays(a,wks,(/contour_tend,contour_psl/),pltres,mpres)\n\n        ; Non-Convective and Convective Precipiation Tendencies\n          plot = wrf_map_overlays(a,wks,(/contour_res,contour_prm/),pltres,mpres)\n\n    end if    ; END IF FOR SKIPPING FIRST TIME\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    times_sav = times(it)\n    FirstTime = False\n  end do        ; END OF TIME LOOP\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_Precip_Final.ncl",
    "content": "\n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n\n; From the \"Using NCL with VAPOR to Visualize WRF-ARW data\"\n; tutorial.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\n; load the wrf2geotiff library from the VAPOR distribution:\nload \"$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl\"\n\nbegin\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n\n; Instead of selecting one file, make a variable that has\n; all the names of the WRF output files in it:\n; a = addfile(\"wrfout_d02_2008-09-28_00.nc\",\"r\")\n  wrffiles = systemfunc(\"ls wrfout_d02_2008-09-28*\")\n  numFiles = dimsizes(wrffiles)\n  do i = 0, numFiles-1\n    wrffiles(i) = wrffiles(i)+\".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; We generate plots, but what kind do we prefer?\n; For wrf2geotiff, the type MUST be ps\n; type = \"x11\"\n; type = \"pdf\"\n  type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_Precip\")\n\n; wrf2geotiff_open() creates the opaque pointer wrf2gtiff:\n  wrf2gtiff = wrf2geotiff_open(wks)\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n\n; Following are needed for control of frame advance:\n  pltres = True\n  pltres@gsnFrame = False\n\n  pltres = True\n  mpres = True\n  mpres@mpGeophysicalLineColor = \"Black\"\n  mpres@mpNationalLineColor    = \"Black\"\n  mpres@mpUSStateLineColor     = \"Black\"\n  mpres@mpGridLineColor        = \"Black\"\n  mpres@mpLimbLineColor        = \"Black\"\n  mpres@mpPerimLineColor       = \"Black\"\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; What times and how many time steps are in the data set?\n  FirstTime = True\n\n; Make a loop over all the files:\n  do ifile = 0,numFiles -1\n    a = inpFiles[ifile]\n\n    times  = wrf_user_list_times(a)  ; get times in the file\n    ntimes = dimsizes(times)         ; number of times in the file\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Loop over all the times, not just the odd times:\n; do it = 0,ntimes-1,2 ; TIME LOOP\n    do it = 0, ntimes-1 ; Modified to do every time step\n\n      print(\"Working on time: \" + times(it) )\n      if (FirstTime) then            ; Save some times for tracking tendencies\n        times_sav = times(it)\n      end if\n      res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need        \n\n    slp = wrf_user_getvar(a,\"slp\",it)  ; slp\n      wrf_smooth_2d( slp, 3 )            ; smooth slp\n\n  ; Get non-convective, convective and total precipitation\n  ; Calculate tendency values                               \n      rain_exp = wrf_user_getvar(a,\"RAINNC\",it)\n      rain_con = wrf_user_getvar(a,\"RAINC\",it)\n      rain_tot = rain_exp + rain_con\n      rain_tot@description = \"Total Precipitation\"\n\n      if( FirstTime ) then\n        if ( it .eq. 0 ) then\n          rain_exp_save = rain_exp\n          rain_con_save = rain_con\n          rain_tot_save = rain_tot\n        else\n          rain_exp_save = wrf_user_getvar(a,\"RAINNC\",it-1)\n          rain_con_save = wrf_user_getvar(a,\"RAINC\",it-1)\n          rain_tot_save = rain_exp_save + rain_con_save\n          FirstTime = False\n          times_sav = times(it-1)\n        end if\n      end if\n\n      rain_exp_tend = rain_exp - rain_exp_save\n      rain_con_tend = rain_con - rain_con_save\n      rain_tot_tend = rain_tot - rain_tot_save\n      rain_exp_tend@description = \"Explicit Precipitation Tendency\"\n      rain_con_tend@description = \"Param  Precipitation Tendency\"\n      rain_tot_tend@description = \"Precipitation Tendency\"\n\n  ; Bookkeeping, just to allow the tendency at the next time step\n      rain_exp_save = rain_exp\n      rain_con_save = rain_con\n      rain_tot_save = rain_tot\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Don't skip the first time: we need an image at each time stamp\n; This will result in a warning message on the first plot\n;     if( .not. FirstTime ) then ; We don’t skip the first time\n\n      ; Plotting options for Sea Level Pressure\n        opts_psl = res          \n        opts_psl@ContourParameters = (/ 900., 1100., 2. /)\n        opts_psl@cnLineColor       = \"Blue\"\n        opts_psl@cnInfoLabelOn     = False\n        opts_psl@cnLineLabelFontHeightF = 0.01\n        opts_psl@cnLineLabelPerimOn = False\n        opts_psl@gsnContourLineThicknessesScale = 1.5\n        contour_psl = wrf_contour(a,wks,slp,opts_psl)\n        delete(opts_psl)\n    \n\n      ; Plotting options for Precipitation\n        opts_r = res                        \n        opts_r@UnitLabel            = \"mm\"\n        opts_r@cnLevelSelectionMode = \"ExplicitLevels\"\n        opts_r@cnLevels             = (/ .1, .2, .4, .8, 1.6, 3.2, 6.4, \\\n                                        12.8, 25.6, 51.2, 102.4/)\n        opts_r@cnFillColors         = (/\"White\",\"White\",\"DarkOliveGreen1\", \\\n                                        \"DarkOliveGreen3\",\"Chartreuse\", \\\n                                        \"Chartreuse3\",\"Green\",\"ForestGreen\", \\\n                                        \"Yellow\",\"Orange\",\"Red\",\"Violet\"/)\n        opts_r@cnInfoLabelOn        = False\n        opts_r@cnConstFLabelOn      = False\n        opts_r@cnFillOn             = True\n    \n\n      ; Total Precipitation (color fill)\n        contour_tot = wrf_contour(a,wks, rain_tot, opts_r)\n    \n      ; Precipitation Tendencies \n        opts_r@SubFieldTitle = \"from \" + times_sav + \" to \" + times(it)\n    \n        contour_tend = wrf_contour(a,wks, rain_tot_tend,opts_r) ; total (color)\n        contour_res = wrf_contour(a,wks,rain_exp_tend,opts_r)   ; exp (color)\n        opts_r@cnFillOn = False\n        opts_r@cnLineColor = \"Red4\"\n        contour_prm = wrf_contour(a,wks,rain_con_tend,opts_r)   ; con (red lines)\n        delete(opts_r)\n\n\n\n      ; MAKE PLOTS                                       \n\n        ; Total Precipitation \n        ; Don’t do this plot for geotiff:\n        ;  plot = wrf_map_overlays(a,wks,contour_tot,pltres,mpres)\n\n        ; Total Precipitation Tendency + SLP\n        ; Do just this one plot:\n          plot = wrf_map_overlays(a,wks,(/contour_tend,contour_psl/),pltres,mpres)\n\n        ; Then put it in geotiff\n        ; Do crop the image to the domain bounds\n        wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, True)\n        ; The frame is needed between time steps after the wrf2geotiff_write\n        frame(wks)\n\n        ; Non-Convective and Convective Precipiation Tendencies\n        ; plot = wrf_map_overlays(a,wks,(/contour_res,contour_prm/),pltres,mpres)\n\n;     end if    ; END IF FOR SKIPPING FIRST TIME\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n      times_sav = times(it)\n      FirstTime = False\n    end do        ; END OF TIME LOOP\n  end do ; END OF LOOP OVER FILES\n\n; At the end, close the wrf2geotiff\n; This is where the tiff writing takes place:\n  wrf2geotiff_close(wrf2gtiff,wks)\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_Precip_FirstMod.ncl",
    "content": "\n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n\n; From the \"Using NCL with VAPOR to Visualize WRF-ARW data\"\n; tutorial.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n\nbegin\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n\n; Instead of selecting one file, make a variable that has\n; all the names of the WRF output files in it:\n; a = addfile(\"wrfout_d02_2008-09-28_00.nc\",\"r\")\n  wrffiles = systemfunc(\"ls wrfout_d02_2008-09-28*\")\n  numFiles = dimsizes(wrffiles)\n  do i = 0, numFiles-1\n    wrffiles(i) = wrffiles(i)+\".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; We generate plots, but what kind do we prefer?\n  type = \"x11\"\n; type = \"pdf\"\n; type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_Precip\")\n\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n\n  pltres = True\n  mpres = True\n  mpres@mpGeophysicalLineColor = \"Black\"\n  mpres@mpNationalLineColor    = \"Black\"\n  mpres@mpUSStateLineColor     = \"Black\"\n  mpres@mpGridLineColor        = \"Black\"\n  mpres@mpLimbLineColor        = \"Black\"\n  mpres@mpPerimLineColor       = \"Black\"\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; What times and how many time steps are in the data set?\n  FirstTime = True\n\n; Make a loop over all the files:\n  do ifile = 0,numFiles -1\n    a = inpFiles[ifile]\n\n    times  = wrf_user_list_times(a)  ; get times in the file\n    ntimes = dimsizes(times)         ; number of times in the file\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Loop over all the times, not just the odd times:\n; do it = 0,ntimes-1,2 ; TIME LOOP\n    do it = 0, ntimes-1 ; Modified to do every time step\n\n      print(\"Working on time: \" + times(it) )\n      if (FirstTime) then            ; Save some times for tracking tendencies\n        times_sav = times(it)\n      end if\n      res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need        \n\n    slp = wrf_user_getvar(a,\"slp\",it)  ; slp\n      wrf_smooth_2d( slp, 3 )            ; smooth slp\n\n  ; Get non-convective, convective and total precipitation\n  ; Calculate tendency values                               \n      rain_exp = wrf_user_getvar(a,\"RAINNC\",it)\n      rain_con = wrf_user_getvar(a,\"RAINC\",it)\n      rain_tot = rain_exp + rain_con\n      rain_tot@description = \"Total Precipitation\"\n\n      if( FirstTime ) then\n        if ( it .eq. 0 ) then\n          rain_exp_save = rain_exp\n          rain_con_save = rain_con\n          rain_tot_save = rain_tot\n        else\n          rain_exp_save = wrf_user_getvar(a,\"RAINNC\",it-1)\n          rain_con_save = wrf_user_getvar(a,\"RAINC\",it-1)\n          rain_tot_save = rain_exp_save + rain_con_save\n          FirstTime = False\n          times_sav = times(it-1)\n        end if\n      end if\n\n      rain_exp_tend = rain_exp - rain_exp_save\n      rain_con_tend = rain_con - rain_con_save\n      rain_tot_tend = rain_tot - rain_tot_save\n      rain_exp_tend@description = \"Explicit Precipitation Tendency\"\n      rain_con_tend@description = \"Param  Precipitation Tendency\"\n      rain_tot_tend@description = \"Precipitation Tendency\"\n\n  ; Bookkeeping, just to allow the tendency at the next time step\n      rain_exp_save = rain_exp\n      rain_con_save = rain_con\n      rain_tot_save = rain_tot\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Don't skip the first time: we need an image at each time stamp\n; This will result in a warning message on the first plot\n;     if( .not. FirstTime ) then ; We don’t skip the first time\n\n      ; Plotting options for Sea Level Pressure\n        opts_psl = res          \n        opts_psl@ContourParameters = (/ 900., 1100., 2. /)\n        opts_psl@cnLineColor       = \"Blue\"\n        opts_psl@cnInfoLabelOn     = False\n        opts_psl@cnLineLabelFontHeightF = 0.01\n        opts_psl@cnLineLabelPerimOn = False\n        opts_psl@gsnContourLineThicknessesScale = 1.5\n        contour_psl = wrf_contour(a,wks,slp,opts_psl)\n        delete(opts_psl)\n    \n\n      ; Plotting options for Precipitation\n        opts_r = res                        \n        opts_r@UnitLabel            = \"mm\"\n        opts_r@cnLevelSelectionMode = \"ExplicitLevels\"\n        opts_r@cnLevels             = (/ .1, .2, .4, .8, 1.6, 3.2, 6.4, \\\n                                        12.8, 25.6, 51.2, 102.4/)\n        opts_r@cnFillColors         = (/\"White\",\"White\",\"DarkOliveGreen1\", \\\n                                        \"DarkOliveGreen3\",\"Chartreuse\", \\\n                                        \"Chartreuse3\",\"Green\",\"ForestGreen\", \\\n                                        \"Yellow\",\"Orange\",\"Red\",\"Violet\"/)\n        opts_r@cnInfoLabelOn        = False\n        opts_r@cnConstFLabelOn      = False\n        opts_r@cnFillOn             = True\n    \n\n      ; Total Precipitation (color fill)\n        contour_tot = wrf_contour(a,wks, rain_tot, opts_r)\n    \n      ; Precipitation Tendencies \n        opts_r@SubFieldTitle = \"from \" + times_sav + \" to \" + times(it)\n    \n        contour_tend = wrf_contour(a,wks, rain_tot_tend,opts_r) ; total (color)\n        contour_res = wrf_contour(a,wks,rain_exp_tend,opts_r)   ; exp (color)\n        opts_r@cnFillOn = False\n        opts_r@cnLineColor = \"Red4\"\n        contour_prm = wrf_contour(a,wks,rain_con_tend,opts_r)   ; con (red lines)\n        delete(opts_r)\n\n\n\n      ; MAKE PLOTS                                       \n\n        ; Total Precipitation \n        ; Don’t do this plot for geotiff:\n        ;  plot = wrf_map_overlays(a,wks,contour_tot,pltres,mpres)\n\n        ; Total Precipitation Tendency + SLP\n        ; Do just this one plot:\n          plot = wrf_map_overlays(a,wks,(/contour_tend,contour_psl/),pltres,mpres)\n\n        ; Non-Convective and Convective Precipiation Tendencies\n        ; plot = wrf_map_overlays(a,wks,(/contour_res,contour_prm/),pltres,mpres)\n\n;     end if    ; END IF FOR SKIPPING FIRST TIME\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n      times_sav = times(it)\n      FirstTime = False\n    end do        ; END OF TIME LOOP\n  end do ; END OF LOOP OVER FILES\n\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_Surface1.ncl",
    "content": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Adapted from the script \"wrf_Surface1.ncl\" at:\n;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/BASIC_SFC/wrf_Surface1.ncl\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n \n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\nload \"$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl\"\n\n\nbegin\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; Add your own data here....\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n  ;;;a = addfile(\"./wrfout_d01_2000-01-24_12:00:00.nc\",\"r\")\n  wrffiles = systemfunc(\"ls ./HurricaneIKE/wrfout_d03_2008*\")\n  numFiles = dimsizes(wrffiles)\n  do i=0,numFiles-1\n    wrffiles(i) = wrffiles(i) + \".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; Output type must be postscript...\n  type = \"ps\"    \n  wks = gsn_open_wks(type,\"plt_Surface1\")\n\n  ; Do we want the Geotiffs cropped?\n  if (.not.isdefined(\"cropPlot\")) then\n      cropPlot = True\n  end if\n\n  ; initialize our tiff-capture process...\n  wrf2gtiff = wrf2geotiff_open(wks)\n\n; Set some basic resources\n  res = True\n  res@MainTitle                   = \"REAL-TIME WRF\"\n\n  pltres = True\n  pltres@FramePlot = False   ; Extremely important for geotiff output process\n  mpres = True\n\n; loop over files...\ndo ifile = 0, numFiles-1\na = inpFiles[ifile]\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; What times and how many time steps are in the data set?\n  times  = wrf_user_list_times(a)  ; get times in the file\n  ntimes = dimsizes(times)         ; number of times in the file\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  do it = 0,ntimes-1,2             ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need        \n\n    slp = wrf_user_getvar(a,\"slp\",it)    ; slp\n      wrf_smooth_2d( slp, 3 )            ; smooth slp\n    tc = wrf_user_getvar(a,\"tc\",it)      ; 3D tc \n    td = wrf_user_getvar(a,\"td\",it)      ; 3D td \n    u  = wrf_user_getvar(a,\"ua\",it)      ; 3D U at mass points\n    v  = wrf_user_getvar(a,\"va\",it)      ; 3D V at mass points\n    td2 =  wrf_user_getvar(a,\"td2\",it)   ; Td2 in C\n    tc2 = wrf_user_getvar(a,\"T2\",it)     ; T2 in Kelvin\n       tc2 = tc2-273.16                  ; T2 in C\n    u10 = wrf_user_getvar(a,\"U10\",it)    ; u at 10 m, mass point\n    v10 = wrf_user_getvar(a,\"V10\",it)    ; v at 10 m, mass point\n\n    tf2 = 1.8*tc2+32.                    ; Turn temperature into Fahrenheit\n      tf2@description = \"Surface Temperature\"\n      tf2@units = \"F\"\n    td_f = 1.8*td2+32.                   ; Turn temperature into Fahrenheit\n      td_f@description = \"Surface Dew Point Temp\" \n      td_f@units = \"F\"\n    u10 = u10*1.94386                    ; Turn wind into knots\n    v10 = v10*1.94386\n      u10@units = \"kts\"\n      v10@units = \"kts\"\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    ; Plotting options for T                \n      opts = res                         \n      opts@cnFillOn = True  \n      opts@ContourParameters = (/ -20., 90., 5./)\n      opts@gsnSpreadColorEnd = -3  ; End third from the last color in color map\n      contour_tc = wrf_contour(a,wks,tf2,opts)\n      delete(opts)\n\n\n    ; Plotting options for Td\n      opts = res         \n      opts@cnFillOn = True \n      opts@cnLinesOn = True\n      opts@cnLineLabelsOn = True\n      opts@ContourParameters = (/ -20., 90., 5./) \n      opts@cnLineLabelBackgroundColor = -1\n      opts@gsnSpreadColorEnd = -3  ; End third from the last color in color map\n      contour_td = wrf_contour(a,wks,td_f,opts)\n      delete(opts)\n\n\n    ; Plotting options for SLP                     \n      opts = res         \n      opts@cnLineColor = \"Blue\"\n      opts@cnHighLabelsOn = True\n      opts@cnLowLabelsOn = True\n      opts@ContourParameters = (/ 900., 1100., 4. /)\n      opts@cnLineLabelBackgroundColor = -1\n      opts@gsnContourLineThicknessesScale = 2.0\n      contour_psl = wrf_contour(a,wks,slp,opts)\n      delete(opts)\n\n    ; Plotting options for Wind Vectors                 \n      opts = res         \n      opts@FieldTitle = \"Wind\"       ; overwrite Field Title\n      opts@NumVectors = 47           ; density of wind barbs\n      vector = wrf_vector(a,wks,u10,v10,opts)\n      delete(opts)\n  \n\n    ; MAKE PLOTS                                       \n      plot = wrf_map_overlays(a,wks,(/contour_tc,contour_psl,vector/),pltres,mpres)\n      wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, cropPlot)\n      frame(wks)  ; Now that we are done drawing, draw the frame\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  end do        ; END OF TIME LOOP\nend do          ; END OF FILES LOOP\n\nwrf2geotiff_close(wrf2gtiff, wks)\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_cloud.ncl",
    "content": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Adapted from the script \"wrf_cloud.ncl\" at:\n;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/LEVELS_MODEL/wrf_Cloud.htm\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n \n\n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\n;load \"./WRFUserARW.ncl\"\nload \"$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl\"\n\n\nbegin\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; Add your own data here....\n;\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n  ;;;;a = addfile(\"./wrfout_d03_2008-09-14_18:00:00.nc\",\"r\")            \n  wrffiles = systemfunc(\"ls ./HurricaneIKE/wrfout_d03_2008*\")\n  numFiles = dimsizes(wrffiles)\n  do i=0,numFiles-1\n    wrffiles(i) = wrffiles(i) + \".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n  ; Do we want the Geotiffs cropped?\n  if (.not.isdefined(\"cropPlot\")) then\n      cropPlot = True\n  end if\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Output type must be postscript...\n  type = \"ps\"    \n  wks = gsn_open_wks(type,\"plt_Cloud\")\n  gsn_define_colormap(wks,\"WhBlGrYeRe\")   ; overwrite the .hluresfile color map\n\n  ; initialize our tiff-capture process...\n  wrf2gtiff = wrf2geotiff_open(wks)\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n\n  mpres  = True  ; Map resources\n  pltres = True ; Plot resources\n\n  pltres@FramePlot = False   ; Extremely important for geotiff output process\n\n; Loop over files...\ndo ifile = 0, numFiles-1\n  a = inpFiles[ifile]\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; What times and how many time steps are in the data set?\n  times  = wrf_user_list_times(a)  ; get times in the file\n  ntimes = dimsizes(times)         ; number of times in the file\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  do it = ntimes-1,ntimes-1        ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; First get the variables we will need        \n\n    ;; original script generated several different plots per timestep\n\n    if(isfilevar(a,\"QVAPOR\"))\n      qv = wrf_user_getvar(a,\"QVAPOR\",it) \n      qv = qv*1000.\n      qv@units = \"g/kg\"   \n    end if\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    ;; original script looped over levels\n    ;;;;do level = 0,24,5      ; LOOP OVER LEVELS\n      level = 4\n\n      display_level = level + 1\n      opts = res\n      opts@cnFillOn         = True\n      opts@gsnSpreadColors  = False\n      opts@PlotLevelID      = \"Eta Level  \" + display_level\n\n      if (isvar(\"qv\"))\n        contour = wrf_contour(a,wks,qv(level,:,:),opts)\n        plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres)\n        wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, cropPlot)\n        frame(wks)  ; Now that we are done drawing, draw the frame\n        delete(contour)\n      end if\n\n      delete(opts)\n\n    ;;;;end do      ; END OF LEVEL LOOP\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  end do        ; END OF TIME LOOP     \nend do          ; END OF FILE LOOP\n\nwrf2geotiff_close(wrf2gtiff, wks)\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_crossSection4.ncl",
    "content": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Adapted from the script \"wrf_CrossSection_4.ncl\" at:\n;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/CROSS_SECTION/wrf_CrossSection_4.ncl\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n \n\n;   Example script to produce plots for a WRF real-data run,\n;   with the ARW coordinate dynamics option.\n;   Plot data on a cross section\n;   This script will plot data at a set angle through a specified point\n;   This script adds lon/lat info along X-axis\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\nload \"$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl\"\n\nbegin\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n  ;;a = addfile(\"./wrfout_d01_2000-01-24_12:00:00.nc\",\"r\")\n  wrffiles = systemfunc(\"ls ./HurricaneIKE/wrfout_d03_2008*\")\n  numFiles = dimsizes(wrffiles)\n  do i=0,numFiles-1\n    wrffiles(i) = wrffiles(i) + \".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n\n; We generate plots, but what kind do we prefer?\n; type = \"x11\"\n; type = \"pdf\"\n  type = \"ps\"\n; type = \"ncgm\"\n  wks = gsn_open_wks(type,\"plt_CrossSection4\")\n\n; initialize our tiff-capture process...\n  wrf2gtiff = wrf2geotiff_open(wks)\n\n; These vertical cross sections make improper geotiffs; disable georeference in tiff-capture...\n  wrf2geotiff_disableGeoTags(wrf2gtiff)\n\n; Set some basic resources\n  res = True\n  res@MainTitle = \"REAL-TIME WRF\"\n  res@Footer = False\n  \n  pltres = True\n  pltres@FramePlot = False\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n  FirstTime = True\n  FirstTimeMap = True\n\ndo ifile=0, numFiles-1\n  a = inpFiles[ifile]\n\n  times  = wrf_user_list_times(a)  ; get times in the file\n  ntimes = dimsizes(times)         ; number of times in the file\n\n  mdims = getfilevardimsizes(a,\"P\") ; get some dimension sizes for the file\n  nd = dimsizes(mdims)\n\n  xlat = wrf_user_getvar(a, \"XLAT\",0)\n  xlon = wrf_user_getvar(a, \"XLONG\",0)\n  ter = wrf_user_getvar(a, \"HGT\",0)\n\n;---------------------------------------------------------------\n\n  do it = 0,ntimes-1,2             ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n    tc   = wrf_user_getvar(a,\"tc\",it)      ; T in C\n    rh   = wrf_user_getvar(a,\"rh\",it)      ; relative humidity\n    z    = wrf_user_getvar(a, \"z\",it)      ; grid point height\n\n    if ( FirstTime ) then                ; get height info for labels\n      zmin = 0.\n      zmax = 6.                          ; We are only interested in the first 6km\n      nz   = floattoint(zmax + 1)\n    end if\n\n\n;---------------------------------------------------------------\n\n;;; Original script made 3 cross-sectional slices per timestamp.\n;;; For use in Vapor, we want all plots across all files to be the same type.\n;;; Set \"ip\" appropriately to get the desired slice.\n;;;    do ip = 1, 3      \t; we are doing 3 plots\n;;;\t\t\t; all with the pivot point (plane) in the center of the domain\n;;;\t\t\t; at angles 0, 45 and 90\n        ip=1  ; 90-degree slice\n        ;ip=2  ; 0-degree slice\n        ;ip=3  ; 45-degree slice\n ;  \n ;                   |\n ;       angle=0 is  |\n ;                   |\n ; \n\n        plane = new(2,float)\n        plane = (/ mdims(nd-1)/2, mdims(nd-2)/2 /)    ; pivot point is center of domain (x,y)\n        opts = False\n\n        if(ip .eq. 1) then\n          angle = 90.\n          X_plane = wrf_user_intrp2d(xlon,plane,angle,opts)\n          X_desc = \"longitude\"\n        end if\n        if(ip .eq. 2) then\n          angle = 0.\n          X_plane = wrf_user_intrp2d(xlat,plane,angle,opts)\n          X_desc = \"latitude\"\n        end if\n        if(ip .eq. 3) then\n          angle = 45.\n          X_plane = wrf_user_intrp2d(xlon,plane,angle,opts)\n          X_desc = \"longitude\"\n        end if\n\n        rh_plane = wrf_user_intrp3d(rh,z,\"v\",plane,angle,opts)\n        tc_plane = wrf_user_intrp3d(tc,z,\"v\",plane,angle,opts)\n\n\n      ; Find the index where 6km is - only need to do this once\n        if ( FirstTime ) then\n          zz = wrf_user_intrp3d(z,z,\"v\",plane,angle,opts)\n          b = ind(zz(:,0) .gt. zmax*1000. )\n          zmax_pos = b(0) - 1\n          if ( abs(zz(zmax_pos,0)-zmax*1000.) .lt. abs(zz(zmax_pos+1,0)-zmax*1000.) ) then\n            zspan = b(0) - 1\n          else\n            zspan = b(0)\n          end if\n          delete(zz)\n          delete(b)\n          FirstTime = False\n        end if\n\n      ; X-axis lables\n      dimsX = dimsizes(X_plane)\n      xmin  = X_plane(0)\n      xmax  = X_plane(dimsX(0)-1)\n      xspan = dimsX(0)-1\n      nx    = floattoint( (xmax-xmin)/2 + 1)\n\n      ;---------------------------------------------------------------\n        \n      ; Options for XY Plots\n        opts_xy                         = res\n        opts_xy@tiXAxisString           = X_desc\n        opts_xy@tiYAxisString           = \"Height (km)\"\n        opts_xy@cnMissingValPerimOn     = True\n        opts_xy@cnMissingValFillColor   = 0\n        opts_xy@cnMissingValFillPattern = 11\n        opts_xy@tmXTOn                  = False\n        opts_xy@tmYROn                  = False\n        opts_xy@tmXBMode                = \"Explicit\"\n        opts_xy@tmXBValues              = fspan(0,xspan,nx)                    ; Create tick marks\n        opts_xy@tmXBLabels              = sprintf(\"%.1f\",fspan(xmin,xmax,nx))  ; Create labels\n        opts_xy@tmXBLabelFontHeightF    = 0.015\n        opts_xy@tmYLMode                = \"Explicit\"\n        opts_xy@tmYLValues              = fspan(0,zspan,nz)                    ; Create tick marks\n        opts_xy@tmYLLabels              = sprintf(\"%.1f\",fspan(zmin,zmax,nz))  ; Create labels\n        opts_xy@tiXAxisFontHeightF      = 0.020\n        opts_xy@tiYAxisFontHeightF      = 0.020\n        opts_xy@tmXBMajorLengthF        = 0.02\n        opts_xy@tmYLMajorLengthF        = 0.02\n        opts_xy@tmYLLabelFontHeightF    = 0.015\n        opts_xy@PlotOrientation         = tc_plane@Orientation\n\n\n      ; Plotting options for RH\n        opts_rh = opts_xy\n        opts_rh@ContourParameters       = (/ 10., 90., 10. /)\n        opts_rh@pmLabelBarOrthogonalPosF = -0.1 \n        opts_rh@cnFillOn                = True\n        opts_rh@cnFillColors            = (/\"White\",\"White\",\"White\", \\\n                                            \"White\",\"Chartreuse\",\"Green\", \\\n                                            \"Green3\",\"Green4\", \\\n                                            \"ForestGreen\",\"PaleGreen4\"/)\n\n      ; Plotting options for Temperature\n        opts_tc = opts_xy\n        opts_tc@cnInfoLabelZone = 1\n        opts_tc@cnInfoLabelSide = \"Top\"\n        opts_tc@cnInfoLabelPerimOn = True\n        opts_tc@cnInfoLabelOrthogonalPosF = -0.00005\n        opts_tc@ContourParameters  = (/ 5. /)\n\n\n      ; Get the contour info for the rh and temp\n        contour_tc = wrf_contour(a,wks,tc_plane(0:zmax_pos,:),opts_tc)\n        contour_rh = wrf_contour(a,wks,rh_plane(0:zmax_pos,:),opts_rh)\n\n      ;---------------------------------------------------------------\n\n  ; MAKE PLOTS         \n\n        if (FirstTimeMap) then\n          lat_plane = wrf_user_intrp2d(xlat,plane,angle,opts)\n          lon_plane = wrf_user_intrp2d(xlon,plane,angle,opts)\n          mpres = True\n          pltres = True\n          pltres@FramePlot = False\n          optsM = res\n          optsM@NoHeaderFooter = True\n          optsM@cnFillOn = True\n          optsM@lbTitleOn = False\n;;;          contour  = wrf_contour(a,wks,ter,optsM)\n;;;          plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres)\n          lnres = True\n          lnres@gsLineThicknessF = 3.0\n          lnres@gsLineColor = \"Red\"\n;;;          do ii = 0,dimsX(0)-2\n;;;            gsn_polyline(wks,plot,(/lon_plane(ii),lon_plane(ii+1)/),(/lat_plane(ii),lat_plane(ii+1)/),lnres)\n;;;          end do\n;;;          wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, True)\n;;;          frame(wks)\n          delete(lon_plane)\n          delete(lat_plane)\n    ;;????      pltres@FramePlot = True\n       end if\n\n       plot = wrf_overlays(a,wks,(/contour_rh,contour_tc/),pltres)    ; plot x-section\n       wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, True)\n       frame(wks)  ; Now that we are done drawing, draw the frame\n\n  ; Delete options and fields, so we don't have carry over\n        delete(opts_xy)\n        delete(opts_tc)\n        delete(opts_rh)\n        delete(tc_plane)\n        delete(rh_plane)\n        delete(X_plane)\n\n;;;    end do  ; make next cross section\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n    FirstTimeMap = False\n  end do        ; END OF TIME LOOP\nend do          ; END OF FILES LOOP\n\n  wrf2geotiff_close(wrf2gtiff, wks)\nend\n"
  },
  {
    "path": "share/examples/NCL/wrf_pv.ncl",
    "content": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;; Adapted from the script \"wrf_pv.ncl\" at:\n;; http://www.mmm.ucar.edu/wrf/OnLineTutorial/Graphics/NCL/Examples/DIAGNOSTICS/wrf_pv.htm\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n \n;   Example script to produce Vorticity plots from WRF ARW model data\n;   November 2008\n\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl\"\nload \"$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl\"\nload \"$VAPOR_HOME/share/examples/NCL/wrf2geotiff.ncl\"\n\nbegin\n;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n; Add your own data here....\n;\n; The WRF ARW input file.  \n; This needs to have a \".nc\" appended, so just do it.\n  ;;;a = addfile(\"./wrfout_d01_2005-08-28_00.nc\",\"r\")\n  wrffiles = systemfunc(\"ls ./HurricaneIKE/wrfout_d03_2008*\")\n  numFiles = dimsizes(wrffiles)\n  do i=0,numFiles-1\n    wrffiles(i) = wrffiles(i) + \".nc\"\n  end do\n  inpFiles = addfiles(wrffiles,\"r\")\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; Output type must be postscript...\n  type = \"ps\"    \n  wks = gsn_open_wks(type,\"plt_pv\")\n\n  ; Do we want the Geotiffs cropped?\n  if (.not.isdefined(\"cropPlot\")) then\n      cropPlot = True\n  end if\n\n  ; initialize our tiff-capture process...\n  wrf2gtiff = wrf2geotiff_open(wks)\n\n; Set some basic resources\n  res = True\n  res@MainTitle                   = \"REAL-TIME WRF\"\n\n  mpres = True\n  pltres = True\n  pltres@FramePlot = False   ; Extremely important for geotiff output process\n\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n; loop over files...\ndo ifile = 0, numFiles-1\n  a = inpFiles[ifile]\n\n; What times and how many time steps are in the data set?\n  times  = wrf_user_list_times(a)  ; get times in the file\n  ntimes = dimsizes(times)         ; number of times in the file\n\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n  do it = 0,ntimes-1,2             ; TIME LOOP\n\n    print(\"Working on time: \" + times(it) )\n    res@TimeLabel = times(it)   ; Set Valid time to use on plots\n\n\n  ; Get the data\n    pvo   = wrf_user_getvar(a,\"pvo\",it)\n    avo   = wrf_user_getvar(a,\"avo\",it)\n    p     = wrf_user_getvar(a,\"pressure\",it)\n\n\n  ; Interpolate to pressure\n    pv_plane = wrf_user_intrp3d(pvo,p,\"h\",300.,0,False)\n    av_plane = wrf_user_intrp3d(avo,p,\"h\",500.,0,False)\n\n\n    ; Plotting options \n      opts = res                         \n      opts@cnFillOn = True  \n      opts@gsnSpreadColorEnd = -3  ; End third from the last color in color map\n      opts@ContourParameters = (/ 0., 100., 10./)\n      ;; Original script generated two distinct plots per timestep...\n      ;;contour_a = wrf_contour(a,wks,av_plane,opts)\n\n      opts@ContourParameters = (/ 0., 5., 1./)\n      contour = wrf_contour(a,wks,pv_plane,opts)\n      delete(opts)\n\n    ; MAKE PLOTS                                       \n      ;; Original script generated two distinct plots per timestep...\n      ;;plot = wrf_map_overlays(a,wks,(/contour_a/),pltres,mpres)\n\n      plot = wrf_map_overlays(a,wks,(/contour/),pltres,mpres)\n      wrf2geotiff_write(wrf2gtiff, a, times(it), wks, plot, cropPlot)\n      frame(wks)  ; Now that we are done drawing, draw the frame\n\n  end do        ; END OF TIME LOOP\nend do          ; END OF FILES LOOP\n;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\nwrf2geotiff_close(wrf2gtiff, wks)\n\nend\n"
  },
  {
    "path": "share/examples/VDC/amr_ex.cpp",
    "content": "//\n//      $Id$\n//\n//***********************************************************************\n//                                                                      *\n//                      Copyright (C)  2006                             *\n//          University Corporation for Atmospheric Research             *\n//                      All Rights Reserved                             *\n//                                                                      *\n//***********************************************************************\n//\n//\tFile:\t\tamr.cpp\n//\n//\tAuthor:\t\tJohn Clyne\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tThu Apr  9 11:42:00 MDT 2009\n//\n//\tDescription:\tThis example demonstrates the construction of\n//\ta VDC AMR data set. The example data are synthesized by sampling\n//  a regular Cartesian grid. Prior to executing this code a suitable\n//\t.vdf file must be created using the command:\n//\n//\t\tvdfcreate -gridtype block_amr -dimension NxNxN -bs\n//\t\tCellDimxCellDimxCellDim -level NLevels\n//\t\t-varnames ml:checker test.vdf\n//\n// where N, CellDim, and NLevels are the values defined below. For example:\n//\n//\t\tvdfcreate -gridtype block_amr -dimension 256x256x256 -bs\n//\t\t8x8x8 -level 2 \t-varnames ml:checker test.vdf\n//\n// Once a .vdf file has been created, the example can be invoked with\n// the command:\n//\n//\t\t$VAPOR_HOME/bin/amr_ex test.vdf\n//\n//\n#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include \"vapor/VAssert.h\"\n#include <cstdio>\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/AMRTree.h>\n#include <vapor/AMRData.h>\n#include <vapor/AMRIO.h>\n#include <vapor/Metadata.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\n//\n// Dimension of AMR grid if all cells are fully refined, creating\n// a rectilinear Cartesian grid.\n//\nconst int N = 256;\n\n//\n// Dimension of AMR block. Must be at least 2. This restriction could\n// be relaxed if AMRData::ReGrid were modified.\n//\nconst int CellDim = 8;\n\n//\n// Maximum number of refinement levels. Must be hardcoded to 2 in this example\n//\nconst int NLevels = 2;\n\n//\n//\tCommand line argument stuff\n//\nstruct opt_t {\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T debug;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"help\", 0, \"\", \"Print this message and exit\"}, {\"debug\", 0, \"\", \"Enable verbose debugging output\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}};\n\n//\n// The marschner lobb function for synthesizing data\n//\ndouble marschner_lobb(double x, double y, double z, double alpha, double fm)\n{\n    double pr;\n    double r;\n    double v;\n\n    r = sqrt(x * x + y * y);\n    pr = cos(2 * M_PI * fm * cos(M_PI * r / 2.0));\n\n    v = (1.0 - sin(M_PI * z / 2.0) + (alpha * (1.0 + pr))) / (2 * (1 + alpha));\n    return (v);\n}\n\n#define ALPHA (double)0.25\n#define FM    (double)6.0\nfloat *make_marschner_lobb(int nx, int ny, int nz)\n{\n    float *grid = new float[nx * ny * nz];\n\n    for (int z = 0; z < nz; z++) {\n        for (int y = 0; y < ny; y++) {\n            for (int x = 0; x < nx; x++) {\n                double xf, yf, zf;\n\n                xf = (x - nx / 2) * 2.0 / (double)(nx - 1.0);\n                yf = (y - ny / 2) * 2.0 / (double)(ny - 1.0);\n                zf = (z - nz / 2) * 2.0 / (double)(nz - 1.0);\n\n                grid[x + (nx * y) + (nx * ny * z)] = (float)marschner_lobb(xf, yf, zf, ALPHA, FM);\n            }\n        }\n    }\n\n    return (grid);\n}\n\n//\n// another function for synthesizing data\n//\n#define ISODD(X) ((X) % 2)\nfloat *make_checker(int nx, int ny, int nz, int chksz)\n{\n    float *grid = new float[nx * ny * nz];\n\n    for (int z = 0; z < nz; z++) {\n        for (int y = 0; y < ny; y++) {\n            for (int x = 0; x < nx; x++) {\n                if (ISODD((x / chksz) + (y / chksz) + (z / chksz))) {\n                    grid[x + (nx * y) + (nx * ny * z)] = 1.0;\n                } else {\n                    grid[x + (nx * y) + (nx * ny * z)] = 0.0;\n                }\n            }\n        }\n    }\n\n    return (grid);\n}\n\n//\n//\tThis function interpolates data on a 3D Cartesian grid using Nearest\n//\tNeighbor\n//\nfloat resample_grid_point(float *grid, double x, double y, double z)\n{\n    int xi, yi, zi;\n\n    double delta = 1.0 / (double)N;\n    double start = delta / 2.0;\n\n    xi = (int)rint((x - start) * (double)N);\n    yi = (int)rint((y - start) * (double)N);\n    zi = (int)rint((z - start) * (double)N);\n\n    VAssert(xi >= 0 && xi < N);\n    VAssert(yi >= 0 && yi < N);\n    VAssert(zi >= 0 && zi < N);\n\n    return (grid[zi * N * N + yi * N + xi]);\n}\n\n//\n//\tThis function will write a single AMR variable to a Vapor Data\n//\tCollection (VDC)\n//\nconst char *ProgName;\nvoid        process_variable(AMRIO *amrio, AMRTree *tree, AMRData *amrdata, float *grid, const char *varname)\n{\n    AMRTree::cid_t cellid;\n    size_t         cell_dim[] = {CellDim, CellDim, CellDim};\n\n    //\n    // Treverse the AMR tree hierarchy. For each cell in the tree, whether\n    // it is a leaf or internal node, we provide data by sampling\n    // a function defined on a Cartesian grid.\n    //\n    bool first = true;\n    while ((cellid = tree->GetNextCell(first)) >= 0) {\n        first = false;\n\n        double minu[3], maxu[3];\n\n        // Get the bounds of the cell (min and max extent) defined in\n        // in user coordinates. In this example user coordinates run\n        // from 0.0 to 1.0.\n        //\n        int rc = tree->GetCellBounds(cellid, minu, maxu);\n        if (rc < 0) {\n            cerr << ProgName << \" : \" << tree->GetErrMsg() << endl;\n            exit(1);\n        }\n\n        // Get a pointer to a block of data associated with this cell.\n        //\n        float *block = amrdata->GetBlock(cellid);\n\n        // For each grid point in the cell block assign a value\n        //\n        for (int k = 0; k < cell_dim[2]; k++) {\n            for (int j = 0; j < cell_dim[1]; j++) {\n                for (int i = 0; i < cell_dim[0]; i++) {\n                    double deltax = (maxu[0] - minu[0]) / (double)cell_dim[0];\n                    double deltay = (maxu[1] - minu[1]) / (double)cell_dim[1];\n                    double deltaz = (maxu[2] - minu[2]) / (double)cell_dim[2];\n\n                    double startx = minu[0] + (deltax / 2.0);\n                    double starty = minu[1] + (deltay / 2.0);\n                    double startz = minu[2] + (deltaz / 2.0);\n\n                    block[k * cell_dim[0] * cell_dim[1] + j * cell_dim[0] + i] = resample_grid_point(grid, startx + i * deltax, starty + j * deltay, startz + k * deltaz);\n                }\n            }\n        }\n    }\n\n    //\n    // Write the data to the VDC giving it the name, 'varname'\n    //\n    if (amrio->OpenVariableWrite(0, varname, -1) < 0) {\n        cerr << ProgName << \" : \" << amrio->GetErrMsg() << endl;\n        exit(1);\n    }\n\n    if (amrio->VariableWrite(amrdata) < 0) {\n        cerr << ProgName << \" : \" << amrio->GetErrMsg() << endl;\n        exit(1);\n    }\n\n    if (amrio->CloseVariable() < 0) {\n        cerr << ProgName << \" : \" << amrio->GetErrMsg() << endl;\n        exit(1);\n    }\n}\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    const char * metafile;\n\n    ProgName = Basename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage : \" << ProgName << \" [options] metafile \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (argc != 2) {\n        cerr << \"Usage : \" << ProgName << \" [options] metafile \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    metafile = argv[1];    // Path to a suitably defined vdf file\n\n    MyBase::SetErrMsgFilePtr(stderr);\n    if (opt.debug) MyBase::SetDiagMsgFilePtr(stderr);\n\n    // Create an AMRIO object to write the AMR grid to the VDC\n    //\n    AMRIO *amrio = new AMRIO(metafile);\n    if (amrio->GetErrCode() != 0) {\n        cerr << ProgName << \" : \" << amrio->GetErrMsg() << endl;\n        exit(1);\n    }\n\n    //\n    // Verify .vdf metafile was properly setup with vdfcreate command\n    //\n    const size_t *bs = amrio->GetBlockSize();\n    for (int i = 0; i < 3; i++) {\n        if (bs[i] != CellDim) {\n            cerr << ProgName << \" : Invalid block size\" << endl;\n            exit(1);\n        }\n    }\n    const size_t *dim = amrio->GetDimension();\n    for (int i = 0; i < 3; i++) {\n        if (dim[i] != N) {\n            cerr << ProgName << \" : Invalid dimension : \" << dim[i] << endl;\n            exit(1);\n        }\n    }\n    int nlevels = amrio->GetNumTransforms();\n    if (nlevels != NLevels) {\n        cerr << ProgName << \" : Invalid number of refinment levels\" << endl;\n        exit(1);\n    }\n\n    // The dimensions of the base level AMR mesh specified in blocks (cells)\n    size_t basedim = (N / CellDim) >> NLevels;\n    VAssert(basedim >= 5);    // we' going to refine the boundaries twice\n    size_t basedimv[3] = {basedim, basedim, basedim};\n\n    // User coordinate system extents. Can be set to anything\n    //\n    double min[3] = {0.0, 0.0, 0.0};\n    double max[3] = {1.0, 1.0, 1.0};\n\n    //\n    // Create an AMRTree object to express the AMR refinement hierarchy\n    //\n    // The tree starts out as a rectilinear grid of cells with dimension\n    // given by basedim\n    //\n    cout << ProgName << \" : Tree create start\" << endl;\n    AMRTree *tree = new AMRTree(basedimv, min, max);\n    if (AMRTree::GetErrCode() != 0) {\n        fprintf(stderr, \"AMRTree() : %s\\n\", AMRTree::GetErrMsg());\n        exit(1);\n    }\n\n    // Refine the tree: The boundary cells are left unrefined. The cells\n    // boardering the boundary cells are refined once. Everything else is\n    // refined twice.\n    //\n    for (AMRTree::cid_t z = 1; z < basedim - 1; z++) {\n        for (AMRTree::cid_t y = 1; y < basedim - 1; y++) {\n            for (AMRTree::cid_t x = 1; x < basedim - 1; x++) {\n                size_t xyz[] = {x, y, z};\n\n                AMRTree::cid_t cellid = tree->GetCellID(xyz, 0);\n\n                tree->RefineCell(cellid);\n            }\n        }\n    }\n\n    for (AMRTree::cid_t z = 2; z < basedim - 2; z++) {\n        for (AMRTree::cid_t y = 2; y < basedim - 2; y++) {\n            for (AMRTree::cid_t x = 2; x < basedim - 2; x++) {\n                size_t xyz[] = {x, y, z};\n\n                AMRTree::cid_t cellid = tree->GetCellID(xyz, 0);\n                AMRTree::cid_t child = tree->GetCellChildren(cellid);\n\n                for (AMRTree::cid_t i = 0; i < 8; i++) { tree->RefineCell(child + i); }\n            }\n        }\n    }\n\n    //\n    // Calling EndRefinement() is optional, but it can signficantly\n    // improve performance,  namely when calling AMRData::GetBlock\n    //\n    tree->EndRefinement();\n\n    cout << ProgName << \" : Tree create finished\" << endl;\n\n    // Print out info about the tree hierarchy\n    //\n    if (opt.debug) {\n        int            level;\n        bool           first = true;\n        AMRTree::cid_t cellid;\n        while ((cellid = tree->GetNextCell(first)) >= 0) {\n            size_t         xyz[3], xyz_b[3];\n            AMRTree::cid_t baseblockidx;\n            AMRTree::cid_t nodeidx;\n            first = false;\n\n            tree->GetCellLocation(cellid, xyz, &level);\n            tree->DecodeCellID(cellid, &baseblockidx, &nodeidx);\n            xyz_b[0] = xyz[0] >> level;\n            xyz_b[1] = xyz[1] >> level;\n            xyz_b[2] = xyz[2] >> level;\n            cerr << \"level, id, location base_location \" << level << \" (\" << baseblockidx << \" \" << nodeidx << \") (\" << xyz[0] << \" \" << xyz[1] << \" \" << xyz[2] << \") (\" << xyz_b[0] << \" \" << xyz_b[1]\n                 << \" \" << xyz_b[2] << \")\" << endl;\n        }\n    }\n\n    //\n    // Open a tree for writing at the indicated time step. Only one\n    // tree is needed per time step (all variables at a given\n    // time step must have the same hierarchy).\n    //\n    if (amrio->OpenTreeWrite(0) < 0) {\n        cerr << ProgName << \" : \" << amrio->GetErrMsg() << endl;\n        exit(1);\n    }\n\n    if (amrio->TreeWrite(tree) < 0) {\n        cerr << ProgName << \" : \" << amrio->GetErrMsg() << endl;\n        exit(1);\n    }\n\n    if (amrio->CloseTree() < 0) {\n        cerr << ProgName << \" : \" << amrio->GetErrMsg() << endl;\n        exit(1);\n    }\n\n    // Create an AMRData object to store the sampled solution data. Each\n    // cell in the AMR tree is of dimension CellDim by CellDim by CellDim\n    //\n    size_t   cell_dim[] = {CellDim, CellDim, CellDim};\n    AMRData *amrdata = new AMRData(tree, cell_dim);\n\n    // Create a synthetic data set and place it in the tree\n    //\n    float *grid = make_marschner_lobb(N, N, N);\n    cout << ProgName << \" : variable 1 create start\" << endl;\n    process_variable(amrio, tree, amrdata, grid, \"ml\");\n    cout << ProgName << \" : variable 1 create finished\" << endl;\n    delete[] grid;\n\n    grid = make_checker(N, N, N, 8);\n    cout << ProgName << \" : variable 2 create start\" << endl;\n    process_variable(amrio, tree, amrdata, grid, \"checker\");\n    cout << ProgName << \" : variable 2 create finished\" << endl;\n    delete[] grid;\n\n    exit(0);\n}\n"
  },
  {
    "path": "share/examples/generateExampleDCP.py",
    "content": "# Run this file to create an example DCP dataset\n\n\nfrom netCDF4 import Dataset\nimport numpy as np\n\n\nN = 2000\ndim = 3\nnp.random.seed(0)\npos = np.random.random_sample((N,dim))*200-100\nvel = np.random.random_sample((N,dim))*20-1\n\n\n# Generate example particles for next timestep\ndef StepSimulation() -> None:\n    global pos, vel\n    G = 3000\n    r = np.sqrt(np.sum(pos**2, axis=-1))\n    r = np.clip(r, 10, 100**2)\n    d = -pos/r[:,None]\n    vel += d*(G/r**2)[:,None]\n    pos += vel * 0.1\n    filt = np.column_stack((pos,vel))[np.all((pos>-100) & (pos<100), axis=1)]\n    pos = filt[:, 0:dim]\n    vel = filt[:, dim:dim*2]\n\n\n# Wraps an array in an additional dimension\n# This is required for data time varying data that is only spacial\n# as is this case in this demo\ndef AddTimeDim(data: np.ndarray) -> np.ndarray:\n    return np.expand_dims(data, axis=0)\n\n\ndef WriteTimestep(ts: float, positionData: np.ndarray, **kwargs: np.ndarray) -> None:\n    dataset = Dataset(f\"particles_{ts:03}.nc\", \"w\", format=\"NETCDF4\")\n\n    particleCount:int = positionData.shape[0]\n    dataset.createDimension(\"P\", particleCount) # The P dimension represents the number of particles at this timestep\n    dataset.createDimension(\"T\", None) # Time dimension\n    dataset.createDimension(\"axis\", 3) # Utility dimension for packing 3 components for 3D particles into a single variable\n\n    # Time coordinate\n    T = dataset.createVariable(\"T\", \"f8\", (\"T\",))\n    T.units = \"seconds\"\n    T[:] = np.array([ts])\n\n    # 3D vars can be packed in a single variable by adding the axis dimension\n    Position = dataset.createVariable(\"Position\", \"f4\", (\"T\", \"P\", \"axis\"), zlib=True)\n    # positionData is 2D (numParticles * axis) whereas Position is 3D (time * numParticles * axis)\n    Position[:] = AddTimeDim(positionData)\n    # Alternatively, you could do the following:\n    # Position_x = dataset.createVariable(\"Position_x\", \"f4\", (\"T\", \"P\"), zlib=True)\n    # Position_x[:] = AddTimeDim(positionData_x:1d array)\n    # and so on for the other 2 axes\n\n    # Save all remaining particle properties passed in to nc file\n    for name, data in kwargs.items():\n        var = dataset.createVariable(name, \"f4\", (\"T\", \"P\", \"axis\")[0:data.ndim + 1], zlib=True)\n        var[:] = AddTimeDim(data)\n\n    dataset.close()\n\n\nfor ts in range(400):\n    # Compute magnitude of velocity for each particle\n    speed = np.sqrt(np.sum(vel**2, axis=-1))\n    # Since 3-component properties such as velocity are common for 3D particles,\n    # DCP allows packing them as a 2D array of size N_particles by 3\n    # vel is an array of size Nx3 and speed is an array of size N\n    WriteTimestep(ts, pos, vel=vel, speed=speed)\n    # The following would also work\n    # WriteTimestep(ts, pos, vel_x=vel[:,0], vel_y=vel[:,1], vel_z=vel[:,2], speed=speed)\n    StepSimulation()\n"
  },
  {
    "path": "share/examples/idl/AddCurlVDF.pro",
    "content": "\r\n;   AddCurlVDF.pro\r\n;\r\n;   Utility to read three variables from a VDF, calculate their curl\r\n;   and optionally the curl's magnitude, and put them back into the VDF.\r\n;   All three variables must be present at full resolution.\r\n;\r\n;   The .pro files curl_findiff.pro and deriv_findiff.pro must be in the\r\n;   directory from which you started idl.\r\n;\r\n;   The vdf file is replaced.  The previous vdf file is saved, with\r\n;   _saved appended to its name, in case of catastrophic failure\r\n;\r\n;   Arguments are:\r\n;   vdffile = file path of the metadata file\r\n;   varx, vary, varz = the 3 variables defining the field \r\n;       whose curl is being calculated\r\n;   curlx,curly,curlz = the names for the three components\r\n;       of the curl being calculated\r\n;   tsstart = the time step to start with (or the only time step)\r\n;   tsmax = (keyword parameter) the time step to stop with (don't specify\r\n;           if you only want the one time step, tsstart)\r\n;   tsival = (keyword parameter) the interval between time steps (will compute\r\n;            info for tsstart, tsstart + tsival, etc.) (again, don't specify if\r\n;            you only want the one time step, tsstart)\r\n;   mag = (keyword parameter) name of curl's magnitude (do not specify if you\r\n;         don't want the\r\n;         magnitude of the curl written)\r\n;   onlymag = (keyword parameter) set this to anything if you only want the \r\n;             curl's magnitude and not the actual vector field (note that you\r\n;             must still supply names for curlx, curly, curlz)\r\n;\r\n;   Note: if you want to add the magnitude later, use AddMagVDF\r\n;\r\n\r\nPRO AddCurlVDF, vdffile,varx,vary,varz,curlx,curly,curlz,tsstart, $\r\n                TSMAX=tsmax,TSIVAL=tsival,MAG=mag,ONLYMAG=onlymag\r\n\r\n;   Make sure we're actually doing something\r\nIF ( ~keyword_set(mag) && keyword_set(onlymag) ) THEN BEGIN\r\n    print, \"Neither curl nor curl's magnitude requested.  Nothing modified.\"\r\n    RETURN\r\nENDIF\r\n\r\n\r\n;   \r\n;   Variable timestep now functions as a switch and initializer\r\n;\r\ntimestep = tsstart\r\nIF ( ~keyword_set(tsmax) ) THEN tsmax=tsstart\r\nIF ( ~keyword_set(tsival) ) THEN tsival=1\r\n\r\n;\r\n;   Start with the current metadata:\r\n;\r\n\r\nmfd = vdf_create(vdffile)\r\n\r\n;\r\n;   save the current vdf file (in case we screw up)\r\n;\r\n\r\nsavedvdffile = STRING(vdffile,'_saved')\r\nvdf_write,mfd,savedvdffile\r\n\r\n;\r\n;   Add the new variable names to the current variable names:\r\n;\r\n\r\n;\r\n;   How many variable names?\r\n;\r\nIF ( keyword_set(mag) && ~keyword_set(onlymag) ) THEN newnum = 4 \r\nIF ( keyword_set(mag) && keyword_set(onlymag) ) THEN newnum = 1\r\nIF ( ~keyword_set(mag) ) THEN newnum = 3\r\n\r\nnvarnames3d = 0\r\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\r\n        varnames = vdf_getvariables3d(mfd)\r\n        nvarnames3d = n_elements(varnames)\r\nendif\r\n\r\nnvarnames2dxy = 0\r\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\r\n        varnames2dxy = vdf_getvariables2dxy(mfd)\r\n        nvarnames2dxy = n_elements(varnames2dxy)\r\nendif\r\n\r\nnumvarsarray = size(varnames)\r\nnumvars = newnum + numvarsarray[1]\r\nnewvarnames = strarr(numvars)\r\n;   Need to make sure the new var names are not in the list!\r\nrepeatvariables = 0\r\nprint, 'num 3D vars = ',numvars\r\nFOR I = 0, numvars-newnum-1 DO BEGIN\r\n    newvarnames[I] = varnames[I]\r\n    IF ( ~keyword_set(onlymag) ) THEN BEGIN\r\n        IF (varnames[I] EQ curlx) THEN repeatvariables = 1+repeatvariables\r\n        IF (varnames[I] EQ curly) THEN repeatvariables = 1+repeatvariables\r\n        IF (varnames[I] EQ curlz) THEN repeatvariables = 1+repeatvariables\r\n    ENDIF\r\n        IF ( keyword_set(mag) ) THEN BEGIN\r\n        IF ( varnames [I] EQ mag ) THEN repeatvariables += 1\r\n    ENDIF\r\nENDFOR\r\n\r\nIF (repeatvariables GT 0 AND repeatvariables LT newnum) THEN BEGIN\r\n    print, 'ERROR:  some but not all curl variable names exist already'\r\n    STOP\r\nENDIF\r\n\r\nIF (repeatvariables EQ 0) THEN BEGIN\r\n    IF ( ~keyword_set(onlymag) ) THEN BEGIN\r\n        newvarnames[numvars-newnum] = curlx\r\n        newvarnames[numvars-newnum+1] = curly\r\n        newvarnames[numvars-newnum+2] = curlz\r\n    ENDIF\r\n    IF ( keyword_set(mag) && ~keyword_set(onlymag) ) THEN $\r\n        newvarnames[numvars-newnum+3] = mag\r\n    IF ( keyword_set(onlymag) ) THEN newvarnames[numvars-newnum] = mag\r\nENDIF\r\n\r\nIF (repeatvariables EQ newnum) THEN newvarnames = varnames\r\n\r\n\r\n;\r\n;   reset the varnames in mfd to the new value:\r\n;   provided not all variables are repeated\r\n;   Note that by default all variable names are 3D\r\n;\r\nif (repeatvariables NE newnum) THEN BEGIN\r\n\tif (nvarnames2dxy gt 0) THEN BEGIN \r\n\t\tvdf_setvarnames,mfd,[newvarnames,varnames2dxy]\r\n\t\tvdf_setvariables2DXY,mfd,varnames2dxy\r\n\tENDIF ELSE BEGIN\r\n\t\tvdf_setvarnames,mfd,newvarnames\r\n\tENDELSE\r\nENDIF\r\n\r\nreflevel = vdf_getnumtransforms(mfd)\r\n\r\n;\r\n;   Begin loop that iterates over time steps\r\n;\r\nREPEAT BEGIN\r\n\r\nprint, \"Working on time step \", timestep\r\n\r\n;\r\n;   Create \"Buffered Read\" objects for each variable to read the data, passing the\r\n;   metadata object handle created by vdf_create() as an argument\r\n;\r\n\r\ndfdx = vdc_bufreadcreate(mfd)\r\ndfdy = vdc_bufreadcreate(mfd)\r\ndfdz = vdc_bufreadcreate(mfd)\r\n\r\n;\r\n;\r\n;   Determine the dimensions of the x-variable at the full transformation\r\n;   level.\r\n;   This is used as the dimension of all the variables\r\n;\r\n\r\ndim = vdc_getdim(dfdx, reflevel)\r\n\r\n;\r\n;   Create appropriately sized arrays to hold the source and result data\r\n;\r\n\r\nsrcx = fltarr(dim[0],dim[1],dim[2])\r\nsrcy = fltarr(dim[0],dim[1],dim[2])\r\nsrcz = fltarr(dim[0],dim[1],dim[2])\r\n\r\ndstx = fltarr(dim[0],dim[1],dim[2])\r\ndsty = fltarr(dim[0],dim[1],dim[2])\r\ndstz = fltarr(dim[0],dim[1],dim[2])\r\n\r\n;\r\n;   Prepare to read the indicated time step and variables\r\n;\r\n\r\nvdc_openvarread, dfdx, timestep, varx, reflevel\r\n\r\n;\r\n;   Read the volume one slice at a time\r\n;\r\nslcx = fltarr(dim[0],dim[1])\r\nslcy = fltarr(dim[0],dim[1])\r\nslcz = fltarr(dim[0],dim[1])\r\n\r\n;   Determine the grid spacing\r\n\r\nextents = VDF_GETEXTENTS(mfd)\r\ndeltax = (extents[3] - extents[0])/FLOAT(dim[0])\r\ndeltay = (extents[4] - extents[1])/FLOAT(dim[1])\r\ndeltaz = (extents[5] - extents[2])/FLOAT(dim[2])\r\n\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    vdc_bufreadslice, dfdx, slcx\r\n\r\n    ; copy to 3d array\r\n    srcx[*,*,z] = slcx\r\n\r\n    ;  Report every 100 reads:\r\n    IF ((z MOD 100) EQ 0) THEN print,'reading x  slice ',z\r\nENDFOR\r\nvdc_closevar, dfdx\r\nvdc_bufreaddestroy, dfdx\r\nvdc_openvarread, dfdy, timestep, vary, reflevel\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    vdc_bufreadslice, dfdy, slcy\r\n    ; copy to 3d array\r\n    srcy[*,*,z] = slcy\r\n    ;  Report every 100 reads:\r\n    IF ((z MOD 100) EQ 0) THEN print,'reading y  slice ',z\r\nENDFOR\r\n\r\nvdc_closevar, dfdy\r\nvdc_bufreaddestroy, dfdy\r\nvdc_openvarread, dfdz, timestep, varz, reflevel\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    vdc_bufreadslice, dfdz, slcz\r\n    ; copy to 3d array\r\n    srcz[*,*,z] = slcz\r\n    ;  Report every 100 reads:\r\n    IF ((z MOD 100) EQ 0) THEN print,'reading z  slice ',z\r\nENDFOR\r\n\r\nvdc_closevar, dfdz\r\nvdc_bufreaddestroy, dfdz\r\n;  Now perform the curl on the data\r\ncurl_findiff,srcx,srcy,srcz,dstx,dsty,dstz,deltax,deltay,deltaz\r\n\r\nprint,'performed the curl on ',varx,' ', vary,' ', varz\r\n\r\n\r\nIF ( ~keyword_set(onlymag) ) THEN BEGIN\r\n\r\n    dfdcurlx = vdc_bufwritecreate(mfd)\r\n    vdc_openvarwrite, dfdcurlx, timestep, curlx, reflevel\r\n    ; write the data one slice at a time\r\n    FOR z = 0, dim[2]-1 DO BEGIN\r\n        slcx = dstx[*,*,z]\r\n        vdc_bufwriteslice,dfdcurlx, slcx\r\n        ;  Report every 100 writes:\r\n        IF ((z MOD 100) EQ 0) THEN print,'writing x slice ',z\r\n    ENDFOR\r\n    vdc_closevar, dfdcurlx\r\n    vdc_bufwritedestroy, dfdcurlx\r\n\r\n    dfdcurly = vdc_bufwritecreate(mfd)\r\n    vdc_openvarwrite, dfdcurly, timestep, curly, reflevel\r\n    FOR z = 0, dim[2]-1 DO BEGIN\r\n        slcy = dsty[*,*,z]\r\n        vdc_bufwriteslice,dfdcurly, slcy\r\n        ;  Report every 100 writes:\r\n        IF ((z MOD 100) EQ 0) THEN print,'writing y slice ',z\r\n    ENDFOR\r\n    vdc_closevar, dfdcurly\r\n    vdc_bufwritedestroy, dfdcurly\r\n\r\n    dfdcurlz = vdc_bufwritecreate(mfd)\r\n    vdc_openvarwrite, dfdcurlz, timestep, curlz, reflevel\r\n    FOR z = 0, dim[2]-1 DO BEGIN\r\n        slcz = dstz[*,*,z]\r\n        vdc_bufwriteslice,dfdcurlz, slcz\r\n        ;  Report every 100 writes:\r\n        IF ((z MOD 100) EQ 0) THEN print,'writing z slice ',z\r\n    ENDFOR\r\n    vdc_closevar, dfdcurlz\r\n    vdc_bufwritedestroy, dfdcurlz\r\n\r\nENDIF\r\n\r\n;\r\n; If desired, compute and write the magnitude of the curl\r\n;\r\nIF ( keyword_set(mag) ) THEN BEGIN\r\n    dfdmag = vdc_bufwritecreate(mfd)\r\n    allMag = fltarr(dim[0],dim[1],dim[2])\r\n    allMag = sqrt( dstx^2 + dsty^2 + dstz^2 )\r\n    slcmag = fltarr(dim[0],dim[1])\r\n    vdc_openvarwrite, dfdmag, timestep, mag, reflevel\r\n    FOR z = 0, dim[2]-1 DO BEGIN\r\n        slcmag = allMag[*,*,z]\r\n        vdc_bufwriteslice, dfdmag, slcmag\r\n        ;  Report every 100 writes\r\n        IF ( (z MOD 100) EQ 0) THEN print, \"Writing magnitude's z slice \", z\r\n    ENDFOR\r\n    vdc_closevar, dfdmag\r\n    vdc_bufwritedestroy, dfdmag\r\nENDIF\r\n\r\n;\r\n;  First time, replace the vdf file with the new one\r\n;\r\n\r\nIF (timestep EQ tsstart AND repeatvariables NE newnum) THEN vdf_write,mfd,vdffile\r\n\r\n\r\nprint,'Curl completed'\r\n\r\ntimestep += tsival\r\n\r\nENDREP UNTIL ( timestep GT tsmax )\r\n\r\nvdf_destroy, mfd\r\n\r\nEND\r\n"
  },
  {
    "path": "share/examples/idl/AddDivVDF.pro",
    "content": "\r\n;   AddDivVDF.pro\r\n;\r\n;   Utility to read three variables from a VDF, calculate their divergence \r\n;   and put it back into the VDF.\r\n;   All three variables must be present at full resolution.\r\n;\r\n;   The .pro files deriv_findiff.pro and div_findiff.pro must be in the\r\n;   directory from which you started idl.\r\n;\r\n;   The vdf file is replaced.  The previous vdf file is saved, with\r\n;   _saved appended to its name, in case of catastrophic failure\r\n;\r\n;   Arguments are:\r\n;   vdffile = file path of the metadata file\r\n;   varx, vary, varz = the 3 variables defining the field \r\n;       whose divergence is being calculated\r\n;   divvar = the name for the divergence variable being calculated \r\n;   tsstart = the time step to start with (or the only time step)\r\n;   tsmax = (keyword parameter) the time step to stop with (don't specify\r\n;           if you only want the one time step, tsstart)\r\n;   tsival = (keyword parameter) the interval between time steps (will compute\r\n;            info for tsstart, tsstart + tsival, etc.) (again, don't specify if\r\n;            you only want the one time step, tsstart)\r\n;\r\n\r\nPRO AddDivVDF, vdffile,varx,vary,varz,divvar,tsstart, $\r\n                TSMAX=tsmax,TSIVAL=tsival\r\n\r\n\r\n;   \r\n;   Variable timestep now functions as a switch and initializer\r\n;\r\ntimestep = tsstart\r\nIF ( ~keyword_set(tsmax) ) THEN tsmax=tsstart\r\nIF ( ~keyword_set(tsival) ) THEN tsival=1\r\n\r\n;\r\n;   Start with the current metadata:\r\n;\r\n\r\nmfd = vdf_create(vdffile)\r\n\r\n;\r\n;   save the current vdf file (in case we screw up)\r\n;\r\n\r\nsavedvdffile = STRING(vdffile,'_saved')\r\nvdf_write,mfd,savedvdffile\r\n\r\n;\r\n;   Add the new variable name to the current variable names:\r\n;\r\n\r\nnvarnames3d = 0\r\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\r\n        varnames = vdf_getvariables3d(mfd)\r\n        nvarnames3d = n_elements(varnames)\r\nendif\r\n\r\nnvarnames2dxy = 0\r\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\r\n        varnames2dxy = vdf_getvariables2dxy(mfd)\r\n        nvarnames2dxy = n_elements(varnames2dxy)\r\nendif\r\n\r\nnumvarsarray = size(varnames)\r\nnumvars = 1 + numvarsarray[1]\r\nnewvarnames = strarr(numvars)\r\n;   Need to make sure the new var name is not in the list!\r\nisinvariables = 0\r\nFOR I = 0, numvars-2 DO BEGIN\r\n        newvarnames[I] = varnames[I]\r\n        if (varnames[I] EQ divvar) THEN isinvariables = 1\r\nENDFOR\r\n\r\nIF (isinvariables EQ 0) THEN newvarnames[numvars-1] = divvar ELSE newvarnames = varnames\r\n\r\nprint,'The 3D variable names in the vdf will be: ',newvarnames\r\n\r\n;\r\n;   reset the varnames in mfd to the new value:\r\n;   provided not all variables are repeated\r\n;   Note that by default all variable names are 3D\r\n;\r\nif (isinvariables EQ 0) THEN BEGIN\r\n\tif (nvarnames2dxy gt 0) THEN BEGIN\r\n\t\tvdf_setvarnames,mfd,[newvarnames,varnames2d]\r\n\t\tvdf_setvariables2DXY,mfd,varnames2d\r\n\tENDIF ELSE BEGIN\r\n\t\tvdf_setvarnames,mfd,newvarnames\r\n\tENDELSE\r\nENDIF\r\n\r\nreflevel = vdf_getnumtransforms(mfd)\r\n\r\n;\r\n;   Begin loop that iterates over time steps\r\n;\r\nREPEAT BEGIN\r\n\r\nprint, \"Working on time step \", timestep\r\n\r\n;\r\n;   Create \"Buffered Read\" objects for each variable to read the data, passing the\r\n;   metadata object handle created by vdf_create() as an argument\r\n;\r\n\r\ndfdx = vdc_bufreadcreate(mfd)\r\ndfdy = vdc_bufreadcreate(mfd)\r\ndfdz = vdc_bufreadcreate(mfd)\r\ndfddiv = vdc_bufwritecreate(mfd)\r\n\r\n;\r\n;\r\n;   Determine the dimensions of the x-variable at the full transformation\r\n;   level.\r\n;   This is used as the dimension of all the variables\r\n;\r\n\r\ndim = vdc_getdim(dfdx, reflevel)\r\n\r\n;\r\n;   Create appropriately sized arrays to hold the source and result data\r\n;\r\n\r\nsrcx = fltarr(dim[0],dim[1],dim[2])\r\nsrcy = fltarr(dim[0],dim[1],dim[2])\r\nsrcz = fltarr(dim[0],dim[1],dim[2])\r\n\r\ndivarray = fltarr(dim[0],dim[1],dim[2])\r\n\r\n;\r\n;   Prepare to read the indicated time step and variables\r\n;\r\n\r\nvdc_openvarread, dfdx, timestep, varx, reflevel\r\nvdc_openvarread, dfdy, timestep, vary, reflevel\r\nvdc_openvarread, dfdz, timestep, varz, reflevel\r\nvdc_openvarwrite, dfddiv, timestep,divvar , reflevel\r\n\r\n;\r\n;   Read the volume one slice at a time\r\n;\r\nslcx = fltarr(dim[0],dim[1])\r\nslcy = fltarr(dim[0],dim[1])\r\nslcz = fltarr(dim[0],dim[1])\r\n\r\n;   Determine the grid spacing\r\n\r\nextents = VDF_GETEXTENTS(mfd)\r\ndeltax = (extents[3] - extents[0])/FLOAT(dim[0])\r\ndeltay = (extents[4] - extents[1])/FLOAT(dim[1])\r\ndeltaz = (extents[5] - extents[2])/FLOAT(dim[2])\r\n\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    vdc_bufreadslice, dfdx, slcx\r\n    ; copy to 3d array\r\n    srcx[*,*,z] = slcx\r\n    vdc_bufreadslice, dfdy, slcy\r\n    srcy[*,*,z] = slcy\r\n    vdc_bufreadslice, dfdz, slcz\r\n    srcz[*,*,z] = slcz\r\n    ;  Report every 100 reads:\r\n    IF ((z MOD 100) EQ 0) THEN print,'reading x  slice ',z\r\nENDFOR\r\nvdc_closevar, dfdx\r\nvdc_bufreaddestroy, dfdx\r\n\r\nvdc_closevar, dfdy\r\nvdc_bufreaddestroy, dfdy\r\nvdc_closevar, dfdz\r\nvdc_bufreaddestroy, dfdz\r\n\r\n;  Now perform the divergence on the data\r\ndiv_findiff,srcx,srcy,srcz,divarray,deltax,deltay,deltaz\r\n\r\nprint,'performed the divergence on ',varx,' ', vary,' ', varz\r\n\r\n; write the data one slice at a time\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    slc = divarray[*,*,z]\r\n    vdc_bufwriteslice,dfddiv, slc\r\n    ;  Report every 100 writes:\r\n    IF ((z MOD 100) EQ 0) THEN print,'writing x slice ',z\r\nENDFOR\r\nvdc_closevar, dfddiv\r\nvdc_bufwritedestroy, dfddiv\r\n\r\n;\r\n;  First time, replace the vdf file with the new one\r\n;\r\n\r\nIF (timestep EQ tsstart AND isinvariables EQ 0) THEN vdf_write,mfd,vdffile\r\n\r\nprint,'Divergence completed'\r\n\r\ntimestep += tsival\r\n\r\nENDREP UNTIL ( timestep GT tsmax )\r\n\r\nvdf_destroy, mfd\r\n\r\nEND\r\n"
  },
  {
    "path": "share/examples/idl/AddMagVDF.pro",
    "content": ";\n;\tAddMagVDF.pro\n;\n;\tUtility to read three 3D variables from a VDF and calculate their magnitude\n;\tand put it back into the VDF.\n;\tAll three variables must be present at full resolution.\n;\tThis is performed one time-step at a time.\n;\tThe vdf file is replaced.  The previous vdf file is saved, with\n;\t_saved appended to its name, in case of catastrophic failure \n;\t \n;\tArguments are:\n;\tvdffile = file path of the metadata file\n;\tvarx, vary, varz = the 3 3D variables defining the field\n;\t\twhose magnitude is being calculated\n;\tmagvarname is the name for the field magnitude being calculated\n;\ttsstart specifies the first timestep for which the magnitude\n;\t\tis calculated.  If multiple timesteps are needed,\n;\tkeyword variables:\n;       tsmax = largest time step\n;\ttsival = increment between time steps\t\n;\n\nPRO AddMagVDF,vdffile,varx,vary,varz,magvarname,tsstart,$\n\tTSMAX=tsmax,TSIVAL=tsival\n\n;\n;   Set up timesteps\n;\ntimestep = tsstart\nIF (~keyword_set(tsmax)) THEN tsmax = tsstart\nIF (~keyword_set(tsival)) THEN tsival = 1\n\n\n;\n;\tStart with the current metadata:\n;\n\nmfd = vdf_create(vdffile)\n\n;\n; \tsave the current vdf file (in case we screw up)\n;\n\nsavedvdffile = STRING(vdffile,'_saved')\nvdf_write,mfd,savedvdffile\n\n;\n; \tAdd the new variable name to the current variable names:\n;\n\nnvarnames3d = 0\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\n        varnames = vdf_getvariables3d(mfd)\n        nvarnames3d = n_elements(varnames)\nendif\n\nnvarnames2dxy = 0\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\n        varnames2dxy = vdf_getvariables2dxy(mfd)\n        nvarnames2dxy = n_elements(varnames2dxy)\nendif\n\n\nnumvarsarray = size(varnames)\nnumvars = 1 + numvarsarray[1]\nnewvarnames = strarr(numvars) \n;  \tNeed to make sure this is not in the list!\nisinvariables = 0\nFOR I = 0, numvars-2 DO BEGIN\n\tnewvarnames[I] = varnames[I]\n\tif (varnames[I] EQ magvarname) THEN isinvariables = 1\nENDFOR\n\t\nIF (isinvariables EQ 0) THEN newvarnames[numvars-1] = magvarname ELSE newvarnames = varnames\n\nprint,'The 3D variable names in the vdf will be: ',newvarnames\n\n;\n;\treset the varnames in mfd to the new value:\n;\tand set the 2d vars if there are any\n;\n\nif (isinvariables EQ 0) THEN BEGIN\n\tif (nvarnames2dxy gt 0) THEN BEGIN\n\t\tvdf_setvarnames,mfd,[newvarnames,varnames2dxy]\n\t\tvdf_setvariables2dxy,mfd,varnames2dxy\n\tENDIF ELSE BEGIN\n\t\tvdf_setvarnames,mfd,newvarnames\n\tENDELSE\nENDIF\n\nreflevel = vdf_getnumtransforms(mfd)\nnumtimesteps = vdf_getnumtimesteps(mfd)\n\nREPEAT BEGIN\n\n;\n;\tCreate \"Buffered Read\" objects for each variable to read the data, passing the \n;\tmetadata object handle created by vdf_create() as an argument\n;\n\ndfdx = vdc_bufreadcreate(mfd)\ndfdy = vdc_bufreadcreate(mfd)\ndfdz = vdc_bufreadcreate(mfd)\ndfdmag = vdc_bufwritecreate(mfd)\n\n;\n;\n;\tDetermine the dimensions of the x-variable at the full transformation\n;\tlevel. \n;\tThis is used as the dimension of all the variables\n;\tNote. vdc_getdim() correctly handles dimension calucation for \n;\tvolumes with non-power-of-two dimensions. \n; \n\ndim = vdc_getdim(dfdx, reflevel)\n\n;\n;\tCreate appropriately sized arrays to hold the volume slices:\n;\n\nslicex = fltarr(dim[0], dim[1])\nslicey = fltarr(dim[0], dim[1])\nslicez = fltarr(dim[0], dim[1])\nslicemag = fltarr(dim[0], dim[1])\nslicemagsq = fltarr(dim[0], dim[1])\n\n\n;\n;\tPrepare to read and write the indicated time step and variables\n;\n\nvdc_openvarread, dfdx, timestep, varx, reflevel\nvdc_openvarread, dfdy, timestep, vary, reflevel\nvdc_openvarread, dfdz, timestep, varz, reflevel\nvdc_openvarwrite,dfdmag, timestep, magvarname, reflevel\n\n;\n;\tRead the volume one slice at a time\n;\n\nFOR z = 0, dim[2]-1 DO BEGIN \n\tvdc_bufreadslice, dfdx, slicex\n\tvdc_bufreadslice, dfdy, slicey\n\tvdc_bufreadslice, dfdz, slicez\n\t\n\tslicemagsq = slicex*slicex + slicey*slicey + slicez*slicez \n\tslicemag = sqrt(slicemagsq) \n\t\n\tvdc_bufwriteslice, dfdmag, slicemag\n\n\t; \tReport every 100 writes:\n\n\tIF ((Z MOD 100) EQ 0) THEN print,'wrote slice ',z\n\nENDFOR\n\nvdc_closevar, dfdmag \nvdc_closevar, dfdx\nvdc_closevar, dfdy\nvdc_closevar, dfdz\n\nvdc_bufwritedestroy, dfdmag\nvdc_bufreaddestroy, dfdx\nvdc_bufreaddestroy, dfdy\nvdc_bufreaddestroy, dfdz\n\n\n;\n;  Replace the vdf file with the new one, the first time through:\n;\nIF (timestep EQ tsstart AND isinvariables EQ 0) THEN vdf_write,mfd,vdffile\n\nprint,'Magnitude calculated of timestep ', timestep\n\ntimestep += tsival\n\nENDREP UNTIL (timestep GT tsmax)\nvdf_destroy, mfd\n\nend\n"
  },
  {
    "path": "share/examples/idl/AddWRFCurl.pro",
    "content": ";\r\n;   AddWRFCurl.pro\r\n;\r\n;   Utility to read three variables from a WRF VDF, calculate their curl\r\n;   and put them back into the VDF.\r\n;   All three variables and ELEVATION must be present at full resolution.\r\n;\r\n;   The .pro files wrf_curl_findiff.pro and deriv_findiff.pro  \r\n;   and elev_deriv.pro must be in the\r\n;   directory from which you started idl.\r\n;\r\n;   The vdf file is replaced.  The previous vdf file is saved, with\r\n;   _saved appended to its name, in case of catastrophic failure\r\n;\r\n;   Arguments are:\r\n;   vdffile = file path of the metadata file\r\n;   varx, vary, varz = the 3 variables defining the file\r\n;       whose magnitude is being calculated\r\n;   curlx,curly,curlz = the names for the three components\r\n;       of the curl being calculated\r\n;   tsstart = the first (smallest) time step this is applied to\r\n;     keyword args:\r\n;   tsmax = the largest time step this is applied to\r\n;   tsival = the increment between successive time steps  \r\n;   mag = (keyword parameter) name of curl's magnitude (do not specify if you\r\n;         don't want the\r\n;         magnitude of the curl written)\r\n;   onlymag = (keyword parameter) set this to anything if you only want the\r\n;             curl's magnitude and not the actual vector field (note that you\r\n;             must still supply names for curlx, curly, curlz)\r\n;\r\n;   Note: if you want to add the magnitude later, use AddMagVDF\r\n;\r\n\r\n;\r\n;\r\n\r\nPRO AddWRFCurl, vdffile,varx,vary,varz,curlx,curly,curlz,tsstart, $\r\n\t\tTSMAX=tsmax,TSIVAL=tsival,MAG=mag,ONLYMAG=onlymag\r\n\r\n;   Make sure we're actually doing something\r\nIF ( ~keyword_set(mag) && keyword_set(onlymag) ) THEN BEGIN\r\n    print, \"Neither curl nor curl's magnitude requested.  Nothing modified.\"\r\n    RETURN\r\nENDIF\r\n\r\n\r\n;\r\n;   Set up timesteps\r\n;\r\ntimestep = tsstart\r\nIF (~keyword_set(tsmax)) THEN tsmax = tsstart\r\nIF (~keyword_set(tsival)) THEN tsival = 1\r\n\r\n\r\n;\r\n;   Start with the current metadata:\r\n;\r\n\r\nmfd = vdf_create(vdffile)\r\n\r\n;\r\n;   save the current vdf file (in case we screw up)\r\n;\r\n\r\nsavedvdffile = STRING(vdffile,'_saved')\r\nvdf_write,mfd,savedvdffile\r\n\r\n;\r\n;   Add the new variable names to the current variable names:\r\n;\r\n\r\n;\r\n;   How many variable names?\r\n;\r\nIF ( keyword_set(mag) && ~keyword_set(onlymag) ) THEN newnum = 4\r\nIF ( keyword_set(mag) && keyword_set(onlymag) ) THEN newnum = 1\r\nIF ( ~keyword_set(mag) ) THEN newnum = 3\r\n\r\nnvarnames3d = 0\r\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\r\n        varnames = vdf_getvariables3d(mfd)\r\n        nvarnames3d = n_elements(varnames)\r\nendif\r\n\r\nnvarnames2dxy = 0\r\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\r\n        varnames2dxy = vdf_getvariables2dxy(mfd)\r\n        nvarnames2dxy = n_elements(varnames2dxy)\r\nendif\r\n\r\nnumvarsarray = size(varnames)\r\nnumvars = newnum + numvarsarray[1]\r\nnewvarnames = strarr(numvars)\r\n;   Need to make sure these are not in the list!\r\nrepeatvariables = 0\r\nprint, 'numvars = ',numvars\r\nFOR I = 0, numvars-newnum-1 DO BEGIN\r\n    newvarnames[I] = varnames[I]\r\n    IF ( ~keyword_set(onlymag) ) THEN BEGIN\r\n        IF (varnames[I] EQ curlx) THEN repeatvariables = 1+repeatvariables\r\n        IF (varnames[I] EQ curly) THEN repeatvariables = 1+repeatvariables\r\n        IF (varnames[I] EQ curlz) THEN repeatvariables = 1+repeatvariables\r\n    ENDIF\r\n        IF ( keyword_set(mag) ) THEN BEGIN\r\n        IF ( varnames [I] EQ mag ) THEN repeatvariables += 1\r\n    ENDIF\r\nENDFOR\r\n\r\nIF (repeatvariables GT 0 AND repeatvariables LT newnum) THEN BEGIN\r\n    print, 'ERROR:  some but not all curl variable names exist already'\r\n    STOP\r\nENDIF\r\n\r\nIF (repeatvariables EQ 0) THEN BEGIN\r\n    IF ( ~keyword_set(onlymag) ) THEN BEGIN\r\n        newvarnames[numvars-newnum] = curlx\r\n        newvarnames[numvars-newnum+1] = curly\r\n        newvarnames[numvars-newnum+2] = curlz\r\n    ENDIF\r\n    IF ( keyword_set(mag) && ~keyword_set(onlymag) ) THEN $\r\n        newvarnames[numvars-newnum+3] = mag\r\n    IF ( keyword_set(onlymag) ) THEN newvarnames[numvars-newnum] = mag\r\nENDIF\r\n\r\n;\r\n;   reset the varnames in mfd to the new value:\r\n;\r\nIF (repeatvariables EQ 0) THEN BEGIN\r\n\tif(nvarnames2dxy gt 0) THEN BEGIN\r\n\t\tvdf_setvarnames,mfd,[newvarnames,varnames2dxy]\r\n\t\tvdf_setvariables2dXY,mfd,varnames2dxy\r\n\tENDIF ELSE BEGIN\r\n\t\tvdf_setvarnames,mfd,newvarnames\r\n\tENDELSE\t\r\nENDIF\r\n\r\nreflevel = vdf_getnumtransforms(mfd)\r\n\r\nREPEAT BEGIN\r\n\r\nprint, \"Working on time step \", timestep\r\n\r\n;\r\n;   Create \"Buffered Read\" objects for each variable to read the data, passing the\r\n;   metadata object handle created by vdf_create() as an argument\r\n;\r\n\r\ndfdx = vdc_bufreadcreate(mfd)\r\ndfdy = vdc_bufreadcreate(mfd)\r\ndfdz = vdc_bufreadcreate(mfd)\r\ndfde = vdc_bufreadcreate(mfd)\r\n\r\n;\r\n;\r\n;   Determine the dimensions of the x-variable at the full transformation\r\n;   level.\r\n;   This is used as the dimension of all the variables\r\n;   Note. vdc_getdim() correctly handles dimension calucation for\r\n;   volumes with non-power-of-two dimensions.\r\n;\r\n\r\ndim = vdc_getdim(dfdx, reflevel)\r\n\r\n;\r\n;   Create appropriately sized arrays to hold the source and result data\r\n;\r\n\r\nsrcx = fltarr(dim[0],dim[1],dim[2])\r\nsrcy = fltarr(dim[0],dim[1],dim[2])\r\nsrcz = fltarr(dim[0],dim[1],dim[2])\r\nsrce = fltarr(dim[0],dim[1],dim[2])\r\n\r\ndstx = fltarr(dim[0],dim[1],dim[2])\r\ndsty = fltarr(dim[0],dim[1],dim[2])\r\ndstz = fltarr(dim[0],dim[1],dim[2])\r\n\r\n;\r\n;   Prepare to read the indicated time step and variables\r\n;\r\n\r\nvdc_openvarread, dfdx, timestep, varx, reflevel\r\nvdc_openvarread, dfdy, timestep, vary, reflevel\r\nvdc_openvarread, dfdz, timestep, varz, reflevel\r\nvdc_openvarread, dfde, timestep, 'ELEVATION', reflevel\r\n\r\n;\r\n;   Read the volume one slice at a time\r\n;\r\nslcx = fltarr(dim[0],dim[1])\r\nslcy = fltarr(dim[0],dim[1])\r\nslcz = fltarr(dim[0],dim[1])\r\nslce = fltarr(dim[0],dim[1])\r\n\r\n;   Determine the grid spacing\r\n\r\nextents = VDF_GETEXTENTS(mfd)\r\ndeltax = (extents[3] - extents[0])/FLOAT(dim[0])\r\ndeltay = (extents[4] - extents[1])/FLOAT(dim[1])\r\n\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    vdc_bufreadslice, dfdx, slcx\r\n\r\n    ; copy to 3d array\r\n    srcx[*,*,z] = slcx\r\n    vdc_bufreadslice, dfdy, slcy\r\n    srcy[*,*,z] = slcy\r\n    vdc_bufreadslice, dfdz, slcz\r\n    srcz[*,*,z] = slcz\r\n    vdc_bufreadslice, dfde, slce\r\n    srce[*,*,z] = slce\r\n\r\n    ;  Report every 100 reads:\r\n    IF ((z MOD 100) EQ 0) THEN print,'reading slice ',z\r\nENDFOR\r\nvdc_closevar, dfdx\r\nvdc_bufreaddestroy, dfdx\r\n\r\nvdc_closevar, dfdy\r\nvdc_bufreaddestroy, dfdy\r\n\r\nvdc_closevar, dfdz\r\nvdc_bufreaddestroy, dfdz\r\n\r\nvdc_closevar, dfde\r\nvdc_bufreaddestroy, dfde\r\n;  Now perform the curl on the data\r\nwrf_curl_findiff,srcx,srcy,srcz,dstx,dsty,dstz,deltax,deltay,srce\r\n\r\n\r\n;  If requested, write out the components of the curl:\r\nIF (~keyword_set(onlymag) ) THEN BEGIN\r\n    dfdcurlx = vdc_bufwritecreate(mfd)\r\n    vdc_openvarwrite, dfdcurlx, timestep, curlx, reflevel\r\n    dfdcurly = vdc_bufwritecreate(mfd)\r\n    vdc_openvarwrite, dfdcurly, timestep, curly, reflevel\r\n    dfdcurlz = vdc_bufwritecreate(mfd)\r\n    vdc_openvarwrite, dfdcurlz, timestep, curlz, reflevel\r\n    ; write the data one slice at a time\r\n    FOR z = 0, dim[2]-1 DO BEGIN\r\n        slcx = dstx[*,*,z]\r\n        vdc_bufwriteslice,dfdcurlx, slcx\r\n        slcy = dsty[*,*,z]\r\n        vdc_bufwriteslice,dfdcurly, slcy\r\n        slcz = dstz[*,*,z]\r\n        vdc_bufwriteslice,dfdcurlz, slcz\r\n        ;  Report every 100 writes:\r\n        IF ((z MOD 100) EQ 0) THEN print,'writing slice ',z\r\n    ENDFOR\r\n    vdc_closevar, dfdcurlx\r\n    vdc_bufwritedestroy, dfdcurlx\r\n    vdc_closevar, dfdcurly\r\n    vdc_bufwritedestroy, dfdcurly\r\n    vdc_closevar, dfdcurlz\r\n    vdc_bufwritedestroy, dfdcurlz\r\n\r\n\r\nENDIF\r\n\r\n;\r\n; If desired, compute and write the magnitude of the curl\r\n;\r\nIF ( keyword_set(mag) ) THEN BEGIN\r\n    dfdmag = vdc_bufwritecreate(mfd)\r\n    allMag = fltarr(dim[0],dim[1],dim[2])\r\n    allMag = sqrt( dstx^2 + dsty^2 + dstz^2 )\r\n    slcmag = fltarr(dim[0],dim[1])\r\n    vdc_openvarwrite, dfdmag, timestep, mag, reflevel\r\n    FOR z = 0, dim[2]-1 DO BEGIN\r\n        slcmag = allMag[*,*,z]\r\n        vdc_bufwriteslice, dfdmag, slcmag\r\n        ;  Report every 100 writes\r\n        IF ( (z MOD 100) EQ 0) THEN print, \"Writing magnitude's z slice \", z\r\n    ENDFOR\r\n    vdc_closevar, dfdmag\r\n    vdc_bufwritedestroy, dfdmag\r\nENDIF\r\n\r\n;\r\n;  Replace the vdf file with the new one, the first time through:\r\n;\r\n \r\nIF (timestep EQ tsstart AND repeatvariables NE newnum) THEN vdf_write,mfd,vdffile\r\n\r\nprint,'Curl completed of timestep ', timestep\r\n\r\ntimestep += tsival\r\n\r\nENDREP UNTIL (timestep GT tsmax)\r\n\r\nvdf_destroy, mfd\r\n\r\nEND\r\n"
  },
  {
    "path": "share/examples/idl/AddWRFDiv.pro",
    "content": "\r\n;   AddWRFDiv.pro\r\n;\r\n;   Utility to read three variables from a WRF VDF, calculate their divergence \r\n;   and put it back into the VDF.\r\n;   All three variables must be present at full resolution.\r\n;\r\n;   The .pro files deriv_findiff.pro and wrf_div_findiff.pro \r\n;   and elev_deriv.pro must be in the\r\n;   directory from which you started idl.\r\n;\r\n;   The vdf file is replaced.  The previous vdf file is saved, with\r\n;   _saved appended to its name, in case of catastrophic failure\r\n;\r\n;   Arguments are:\r\n;   vdffile = file path of the metadata file\r\n;   varx, vary, varz = the 3 variables defining the field \r\n;       whose divergence is being calculated\r\n;   divVar = the name for the divergence variable being calculated \r\n;   tsstart = the time step to start with (or the only time step)\r\n;   tsmax = (keyword parameter) the time step to stop with (don't specify\r\n;           if you only want the one time step, tsstart)\r\n;   tsival = (keyword parameter) the interval between time steps (will compute\r\n;            info for tsstart, tsstart + tsival, etc.) (again, don't specify if\r\n;            you only want the one time step, tsstart)\r\n;\r\n\r\nPRO AddWRFDiv, vdffile,varx,vary,varz,divvar,tsstart, $\r\n                TSMAX=tsmax,TSIVAL=tsival\r\n\r\n\r\n;   \r\n;   Variable timestep now functions as a switch and initializer\r\n;\r\ntimestep = tsstart\r\nIF ( ~keyword_set(tsmax) ) THEN tsmax=tsstart\r\nIF ( ~keyword_set(tsival) ) THEN tsival=1\r\n\r\n;\r\n;   Start with the current metadata:\r\n;\r\n\r\nmfd = vdf_create(vdffile)\r\n\r\n;\r\n;   save the current vdf file (in case we screw up)\r\n;\r\n\r\nsavedvdffile = STRING(vdffile,'_saved')\r\nvdf_write,mfd,savedvdffile\r\n\r\n;\r\n;   Add the new variable name to the current variable names:\r\n;\r\n\r\n;\r\n;   How many variable names?\r\n;\r\n \r\nnvarnames3d = 0\r\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\r\n        varnames = vdf_getvariables3d(mfd)\r\n        nvarnames3d = n_elements(varnames)\r\nendif\r\n\r\nnvarnames2dxy = 0\r\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\r\n        varnames2dxy = vdf_getvariables2dxy(mfd)\r\n        nvarnames2dxy = n_elements(varnames2dxy)\r\nendif\r\n\r\nnumvarsarray = size(varnames)\r\nnumvars = 1 + numvarsarray[1]\r\nnewvarnames = strarr(numvars)\r\n;   Need to make sure the new var name is not in the list!\r\nisinvariables = 0\r\nFOR I = 0, numvars-2 DO BEGIN\r\n        newvarnames[I] = varnames[I]\r\n        if (varnames[I] EQ divvar) THEN isinvariables = 1\r\nENDFOR\r\n\r\nIF (isinvariables EQ 0) THEN newvarnames[numvars-1] = divvar ELSE newvarnames = varnames\r\n\r\nprint,'The 3D variable names in the vdf will be: ',newvarnames\r\n\r\n;\r\n;   reset the varnames in mfd to the new value:\r\n;   provided not all variables are repeated\r\n;   Note that by default all variable names are 3D\r\n;\r\nif (isinvariables EQ 0) THEN BEGIN\r\n\tif (nvarnames2dxy gt 0) THEN BEGIN\r\n\t\tvdf_setvarnames,mfd,[newvarnames,varnames2dxy]\r\n\t\tvdf_setvariables2DXY,mfd,varnames2dxy\r\n\tENDIF ELSE BEGIN\r\n\t\tvdf_setvarnames,mfd,newvarnames\r\n\tENDELSE\r\nENDIF\r\n\r\nreflevel = vdf_getnumtransforms(mfd)\r\n\r\n;\r\n;   Begin loop that iterates over time steps\r\n;\r\nREPEAT BEGIN\r\n\r\nprint, \"Working on time step \", timestep\r\n\r\n;\r\n;   Create \"Buffered Read\" objects for each variable to read the data, passing the\r\n;   metadata object handle created by vdf_create() as an argument\r\n;\r\n\r\ndfdx = vdc_bufreadcreate(mfd)\r\ndfdy = vdc_bufreadcreate(mfd)\r\ndfdz = vdc_bufreadcreate(mfd)\r\ndfde = vdc_bufreadcreate(mfd)\r\ndfddiv = vdc_bufwritecreate(mfd)\r\n\r\n;\r\n;\r\n;   Determine the dimensions of the x-variable at the full transformation\r\n;   level.\r\n;   This is used as the dimension of all the variables\r\n;\r\n\r\ndim = vdc_getdim(dfdx, reflevel)\r\n\r\n;\r\n;   Create appropriately sized arrays to hold the source and result data\r\n;\r\n\r\nsrcx = fltarr(dim[0],dim[1],dim[2])\r\nsrcy = fltarr(dim[0],dim[1],dim[2])\r\nsrcz = fltarr(dim[0],dim[1],dim[2])\r\nsrce = fltarr(dim[0],dim[1],dim[2])\r\n\r\ndivarray = fltarr(dim[0],dim[1],dim[2])\r\n\r\n;\r\n;   Prepare to read the indicated time step and variables\r\n;\r\n\r\nvdc_openvarread, dfdx, timestep, varx, reflevel\r\nvdc_openvarread, dfdy, timestep, vary, reflevel\r\nvdc_openvarread, dfdz, timestep, varz, reflevel\r\nvdc_openvarread, dfde, timestep, 'ELEVATION', reflevel\r\nvdc_openvarwrite, dfddiv, timestep, divvar, reflevel\r\n\r\n;\r\n;   Read the volume one slice at a time\r\n;\r\nslcx = fltarr(dim[0],dim[1])\r\nslcy = fltarr(dim[0],dim[1])\r\nslcz = fltarr(dim[0],dim[1])\r\nslce = fltarr(dim[0],dim[1])\r\n\r\n;   Determine the grid spacing\r\n\r\nextents = VDF_GETEXTENTS(mfd)\r\ndeltax = (extents[3] - extents[0])/FLOAT(dim[0])\r\ndeltay = (extents[4] - extents[1])/FLOAT(dim[1])\r\n\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    vdc_bufreadslice, dfdx, slcx\r\n    ; copy to 3d array\r\n    srcx[*,*,z] = slcx\r\n    vdc_bufreadslice, dfdy, slcy\r\n    ; copy to 3d array\r\n    srcy[*,*,z] = slcy\r\n    vdc_bufreadslice, dfdz, slcz\r\n    ; copy to 3d array\r\n    srcz[*,*,z] = slcz\r\n    vdc_bufreadslice, dfde, slce\r\n    ; copy to 3d array\r\n    srce[*,*,z] = slce\r\n\r\n    ;  Report every 100 reads:\r\n    IF ((z MOD 100) EQ 0) THEN print,'reading slice ',z\r\nENDFOR\r\nvdc_closevar, dfdx\r\nvdc_closevar, dfdy\r\nvdc_closevar, dfdz\r\nvdc_closevar, dfde\r\nvdc_bufreaddestroy, dfdx\r\nvdc_bufreaddestroy, dfdy\r\nvdc_bufreaddestroy, dfdz\r\nvdc_bufreaddestroy, dfde\r\n\r\n;  Now perform the divergence on the data\r\nwrf_div_findiff,srcx,srcy,srcz,divarray,deltax,deltay,srce\r\n\r\nprint,'performed the divergence on ',varx,' ', vary,' ', varz\r\n\r\n; write the data one slice at a time\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    slc = divarray[*,*,z]\r\n    vdc_bufwriteslice,dfddiv, slc\r\n    ;  Report every 100 writes:\r\n    IF ((z MOD 100) EQ 0) THEN print,'writing x slice ',z\r\nENDFOR\r\nvdc_closevar, dfddiv\r\nvdc_bufwritedestroy, dfddiv\r\n\r\n;\r\n;  First time, replace the vdf file with the new one\r\n;\r\n\r\nIF (timestep EQ tsstart AND isinvariables EQ 0) THEN vdf_write,mfd,vdffile\r\n\r\nprint,'Divergence completed'\r\n\r\ntimestep += tsival\r\n\r\nENDREP UNTIL ( timestep GT tsmax )\r\n\r\nvdf_destroy, mfd\r\n\r\nEND\r\n"
  },
  {
    "path": "share/examples/idl/AddWRFETH.pro",
    "content": ";\r\n;   AddWRFETH.pro\r\n;\r\n;   Utility to calculate Equivalent Potential Temperature\r\n;   and put it back into the VDF, as the variable named ETH_.\r\n;   The VDC must have TK_, QVAPOR, P, and PB already\r\n;   with the usual meanings in a WRF dataset\r\n;   Formula was provided by Yongsheng Chen\r\n;\r\n;   The vdf file is replaced.  The previous vdf file is saved, with\r\n;   _saved appended to its name, in case of catastrophic failure\r\n;\r\n;   Arguments are:\r\n;   vdffile = file path of the metadata file\r\n;   tsstart = the first (smallest) time step this is applied to\r\n;     keyword args:\r\n;   tsmax = the largest time step this is applied to\r\n;   tsival = the increment between successive time steps  \r\n;\r\n\r\nPRO AddWRFETH, vdffile,tsstart, $\r\n\t\tTSMAX=tsmax,TSIVAL=tsival\r\n\r\n\r\n;\r\n;   Set up timesteps\r\n;\r\ntimestep = tsstart\r\nIF (~keyword_set(tsmax)) THEN tsmax = tsstart\r\nIF (~keyword_set(tsival)) THEN tsival = 1\r\n\r\n\r\n;\r\n;   Start with the current metadata:\r\n;\r\n\r\nmfd = vdf_create(vdffile)\r\n\r\n;\r\n;   save the current vdf file (in case we screw up)\r\n;\r\n\r\nsavedvdffile = STRING(vdffile,'_saved')\r\nvdf_write,mfd,savedvdffile\r\n\r\n;\r\n;   Add the new variable name to the current variable names:\r\n;   But need to know if it's already there\r\n;   How many variable names?\r\n;\r\n\r\nnvarnames3d = 0\r\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\r\n        varnames = vdf_getvariables3d(mfd)\r\n        nvarnames3d = n_elements(varnames)\r\nendif\r\n\r\nnvarnames2dxy = 0\r\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\r\n        varnames2dxy = vdf_getvariables2dxy(mfd)\r\n        nvarnames2dxy = n_elements(varnames2dxy)\r\nendif\r\n\r\nnumvarsarray = size(varnames)\r\nnumvars = 1 + numvarsarray[1]\r\nnewvarnames = strarr(numvars)\r\n;   Need to make sure these are not in the list!\r\nrepeatvariables = 0\r\n\r\nFOR I = 0, numvars-2 DO BEGIN\r\n    newvarnames[I] = varnames[I]\r\n    IF (varnames[I] EQ 'ETH_') THEN repeatvariables = 1+repeatvariables\r\nENDFOR\r\n\r\nIF (repeatvariables EQ 0) THEN newvarnames[numvars-1] = 'ETH_' \r\n\r\n;\r\n;   reset the varnames in mfd to the new value:\r\n;   unless it's already in the vdf\r\n;\r\nif (repeatvariables EQ 0) THEN BEGIN\r\n\tif(nvarnames2dxy gt 0) THEN BEGIN \r\n\t\tvdf_setvarnames,mfd,[newvarnames,varnames2dxy]\r\n\t\tvdf_setvariables2dXY,mfd,varnames2dxy\r\n\tENDIF ELSE BEGIN\r\n\t\tvdf_setvarnames,mfd,newvarnames\r\n\tENDELSE\r\nENDIF\r\n\r\nreflevel = vdf_getnumtransforms(mfd)\r\n\r\nREPEAT BEGIN\r\n\r\nprint, \"Working on time step \", timestep\r\n\r\n;\r\n;   Create \"Buffered Read\" objects for each variable to read the data, passing the\r\n;   metadata object handle created by vdf_create() as an argument\r\n;\r\n\r\ndfdP = vdc_bufreadcreate(mfd)\r\ndfdPB = vdc_bufreadcreate(mfd)\r\ndfdQV = vdc_bufreadcreate(mfd)\r\ndfdTK = vdc_bufreadcreate(mfd)\r\ndfdETH = vdc_bufwritecreate(mfd)\r\n\r\n;\r\n;\r\n;   Determine the dimensions of the P-variable at the full transformation\r\n;   level.\r\n;   This is used as the dimension of all the variables\r\n;\r\n\r\ndim = vdc_getdim(dfdP, reflevel)\r\n\r\n;\r\n;   Prepare to read the indicated time step and variables\r\n;\r\n\r\nvdc_openvarread, dfdP, timestep, 'P', reflevel\r\nvdc_openvarread, dfdPB, timestep, 'PB', reflevel\r\nvdc_openvarread, dfdQV, timestep, 'QVAPOR', reflevel\r\nvdc_openvarread, dfdTK, timestep, 'TK_', reflevel\r\nvdc_openvarwrite, dfdETH, timestep, 'ETH_', reflevel\r\n\r\n\r\n;\r\n;   Read the volume one slice at a time\r\n;\r\n\r\nslcP = fltarr(dim[0],dim[1])\r\nslcPB = fltarr(dim[0],dim[1])\r\nslcQV = fltarr(dim[0],dim[1])\r\nslcTK = fltarr(dim[0],dim[1])\r\n\r\n;   Determine the grid spacing\r\n\r\nextents = VDF_GETEXTENTS(mfd)\r\n\r\n; establish some constants:\r\neps = 0.622\r\ngamm = 287.04/1004.\r\nrgasmd=0.608\r\ncpmd=0.887\r\ngammamd=rgasmd-cpmd\r\ntlclc1=2840.\r\ntlclc2=3.5\r\ntlclc3=4.805\r\ntlclc4=55.\r\nthtecon1=3376. \r\nthtecon2=2.54\r\nthtecon3=.81\r\n\r\n; process the data one slice at a time:\r\n\r\nmaxslcETH = 0.0\r\nminslcETH = 10000000.\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    vdc_bufreadslice, dfdP, slcP\r\n    vdc_bufreadslice, dfdPB, slcPB\r\n    vdc_bufreadslice, dfdQV, slcQV\r\n    vdc_bufreadslice, dfdTK, slcTK\r\n    PR = (slcP + slcPB)*0.01\r\n    \r\n    Q = slcQV > 1.e-15\r\n    E = Q*PR/(eps+Q)\r\n     \r\n    tlcl = tlclc1/(alog(slcTK^tlclc2/E)-tlclc3)+tlclc4\r\n    slcETH = slcTK*(1000./PR)^(gamm*(1.+gammamd*Q))*EXP((thtecon1/tlcl-thtecon2)*Q*(1.+thtecon3*Q))\r\n    ;  Report every 20 slices\r\n    IF ((z MOD 20) EQ 0) THEN print,'reading slice ',z\r\n    vdc_bufwriteslice, dfdETH, slcETH\r\nENDFOR\r\nvdc_closevar, dfdP\r\nvdc_bufreaddestroy, dfdP\r\nvdc_closevar, dfdPB\r\nvdc_bufreaddestroy, dfdPB\r\nvdc_closevar, dfdQV\r\nvdc_bufreaddestroy, dfdQV\r\nvdc_closevar, dfdTK\r\nvdc_bufreaddestroy, dfdTK\r\nvdc_closevar, dfdETH\r\nvdc_bufwritedestroy, dfdETH\r\n\r\n;\r\n;  Replace the vdf file with the new one, the first time through:\r\n;\r\n \r\nIF (timestep EQ tsstart AND repeatvariables EQ 0) THEN vdf_write,mfd,vdffile\r\n\r\nprint,'ETH_ completed of timestep ', timestep\r\n\r\ntimestep += tsival\r\n\r\nENDREP UNTIL (timestep GT tsmax)\r\n\r\nvdf_destroy, mfd\r\n\r\nEND\r\n"
  },
  {
    "path": "share/examples/idl/MakeCmbo.pro",
    "content": ";\r\n;   MakeCombo.pro\r\n;\r\n;   Utility to calculate a combination of 3D variables in a vdf,\r\n;   and put it back into the VDF.\r\n;   i.e. calculate A*U/W+B*V/T+C/S, where U, V, W, T, and S are 3D variables and\r\n;   A, B, and C are constants.  \r\n;   All variables involved must be present at full resolution,\r\n;\r\n;   The vdf file is replaced.  The previous vdf file is saved, with\r\n;   _saved appended to its name, in case of catastrophic failure\r\n;\r\n;   Arguments are:\r\n;   vdffile = file path of the metadata file\r\n;   uVar, vVar, wVar, tVar, sVar = (keyword parameters) the 5 3D variable names.\r\n;       To add a constant, omit S and set C to your constant\r\n;   resVar = name for the combination\r\n;   A,B,C = coefficients\r\n;   tsstart = first time step for which to calculate the combination.  If tsmax\r\n;       and tsival are not specified, then only tsstart is computed\r\n;   tsmax = (keyword parameter) last time step for which to compute combination\r\n;   tsival = (keyword parameter) interval between desired time steps\r\n;\r\n\r\nPRO MakeCmbo, vdffile,U=uVar,V=vVar,W=wVar,T=tVar,S=sVar,A,B,C, $\r\n              resVar,tsstart,TSMAX=tsmax,TSIVAL=tsival\r\n\r\n;\r\n;   Define some logical variables for conciseness\r\n;\r\ngotU = keyword_set(uVar)\r\ngotW = keyword_set(wVar)\r\ngotV = keyword_set(vVar)\r\ngotT = keyword_set(tVar)\r\ngotS = keyword_set(sVar)\r\n\r\n;\r\n;   Make sure we're using at least one variable\r\n;\r\nIF ( ~( gotU || gotW || gotV || gotT || gotS ) ) THEN BEGIN\r\n    print, \"No variables added and no files modified\"\r\n    return\r\nENDIF\r\n\r\n;\r\n;   What to do if timestep keywords aren't defined\r\n;\r\nIF ( ~keyword_set(tsmax) ) THEN tsmax = tsstart\r\nIF ( ~keyword_set(tsival) ) THEN tsival = 1\r\n\r\n;\r\n;   Initialize timestep\r\n;\r\ntimestep = tsstart\r\n\r\n;\r\n;   Start with the current metadata:\r\n;\r\n\r\nmfd = vdf_create(vdffile)\r\n\r\n;\r\n;   save the current vdf file (in case we screw up)\r\n;\r\n\r\nsavedvdffile = STRING(vdffile,'_saved')\r\nvdf_write,mfd,savedvdffile\r\n\r\n;\r\n;   Add the new variable name to the current variable names, if it's\r\n;   not already there\r\n;\r\n\r\nnvarnames3d = 0\r\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\r\n        varnames = vdf_getvariables3d(mfd)\r\n        nvarnames3d = n_elements(varnames)\r\nendif\r\n\r\nnvarnames2dxy = 0\r\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\r\n        varnames2dxy = vdf_getvariables2dxy(mfd)\r\n        nvarnames2dxy = n_elements(varnames2dxy)\r\nendif\r\n\r\nnumvarsarray = size(varnames)\r\nnumvars = 1 + numvarsarray[1]\r\nnewvarnames = strarr(numvars)\r\n;   Need to make sure this is not in the list!\r\nisinvariables = 0\r\nFOR I = 0, numvars-2 DO BEGIN\r\n    newvarnames[I] = varnames[I]\r\n    if (varnames[I] EQ resVar) THEN isinvariables = 1\r\nENDFOR\r\n\r\nIF (isinvariables EQ 0) THEN newvarnames[numvars-1] = resVar ELSE newvarnames = varnames\r\n\r\nprint,'The 3D variable names in the vdf will be: ',newvarnames\r\n\r\n;\r\n;   reset the varnames in mfd to the new value:\r\n;\r\nif (isinvariables EQ 0) THEN BEGIN\r\n\tif(nvarnames2dxy gt 0) THEN BEGIN\r\n\t\tvdf_setvarnames,mfd,[newvarnames,varnames2dxy]\r\n\t\tvdf_setvariables2dxy,mfd,varnames2dxy\r\n\tENDIF ELSE BEGIN\r\n\t\tvdf_setvarnames,mfd,newvarnames\r\n\tENDELSE\r\nENDIF\r\n\r\nreflevel = vdf_getnumtransforms(mfd)\r\nnumtimesteps = vdf_getnumtimesteps(mfd)\r\n\r\n;\r\n;   Begin loop that iterates over time steps\r\n;\r\nREPEAT BEGIN\r\n\r\nprint, \"Working on time step \", timestep\r\n\r\n;\r\n;   Create \"Buffered Read\" objects for each variable to read the data, passing the\r\n;   metadata object handle created by vdf_create() as an argument\r\n;\r\n\r\nIF ( gotU ) then dfdu = vdc_bufreadcreate(mfd)\r\nIF ( gotW ) then dfdw = vdc_bufreadcreate(mfd)\r\nIF ( gotV ) then dfdv = vdc_bufreadcreate(mfd)\r\nIF ( gotT ) then dfdt = vdc_bufreadcreate(mfd)\r\nIF ( gotS ) then dfds = vdc_bufreadcreate(mfd)\r\n\r\ndfdres = vdc_bufwritecreate(mfd)\r\n\r\n\r\n;\r\n;\r\n;   Determine the dimensions of one of the variables at the full transformation\r\n;   level.\r\n;   This is used as the dimension of all the variables\r\n;   Note. vdc_getdim() correctly handles dimension calucation for\r\n;   volumes with non-power-of-two dimensions.\r\n;\r\nIF ( gotU ) THEN $\r\n    dim = vdc_getdim(dfdu, reflevel) ELSE $\r\nIF ( gotW ) THEN $\r\n    dim = vdc_getdim(dfdw, reflevel) ELSE $\r\nIF ( gotV ) THEN $\r\n    dim = vdc_getdim(dfdv, reflevel) ELSE $\r\nIF ( gotT ) THEN $\r\n    dim = vdc_getdim(dfdt, reflevel) ELSE $\r\nIF ( gotS ) THEN $\r\n    dim = vdc_getdim(dfds, reflevel) ELSE $\r\n    BEGIN\r\n    print, \"No variables present, early error detection failed\"\r\n    return\r\n    ENDELSE\r\n\r\n;\r\n;   Create appropriately sized arrays to hold the volume slices:\r\n;\r\nIF ( gotU ) THEN sliceu = fltarr(dim[0], dim[1])\r\nIF ( gotW ) THEN slicew = fltarr(dim[0], dim[1])\r\nIF ( gotV ) THEN slicev = fltarr(dim[0], dim[1])\r\nIF ( gotT ) THEN slicet = fltarr(dim[0], dim[1])\r\nIF ( gotS ) THEN slices = fltarr(dim[0], dim[1])\r\n\r\nsliceres = fltarr(dim[0], dim[1])\r\n\r\n\r\n\r\n;\r\n;   Prepare to read and write the indicated time step and variables\r\n;\r\nIF ( gotU ) THEN vdc_openvarread, dfdu, timestep, uVar, reflevel\r\nIF ( gotW ) THEN vdc_openvarread, dfdw, timestep, wVar, reflevel\r\nIF ( gotV ) THEN vdc_openvarread, dfdv, timestep, vVar, reflevel\r\nIF ( gotT ) THEN vdc_openvarread, dfdt, timestep, tVar, reflevel\r\nIF ( gotS ) THEN vdc_openvarread, dfds, timestep, sVar, reflevel\r\nvdc_openvarwrite,dfdres, timestep, resVar, reflevel\r\n\r\n;\r\n;   Read the volume one slice at a time\r\n;\r\n\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    IF ( gotU ) THEN BEGIN\r\n        vdc_bufreadslice, dfdu, sliceu\r\n        sliceres = A*sliceu\r\n        IF ( gotW ) THEN BEGIN\r\n            vdc_bufreadslice, dfdw, slicew\r\n            sliceres /= slicew\r\n        ENDIF\r\n    ENDIF ELSE BEGIN\r\n        IF ( gotW ) THEN BEGIN\r\n            vdc_bufreadslice, dfdw, slicew\r\n            sliceres = A/slicew\r\n        ENDIF\r\n    ENDELSE\r\n\r\n    IF ( gotV ) THEN BEGIN\r\n        vdc_bufreadslice, dfdv, slicev\r\n        IF ( gotT ) THEN BEGIN\r\n            vdc_bufreadslice, dfdt, slicet\r\n            sliceres += B*slicev/slicet\r\n        ENDIF ELSE sliceres += B*slicev\r\n    ENDIF ELSE BEGIN\r\n        IF ( gotT ) THEN BEGIN\r\n            vdc_bufreadslice, dfdt, slicet\r\n            sliceres += B/slicet\r\n        ENDIF\r\n    ENDELSE\r\n\r\n    IF ( gotS ) THEN BEGIN\r\n        vdc_bufreadslice, dfds, slices\r\n        sliceres += C/slices\r\n    ENDIF ELSE sliceres += C\r\n\r\n    vdc_bufwriteslice, dfdres, sliceres\r\n\r\n    ;  Report every 100 writes:\r\n\r\n    IF ((Z MOD 100) EQ 0) THEN print,'wrote slice ',z\r\n\r\nENDFOR\r\n\r\nvdc_closevar, dfdres\r\nIF ( gotU ) THEN BEGIN\r\n    vdc_closevar, dfdu\r\n    vdc_bufreaddestroy, dfdu\r\nENDIF\r\nIF ( gotW ) THEN BEGIN\r\n    vdc_closevar, dfdw\r\n    vdc_bufreaddestroy, dfdw\r\nENDIF\r\nIF ( gotV ) THEN BEGIN\r\n    vdc_closevar, dfdv\r\n    vdc_bufreaddestroy, dfdv\r\nENDIF\r\nIF ( gotT ) THEN BEGIN\r\n    vdc_closevar, dfdt\r\n    vdc_bufreaddestroy, dfdt\r\nENDIF\r\nIF ( gotS ) THEN BEGIN\r\n    vdc_closevar, dfds\r\n    vdc_bufreaddestroy, dfds\r\nENDIF\r\n\r\nvdc_bufwritedestroy, dfdres\r\n\r\n\r\n;\r\n;  Replace the vdf file with the new one\r\n;\r\n\r\nvdf_write,mfd,vdffile\r\n;vdf_destroy, mfd\r\nprint,dim[2],' slices written to output file'\r\n\r\ntimestep += tsival\r\n\r\nENDREP UNTIL ( timestep GT tsmax )\r\n\r\nvdf_destroy, mfd\r\n\r\nEND\r\n\r\n"
  },
  {
    "path": "share/examples/idl/MakeLinCmb.pro",
    "content": ";\r\n;   MakeLinCmb.pro\r\n;\r\n;   Utility to calculate a linear combination of 3D variables in a vdf,\r\n;   and put it back into the VDF.\r\n;   i.e. calculate A*U+B*V+C, where U and V are 3D variables and\r\n;   A, B, and C are constants.  If B is 0, V is ignored.\r\n;   U must be present at full resolution,\r\n;   If B != 0, then V must be present at full resolution\r\n;\r\n;   This is performed one time-step at a time.\r\n;   The vdf file is replaced.  The previous vdf file is saved, with\r\n;   _saved appended to its name, in case of catastrophic failure\r\n;\r\n;   Arguments are:\r\n;   vdffile = file path of the metadata file\r\n;   uVar, vVar  the 2 variable names (of U and V)\r\n;   resVar is the name for the linear combination\r\n;   A,B,C are the coefficients\r\n;   timestep specifies the (only) timestep for which the lin comb\r\n;     is calculated.  If multiple timesteps are needed,\r\n;     the calculation must be repeated for each of them.\r\n;\r\n\r\nPRO MakeLinCmb,vdffile,uVar,vVar,A,B,C,resVar,timestep\r\n\r\n;\r\n;   Start with the current metadata:\r\n;\r\n\r\nmfd = vdf_create(vdffile)\r\n\r\n;\r\n;   save the current vdf file (in case we screw up)\r\n;\r\n\r\nsavedvdffile = STRING(vdffile,'_saved')\r\nvdf_write,mfd,savedvdffile\r\n\r\n;\r\n;   Add the new variable name to the current variable names, if it's\r\n;   not already there\r\n;\r\n\r\nnvarnames3d = 0\r\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\r\n        varnames = vdf_getvariables3d(mfd)\r\n        nvarnames3d = n_elements(varnames)\r\nendif\r\n\r\nnvarnames2dxy = 0\r\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\r\n        varnames2dxy = vdf_getvariables2dxy(mfd)\r\n        nvarnames2dxy = n_elements(varnames2dxy)\r\nendif\r\n\r\nnumvarsarray = size(varnames)\r\nnumvars = 1 + numvarsarray[1]\r\nnewvarnames = strarr(numvars)\r\n;   Need to make sure this is not in the list!\r\nisinvariables = 0\r\nFOR I = 0, numvars-2 DO BEGIN\r\n    newvarnames[I] = varnames[I]\r\n    if (varnames[I] EQ resVar) THEN isinvariables = 1\r\nENDFOR\r\n\r\nIF (isinvariables EQ 0) THEN newvarnames[numvars-1] = resVar ELSE newvarnames = varnames\r\n\r\nprint,'The 3D variable names in the vdf will be: ',newvarnames\r\n\r\n;\r\n;   reset the varnames in mfd to the new value:\r\n;\r\nif (isinvariables EQ 0) THEN BEGIN\r\n\tif(nvarnames2dxy gt 0) THEN BEGIN\r\n\t\tvdf_setvarnames,mfd,[newvarnames,varnames2dxy]\r\n\t\tvdf_setvariables2dxy,mfd,varnames2dxy\r\n\tENDIF ELSE BEGIN\r\n\t\tvdf_setvarnames,mfd,newvarnames\r\n\tENDELSE\r\nENDIF\r\n\r\nreflevel = vdf_getnumtransforms(mfd)\r\nnumtimesteps = vdf_getnumtimesteps(mfd)\r\n\r\n;\r\n;   Create \"Buffered Read\" objects for each variable to read the data, passing the\r\n;   metadata object handle created by vdf_create() as an argument\r\n;\r\n\r\ndfdu = vdc_bufreadcreate(mfd)\r\nif ( B NE 0) then dfdv = vdc_bufreadcreate(mfd)\r\ndfdres = vdc_bufwritecreate(mfd)\r\n\r\n;\r\n;\r\n;   Determine the dimensions of the u-variable at the full transformation\r\n;   level.\r\n;   This is used as the dimension of all the variables\r\n;   Note. vdc_getdim() correctly handles dimension calucation for\r\n;   volumes with non-power-of-two dimensions.\r\n;\r\n\r\ndim = vdc_getdim(dfdu, reflevel)\r\n\r\n;\r\n;   Create appropriately sized arrays to hold the volume slices:\r\n;\r\n\r\nsliceu = fltarr(dim[0], dim[1])\r\nIF ( B NE 0) then slicev = fltarr(dim[0], dim[1])\r\nsliceres = fltarr(dim[0], dim[1])\r\n\r\n\r\n\r\n;\r\n;   Prepare to read and write the indicated time step and variables\r\n;\r\n\r\nvdc_openvarread, dfdu, timestep, uVar, reflevel\r\nIF ( B NE 0) then vdc_openvarread, dfdv, timestep, vVar, reflevel\r\nvdc_openvarwrite,dfdres, timestep, resVar, reflevel\r\n\r\n;\r\n;   Read the volume one slice at a time\r\n;\r\n\r\nFOR z = 0, dim[2]-1 DO BEGIN\r\n    vdc_bufreadslice, dfdu, sliceu\r\n    IF ( B NE 0) then vdc_bufreadslice, dfdv, slicev\r\n\r\n    sliceres = sliceu*A + C\r\n    IF ( B NE 0) then sliceres = sliceres + slicev*B\r\n\r\n    vdc_bufwriteslice, dfdres, sliceres\r\n\r\n    ;  Report every 100 writes:\r\n\r\n    IF ((Z MOD 100) EQ 0) THEN print,'wrote slice ',z\r\n\r\nENDFOR\r\n\r\nvdc_closevar, dfdres\r\nvdc_closevar, dfdu\r\nIF ( B NE 0) then vdc_closevar, dfdv\r\n\r\n\r\nvdc_bufwritedestroy, dfdres\r\nvdc_bufreaddestroy, dfdu\r\nIF ( B NE 0) then vdc_bufreaddestroy, dfdv\r\n\r\n;\r\n;  Replace the vdf file with the new one\r\n;\r\n\r\nvdf_write,mfd,vdffile\r\nvdf_destroy, mfd\r\nprint,dim[2],' slices written to output file'\r\nend\r\n"
  },
  {
    "path": "share/examples/idl/PrintMetaVDF.pro",
    "content": ";\t$Id$\n;\n;\tThis example shows how to extact various bits of metadata information\n;\tfrom a from a VDF data collection.\n;\n;\tNote: in order to run this example you must have first created\n;\ta VDF data collection by running either the WriteVDF.pro\n;\tor WriteTimeVaryVDF.pro example programs\n\n\n;\n;\tCreate a VDF metadata object from an existing metadata file. The\n;\tmetadata file must already exist on disk, having been created from\n;\tone of the example programs that generates a .vdf file.\n;\nvdffile = 'test.vdf'\nmfd = vdf_create(vdffile)\n\n\nprint, 'Block size = ', vdf_getblocksize(mfd)\nbs = vdf_getblocksize(mfd)\n\nprint, 'Dimension = ', vdf_getdimension(mfd)\n\nprint, 'Num Filter Coefficients = ', vdf_getfiltercoef(mfd)\n\nprint, 'Num Lifting Coefficients = ', vdf_getliftingcoef(mfd)\n\nprint, 'Num Wavelet Transforms = ', vdf_getnumtransforms(mfd)\n\nprint, 'Grid Type = ', vdf_getgridtype(mfd)\n\nprint, 'Coordinate Type = ', vdf_getcoordtype(mfd)\n\nprint, 'Volume extents = ', vdf_getextents(mfd)\n\nprint, 'Num Time Steps = ', vdf_getnumtimesteps(mfd)\n\nprint, 'Variable Names = ', vdf_getvarnames(mfd)\n\nnvarnames3d = 0\nif (n_elements(vdf_getvariables3d(mfd)) ne 0) then begin\n\tvarnames3d = vdf_getvariables3d(mfd)\n\tnvarnames3d = n_elements(varnames3d)\n\tprint, '3D Variable Names = ', varnames3d\nendif\n\nnvarnames2dxy = 0\nif (n_elements(vdf_getvariables2dxy(mfd)) ne 0) then begin\n\tvarnames2dxy = vdf_getvariables2dxy(mfd)\n\tnvarnames2dxy = n_elements(varnames2dxy)\n\tprint, '2DXY Variable Names = ', varnames2dxy\nendif\n\nprint, 'Global comment = ', vdf_getcomment(mfd)\n\n\ntimesteps = vdf_getnumtimesteps(mfd)\n\nfor ts = 0, timesteps[0]-1 do begin\n\tprint, 'Time step ', ts, ' metadata'\n\tprint, '\tUser Time = ', vdf_gettusertime(mfd, ts)\n\tif (n_elements(vdf_gettxcoords(mfd, ts)) ne 0) then print, '\tXCoords = ', vdf_gettxcoords(mfd, ts)\n\tif (n_elements(vdf_gettycoords(mfd, ts)) ne 0) then print, '\tYCoords = ', vdf_gettycoords(mfd, ts)\n\tif (n_elements(vdf_gettzcoords(mfd, ts)) ne 0) then print, '\tZCoords = ', vdf_gettzcoords(mfd, ts)\n\tif (n_elements(vdf_gettcomment(mfd, ts)) ne 0) then print, '\tComment = ', vdf_gettcomment(mfd, ts)\n\n\tfor v = 0, nvarnames3d-1 do begin\n\t\tprint, '\t3D Variable ', varnames3d[v], ':'\n\t\tif (n_elements(vdf_getvcomment(mfd, ts, varnames3d[v])) ne 0) then print, '\tComment = ', vdf_getvcomment(mfd, ts, varnames3d[v])\n\n\tendfor\n\n\tfor v = 0, nvarnames2dxy-1 do begin\n\t\tprint, '\t2D Variable ', varnames2dxy[v], ':'\n\t\tif (n_elements(vdf_getvcomment(mfd, ts, varnames2dxy[v])) ne 0) then print, '\tComment = ', vdf_getvcomment(mfd, ts, varnames2dxy[v])\n\n\tendfor\nendfor\n\n\nvdf_destroy, mfd\n\nend\n"
  },
  {
    "path": "share/examples/idl/QuickStartEx1.pro",
    "content": "; $Id$\r\n;\r\n;\r\n\r\n;\r\n;   This example is referenced by the VAPOR Quick Start guide. It\r\n;   demonstrates VAPOR's interaction with IDL by importing a data\r\n;   subregion from VAPOR, calculating the Z component of vorticity,\r\n;   and exporting the new quantity back to VAPOR.\r\n;\r\n\r\n;\r\n; Import a region of data previously exported by vaporgui.\r\n; In this case, the components of the velocity field, scaled by ro\r\n;\r\nru = impregion(STATEINFO=stateinfo, VARNAME='ru')\r\nrv = impregion(STATEINFO=stateinfo, VARNAME='rv')\r\nrw = impregion(STATEINFO=stateinfo, VARNAME='rw')\r\nro = impregion(STATEINFO=stateinfo, VARNAME='ro')\r\n\r\nru = ru/ro\r\nrv = rv/ro\r\nrw = rw/ro\r\n\r\ndim = size(ru, /DIMENSIONS)\r\n\r\n;\r\n; Compute vorticity\r\n;\r\nx=findgen(dim[0])\r\ny=findgen(dim[1])\r\ndvu=fltarr(dim[0], dim[1], dim[2])\r\nomz=fltarr(dim[0], dim[1], dim[2])\r\nfor k=0,dim[2]-1 do begin\r\n    tmp=reform(ru(*,*,k))\r\n;    dvu(*,*,k)=myderiv(x,tmp,1,1)\r\n    omz(*,*,k)=myderiv(y,tmp,2,1)\r\n    tmp=reform(rv(*,*,k))\r\n;    dvu(*,*,k)=dvu(*,*,k)+myderiv(y,tmp,2,1)\r\n    omz(*,*,k)=myderiv(x,tmp,1,1)-omz(*,*,k)\r\nendfor\r\n\r\n;\r\n; Finally, export the region to a new VDC, named 'QuickStartEx1.vdf'.\r\n; The new variable we have created will be named 'omz'. The new VDC maybe\r\n; either merged into a running vaporgui session from whence the original\r\n; data came, or may simply be loaded as a new data set\r\n;\r\n;  Note there's an arithmetic error we can ignore...\r\n\r\ntmpvdf = 'QuickStartEx1.vdf'\r\nvarname = 'omz'\r\nexpregion, tmpvdf, stateinfo, varname, omz\r\n\r\nend\r\n"
  },
  {
    "path": "share/examples/idl/README.txt",
    "content": "This directory contains a number of examples demonstrating how to read and \nwrite VDF files from IDL\n"
  },
  {
    "path": "share/examples/idl/ReadRegionVDF.pro",
    "content": ";\t$Id$\n;\n;\tThis example shows how to read a single data volume\n;\tfrom a VDF data collection using a \"Region Read\" object. The data \n;\tvolume\tis not read in its entirety -- a spatial subregion (the first\n;\toctant) is extracted from the full spatial domain.  The volume\n;\tresolution, however, is the native data resolution.\n;\n;\tNote: in order to run this example you must have first created\n;\ta VDF data collection by running either the WriteVDF.pro\n;\tor WriteTimeVaryVDF.pro example programs\n\n\n\n;\n;\tThe refinement level of the multiresolution data\n;\tA value of 0 indicates that the data should be read at the\n;\tcoarsest resolution, a value of 1 indicates the next refinement\n;\tlevel, and so on\n;\tA value of -1 implies a the finest (native) resolution\n;\nreflevel = -1\n\n;\n;\tCreate a VDF metadata object from an existing metadata file. The\n;\tmetadata file must already exist on disk, having been created from\n;\tone of the example programs that generates a .vdf file.\n;\nvdffile = 'test.vdf'\nmfd = vdf_create(vdffile)\n\n\n;\n;\tCreate a \"Buffered Read\" object to read the data, passing the \n;\tmetadata object handle created by vdf_create() as an argument\n;\ndfd = vdc_regreadcreate(mfd)\n\n;\n;\tDetermine the dimensions of the volume at the given transformation\n;\tlevel. \n;\n;\tNote. vdc_getdim() correctly handles dimension calucation for \n;\tvolumes with non-power-of-two dimensions. \n;\ndim = vdc_getdim(dfd, reflevel)\n\n;\n;\tCompute the coordinates for the desired subregion. In this case, the \n;\tfirst octant will be read\nmin = [0,0,0]\nmax = (dim / 2) - 1\n\n;\n;\tCreate an appropriately sized array to hold the volume\n;\nf = fltarr(dim/2)\n\n\n;\n;\tPrepare to read the indicated time step and variable\n;\nvarnames = ['ml']\nvdc_openvarread, dfd, 0, varnames[0], reflevel\n\n;\n;\tRead the volume subregion. Note, unlike the buffered read/write\n;\tobjects, the \"Region Reader\" object does not read a single slice\n;\tat a time -- it slurps in the entire in single call.\n;\nvdc_regread, dfd, min, max, f\n\n;\n; Close the currently opened variable/time-step. \n;\nvdc_closevar, dfd\n\n\n;\n;\tDestroy the \"buffered read\" data transformation object. \n;\tWe're done with it.\n;\nvdc_regreaddestroy, dfd\n\nvdf_destroy, mfd\n\nend\n"
  },
  {
    "path": "share/examples/idl/ReadVDF.pro",
    "content": ";\t$Id$\n;\n;\tThis example shows how to read a single data volume\n;\tfrom a VDF data collection using a \"Buffered Read\" object. The entire\n;\tspatial domain of the volume is retrieved (as opposed to fetching \n;\ta spatial subregion). However, the volume is extracted at 1/8th \n;\tits native spatial resolution (1/2 resolution along each dimension).\n;\n;\tNote: in order to run this example you must have first created\n;\ta VDF data collection by running either the WriteVDF.pro\n;\tor WriteTimeVaryVDF.pro example programs\n\n\n\n;   A value of 0 indicates that the data should be read at the\n;   coarsest resolution, a value of 1 indicates the next refinement\n;   level, and so on\n;   A value of -1 implies a the finest (native) resolution\n;\nreflevel = 1\n\n;\n;\tCreate a VDF metadata object from an existing metadata file. The\n;\tmetadata file must already exist on disk, having been created from\n;\tone of the example programs that generates a .vdf file.\n;\nvdffile = 'test.vdf'\nmfd = vdf_create(vdffile)\n\n\n;\n;\tCreate a \"Buffered Read\" object to read the data, passing the \n;\tmetadata object handle created by vdf_create() as an argument\n;\ndfd = vdc_bufreadcreate(mfd)\n\n;\n;\tDetermine the dimensions of the volume at the given transformation\n;\tlevel. \n;\n;\tNote. vdc_getdim() correctly handles dimension calucation for \n;\tvolumes with non-power-of-two dimensions. \n;\ndim = vdc_getdim(dfd, reflevel)\n\n;\n;\tCreate an appropriately sized array to hold the volume\n;\nf = fltarr(dim)\nslice = fltarr(dim[0], dim[1])\n\n\n;\n;\tPrepare to read the indicated time step and variable\n;\nvarnames = ['ml']\nvdc_openvarread, dfd, 0, varnames[0], reflevel\n\n;\n;\tRead the volume one slice at a time\n;\nfor z = 0, dim[2]-1 do begin\n\tvdc_bufreadslice, dfd, slice\n\t\n\t; IDL won't let us read directly into a subscripted array - need \n\t; to read into a 2D array and then copy to 3D :-(\n\t;\n\tf[*,*,z] = slice\nendfor\n\n;\n; Close the currently opened variable/time-step. \n;\nvdc_closevar, dfd\n\n\n;\n;\tDestroy the \"buffered read\" data transformation object. \n;\tWe're done with it.\n;\nvdc_bufreaddestroy, dfd\n\n\nvdf_destroy, mfd\nend\n"
  },
  {
    "path": "share/examples/idl/WRFVortMagEx.pro",
    "content": ";\r\n\r\n;\r\n;   This example demonstrates the use of VAPOR with IDL\r\n;   on a WRF dataset, by importing a data\r\n;   subregion from VAPOR, calculating the magnitude of vorticity,\r\n;   and exporting the new variable (VMag) back to VAPOR.\r\n;\r\n; Import a region of data previously exported by vaporgui.\r\n; In this case, the components of the velocity field\r\n; and the ELEVATION variable\r\n;\r\nU = impregion(STATEINFO=stateinfo, VARNAME='U')\r\nV = impregion(STATEINFO=stateinfo, VARNAME='V')\r\nW = impregion(STATEINFO=stateinfo, VARNAME='W')\r\nELEV = impregion(STATEINFO=stateinfo, VARNAME='ELEVATION')\r\n\r\n\r\nmfd = vdf_create(stateinfo.VDFPATH)\r\nextents = VDF_GETEXTENTS(mfd)\r\ndfd = vdc_bufreadcreate(mfd)\r\ndims = vdc_getdim(dfd, -1)\r\n\r\n; Calculate deltax, deltay based on horizontal size of full data\r\ndeltax =  (extents[3] - extents[0])/float(dims[0])\r\ndeltay =  (extents[4] - extents[1])/float(dims[1])\r\n\r\n\r\n;\r\n; Compute vorticity magnitude, results go in resx,resy,resz\r\n;\r\n;print, 'deltas: ', deltax, deltay\r\n\r\nprint, 'input minmax ', min(U),max(U),min(V),max(V),min(W),max(W)\r\n\r\nwrf_curl_findiff,U,V,W,resx,resy,resz,deltax,deltay,ELEV\r\n\r\n; \r\n; Now, calculate and export vorticity magnitude \r\n;\r\nvMag = sqrt( resx^2 + resy^2 + resz^2 )\r\n\r\nminval = Min(vmag)\r\nmaxval = Max(vmag)\r\n\r\n;print,'min,max: ',minval, maxval\r\n\r\ntmpvdf = 'VMag.vdf'\r\nexpregion, tmpvdf, stateinfo, 'VMag', vMag \r\nend\r\n\r\n"
  },
  {
    "path": "share/examples/idl/WriteTimeVaryVDF.pro",
    "content": ";\t$Id$\n;\n;\tThis example shows how to create a time varying data set containing \n;\ta single variable\n;\n\n\n; \n;\tDimensions of the data volumes - all volumes in a data set must be \n;\tof the same dimension\n;\ndim = [64,64,64]\n\n;\n;\n; The number of coarsened approximations to create. A value of 0\n; indicates that the data should not be transformed, i.e. the\n; data will only exist at it's native resolution. A value of 1\n; indicates that a single coarsening should be applied, and so on.\n;\nnum_levels = 1\n\n;\n;\tCreate a new VDF metadata object of the indicated dimension and \n;\ttransform\n;\tlevel. vdf_create() returns a handle for future operations on \n;\tthe metadata object.\n;\nmfd = vdf_create(dim,num_levels)\n\n;\n;\tSet the maximum number of timesteps in the data set. Note, valid data \n;\tset may contain less than the maximum number of time steps, \n;\tbut not more\n;\ntimesteps = 10\nvdf_setnumtimesteps, mfd,timesteps\n\n;\n;\tSet the names of the variables the data set will contain. In this case,\n;\tonly a single variable will be present, \"ml\"\n;\nvarnames = ['ml']\nvdf_setvarnames, mfd, varnames\n\n;\n;\tStore the metadata object in a file for subsequent use\n;\nvdffile = 'test.vdf'\nvdf_write, mfd, vdffile\n\n;\n;\tDestroy the metadata object. We're done with it.\n;\nvdf_destroy, mfd\n\n\n;\n;\tAt this point we've defined all of the metadata associated with \n;\tthe test data set. Now we're ready to begin populating the data\n;\tset with actual data. Our data, in this case, will be a \n;\ttime-varying Marschner Lobb function sampled on a regular grid\n;\n\n\n;\n;\tCreate a \"buffered write\" data transformation object. The data\n;\ttransformation object will permit us to write (transform) raw\n;\tdata into the data set. The metadata for the data volumes is\n;\tobtained from the metadata file we created previously. I.e.\n;\t'vdffile' must contain the path to a previously created .vdf\n;\tfile. The 'vdf_bufwritecreate' returns a handle, 'dfd', for \n;\tsubsequent ;\toperations.\n;\ndfd = vdc_bufwritecreate(vdffile)\n\n;\n;\tGenerate a time varying data, set one volume at a time, saving each\n;\tvolume into the data collection\n;\nalpha = 0.05\nfor ts = 0, timesteps-1 do begin\n\n\t; Create a synthetic data volume\n\t;\n\tf = marschner_lobb(dim[0], dim[1], dim[2], ALPHA=alpha)\n\talpha = alpha + 0.05\n\n\t; \n\t; Prepare the data set for writing. We need to identify the time step\n\t; and the name of the variable that we wish to store\n\t;\n\tvdc_openvarwrite, dfd, ts, varnames[0]\n\n\n\t;\n\t; Write (transform) the volume to the data set one slice at a time\n\t;\n\tfor z = 0, dim[2]-1 do begin\n\t\tvdc_bufwriteslice, dfd, f[*,*,z]\n\tendfor\n\n\t;\n\t; Close the currently opened variable/time-step. We're done writing\n\t; to it\n\t;\n\tvdc_closevar, dfd\n\n\nendfor\n\n\n;\n;\tDestroy the \"buffered write\" data transformation object. \n;\tWe're done with it.\n;\nvdc_bufwritedestroy, dfd\n\n\nend\n"
  },
  {
    "path": "share/examples/idl/WriteVDF.pro",
    "content": ";\t$Id$\n;\n;\tThis example shows how to create a data set containing \n;\ta single variable and at a single time step\n;\n\n\n; \n;\tDimensions of the data volumes - all volumes in a data set must be \n;\tof the same dimension\n;\ndim = [64,64,64]\n\n;\n;\n; The number of coarsened approximations to create. A value of 0\n; indicates that the data should not be transformed, i.e. the\n; data will only exist at it's native resolution. A value of 1\n; indicates that a single coarsening should be applied, and so on.\n;\nnum_levels = 1\n\n;\n;\tCreate a new VDF metadata object of the indicated dimension and \n;\ttransform\n;\tlevel. vdf_create() returns a handle for future operations on \n;\tthe metadata object.\n;\nmfd = vdf_create(dim,num_levels)\n\n;\n;\tSet the maximum number of timesteps in the data set. Note, valid data \n;\tset may contain less than the maximum number of time steps, \n;\tbut not more\n;\ntimesteps = 1\nvdf_setnumtimesteps, mfd,timesteps\n\n;\n;\tSet the names of the variables the data set will contain. In this case,\n;\tonly a single variable will be present, \"ml\"\n;\nvarnames = ['ml']\nvdf_setvarnames, mfd, varnames\n\n;\n;\tStore the metadata object in a file for subsequent use\n;\nvdffile = 'test.vdf'\nvdf_write, mfd, vdffile\n\n;\n;\tDestroy the metadata object. We're done with it.\n;\nvdf_destroy, mfd\n\n\n;\n;\tAt this point we've defined all of the metadata associated with \n;\tthe test data set. Now we're ready to begin populating the data\n;\tset with actual data. Our data, in this case, will be a \n;\ttime-varying Marschner Lobb function sampled on a regular grid\n;\n\n\n;\n;\tCreate a \"buffered write\" data transformation object. The data\n;\ttransformation object will permit us to write (transform) raw\n;\tdata into the data set. The metadata for the data volumes is\n;\tobtained from the metadata file we created previously. I.e.\n;\t'vdffile' must contain the path to a previously created .vdf\n;\tfile. The 'vdc_bufwritecreate' returns a handle, 'dfd', for \n;\tsubsequent ;\toperations.\n;\ndfd = vdc_bufwritecreate(vdffile)\n\n\n; Create a synthetic data volume\n;\nf = marschner_lobb(dim[0], dim[1], dim[2])\n\n; \n; Prepare the data set for writing. We need to identify the time step\n; and the name of the variable that we wish to store\n;\nvdc_openvarwrite, dfd, 0, varnames[0], -1\n\n\n;\n; Write (transform) the volume to the data set one slice at a time\n;\nfor z = 0, dim[2]-1 do begin\n\tvdc_bufwriteslice, dfd, f[*,*,z]\nendfor\n\n;\n; Close the currently opened variable/time-step. We're done writing\n; to it\n;\nvdc_closevar, dfd\n\n\n;\n;\tDestroy the \"buffered write\" data transformation object. \n;\tWe're done with it.\n;\nvdc_bufwritedestroy, dfd\n\n\nend\n"
  },
  {
    "path": "share/examples/idl/curl_findiff.pro",
    "content": "; $Id$\r\n;\r\n; NAME:\r\n;       CURL_FINDIFF\r\n;\r\n; PURPOSE:\r\n;       Computes the curl of a vector field using sixth\r\n;       order finite differences in regular Cartesian grids\r\n;\r\n; CALLING SEQUENCE:\r\n;       CURL_FINDIFF,INX,INY,INZ,OUTX,OUTY,OUTZ,DX,DY,DZ\r\n;\r\n; PARAMETERS:\r\n;       INX[in]:   3D array with the x component of the field\r\n;       INY[in]:   3D array with the y component of the field\r\n;       INZ[in]:   3D array with the z component of the field\r\n;       OUTX[out]: 3D array with the x component of the curl\r\n;       OUTY[out]: 3D array with the y component of the curl\r\n;       OUTZ[out]: 3D array with the z component of the curl\r\n;       DX[in]:    spatial step of the grid in the x direction\r\n;       DY[in]:    spatial step of the grid in the y direction.\r\n;       DZ[in]:    spatial step of the grid in the z direction.\r\n;\r\n;\r\n; COMMON BLOCKS:\r\n;       None\r\n;\r\n;-\r\nPRO curl_findiff,inx,iny,inz,outx,outy,outz,dx,dy,dz\r\n\r\non_error,2                      ;return to caller if an error occurs\r\n\r\nderiv_findiff,inz,aux1,2,dy       ;x component of the curl\r\nderiv_findiff,iny,aux2,3,dz\r\noutx = aux1-aux2\r\n\r\nderiv_findiff,inx,aux1,3,dz       ;y component of the curl\r\nderiv_findiff,inz,aux2,1,dx\r\nouty = aux1-aux2\r\n\r\nderiv_findiff,iny,aux1,1,dx       ;z component of the curl\r\nderiv_findiff,inx,aux2,2,dy\r\noutz = aux1-aux2\r\n\r\nend\r\n"
  },
  {
    "path": "share/examples/idl/deriv_findiff.pro",
    "content": "; $Id$\n;\n; NAME:\n;       DERIV_FINDIFF\n;\n; PURPOSE:\n;       Computes first order derivatives using sixth order finite\n;       differences in regular Cartesian grids\n;\n; CALLING SEQUENCE:\n;       DERIV_FINDIFF,IN,OUT,DIR,DX\n;\n; PARAMETERS:\n;       IN[in]:   3D array with the field component\n;       OUT[out]: 3D array with the spatial derivative\n;       DIR[in]:  direction (1,2, or 3) of the the derivative\n;       DX[in]:   spatial step of the grid in the direction DIR\n;       \n; COMMON BLOCKS:\n;       None\n;\n;-\nPRO deriv_findiff,in,out,dir,dx\n\non_error,2                      ;return to caller if an error occurs\ns = size(in)                    ;size of the input array\nout = in                        ;output has the same size than input\n\nif dir eq 1 then begin          ;derivative for dir=1\n   for i = 0,2 do begin\n       out(i,*,*) = (-11*in(i,*,*)+18*in(i+1,*,*)-9*in(i+2,*,*)+2*in(i+3,*,*))$\n                    /(6*dx)     ;forward differences near the first boundary\n   endfor\n   for i = 3,s(dir)-4 do begin\n       out(i,*,*) = (-in(i-3,*,*)+9*in(i-2,*,*)-45*in(i-1,*,*)+45*in(i+1,*,*) $\n                    -9*in(i+2,*,*)+in(i+3,*,*))/(60*dx) ;centered differences\n   endfor\n   for i = s(dir)-3,s(dir)-1 do begin\n       out(i,*,*) = (-2*in(i-3,*,*)+9*in(i-2,*,*)-18*in(i-1,*,*)+11*in(i,*,*))$\n                    /(6*dx)     ;backward differences near the second boundary\n   endfor\nendif\n\nif dir eq 2 then begin          ;derivative for dir=2\n   for i = 0,2 do begin\n       out(*,i,*) = (-11*in(*,i,*)+18*in(*,i+1,*)-9*in(*,i+2,*)+2*in(*,i+3,*))$\n                    /(6*dx)     ;forward differences near the first boundary\n   endfor\n   for i = 3,s(dir)-4 do begin\n       out(*,i,*) = (-in(*,i-3,*)+9*in(*,i-2,*)-45*in(*,i-1,*)+45*in(*,i+1,*) $\n                    -9*in(*,i+2,*)+in(*,i+3,*))/(60*dx) ;centered differences\n   endfor\n   for i = s(dir)-3,s(dir)-1 do begin\n       out(*,i,*) = (-2*in(*,i-3,*)+9*in(*,i-2,*)-18*in(*,i-1,*)+11*in(*,i,*))$\n                    /(6*dx)     ;backward differences near the second boundary\n   endfor\nendif\n\nif dir eq 3 then begin          ;derivative for dir=3\n   for i = 0,2 do begin\n       out(*,*,i) = (-11*in(*,*,i)+18*in(*,*,i+1)-9*in(*,*,i+2)+2*in(*,*,i+3))$\n                    /(6*dx)     ;forward differences near the first boundary\n   endfor\n   for i = 3,s(dir)-4 do begin\n       out(*,*,i) = (-in(*,*,i-3)+9*in(*,*,i-2)-45*in(*,*,i-1)+45*in(*,*,i+1)$\n                    -9*in(*,*,i+2)+in(*,*,i+3))/(60*dx) ;centered differences\n   endfor\n   for i = s(dir)-3,s(dir)-1 do begin\n       out(*,*,i) = (-2*in(*,*,i-3)+9*in(*,*,i-2)-18*in(*,*,i-1)+11*in(*,*,i))$\n                    /(6*dx)     ;backward differences near the second boundary\n   endfor\nendif\n\nend\n"
  },
  {
    "path": "share/examples/idl/div_findiff.pro",
    "content": "; $Id$\r\n;\r\n; NAME:\r\n;       DIV_FINDIFF\r\n;\r\n; PURPOSE:\r\n;       Computes the divergence of a vector field using sixth\r\n;       order finite differences in regular Cartesian grids\r\n;\r\n; CALLING SEQUENCE:\r\n;       DIV_FINDIFF,INX,INY,INZ,OUT,DX,DY,DZ\r\n;\r\n; PARAMETERS:\r\n;       INX[in]:   3D array with the x component of the field\r\n;       INY[in]:   3D array with the y component of the field\r\n;       INZ[in]:   3D array with the z component of the field\r\n;       OUT[out]:  3D array with the divergence\r\n;       DX[in]:    spatial step of the grid in the x direction\r\n;       DY[in]:    spatial step of the grid in the y direction.\r\n;       DZ[in]:    spatial step of the grid in the z direction.\r\n;\r\n;\r\n; COMMON BLOCKS:\r\n;       None\r\n;\r\n;-\r\nPRO div_findiff,inx,iny,inz,out,dx,dy,dz\r\n\r\non_error,2                      ;return to caller if an error occurs\r\n\r\nderiv_findiff,inx,aux1,1,dx       ;x component of the div \r\nderiv_findiff,iny,aux2,2,dy       ;y component of the div \r\nderiv_findiff,inz,aux3,3,dz       ;z component of the div \r\n\r\nout = aux1+aux1+aux3 \r\n\r\nend\r\n"
  },
  {
    "path": "share/examples/idl/elev_deriv.pro",
    "content": "; NAME:\n;      ELEV_DERIV \n;\n; PURPOSE:\n;       Computes first order z-derivatives using 6 order differences \n;       differences in WRF grids.  The z-derivative is based on\n;\tthe ratio of differences in the field variable to differences\n;\tin the ELEVATION variable, both in the z-coordinate.  \n;       No provision is made for a non-increasing ELEVATION variable...\n;\tthat could result in divide by zero.\n;\tThe ELEV variable must have the same dimensions as IN\n;\n; CALLING SEQUENCE:\n;       ELEV_DERIV,ELEV,IN,OUT\n;\n; PARAMETERS:\n;       IN[in]:   3D array of field variable\n;       OUT[out]: 3D array with the z derivative\n;       ELEV[in]: 3D array of elevations (z-coordinates)\n;       \n; COMMON BLOCKS:\n;       None\n;\n;-\nPRO elev_deriv,in,out,elev \n\non_error,2                      ;return to caller if an error occurs\ns = size(in)                    ;size of the input array\n                       ;output has the same size than input\nout = fltarr(s(1),s(2),s(3))\n\n\n   for i = 0,2 do begin\n       out(*,*,i) = (-11*in(*,*,i)+18*in(*,*,i+1)-9*in(*,*,i+2)+2*in(*,*,i+3))$\n       \t/(-11*elev(*,*,i)+18*elev(*,*,i+1)-9*elev(*,*,i+2)+2*elev(*,*,i+3))\n                    ;forward differences near the first boundary\n   endfor\n   for i = 3,s(3)-4 do begin\n       out(*,*,i) = (-in(*,*,i-3)+9*in(*,*,i-2)-45*in(*,*,i-1)+45*in(*,*,i+1)$\n                    -9*in(*,*,i+2)+in(*,*,i+3))$\n       \t/(-elev(*,*,i-3)+9*elev(*,*,i-2)-45*elev(*,*,i-1)+45*elev(*,*,i+1)$\n                    -9*elev(*,*,i+2)+elev(*,*,i+3)) ;centered differences\n   endfor\n   for i = s(3)-3,s(3)-1 do begin\n       out(*,*,i) = (-2*in(*,*,i-3)+9*in(*,*,i-2)-18*in(*,*,i-1)+11*in(*,*,i))$\n       \t/(-2*elev(*,*,i-3)+9*elev(*,*,i-2)-18*elev(*,*,i-1)+11*elev(*,*,i))\n                    ;backward differences near the second boundary\n   endfor\n\nend\n"
  },
  {
    "path": "share/examples/idl/expregion.pro",
    "content": ";\n; NAME:\n;       EXPREGION\n;\n; PURPOSE:\n;\t\tExport a volume subregion to VAPoR. This procedure is a convenience\n;\t\tfunction for exporting a subvolume to VAPOR. In essense, it simply\n;\t\tcreates a mini VDC with the same basic attributes (dimension, \n;\t\tuser extents, num transforms, etc) as an existing \"parent\" VDC. \n;\t\tThe new, mini VDC may be merged with the parent VDC by the\n;\t\tvapor gui.\n;\n;\t\tN.B. This procedure assumes that the region to be exported is sampled\n;\t\tat the native (highest) resolution of the grid.\n;\n; CALLING SEQUENCE:\n;       EXPREGION, VDF, STATEINFO, VARNAMES, ARRAY0 [, ARRAY1 [, ARRAY2...[, ARRAY5]]]\n;\n; KEYWORD PARAMETERS:\n;\n;\t\tAPPEND:\t\tA boolean indicating whether exported variables should\n;\t\t\t\t\tbe written to an existing .vdf file named by VDF. If not\n;\t\t\t\t\tset a new .vdf file will be created\n;\n;       COORD:\t\tA three-element array containing the starting XYZ \n;\t\t\t\t\tcoordinates (in voxels) of the region\n;\t\t\t\t\tto be exported relative to the parent VDC. The\n;\t\t\t\t\tdefault is to use the MINRANGE structure member of \n;\t\t\t\t\tthe STATEINFO paramater\n;\n;       NUMTS:\t\tIf set specifies the number of timesteps to allow\n;\t\t\t\t\tfor in the .vdf file specified by VDF. This keyword\n;\t\t\t\t\tand the APPEND keyword are mutually exclusive.\n;\n;\t\tTS:\t\t\tIf set specifies the time set offset for the\n;\t\t\t\t\texported variable. The default is 0\n;\n;\t\tVAR2DXY:\tIf set the variables 2D arrays in the XY plane\n;\t\t\t\t\t\n;\n; INPUTS:\n;\n;\t\tVDF:\t\tPath name of the vdf file that will describe\n;\t\t\t\t\tthe region\n;\n;\n;\t\tSTATEINFO:\tA stateinfo structure returned by vaporimport() (the\n;\t\t\t\t\tparent VDC)\n;\n;       VARNAMES:\tThe names of the variables that are being exported. \n;\t\t\t\t\tThe number of ARRAY arguments must agree with the\n;\t\t\t\t\tnumber of names contained in VARNAMES\n;\n;\t\tARRAY0:\t\tFirst 3D array containig the region to export\n;\t\tARRAY1:\t\tSecond 3D array containig the region to export\n;\t\tARRAY2:\t\tThird 3D array containig the region to export\n;\t\tARRAY3:\t\tFourth 3D array containig the region to export\n;\t\tARRAY4:\t\tFifth 3D array containig the region to export\n;\t\tARRAY5:\t\tSixth 3D array containig the region to export\n;\n; OUTPUTS:\n;\n; COMMON BLOCKS:\n;       None.\n;\n;-\npro expregion, vdf, stateinfo, varnames, array0, array1, array2, array3, array4, array5, COORD=coord, APPEND=append, NUMTS=numts, TS=ts, VAR2DXY=var2dxy\n\n\n\ton_error,2                      ;Return to caller if an error occurs\n\tif keyword_set(coord) eq 0 then coord = stateinfo.minrange\n\tif keyword_set(numts) eq 0 then numts = 1\n\tif keyword_set(ts) eq 0 then ts = 0\n\tif keyword_set(append) eq 0 then append = 0\n\tif keyword_set(var2dxy) eq 0 then var2dxy = 0\n\tvarnamesvec = [varnames]\t; Ensure varnames is an array\n\n\n\t;\n\t; Open the .vdf file describing the parent VDC\n\t;\n\tmfd = vdf_create(stateinfo.vdfpath)\n\n\t;\n\t; Extract the relevant attributes from the parent VDC\n\t;\n\tnfiltercoef = vdf_getfiltercoef(mfd)\n\tnliftingcoef = vdf_getliftingcoef(mfd)\n\tbs = vdf_getblocksize(mfd)\n\tnxforms = vdf_getnumtransforms(mfd)\n\tdim = vdf_getdimension(mfd)\n\n\tvdf_destroy, mfd\n\n\t;\n\t; If the append keyword is set create a new, \"mini\" VDC with the \n\t; same basic attributes of the parente VDC. Otherwise the .vdf file \n\t; referenced by 'vdf' must already exist.\n\t;\n\tif (append eq 0) then begin\n\t\tmfd = vdf_create(dim, nxforms, BS=bs, NFILTERCOEF=nfiltercoef, NLIFTINGCOEF=nliftingcoef)\n\n\t\t;\n\t\t; Add the new variable to the mini VDC\n\t\t;\n\t\tvdf_setvarnames, mfd, varnamesvec\n\t\tif (var2dxy eq 1)  then begin\n\t\t\tvdf_setvariables2dxy, mfd, varnamesvec\n\t\tendif\n\t\tvdf_setnumtimesteps, mfd, numts\n\n\t\tvdf_write, mfd, vdf\n\t\tvdf_destroy, mfd\n\tendif\n\n\n\t;\n\t; Now write the arrays to the new VDC\n\t;\n\tif (var2dxy eq 1)  then begin\n\t\tdfd = vdc_regwritecreate2d(vdf)\n\tendif else begin\n\t\tdfd = vdc_regwritecreate(vdf)\n\tendelse\n\n\t;\n\t; Brain damaged code for handling optional number of function\n\t; parameters\n\t;\n\tif (n_elements(array0) ne 0) and (n_elements(varnamesvec) ge 1) then begin\n\t\tvdc_openvarwrite, dfd, ts, varnamesvec[0], -1\n\t\tvdc_regwrite, dfd, array0, coord\n\t\tvdc_closevar, dfd\n\tendif\n\tif (n_elements(array1) ne 0) and (n_elements(varnamesvec) ge 2) then begin\n\t\tvdc_openvarwrite, dfd, ts, varnamesvec[1], -1\n\t\tvdc_regwrite, dfd, array1, coord\n\t\tvdc_closevar, dfd\n\tendif\n\tif (n_elements(array2) ne 0) and (n_elements(varnamesvec) ge 3) then begin\n\t\tvdc_openvarwrite, dfd, ts, varnamesvec[2], -1\n\t\tvdc_regwrite, dfd, array2, coord\n\t\tvdc_closevar, dfd\n\tendif\n\tif (n_elements(array3) ne 0) and (n_elements(varnamesvec) ge 4) then begin\n\t\tvdc_openvarwrite, dfd, ts, varnamesvec[3], -1\n\t\tvdc_regwrite, dfd, array3, coord\n\t\tvdc_closevar, dfd\n\tendif\n\tif (n_elements(array4) ne 0) and (n_elements(varnamesvec) ge 5) then begin\n\t\tvdc_openvarwrite, dfd, ts, varnamesvec[4], -1\n\t\tvdc_regwrite, dfd, array4, coord\n\t\tvdc_closevar, dfd\n\tendif\n\tif (n_elements(array5) ne 0) and (n_elements(varnamesvec) ge 6) then begin\n\t\tvdc_openvarwrite, dfd, ts, varnamesvec[5], -1\n\t\tvdc_regwrite, dfd, array5, coord\n\t\tvdc_closevar, dfd\n\tendif\n\n\n\tvdc_regwritedestroy, dfd\n\nend\n"
  },
  {
    "path": "share/examples/idl/impexp.pro",
    "content": "; $Id$\n;\n; This example shows how to importion a region of data from vaporgui,\n; perform an operation on that region, rename and export the region back\n; to vaporgui\n;\n\n;\n; Import a region of data previously exported by vaporgui\n;\nregion = impregion(STATEINFO=stateinfo)\n\n;\n; Perform an operation on the imported data - in this example we \n; apply a simple algebraic operator\n;\nregion = region * region\n\n;\n; Finally, export the region to a new VDC, named 'impexp.vdf'. The new\n; variable we have created will be named 'varsqr'. The new VDC maybe\n; either import into a running vaporgui session from whence the original\n; data came, or may simply be loaded as a new data set\n;\ntmpvdf = 'impexp.vdf'\nvarname = 'varsqr'\nexpregion, tmpvdf, stateinfo, varname, region\n\n\nend\n"
  },
  {
    "path": "share/examples/idl/impregion.pro",
    "content": "; $Id$\n;\n; NAME:\n;       IMPREGION\n;\n; PURPOSE:\n;\t\tImport a volume subregion from VAPoR. The subregion must\n;\t\tfirst have been exported by VAPoR\n;       endian or big endian format. \n;\n; CALLING SEQUENCE:\n;       IMPREGION\n;\n; KEYWORD PARAMETERS:\n;       REFLEVEL[in]:    The desired refinement level. If this keyword is \n;\t\t\tnot set, the subregion will be imported at full resolution\n;\n;       VARNAME[in]:    The desired variable. If this keyword is \n;\t\t\tnot set, the default exported variable returned by\n;\t\t\t'vaporimport()' will be obtained\n;\n;       TIMESTEP[in]:    The desired time step. If this keyword is \n;\t\t\tnot set, the default exported time step returned by\n;\t\t\t'vaporimport()' will be obtained\n;\n;       STATEINFO[out]:    If this keyword is present the output of\n;\t\t\tthe 'vaporimport()' function is returned by the keyword\n;\t\t\targument, possibly modified by the VARNAME and TIMESTEP \n;\t\t\tkeyword. \n;\n; OUTPUTS:\n;       The region is returned\n;\n; COMMON BLOCKS:\n;       None.\n;\n;-\nfunction impregion, REFLEVEL=reflevel, STATEINFO=stateinfo, VARNAME=varname, TIMESTEP=timestep\n\n\non_error,2                      ;Return to caller if an error occurs\nif keyword_set(reflevel) eq 0 then reflevel = -1\n\n\t; Get the state info exported from VAPoR that describes the \n\t; region of interest. vaporimport() returns a structure with \n\t; the following fields:\n\t;\tVDFPATH\t\t: Path to the .vdf file\n\t;\tTIMESTEP\t: Time step of the volume subregion of interest\n\t;\tVARNAME\t\t: Variable name of volume subregion of interest\n\t;\tMINRANGE\t: Minimum extents of region of interest in volume\n\t;\t\t\t\tcoordinates specified relative to the finest resolution\n\t;\tMAXRANGE\t: Maximum extents of region of interest in volume\n\t;\t\t\t\tcoordinates specified relative to the finest resolution\n\tstateinfo = vaporimport()\n\n\tif keyword_set(varname) then begin\n\t\tstateinfo.varname = varname\n\tendif else begin\n\t\tvarname = stateinfo.varname\n\tendelse\n\t;if keyword_set(timestep) then begin\n\tif arg_present(timestep) then begin\n\t\tstateinfo.timestep = timestep\n\tendif else begin\n\t\ttimestep = stateinfo.timestep\n\tendelse\n\n\tmfd = vdf_create(stateinfo.vdfpath)\n\tvars3d = vdf_getvariables3d(mfd)\n\tvarIs2D = 1\n\tfor i=0, n_elements(vars3d)-1 do begin\n\t\tif (vars3d[i] eq varname) then varIs2D = 0\n\tendfor\n\n\n\t;\n\t;   Create a \"Buffered Read\" object to read the data, passing the\n\t;   metadata object handle created by vdf_create() as an argument\n\t;\n\tif (varIs2D) then begin\n\t\tdfd = vdc_regreadcreate2d(mfd) \n\tendif else begin\n\t\tdfd = vdc_regreadcreate(mfd) \n\tendelse\n\n\t;\n\t; Transform coordinates from finest resolution to resolution\n\t; of interest. Note, the coordinates returned in 'stateinfo' \n\t; are in voxel coordinates relative to the finest resolution level.\n\t; We first convert voxel coordinates to user coordinates, then \n\t; convert user coordinates back to voxel coordinates, but at \n\t; the requested refinement level. \n\t;\n\tminu = vdc_mapvox2user(dfd, -1, timestep,stateinfo.minrange)\n\tmin = vdc_mapuser2vox(dfd,reflevel,timestep,minu)\n\n\tmaxu = vdc_mapvox2user(dfd, -1, timestep,stateinfo.maxrange)\n\tmax = vdc_mapuser2vox(dfd,reflevel,timestep,maxu)\n\n\n\t; Create an array large enough to hold the volume subregion\n\t;\n\tif (varIs2D) then begin\n\t\tf = fltarr(max[0]-min[0]+1,max[1]-min[1]+1)\n\tendif else begin\n\t\tf = fltarr(max[0]-min[0]+1,max[1]-min[1]+1,max[2]-min[2]+1)\n\tendelse\n\n\t; Select the variable and time step we want to read\n\t;\n\tvdc_openvarread, dfd, timestep, varname, reflevel\n\n\t; Read the subregion\n\t;\n\tvdc_regread, dfd, min, max, f\n\n\tvdc_closevar, dfd\n\n\tvdc_regreaddestroy, dfd\n\n\treturn, f\n\nend\n"
  },
  {
    "path": "share/examples/idl/marschner_lobb.pro",
    "content": ";\t$Id$\n;\n; Evaluate the 3D marschner lobb function over a grid at the specified\n; resolution. The sampled function is returned.\n;\n\nfunction marschner_lobb, nx, ny, nz, ALPHAFLAG = ALPHA, FMFLAG=FM\n\n\tif (n_elements(ALPHA) eq 0) then ALPHA = 0.25\n\tif (n_elements(FM) eq 0) then FM = 6.0\n\n\trarr = fltarr(nx,ny,nz)\n\tzarr = fltarr(nx,ny,nz)\n\tPI = 3.14159265358979323846\n\n\tfor z = 0, nz-1 do begin\n\t\tfor y = 0, ny-1 do begin\n\t\t\tyc = (y / float(ny-1)) - 0.5\n\t\t\tfor x = 0, nx-1 do begin\n\t\t\t\txc = (x / float(nx-1)) - 0.5\n\t\t\t\trarr[x,y,z] = sqrt(xc*xc + yc*yc)\n\t\t\t\tzarr[x,y,z] = (z / float(nz-1)) - 0.5\n\t\t\tendfor\n\t\tendfor\n\tendfor\n\n\tpr = cos(2*PI*FM*cos(PI*rarr/2.0))\n\tf = (1.0 - sin(PI*zarr/2.0) + (ALPHA * (1.0 + pr))) / (2*(1+ALPHA))\n\t\t\t\t\n\treturn, f\nend\n"
  },
  {
    "path": "share/examples/idl/myderiv.pro",
    "content": ";\n;\t$Id$;\n;\n\nFUNCTION myderiv,x,fx,n,nonperiod\n;\n;\n      nx=n_elements(x)\n      s=size(fx)\n      ndim=s(0)\n;\n;  Centered differences\n;\nif (ndim eq 1) then begin\n        dfx=-1.*(shift(fx,1)-shift(fx,-1))/(x(2)-x(0))\n\tif (nonperiod ne 0) then begin\n\t\tlf=0\n\t\trt=s(1)-1\n\t\tdfx(lf)=(-3.0d00*fx(lf)+4.0d00*fx(lf+1)-fx(lf+2))/(x(2)-x(0))\n\t\tdfx(rt)=(fx(rt-2)-4.0d00*fx(rt-1)+3.0d00*fx(rt))/(x(2)-x(0))\n\tendif\nendif\nif (ndim eq 2) then begin\n      if(n eq 1) then begin\n        dfx=-1.*(shift(fx,1,0)-shift(fx,-1,0))/(x(2)-x(0))\n        if (nonperiod ne 0) then begin\n                lf=0\n                rt=s(1)-1\n                dfx(lf,*)=(-3.0d00*fx(lf,*)+4.0d00*fx(lf+1,*)-fx(lf+2,*))/(x(2)-x(0))\n                dfx(rt,*)=(fx(rt-2,*)-4.0d00*fx(rt-1,*)+3.0d00*fx(rt,*))/(x(2)-x(0))\n        endif\n      endif\n      if(n eq 2) then begin\n        dfx=-1.*(shift(fx,0,1)-shift(fx,0,-1))/(x(2)-x(0))\n\tif (nonperiod ne 0) then begin\n                lf=0\n                rt=s(2)-1\n                dfx(*,lf)=(-3.0d00*fx(*,lf)+4.0d00*fx(*,lf+1)-fx(*,lf+2))/(x(2)-x(0))\n                dfx(*,rt)=(fx(*,rt-2)-4.0d00*fx(*,rt-1)+3.0d00*fx(*,rt))/(x(2)-x(0))\n        endif\n      endif\nendif\nif (ndim eq 3) then begin\n      if(n eq 1) then begin\n        dfx=-1.*(shift(fx,1,0,0)-shift(fx,-1,0,0))/(x(2)-x(0))\n\tif (nonperiod ne 0) then begin\n                lf=0\n                rt=s(1)-1\n                dfx(lf,*,*)=(-3.0d00*fx(lf,*,*)+4.0d00*fx(lf+1,*,*)-fx(lf+2,*,*))/(x(2)-x(0))\n                dfx(rt,*,*)=(fx(rt-2,*,*)-4.0d00*fx(rt-1,*,*)+3.0d00*fx(rt,*,*))/(x(2)-x(0))\n        endif\n      endif\n      if(n eq 2) then begin\n        dfx=-1.*(shift(fx,0,1,0)-shift(fx,0,-1,0))/(x(2)-x(0))\n\tif (nonperiod ne 0) then begin\n                lf=0\n                rt=s(2)-1\n                dfx(*,lf,*)=(-3.0d00*fx(*,lf,*)+4.0d00*fx(*,lf+1,*)-fx(*,lf+2,*))/(x(2)-x(0))\n                dfx(*,rt,*)=(fx(*,rt-2,*)-4.0d00*fx(*,rt-1,*)+3.0d00*fx(*,rt,*))/(x(2)-x(0))\n        endif\n      endif\n      if(n eq 3) then begin\n        dfx=-1.*(shift(fx,0,0,1)-shift(fx,0,0,-1))/(x(2)-x(0))\n\tif (nonperiod ne 0) then begin\n                lf=0\n                rt=s(3)-1\n                dfx(*,*,lf)=(-3.0d00*fx(*,*,lf)+4.0d00*fx(*,*,lf+1)-fx(*,*,lf+2))/(x(2)-x(0))\n                dfx(*,*,rt)=(fx(*,*,rt-2)-4.0d00*fx(*,*,rt-1)+3.0d00*fx(*,*,rt))/(x(2)-x(0))\n        endif\n      endif\nendif\n;\n      return,dfx\n      end\n"
  },
  {
    "path": "share/examples/idl/pencil2vapor.pro",
    "content": "PRO pencil2vapor,topdir,numprocs, vdffile,timestep,varfilename\n;\n; Program to convert a directory of pencil files into a vapor dataset.\n; Arguments are:\n;\ttopdir = absolute path to directory where pencil data is stored\n;\tnumprocs = number of procN subdirectories (N goes from 0 to numprocs -1)\n;\tvdffile = absolute path, including filename, of vdf file for the result.\n;\t\tThe vdf file should be created by running vdffile before this.\n;\t\tThe vdf file should specify names for the variables, in the same order\n;\t\tas they appear in the pencil var.dat files\n;\ttimestep = an integer timestep for the data to be converted.  Must be within\n;\t\tthe number of time steps specified in the vdf file \n;\tvarfilename = a string used to identify the name of the var.dat files.  If it\n;\t\tis not specified, then the default is \"var\"\n;\t \n; \tThe chunks associated with the different processors are not assumed to be\n;\tthe same size, however, all chunks at a given x-coordinate have the same x-thickness,\n;\tand likewize for the chunks at a given y or z coordinate\n;\n\tIF (N_PARAMS() LT 5 ) THEN varfilename = 'var'\n\tvarfilename = varfilename + '.dat' \n;\n;    Create tables to hold information about data:\n;\n\txsize = intarr(numprocs)\n\tysize = intarr(numprocs)\n\tzsize = intarr(numprocs)\n\txposition = intarr(numprocs)\n\typosition = intarr(numprocs)\n\tzposition = intarr(numprocs)\n;\n;\tRead dim.dat files:\n;\n;\t(while finding the thickest z-size)\n\tmaxzthick = 0\n\tFOR I = 0, numprocs-1 DO BEGIN\n\t\tdimfile = topdir+'/proc'+STRTRIM(STRING(I),1)+'/dim.dat'\n\t\tOPENR, 1, dimfile \n;\tRead the first line (contains sizes)\n\t\tREADF,1,sizex,sizey,sizez,foo,bar\n\t\txsize[I] = sizex\n\t\tysize[I] = sizey\n\t\tzsize[I] = sizez\n\t\tIF (sizez GT maxzthick) THEN maxzthick = sizez\n;\tRead second line (precision, a string) \n\t\tprec = ' '\n\t\tREADF,1,prec\n;\tRead third line (ghost widths)\n\t\tREADF,1,ghostx,ghosty,ghostz\n;\tRead the last line (contains positions)\n\t\tREADF,1,xpos,ypos,zpos\n\t\txposition[I] = xpos\n\t\typosition[I] = ypos\n\t\tzposition[I] = zpos\n\t\tCLOSE, 1\n\tENDFOR\n\tmaxzthick = maxzthick - 2*ghostz\n;  \tDetermine the x,y,and z-grid spacing\n\n\txspacing = intarr(numprocs)\n\tyspacing = intarr(numprocs)\n\tzspacing = intarr(numprocs)\n\txspacing[*] = 0\n\tyspacing[*] = 0\n\tyspacing[*] = 0\n\n\tFOR I = 0, numprocs-1 DO BEGIN\n\t\txspacing[xposition[I]] = xsize[I] - 2*ghostx\n\t\tyspacing[yposition[I]] = ysize[I] - 2*ghosty\n\t\tzspacing[zposition[I]] = zsize[I] - 2*ghostz\n\tENDFOR\n\n;\tAccumulate the spacings\n\txtot = 0\n\tytot = 0\n\tztot = 0\n\tFOR I = 0, numprocs -1 DO BEGIN\n\t\tIF (xspacing[I] NE 0) THEN BEGIN\n\t\t\txtot = xtot + xspacing[I]\n\t\t\txspacing[I] = xtot - xspacing[I]\t\t\n\t\tENDIF\n\t\tIF (yspacing[I] NE 0) THEN BEGIN\n\t\t\tytot = ytot + yspacing[I]\n\t\t\tyspacing[I] = ytot - yspacing[I]\t\t\n\t\tENDIF\n\t\tIF (zspacing[I] NE 0) THEN BEGIN\n\t\t\tnumslabs = I+1\n\t\t\tztot = ztot + zspacing[I]\n\t\t\tzspacing[I] = ztot - zspacing[I]\t\t\n\t\tENDIF\n\tENDFOR\n\n;\tSort the tables on z-coordinate:\n;\n\tfileorder = SORT(zposition)\n\n;\tCreate the metadata from the vdffile.\n;\tFind the dimensions of the data.\n;\tThese had better agree with the pencil data!\n; \n\tmfd = vdf_create(vdffile)\n\tdim = vdf_getdimension(mfd)\n\tvarnames = vdf_getvarnames(mfd)\n\tsz = size(varnames)\n\tnumvariables = sz[1]\n\n;\n;\tDetermine how many chunks of pencil data are associated with a slab:\n;\n\tchunksperslab = numprocs/numslabs\n;\tAllocate enough memory to hold the largest slab:\n\n\tslabdata = FLTARR(dim[0],dim[1],maxzthick)\n\n;\tLoop over each variable\n\tFOR varnum = 0, numvariables -1 DO BEGIN\n\t\tprint, 'assembling variable ',varnames[varnum]\n\t\tdfd = vdc_bufwritecreate(mfd)\n\t\tvdc_openvarwrite, dfd, timestep, varnames[varnum], -1\n;\n;  \tLoop over the slabs:\n\t\n\t\tFOR slab = 0, numslabs -1 DO BEGIN\n;\tFor each slab, loop over the proc directories (chunks) associated with it:\n\t\t\tFOR chunk = 0, chunksperslab-1 DO BEGIN \t\t\n\t\t\t\tchunknum = slab*chunksperslab + chunk \n\t\t\t\tdirnum = fileorder[chunknum]\n;\t\t\t\tread the chunk into the dataarray\n;\t\t\t\tCreate an array to hold a variable chunk as it is read from the proc directory \n\t\t\t\tIF (prec EQ 'D') THEN BEGIN\n\t\t\t\t\tdataarray = DBLARR(xsize[dirnum],ysize[dirnum],zsize[dirnum],numvariables)\n\t\t\t\tENDIF ELSE dataarray = FLTARR(xsize[dirnum],ysize[dirnum],zsize[dirnum],numvariables)\n\t\t\t\tvarfile = topdir+'/proc'+STRTRIM(STRING(dirnum),1)+'/'+varfilename\n\t\t\t\topenr,1,varfile,/f77\n\t\t\t\treadu,1,dataarray\n\t\t\t\tclose,1\n;\n;\t\t\t\tThen copy the data chunks into the data slab:\n\t\t\t\tminx = xspacing[xposition[dirnum]]\n\t\t\t\tmaxx = FIX(minx + xsize[dirnum] - 2*ghostx-1)\n\t\t\t\tminy = yspacing[yposition[dirnum]]\n\t\t\t\tmaxy = FIX(miny + ysize[dirnum] - 2*ghosty-1)\n\t\t\t\tminz = zspacing[zposition[dirnum]]\n\t\t\t\tmaxz = FIX(minz + zsize[dirnum] - 2*ghostz-1)\n\t\t\t\tslabdata[minx:maxx,miny:maxy,0:(maxz-minz)] = FLOAT(dataarray[ghostx:xsize[dirnum]-ghostx-1,ghosty:ysize[dirnum]-ghosty-1,ghostz:zsize[dirnum]-ghostz-1,varnum])\n\t\t\tENDFOR\n; \t\t\tnow the full slab is populated, write it to the vdf, one\n; \t\t\tz-slice at a time\n;\n\t\t\tFOR z = 0, (maxz-minz) DO BEGIN\n\t\t\t\tvdc_bufwriteslice, dfd, slabdata[*,*,z]\n\t\t\tENDFOR\n\t\tENDFOR\n;  \tNow close the dfd\n\t\tvdc_closevar, dfd\n\t\tvdc_bufwritedestroy,dfd\n\tENDFOR\nEND\n"
  },
  {
    "path": "share/examples/idl/wrf_curl_findiff.pro",
    "content": ";\r\n; NAME:\r\n;       WRF_CURL_FINDIFF\r\n;\r\n; PURPOSE:\r\n;       Computes the curl of a vector field using sixth\r\n;       order finite differences on WRF grid \r\n;\tUses an interpolation scheme described by Mark Stoellinga\r\n;\tto directly calculate the derivatives on the WRF grid.\r\n;\tThe 6th order difference terms are due to Pablo Mininni\r\n;\r\n; CALLING SEQUENCE:\r\n;       WRF_CURL_FINDIFF,INX,INY,INZ,OUTX,OUTY,OUTZ,DX,DY,ELEV\r\n;\r\n; PARAMETERS:\r\n;       INX[in]:   3D array with the x component of the field\r\n;       INY[in]:   3D array with the y component of the field\r\n;       INZ[in]:   3D array with the z component of the field\r\n;       OUTX[out]: 3D array with the x component of the curl\r\n;       OUTY[out]: 3D array with the y component of the curl\r\n;       OUTZ[out]: 3D array with the z component of the curl\r\n;       DX[in]:    spatial step of the grid in the x direction\r\n;       DY[in]:    spatial step of the grid in the y direction.\r\n;\tELEV[in]:  elevation variable\r\n;\r\n;\r\n; COMMON BLOCKS:\r\n;       None\r\n;\r\n;-\r\nPRO wrf_curl_findiff,inx,iny,inz,outx,outy,outz,dx,dy,elev\r\n\r\non_error,2                      ;return to caller if an error occurs\r\n\r\n; x component is dW/dy - dV/dz \r\n; dW/dy is calc by (dW/dy)_eta - (dW/dz)*(dZ/dy)_eta\r\n; where _eta indicates the derivative calculated in the WRF grid coordinates\r\n; as is performed by deriv_findiff.pro\r\n; and Z is the ELEVATION.\r\nderiv_findiff, inz, aux1, 2, dy\r\nelev_deriv, inz, aux2, elev\r\nderiv_findiff, elev, aux3, 2, dy  \r\n;  dV/dz:\r\nelev_deriv, iny, aux4, elev\r\noutx = aux1 - aux2*aux3 - aux4\r\n\r\n; y component is dU/dz - dW/dx \r\n;  dU/dz:\r\nelev_deriv, inx, aux4, elev\r\n; dW/dx is calc by (dW/dx)_eta - (dW/dz)*(dZ/dx)_eta\r\nderiv_findiff, inz, aux1, 1, dx\r\nelev_deriv, inz, aux2, elev\r\nderiv_findiff, elev, aux3, 1, dx  \r\n\r\nouty = aux4 - aux1 + aux2*aux3\r\n\r\n; z component of curl is dV/dx - dU/dy\r\n; dV/dx is (dV/dx)_eta - (dV/dz)*(dZ/dx)_eta\r\nderiv_findiff, iny, aux1, 1, dx\r\nelev_deriv, iny, aux2, elev\r\nderiv_findiff, elev, aux3, 1, dx  \r\n; dU/dy is (dU/dy)_eta - (dU/dz)*(dZ/dy)_eta\r\nderiv_findiff, inx, aux4, 2, dy\r\nelev_deriv, inx, aux5, elev\r\nderiv_findiff, elev, aux6, 2, dy  \r\noutz = aux1 - aux2*aux3 - aux4 + aux5*aux6\r\n\r\n\r\nend\r\n"
  },
  {
    "path": "share/examples/idl/wrf_div_findiff.pro",
    "content": ";\r\n; NAME:\r\n;       WRF_DIV_FINDIFF\r\n;\r\n; PURPOSE:\r\n;       Computes the divergence of a vector field using sixth\r\n;       order finite differences on WRF grid \r\n;\tUses an interpolation scheme described by Mark Stoellinga\r\n;\tto directly calculate the derivatives on the WRF grid.\r\n;\tThe 6th order difference terms are due to Pablo Mininni\r\n;\r\n; CALLING SEQUENCE:\r\n;       WRF_DIV_FINDIFF,INX,INY,INZ,OUT,DX,DY,ELEV\r\n;\r\n; PARAMETERS:\r\n;       INX[in]:   3D array with the x component of the field\r\n;       INY[in]:   3D array with the y component of the field\r\n;       INZ[in]:   3D array with the z component of the field\r\n;       OUT[out]:  3D array with the divergence \r\n;       DX[in]:    spatial step of the grid in the x direction\r\n;       DY[in]:    spatial step of the grid in the y direction.\r\n;\tELEV[in]:  elevation variable\r\n;\r\n;\r\n; COMMON BLOCKS:\r\n;       None\r\n;\r\n;-\r\nPRO wrf_div_findiff,inx,iny,inz,out,dx,dy,elev\r\n\r\non_error,2                      ;return to caller if an error occurs\r\n\r\n; calculate dU/dx as (dU/dx)_eta - (dU/dz)*(dZ/dx)_eta\r\n; where _eta indicates the derivative calculated in the WRF grid coordinates\r\n; as is performed by deriv_findiff.pro\r\nderiv_findiff, inx, aux1, 1, dx\r\nelev_deriv, inx, aux2, elev\r\nderiv_findiff, elev, aux3, 1, dx  \r\nout = aux1 - aux2*aux3\r\n\r\n; calculate dV/dy as (dV/dy)_eta - (dV/dz)*(dZ/dy)_eta\r\n; where _eta indicates the derivative calculated in the WRF grid coordinates\r\n; as is performed by deriv_findiff.pro\r\nderiv_findiff, iny, aux1, 2, dy\r\nelev_deriv, iny, aux2, elev\r\nderiv_findiff, elev, aux3, 2, dy  \r\nout = out + aux1 - aux2*aux3\r\n\r\n; dW/dz:\r\nelev_deriv, inz, aux1, elev\r\n\r\nout = out + aux1\r\n\r\nend\r\n"
  },
  {
    "path": "share/examples/listOfSeeds.txt",
    "content": "#\n# Seed injection points within your domain may be defined in this file\n# as comma separated values.\n#\n\n# A line starts with a pound sign is ignored, so is an empty line.\n\n# This is a seed at location (.5, .5, .5)\n.5,.5,.5\n\n# The following line would be ill-formated because it has less than 3 values.\n# .5,.5\n\n# The following line specifies a location (1.0, 1.0, 1.0) with the rest of values ignored.\n1.0, 1.0, 1.0, 0.0, -1.0, -2.0\n\n# The following line specifies a repeated location (.5, .5, .5) which will be ignored.\n.5,.5,.5\n\n"
  },
  {
    "path": "share/gitHooks/pre-push",
    "content": "#!/bin/sh\n#\n\nDRYRUN='false'\nMAIN='false'\n\n# -d initiates a dry-run where code will be scanned, but changes will not be applied\n# -m initiates a comparison between the local HEAD and 'main', instead of comparing\n#    the the local HEAD with the remote HEAD\nwhile getopts dm flag;\ndo\n    case ${flag} in\n        d) DRYRUN='true' ;;\n        m) MAIN='true' ;;\n    esac\ndone\n\necho \"  Running dryrun?    $DRYRUN\"\necho \"  Force comparison to main? $MAIN\"\n\nBRANCH=`git rev-parse --abbrev-ref HEAD`\n\n# If our current branch does not exist in the remote repository yet, then compare\n# our local changes with main.  Otherwise, compare our local changes with the remote\n# branch.\nif [ \"${MAIN}\" != \"true\" ]; then\n    if [ `git ls-remote --heads https://github.com/NCAR/VAPOR.git $BRANCH | wc -l` = 0 ]; then\n        COMPARE_BRANCH=\"main\"\n    else\n        COMPARE_BRANCH=$BRANCH\n    fi\nfi\n\necho \"  Comparing current changes with branch: $COMPARE_BRANCH\"\n\n# If we're on the readTheDocs branch, skip clang-format\n#\nif [ \"$BRANCH\" = \"readTheDocs\" ]; then\n    echo \"pre-push hook skipped for current branch.\"\n\n# Otherwise format the changed lines in all commits up to this push\n#\nelse\n    for COMMIT in $(git log --pretty=format:%h origin/$COMPARE_BRANCH...$BRANCH); do\n        echo \"Reading Commit: $COMMIT\"\n        for FILE in $(git diff --name-only $COMMIT^ $COMMIT |grep -E \"\\.h|\\.cpp\"); do\n            NUMBERS=\"\"\n            for NUMBER in $(git blame --line-porcelain \"$FILE\" | egrep ^$COMMIT | cut -d' ' -f3); do\n                NUMBERS=\"$NUMBERS --lines $NUMBER:$NUMBER \"\n            done\n\n            if [ \"$NUMBERS\" != \"\" ]; then\n                if [ \"${DRYRUN}\" = \"true\" ]; then\n                    echo \"dry run activated\"\n                    clang-format --dry-run -i $FILE $NUMBERS >> /tmp/clang-format.txt 2>&1\n                else\n                    echo \"  Running clang-format on $FILE, line $NUMBERS\"\n                    clang-format -i $FILE $NUMBERS\n                    git add $FILE\n                fi\n            fi\n        done\n    done\n\n    if [ \"${DRYRUN}\" = \"false\" ]; then\n        git commit -m \"clang-format pre-push hook\"\n    fi\n\n    # git commit will return non-zero status if there's nothing to commit.  Make sure\n    # we return 0 so git 'push' will still be invoked\n    exit 0\nfi\n"
  },
  {
    "path": "share/gitHooks/setupHooks.sh",
    "content": "#!/bin/sh\n\nROOT_DIR=$(git rev-parse --show-toplevel)\nHOOK_DIR=$ROOT_DIR/.git/hooks\nHOOK=$HOOK_DIR/pre-push\nln -sf $ROOT_DIR/share/gitHooks/pre-push $HOOK\n\nif [ -e \"$HOOK\" ]\nthen\n    echo \"pre-push hook installed in $HOOK_DIR\"\nelse\n    echo \"Failure: Unable to create sym-link in $HOOK_DIR\"\nfi\n"
  },
  {
    "path": "share/notices/__example-notice.json",
    "content": "{\n    \"_comment-1\": \"This is an example notice. It will be ingored by Vapor\",\n\n    \"_comment-2\": \"This is the date at which the notice will be displayed to users\",\n    \"_comment-3\": \"The time format is yyyy-MM-dd by Qt's specification\",\n\t\"date\": \"2021-06-01\",\n\n    \"_comment-4\": \"This is the date at which the notice will no longer be displayed to users\",\n\t\"until\": \"2021-09-27\",\n\n\n    \"_comment-5\": \"This is the content of the notice. It uses a subset of HTML that is supported by QTextBrowser\",\n\n\t\"content\": \"<br> <center><h1>Notice</h1></center> <hr> <br> <h2>Vapor's homepage: <a href='http://www.vapor.ucar.edu'>Link</a></h2>\"\n}\n"
  },
  {
    "path": "share/palettes/Diverging/BlueWhiteGold.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<UseWhitespace Type=\"Long\">\n  1\n</UseWhitespace>\n<ColorMapControlPoints Type=\"Double\">\n  0.5933147668838501 0.7607843279838562 0.9137254953384399 0 0.1142061278223991 0.8627451062202454 0.6784313917160034 0.9900000095367432 \n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/CoolWarm.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<UseWhitespace Type=\"Long\">\n  2 \n</UseWhitespace>\n<ColorMapControlPoints Type=\"Double\">\n  0.644444465637207 0.6949999928474426 0.7570000290870667 0 0.9666666388511658 0.9769999980926514 0.7059999704360962 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/CoolWarmBent.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  0.640668511390686 0.6941176652908325 0.7568627595901489 0 -0.002785515272989869 0 0.9490196108818054 0.5208055377006531 0.9665738344192505 0.9764705896377563 0.7058823704719543 0.9900000095367432 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.33333333333333333 1 0.66666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/CoolWarmSmooth.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<UseWhitespace Type=\"Long\">\n  1 \n</UseWhitespace>\n<ColorMapControlPoints Type=\"Double\">\n  0.640668511390686 0.6941176652908325 0.7568627595901489 0 0.9665738344192505 0.9764705896377563 0.7058823704719543 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/GreenWhitePurple.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<UseWhitespace Type=\"Long\">\n  1 \n</UseWhitespace>\n<ColorMapControlPoints Type=\"Double\">\n  0.3760445713996887 0.8392156958580017 0.5333333611488342 0 0.7325905561447144 0.5137255191802979 0.6352941393852234 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/GreenWhiteRed.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<UseWhitespace Type=\"Long\">\n  1 \n</UseWhitespace>\n<ColorMapControlPoints Type=\"Double\">\n  0.3760445713996887 0.8470588326454163 0.5333333611488342 0 0.9944289922714233 0.7176470756530762 0.7607843279838562 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/PurpleWhiteOrange.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<UseWhitespace Type=\"Long\">\n  1 \n</UseWhitespace>\n<ColorMapControlPoints Type=\"Double\">\n  0.7353760600090027 0.5098039507865906 0.6313725709915161 0 0.06685236841440201 0.9411764740943909 0.7607843279838562 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  0 1 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/balance.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n5 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.6488481188400105 0.6437021499566375 0.2615123885530548 0 0.5900150015421565 0.9393560590369526 0.7454889092261349 0.1666666666666667 0.5457489954299063 0.3848527451053083 0.7434335263117878 0.3333333333333333 0.02692698143186436 0.02309190124513382 0.9450241336950317 0.5 0.04242886065790093 0.4458818451186248 0.8157857974447502 0.6666666666666666 0.9959726603348144 0.7974657948930718 0.6483618361407727 0.8333333333333333 0.971657574461405 0.8504701197267419 0.236056364664614 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/curl.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.8278897949606616 0.7542061978182768 0.20853720637712653 0.0 0.9250743235535671 0.6951507646615473 0.61270939731 0.16666666666666666 0.035853343170463105 0.4555012519711035 0.8593125235209843 0.3333333333333333 0.02950939488983051 0.03726602425907123 0.9929465713958281 0.5 0.3899353073524154 0.2959263644853567 0.7018019300139728 0.6666666666666666 0.5106145733580575 0.8148005363261331 0.4477088968524857 0.8333333333333333 0.6368377882653272 0.6893555377202758 0.26479016778008574 1.0\n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/delta.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1415.363525390625 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1415.363525390625 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.6140949377805809 0.7355416095492259 0.2494811599712868 0 0.6330804295737312 0.7032664339670238 0.4936502476018932 0.07142857142857142 0.5859736252285871 0.830428699019629 0.6195251374197684 0.1428571428571428 0.5510623284995626 0.7685151994004963 0.6453485009817425 0.2142857142857143 0.5190234368385999 0.6038502597225501 0.6808595744198757 0.2857142857142857 0.4829421039692708 0.3036057396192864 0.7460500590687459 0.3571428571428571 0.4257600007162249 0.1002650673205966 0.8533263291295689 0.4285714285714285 0.1588483782677347 0.1986719170815648 0.9982730268101483 0.5 0.1368479050484376 0.4482582772952977 0.8995373837127171 0.5714285714285714 0.155234671931644 0.723048717630318 0.7426430871174343 0.6428571428571428 0.1972179231386593 0.9591742653183207 0.6180898846857883 0.7142857142857142 0.2791330843893799 0.7994216841630458 0.5211096093711738 0.7857142857142857 0.3909196980487105 0.8815572324657858 0.4047485074383744 0.8571428571428571 0.397139111935538 0.6788372476449076 0.2717262314473357 0.9285714285714285 0.288402825198751 0.4665912550886617 0.1373386075843833 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1415.363525390625 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/diff.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n5 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.5859776512391991 0.8767176683047709 0.249846444559915 0 0.5672289034733282 0.4310019519368037 0.4884111449080716 0.1666666666666667 0.5751576319408671 0.1101281155816629 0.7073025514622064 0.3333333333333333 0.03091203441454771 0.02270456720342846 0.962971730415212 0.5 0.1198337800190978 0.1931171328565661 0.6902175511682563 0.6666666666666666 0.1310320694992013 0.5696636144086142 0.423147463724184 0.8333333333333333 0.2033062807024827 0.7980878893216422 0.1339166670121798 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Diverging/tarn.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n7 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.262152612700985 0.6149905855180422 0.1386884202488073 0 0.1442785294697875 0.7270786717586432 0.4178758479312351 0.1666666666666667 0.07458590230439183 0.5094780890838793 0.8288195980598317 0.3333333333333334 0.0380974216812194 0.02408740926575129 0.9884162623276403 0.5 0.3441111492041977 0.1524328039795236 0.6963445147045469 0.6666666666666667 0.5188190638418212 0.7374157832587309 0.4710274926158041 0.8333333333333334 0.6287394897504813 0.8021011784991612 0.3108793933905304 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Highlighting/oxy.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n0 \n</ColorInterpolationType>\n<UseWhitespace Type=\"Long\">\n0 \n</UseWhitespace>\n<ColorMapControlPoints Type=\"Double\">\n0.01350000035017729 0.8043488264083862 0.1803921610116959 0 \n0.02777777798473835 0.8333256840705872 0.4235294163227081 0.197\n-1 0 0.2705882489681244 0.2\n0.1666666716337204 0.008270390331745148 0.9490196108818054 0.797\n0.1754444390535355 0.5960784554481506 1 0.8\n0.1339722275733948 0.7939726710319519 0.7803921699523926 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Highlighting/topo.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n5 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.7938268228367832 0.4059326069616122 0.1727215696232308 0 0.6190058274300871 0.568850001160404 0.5676029832475817 0.1666666666667 0.5012583114787256 0.5119882782922851 0.6340450861601971 0.3333333333333 0.1755833327770233 0.221347376704216 0.9921568632125854 0.499 0.2948611080646515 0.3939421772956848 0.1294117718935013 0.5 0.2474454176360088 0.523618576887678 0.370720292815769 0.66666666666 0.1211480166335046 0.6284944517502499 0.6664663550324849 0.8333333333333 0.1980982980158893 0.09908783848317795 0.9933519398287799 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/BlackBody.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  -0.002785515272989869 0 0 0 0 0.8117647171020508 0.6980392336845398 0.3912840485572815 0.07520891726016998 0.9803921580314636 0.8901960849761963 0.5801073312759399 0.1448467969894409 0.9176470637321472 0.9333333373069763 0.8404544591903687 -0.002785515272989869 0 1 0.9900000095367432 \n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/BlackBodyExtended.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  -0.002785515272989869 0 0 0 0.640668511390686 1 0.658823549747467 0.1373885571956635 0.7409470677375793 1 0.8941176533699036 0.2949162721633911 0.9693593382835388 0.9098039269447327 0.8627451062202454 0.5208055377006531 0.05013927444815636 0.7803921699523926 1 0.6753613352775574 0.1448467969894409 0.9176470637321472 0.9333333373069763 0.8418055176734924 -0.002785515272989869 0 1 0.9900000095367432 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  -1 1\n</DataBounds>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -1 1\n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/BlackWhite.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  0 0 0 0 0 0 1 0.9900000095367432 \n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/Kindlmann.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  -0.002785515272989869 0 0 0 0.7660167217254639 0.9490196108818054 0.2980392277240753 0.09803897142410278 0.7353760600090027 0.9529411792755127 0.5686274766921997 0.199999988079071 0.6044568419456482 0.9529411792755127 0.6470588445663452 0.3038330078125 0.5013927817344666 0.9529411792755127 0.4156862795352936 0.4078609943389893 0.412256270647049 0.9490196108818054 0.5372549295425415 0.5019609928131104 0.3481894135475159 0.9529411792755127 0.658823549747467 0.6000000238418579 0.2646239697933197 0.95686274766922 0.7607843279838562 0.6961669921875 0.1727019548416138 0.9529411792755127 0.8078431487083435 0.800000011920929 0.06963787972927094 0.2156862765550613 0.9882352948188782 0.901249885559082 -0.002785515272989869 0 1 0.9900000095367432 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/KindlmannExtended.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  -0.002785515272989869 0 0 0 0.7325905561447144 0.9529411792755127 0.4039215743541718 0.1218169927597046 0.5013927817344666 0.95686274766922 0.2627451121807098 0.250980019569397 0.3454039096832275 0.9529411792755127 0.4039215743541718 0.3803920149803162 0.1754874587059021 0.9529411792755127 0.4862745106220245 0.5019609928131104 0.02785515412688255 0.6980392336845398 0.9647058844566345 0.6196080446243286 0.8495821952819824 0.4039215743541718 0.9803921580314636 0.749472975730896 0.7493036389350891 0.1607843190431595 0.9921568632125854 0.8841270208358765 -0.002785515272989869 0 1 0.9900000095367432 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/Rainbow.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1\n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  0.835654616355896 1 1 0 0.6685236692428589 1 1 0.3312032520771027 0.3342618346214294 1 1 0.6659361124038696 0 1 1 0.9900000095367432 \n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<DataBounds Type=\"Double\">\n -1 1\n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/algae.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.30431393807842216 0.1660980033034706 0.9769128443086749 0.0 0.30005392008677356 0.2989152547067349 0.8338063126244977 0.16666666666666666 0.3309718871642622 0.4515992141435242 0.7070616628058336 0.3333333333333333 0.4130561078076512 0.8801649528576773 0.5796325615836696 0.5 0.42542750956654046 0.8403187904684511 0.4316407590421983 0.6666666666666666 0.410290285400631 0.64157633829156 0.28324566551643965 0.8333333333333333 0.3564950013178268 0.515400832815782 0.14208946011590498 1.0\n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/amp.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.02635813386433533 0.021761412834227965 0.9463470914425774 0.0 0.04010142603941556 0.20791215214883926 0.8735014600514631 0.16666666666666666 0.04242515583198917 0.4478198859077958 0.8153328745786678 0.3333333333333333 0.03676973779567544 0.6927978622162377 0.7514064033944252 0.5 0.9973316222226559 0.792673038422649 0.6513700233144809 0.6666666666666666 0.9584512517521356 0.8750622180279034 0.4499550509587918 0.8333333333333333 0.971657574461405 0.8504701197267419 0.23605636466461405 1.0\n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/deep.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.16798488162105954 0.19533632833453615 0.9943734553013935 0.0 0.33735559873470516 0.25865604304601525 0.8740670650055499 0.16666666666666666 0.4611472243939132 0.4995300219326743 0.7276949011320993 0.3333333333333333 0.5307921490613369 0.5432212914796786 0.6185294158631611 0.5 0.5935831949277645 0.584827649057945 0.5830452587571144 0.6666666666666666 0.6867084184579647 0.4725176065265601 0.42500331672496205 0.8333333333333333 0.7938268228367832 0.40593260696161215 0.1727215696232308 1.0\n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/dense.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.4985029056155954 0.044459364441300706 0.9441797977915001 0.0 0.5538618981465113 0.28459785042143 0.8875413292226666 0.16666666666666666 0.5981049031515369 0.4825601716434142 0.8962023935259622 0.3333333333333333 0.6774379035261949 0.46932251013476056 0.8354485830591045 0.5 0.7548424727275783 0.596020164491061 0.6452378997676681 0.6666666666666666 0.8332113916290097 0.7006204506630465 0.38330035466997037 0.8333333333333333 0.908421307425615 0.7375779324974272 0.21298394220008482 1.0\n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/haline.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n6 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.7011534992182886 0.774675775404715 0.4225729247643044 0 0.6088781425912405 0.8740527287776149 0.6109238301118911 0.1666666666666667 0.5448574374231362 0.7694018538276051 0.5438113725374379 0.3333333333333334 0.4768648232665631 0.5931034349030235 0.577131576635999 0.5 0.3865097026016158 0.5168905297066437 0.7265676248366645 0.6666666666666667 0.2282869252736467 0.5736335355767576 0.8470513147981416 0.8333333333333334 0.1422451679013383 0.3937413041608905 0.9940805805099583 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/ice.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n7 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.6457410650120362 0.7894687174364072 0.07272873735907764 0 0.6734507537530291 0.5074184930577886 0.316351221127571 0.1666666666666667 0.6422358037081647 0.5824508021175889 0.5885298594478888 0.3333333333333334 0.5862361315939045 0.6384738978095406 0.7194288695343958 0.5 0.5518749196791298 0.5112952008114653 0.7819829669338884 0.6666666666666667 0.5181582182863426 0.2844717529303322 0.8566135671784518 0.8333333333333334 0.5022720327010908 0.07531334884986909 0.9928328638314804 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/matter.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n6 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.1315047750870439 0.3049367995017602 0.9942936149611202 0 0.07435862552520107 0.4982105379942617 0.9694484453171449 0.1666666666666667 0.0365168642500231 0.6239726620240689 0.9204453195710341 0.3333333333333333 0.9770167116808333 0.6738182081962212 0.8085246874446361 0.5 0.9151686322101068 0.7743545622095169 0.6229363449371849 0.6666666666666666 0.8546586694913163 0.7611032331430697 0.4003852641200215 0.8333333333333333 0.7808880998021044 0.7566950434006665 0.2430426744218359 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/phase.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n6 \n</ColorInterpolationType>\n<UseWhitespace Type=\"Long\">\n0 \n</UseWhitespace>\n<ColorMapControlPoints Type=\"Double\">\n0.1151063084707132 0.9249396140571944 0.6583083928922511 0 0.9827516762211339 0.6616042724377271 0.8425387334318171 0.1666666666666667 0.8327756885548686 0.7732839976462316 0.8173214043862718 0.3333333333333334 0.6809881354681986 0.5224959435452883 0.9417848067474301 0.5 0.5246391807803946 0.8208898372298726 0.6577323260140637 0.6666666666666667 0.3567894711420296 0.6566328658214546 0.6009446614046378 0.8333333333333334 0.1151063084706448 0.9249396140554326 0.6583083928921536 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/rain.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n6 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.6951979254202271 0.02295059012081452 0.9527121598234155 0 0.09453797769959756 0.2114576666915019 0.833684474704683 0.1666666666666667 0.2536636757508912 0.2498954596283127 0.6552266499575032 0.3333333333333333 0.4332665894273724 0.5735234776522391 0.5574166090031631 0.5 0.5020626150570218 0.9676627588506598 0.4264935743343106 0.6666666666666666 0.5674344311981884 0.6147742237450133 0.3483613905337878 0.8333333333333333 0.7058246076905745 0.5301018061190311 0.2213363669373893 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/solar.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n5 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.9783639431921791 0.6161958731217829 0.201425099783396 0 0.9967939632653428 0.6597135862458171 0.4068349561616131 0.1666666666666667 0.04240662863510477 0.8151825886459937 0.5923480147332496 0.3333333333333334 0.08309895316788585 0.894945393952475 0.7141299649529337 0.5 0.1129395338615871 0.8741471283229515 0.7979274645055595 0.6666666666666667 0.1465135077437694 0.7828284227016814 0.8556846647048814 0.8333333333333334 0.193672596476034 0.7045765444566169 0.9939881188401473 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/speed.tf3",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"?>\n<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 1 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMapParams>\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<ColorInterpolationType Type=\"Long\">\n  0 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.1596307072865247 0.1955973620128987 0.9996253193176977 0.0 0.1373421430079236 0.48977236844084415 0.8818245887426445 0.16666666666666666 0.16865647082418778 0.8113800283790015 0.6743006234739316 0.3333333333333333 0.22966149294080326 0.9165428294945905 0.5713169711328536 0.5 0.3621715121548401 0.7882711545792705 0.4491042457325262 0.6666666666666666 0.4004708869579201 0.7322728624001044 0.29398786489640066 0.8333333333333333 0.288402825198751 0.46659125508866167 0.13733860758438335 1.0\n</ColorMapControlPoints>\n</ColorMapParams>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>Type=\"ParamsBase\" >\n<DataBounds Type=\"Double\">\n -1 1 \n</DataBounds>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/tempo.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n6 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.0225033366813406 0.04084497581785965 0.9985763296811462 0 0.2657248163043771 0.1122146822936219 0.8209970689783633 0.1666666666666667 0.3906836969353442 0.2983860344980878 0.7009183842407573 0.3333333333333333 0.4679695435964035 0.7121223502366618 0.5784169089899582 0.5 0.5098142117208065 0.8180924994963084 0.4492060096666722 0.6666666666666666 0.5584755476416275 0.693740141825086 0.3584370856671011 0.8333333333333333 0.6368377882653272 0.6893555377202758 0.2647901677800857 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/thermal.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n6 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.5568814119463522 0.9229178682838526 0.2018108864558305 0 0.6549755477788276 0.7063194674835263 0.5859183845130114 0.1666666666666667 0.7634505310371908 0.5010011918119459 0.5741764823913097 0.3333333333333334 0.9294383782438684 0.4603631099484105 0.6922877457570544 0.5 0.0372788517634953 0.6264281833061038 0.9199740625655836 0.6666666666666667 0.1043208552539475 0.7578562555330935 0.9855936903889445 0.8333333333333334 0.1861128251649463 0.6380337773337329 0.9821574063216706 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/palettes/Sequential/turbid.tf3",
    "content": "<MapperFunctionParams>\n<OpacityComposition Type=\"Long\">\n0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n0 \n</Type>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n<Freq Type=\"Double\">\n5 \n</Freq>\n<Mean Type=\"Double\">\n0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n1 0 1 0.3333333333333333 1 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n0 \n</RelMinValue>\n<SSq Type=\"Double\">\n0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n6 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n0.195866594439376 0.3024741580025216 0.9639053479101408 0 0.1435051206852861 0.4672478059499121 0.8292275089883606 0.1666666666666667 0.1113678407626282 0.6280264035922246 0.7496385821697368 0.3333333333333333 0.08644661232811861 0.6327132693687203 0.6315116605695774 0.5 0.06795198707528698 0.5377144793877353 0.4748206472212549 0.6666666666666666 0.06210044096611798 0.4098310229471856 0.3000685503066236 0.8333333333333333 0.08104897376521929 0.2074708678666135 0.1339921324751869 1 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n-939.5371704101562 1877.108642578125 \n</DataBounds>\n</ColorMapParams>\n</MapperFunctionParams>\n"
  },
  {
    "path": "share/python/imagewriter.py",
    "content": "# outfile   : string\n# width     : image width\n# height    : image height\n# rgbbuffer : buffer of R, G, B values\n\ndef drawpng( outfile, width, height, rgbbuffer ):\n    import matplotlib\n    matplotlib.use('AGG')\n    import matplotlib.image as mpimg\n    import numpy as np\n\n    buf = np.array( rgbbuffer, dtype=np.uint8 )\n    buf = buf.reshape( height, width, 3 )\n    mpimg.imsave( outfile, buf, format='png' )\n\n    return 0\n\n\ndef main():\n    width =64 \n    height = 128\n    buf = []\n    for y in range( height ):\n        for x in range( width ):\n            buf.append(x)\n            buf.append(y)\n            buf.append(0)\n\n    drawpng( \"rgb.png\", width, height, buf )\n\n\nif __name__ == \"__main__\":\n    main()\n\n"
  },
  {
    "path": "share/python/plot.py",
    "content": "# outFile   : string\n# varNames  : list of strings\n# sequences : list of list of floats. Has the Y values of the plot\n# xValues   : list of floats.         Has the X values of the plot\n# xLabel    : a single string.        Has the X label.\n# yLabel    : a single string.        Has the Y label.\ndef plotSequences( outFile, varNames, sequences, xValues, xLabel, yLabel ):\n    import matplotlib\n    matplotlib.use('AGG')\n    import matplotlib.pyplot as plt\n\n    fig, ax = plt.subplots(figsize=(8, 6))\n    if len(varNames) > 0:\n        for i in range(len(varNames)):\n            ax.plot( xValues, sequences[i], '-x', label=varNames[i] )\n        ax.legend(loc='best')\n\n    ax.set(xlabel=xLabel, ylabel=yLabel, title=\"Vapor Plot Utility\")\n    #ax.set_xticks( xValues ) # give it fixed xticks\n\n    fig.savefig( outFile )\n    plt.close( fig )\n\n    return 0\n"
  },
  {
    "path": "share/python/plot1D.py",
    "content": "\n\n# Pass in the X dimension list as well, or just leave it blank\ndef plot1D( D, imagePath, X=None ):\n\n  import numpy as np\n  import matplotlib\n  matplotlib.use('AGG')\n\t\n  import matplotlib.pyplot as plt\n\n \n  #\n  # Setup Plot\n  #\n  # N.B. This method needs to be defined inside of plot1D. Otherwise the\n  # invocation from the python interpreter in vaporgui will fail. \n  #\n  # font sizes: xx-small, x-small, # small, medium, large, x-large, xx-large\n  # linestyles: '-', '--', '-.', ':', 'None', ' ', ''\n  # colors: 'blue', 'gree', 'red', 'cyan', 'magenta', 'yellow', 'black', 'white'\n  # legend locations: 'best', 'upper right', 'upper left', \n  # 'lower left', 'right', 'center left', 'center right', \n  # 'lower center', 'upper center', 'center'\n  #\n  def setupPlot( title, leftLimit, rightLimit ):\n    fig = plt.figure( figsize=(10,6), dpi=100, frameon=True )\n    plt.title( title, color='Black', fontsize='xx-large')  \n    plt.xlabel(\"X Dimension\", color='Black', fontsize='large')\n    plt.ylabel(\"Y Dimension\", color='Black', fontsize='large')\n    plt.xlim(leftLimit, rightLimit)\n    plt.grid(True)\n\n  \n  plt.ioff()\n  xRange = 0\n  if X is None:\n    for v in D.itervalues():\n      if len(v) > xRange:\n        xRange = len(v)\n    X = range(xRange)\n\n  setupPlot( 'Vapor Sample Plot Script', X[0], X[-1] )\n\n  globalYMin = None\n  globalYMax = None\n  for k, v in D.iteritems():\n    localYMin = min(v)\n    localYMax = max(v)\n    if globalYMin is None or globalYMin > localYMin:\n      globalYMin = localYMin\n    if globalYMax is None or globalYMax < localYMax:\n      globalYMax = localYMax\n    plt.plot(X, v, linewidth=1.0, linestyle='-', color=None, label=k) \n    # use log scale on Y axis:\n    # plt.semilogy(X, v, linewidth=1.0, linestyle='-', color=None, label=k) \n  #plt.axis([X[0], X[-1], globalYMin, globalYMax])\n    \n  plt.legend(loc='best', frameon=True, fontsize='large') \n\n    \n  plt.savefig(imagePath)\n  plt.gcf().clear()\n  \n#\n# Test function for invoking plot1D() from command line\n#\ndef runit():\n  import os\n  import numpy as np\n  outputfile = os.path.join(os.path.expanduser('~'), 'foo.png')\n  X = np.linspace(-np.pi, np.pi, 256,endpoint=True)\n  C,S = np.cos(X) + 2, np.sin(X) + 2\n  dic = {\"cosine\" : C, \"sine\" : S }\n  print 'Output file: ', outputfile\n  plot1D( dic, outputfile, X )\n\nif __name__ == '__main__':\n    runit()\n"
  },
  {
    "path": "share/python/pythonSystemStartup.py",
    "content": "from numpy import *\nfrom vapor_utils import *\n\n"
  },
  {
    "path": "share/python/vapor_utils.py",
    "content": "\"\"\" The vapor_utils module contains:\r\n    StaggeredToUnstaggeredGrid - resample staggered grid\r\n    DerivFinDiff - calculate derivative using 6th order finite differences\r\n    DerivVarFinDiff - calculate a derivative of one 3D \r\n    variable with respect to another variable.\r\n    CurlFinDiff - calculate curl using finite differences\r\n    DivFinDiff - calculate divergence using finite differences\r\n    GradFinDiff - calculate gradient using finite differences.\r\n    Interp3d - interpolate a 3D variable to a vertical level surface of another variable.\r\n    VectorRotate - rotate and scale vector field for lat-lon grid.    \r\n\"\"\"\r\n\r\nimport numpy as np\r\n\r\ndef _StaggeredToUnstaggeredGrid2D(a, axis):\r\n    assert isinstance(a, np.ndarray), 'A is not np.ndarray'\r\n    assert a.ndim == 2\r\n    assert axis >= 0 and axis < a.ndim\r\n\r\n    from scipy.interpolate import RectBivariateSpline\r\n\r\n    x = np.arange(a.shape[1])\r\n    y = np.arange(a.shape[0])\r\n\r\n    if (axis == 1):\r\n        xprime = np.arange(0.5, a.shape[axis] - 0.5)\r\n        yprime = y\r\n    else:\r\n        xprime = x\r\n        yprime = np.arange(0.5, a.shape[axis] - 0.5)\r\n        \r\n\r\n    interp_spline = RectBivariateSpline(y, x,a)\r\n    return interp_spline(yprime, xprime)\r\n\r\ndef StaggeredToUnstaggeredGrid(a, axis):\r\n\r\n    \"\"\"Resample a numpy array on a staggered grid to an unstaggered grid\r\n\r\n    This function is useful for resampling data sampled on an Arakawa C-grid\r\n    to an Arakawa A-grid. E.g. resampling the velocity grid to the mass\r\n    grid. It simply down samples the specified axis specified by `axis`\r\n    by one grid point, locating the new grid points in the returned\r\n    array at the midpoints of the samples in the original array, `a`\r\n\r\n    Parameters\r\n    -----------\r\n    a : numpy.ndarray\r\n        A two or three dimensional Numpy array\r\n\r\n    axis : int \r\n\r\n        An integer in the range 0..n, where n is a.ndim - 1, \r\n        specifying which axis should be downsampled. Zero is the slowest\r\n        varying dimension.\r\n\r\n    Returns\r\n    -------\r\n    aprime: numpy.ndarray:\r\n        The resampled array\r\n\r\n    \"\"\"\r\n\r\n \r\n    assert isinstance(a, np.ndarray), 'A is not np.ndarray'\r\n    assert a.ndim >= 2 and a.ndim <= 3\r\n    assert axis >= 0 and axis < a.ndim\r\n\r\n    if (a.ndim == 2):\r\n        return _StaggeredToUnstaggeredGrid2D(a,axis)\r\n\r\n    newshape = list(a.shape)\r\n    newshape[axis] -= 1;\r\n    aprime = np.empty(newshape, a.dtype)\r\n\r\n    if (axis == 1 or axis == 2):\r\n        for k in range(0,aprime.shape[0]):\r\n            aprime[k,::,::] =  _StaggeredToUnstaggeredGrid2D(a[k,::,::],axis-1)\r\n\r\n    else:\r\n        for i in range(0,aprime.shape[2]):\r\n            aprime[::,::,i] =  _StaggeredToUnstaggeredGrid2D(a[::,::,i],axis)\r\n\r\n    return(aprime)\r\n\r\ndef Mag(*argv):\r\n\r\n    \"\"\"Return the magnitude of one or more vectors\r\n\r\n    This method computes the vector magnitude of the Numpy arrays in\r\n    *args*.  Each array in *args* must have the same number of dimensions.\r\n    The arrays may be a mixture of staggered and unstaggered arrays. I.e.\r\n    for any axis the dimension length may differ by no more than one.\r\n    Staggered arrays are downsampled along the staggered axis to have the\r\n    same dimension length as the unstaggered array. Thus all arrays are\r\n    resampled as necessary to have the same shape prior to computing\r\n    the array magnitude.\r\n\r\n    Parameters\r\n    ----------\r\n    *argv : tuple of numpy.ndarray\r\n        A a list of two or three-dimensional Numpy arrays\r\n\r\n    Returns\r\n    -------\r\n    a : numpy.ndarray\r\n        The vector magnitude\r\n\r\n    \"\"\"\r\n\r\n    for arg in argv:\r\n        assert isinstance(arg, np.ndarray), 'A is not np.ndarray'\r\n\r\n    ndim = argv[0].ndim\r\n    for i in range(0,len(argv)-1):\r\n        assert ndim == argv[i].ndim, 'Arrays must all have same rank'\r\n\r\n    shapes = np.empty(ndim*len(argv), dtype=int).reshape(len(argv), ndim)\r\n    for i in range(0,len(argv)):\r\n        shapes[i,::] = argv[i].shape\r\n    \r\n    baseshape = np.empty(ndim, dtype=int)\r\n    for i in range(0,ndim):\r\n        baseshape[i] = np.amin(shapes[::,i])\r\n\r\n    for i in range(0,len(argv)):\r\n        if (np.sum(np.array(argv[i].shape)-baseshape) > 1):\r\n            raise ValueError(\"array dimensions may only differ by one\")\r\n\r\n    magsqr = np.zeros(np.prod(baseshape), argv[0].dtype).reshape(baseshape)\r\n\r\n    for i in range(0,len(argv)):\r\n        myshape = np.array(argv[i].shape)\r\n\r\n        if np.array_equal(myshape,baseshape):\r\n            magsqr += argv[i] * argv[i]\r\n        else:\r\n            axis = -1\r\n            for j in range(0,myshape.size):\r\n                if (myshape[j] == baseshape[j] + 1):\r\n                    axis = j\r\n\r\n            tmp = StaggeredToUnstaggeredGrid(argv[i], axis)\r\n            magsqr += tmp * tmp\r\n\r\n\r\n    return(np.sqrt(magsqr))\r\n\r\ndef _deriv_findiff2(a,axis,dx):\r\n    \"\"\"Function that calculates first-order derivatives \r\n    using 2nd order finite differences in regular Cartesian grids.\r\n    \"\"\"\r\n\r\n    s = np.shape(a)    #size of the input array\r\n    aprime = np.array(a)    #output has the same size than input\r\n\r\n    #\r\n    # derivative for user axis=2. In python this is the slowest \r\n    # varying \r\n    #\r\n    if axis == 2: \r\n\r\n        #forward differences near the first boundary\r\n        for i in range(1):\r\n            aprime[:,:,i] = (-a[:,:,i]+a[:,:,i+1]) / (dx)     \r\n\r\n        #centered differences\r\n        for i in range(1,s[2]-1):\r\n            aprime[:,:,i] = (-a[:,:,i-1]+a[:,:,i+1])/(2*dx) \r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[2]-1,s[2]):\r\n            aprime[:,:,i] = (a[:,:,i-1]-a[:,:,i]) /(dx)     \r\n\r\n    #\r\n    # derivative for axis=1\r\n    #\r\n    if axis == 1: \r\n        #forward differences near the first boundary\r\n        for i in range(1):\r\n            aprime[:,i,:] = (-a[:,i,:]+a[:,i+1,:]) / (dx)     \r\n\r\n        #centered differences\r\n        for i in range(1,s[1]-1):\r\n            aprime[:,i,:] = (-a[:,i-1,:]+a[:,i+1,:])/(2*dx) \r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[1]-1,s[1]):\r\n            aprime[:,i,:] = (a[:,i-1,:]-a[:,i,:]) /(dx)     \r\n\r\n    #\r\n    # derivative for user axis=0\r\n    #\r\n    if axis == 0:\r\n        #forward differences near the first boundary\r\n        for i in range(1):\r\n            aprime[i,:,:] = (-a[i,:,:]+a[i+1,:,:]) / (dx)     \r\n\r\n        #centered differences\r\n        for i in range(1,s[0]-1):\r\n            aprime[i,:,:] = (-a[i-1,:,:]+a[i+1,:,:])/(2*dx) \r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[0]-1,s[0]):\r\n            aprime[i,:,:] = (a[i-1,:,:]-a[i,:,:]) /(dx)     \r\n\r\n    return aprime\r\n\r\ndef _deriv_findiff4(a,axis,dx):\r\n    \"\"\"Function that calculates first-order derivatives \r\n    using 4th order finite differences in regular Cartesian grids.\r\n    \"\"\"\r\n\r\n    s = np.shape(a)    #size of the input array\r\n    aprime = np.array(a)    #output has the same size than input\r\n\r\n    if axis == 2: \r\n\r\n        #forward differences near the first boundary\r\n        for i in range(2):\r\n            aprime[:,:,i] = (-3*a[:,:,i]+4*a[:,:,i+1]-a[:,:,i+2]) / (2*dx)     \r\n\r\n        #centered differences\r\n        for i in range(2,s[2]-2):\r\n            aprime[:,:,i] = (a[:,:,i-2]-8*a[:,:,i-1]+8*a[:,:,i+1]-a[:,:,i+2])/(12*dx) \r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[2]-2,s[2]):\r\n            aprime[:,:,i] = (a[:,:,i-2]-4*a[:,:,i-1]+3*a[:,:,i]) /(2*dx)     \r\n\r\n    #\r\n    # derivative for axis=2\r\n    #\r\n    if axis == 1: \r\n        #forward differences near the first boundary\r\n        for i in range(2):\r\n            aprime[:,i,:] = (-3*a[:,i,:]+4*a[:,i+1,:]-a[:,i+2,:]) / (2*dx)     \r\n\r\n        #centered differences\r\n        for i in range(2,s[1]-2):\r\n            aprime[:,i,:] = (a[:,i-2,:]-8*a[:,i-1,:]+8*a[:,i+1,:]-a[:,i+2,:])/(12*dx) \r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[1]-2,s[1]):\r\n            aprime[:,i,:] = (a[:,i-2,:]-4*a[:,i-1,:]+3*a[:,i,:]) /(2*dx)     \r\n\r\n    #\r\n    # derivative for user axis=3\r\n    #\r\n    if axis == 0:\r\n        #forward differences near the first boundary\r\n        for i in range(2):\r\n            aprime[i,:,:] = (-3*a[i,:,:]+4*a[i+1,:,:]-a[i+2,:,:]) / (2*dx)     \r\n\r\n        #centered differences\r\n        for i in range(2,s[0]-2):\r\n            aprime[i,:,:] = (a[i-2,:,:]-8*a[i-1,:,:]+8*a[i+1,:,:]-a[i+2,:,:])/(12*dx) \r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[0]-2,s[0]):\r\n            aprime[i,:,:] = (a[i-2,:,:]-4*a[i-1,:,:]+3*a[i,:,:]) /(2*dx)     \r\n\r\n\r\n    return aprime\r\n\r\ndef DerivFinDiff(a,axis,dx,order=6):\r\n\r\n    \"\"\" Function that calculates first-order derivatives on Cartesian grids.\r\n\r\n    This function computes the partial derivative of a multidimensional\r\n    array using 2nd, 4th, or 6th order finite differences.\r\n\r\n    Parameters\r\n    ----------\r\n\r\n    a : numpy.ndarray\r\n        A two or three-dimensional Numpy array\r\n\r\n    axis : int\r\n        The axis along which the derivative should be taken. The slowest\r\n        varying axis is 0. The next slowest is 1.\r\n\r\n    dx : float\r\n        The differential step size\r\n\r\n    order : int, optional\r\n        The accuracy order of finite difference method. The default is 6. Valid \r\n        values are 2, 4, 6.\r\n\r\n    Calling sequence\r\n    ----------------\r\n\r\n    >>> deriv = DerivFinDiff(a,axis,delta, order=6)\r\n\r\n    Returns\r\n    -------\r\n\r\n    da_dx : numpy.ndarray\r\n        The derivative of `a` with respect to `dx` along `axis` \r\n\r\n    \"\"\"\r\n\r\n    if order == 4:\r\n        return _deriv_findiff4(a,axis,dx)\r\n\r\n    if order == 2:\r\n        return _deriv_findiff2(a,axis,dx)\r\n\r\n    s = np.shape(a)    #size of the input array\r\n    aprime = np.array(a)    #output has the same size than input\r\n\r\n    #\r\n    # derivative for user axis=2, in python this is third coordinate\r\n    #\r\n    if axis == 2: \r\n        if (s[2] < 2):\r\n            return np.zeros_like(a)\r\n        if (s[2] < 4):\r\n            return _deriv_findiff2(a,axis,dx)\r\n        if (s[2] < 6):\r\n            return _deriv_findiff4(a,axis,dx)\r\n\r\n        #forward differences near the first boundary\r\n        for i in range(3):\r\n            aprime[:,:,i] = (-11*a[:,:,i]+18*a[:,:,i+1]-9*a[:,:,i+2]+2*a[:,:,i+3]) / (6*dx)     \r\n\r\n        #centered differences\r\n        for i in range(3,s[2]-3):\r\n            aprime[:,:,i] = (-a[:,:,i-3]+9*a[:,:,i-2]-45*a[:,:,i-1]+45*a[:,:,i+1] -9*a[:,:,i+2]+a[:,:,i+3])/(60*dx) \r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[2]-3,s[2]):\r\n            aprime[:,:,i] = (-2*a[:,:,i-3]+9*a[:,:,i-2]-18*a[:,:,i-1]+11*a[:,:,i]) /(6*dx)     \r\n\r\n    #\r\n    # derivative for axis=1\r\n    #\r\n    if axis == 1: \r\n        if (s[1] < 2):\r\n            return np.zeros_like(a)\r\n        if (s[1] < 4):\r\n            return _deriv_findiff2(a,axis,dx)\r\n        if (s[1] < 6):\r\n            return _deriv_findiff4(a,axis,dx)\r\n\r\n        for i in range(3):\r\n            aprime[:,i,:] = (-11*a[:,i,:]+18*a[:,i+1,:]-9*a[:,i+2,:]+2*a[:,i+3,:]) /(6*dx)     #forward differences near the first boundary\r\n\r\n        for i in range(3,s[1]-3):\r\n            aprime[:,i,:] = (-a[:,i-3,:]+9*a[:,i-2,:]-45*a[:,i-1,:]+45*a[:,i+1,:] -9*a[:,i+2,:]+a[:,i+3,:])/(60*dx) #centered differences\r\n\r\n        for i in range(s[1]-3,s[1]):\r\n            aprime[:,i,:] = (-2*a[:,i-3,:]+9*a[:,i-2,:]-18*a[:,i-1,:]+11*a[:,i,:]) /(6*dx)     #backward differences near the second boundary\r\n\r\n    #\r\n    # derivative for user axis=0\r\n    #\r\n    if axis == 0:\r\n        if (s[0] < 2):\r\n            return np.zeros_like(a)\r\n        if (s[0] < 4):\r\n            return _deriv_findiff2(a,axis,dx)\r\n        if (s[0] < 6):\r\n            return _deriv_findiff4(a,axis,dx)\r\n\r\n        for i in range(3):\r\n            aprime[i,:,:] = (-11*a[i,:,:]+18*a[i+1,:,:]-9*a[i+2,:,:]+2*a[i+3,:,:]) /(6*dx)     #forward differences near the first boundary\r\n\r\n        for i in range(3,s[0]-3):\r\n            aprime[i,:,:] = (-a[i-3,:,:]+9*a[i-2,:,:]-45*a[i-1,:,:]+45*a[i+1,:,:] -9*a[i+2,:,:]+a[i+3,:,:])/(60*dx) #centered differences\r\n\r\n        for i in range(s[0]-3,s[0]):\r\n            aprime[i,:,:] = (-2*a[i-3,:,:]+9*a[i-2,:,:]-18*a[i-1,:,:]+11*a[i,:,:]) /(6*dx)     #backward differences near the second boundary\r\n\r\n    return aprime\r\n\r\ndef _deriv_var_findiff2(a,var,axis):\r\n\r\n    s = np.shape(a)    #size of the input array\r\n    aprime = np.array(a)    #output has the same size than input\r\n\r\n    if axis == 2: \r\n\r\n        #forward differences near the first boundary\r\n        for i in range(1):\r\n            aprime[:,:,i] = (-a[:,:,i]+a[:,:,i+1]) / (-var[:,:,i]+var[:,:,i+1]) \r\n\r\n        #centered differences\r\n        for i in range(1,s[2]-1):\r\n            aprime[:,:,i] = (-a[:,:,i-1]+a[:,:,i+1])/(-var[:,:,i-1]+var[:,:,i+1])\r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[2]-1,s[2]):\r\n            aprime[:,:,i] = (a[:,:,i-1]-a[:,:,i]) / (var[:,:,i-1]-var[:,:,i])\r\n\r\n    if axis == 1:\r\n        #forward differences near the first boundary\r\n        for i in range(1):\r\n            aprime[:,i,:] = (-a[:,i,:]+a[:,i+1,:]) / (-var[:,i,:]+var[:,i+1,:]) \r\n\r\n        #centered differences\r\n        for i in range(1,s[1]-1):\r\n            aprime[:,i,:] = (-a[:,i-1,:]+a[:,i+1,:])/(-var[:,i-1,:]+var[:,i+1,:])\r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[1]-1,s[1]):\r\n            aprime[:,i,:] = (a[:,i-1,:]-a[:,i,:]) / (var[:,i-1,:]-var[:,i,:])\r\n\r\n    #\r\n    #\r\n    if axis == 0:\r\n        #forward differences near the first boundary\r\n        for i in range(1):\r\n            aprime[i,:,:] = (-a[i,:,:]+a[i+1,:,:]) / (-var[i,:,:]+var[i+1,:,:])\r\n\r\n        #centered differences\r\n        for i in range(1,s[0]-1):\r\n            aprime[i,:,:] = (-a[i-1,:,:]+a[i+1,:,:])/ (-var[i-1,:,:]+var[i+1,:,:])\r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[0]-1,s[0]):\r\n            aprime[i,:,:] = (a[i-1,:,:]-a[i,:,:]) / (var[i-1,:,:]-var[i,:,:])\r\n\r\n    return aprime\r\n\r\n\r\n\r\ndef _deriv_var_findiff4(a,var,axis):\r\n\r\n    s = np.shape(a)    #size of the input array\r\n    aprime = np.array(a)    #output has the same size than input\r\n\r\n    #\r\n    # derivative for user axis=2\r\n    #\r\n    if axis == 2: \r\n\r\n        #forward differences near the first boundary\r\n        for i in range(2):\r\n            aprime[:,:,i] = (-3*a[:,:,i]+4*a[:,:,i+1]-a[:,:,i+2]) / (-3*var[:,:,i]+4*var[:,:,i+1]-var[:,:,i+2]) \r\n\r\n        #centered differences\r\n        for i in range(2,s[2]-2):\r\n            aprime[:,:,i] = (a[:,:,i-2]-8*a[:,:,i-1]+8*a[:,:,i+1]-a[:,:,i+2])/(var[:,:,i-2]-8*var[:,:,i-1]+8*var[:,:,i+1]-var[:,:,i+2])\r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[2]-2,s[2]):\r\n            aprime[:,:,i] = (a[:,:,i-2]-4*a[:,:,i-1]+3*a[:,:,i]) / (var[:,:,i-2]-4*var[:,:,i-1]+3*var[:,:,i])\r\n\r\n    #\r\n    #\r\n    if axis == 1: \r\n        #forward differences near the first boundary\r\n        for i in range(2):\r\n            aprime[:,i,:] = (-3*a[:,i,:]+4*a[:,i+1,:]-a[:,i+2,:]) / (-3*var[:,i,:]+4*var[:,i+1,:]-var[:,i+2,:])\r\n\r\n        #centered differences\r\n        for i in range(2,s[1]-2):\r\n            aprime[:,i,:] = (a[:,i-2,:]-8*a[:,i-1,:]+8*a[:,i+1,:]-a[:,i+2,:])/ (var[:,i-2,:]-8*var[:,i-1,:]+8*var[:,i+1,:]-var[:,i+2,:])\r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[1]-2,s[1]):\r\n            aprime[:,i,:] = (a[:,i-2,:]-4*a[:,i-1,:]+3*a[:,i,:]) / (var[:,i-2,:]-4*var[:,i-1,:]+3*var[:,i,:])\r\n\r\n    #\r\n    #\r\n    if axis == 0:\r\n        #forward differences near the first boundary\r\n        for i in range(2):\r\n            aprime[i,:,:] = (-3*a[i,:,:]+4*a[i+1,:,:]-a[i+2,:,:]) / (-3*var[i,:,:]+4*var[i+1,:,:]-var[i+2,:,:])\r\n\r\n        #centered differences\r\n        for i in range(2,s[0]-2):\r\n            aprime[i,:,:] = (a[i-2,:,:]-8*a[i-1,:,:]+8*a[i+1,:,:]-a[i+2,:,:])/ (var[i-2,:,:]-8*var[i-1,:,:]+8*var[i+1,:,:]-var[i+2,:,:])\r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[0]-2,s[0]):\r\n            aprime[i,:,:] = (a[i-2,:,:]-4*a[i-1,:,:]+3*a[i,:,:]) / (var[i-2,:,:]-4*var[i-1,:,:]+3*var[i,:,:])\r\n\r\n\r\n    return aprime\r\n\r\ndef DerivVarFinDiff(a,var,axis,order=6):\r\n\r\n    \"\"\" Function that calculates first-order derivatives on Cartesian grids\r\n    with respect to another variable\r\n\r\n    This function computes the partial derivative of a multidimensional\r\n    array using 2nd, 4th, or 6th order finite differences with respect\r\n    to a second multidimensional array of the same shape.\r\n\r\n    Parameters\r\n    ----------\r\n\r\n    a : numpy.ndarray\r\n        A two or three-dimensional Numpy array\r\n\r\n    var : numpy.ndarray\r\n        A two or three-dimensional Numpy array of the same shape as\r\n        `a`\r\n\r\n    axis : int\r\n        The axis along which the derivative should be taken. The slowest\r\n        varying axis is 0. The next slowest is 1.\r\n\r\n    order : int, optional\r\n        The accuracy order of finite difference method. The default is 6. Valid \r\n        values are 2, 4, 6.\r\n\r\n    Calling sequence\r\n    ----------------\r\n\r\n    >>> deriv = DerivFinDiff(a,var,delta, order=6)\r\n\r\n    Returns\r\n    -------\r\n\r\n    da_var : numpy.ndarray\r\n        The derivative of `a` with respect to `var` along `axis` \r\n\r\n    \"\"\"\r\n\r\n    if order == 4:\r\n        return deriv_var_findiff4(a,var,axis)\r\n\r\n    if order == 2:\r\n        return deriv_var_findiff2(a,var,axis)\r\n\r\n    s = np.shape(a)    #size of the input array\r\n    aprime = np.array(a)    #output has the same size than input\r\n\r\n    #\r\n    # derivative for axis=2\r\n    #\r\n    if axis == 2:\r\n        if (s[2] < 2):\r\n            return np.zeros_like(a)\r\n        if (s[2] < 4):\r\n            return deriv_var_findiff2(a,var,axis)\r\n        if (s[2] < 6):\r\n            return deriv_var_findiff4(a,var,axis)\r\n\r\n        #forward differences near the first boundary\r\n        for i in range(3):\r\n            aprime[:,:,i] = (-11*a[:,:,i]+18*a[:,:,i+1]-9*a[:,:,i+2]+2*a[:,:,i+3]) / (-11*var[:,:,i]+18*var[:,:,i+1]-9*var[:,:,i+2]+2*var[:,:,i+3])     \r\n\r\n        #centered differences\r\n        for i in range(3,s[2]-3):\r\n            aprime[:,:,i] = (-a[:,:,i-3]+9*a[:,:,i-2]-45*a[:,:,i-1]+45*a[:,:,i+1] -9*a[:,:,i+2]+a[:,:,i+3])/(-var[:,:,i-3]+9*var[:,:,i-2]-45*var[:,:,i-1]+45*var[:,:,i+1] -9*var[:,:,i+2]+var[:,:,i+3]) \r\n\r\n        #backward differences near the second boundary\r\n        for i in range(s[2]-3,s[2]):\r\n            aprime[:,:,i] = (-2*a[:,:,i-3]+9*a[:,:,i-2]-18*a[:,:,i-1]+11*a[:,:,i]) /(-2*var[:,:,i-3]+9*var[:,:,i-2]-18*var[:,:,i-1]+11*var[:,:,i])     \r\n\r\n    #\r\n    # derivative for axis=1\r\n    #\r\n    if axis == 1: \r\n        if (s[1] < 2):\r\n            return np.zeros_like(a)\r\n        if (s[1] < 4):\r\n            return deriv_var_findiff2(a,var,axis)\r\n        if (s[1] < 6):\r\n            return deriv_var_findiff4(a,var,axis)\r\n\r\n        for i in range(3):\r\n            aprime[:,i,:] = (-11*a[:,i,:]+18*a[:,i+1,:]-9*a[:,i+2,:]+2*a[:,i+3,:]) /(-11*var[:,i,:]+18*var[:,i+1,:]-9*var[:,i+2,:]+2*var[:,i+3,:])      #forward differences near the first boundary\r\n\r\n        for i in range(3,s[1]-3):\r\n            aprime[:,i,:] = (-a[:,i-3,:]+9*a[:,i-2,:]-45*a[:,i-1,:]+45*a[:,i+1,:] -9*a[:,i+2,:]+a[:,i+3,:])/(-var[:,i-3,:]+9*var[:,i-2,:]-45*var[:,i-1,:]+45*var[:,i+1,:] -9*var[:,i+2,:]+var[:,i+3,:]) #centered differences\r\n\r\n        for i in range(s[1]-3,s[1]):\r\n            aprime[:,i,:] = (-2*a[:,i-3,:]+9*a[:,i-2,:]-18*a[:,i-1,:]+11*a[:,i,:]) /(-2*var[:,i-3,:]+9*var[:,i-2,:]-18*var[:,i-1,:]+11*var[:,i,:])     #backward differences near the second boundary\r\n\r\n    #\r\n    # derivative for axis=0\r\n    #\r\n    if axis == 0:\r\n        if (s[0] < 2):\r\n            return np.zeros_like(a)\r\n        if (s[0] < 4):\r\n            return deriv_var_findiff2(a,var,axis)\r\n        if (s[0] < 6):\r\n            return deriv_var_findiff4(a,var,axis)\r\n\r\n        for i in range(3):\r\n            aprime[i,:,:] = (-11*a[i,:,:]+18*a[i+1,:,:]-9*a[i+2,:,:]+2*a[i+3,:,:]) /(-11*var[i,:,:]+18*var[i+1,:,:]-9*var[i+2,:,:]+2*var[i+3,:,:])     #forward differences near the first boundary\r\n\r\n        for i in range(3,s[0]-3):\r\n            aprime[i,:,:] = (-a[i-3,:,:]+9*a[i-2,:,:]-45*a[i-1,:,:]+45*a[i+1,:,:] -9*a[i+2,:,:]+a[i+3,:,:])/(-var[i-3,:,:]+9*var[i-2,:,:]-45*var[i-1,:,:]+45*var[i+1,:,:] -9*var[i+2,:,:]+var[i+3,:,:]) #centered differences\r\n\r\n        for i in range(s[0]-3,s[0]):\r\n            aprime[i,:,:] = (-2*a[i-3,:,:]+9*a[i-2,:,:]-18*a[i-1,:,:]+11*a[i,:,:]) /(-2*var[i-3,:,:]+9*var[i-2,:,:]-18*var[i-1,:,:]+11*var[i,:,:])     #backward differences near the second boundary\r\n\r\n    return aprime\r\n\r\ndef CurlFinDiff(M,N,P,dx,dy,dz,order=6):\r\n\r\n    \"\"\" Function that calculates the Curl of a vector field on Cartesian grids\r\n\r\n    This function computes the curl of a 3D vector field defined by\r\n    the vector component arrays `M`, `N`, and `P`\r\n    using 2nd, 4th, or 6th order finite differences. \r\n\r\n    If F is defined as \r\n\r\n        M(x,y,z)i + N(x,y,z)j + P(x,y,z)\r\n\r\n    then curl F is given by:\r\n\r\n        (dP/dy - dN/dz)i + (dM/dz - dP/dx)j + (dN/dx - dM/dy)k\r\n\r\n    Parameters\r\n    ----------\r\n\r\n    M : numpy.ndarray\r\n        A three-dimensional Numpy array giving the x component of the vector\r\n\r\n    N : numpy.ndarray\r\n        A three-dimensional Numpy array giving the y component of the vector\r\n\r\n    P : numpy.ndarray\r\n        A three-dimensional Numpy array giving the z component of the vector\r\n\r\n    dx : float \r\n        The differential step size along the fastest varying axis\r\n\r\n    dy : float \r\n        The differential step size along the second fastest varying axis\r\n\r\n    dz : float \r\n        The differential step size along the third fastest varying axis\r\n\r\n    order : int, optional\r\n        The accuracy order of finite difference method. The default is 6. Valid \r\n        values are 2, 4, 6.\r\n\r\n    Calling sequence\r\n    ----------------\r\n\r\n    >>> wx,wy,wz = CurlFinDiff(M,N,P,dx,dy,dz,order=6)\r\n\r\n    Returns\r\n    -------\r\n\r\n    wx,wy,wz : numpy.ndarray\r\n        The i,j,k components of the curl, respectively\r\n\r\n    \"\"\"\r\n    \r\n    aux1 = DerivFinDiff(P,1,dy,order)       #x component of the curl\r\n    aux2 = DerivFinDiff(N,0,dz,order)     \r\n    outx = aux1-aux2                        \r\n\r\n    aux1 = DerivFinDiff(M,0,dz,order)       #y component of the curl\r\n    aux2 = DerivFinDiff(P,2,dx,order)\r\n    outy = aux1-aux2\r\n\r\n    aux1 = DerivFinDiff(N,2,dx,order)       #z component of the curl\r\n    aux2 = DerivFinDiff(M,1,dy,order)\r\n    outz = aux1-aux2\r\n\r\n    return outx, outy, outz         #return results in user coordinate order\r\n\r\n\r\n# Calculate divergence\r\ndef DivFinDiff(M,N,P,dx,dy,dz,order=6):\r\n\r\n    \"\"\" Function that calculates the Divergence of a vector field on\r\n    Cartesian grids\r\n\r\n    This function computes the divergence of a 3D vector field defined by\r\n    the vector component arrays `M`, `N`, and `P`\r\n    using 2nd, 4th, or 6th order finite differences. \r\n\r\n    If F is defined as \r\n\r\n        M(x,y,z)i + N(x,y,z)j + P(x,y,z)\r\n\r\n    then div F is given by:\r\n\r\n        dM/dx + dN/dy + dP/dz\r\n\r\n    Parameters\r\n    ----------\r\n\r\n    M : numpy.ndarray\r\n        A three-dimensional Numpy array giving the x component of the vector\r\n\r\n    N : numpy.ndarray\r\n        A three-dimensional Numpy array giving the y component of the vector\r\n\r\n    P : numpy.ndarray\r\n        A three-dimensional Numpy array giving the z component of the vector\r\n\r\n    dx : float \r\n        The differential step size along the fastest varying axis\r\n\r\n    dy : float \r\n        The differential step size along the second fastest varying axis\r\n\r\n    dz : float \r\n        The differential step size along the third fastest varying axis\r\n\r\n    order : int, optional\r\n        The accuracy order of finite difference method. The default is 6. Valid \r\n        values are 2, 4, 6.\r\n\r\n    Calling sequence\r\n    ----------------\r\n\r\n    >>> a = DivFinDiff(M,N,P,dx,dy,dz,order=6)\r\n\r\n    Returns\r\n    -------\r\n\r\n    wx,wy,wz : numpy.ndarray\r\n        The i,j,k components of the curl, respectively\r\n\r\n    \"\"\"\r\n\r\n    return DerivFinDiff(P,0,dz,order) + \\\r\n        DerivFinDiff(N,1,dy,order) + DerivFinDiff(M,2,dx,order)\r\n\r\n\r\ndef GradFinDif(A,dx,dy,dz,order=6):\r\n    \"\"\" Function that calculates the Gradient of a scalar field on\r\n    Cartesian grids\r\n\r\n    This function computes the gradient of a scalar field `A`:\r\n\r\n        dA/dx*i + dA/dy*j + dA/dz*k\r\n\r\n    Parameters\r\n    ----------\r\n\r\n    A : numpy.ndarray\r\n        A three-dimensional Numpy array \r\n\r\n    dx : float \r\n        The differential step size along the fastest varying axis\r\n\r\n    dy : float \r\n        The differential step size along the second fastest varying axis\r\n\r\n    dz : float \r\n        The differential step size along the third fastest varying axis\r\n\r\n    order : int, optional\r\n        The accuracy order of finite difference method. The default is 6. Valid \r\n        values are 2, 4, 6.\r\n\r\n    Calling sequence\r\n    ----------------\r\n\r\n    >>> da_dx,da_dy,da_dz = GradFinDif(A,dx,dy,dz,order=6)\r\n\r\n    Returns\r\n    -------\r\n\r\n    da_dx,da_dy,da_dz: numpy.ndarray\r\n        The partial derivatives of A with respect to x,y,z, respectively\r\n\r\n    \"\"\"\r\n\r\n    aux1 = DerivFinDiff(A,2,dx,order)    #x component of the gradient \r\n    aux2 = DerivFinDiff(A,1,dy,order)\r\n    aux3 = DerivFinDiff(A,0,dz,order)\r\n    \r\n    return aux1,aux2,aux3 # return in user coordinate (x,y,z) order\r\n\r\n\r\ndef Interp3d(A,PR,val):\r\n    '''Method that vertically interpolates one 3D variable to a level determined by \r\n    another variable.  The second variable (PR) is typically pressure.  \r\n    The second variable must decrease\r\n    as a function of z (elevation).  The returned value is a 2D variable having\r\n    values interpolated to the surface defined by PR = val\r\n    Sweep array from bottom to top'''\r\n    s = np.shape(PR)    #size of the input arrays\r\n    ss = [s[1],s[2]] # shape of 2d arrays\r\n    interpVal = np.empty(ss,np.float32)\r\n    ratio = np.zeros(ss,np.float32)\r\n\r\n    #  the LEVEL value is determine the lowest level where P<=val\r\n    LEVEL = np.empty(ss,np.int32)\r\n    LEVEL[:,:] = -1 #value where PR<=val has not been found\r\n    for K in range(s[0]):\r\n        #LEVNEED is true if this is first time PR<val.\r\n        LEVNEED = np.logical_and(np.less(LEVEL,0), np.less(PR[K,:,:] , val))\r\n        LEVEL[LEVNEED]=K\r\n        ratio[LEVNEED] = (val-PR[K,LEVNEED])/(PR[K-1,LEVNEED]-PR[K,LEVNEED])\r\n        interpVal[LEVNEED] = ratio[LEVNEED]*A[K,LEVNEED]+(1-ratio[LEVNEED])*A[K-1,LEVNEED] \r\n        LEVNEED = np.greater(LEVEL,0)\r\n    # Set unspecified values to value of A at top of data:\r\n    LEVNEED = np.less(LEVEL,0)\r\n    interpVal[LEVNEED] = A[s[0]-1,LEVNEED]\r\n    return interpVal\r\n\r\ndef VectorRotate(angleRad, latDeg, u, v):\r\n    '''Rotate and scale vectors u,v for integration on\r\n    lon-lat grid.\r\n    Calling sequence: \r\n    rotfield=VectorRotate(angleRad, latDeg, u,v)\r\n    Where:  \r\n    angleRad: 2D var, rotation from East in radians\r\n    latDeg: 2D var, latitude in degrees\r\n    u,v: 3D vars, x,y components of a vector field\r\n    rotfield is a 2-tuple of 3-dimensional float32 arrays,\r\n    representing rotation of u,v, returned by this operator.\r\n    '''     \r\n    import math\r\n    umod = np.cos(angleRad)*u + np.sin(angleRad)*v\r\n    vmod = -np.sin(angleRad)*u + np.cos(angleRad)*v\r\n    umod = umod/np.cos(latDeg*math.pi/180.)\r\n    return umod,vmod\r\n\r\ndef mag3d(a1,a2,a3): \r\n    '''Calculate the magnitude of a 3-vector.\r\n    Calling sequence: MAG = mag3d(A,B,C)\r\n    Where:  A, B, and C are float32 np arrays.\r\n    Result MAG is a float32 np array containing the square root\r\n    of the sum of the squares of A, B, and C.'''\r\n\r\n    raise DeprecationWarning('Use Mag() instead')\r\n    from np import sqrt\r\n    return sqrt(a1*a1 + a2*a2 + a3*a3)\r\n\r\ndef mag2d(a1,a2): \r\n    '''Calculate the magnitude of a 2-vector.\r\n    Calling sequence: MAG = mag2d(A,B)\r\n    Where:  A, and B are float32 np arrays.\r\n    Result MAG is a float32 np array containing the square root\r\n    of the sum of the squares of A and B.'''\r\n    from np import sqrt\r\n    return sqrt(a1*a1 + a2*a2)\r\n"
  },
  {
    "path": "share/python/vapor_wrf.py",
    "content": "''' vapor_wrf module includes following WRF-based utilities:\r\n\tETH - equivalent potential temperature\r\n\tRH - relative humidity\r\n\tSHEAR - horizontal wind shear\r\n\tSLP - sea-level pressure (2D)\r\n\tTD - dewpoint temperature\r\n\tTK - temperature in degrees Kelvin.'''\r\n\t\r\nimport numpy \r\nimport vapor_utils\r\n\r\ndef ETH(P,PB,T,QVAPOR):\r\n\t''' Program to calculate equivalent potential temperature using WRF\r\n\tvariables P, PB, T, QVAPOR.\r\n\tCalling sequence:  WRF_ETH = ETH(P,PB,T,QVAPOR)\r\n\tResult WRF_ETH is a 3D variable on same grid as P,PB,T,QVAPOR.'''\r\n#Copied from NCL/Fortran source code DEQTHECALC in eqthecalc.f\r\n\tc = 2.0/7.0\r\n\tEPS = 0.622\r\n\tGAMMA = 287.04/1004.0\r\n\tGAMMAMD = 0.608 -0.887\r\n\tTLCLC1 = 2840.0\r\n\tTLCLC2 = 3.5\r\n\tTLCLC3 = 4.805\r\n\tTLCLC4 = 55.0\r\n\tTHTECON1 = 3376.0\r\n\tTHTECON2 = 2.54\r\n\tTHTECON3 = 0.81\r\n\tTH = T+300.0\r\n#calculate Temp. in Kelvin\r\n\tPRESS = 0.01*(P+PB)\r\n\tTK = TH*numpy.power(PRESS*.001,c)\r\n\tQ = numpy.maximum(QVAPOR, 1.e-15)\r\n\tE = Q*PRESS/(EPS+Q)\r\n\tTLCL = TLCLC4+ TLCLC1/(numpy.log(numpy.power(TK,TLCLC2)/E)-TLCLC3)\r\n\tEXPNT = (THTECON1/TLCL - THTECON2)*Q*(1.0+THTECON3*Q)\r\n\tWRF_ETH = TK*numpy.power(1000.0/PRESS,GAMMA*(1.0+GAMMAMD*Q))*numpy.exp(EXPNT)\r\n\treturn WRF_ETH\r\n\r\ndef RH(P,PB,T,QVAPOR):\r\n\t''' Calculation of relative humidity.\r\n\tCalling sequence WRF_RH = RH(P,PB,T,QVAPOR),\r\n\twhere P,PB,T,QVAPOR are standard WRF 3D variables,\r\n\tresult WRF_RH is 3D variable on same grid as inputs.'''\r\n#Formula is from wrf_user.f\r\n\tc = 2.0/7.0\r\n\tSVP1 = 0.6112\r\n\tSVP2 = 17.67\r\n\tSVPT0 = 273.15\r\n\tSVP3 = 29.65\r\n\tEP_3 = 0.622\r\n\tTH = T+300.0\r\n\tPRESS = P+PB\r\n\tTK = TH*numpy.power(PRESS*.00001,c)\r\n\tES = 10*SVP1*numpy.exp(SVP2*(TK-SVPT0)/(TK-SVP3))\r\n\tQVS = EP_3*ES/(0.01*PRESS - (1.-EP_3)*ES)\r\n\tWRF_RH = 100.0*numpy.maximum(numpy.minimum(QVAPOR/QVS,1.0),0)\r\n\treturn WRF_RH\r\n\r\n\r\ndef SHEAR(U,V,P,PB,level1=200.,level2=850.):\r\n\t'''Program calculates horizontal wind shear\r\n\tCalling sequence: SHR = SHEAR(U,V,P,PB,level1,level2)\r\n\twhere U and V are 3D wind velocity components, and\r\n\tresult SHR is 3D wind shear.\r\n\tShear is defined as the RMS difference between the horizontal \r\n\tvelocity interpolated to the specified pressure levels,\r\n \tlevel1 and level2 (in millibars) which default to 200 and 850.'''\r\n\tfrom numpy import sqrt\r\n\tPR = 0.01*(P+PB)\r\n\tU=vapor_utils.StaggeredToUnstaggeredGrid(U,2) \r\n\tV=vapor_utils.StaggeredToUnstaggeredGrid(V,1) \r\n\tuinterp1 = vapor_utils.interp3d(U,PR,level1)\r\n\tuinterp2 = vapor_utils.interp3d(U,PR,level2)\r\n\tvinterp1 = vapor_utils.interp3d(V,PR,level1)\r\n\tvinterp2 = vapor_utils.interp3d(V,PR,level2)\r\n\tresult = (uinterp1-uinterp2)*(uinterp1-uinterp2)+(vinterp1-vinterp2)*(vinterp1-vinterp2)\r\n\tresult = sqrt(result)\r\n\treturn result \r\n\r\ndef SLP(P,PB,T,QVAPOR,ELEVATION):\r\n\t'''Calculation of Sea-level pressure.\r\n\tCalling sequence:  WRF_SLP = SLP(P,PB,T,QVAPOR,ELEVATION)\r\n\twhere P,PB,T,QVAPOR are WRF 3D variables and ELEVATION is \r\n\tthe VAPOR variable indicating the elevation in meters above sea level.\r\n\tResult is a 2D variable with same horizonal extents as input variables.''' \r\n#Copied (and adapted) from NCL fortran source code wrf_user.f\r\n#constants:\r\n\tR=287.04\r\n\tG=9.81\r\n\tGAMMA=0.0065\r\n\tTC=273.16+17.05\r\n\tPCONST=10000\r\n\tc = 2.0/7.0\r\n#calculate TK:\r\n\tTH = T+300.0\r\n\tPR = P+PB\r\n\tTK = (T+300.0)*numpy.power(PR*.00001,c)\r\n#Find least z that is PCONST Pa above the surface\r\n#Sweep array from bottom to top\r\n\ts = numpy.shape(P)\t#size of the input array\r\n\tss = [s[1],s[2]] # shape of 2d arrays\r\n\tWRF_SLP = numpy.empty(ss,numpy.float32)\r\n\tLEVEL = numpy.empty(ss,numpy.int32)\r\n\t# Ridiculous MM5 test:\r\n\tRIDTEST = numpy.empty(ss,numpy.int32)\r\n\tPLO = numpy.empty(ss, numpy.float32)\r\n\tZLO = numpy.empty(ss,numpy.float32)\r\n\tTLO = numpy.empty(ss,numpy.float32)\r\n\tPHI = numpy.empty(ss,numpy.float32)\r\n\tZHI = numpy.empty(ss,numpy.float32)\r\n\tTHI = numpy.empty(ss,numpy.float32)\r\n\tLEVEL[:,:] = -1\r\n\tfor K in range(s[0]):\r\n\t\tKHI = numpy.minimum(K+1, s[0]-1)\r\n\t\tLEVNEED = numpy.logical_and(numpy.less(LEVEL,0), numpy.less(PR[K,:,:] , PR[0,:,:] - PCONST))\r\n\t\tLEVEL[LEVNEED]=K\r\n\t\tPLO=numpy.where(LEVNEED,PR[K,:,:],PLO[:,:])\r\n\t\tTLO=numpy.where(LEVNEED,TK[K,:,:]*(1.+0.608*QVAPOR[K,:,:]), TLO[:,:])\r\n\t\tZLO=numpy.where(LEVNEED,ELEVATION[K,:,:],ZLO[:,:])\r\n\t\tPHI=numpy.where(LEVNEED,PR[KHI,:,:],PHI[:,:])\r\n\t\tTHI=numpy.where(LEVNEED,TK[KHI,:,:]*(1.+0.608*QVAPOR[KHI,:,:]), THI[:,:])\r\n\t\tZHI=numpy.where(LEVNEED,ELEVATION[KHI,:,:],ZHI[:,:])\r\n\tP_AT_PCONST = PR[0,:,:]-PCONST\r\n\tT_AT_PCONST = THI - (THI-TLO)*numpy.log(P_AT_PCONST/PHI)*numpy.log(PLO/PHI)\r\n\tZ_AT_PCONST = ZHI - (ZHI-ZLO)*numpy.log(P_AT_PCONST/PHI)*numpy.log(PLO/PHI)\r\n\tT_SURF = T_AT_PCONST*numpy.power((PR[0,:,:]/P_AT_PCONST),(GAMMA*R/G))\r\n\tT_SEA_LEVEL = T_AT_PCONST + GAMMA*Z_AT_PCONST\r\n\tRIDTEST = numpy.logical_and(T_SURF <= TC, T_SEA_LEVEL >= TC)\r\n\tT_SEA_LEVEL = numpy.where(RIDTEST, TC, TC - .005*(T_SURF -TC)**2)\r\n\tZ_HALF_LOWEST=ELEVATION[0,:,:]\r\n\tWRF_SLP = 0.01*(PR[0,:,:]*numpy.exp(2.*G*Z_HALF_LOWEST/(R*(T_SEA_LEVEL+T_SURF))))\r\n\treturn WRF_SLP\r\n\r\ndef TD(P,PB,QVAPOR):\r\n\t''' Calculation of dewpoint temperature based on WRF variables.\r\n\tCalling sequence: WRFTD = TD(P,PB,QVAPOR)\r\n\twhere P,PB,QVAPOR are WRF 3D variables, and result WRFTD \r\n\tis a 3D variable on the same grid.'''\r\n#Let PR = 0.1*(P+PB) (pressure in hPa)\r\n#and QV = MAX(QVAPOR,0)\r\n#Where TDC = QV*PR/(0.622+QV)\r\n# TDC = MAX(TDC,0.001)\r\n#Formula is (243.5*log(TDC) - 440.8)/(19.48-log(TDC))\r\n\tQV = numpy.maximum(QVAPOR,0.0)\r\n\tTDC = 0.01*QV*(P+PB)/(0.622+QV)\r\n\tTDC = numpy.maximum(TDC,0.001)\r\n\tWRF_TD =(243.5*numpy.log(TDC) - 440.8)/(19.48 - numpy.log(TDC))\r\n\treturn WRF_TD\r\n\r\n\r\ndef TK(P,PB,T):\r\n\t''' Calculation of temperature in degrees kelvin using WRF variables.\r\n\tCalling sequence: TMP = TK(P,PB,T)\r\n\tWhere P,PB,T are WRF 3D variables, result TMP is a 3D variable\r\n\tindicating the temperature in degrees Kelvin.'''\r\n#Formula is (T+300)*((P+PB)*10**(-5))**c, \r\n#Where c is 287/(7*287*.5) = 2/7\r\n\tc = 2.0/7.0\r\n\tTH = T+300.0\r\n\tWRF_TK = TH*numpy.power((P+PB)*.00001,c)\r\n\treturn WRF_TK\r\n"
  },
  {
    "path": "share/shaders/.gitattributes",
    "content": "BBTraversalAlgorithms.frag -diff -merge\nBBTraversalAlgorithms.frag linguist-generated=true\n"
  },
  {
    "path": "share/shaders/2DData.frag",
    "content": "#version 330 core\n\nuniform sampler1D colormap;\nuniform float minLUTValue;\nuniform float maxLUTValue;\n\nuniform float constantOpacity;\n\nin vec2 vertexData;\n\nout vec4 fragColor;\n\nvoid main(void)\n{\n\tif (minLUTValue > maxLUTValue) discard;\n\n\tvec2 texel = vertexData;\n\n\t// Check for missing value\n\tif (texel.y != 0.0) discard;\n\n\tfloat s = (texel.x - minLUTValue) / (maxLUTValue - minLUTValue);\n    if (maxLUTValue == minLUTValue) s=0.;\n\tvec4 color = texture(colormap, s);\n    float alpha = color.a * constantOpacity;\n    \n\tfragColor = vec4(color.rgb, alpha);\n    \n    if (alpha < 0.001)\n        discard;\n}\n"
  },
  {
    "path": "share/shaders/2DData.vert",
    "content": "#version 330 core\n\nuniform mat4 MVP;\n\nlayout (location = 0) in vec3 vertex;\nlayout (location = 1) in vec2 vVertexData;\n\nout vec2 vertexData;\n\nuniform vec4 clippingPlanes[6];\nout float gl_ClipDistance[6];\n\nvoid main()\n{\n\tgl_Position = MVP * vec4(vertex, 1.0);\n\tvertexData = vVertexData;\n\n\tfor (int i = 0; i < 6; i++)\n\t\tgl_ClipDistance[i] = dot(vec4(vertex, 1.0), clippingPlanes[i]);\n}\n"
  },
  {
    "path": "share/shaders/BBTraversalAlgorithms.frag",
    "content": "// ---------------------------------------------\n// This file is generated by GenerateBBTraversals.pl\n// Any changes made to this file will be lost\n// ---------------------------------------------\n\n\nint SearchSideForInitialCellWithOctree_1Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\n\tint yEnd0 = lDims0.y;\n\tint xEnd0 = lDims0.x;\n\tint x1 = 0;\n\tint y1 = 0;\n\t\n\tfor (int y0 = y1*2; y0 < yEnd0; y0++) {\n\tfor (int x0 = x1*2; x0 < xEnd0; x0++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\n\t\tindex[slowDim] = y0;\n\t\tindex[fastDim] = x0;\n\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\tintersections++;\n\t\n\t\n\t}\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_2Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\n\tint yEnd1 = lDims1.y;\n\tint xEnd1 = lDims1.x;\n\tint x2 = 0;\n\tint y2 = 0;\n\t\n\tfor (int y1 = y2*2; y1 < yEnd1; y1++) {\n\tfor (int x1 = x2*2; x1 < xEnd1; x1++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\n\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\n\t\tfor (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\tfor (int x0 = x1*2; x0 < xEnd0; x0++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\n\t\t\tindex[slowDim] = y0;\n\t\t\tindex[fastDim] = x0;\n\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\tintersections++;\n\t\t\n\t\t\n\t\t}\n\t\t}\n\t\t}\n\t\n\t\n\t}\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_3Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\n\tint yEnd2 = lDims2.y;\n\tint xEnd2 = lDims2.x;\n\tint x3 = 0;\n\tint y3 = 0;\n\t\n\tfor (int y2 = y3*2; y2 < yEnd2; y2++) {\n\tfor (int x2 = x3*2; x2 < xEnd2; x2++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\n\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\n\t\tfor (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\tfor (int x1 = x2*2; x1 < xEnd1; x1++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\n\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\n\t\t\tfor (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\tfor (int x0 = x1*2; x0 < xEnd0; x0++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\n\t\t\t\tindex[slowDim] = y0;\n\t\t\t\tindex[fastDim] = x0;\n\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\tintersections++;\n\t\t\t\n\t\t\t\n\t\t\t}\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t\n\t\t}\n\t\t}\n\t\t}\n\t\n\t\n\t}\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_4Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\n\tint yEnd3 = lDims3.y;\n\tint xEnd3 = lDims3.x;\n\tint x4 = 0;\n\tint y4 = 0;\n\t\n\tfor (int y3 = y4*2; y3 < yEnd3; y3++) {\n\tfor (int x3 = x4*2; x3 < xEnd3; x3++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\n\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\n\t\tfor (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\tfor (int x2 = x3*2; x2 < xEnd2; x2++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\n\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\n\t\t\tfor (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\tfor (int x1 = x2*2; x1 < xEnd1; x1++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\n\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\n\t\t\t\tfor (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0; x0++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\n\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\tintersections++;\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t}\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t\n\t\t}\n\t\t}\n\t\t}\n\t\n\t\n\t}\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_5Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\tivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4);\n\n\tint yEnd4 = lDims4.y;\n\tint xEnd4 = lDims4.x;\n\tint x5 = 0;\n\tint y5 = 0;\n\t\n\tfor (int y4 = y5*2; y4 < yEnd4; y4++) {\n\tfor (int x4 = x5*2; x4 < xEnd4; x4++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) {\n\t\n\t\tint yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2;\n\t\tint xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2;\n\t\t\n\t\tfor (int y3 = y4*2; y3 < yEnd3; y3++) {\n\t\tfor (int x3 = x4*2; x3 < xEnd3; x3++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\t\n\t\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\t\n\t\t\tfor (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\t\tfor (int x2 = x3*2; x2 < xEnd2; x2++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\t\n\t\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\t\n\t\t\t\tfor (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\t\tfor (int x1 = x2*2; x1 < xEnd1; x1++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\t\n\t\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\t\n\t\t\t\t\tfor (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0; x0++) {\n\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\t\n\t\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\t\tintersections++;\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t}\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t\n\t\t}\n\t\t}\n\t\t}\n\t\n\t\n\t}\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_6Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\tivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4);\n\tivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5);\n\n\tint yEnd5 = lDims5.y;\n\tint xEnd5 = lDims5.x;\n\tint x6 = 0;\n\tint y6 = 0;\n\t\n\tfor (int y5 = y6*2; y5 < yEnd5; y5++) {\n\tfor (int x5 = x6*2; x5 < xEnd5; x5++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) {\n\t\n\t\tint yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2;\n\t\tint xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2;\n\t\t\n\t\tfor (int y4 = y5*2; y4 < yEnd4; y4++) {\n\t\tfor (int x4 = x5*2; x4 < xEnd4; x4++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) {\n\t\t\n\t\t\tint yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2;\n\t\t\tint xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2;\n\t\t\t\n\t\t\tfor (int y3 = y4*2; y3 < yEnd3; y3++) {\n\t\t\tfor (int x3 = x4*2; x3 < xEnd3; x3++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\t\t\n\t\t\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\t\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\t\t\n\t\t\t\tfor (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\t\t\tfor (int x2 = x3*2; x2 < xEnd2; x2++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\t\t\n\t\t\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\t\t\n\t\t\t\t\tfor (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\t\t\tfor (int x1 = x2*2; x1 < xEnd1; x1++) {\n\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\t\t\n\t\t\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0; x0++) {\n\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\t\t\tintersections++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t}\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t\n\t\t}\n\t\t}\n\t\t}\n\t\n\t\n\t}\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_7Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\tivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4);\n\tivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5);\n\tivec2 lDims6 = GetBBoxArrayDimensions(sideID, 6);\n\n\tint yEnd6 = lDims6.y;\n\tint xEnd6 = lDims6.x;\n\tint x7 = 0;\n\tint y7 = 0;\n\t\n\tfor (int y6 = y7*2; y6 < yEnd6; y6++) {\n\tfor (int x6 = x7*2; x6 < xEnd6; x6++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x6, y6, sideID, 6)) {\n\t\n\t\tint yEnd5 = y6 == lDims6.y-1 ? lDims5.y : (y6+1)*2;\n\t\tint xEnd5 = x6 == lDims6.x-1 ? lDims5.x : (x6+1)*2;\n\t\t\n\t\tfor (int y5 = y6*2; y5 < yEnd5; y5++) {\n\t\tfor (int x5 = x6*2; x5 < xEnd5; x5++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) {\n\t\t\n\t\t\tint yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2;\n\t\t\tint xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2;\n\t\t\t\n\t\t\tfor (int y4 = y5*2; y4 < yEnd4; y4++) {\n\t\t\tfor (int x4 = x5*2; x4 < xEnd4; x4++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) {\n\t\t\t\n\t\t\t\tint yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2;\n\t\t\t\tint xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2;\n\t\t\t\t\n\t\t\t\tfor (int y3 = y4*2; y3 < yEnd3; y3++) {\n\t\t\t\tfor (int x3 = x4*2; x3 < xEnd3; x3++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\t\t\t\n\t\t\t\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\t\t\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\t\t\t\n\t\t\t\t\tfor (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\t\t\t\tfor (int x2 = x3*2; x2 < xEnd2; x2++) {\n\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\t\t\t\n\t\t\t\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\t\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\t\t\t\tfor (int x1 = x2*2; x1 < xEnd1; x1++) {\n\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0; x0++) {\n\t\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\t\t\t\tintersections++;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t}\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t\n\t\t}\n\t\t}\n\t\t}\n\t\n\t\n\t}\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_8Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\tivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4);\n\tivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5);\n\tivec2 lDims6 = GetBBoxArrayDimensions(sideID, 6);\n\tivec2 lDims7 = GetBBoxArrayDimensions(sideID, 7);\n\n\tint yEnd7 = lDims7.y;\n\tint xEnd7 = lDims7.x;\n\tint x8 = 0;\n\tint y8 = 0;\n\t\n\tfor (int y7 = y8*2; y7 < yEnd7; y7++) {\n\tfor (int x7 = x8*2; x7 < xEnd7; x7++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x7, y7, sideID, 7)) {\n\t\n\t\tint yEnd6 = y7 == lDims7.y-1 ? lDims6.y : (y7+1)*2;\n\t\tint xEnd6 = x7 == lDims7.x-1 ? lDims6.x : (x7+1)*2;\n\t\t\n\t\tfor (int y6 = y7*2; y6 < yEnd6; y6++) {\n\t\tfor (int x6 = x7*2; x6 < xEnd6; x6++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x6, y6, sideID, 6)) {\n\t\t\n\t\t\tint yEnd5 = y6 == lDims6.y-1 ? lDims5.y : (y6+1)*2;\n\t\t\tint xEnd5 = x6 == lDims6.x-1 ? lDims5.x : (x6+1)*2;\n\t\t\t\n\t\t\tfor (int y5 = y6*2; y5 < yEnd5; y5++) {\n\t\t\tfor (int x5 = x6*2; x5 < xEnd5; x5++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) {\n\t\t\t\n\t\t\t\tint yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2;\n\t\t\t\tint xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2;\n\t\t\t\t\n\t\t\t\tfor (int y4 = y5*2; y4 < yEnd4; y4++) {\n\t\t\t\tfor (int x4 = x5*2; x4 < xEnd4; x4++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) {\n\t\t\t\t\n\t\t\t\t\tint yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2;\n\t\t\t\t\tint xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2;\n\t\t\t\t\t\n\t\t\t\t\tfor (int y3 = y4*2; y3 < yEnd3; y3++) {\n\t\t\t\t\tfor (int x3 = x4*2; x3 < xEnd3; x3++) {\n\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\t\t\t\t\n\t\t\t\t\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\t\t\t\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\t\t\t\t\n\t\t\t\t\t\tfor (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\t\t\t\t\tfor (int x2 = x3*2; x2 < xEnd2; x2++) {\n\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\t\t\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tfor (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\t\t\t\t\tfor (int x1 = x2*2; x1 < xEnd1; x1++) {\n\t\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\t\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tfor (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\t\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0; x0++) {\n\t\t\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\t\t\t\t\tintersections++;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t}\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t\n\t\t}\n\t\t}\n\t\t}\n\t\n\t\n\t}\n\t}\n\t}\n\n\treturn intersections;\n}\n\n"
  },
  {
    "path": "share/shaders/BBTraversalAlgorithmsNV.frag",
    "content": "// ---------------------------------------------\n// This file is generated by GenerateBBTraversalsNvidia.pl\n// Any changes made to this file will be lost\n// ---------------------------------------------\n\n\nint SearchSideForInitialCellWithOctree_1Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\n\tint yEnd0 = lDims0.y;\n\tint xEnd0 = lDims0.x;\n\tint x1 = 0;\n\tint y1 = 0;\n\t\n\t// for (int y0 = y1*2; y0 < yEnd0; y0++) {\n\tint y0 = y1*2;\n\tfor (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\n\t\tindex[slowDim] = y0;\n\t\tindex[fastDim] = x0;\n\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\tintersections++;\n\t\n\t}\n\tif (x0 == xEnd0-1) {\n\t\tx0 = x1*2-1;\n\t\ty0++;\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_2Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\n\tint yEnd1 = lDims1.y;\n\tint xEnd1 = lDims1.x;\n\tint x2 = 0;\n\tint y2 = 0;\n\t\n\t// for (int y1 = y2*2; y1 < yEnd1; y1++) {\n\tint y1 = y2*2;\n\tfor (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\n\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\n\t\t// for (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\tint y0 = y1*2;\n\t\tfor (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\n\t\t\tindex[slowDim] = y0;\n\t\t\tindex[fastDim] = x0;\n\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\tintersections++;\n\t\t\n\t\t}\n\t\tif (x0 == xEnd0-1) {\n\t\t\tx0 = x1*2-1;\n\t\t\ty0++;\n\t\t}\n\t\t}\n\t\n\t}\n\tif (x1 == xEnd1-1) {\n\t\tx1 = x2*2-1;\n\t\ty1++;\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_3Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\n\tint yEnd2 = lDims2.y;\n\tint xEnd2 = lDims2.x;\n\tint x3 = 0;\n\tint y3 = 0;\n\t\n\t// for (int y2 = y3*2; y2 < yEnd2; y2++) {\n\tint y2 = y3*2;\n\tfor (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\n\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\n\t\t// for (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\tint y1 = y2*2;\n\t\tfor (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\n\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\n\t\t\t// for (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\tint y0 = y1*2;\n\t\t\tfor (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\n\t\t\t\tindex[slowDim] = y0;\n\t\t\t\tindex[fastDim] = x0;\n\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\tintersections++;\n\t\t\t\n\t\t\t}\n\t\t\tif (x0 == xEnd0-1) {\n\t\t\t\tx0 = x1*2-1;\n\t\t\t\ty0++;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t}\n\t\tif (x1 == xEnd1-1) {\n\t\t\tx1 = x2*2-1;\n\t\t\ty1++;\n\t\t}\n\t\t}\n\t\n\t}\n\tif (x2 == xEnd2-1) {\n\t\tx2 = x3*2-1;\n\t\ty2++;\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_4Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\n\tint yEnd3 = lDims3.y;\n\tint xEnd3 = lDims3.x;\n\tint x4 = 0;\n\tint y4 = 0;\n\t\n\t// for (int y3 = y4*2; y3 < yEnd3; y3++) {\n\tint y3 = y4*2;\n\tfor (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\n\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\n\t\t// for (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\tint y2 = y3*2;\n\t\tfor (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\n\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\n\t\t\t// for (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\tint y1 = y2*2;\n\t\t\tfor (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\n\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\n\t\t\t\t// for (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\tint y0 = y1*2;\n\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\n\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\tintersections++;\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\tif (x0 == xEnd0-1) {\n\t\t\t\t\tx0 = x1*2-1;\n\t\t\t\t\ty0++;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t}\n\t\t\tif (x1 == xEnd1-1) {\n\t\t\t\tx1 = x2*2-1;\n\t\t\t\ty1++;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t}\n\t\tif (x2 == xEnd2-1) {\n\t\t\tx2 = x3*2-1;\n\t\t\ty2++;\n\t\t}\n\t\t}\n\t\n\t}\n\tif (x3 == xEnd3-1) {\n\t\tx3 = x4*2-1;\n\t\ty3++;\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_5Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\tivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4);\n\n\tint yEnd4 = lDims4.y;\n\tint xEnd4 = lDims4.x;\n\tint x5 = 0;\n\tint y5 = 0;\n\t\n\t// for (int y4 = y5*2; y4 < yEnd4; y4++) {\n\tint y4 = y5*2;\n\tfor (int x4 = x5*2; x4 < xEnd4 && y4 < yEnd4; x4++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) {\n\t\n\t\tint yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2;\n\t\tint xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2;\n\t\t\n\t\t// for (int y3 = y4*2; y3 < yEnd3; y3++) {\n\t\tint y3 = y4*2;\n\t\tfor (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\t\n\t\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\t\n\t\t\t// for (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\t\tint y2 = y3*2;\n\t\t\tfor (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\t\n\t\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\t\n\t\t\t\t// for (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\t\tint y1 = y2*2;\n\t\t\t\tfor (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\t\n\t\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\t\n\t\t\t\t\t// for (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\t\tint y0 = y1*2;\n\t\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) {\n\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\t\n\t\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\t\tintersections++;\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\tif (x0 == xEnd0-1) {\n\t\t\t\t\t\tx0 = x1*2-1;\n\t\t\t\t\t\ty0++;\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\tif (x1 == xEnd1-1) {\n\t\t\t\t\tx1 = x2*2-1;\n\t\t\t\t\ty1++;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t}\n\t\t\tif (x2 == xEnd2-1) {\n\t\t\t\tx2 = x3*2-1;\n\t\t\t\ty2++;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t}\n\t\tif (x3 == xEnd3-1) {\n\t\t\tx3 = x4*2-1;\n\t\t\ty3++;\n\t\t}\n\t\t}\n\t\n\t}\n\tif (x4 == xEnd4-1) {\n\t\tx4 = x5*2-1;\n\t\ty4++;\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_6Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\tivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4);\n\tivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5);\n\n\tint yEnd5 = lDims5.y;\n\tint xEnd5 = lDims5.x;\n\tint x6 = 0;\n\tint y6 = 0;\n\t\n\t// for (int y5 = y6*2; y5 < yEnd5; y5++) {\n\tint y5 = y6*2;\n\tfor (int x5 = x6*2; x5 < xEnd5 && y5 < yEnd5; x5++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) {\n\t\n\t\tint yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2;\n\t\tint xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2;\n\t\t\n\t\t// for (int y4 = y5*2; y4 < yEnd4; y4++) {\n\t\tint y4 = y5*2;\n\t\tfor (int x4 = x5*2; x4 < xEnd4 && y4 < yEnd4; x4++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) {\n\t\t\n\t\t\tint yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2;\n\t\t\tint xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2;\n\t\t\t\n\t\t\t// for (int y3 = y4*2; y3 < yEnd3; y3++) {\n\t\t\tint y3 = y4*2;\n\t\t\tfor (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\t\t\n\t\t\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\t\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\t\t\n\t\t\t\t// for (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\t\t\tint y2 = y3*2;\n\t\t\t\tfor (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\t\t\n\t\t\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\t\t\n\t\t\t\t\t// for (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\t\t\tint y1 = y2*2;\n\t\t\t\t\tfor (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) {\n\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\t\t\n\t\t\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// for (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\t\t\tint y0 = y1*2;\n\t\t\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) {\n\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\t\t\tintersections++;\n\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (x0 == xEnd0-1) {\n\t\t\t\t\t\t\tx0 = x1*2-1;\n\t\t\t\t\t\t\ty0++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\tif (x1 == xEnd1-1) {\n\t\t\t\t\t\tx1 = x2*2-1;\n\t\t\t\t\t\ty1++;\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\tif (x2 == xEnd2-1) {\n\t\t\t\t\tx2 = x3*2-1;\n\t\t\t\t\ty2++;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t}\n\t\t\tif (x3 == xEnd3-1) {\n\t\t\t\tx3 = x4*2-1;\n\t\t\t\ty3++;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t}\n\t\tif (x4 == xEnd4-1) {\n\t\t\tx4 = x5*2-1;\n\t\t\ty4++;\n\t\t}\n\t\t}\n\t\n\t}\n\tif (x5 == xEnd5-1) {\n\t\tx5 = x6*2-1;\n\t\ty5++;\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_7Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\tivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4);\n\tivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5);\n\tivec2 lDims6 = GetBBoxArrayDimensions(sideID, 6);\n\n\tint yEnd6 = lDims6.y;\n\tint xEnd6 = lDims6.x;\n\tint x7 = 0;\n\tint y7 = 0;\n\t\n\t// for (int y6 = y7*2; y6 < yEnd6; y6++) {\n\tint y6 = y7*2;\n\tfor (int x6 = x7*2; x6 < xEnd6 && y6 < yEnd6; x6++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x6, y6, sideID, 6)) {\n\t\n\t\tint yEnd5 = y6 == lDims6.y-1 ? lDims5.y : (y6+1)*2;\n\t\tint xEnd5 = x6 == lDims6.x-1 ? lDims5.x : (x6+1)*2;\n\t\t\n\t\t// for (int y5 = y6*2; y5 < yEnd5; y5++) {\n\t\tint y5 = y6*2;\n\t\tfor (int x5 = x6*2; x5 < xEnd5 && y5 < yEnd5; x5++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) {\n\t\t\n\t\t\tint yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2;\n\t\t\tint xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2;\n\t\t\t\n\t\t\t// for (int y4 = y5*2; y4 < yEnd4; y4++) {\n\t\t\tint y4 = y5*2;\n\t\t\tfor (int x4 = x5*2; x4 < xEnd4 && y4 < yEnd4; x4++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) {\n\t\t\t\n\t\t\t\tint yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2;\n\t\t\t\tint xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2;\n\t\t\t\t\n\t\t\t\t// for (int y3 = y4*2; y3 < yEnd3; y3++) {\n\t\t\t\tint y3 = y4*2;\n\t\t\t\tfor (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\t\t\t\n\t\t\t\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\t\t\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\t\t\t\n\t\t\t\t\t// for (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\t\t\t\tint y2 = y3*2;\n\t\t\t\t\tfor (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) {\n\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\t\t\t\n\t\t\t\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\t\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// for (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\t\t\t\tint y1 = y2*2;\n\t\t\t\t\t\tfor (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) {\n\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// for (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\t\t\t\tint y0 = y1*2;\n\t\t\t\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) {\n\t\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\t\t\t\tintersections++;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (x0 == xEnd0-1) {\n\t\t\t\t\t\t\t\tx0 = x1*2-1;\n\t\t\t\t\t\t\t\ty0++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (x1 == xEnd1-1) {\n\t\t\t\t\t\t\tx1 = x2*2-1;\n\t\t\t\t\t\t\ty1++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\tif (x2 == xEnd2-1) {\n\t\t\t\t\t\tx2 = x3*2-1;\n\t\t\t\t\t\ty2++;\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\tif (x3 == xEnd3-1) {\n\t\t\t\t\tx3 = x4*2-1;\n\t\t\t\t\ty3++;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t}\n\t\t\tif (x4 == xEnd4-1) {\n\t\t\t\tx4 = x5*2-1;\n\t\t\t\ty4++;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t}\n\t\tif (x5 == xEnd5-1) {\n\t\t\tx5 = x6*2-1;\n\t\t\ty5++;\n\t\t}\n\t\t}\n\t\n\t}\n\tif (x6 == xEnd6-1) {\n\t\tx6 = x7*2-1;\n\t\ty6++;\n\t}\n\t}\n\n\treturn intersections;\n}\n\nint SearchSideForInitialCellWithOctree_8Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\tivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n\tivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n\tivec2 lDims2 = GetBBoxArrayDimensions(sideID, 2);\n\tivec2 lDims3 = GetBBoxArrayDimensions(sideID, 3);\n\tivec2 lDims4 = GetBBoxArrayDimensions(sideID, 4);\n\tivec2 lDims5 = GetBBoxArrayDimensions(sideID, 5);\n\tivec2 lDims6 = GetBBoxArrayDimensions(sideID, 6);\n\tivec2 lDims7 = GetBBoxArrayDimensions(sideID, 7);\n\n\tint yEnd7 = lDims7.y;\n\tint xEnd7 = lDims7.x;\n\tint x8 = 0;\n\tint y8 = 0;\n\t\n\t// for (int y7 = y8*2; y7 < yEnd7; y7++) {\n\tint y7 = y8*2;\n\tfor (int x7 = x8*2; x7 < xEnd7 && y7 < yEnd7; x7++) {\n\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x7, y7, sideID, 7)) {\n\t\n\t\tint yEnd6 = y7 == lDims7.y-1 ? lDims6.y : (y7+1)*2;\n\t\tint xEnd6 = x7 == lDims7.x-1 ? lDims6.x : (x7+1)*2;\n\t\t\n\t\t// for (int y6 = y7*2; y6 < yEnd6; y6++) {\n\t\tint y6 = y7*2;\n\t\tfor (int x6 = x7*2; x6 < xEnd6 && y6 < yEnd6; x6++) {\n\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x6, y6, sideID, 6)) {\n\t\t\n\t\t\tint yEnd5 = y6 == lDims6.y-1 ? lDims5.y : (y6+1)*2;\n\t\t\tint xEnd5 = x6 == lDims6.x-1 ? lDims5.x : (x6+1)*2;\n\t\t\t\n\t\t\t// for (int y5 = y6*2; y5 < yEnd5; y5++) {\n\t\t\tint y5 = y6*2;\n\t\t\tfor (int x5 = x6*2; x5 < xEnd5 && y5 < yEnd5; x5++) {\n\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x5, y5, sideID, 5)) {\n\t\t\t\n\t\t\t\tint yEnd4 = y5 == lDims5.y-1 ? lDims4.y : (y5+1)*2;\n\t\t\t\tint xEnd4 = x5 == lDims5.x-1 ? lDims4.x : (x5+1)*2;\n\t\t\t\t\n\t\t\t\t// for (int y4 = y5*2; y4 < yEnd4; y4++) {\n\t\t\t\tint y4 = y5*2;\n\t\t\t\tfor (int x4 = x5*2; x4 < xEnd4 && y4 < yEnd4; x4++) {\n\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x4, y4, sideID, 4)) {\n\t\t\t\t\n\t\t\t\t\tint yEnd3 = y4 == lDims4.y-1 ? lDims3.y : (y4+1)*2;\n\t\t\t\t\tint xEnd3 = x4 == lDims4.x-1 ? lDims3.x : (x4+1)*2;\n\t\t\t\t\t\n\t\t\t\t\t// for (int y3 = y4*2; y3 < yEnd3; y3++) {\n\t\t\t\t\tint y3 = y4*2;\n\t\t\t\t\tfor (int x3 = x4*2; x3 < xEnd3 && y3 < yEnd3; x3++) {\n\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x3, y3, sideID, 3)) {\n\t\t\t\t\t\n\t\t\t\t\t\tint yEnd2 = y3 == lDims3.y-1 ? lDims2.y : (y3+1)*2;\n\t\t\t\t\t\tint xEnd2 = x3 == lDims3.x-1 ? lDims2.x : (x3+1)*2;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// for (int y2 = y3*2; y2 < yEnd2; y2++) {\n\t\t\t\t\t\tint y2 = y3*2;\n\t\t\t\t\t\tfor (int x2 = x3*2; x2 < xEnd2 && y2 < yEnd2; x2++) {\n\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x2, y2, sideID, 2)) {\n\t\t\t\t\t\t\n\t\t\t\t\t\t\tint yEnd1 = y2 == lDims2.y-1 ? lDims1.y : (y2+1)*2;\n\t\t\t\t\t\t\tint xEnd1 = x2 == lDims2.x-1 ? lDims1.x : (x2+1)*2;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t// for (int y1 = y2*2; y1 < yEnd1; y1++) {\n\t\t\t\t\t\t\tint y1 = y2*2;\n\t\t\t\t\t\t\tfor (int x1 = x2*2; x1 < xEnd1 && y1 < yEnd1; x1++) {\n\t\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x1, y1, sideID, 1)) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tint yEnd0 = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n\t\t\t\t\t\t\t\tint xEnd0 = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t// for (int y0 = y1*2; y0 < yEnd0; y0++) {\n\t\t\t\t\t\t\t\tint y0 = y1*2;\n\t\t\t\t\t\t\t\tfor (int x0 = x1*2; x0 < xEnd0 && y0 < yEnd0; x0++) {\n\t\t\t\t\t\t\t\tif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x0, y0, sideID, 0)) {\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tindex[slowDim] = y0;\n\t\t\t\t\t\t\t\t\tindex[fastDim] = x0;\n\t\t\t\t\t\t\t\t\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\t\t\t\t\t\t\t\t\tintersections++;\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (x0 == xEnd0-1) {\n\t\t\t\t\t\t\t\t\tx0 = x1*2-1;\n\t\t\t\t\t\t\t\t\ty0++;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (x1 == xEnd1-1) {\n\t\t\t\t\t\t\t\tx1 = x2*2-1;\n\t\t\t\t\t\t\t\ty1++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (x2 == xEnd2-1) {\n\t\t\t\t\t\t\tx2 = x3*2-1;\n\t\t\t\t\t\t\ty2++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\tif (x3 == xEnd3-1) {\n\t\t\t\t\t\tx3 = x4*2-1;\n\t\t\t\t\t\ty3++;\n\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\n\t\t\t\t}\n\t\t\t\tif (x4 == xEnd4-1) {\n\t\t\t\t\tx4 = x5*2-1;\n\t\t\t\t\ty4++;\n\t\t\t\t}\n\t\t\t\t}\n\t\t\t\n\t\t\t}\n\t\t\tif (x5 == xEnd5-1) {\n\t\t\t\tx5 = x6*2-1;\n\t\t\t\ty5++;\n\t\t\t}\n\t\t\t}\n\t\t\n\t\t}\n\t\tif (x6 == xEnd6-1) {\n\t\t\tx6 = x7*2-1;\n\t\t\ty6++;\n\t\t}\n\t\t}\n\t\n\t}\n\tif (x7 == xEnd7-1) {\n\t\tx7 = x8*2-1;\n\t\ty7++;\n\t}\n\t}\n\n\treturn intersections;\n}\n\n"
  },
  {
    "path": "share/shaders/Contour.frag",
    "content": "#version 330 core\n\nuniform sampler1D colormap;\nuniform float minLUTValue;\nuniform float maxLUTValue;\n\nin float fValue;\nout vec4 FragColor;\n\nvoid main() {\n    //FragColor = fColor;\n    \n    float s = (fValue - minLUTValue) / (maxLUTValue - minLUTValue);\n    vec4 color = texture(colormap, s);\n    FragColor = color;\n}\n"
  },
  {
    "path": "share/shaders/Contour.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float value;\n\nout float fValue;\n\nuniform mat4 MVP;\n\nvoid main() {\n    gl_Position = MVP * vec4(vPos, 1.0);\n    fValue = value;\n}\n"
  },
  {
    "path": "share/shaders/DepthBuffer.frag",
    "content": "#version 330 core\n\nuniform sampler2D sampler;\nuniform float near;\nuniform float far;\nuniform bool linearize;\n\nin vec2 ST;\n\nout vec4 fragColor;\n\nvoid main(void)\n{\n\tfloat depth = texture(sampler, ST).r;\n\tif (linearize)\n\t\tdepth = (2.0 * near) / (far + near - depth * (far - near));\n\tfragColor = vec4(vec3(depth), 1.0);\n}\n"
  },
  {
    "path": "share/shaders/DepthBuffer.vert",
    "content": "#version 330 core\n\nuniform mat4 MVP;\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsArrow.frag",
    "content": "// Basic fragment shader. Maps the fValue onto a color using the LUT then applies Phong lighting.\n\n#version 330 core\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform vec3 lightDir = vec3(0, 0, -1);\nuniform bool lightingEnabled = true;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\nuniform vec3 scales;\n\nin float fValue;\nin  vec3 fNormal;\nout vec4 fragment;\n\nuniform float phongAmbient;\nuniform float phongDiffuse;\nuniform float phongSpecular;\nuniform float phongShininess;\nfloat PhongLighting(vec3 normal, vec3 viewDir)\n{\n\tif (!lightingEnabled)\n\t\treturn 1.0;\n    \n    vec3 lightDir = viewDir;\n\n    float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse;\n\n    float specularStrength = phongSpecular;\n    vec3 reflectDir = reflect(lightDir, normal);\n    float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess);\n    float specular = specularStrength * spec;\n\n    return max(phongAmbient + diffuse + specular, phongAmbient);\n}\n\nvoid main() {\n    vec4 color;\n    if (constantColorEnabled)\n        color = vec4(constantColor, 1.0f);\n    else\n        color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n    if (lightingEnabled) {\n\t\tvec3 normal;\n\t\tif (gl_FrontFacing)\n\t\t\tnormal = -fNormal;\n\t\telse \n\t\t\tnormal = fNormal;\n\n\t\tvec3 ld = normalize(lightDir * scales);\n        // float diffuse = max(dot(normal, ld), 0.0);\n        // color.rgb *= max(diffuse, 0.2f);\n        color.rgb *= PhongLighting(normal, ld);\n    }\n    fragment = color;\n    \n    if (color.a < 0.05) discard;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsArrow.geom",
    "content": "// This shader generates a cone at every vertex v_n pointing in the direction of \n// the average normal between v_n-1 to v_n and v_n to v_n+1. The cone is generated\n// as a triangle strip, generated from the bottom circle and top vertex. This\n// geometry is generated at the origin and transformed with a simple affine tranformation\n// using basis vectors.\n// \n// EmitWorld(vec3 v) projects v and emits it.\n// CylinderVert(v, ...) is a helper function that generates a point on a circle\n// given the parameters and passes it to EmitWorld.\n\n#version 330 core\n\n#include FlowInclude.geom\n\n#define REFINEMENT 7\n\nlayout (lines_adjacency) in;\nlayout (triangle_strip, max_vertices = 32) out; // (7 * 2 + 2) * 2\n\n\nin  float gValue[];\nin  float clip[];\nout float fValue;\nout vec3 fNormal;\n\n\nuniform mat4 P;\nuniform mat4 MV;\nuniform vec3 scales;\nuniform float radius = 0.05;\nuniform int glyphStride = 1;\nuniform bool showOnlyLeadingSample = false;\n\n\nvoid EmitWorld(const vec3 v);\nvoid CylinderVert(const vec3 v, const vec3 d, const float value);\n\n\nvoid main()\n{\n\t// Discard skipped samples\n\tif (showOnlyLeadingSample) {\n\t\tif (gl_PrimitiveIDIn < nVertices-4)\n\t\t\treturn;\n\t} else {\n\t\tif (gl_PrimitiveIDIn % glyphStride != 0)\n\t\t\treturn;\n\t}\n\n\t// Need to manually clip when using geometry shader\n    if (clip[1] < 0.0 || clip[2] < 0.0)\n        return;\n\n    vec3 V[4];\n    for (int i = 0; i < 4; i++)\n        V[i] = gl_in[i].gl_Position.xyz;\n\n    vec3 VN[3];\n    for (int i = 0; i < 3; i++)\n        VN[i] = normalize(V[i+1] - V[i]);\n\n    vec3 N[2];\n    vec3 up = vec3(0, 0, 1);\n    bool parallelToUpChanged = false;\n    for (int i = 0; i < 2; i++) {\n        N[i] = normalize((VN[i] + VN[i+1])/2);\n        if (1 - dot(N[i], up) < FLT_EPSILON)\n            parallelToUpChanged = true;\n    }\n\n\t// Basis vectors are generated against an arbritray up which needs to be different from N\n    if (parallelToUpChanged)\n        up = vec3(1, 0, 0);\n\n\t// Generate basis vectors\n    vec3 XH[2];\n    vec3 YH[2];\n    for (int i = 0; i < 2; i++) {\n        XH[i] = normalize(cross(N[i], up));\n        YH[i] = normalize(cross(XH[i], N[i]));\n    }\n\n    fValue = gValue[1];\n    vec3 top = V[1] + N[0] * radius * 1.618 / scales;\n\n\t// Plot geometry sides\n    for (int i = 0; i < REFINEMENT + 1; i++) {\n        float t = float(i)/float(REFINEMENT) * 2.f * PI;\n        vec3 d;\n        d = XH[0]*cos(t) + YH[0]*sin(t);\n        vec3 bottom = V[1] + d * radius / scales;\n\n        // fNormal = normalize((d + N[0])/2.0f);\n        fNormal = normalize(cross(top-bottom, cross(d, N[0])));\n\n        EmitWorld(bottom);\n        EmitWorld(top);\n    }\n    EndPrimitive();\n\n    fNormal = -N[0];\n\n    // Plot geometry bottom\n    for (int i = 0; i < REFINEMENT + 1; i++) {\n        float t = float(i)/float(REFINEMENT) * 2.f * PI;\n        vec3 d;\n        d = XH[0]*cos(t) + YH[0]*sin(t);\n\n        EmitWorld(V[1]);\n        EmitWorld(V[1] + d * radius / scales);\n    }\n    EndPrimitive();\n} \n\n\nvoid EmitWorld(const vec3 v)\n{\n    gl_Position = P * MV * vec4(v, 1.0f);\n    EmitVertex();\n}\n\n\nvoid CylinderVert(const vec3 v, const vec3 d, const float value)\n{\n    fNormal = d;\n    EmitWorld(v + d * radius);\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsArrow.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\nuniform vec4 clippingPlanes[6];\n// out float gl_ClipDistance[6];\nout float clip;\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = vec4(vPos, 1.0f);\n\n    clip = 0;\n\tfor (int i = 0; i < 6; i++)\n\t\tclip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsArrow2D.frag",
    "content": "// Basic fragment shader. Maps the fValue onto a color using the LUT.\n#version 330 core\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform float radius = 0.05f;\nuniform float border = 0.f;\nuniform vec3 borderColor = vec3(1.0f);\nuniform bool antiAlias = false;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\n\nin float fValue;\nin float t;\n\nout vec4 fragment;\n\n\nvoid main()\n{\n    if (constantColorEnabled)\n        fragment = vec4(constantColor, 1.0f);\n    else {\n        vec4 c = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n        if (antiAlias) {\n            float S = 12;\n            S *= (radius + border) / 0.1;\n            c.rgb = mix(c.rgb, borderColor, clamp((abs(t)-radius/(radius+border))*S, 0.f, 1.f));\n            c.a *= min(((1-abs(t))*S), 1);\n        } else {\n            if (abs(t) > radius/(radius+border))\n                c = vec4(borderColor, 1.f);\n        }\n\n\n        fragment = c;\n        \n        if (c.a < 0.05) discard;\n    }\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsArrow2D.geom",
    "content": "// This shader generates a 2D triangle at every vertex v_n pointing in the direction of \n// the average normal between v_n-1 to v_n and v_n to v_n+1.\n// \n\n#version 330 core\n\n#include FlowInclude.geom\n\nlayout (lines_adjacency) in;\nlayout (triangle_strip, max_vertices = 3) out;\n\nin  float gValue[];\nin  float clip[];\nout float fValue;\nout float t;\n\nuniform float radius = 0.05f;\nuniform int glyphStride = 1;\nuniform bool showOnlyLeadingSample = false;\nuniform float border = 0.f;\nuniform float aspect;\n\n\nvoid main()\n{\n\t// Discard skipped samples\n\tif (showOnlyLeadingSample) {\n\t\tif (gl_PrimitiveIDIn < nVertices-4)\n\t\t\treturn;\n\t} else {\n\t\tif (gl_PrimitiveIDIn % glyphStride != 0)\n\t\t\treturn;\n\t}\n\n\t// Need to manually clip when using geometry shader\n    if (clip[1] < 0.0 || clip[2] < 0.0)\n        return;\n\n    vec2 vS[4];\n    for (int i = 0; i < 4; i++)\n        vS[i] = gl_in[i].gl_Position.xy / gl_in[i].gl_Position.w;\n\n    vec2 vN[3];\n    for (int i = 0; i < 3; i++)\n        vN[i] = normalize(vS[i+1] - vS[i]);\n\n\t// These calculations are done in screen-space so need to account for aspect ratio.\n    vec2 n[2];\n    vec2 p[2];\n    vec4 o[2];\n    for (int i = 0; i < 2; i++) {\n        n[i] = normalize((vN[i] + vN[i+1])/2);\n        p[i] = vec2(-n[i].y, n[i].x);\n        p[i].x /= aspect;\n        o[i] = vec4(p[i], 0.0f, 0.0f) * (radius*2 + border);\n    }\n\n\n#define v0 gl_in[1].gl_Position\n#define v1 gl_in[2].gl_Position\n\n    vec4 top = v0 + vec4(n[0],0,0) * radius * 1.618 * 2;\n    fValue = gValue[1];\n\n    gl_Position = v0 - o[0]; t = -1; EmitVertex();\n    gl_Position = top;        t = -1; EmitVertex();\n    gl_Position = v0 + o[0]; t =  1; EmitVertex();\n\n    EndPrimitive();\n} \n"
  },
  {
    "path": "share/shaders/FlowGlyphsArrow2D.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\nuniform mat4 P;\nuniform mat4 MV;\n\nuniform vec4 clippingPlanes[6];\n// out float gl_ClipDistance[6];\nout float clip;\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = P * MV * vec4(vPos, 1.0f);\n\n    clip = 0;\n\tfor (int i = 0; i < 6; i++)\n\t\tclip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsLineDirArrow2D.frag",
    "content": "// Basic fragment shader. Maps the fValue onto a color using the LUT.\n#version 330 core\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform float radius = 0.05f;\nuniform float border = 0.f;\nuniform vec3 borderColor = vec3(1.0f);\nuniform bool antiAlias = false;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\n\nin float fValue;\nin float fFade;\nin float t;\n\nout vec4 fragment;\n\n\nvoid main()\n{\n    vec4 color;\n\n    if (constantColorEnabled)\n        color = vec4(constantColor, 1.0f);\n    else {\n        vec4 c = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n        if (antiAlias) {\n            float S = 12;\n            S *= (radius + border) / 0.1;\n            c.rgb = mix(c.rgb, borderColor, clamp((abs(t)-radius/(radius+border))*S, 0.f, 1.f));\n            c.a *= min(((1-abs(t))*S), 1);\n        } else {\n            if (abs(t) > radius/(radius+border))\n                c = vec4(borderColor, 1.f);\n        }\n\n        color = c;\n    }\n\n    color.a *= fFade;\n    if (fFade < 0.05)\n        discard;\n\n    fragment = color;\n    \n    if (color.a < 0.05) discard;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsLineDirArrow2D.geom",
    "content": "// This behaves the same as FlowGlyphsArrow2D.geom except the geometry is clipped against the line\n\n#version 330 core\n\n#include FlowInclude.geom\n\nlayout (lines_adjacency) in;\nlayout (triangle_strip, max_vertices = 6) out;\n\nin  float gValue[];\nin  float clip[];\nout float fValue;\nout float fFade;\nout float t;\n\nuniform float radius = 0.05f;\nuniform int glyphStride = 1;\nuniform float border = 0.f;\nuniform float aspect;\n\n\nvoid main()\n{\n    if (gl_PrimitiveIDIn % glyphStride != 0)\n        return;\n\n    if (clip[1] < 0.0 || clip[2] < 0.0)\n        return;\n\n    vec2 vS[4];\n    for (int i = 0; i < 4; i++)\n        vS[i] = gl_in[i].gl_Position.xy / gl_in[i].gl_Position.w;\n\n    vec2 vN[3];\n    for (int i = 0; i < 3; i++)\n        vN[i] = normalize(vS[i+1] - vS[i]);\n\n    vec2 n[2];\n    vec2 p[2];\n    vec4 o[2];\n    for (int i = 0; i < 2; i++) {\n        n[i] = normalize((vN[i] + vN[i+1])/2);\n        p[i] = vec2(-n[i].y, n[i].x);\n        p[i].x /= aspect;\n        o[i] = vec4(p[i], 0.0f, 0.0f) * (radius*2 + border);\n    }\n\n\n#define v0 gl_in[1].gl_Position\n#define v1 gl_in[2].gl_Position\n\n    float s = 1.9;\n    vec2 fade = CalculateFade();\n\n    vec4 top = v0 + vec4(n[0],0,0) * radius * 1.618 * 2;\n\n    float tTop = length(top.xyz-v0.xyz)/length(v1.xyz-v0.xyz);\n    float fTop = mix(fade[0], fade[1], tTop);\n    float vTop = mix(gValue[1], gValue[2], tTop);\n\n    gl_Position = v0 - o[0]*s; fValue = gValue[1]; fFade = fade[0]; t = -1; EmitVertex();\n    gl_Position = v1 - o[1]; fFade = fade[1]; fValue = gValue[2];        t = -1; EmitVertex();\n    gl_Position = v0 - o[0]; fValue = gValue[1]; fFade = fade[0]; t =  1; EmitVertex();\n\n    EndPrimitive();\n\n    gl_Position = v0 + o[0]*s; fValue = gValue[1]; fFade = fade[0]; t = -1; EmitVertex();\n    gl_Position = v0 + o[0]; fValue = gValue[1]; fFade = fade[0]; t =  1; EmitVertex();\n    gl_Position = v1 + o[1]; fFade = fade[1]; fValue = gValue[2];        t = -1; EmitVertex();\n\n    EndPrimitive();\n} \n"
  },
  {
    "path": "share/shaders/FlowGlyphsLineDirArrow2D.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\nuniform mat4 P;\nuniform mat4 MV;\n\nuniform vec4 clippingPlanes[6];\n// out float gl_ClipDistance[6];\nout float clip;\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = P * MV * vec4(vPos, 1.0f);\n\n    clip = 0;\n\tfor (int i = 0; i < 6; i++)\n\t\tclip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsSphere2D.frag",
    "content": "// Basic fragment shader. Maps the fValue onto a color using the LUT.\n#version 330 core\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform float radius = 0.05f;\nuniform float border = 0.f;\nuniform vec3 borderColor = vec3(1.0f);\nuniform bool antiAlias = false;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\n\nin float fValue;\nin float t;\n\nout vec4 fragment;\n\n\nvoid main()\n{\n    if (constantColorEnabled)\n        fragment = vec4(constantColor, 1.0f);\n    else {\n        vec4 c = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n        if (antiAlias) {\n            float S = 12;\n            S *= (radius + border) / 0.1;\n            c.rgb = mix(c.rgb, borderColor, clamp((abs(t)-radius/(radius+border))*S, 0.f, 1.f));\n            c.a *= min(((1-abs(t))*S), 1);\n        } else {\n            if (abs(t) > radius/(radius+border))\n                c = vec4(borderColor, 1.f);\n        }\n\n\n        fragment = c;\n        \n        if (c.a < 0.05) discard;\n    }\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsSphere2D.geom",
    "content": "// This behaves the same as FlowGlyphsArrow2D.geom except it draws a circle.\n\n#version 330 core\n\n#include FlowInclude.geom\n\n#define REFINEMENT 16\n\nlayout (lines_adjacency) in;\nlayout (triangle_strip, max_vertices = 34) out;\n\nin  float gValue[];\nin  float clip[];\nout float fValue;\nout float t;\n\nuniform float radius = 0.05f;\nuniform int glyphStride = 1;\nuniform bool showOnlyLeadingSample = false;\nuniform float border = 0.f;\nuniform float aspect;\n\n\nvoid main()\n{\n\tif (showOnlyLeadingSample) {\n\t\tif (gl_PrimitiveIDIn < nVertices-4)\n\t\t\treturn;\n\t} else {\n\t\tif (gl_PrimitiveIDIn % glyphStride != 0)\n\t\t\treturn;\n\t}\n\n    if (clip[1] < 0.0 || clip[2] < 0.0)\n        return;\n\n    fValue = gValue[1];\n\n    vec4 o = gl_in[1].gl_Position;\n\n    for (int i = 0; i < REFINEMENT+1; i++) {\n        float theta = float(i)/float(REFINEMENT) * 2.f * PI;\n        vec4 d = vec4(cos(theta), sin(theta), 0.0, 0.0);\n        d.x /= aspect;\n\n        t = 0;\n        gl_Position = o;\n        EmitVertex();\n\n        t = 1;\n        gl_Position = o+d*radius*2;\n        EmitVertex();\n    }\n    EndPrimitive();\n\n} \n"
  },
  {
    "path": "share/shaders/FlowGlyphsSphere2D.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\nuniform mat4 P;\nuniform mat4 MV;\n\nuniform vec4 clippingPlanes[6];\n// out float gl_ClipDistance[6];\nout float clip;\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = P * MV * vec4(vPos, 1.0f);\n\n    clip = 0;\n\tfor (int i = 0; i < 6; i++)\n\t\tclip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsSphereSplat.frag",
    "content": "// Maps the fValue onto a color using the LUT then applies Phong lighting.\n// Using the texture coordinates of the billboard it caclulates the bounds and normals of a sphere\n// which is then used for the lighting calculation.\n\n#version 330 core\n\n#define PI (3.1415926)\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform vec3 lightDir = vec3(0, 0, -1);\nuniform bool lightingEnabled = true;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\nuniform vec3 scales;\n\nin float fValue;\nin  vec2 fC;\nout vec4 fragment;\n\nuniform float phongAmbient;\nuniform float phongDiffuse;\nuniform float phongSpecular;\nuniform float phongShininess;\nfloat PhongLighting(float theta)\n{\n\tif (!lightingEnabled)\n\t\treturn 1.0;\n\n\tfloat ct = cos(theta);\n    float diffuse = ct * phongDiffuse;\n    float specular = phongSpecular * pow(ct, phongShininess);\n    return max(phongAmbient + diffuse + specular, phongAmbient);\n}\n\nvoid main() {\n    vec4 color;\n    if (constantColorEnabled)\n        color = vec4(constantColor, 1.0f);\n    else\n        color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n\tfloat a = length(fC); // Length of a right angle triangle with a hypontenuse going from the origin to the sphere surface.\n\tfloat t = acos(a); // Angle of triangle\n\tfloat t2 = PI/2.0 - t; // Reflected angle\n\n\tif (a > 1)\n\t\tdiscard;\n\n\tcolor.rgb *= PhongLighting(t2);\n    fragment = color;\n    \n    if (color.a < 0.05) discard;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsSphereSplat.geom",
    "content": "// This generates a billboard with a width and height equal to the diameter the sphere\n\n#version 330 core\n\n#include FlowInclude.geom\n\n#define REFINEMENT 10\n\nlayout (lines_adjacency) in;\nlayout (triangle_strip, max_vertices = 4) out;\n\n\nin  float gValue[];\nin  float clip[];\nout float fValue;\nout vec2 fC;\n\n\nuniform mat4 P;\nuniform mat4 MV;\nuniform vec3 cameraPos;\nuniform vec3 scales;\nuniform float radius = 0.05;\nuniform int glyphStride = 1;\nuniform bool showOnlyLeadingSample = false;\n\n\nvoid EmitWorld(const vec3 v);\nvoid CylinderVert(const vec3 v, const vec3 d, const float value);\nvoid Face(const vec3 a, const vec3 b, const vec3 c);\nvoid SubDiv(const vec3 a, const vec3 b, const vec3 c);\n\n\nvoid main()\n{\n\tif (showOnlyLeadingSample) {\n\t\tif (gl_PrimitiveIDIn < nVertices-4)\n\t\t\treturn;\n\t} else {\n\t\tif (gl_PrimitiveIDIn % glyphStride != 0)\n\t\t\treturn;\n\t}\n\n\t// Need to manually clip if using geometry shader.\n    if (clip[1] < 0.0 || clip[2] < 0.0)\n        return;\n\n    fValue = gValue[1];\n    vec3 o = gl_in[1].gl_Position.xyz;\n\n\t// Plane perpendicular to camera normal\n\tvec3 up = vec3(0.0, 0.0, 1.0);\n\tvec3 toCamera = normalize(cameraPos - o);\n\tvec3 xh = normalize(cross(up, toCamera));\n\tvec3 yh = normalize(cross(toCamera, xh));\n\txh /= scales;\n\tyh /= scales;\n\n\t// Billboard\n\tfC = vec2(-1.0, -1.0); EmitWorld(o + radius * (-xh + -yh));\n\tfC = vec2( 1.0, -1.0); EmitWorld(o + radius * ( xh + -yh));\n\tfC = vec2(-1.0,  1.0); EmitWorld(o + radius * (-xh +  yh));\n\tfC = vec2( 1.0,  1.0); EmitWorld(o + radius * ( xh +  yh));\n} \n\n\nvoid EmitWorld(const vec3 v)\n{\n    gl_Position = P * MV * vec4(v, 1.0f);\n    EmitVertex();\n}\n\n\n"
  },
  {
    "path": "share/shaders/FlowGlyphsSphereSplat.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\nuniform vec4 clippingPlanes[6];\n// out float gl_ClipDistance[6];\nout float clip;\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = vec4(vPos, 1.0f);\n\n    clip = 0;\n\tfor (int i = 0; i < 6; i++)\n\t\tclip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsTubeDirArrow.frag",
    "content": "// Basic fragment shader. Maps the fValue onto a color using the LUT then applies Phong lighting.\n#version 330 core\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform vec3 lightDir = vec3(0, 0, -1);\nuniform bool lightingEnabled = true;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\nuniform vec3 scales;\n\nin float fValue;\nin float fFade;\nin  vec3 fNormal;\nout vec4 fragment;\n\nuniform float phongAmbient;\nuniform float phongDiffuse;\nuniform float phongSpecular;\nuniform float phongShininess;\nfloat PhongLighting(vec3 normal, vec3 viewDir)\n{\n\tif (!lightingEnabled)\n\t\treturn 1.0;\n    \n    vec3 lightDir = viewDir;\n\n    float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse;\n\n    float specularStrength = phongSpecular;\n    vec3 reflectDir = reflect(lightDir, normal);\n    float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess);\n    float specular = specularStrength * spec;\n\n    return max(phongAmbient + diffuse + specular, phongAmbient);\n}\n\nvoid main() {\n    vec4 color;\n    if (constantColorEnabled)\n        color = vec4(constantColor, 1.0f);\n    else\n        color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n    if (lightingEnabled) {\n\t\tvec3 normal;\n\t\tif (gl_FrontFacing)\n\t\t\tnormal = -fNormal;\n\t\telse \n\t\t\tnormal = fNormal;\n\n\t\tvec3 ld = normalize(lightDir * scales);\n        // float diffuse = max(dot(normal, ld), 0.0);\n        // color.rgb *= max(diffuse, 0.2f);\n        color.rgb *= PhongLighting(normal, ld);\n    }\n\n    color.a *= fFade;\n    if (fFade < 0.05)\n        discard;\n\n    fragment = color;\n    \n    if (color.a < 0.05) discard;\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsTubeDirArrow.geom",
    "content": "// This behaves the same as FlowGlyphsArrow.geom except it clips the geometry against the tube.\n\n#version 330 core\n\n#include FlowInclude.geom\n\n#define REFINEMENT 7\n\nlayout (lines_adjacency) in;\nlayout (triangle_strip, max_vertices = 32) out; // (7 * 2 + 2) * 2\n\n\nin  float gValue[];\nin  float clip[];\nout float fValue;\nout float fFade;\nout vec3 fNormal;\n\n\nuniform mat4 P;\nuniform mat4 MV;\nuniform vec3 scales;\nuniform float radius = 0.05;\nuniform int glyphStride = 1;\n\n\nvoid EmitWorld(const vec3 v);\nvoid CylinderVert(const vec3 v, const vec3 d, const float value);\n\n\nvoid main()\n{\n    if (gl_PrimitiveIDIn % glyphStride != 0)\n        return;\n\n    if (clip[1] < 0.0 || clip[2] < 0.0)\n        return;\n\n    vec3 V[4];\n    for (int i = 0; i < 4; i++)\n        V[i] = gl_in[i].gl_Position.xyz;\n\n    vec3 VN[3];\n    for (int i = 0; i < 3; i++)\n        VN[i] = normalize(V[i+1] - V[i]);\n\n    vec3 N[2];\n    vec3 up = vec3(0, 0, 1);\n    bool parallelToUpChanged = false;\n    for (int i = 0; i < 2; i++) {\n        N[i] = normalize((VN[i] + VN[i+1])/2);\n        if (1 - dot(N[i], up) < FLT_EPSILON)\n            parallelToUpChanged = true;\n    }\n\n    if (parallelToUpChanged)\n        up = vec3(1, 0, 0);\n\n    vec3 XH[2];\n    vec3 YH[2];\n    for (int i = 0; i < 2; i++) {\n        XH[i] = normalize(cross(N[i], up));\n        YH[i] = normalize(cross(XH[i], N[i]));\n    }\n\n    fValue = gValue[1];\n    vec3 top = V[1] + N[0] * radius * 1.618;\n\n    float s = 1.7;\n    vec2 fade = CalculateFade();\n\n    for (int i = 0; i < REFINEMENT + 1; i++) {\n        float t = float(i)/float(REFINEMENT) * 2.f * PI;\n        vec3 d;\n        d = XH[0]*cos(t) + YH[0]*sin(t);\n\n        vec3 bottom = V[1] + d * radius * s / scales;\n        vec3 top = mix(V[1], V[2], 1.0/1.218) + d * radius / scales;\n\n        // fNormal = normalize((d + N[0])/2.0f);\n        fNormal = normalize(cross(top-bottom, cross(d, N[0])));\n        fFade = fade[0];\n        EmitWorld(bottom);\n\n        fFade = mix(fade[0], fade[1], 1.0/1.218);\n        EmitWorld(top);\n    }\n    EndPrimitive();\n\n    fNormal = -N[0];\n    fFade = fade[0];\n\n    // Bottom\n    for (int i = 0; i < REFINEMENT + 1; i++) {\n        float t = float(i)/float(REFINEMENT) * 2.f * PI;\n        vec3 d;\n        d = XH[0]*cos(t) + YH[0]*sin(t);\n\n        EmitWorld(V[1]);\n        EmitWorld(V[1] + d * radius * s / scales);\n    }\n    EndPrimitive();\n} \n\n\nvoid EmitWorld(const vec3 v)\n{\n    gl_Position = P * MV * vec4(v, 1.0f);\n    EmitVertex();\n}\n\n\nvoid CylinderVert(const vec3 v, const vec3 d, const float value)\n{\n    fNormal = d;\n    EmitWorld(v + d * radius);\n}\n"
  },
  {
    "path": "share/shaders/FlowGlyphsTubeDirArrow.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\nuniform vec4 clippingPlanes[6];\n// out float gl_ClipDistance[6];\nout float clip;\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = vec4(vPos, 1.0f);\n\n    clip = 0;\n\tfor (int i = 0; i < 6; i++)\n\t\tclip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0;\n}\n"
  },
  {
    "path": "share/shaders/FlowInclude.geom",
    "content": "#define FLT_EPSILON 1.19e-07\n#define PI float(3.1415926535897932384626433832795)\n\nuniform int nVertices = 4;\n\nuniform bool fade_tails = false;\nuniform int fade_start;\nuniform int fade_length;\nuniform int fade_stop;\n\nvec2 CalculateFade()\n{\n    if (!fade_tails)\n        return vec2(1.0);\n\n    int i = (nVertices -4) - gl_PrimitiveIDIn;\n\n    i -= fade_stop;\n\n    if (i > 0)\n    return vec2(\n        1.0 - clamp(((i+1) - fade_start) / float(fade_length), 0.0, 1.0),\n        1.0 - clamp((  i   - fade_start) / float(fade_length), 0.0, 1.0)\n    );\n    else\n        return vec2(0);\n}\n"
  },
  {
    "path": "share/shaders/FlowLine.frag",
    "content": "#version 410 core\n\nlayout(location = 0) out vec4 color;\n\nin float            scalarV;\nin vec3             vertModel;\n\nuniform sampler1D   colorMapTexture;\nuniform vec3        colorMapRange;\nuniform bool        singleColor;\n\n\nvoid main(void)\n{\n    if( singleColor )\n    {\n        color = texelFetch( colorMapTexture, 0, 0 );\n    }\n    else\n    {\n        float valTranslate = (scalarV - colorMapRange.x) / colorMapRange.z;\n        color = texture( colorMapTexture, valTranslate );\n        \n        if (color.a < 0.05) discard;\n    }\n}\n\n"
  },
  {
    "path": "share/shaders/FlowLine.vert",
    "content": "#version 410 core\n\n// Input vertex position (.xyz) and colormap value (.w)\nlayout(location = 0) in vec4 vertInfo;\n\nuniform mat4 MV;\nuniform mat4 Projection;\n\nuniform vec4 clippingPlanes[6];\nout float gl_ClipDistance[6];\n\nout float scalarV;\nout vec3  vertModel;\n\nvoid main(void)\n{\n    gl_Position = Projection * MV * vec4( vertInfo.xyz, 1.0 );\n    scalarV     = vertInfo.w;\n    vertModel   = vertInfo.xyz;\n\n\tfor (int i = 0; i < 6; i++)\n\t\tgl_ClipDistance[i] = dot(vec4(vertModel, 1.0), clippingPlanes[i]);\n}\n"
  },
  {
    "path": "share/shaders/FlowLines.frag",
    "content": "// Basic fragment shader. Maps the fValue onto a color using the LUT.\n// This shader also supports anti-aliasing and adding a border to the lines\n// but these features are not currently in use.\n#version 330 core\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform float radius = 0.05f;\nuniform float border = 0.f;\nuniform vec3 borderColor = vec3(1.0f);\nuniform bool antiAlias = false;\nuniform float falloff = 1.0f;\nuniform float tone = 1.0f;\nuniform bool density = false;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\n\nin float fValue;\nin float fFade;\nin float t;\n\nout vec4 fragment;\n\n\nvoid main()\n{\n    vec4 color;\n\n    if (constantColorEnabled)\n        color = vec4(constantColor, 1.0f);\n    else {\n        vec4 c = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n        if (antiAlias) {\n            float S = 12;\n            S *= (radius + border) / 0.1;\n            c.rgb = mix(c.rgb, borderColor, clamp((abs(t)-radius/(radius+border))*S, 0.f, 1.f));\n            c.a *= min(((1-abs(t))*S), 1);\n        } else {\n            if (abs(t) > radius/(radius+border))\n                c = vec4(borderColor, 1.f);\n        }\n\n\n        color = c;\n    }\n    \n    if (density) {\n        color.rgb *= vec3(pow(1-abs(t), falloff));\n        // Not exactly correct but will do for now\n        color.rgb = 1-exp(-tone * color.rgb);\n    }\n\n    color.a *= fFade;\n    if (fFade < 0.05)\n        discard;\n\n    fragment = color;\n    \n    if (color.a < 0.05) discard;\n}\n"
  },
  {
    "path": "share/shaders/FlowLines.geom",
    "content": "// Generates a line represented by quades from a set of points\n\n#version 330 core\n\n#include FlowInclude.geom\n\nlayout (lines_adjacency) in;\nlayout (triangle_strip, max_vertices = 4) out;\n\nin  float gValue[];\nin  float clip[];\nout float fValue;\nout float fFade;\nout float t;\n\nuniform float radius = 0.05f;\nuniform float border = 0.f;\nuniform float aspect;\n\n\nvoid main()\n{\n\t// Need to manually clip when using geometry shader.\n    if (clip[1] < 0.0 || clip[2] < 0.0)\n        return;\n\n    vec2 vS[4]; // Screen space\n    for (int i = 0; i < 4; i++)\n        vS[i] = gl_in[i].gl_Position.xy / gl_in[i].gl_Position.w;\n\n    vec2 vN[3];\n    for (int i = 0; i < 3; i++)\n        vN[i] = normalize(vS[i+1] - vS[i]);\n\n    vec2 n[2];\n    vec2 p[2];\n    vec4 o[2];\n    for (int i = 0; i < 2; i++) {\n        n[i] = normalize((vN[i] + vN[i+1])/2);\n        p[i] = vec2(-n[i].y, n[i].x);\n        p[i].x /= aspect;\n        o[i] = vec4(p[i], 0.0f, 0.0f) * (radius*2 + border);\n    }\n\n    vec2 fade = CalculateFade();\n\n#define v0 gl_in[1].gl_Position\n#define v1 gl_in[2].gl_Position\n\n    gl_Position = v0 - o[0]; fValue = gValue[1]; fFade = fade[0]; t = -1; EmitVertex();\n    gl_Position = v1 - o[1]; fValue = gValue[2]; fFade = fade[1]; t = -1; EmitVertex();\n    gl_Position = v0 + o[0]; fValue = gValue[1]; fFade = fade[0]; t =  1; EmitVertex();\n    gl_Position = v1 + o[1]; fValue = gValue[2]; fFade = fade[1]; t =  1; EmitVertex();\n\n    EndPrimitive();\n} \n"
  },
  {
    "path": "share/shaders/FlowLines.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\nuniform mat4 P;\nuniform mat4 MV;\n\nuniform vec4 clippingPlanes[6];\n// out float gl_ClipDistance[6];\nout float clip;\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = P * MV * vec4(vPos, 1.0f);\n\n    clip = 0;\n\tfor (int i = 0; i < 6; i++)\n\t\tclip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0;\n}\n"
  },
  {
    "path": "share/shaders/FlowTubes.frag",
    "content": "// Basic fragment shader. Maps the fValue onto a color using the LUT then applies Phong lighting.\n#version 330 core\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform vec3 lightDir = vec3(0, 0, -1);\nuniform bool lightingEnabled = true;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\nuniform vec3 scales;\n\nin float fValue;\nin float fFade;\nin vec3  fNormal;\nout vec4 fragment;\n\nuniform float phongAmbient;\nuniform float phongDiffuse;\nuniform float phongSpecular;\nuniform float phongShininess;\nfloat PhongLighting(vec3 normal, vec3 viewDir)\n{\n\tif (!lightingEnabled)\n\t\treturn 1.0;\n    \n    vec3 lightDir = viewDir;\n\n    float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse;\n\n    float specularStrength = phongSpecular;\n    vec3 reflectDir = reflect(lightDir, normal);\n    float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess);\n    float specular = specularStrength * spec;\n\n    return max(phongAmbient + diffuse + specular, phongAmbient);\n}\n\nvoid main() {\n    vec4 color;\n    if (constantColorEnabled)\n        color = vec4(constantColor, 1.0f);\n    else\n        color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n    if (lightingEnabled) {\n\t\tvec3 normal;\n\t\tif (gl_FrontFacing)\n\t\t\tnormal = -fNormal;\n\t\telse \n\t\t\tnormal = fNormal;\n\n\t\tvec3 ld = normalize(lightDir * scales);\n        // float diffuse = max(dot(normal, ld), 0.0);\n        // color.rgb *= max(diffuse, 0.2f);\n        color.rgb *= PhongLighting(normal, ld);\n    }\n\n    color.a *= fFade;\n    if (fFade < 0.05)\n        discard;\n\n    fragment = color;\n    \n    if (color.a < 0.05) discard;\n}\n\n"
  },
  {
    "path": "share/shaders/FlowTubes.geom",
    "content": "// This shader generates tubes between every pair of vertices in a line. \n// The tube is generated as a triangle strip. This geometry is generated at the origin\n// and transformed with a simple affine tranformation using basis vectors.\n// \n// EmitWorld(vec3 v) projects v and emits it.\n// CylinderVert(v, ...) is a helper function that generates a point on a circle\n// given the parameters and passes it to EmitWorld.\n\n#version 330 core\n\n#include FlowInclude.geom\n\n#define REFINEMENT 7\n\nlayout (lines_adjacency) in;\nlayout (triangle_strip, max_vertices = 16) out; // 7 * 2 + 2\n\n\nin  float gValue[];\nin  float clip[];\nout float fValue;\nout float fFade;\nout vec3 fNormal;\n\n\nuniform mat4 P;\nuniform mat4 MV;\nuniform vec3 scales;\nuniform float radius = 0.05;\n\nvoid EmitWorld(const vec3 v);\nvoid CylinderVert(const vec3 v, const vec3 d, const float fade, const float value);\n\n\nvoid main()\n{\n    if (clip[1] < 0.0 || clip[2] < 0.0)\n        return;\n\n    vec3 V[4];\n    for (int i = 0; i < 4; i++)\n        V[i] = gl_in[i].gl_Position.xyz;\n\n    vec3 VN[3];\n    for (int i = 0; i < 3; i++)\n        VN[i] = normalize(V[i+1] - V[i]);\n\n    vec3 N[2];\n    vec3 up = vec3(0, 0, 1);\n    bool parallelToUpChanged = false;\n    for (int i = 0; i < 2; i++) {\n        N[i] = normalize((VN[i] + VN[i+1])/2);\n        if (1 - dot(N[i], up) < FLT_EPSILON)\n            parallelToUpChanged = true;\n    }\n\n    if (parallelToUpChanged)\n        up = vec3(1, 0, 0);\n\n    vec3 XH[2];\n    vec3 YH[2];\n    for (int i = 0; i < 2; i++) {\n        XH[i] = normalize(cross(N[i], up));\n        YH[i] = normalize(cross(XH[i], N[i]));\n    }\n\n    vec2 fade = CalculateFade();\n\n    for (int i = 0; i < REFINEMENT + 1; i++) {\n        float t = float(i)/float(REFINEMENT) * 2.f * PI;\n        vec3 D[2];\n        for (int j = 0; j < 2; j++)\n            D[j] = XH[j]*cos(t) + YH[j]*sin(t);\n\n        CylinderVert(V[1], D[0], fade[0],  gValue[1]);\n        CylinderVert(V[2], D[1], fade[1],  gValue[2]);\n    }\n    EndPrimitive();\n} \n\n\nvoid EmitWorld(const vec3 v)\n{\n    gl_Position = P * MV * vec4(v, 1.0f);\n    EmitVertex();\n}\n\n\nvoid CylinderVert(const vec3 v, const vec3 d, const float fade, const float value)\n{\n    fNormal = d;\n    fValue = value;\n    fFade = fade;\n    vec3 offset = d*radius;\n    offset /= scales;\n    EmitWorld(v + offset);\n}\n\n"
  },
  {
    "path": "share/shaders/FlowTubes.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\nuniform vec4 clippingPlanes[6];\n// out float gl_ClipDistance[6];\nout float clip;\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = vec4(vPos, 1.0f);\n\n    clip = 0;\n\tfor (int i = 0; i < 6; i++)\n\t\tclip -= 0.0 > dot(vec4(vPos, 1.0), clippingPlanes[i]) ? 1.0 : 0.0;\n}\n"
  },
  {
    "path": "share/shaders/Framebuffer.frag",
    "content": "#version 330 core\n\nuniform sampler2D colorBuffer;\nuniform sampler2D depthBuffer;\n\nin vec2 ST;\n\nout vec4 fragColor;\n\nvoid main(void)\n{\n    fragColor = texture(colorBuffer, ST);\n    gl_FragDepth = texture(depthBuffer, ST).r;\n}\n"
  },
  {
    "path": "share/shaders/Framebuffer.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/FramebufferND.frag",
    "content": "#version 330 core\n\n// Draw framebuffer while translating OSPRay depth buffer to OpenGL depth buffer.\n\nuniform mat4 MVP;\nuniform vec3 camPos;\nuniform vec3 camDir;\nuniform sampler2D colorBuffer;\nuniform sampler2D depthBuffer;\n\nin vec2 ST;\n\nout vec4 fragColor;\n\nfloat CalculateDepth(float d)\n{\n    vec4 ndc = MVP * vec4(camPos + camDir*d, 1);\n    ndc.xyz /= ndc.w;\n    return 0.5 * (gl_DepthRange.diff * ndc.z + (gl_DepthRange.near + gl_DepthRange.far));\n}\n\nvoid main(void)\n{\n    fragColor = texture(colorBuffer, ST);\n    gl_FragDepth = CalculateDepth(texture(depthBuffer, ST).r);\n}\n"
  },
  {
    "path": "share/shaders/FramebufferND.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/GenerateBBTraversals.pl",
    "content": "#########################################################\n#                         Notes                         #\n#########################################################\n# \n# This code generates functions with the same signature and functionality as\n# SearchSideForInitialCell but using the BB traversal\n# The functions will be called SearchSideForInitialCellWithOctree_{1-8}Levels\n# \n# Below there is a parametric non-recursive function but it is very slow in GLSL\n# \n#\n#########################################################\n#              Example 2 Level Traversal                #\n#########################################################\n# \n# bool SearchSideForInitialCellWithOctree_2Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1)\n# {\n#     ivec3 side = GetFaceFromFaceIndex(sideID);\n#     ivec3 index = (side+1)/2 * (cellDims-1);\n#     \n#     ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n#     ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n#     \n#     for (int y1 = 0; y1 < lDims1.y; y1++) {\n#         for (int x1 = 0; x1 < lDims1.x; x1++) {\n#             if (IntersectRaySideCellBBoxDirect(origin, dir, x1, y1, sideID, 1)) {\n#                 int y0End = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n#                 int x0End = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n#                 \n#                 for (int y0 = y1*2; y0 < y0End; y0++) {\n#                     for (int x0 = x1*2; x0 < lDims0.x; x0++) {\n#                         if (IntersectRaySideCellBBoxDirect(origin, dir, x0, y0, sideID, 0)) {\n#                             index[slowDim] = y0;\n#                             index[fastDim] = x0;\n#                             if (IntersectRayCellFace(origin, dir, index, side, t1)) {\n#                                 if (IsRayEnteringCell(dir, index, side)) {\n#                                     cellIndex = index;\n#                                     entranceFace = side;\n#                                     return true;\n#                                 }\n#                             }\n#                             \n#                         }\n#                     }\n#                 }\n#             }\n#         }\n#     }\n#     return false;\n# }\n# \n#########################################################\n#               Non-Recursive Traversal                 #\n#########################################################\n# \n# bool SearchSideForInitialCellWithOctreeParametric(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1)\n# {\n#     ivec3 side = GetFaceFromFaceIndex(sideID);\n#     ivec3 index = (side+1)/2 * (cellDims-1);\n#     \n#     #define MAX_LEVELS 8\n#     int x[MAX_LEVELS];\n#     int y[MAX_LEVELS];\n#     int xEnd[MAX_LEVELS];\n#     int yEnd[MAX_LEVELS];\n#     ivec2 dims[MAX_LEVELS];\n#     \n#     for (int i = 0; i < BBLevels; i++)\n#     dims[i] = GetBBoxArrayDimensions(sideID, i);\n#     \n#     \n#     int L = min(BBLevels-1, MAX_LEVELS-1);\n#     int dL = 0;\n#     \n#     xEnd[L] = dims[L].x;\n#     yEnd[L] = dims[L].y;\n#     \n#     while (true) {\n#         for (y[L] = 0; y[L] < yEnd[L] && dL==0; y[L]++) {\n#             for (x[L] = 0; x[L] < xEnd[L] && dL==0; x[L]++) {\n#                 if (IntersectRaySideCellBBoxDirect(origin, dir, x[L], y[L], sideID, L)) {\n#                     if (L == 0) {\n#                         index[slowDim] = y[L];\n#                         index[fastDim] = x[L];\n#                         if (IntersectRayCellFace(origin, dir, index, side, t1)) {\n#                             if (IsRayEnteringCell(dir, index, side)) {\n#                                 cellIndex = index;\n#                                 entranceFace = side;\n#                                 return true;\n#                             }\n#                         }\n#                     } else {\n#                         dL = -1;\n#                         xEnd[L-1] = x[L] == dims[L].x-1 ? dims[L-1].x : (x[L]+1)*2;\n#                         yEnd[L-1] = y[L] == dims[L].y-1 ? dims[L-1].y : (y[L]+1)*2;\n#                     }\n#                 }\n#             }\n#         }\n#         if (dL == -1) {\n#             L--;\n#             dL = 0;\n#         } else {\n#             break;\n#         }\n#     }\n#     return false;\n# }\n# \n# \n# \n# \n# \n# \n# \n#########################################################\n#                    Generate Code                      #\n#########################################################\n\nsub IncrementSpacing {\n\tmy ($str, $n) = @_;\n\tmy $tabs = \"\\t\"x$n;\n\t$str =~ s/^/$tabs/mg;\n\treturn $str;\n}\n\nsub Loop {\n\tmy ($L) = @_;\n\tmy $Lup = $L+1;\n\n\tmy $ret =\"\nfor (int y$L = y$Lup*2; y$L < yEnd$L; y$L++) {\nfor (int x$L = x$Lup*2; x$L < xEnd$L; x$L++) {\nif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x$L, y$L, sideID, $L)) {\n\";\n\tif ($L > 0) {\n\t\tmy $LN = $L-1;\n\n\t\t$ret .=\"\n\tint yEnd$LN = y$L == lDims$L.y-1 ? lDims$LN.y : (y$L+1)*2;\n\tint xEnd$LN = x$L == lDims$L.x-1 ? lDims$LN.x : (x$L+1)*2;\";\n\t\t$ret .=\"\\n\";\n\n\n\t\t$ret .= IncrementSpacing(Loop($LN), 1);\n\t} else {\n\t\t$ret .=\"\n\tindex[slowDim] = y0;\n\tindex[fastDim] = x0;\n\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\tintersections++;\n\";\n\n\t}\n\n\t$ret .= \"\n\n}\n}\n}\n\";\n\treturn $ret;\n}\n\nsub Function {\n\tmy ($levels) = @_;\n\tmy $ret =\n\"int SearchSideForInitialCellWithOctree_${levels}Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\";\n\n\n\tfor (my $i = 0; $i < $levels; $i++) {\n\t\t$ret .= \"\tivec2 lDims$i = GetBBoxArrayDimensions(sideID, $i);\\n\"\n\t}\n\n\tmy $L = $levels-1;\n\t$ret .= \"\n\tint yEnd$L = lDims$L.y;\n\tint xEnd$L = lDims$L.x;\n\tint x${levels} = 0;\n\tint y${levels} = 0;\n\";\n\n\t$ret .= IncrementSpacing(Loop($L), 1);\n\t$ret .= \"\n\treturn intersections;\n}\n\\n\";\n\n\treturn $ret;\n};\n\n\n\nprint \"// ---------------------------------------------\\n\";\nprint \"// This file is generated by $0\\n\";\nprint \"// Any changes made to this file will be lost\\n\";\nprint \"// ---------------------------------------------\\n\";\nprint \"\\n\\n\";\n\nfor (my $i = 1; $i <= 8; $i++) {\n\tprint Function($i);\n}\n"
  },
  {
    "path": "share/shaders/GenerateBBTraversalsNvidia.pl",
    "content": "#########################################################\n#                         Notes                         #\n#########################################################\n# \n# This code generates functions with the same signature and functionality as\n# SearchSideForInitialCell but using the BB traversal\n# The functions will be called SearchSideForInitialCellWithOctree_{1-8}Levels\n# \n# Below there is a parametric non-recursive function but it is very slow in GLSL\n# \n#\n#########################################################\n#              Example 2 Level Traversal                #\n#########################################################\n# \n# bool SearchSideForInitialCellWithOctree_2Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1)\n# {\n#     ivec3 side = GetFaceFromFaceIndex(sideID);\n#     ivec3 index = (side+1)/2 * (cellDims-1);\n#     \n#     ivec2 lDims1 = GetBBoxArrayDimensions(sideID, 1);\n#     ivec2 lDims0 = GetBBoxArrayDimensions(sideID, 0);\n#     \n#     for (int y1 = 0; y1 < lDims1.y; y1++) {\n#         for (int x1 = 0; x1 < lDims1.x; x1++) {\n#             if (IntersectRaySideCellBBoxDirect(origin, dir, x1, y1, sideID, 1)) {\n#                 int y0End = y1 == lDims1.y-1 ? lDims0.y : (y1+1)*2;\n#                 int x0End = x1 == lDims1.x-1 ? lDims0.x : (x1+1)*2;\n#                 \n#                 for (int y0 = y1*2; y0 < y0End; y0++) {\n#                     for (int x0 = x1*2; x0 < lDims0.x; x0++) {\n#                         if (IntersectRaySideCellBBoxDirect(origin, dir, x0, y0, sideID, 0)) {\n#                             index[slowDim] = y0;\n#                             index[fastDim] = x0;\n#                             if (IntersectRayCellFace(origin, dir, index, side, t1)) {\n#                                 if (IsRayEnteringCell(dir, index, side)) {\n#                                     cellIndex = index;\n#                                     entranceFace = side;\n#                                     return true;\n#                                 }\n#                             }\n#                             \n#                         }\n#                     }\n#                 }\n#             }\n#         }\n#     }\n#     return false;\n# }\n# \n#########################################################\n#               Non-Recursive Traversal                 #\n#########################################################\n# \n# bool SearchSideForInitialCellWithOctreeParametric(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1)\n# {\n#     ivec3 side = GetFaceFromFaceIndex(sideID);\n#     ivec3 index = (side+1)/2 * (cellDims-1);\n#     \n#     #define MAX_LEVELS 8\n#     int x[MAX_LEVELS];\n#     int y[MAX_LEVELS];\n#     int xEnd[MAX_LEVELS];\n#     int yEnd[MAX_LEVELS];\n#     ivec2 dims[MAX_LEVELS];\n#     \n#     for (int i = 0; i < BBLevels; i++)\n#     dims[i] = GetBBoxArrayDimensions(sideID, i);\n#     \n#     \n#     int L = min(BBLevels-1, MAX_LEVELS-1);\n#     int dL = 0;\n#     \n#     xEnd[L] = dims[L].x;\n#     yEnd[L] = dims[L].y;\n#     \n#     while (true) {\n#         for (y[L] = 0; y[L] < yEnd[L] && dL==0; y[L]++) {\n#             for (x[L] = 0; x[L] < xEnd[L] && dL==0; x[L]++) {\n#                 if (IntersectRaySideCellBBoxDirect(origin, dir, x[L], y[L], sideID, L)) {\n#                     if (L == 0) {\n#                         index[slowDim] = y[L];\n#                         index[fastDim] = x[L];\n#                         if (IntersectRayCellFace(origin, dir, index, side, t1)) {\n#                             if (IsRayEnteringCell(dir, index, side)) {\n#                                 cellIndex = index;\n#                                 entranceFace = side;\n#                                 return true;\n#                             }\n#                         }\n#                     } else {\n#                         dL = -1;\n#                         xEnd[L-1] = x[L] == dims[L].x-1 ? dims[L-1].x : (x[L]+1)*2;\n#                         yEnd[L-1] = y[L] == dims[L].y-1 ? dims[L-1].y : (y[L]+1)*2;\n#                     }\n#                 }\n#             }\n#         }\n#         if (dL == -1) {\n#             L--;\n#             dL = 0;\n#         } else {\n#             break;\n#         }\n#     }\n#     return false;\n# }\n# \n# \n# \n# \n# \n# \n# \n#########################################################\n#                    Generate Code                      #\n#########################################################\n\nsub IncrementSpacing {\n\tmy ($str, $n) = @_;\n\tmy $tabs = \"\\t\"x$n;\n\t$str =~ s/^/$tabs/mg;\n\treturn $str;\n}\n\nsub Loop {\n\tmy ($L) = @_;\n\tmy $Lup = $L+1;\n\n\tmy $ret =\"\n// for (int y$L = y$Lup*2; y$L < yEnd$L; y$L++) {\nint y$L = y$Lup*2;\nfor (int x$L = x$Lup*2; x$L < xEnd$L && y$L < yEnd$L; x$L++) {\nif (IntersectRaySideCellBBoxDirect(origin, dir, t0, x$L, y$L, sideID, $L)) {\n\";\n\tif ($L > 0) {\n\t\tmy $LN = $L-1;\n\n\t\t$ret .=\"\n\tint yEnd$LN = y$L == lDims$L.y-1 ? lDims$LN.y : (y$L+1)*2;\n\tint xEnd$LN = x$L == lDims$L.x-1 ? lDims$LN.x : (x$L+1)*2;\";\n\t\t$ret .=\"\\n\";\n\n\n\t\t$ret .= IncrementSpacing(Loop($LN), 1);\n\t} else {\n\t\t$ret .=\"\n\tindex[slowDim] = y0;\n\tindex[fastDim] = x0;\n\tif (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n\t\tintersections++;\n\";\n\n\t}\n\n\t$ret .= \"\n}\nif (x$L == xEnd$L-1) {\n\tx$L = x$Lup*2-1;\n\ty$L++;\n}\n}\n\";\n\treturn $ret;\n}\n\nsub Function {\n\tmy ($levels) = @_;\n\tmy $ret =\n\"int SearchSideForInitialCellWithOctree_${levels}Levels(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\tint intersections = 0;\n\n\n\";\n\n\n\tfor (my $i = 0; $i < $levels; $i++) {\n\t\t$ret .= \"\tivec2 lDims$i = GetBBoxArrayDimensions(sideID, $i);\\n\"\n\t}\n\n\tmy $L = $levels-1;\n\t$ret .= \"\n\tint yEnd$L = lDims$L.y;\n\tint xEnd$L = lDims$L.x;\n\tint x${levels} = 0;\n\tint y${levels} = 0;\n\";\n\n\t$ret .= IncrementSpacing(Loop($L), 1);\n\t$ret .= \"\n\treturn intersections;\n}\n\\n\";\n\n\treturn $ret;\n};\n\n\n\nprint \"// ---------------------------------------------\\n\";\nprint \"// This file is generated by $0\\n\";\nprint \"// Any changes made to this file will be lost\\n\";\nprint \"// ---------------------------------------------\\n\";\nprint \"\\n\\n\";\n\nfor (my $i = 1; $i <= 8; $i++) {\n\tprint Function($i);\n}\n"
  },
  {
    "path": "share/shaders/GenerateUniversalBBTraversal.pl",
    "content": "#########################################################\n#                         Notes                         #\n#########################################################\n# \n# This code generates a single function that supports N\n# levels with an unrolled loop. We need to support up to\n# 12 levels for a 4096 grid and. It turns out, up to 9\n# levels, it performs 10% slower than a function that only\n# supports N levels but I found that if you generate a\n# function that supports 12 levels, if you render a 9 level\n# grid, it performs 120% slower.\n#\n# This code is only here because I don't feel like deleting\n# it right now.\n#\n# Please refer to GenerateBBTraversals.pl\n# \n#########################################################\n#                    Generate Code                      #\n#########################################################\n\nsub IncrementSpacing {\n\tmy ($str, $n) = @_;\n\tmy $tabs = \"\\t\"x$n;\n\t$str =~ s/^/$tabs/mg;\n\treturn $str;\n}\n\nsub Loop {\n\tmy ($L) = @_;\n\tmy $Lup = $L+1;\n\n\tmy $ret =\"\nfor (int y$L = y$Lup*2; y$L < yEnd$L; y$L++) {\nfor (int x$L = x$Lup*2; x$L < xEnd$L; x$L++) {\nif (IntersectRaySideCellBBoxDirect(origin, dir, x$L, y$L, sideID, $L) || BBLevels <= $L) {\n\";\n\tif ($L > 0) {\n\t\tmy $LN = $L-1;\n\n\t\t$ret .=\"\n\tint yEnd$LN = y$L == lDims$L.y-1 ? lDims$LN.y : (y$L+1)*2;\n\tint xEnd$LN = x$L == lDims$L.x-1 ? lDims$LN.x : (x$L+1)*2;\";\n\t\t$ret .=\"\\n\";\n\n\n\t\t$ret .= IncrementSpacing(Loop($LN), 1);\n\t} else {\n\t\t$ret .=\"\n\tindex[slowDim] = y0;\n\tindex[fastDim] = x0;\n\tif (IsFaceThatPassedBBTheInitialCell(origin, dir, index, side, cellIndex, entranceFace, t1))\n\t\treturn true;\n\";\n\n\t}\n\n\t$ret .= \"\n\n}\n}\n}\n\";\n\treturn $ret;\n}\n\nsub Function {\n\tmy ($levels) = @_;\n\tmy $ret = \"bool SearchSideForInitialCellWithOctree(vec3 origin, vec3 dir, float t0, int sideID, int fastDim, int slowDim, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1)\n{\n\tivec3 side = GetFaceFromFaceIndex(sideID);\n\tivec3 index = (side+1)/2 * (cellDims-1);\n\n\";\n\n\t$ret .= \"\tivec2 lDims0\";\n\tfor (my $i = 1; $i < $levels; $i++) {\n\t\t$ret .= \", lDims$i\";\n\t}\n\t$ret .= \";\\n\\n\";\n\n\t$ret .= \"\tlDims0 = GetBBoxArrayDimensions(sideID, 0);\\n\";\n\tfor (my $i = 1; $i < $levels; $i++) {\n\t\t$ret .= \"\tif (BBLevels > $i) lDims$i = GetBBoxArrayDimensions(sideID, $i); else lDims$i = ivec2(1);\\n\";\n\t}\n\n\tmy $L = $levels-1;\n\t$ret .= \"\n\tint yEnd$L = lDims$L.y;\n\tint xEnd$L = lDims$L.x;\n\tint x${levels} = 0;\n\tint y${levels} = 0;\n\";\n\n\t$ret .= IncrementSpacing(Loop($L), 1);\n\t$ret .= \"\n\treturn false;\n}\n\\n\";\n\n\treturn $ret;\n};\n\n\nprint Function(12);\n"
  },
  {
    "path": "share/shaders/Image.frag",
    "content": "#version 330 core\n\nuniform sampler2D sampler;\nuniform float constantOpacity;\n\nin vec2 TextureCoord;\n\nout vec4 fragColor;\n\nvoid main(void)\n{\n\tvec4 color = texture(sampler, TextureCoord);\n\n\t// Legacy vapor behavior\n\tif (color.a <= 0.1)\n\t\tdiscard;\n\n\tfragColor = vec4(color.rgb, color.a * constantOpacity);\n}\n"
  },
  {
    "path": "share/shaders/Image.vert",
    "content": "#version 330 core\n\nuniform mat4 MVP;\n\nlayout (location = 0) in vec3 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 TextureCoord;\n\nuniform vec4 clippingPlanes[6];\nout float gl_ClipDistance[6];\n\nvoid main()\n{\n\tgl_Position = MVP * vec4(vertex, 1.0);\n\tTextureCoord = vTextureCoord;\n\n\tfor (int i = 0; i < 6; i++)\n\t\tgl_ClipDistance[i] = dot(vec4(vertex, 1.0), clippingPlanes[i]);\n}\n"
  },
  {
    "path": "share/shaders/Legacy.frag",
    "content": "#version 330 core\n\nuniform bool lightingEnabled;\nuniform bool textureEnabled;\nuniform vec3 lightDir;\n\nuniform sampler2D sampler;\n\nin  vec4 fColor;\nin  vec3 fNormal;\nin  vec2 fTextureCoords;\nout vec4 fragment;\n\nvoid main() {\n    vec4 color = fColor;\n\tif (textureEnabled) {\n\t\tcolor *= texture(sampler, fTextureCoords);\n\t}\n    if (lightingEnabled) {\n\t\tvec3 normal;\n\t\tif (gl_FrontFacing)\n\t\t\tnormal = fNormal;\n\t\telse \n\t\t\tnormal = -fNormal;\n\n        float diffuse = max(dot(normal, -lightDir), 0.0);\n        color.rgb *= max(diffuse, 0.2f);\n    }\n    fragment = color;\n}\n"
  },
  {
    "path": "share/shaders/Legacy.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in vec3 vNormal;\nlayout (location = 2) in vec4 vColor;\nlayout (location = 3) in vec2 vTextureCoords;\n\nout vec3 fNormal;\nout vec4 fColor;\nout vec2 fTextureCoords;\n\nuniform mat4 P;\nuniform mat4 MV;\n\n\nvoid main() {\n    gl_Position = P * MV * vec4(vPos, 1.0f);\n//    fNormal = mat3(transpose(inverse(MV))) * vNormal;\n    fNormal = vNormal;\n    fColor = vColor;\n\tfTextureCoords = vTextureCoords;\n}\n"
  },
  {
    "path": "share/shaders/ParticleDirection.frag",
    "content": "// Basic fragment shader. Maps the fValue onto a color using the LUT then applies Phong lighting.\n#version 330 core\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform vec3 lightDir = vec3(0, 0, -1);\nuniform bool lightingEnabled = true;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\nuniform vec3 scales;\n\nin float fValue;\nin vec3  fNormal;\nout vec4 fragment;\n\nuniform float phongAmbient;\nuniform float phongDiffuse;\nuniform float phongSpecular;\nuniform float phongShininess;\nfloat PhongLighting(vec3 normal, vec3 viewDir)\n{\n\tif (!lightingEnabled)\n\t\treturn 1.0;\n    \n    vec3 lightDir = viewDir;\n\n    float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse;\n\n    float specularStrength = phongSpecular;\n    vec3 reflectDir = reflect(lightDir, normal);\n    float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess);\n    float specular = specularStrength * spec;\n\n    return max(phongAmbient + diffuse + specular, phongAmbient);\n}\n\nvoid main() {\n    // fragment = vec4(1,0,1,1);\n    //fragment = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n    //return;\n\n    vec4 color;\n    if (constantColorEnabled)\n        color = vec4(constantColor, 1.0f);\n    else\n        color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n    if (lightingEnabled) {\n\t\tvec3 normal;\n\t\tif (gl_FrontFacing)\n\t\t\tnormal = -fNormal;\n\t\telse \n\t\t\tnormal = fNormal;\n\n\t\tvec3 ld = normalize(lightDir * scales);\n        // float diffuse = max(dot(normal, ld), 0.0);\n        // color.rgb *= max(diffuse, 0.2f);\n        color.rgb *= PhongLighting(normal, ld);\n    }\n\n    fragment = color;\n    \n    if (color.a < 0.05) discard;\n}\n\n"
  },
  {
    "path": "share/shaders/ParticleDirection.geom",
    "content": "// This shader generates tubes between every pair of vertices in a line. \n// The tube is generated as a triangle strip. This geometry is generated at the origin\n// and transformed with a simple affine transformation using basis vectors.\n// \n// EmitWorld(vec3 v) projects v and emits it.\n// CylinderVert(v, ...) is a helper function that generates a point on a circle\n// given the parameters and passes it to EmitWorld.\n\n#version 330 core\n\n#include FlowInclude.geom\n\n#define REFINEMENT 7\n\nlayout (points) in;\nlayout (triangle_strip, max_vertices = 16) out; // 7 * 2 + 2\n//layout (line_strip, max_vertices = 64) out; // 7 * 2 + 2\n//layout (points, max_vertices = 64) out; // 7 * 2 + 2\n\n\nin  vec3 gNorm[];\nin  float gValue[];\nout float fValue;\nout vec3 fNormal;\n\n\n#ifdef DYNAMIC_RADIUS\nin float gRadius[];\n#endif\n\n\nuniform mat4 P;\nuniform mat4 MV;\nuniform vec3 scales;\nuniform float radius = 0.05;\nuniform float dirScale = 0.05;\n\nvoid EmitWorld(const vec3 v);\nvoid CylinderVert(const vec3 v, const vec3 d, const float value, const float radius);\n\n\nvoid main()\n{\n    //fValue = gValue[0];\n    //EmitWorld(gl_in[0].gl_Position.xyz);\n    //EmitWorld(gl_in[0].gl_Position.xyz + gNorm[0] * dirScale);\n    //EndPrimitive();\n    //return;\n\n    vec3 V[2];\n    V[0] = gl_in[0].gl_Position.xyz;\n\n    vec3 N = gNorm[0];\n    V[1] = V[0] + N * dirScale;\n\n    vec3 up = vec3(0, 0, 1);\n    bool parallelToUpChanged = false;\n    if (1 - dot(N, up) < FLT_EPSILON)\n        parallelToUpChanged = true;\n\n    if (parallelToUpChanged)\n        up = vec3(1, 0, 0);\n\n    vec3 XH;\n    vec3 YH;\n    XH = normalize(cross(N, up));\n    YH = normalize(cross(XH, N));\n\n    #ifdef DYNAMIC_RADIUS\n        float finalRadius = radius * gRadius[0];\n    #else\n        float finalRadius = radius;\n    #endif\n\n    vec2 fade = CalculateFade();\n\n    //fNormal = vec3(1,0,0); fValue = 1; EmitWorld(gl_in[0].gl_Position.xyz); EmitWorld(gl_in[1].gl_Position.xyz); EndPrimitive(); return;\n\n    for (int i = 0; i < REFINEMENT + 1; i++) {\n        float t = float(i)/float(REFINEMENT) * 2.f * PI;\n        vec3 D;\n        D = XH*cos(t) + YH*sin(t);\n\n        CylinderVert(V[0], D, gValue[0], finalRadius);\n        CylinderVert(V[1], D, gValue[0], finalRadius);\n    }\n    EndPrimitive();\n} \n\n\nvoid EmitWorld(const vec3 v)\n{\n    gl_Position = P * MV * vec4(v, 1.0f);\n    EmitVertex();\n}\n\n\nvoid CylinderVert(const vec3 v, const vec3 d, const float value, const float radius)\n{\n    fNormal = d;\n    fValue = value;\n    vec3 offset = d*radius;\n    offset /= scales;\n    EmitWorld(v + offset);\n}\n\n"
  },
  {
    "path": "share/shaders/ParticleDirection.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in vec3 vNorm;\nlayout (location = 2) in float vValue;\n\nout vec3 gNorm;\nout float gValue;\n\n#ifdef DYNAMIC_RADIUS\nlayout (location = 3) in float vRadius;\nout float gRadius;\n#endif\n\nvoid main() {\n    gValue = vValue;\n    gNorm = vNorm;\n    gl_Position = vec4(vPos, 1.0f);\n\n    #ifdef DYNAMIC_RADIUS\n        gRadius = vRadius;\n    #endif\n}\n"
  },
  {
    "path": "share/shaders/ParticlePoint.frag",
    "content": "// Maps the fValue onto a color using the LUT then applies Phong lighting.\n// Using the texture coordinates of the billboard it caclulates the bounds and normals of a sphere\n// which is then used for the lighting calculation.\n\n#version 330 core\n\n#define PI (3.1415926)\n\nuniform bool constantColorEnabled = false;\nuniform vec3 constantColor = vec3(1.0f);\nuniform vec3 lightDir = vec3(0, 0, -1);\nuniform bool lightingEnabled = true;\n\nuniform sampler1D LUT;\nuniform vec2 mapRange;\nuniform vec3 scales;\n\nin float fValue;\nin  vec2 fC;\nout vec4 fragment;\n\nuniform float phongAmbient;\nuniform float phongDiffuse;\nuniform float phongSpecular;\nuniform float phongShininess;\nfloat PhongLighting(float theta)\n{\n\tif (!lightingEnabled)\n\t\treturn 1.0;\n\n\tfloat ct = cos(theta);\n    float diffuse = ct * phongDiffuse;\n    float specular = phongSpecular * pow(ct, phongShininess);\n    return max(phongAmbient + diffuse + specular, phongAmbient);\n}\n\nvoid main() {\n    vec4 color;\n    if (constantColorEnabled)\n        color = vec4(constantColor, 1.0f);\n    else\n        color = texture(LUT, (fValue - mapRange.x) / (mapRange.y - mapRange.x));\n\n\tfloat a = length(fC); // Length of a right angle triangle with a hypontenuse going from the origin to the sphere surface.\n\tfloat t = acos(a); // Angle of triangle\n\tfloat t2 = PI/2.0 - t; // Reflected angle\n\n\tif (a > 1)\n\t\tdiscard;\n\n\tcolor.rgb *= PhongLighting(t2);\n    fragment = color;\n    \n    if (color.a < 0.05) discard;\n}\n"
  },
  {
    "path": "share/shaders/ParticlePoint.geom",
    "content": "// This generates a billboard with a width and height equal to the diameter the sphere\n\n#version 330 core\n\n#define REFINEMENT 10\n\nlayout (points) in;\nlayout (triangle_strip, max_vertices = 4) out;\n\n\nin  float gValue[];\nout float fValue;\nout vec2 fC;\n\n\n#ifdef DYNAMIC_RADIUS\nin float gRadius[];\n#endif\n\n\nuniform mat4 P;\nuniform mat4 MV;\nuniform vec3 cameraPos;\nuniform vec3 scales;\nuniform float radius = 0.05;\n\n\nvoid EmitWorld(const vec3 v);\n\n\nvoid main()\n{\n    fValue = gValue[0];\n    vec3 o = gl_in[0].gl_Position.xyz;\n\n\t// Plane perpendicular to camera normal\n\tvec3 up = vec3(0.0, 0.0, 1.0);\n\tvec3 toCamera = normalize(cameraPos - o);\n\tvec3 xh = normalize(cross(up, toCamera));\n\tvec3 yh = normalize(cross(toCamera, xh));\n\txh /= scales;\n\tyh /= scales;\n\n\t#ifdef DYNAMIC_RADIUS\n        float finalRadius = radius * gRadius[0];\n    #else\n        float finalRadius = radius;\n    #endif\n\n\t// Billboard\n\tfC = vec2(-1.0, -1.0); EmitWorld(o + finalRadius * (-xh + -yh));\n\tfC = vec2( 1.0, -1.0); EmitWorld(o + finalRadius * ( xh + -yh));\n\tfC = vec2(-1.0,  1.0); EmitWorld(o + finalRadius * (-xh +  yh));\n\tfC = vec2( 1.0,  1.0); EmitWorld(o + finalRadius * ( xh +  yh));\n\tEndPrimitive();\n} \n\n\nvoid EmitWorld(const vec3 v)\n{\n    gl_Position = P * MV * vec4(v, 1.0f);\n    EmitVertex();\n}\n"
  },
  {
    "path": "share/shaders/ParticlePoint.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float vValue;\n\nout float gValue;\n\n#ifdef DYNAMIC_RADIUS\nlayout (location = 2) in float vRadius;\nout float gRadius;\n#endif\n\nvoid main() {\n    gValue = vValue;\n    gl_Position = vec4(vPos, 1.0f);\n\n    #ifdef DYNAMIC_RADIUS\n        gRadius = vRadius;\n    #endif\n}\n"
  },
  {
    "path": "share/shaders/ProgTexture.efc",
    "content": "ProgTexture\nProgTexture\nProgTexture"
  },
  {
    "path": "share/shaders/Slice.frag",
    "content": "#version 330 core\n\nuniform sampler1D colormap;\nuniform sampler2D dataValues;\n\nuniform float minLUTValue;\nuniform float maxLUTValue;\nuniform float constantOpacity;\n\nin  vec2 fTexCoord;\nout vec4 fragColor;\n\nvoid main(void)\n{\n\tif (minLUTValue > maxLUTValue) discard;\n\n    float missing = texture(dataValues, fTexCoord).g;\n    if (missing != 0.f) discard; \n\n    float value = texture(dataValues, fTexCoord).r;\n    //if (isnan(value)) discard;\n\n    float normalized = (value - minLUTValue) / (maxLUTValue - minLUTValue);\n    if (maxLUTValue == minLUTValue) normalized=0.;\n\n    vec4  color = texture(colormap, normalized);\n    fragColor = vec4(color.rgb, color.a*constantOpacity);\n    \n    if (color.a <  0.001)\n        discard;\n}\n"
  },
  {
    "path": "share/shaders/Slice.vert",
    "content": "#version 330 core\n\nuniform mat4 MVP;\n\nlayout (location = 0) in vec3 vVertex;\nlayout (location = 1) in vec2 vTexCoord;\n\nout vec2 fTexCoord;\n\nuniform vec4 clippingPlanes[6];\nout float gl_ClipDistance[6];\n\nvoid main()\n{\n    fTexCoord = vTexCoord;\n\n\tgl_Position = MVP * vec4(vVertex, 1.0);\n\n\tfor (int i = 0; i < 6; i++)\n\t\tgl_ClipDistance[i] = dot(vec4(vVertex, 1.0), clippingPlanes[i]);\n}\n"
  },
  {
    "path": "share/shaders/VolumeBase.frag",
    "content": "in vec2 ST;\nout vec4 fragColor;\n\nuniform mat4 MVP;\nuniform vec3 cameraPos;\nuniform vec3 dataBoundsMin;\nuniform vec3 dataBoundsMax;\nuniform vec3 userExtsMin;\nuniform vec3 userExtsMax;\nuniform vec3 scales;\nuniform float density;\nuniform float LUTMin;\nuniform float LUTMax;\nuniform bool mapOrthoMode;\nuniform bool hasMissingData;\nuniform bool fast;\n\nuniform float samplingRateMultiplier;\nuniform bool lightingEnabled;\nuniform float phongAmbient;\nuniform float phongDiffuse;\nuniform float phongSpecular;\nuniform float phongShininess;\n\nuniform sampler3D data;\nuniform sampler1D LUT;\nuniform sampler2D sceneDepth;\nuniform sampler3D missingMask;\n\nuniform bool useColormapData;\n#ifdef USE_SECOND_DATA\nuniform bool hasMissingData2;\nuniform sampler3D data2;\nuniform sampler3D missingMask2;\nuniform sampler1D LUT2;\nuniform float LUTMin2;\nuniform float LUTMax2;\n#endif\n\nbool readDepthBuffer = true;\n\n\n#define ALPHA_BREAK 0.999\n#define ALPHA_DISCARD 0.01\n\n\n// This is *no longer* required for the Nvidia compiler to work with cell traversal\n#define OUT out\n\n\n\n#include VolumeRayMath.frag\n\nvec3 ROYGBV(float v, float minV, float maxV)\n{\n    vec3 colors[6];\n    colors[0] = vec3(1.00, 0.00, 0.00);\n    colors[1] = vec3(1.00, 0.60, 0.00);\n    colors[2] = vec3(1.00, 1.00, 0.00);\n    colors[3] = vec3(0.00, 1.00, 0.00);\n    colors[4] = vec3(0.00, 0.00, 1.00);\n    colors[5] = vec3(0.32, 0.00, 0.32);\n    float ratio = 5.0 * clamp((v-minV)/(maxV-minV), 0, 1);\n    int indexMin=int(floor(ratio));\n    int indexMax=min(int(indexMin)+1,5);\n    vec3 c = mix(colors[indexMin], colors[indexMax], ratio-indexMin);\n    return c;\n}\n\nvec3 ROYGBVE(float v, float from, float to)\n{\n    if (v < from || v > to)\n        return vec3(1);\n    return ROYGBV(v, from, to);\n}\n\nfloat GetSamplingNoise()\n{\n\t// This helps compensate for a lower sampling rate\n\t// It replaces banding artifacts with less obtrusive noise\n\n\treturn fract(sin(gl_FragCoord.x * 12.989 + gl_FragCoord.y * 78.233) * 43758.5453) * 0.1 + 1; \n}\n\nbool DoesSampleHaveMissingData(vec3 dataSTR)\n{\n    return texture(missingMask, dataSTR).r > 0;\n}\n\n#ifdef USE_SECOND_DATA\nbool DoesSampleHaveMissingData2(vec3 dataSTR)\n{\n    return texture(missingMask2, dataSTR).r > 0;\n}\n#endif\n\nbool ShouldRenderSample(const vec3 sampleSTR)\n{\n    if (hasMissingData)\n        if (DoesSampleHaveMissingData(sampleSTR))\n            return false;\n    return true;\n}\n\nfloat GetDepthBuffer()\n{\n    if (readDepthBuffer) {\n        float depth = texture(sceneDepth, ST).r;\n        return depth;\n    } else {\n        return 1.0;\n    }\n}\n\nfloat GetDepthBufferNDC()\n{\n    return GetDepthBuffer() * 2 - 1;\n}\n\nfloat PhongLighting(vec3 normal, vec3 viewDir)\n{\n\tif (!lightingEnabled)\n\t\treturn 1.0;\n    \n    vec3 lightDir = viewDir;\n\n    float diffuse = abs(dot(normal, -lightDir)) * phongDiffuse;\n\n    float specularStrength = phongSpecular;\n    vec3 reflectDir = reflect(lightDir, normal);\n    float spec = pow(abs(dot(viewDir, reflectDir)), phongShininess);\n    float specular = specularStrength * spec;\n\n    return max(phongAmbient + diffuse + specular, phongAmbient);\n}\n\nvec3 GetNormal(vec3 p)\n{\n    vec3 dims = vec3(textureSize(data, 0));\n    vec3 d = 1/dims * 0.5;\n    vec3 s0, s1;\n    s1.x = texture(data, p + d*vec3(1,0,0)).r;\n    s1.y = texture(data, p + d*vec3(0,1,0)).r;\n    s1.z = texture(data, p + d*vec3(0,0,1)).r;\n    s0.x = texture(data, p - d*vec3(1,0,0)).r;\n    s0.y = texture(data, p - d*vec3(0,1,0)).r;\n    s0.z = texture(data, p - d*vec3(0,0,1)).r;\n    \n    // glsl::normalize does not handle 0 length vectors\n    vec3 v = s1-s0;\n    float l = length(v);\n    if (l == 0)\n        return vec3(0);\n    return v/l;\n}\n\nvec4 GetColorForNormalizedCoord(vec3 sampleSTR)\n{\n    float value = texture(data, sampleSTR).r;\n    float valueNorm = (value - LUTMin) / (LUTMax - LUTMin);\n    vec4 color = texture(LUT, valueNorm);\n    \n#ifdef USE_SECOND_DATA\n    if (useColormapData) {\n        if (hasMissingData2)\n            if (DoesSampleHaveMissingData2(sampleSTR))\n                    return vec4(0);\n\n        float value2 = texture(data2, sampleSTR).r;\n        float value2Norm = (value2 - LUTMin2) / (LUTMax2 - LUTMin2);\n        color.rgb = texture(LUT2, value2Norm).rgb;\n    }\n#endif\n    \n    return color;\n}\n\nfloat CalculateDepth(vec3 pos)\n{\n\tvec4 ndc = MVP * vec4(pos, 1);\n\tndc.xyz /= ndc.w;\n\treturn 0.5 * (gl_DepthRange.diff * ndc.z + (gl_DepthRange.near + gl_DepthRange.far));\n}\n\nvec4 PremultiplyAlpha(vec4 color)\n{\n    return vec4(color.rgb * color.a, color.a);\n}\n\n// GL_ONE_MINUS_DST_ALPHA, GL_ONE\nvoid BlendToBack(inout vec4 accum, vec4 color)\n{\n    accum = color * (1-accum.a) + accum * (1);\n}\n\nvoid GetRayParameters(out vec3 eye, out vec3 dir, out vec3 normal, OUT float maxT)\n{\n\tvec2 screen = ST*2-1;\n    vec4 world = inverse(MVP) * vec4(screen, GetDepthBufferNDC(), 1);\n    if (mapOrthoMode) {\n        eye = vec3(world.xy, cameraPos.z);\n    } else {\n        world /= world.w;\n        eye = cameraPos;\n    }\n    dir = normalize(world.xyz - eye);\n    normal = normalize((world.xyz - eye) * scales);\n    maxT = length(world.xyz - eye);\n}\n"
  },
  {
    "path": "share/shaders/VolumeCellBase.frag",
    "content": "#include VolumeBase.frag\n\n// This file implements the cell traversal and provides a framework\n// for rendering a curvilinear grid.\n// It defines a Traverse function which needs to be\n// overridden that does the rendering\n\nuniform ivec3 coordDims;\nuniform float unitDistance;\nuniform float unitOpacityScalar;\nuniform int BBLevels;\n\nvec3 coordDimsF = vec3(coordDims);\nivec3 cellDims = coordDims - 1;\n\nuniform sampler3D coords;\nuniform sampler2DArray boxMins;\nuniform sampler2DArray boxMaxs;\nuniform isampler2D levelDims;\n\n// Temporary workaround\n// ivec3 skipCellWhenSearchingForInit = ivec3(-1);\n\n#define DEBUG 0\n#define DEBUG_SHOW_CELL_INDEX 0\n#define DEBUG_SHOW_GRID 0\n#define DEBUG_SHOW_NORMALS 0\n\n#if DEBUG\nvec3 dbg = vec3(-1);\nvec3 RED   = vec3(1, 0, 0);\nvec3 GREEN = vec3(0, 1, 0);\nvec3 BLUE  = vec3(0, 0, 1);\nvec3 BLACK = vec3(0, 0, 0);\nvec3 WHITE = vec3(1, 1, 1);\nvec3 PURPLE= vec3(1, 0, 1);\n\nint dbgPriority = 0;\nvoid SD(vec3 color, int priority)\n{\n    if (priority >= dbgPriority) {\n        dbg = color;\n        dbgPriority = priority;\n    }\n}\n#endif \n\nvoid DEBUG_SHOW()\n{\n#if DEBUG\n    if (dbg != vec3(-1))\n        fragColor = vec4(dbg, 1);\n#endif \n}\n\n\n#define FI_LEFT  0\n#define FI_RIGHT 1\n#define FI_UP    2\n#define FI_DOWN  3\n#define FI_FRONT 4\n#define FI_BACK  5\n#define FI_NONE 99\n\n#define F_LEFT  ivec3(-1, 0, 0)\n#define F_RIGHT ivec3( 1, 0, 0)\n#define F_UP    ivec3( 0, 0, 1)\n#define F_DOWN  ivec3( 0, 0,-1)\n#define F_FRONT ivec3( 0,-1, 0)\n#define F_BACK  ivec3( 0, 1, 0)\n#define F_NONE  ivec3(-1,-1,-1)\n\n#define CI_LEFT  0\n#define CI_RIGHT 1\n#define CI_UP    2\n#define CI_DOWN  3\n#define CI_FRONT 4\n#define CI_BACK  5\n#define CI_LEFT_FRONT  6\n#define CI_LEFT_BACK   7\n#define CI_RIGHT_FRONT 8\n#define CI_RIGHT_BACK  9\n#define CI_UP_FRONT   10\n#define CI_UP_BACK    11\n#define CI_DOWN_FRONT  12\n#define CI_DOWN_BACK   13\n#define CI_UP_LEFT    14\n#define CI_UP_RIGHT   15\n#define CI_DOWN_LEFT   16\n#define CI_DOWN_RIGHT  17\n#define CI_UP_LEFT_FRONT   18\n#define CI_UP_LEFT_BACK    19\n#define CI_UP_RIGHT_FRONT  20\n#define CI_UP_RIGHT_BACK   21\n#define CI_DOWN_LEFT_FRONT  22\n#define CI_DOWN_LEFT_BACK   23\n#define CI_DOWN_RIGHT_FRONT 24\n#define CI_DOWN_RIGHT_BACK  25\n#define CI_NONE  99\n\n#define C_LEFT  ivec3(-1, 0, 0)\n#define C_RIGHT ivec3( 1, 0, 0)\n#define C_UP    ivec3( 0, 0, 1)\n#define C_DOWN  ivec3( 0, 0,-1)\n#define C_FRONT ivec3( 0,-1, 0)\n#define C_BACK  ivec3( 0, 1, 0)\n#define C_LEFT_FRONT  (C_LEFT+C_FRONT)\n#define C_LEFT_BACK   (C_LEFT+C_BACK)\n#define C_RIGHT_FRONT (C_RIGHT+C_FRONT)\n#define C_RIGHT_BACK  (C_RIGHT+C_BACK)\n#define C_UP_FRONT    (C_UP+C_FRONT)\n#define C_UP_BACK     (C_UP+C_BACK)\n#define C_DOWN_FRONT  (C_DOWN+C_FRONT)\n#define C_DOWN_BACK   (C_DOWN+C_BACK)\n#define C_UP_LEFT     (C_UP+C_LEFT)\n#define C_UP_RIGHT    (C_UP+C_RIGHT)\n#define C_DOWN_LEFT   (C_DOWN+C_LEFT)\n#define C_DOWN_RIGHT  (C_DOWN+C_RIGHT)\n#define C_UP_LEFT_FRONT    (C_UP+C_LEFT+C_FRONT)\n#define C_UP_LEFT_BACK     (C_UP+C_LEFT+C_BACK)\n#define C_UP_RIGHT_FRONT   (C_UP+C_RIGHT+C_FRONT)\n#define C_UP_RIGHT_BACK    (C_UP+C_RIGHT+C_BACK)\n#define C_DOWN_LEFT_FRONT  (C_DOWN+C_LEFT+C_FRONT)\n#define C_DOWN_LEFT_BACK   (C_DOWN+C_LEFT+C_BACK)\n#define C_DOWN_RIGHT_FRONT (C_DOWN+C_RIGHT+C_FRONT)\n#define C_DOWN_RIGHT_BACK  (C_DOWN+C_RIGHT+C_BACK)\n#define C_NONE  ivec3(-1,-1,-1)\n\n// face   fast  slow\n// DOWN    0     1\n// UP      0     1\n// LEFT    1     2\n// RIGHT   1     2\n// FRONT   0     2\n// BACK    0     2\n\nint GetFastDimForFaceIndex(int i)\n{\n    if (i == FI_LEFT || i == FI_RIGHT)\n        return 1;\n    return 0;\n}\n\nint GetSlowDimForFaceIndex(int i)\n{\n    if (i == FI_DOWN || i == FI_UP)\n        return 1;\n    return 2;\n}\n\nivec3 GetFaceFromFaceIndex(int i)\n{\n    if (i == 0) return F_LEFT;\n    if (i == 1) return F_RIGHT;\n    if (i == 2) return F_UP;\n    if (i == 3) return F_DOWN;\n    if (i == 4) return F_FRONT;\n    if (i == 5) return F_BACK;\n}\n\nivec3 GetNeighborFromNeighborCellIndex(const int i)\n{\n    if (i == CI_LEFT)             return C_LEFT;\n    if (i == CI_RIGHT)            return C_RIGHT;\n    if (i == CI_UP)               return C_UP;\n    if (i == CI_DOWN)             return C_DOWN;\n    if (i == CI_FRONT)            return C_FRONT;\n    if (i == CI_BACK)             return C_BACK;\n    if (i == CI_LEFT_FRONT)       return C_LEFT_FRONT;\n    if (i == CI_LEFT_BACK)        return C_LEFT_BACK;\n    if (i == CI_RIGHT_FRONT)      return C_RIGHT_FRONT;\n    if (i == CI_RIGHT_BACK)       return C_RIGHT_BACK;\n    if (i == CI_UP_FRONT)         return C_UP_FRONT;\n    if (i == CI_UP_BACK)          return C_UP_BACK;\n    if (i == CI_DOWN_FRONT)       return C_DOWN_FRONT;\n    if (i == CI_DOWN_BACK)        return C_DOWN_BACK;\n    if (i == CI_UP_LEFT)          return C_UP_LEFT;\n    if (i == CI_UP_RIGHT)         return C_UP_RIGHT;\n    if (i == CI_DOWN_LEFT)        return C_DOWN_LEFT;\n    if (i == CI_DOWN_RIGHT)       return C_DOWN_RIGHT;\n    if (i == CI_UP_LEFT_FRONT)    return C_UP_LEFT_FRONT;\n    if (i == CI_UP_LEFT_BACK)     return C_UP_LEFT_BACK;\n    if (i == CI_UP_RIGHT_FRONT)   return C_UP_RIGHT_FRONT;\n    if (i == CI_UP_RIGHT_BACK)    return C_UP_RIGHT_BACK;\n    if (i == CI_DOWN_LEFT_FRONT)  return C_DOWN_LEFT_FRONT;\n    if (i == CI_DOWN_LEFT_BACK)   return C_DOWN_LEFT_BACK;\n    if (i == CI_DOWN_RIGHT_FRONT) return C_DOWN_RIGHT_FRONT;\n    if (i == CI_DOWN_RIGHT_BACK)  return C_DOWN_RIGHT_BACK;\n}\n\nint GetFaceIndexFromFace(ivec3 face)\n{\n    if (face == F_LEFT)  return FI_LEFT;\n    if (face == F_RIGHT) return FI_RIGHT;\n    if (face == F_UP)    return FI_UP;\n    if (face == F_DOWN)  return FI_DOWN;\n    if (face == F_FRONT) return FI_FRONT;\n    if (face == F_BACK)  return FI_BACK;\n}\n\nvec4 DEBUG_GetFaceColor(ivec3 face)\n{\n    if (face == F_LEFT)  return vec4(0,0,1,1); // Blue\n    if (face == F_RIGHT) return vec4(0,1,0,1); // Green\n    if (face == F_UP)    return vec4(0,1,1,1); // Cyan\n    if (face == F_DOWN)  return vec4(1,0,0,1); // Red\n    if (face == F_FRONT) return vec4(1,0,1,1); // Purple\n    if (face == F_BACK)  return vec4(1,1,0,1); // Yellow\n}\n\nvoid GetFaceCoordinateIndices(ivec3 cell, ivec3 face, OUT ivec3 i0, OUT ivec3 i1, OUT ivec3 i2, OUT ivec3 i3)\n{\n    // CCW\n    if (face == F_DOWN) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(0, 1, 0);\n        i2 = cell + ivec3(1, 1, 0);\n        i3 = cell + ivec3(1, 0, 0);\n    }\n    else if (face == F_UP) {\n        i0 = cell + ivec3(0, 0, 1);\n        i1 = cell + ivec3(1, 0, 1);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(0, 1, 1);\n    }\n    else if (face == F_LEFT) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(0, 0, 1);\n        i2 = cell + ivec3(0, 1, 1);\n        i3 = cell + ivec3(0, 1, 0);\n    }\n    else if (face == F_RIGHT) {\n        i0 = cell + ivec3(1, 0, 0);\n        i1 = cell + ivec3(1, 1, 0);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(1, 0, 1);\n    }\n    else if (face == F_FRONT) {\n        i0 = cell + ivec3(0, 0, 0);\n        i1 = cell + ivec3(1, 0, 0);\n        i2 = cell + ivec3(1, 0, 1);\n        i3 = cell + ivec3(0, 0, 1);\n    }\n    else if (face == F_BACK) {\n        i0 = cell + ivec3(0, 1, 0);\n        i1 = cell + ivec3(0, 1, 1);\n        i2 = cell + ivec3(1, 1, 1);\n        i3 = cell + ivec3(1, 1, 0);\n    }\n}\n\nvoid GetFaceCoordsAndVertices(ivec3 cellIndex, ivec3 face, OUT ivec3 i0, OUT ivec3 i1, OUT ivec3 i2, OUT ivec3 i3, OUT vec3 v0, OUT vec3 v1, OUT vec3 v2, OUT vec3 v3)\n{\n    GetFaceCoordinateIndices(cellIndex, face, i0, i1, i2, i3);\n    v0 = texelFetch(coords, i0, 0).xyz;\n    v1 = texelFetch(coords, i1, 0).xyz;\n    v2 = texelFetch(coords, i2, 0).xyz;\n    v3 = texelFetch(coords, i3, 0).xyz;\n}\n\nvoid GetFaceVertices(ivec3 cellIndex, ivec3 face, OUT vec3 v0, OUT vec3 v1, OUT vec3 v2, OUT vec3 v3)\n{\n    ivec3 i0, i1, i2, i3;\n    GetFaceCoordsAndVertices(cellIndex, face, i0, i1, i2, i3, v0, v1, v2, v3);\n}\n\nfloat GetDataCoordinateSpace(vec3 coordinates)\n{\n    return texture(data, coordinates/coordDimsF).r;\n}\n\nfloat GetDataForCoordIndex(ivec3 coordIndex)\n{\n    vec3 coord = vec3(coordIndex)+vec3(0.5);\n    return texture(data, (coord)/(coordDims-1)).r;\n}\n\nfloat NormalizeData(float data)\n{\n    return (data - LUTMin) / (LUTMax - LUTMin);\n}\n\nvec4 GetColorForNormalizedData(float normalizedData)\n{\n    return texture(LUT, normalizedData);\n}\n\nvec4 GetAverageColorForCoordIndex(ivec3 coordIndex)\n{\n    return GetColorForNormalizedData(NormalizeData(GetDataForCoordIndex(coordIndex)));\n}\n\nvec4 GetColorAtCoord(vec3 coord)\n{\n    // return GetColorForNormalizedData(NormalizeData(GetDataCoordinateSpace(coord)));\n    return GetColorForNormalizedCoord(coord/coordDimsF);\n}\n\nvec3 GetNormalAtCoord(vec3 coord)\n{\n    return GetNormal(coord/coordDimsF);\n}\n\nbool DoesCellHaveMissingData(ivec3 cellCoord)\n{\n    vec3 coord = vec3(cellCoord)+vec3(0.5);\n    return DoesSampleHaveMissingData((coord)/(coordDims-1));\n}\n\nbool IntersectRayCellFace(vec3 o, vec3 d, float rt0, ivec3 cellIndex, ivec3 face, OUT float t, OUT vec3 dataCoordinate)\n{\n    ivec3 i0, i1, i2, i3;\n    vec3 v0, v1, v2, v3;\n    GetFaceCoordsAndVertices(cellIndex, face, i0, i1, i2, i3, v0, v1, v2, v3);\n    \n    vec4 weights;\n    if (IntersectRayQuad(o, d, rt0, v0, v1, v2, v3, t, weights)) {\n        dataCoordinate = (weights.x*i0 + weights.y*i1 + weights.z*i2 + weights.w*i3 + vec3(0.5));\n        return true;\n    }\n    return false;\n}\n\nvec3 GetTriangleNormal(vec3 v0, vec3 v1, vec3 v2)\n{\n    return normalize(cross(v1-v0, v2-v0));\n}\n\nvec3 GetCellFaceNormal(ivec3 cellIndex, ivec3 face)\n{\n    vec3 v0, v1, v2, v3;\n    GetFaceVertices(cellIndex, face, v0, v1, v2, v3);\n    \n    vec3 normal = (GetTriangleNormal(v0, v1, v2) + GetTriangleNormal(v0, v2, v3)) / 2.0f;\n    \n#ifdef INVERT_GRID_COORD_SYS_HAND\n    normal = -normal;\n#endif\n    \n    return normal;\n}\n\nbool FindCellExit(vec3 origin, vec3 dir, float t0, ivec3 currentCell, ivec3 entranceFace, bool allowThinCells, OUT ivec3 exitFace, OUT vec3 exitCoord, OUT float t1)\n{\n    exitFace = F_NONE;\n    for (int i = 0; i < 6; i++) {\n        ivec3 testFace = GetFaceFromFaceIndex(i);\n        \n        if (testFace == entranceFace)\n            continue;\n            \n        if (IntersectRayCellFace(origin, dir, t0, currentCell, testFace, t1, exitCoord)) {\n            // There are cases where very thin cells will result in the same t\n            if (t1 - t0 > EPSILON) {\n                exitFace = testFace;\n                return true;\n            } else if (allowThinCells && (t1 - t0 >= 0)) {\n                exitFace = testFace;\n            }\n        }\n    }\n    if (exitFace != F_NONE)\n        return true;\n    return false;\n}\n\nbool FindCellExit(vec3 origin, vec3 dir, float t0, ivec3 currentCell, ivec3 entranceFace, OUT ivec3 exitFace, OUT vec3 exitCoord, OUT float t1)\n{\n    return FindCellExit(origin, dir, t0, currentCell, entranceFace, true, exitFace, exitCoord, t1);\n}\n\nbool IsCellInBounds(ivec3 cellIndex)\n{\n    return !(any(lessThan(cellIndex, ivec3(0))) || any(greaterThanEqual(cellIndex, cellDims)));\n}\n\nbool SearchNeighboringCells(vec3 origin, vec3 dir, float t0, ivec3 currentCell, OUT ivec3 nextCell, OUT ivec3 exitFace, OUT vec3 exitCoord, OUT float t1)\n{\n    for (int sideID = 0; sideID < 26; sideID++) {\n        ivec3 side = GetNeighborFromNeighborCellIndex(sideID);\n        ivec3 testCell = currentCell + side;\n        if (IsCellInBounds(testCell)) {\n            if (FindCellExit(origin, dir, t0, testCell, -side, false, exitFace, exitCoord, t1)) {\n                nextCell = testCell + exitFace;\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nbool FindNextCell(vec3 origin, vec3 dir, float t0, ivec3 currentCell, ivec3 entranceFace, OUT ivec3 nextCell, OUT ivec3 exitFace, OUT vec3 exitCoord, OUT float t1)\n{\n    if (FindCellExit(origin, dir, t0, currentCell, entranceFace, exitFace, exitCoord, t1)) {\n        nextCell = currentCell + exitFace;\n        if (!IsCellInBounds(nextCell))\n            return false;\n        return true;\n    } else {\n        return SearchNeighboringCells(origin, dir, t0, currentCell, nextCell, exitFace, exitCoord, t1);\n    }\n}\n\nfloat IntegrateConstantAlpha(float a, float distance)\n{\n    return 1 - exp(-a * distance);\n}\n\n// Only accurate for tetrahedra\n// Its an approximation for cubes\nfloat IntegrateAbsorption(float a, float b, float distance)\n{\n    return 1 - exp(-distance * (a+b)/2);\n}\n\nbool ShouldRenderCell(const ivec3 cellIndex)\n{\n    if (hasMissingData)\n        if (DoesCellHaveMissingData(cellIndex))\n            return false;\n    return true;\n}\n\nbool IsRayEnteringCell(vec3 d, ivec3 cellIndex, ivec3 face)\n{\n    vec3 n = GetCellFaceNormal(cellIndex, face);\n    return dot(d, n) < 0;\n}\n\n// vec3 GetCellNonHexahedralFaceNormalAtIntersection(vec3 o, vec3 d, ivec3 cellIndex, ivec3 face)\n// {\n//     float t;\n//     vec3 v0, v1, v2, v3, uvw;\n//     GetFaceVertices(cellIndex, face, v0, v1, v2, v3);\n//     \n//     if (TRI_INSTERSECT_ROUTINE(o, d, 0, v0, v1, v2, t, uvw))\n//         return GetTriangleNormal(v0, v1, v2);\n//     else\n//         return GetTriangleNormal(v0, v2, v3);\n// }\n// \n// bool IsRayEnteringNonHexahedralCell(vec3 o, vec3 d, ivec3 cellIndex, ivec3 face)\n// {\n//     vec3 n = GetCellNonHexahedralFaceNormalAtIntersection(o, d, cellIndex, face);\n//     return dot(d, n) < 0;\n// }\n\nvoid GetSideCellBBox(ivec3 cellIndex, int sideID, int fastDim, int slowDim, OUT vec3 bmin, OUT vec3 bmax)\n{\n    ivec3 index = ivec3(cellIndex[fastDim], cellIndex[slowDim], sideID);\n    bmin = texelFetch(boxMins, index, 0).rgb;\n    bmax = texelFetch(boxMaxs, index, 0).rgb;\n}\n\nbool IntersectRaySideCellBBox(vec3 origin, vec3 dir, float rt0, ivec3 cellIndex, int sideID, int fastDim, int slowDim)\n{\n    vec3 bmin, bmax;\n    float t0, t1;\n    GetSideCellBBox(cellIndex, sideID, fastDim, slowDim, bmin, bmax);\n    if (IntersectRayBoundingBox(origin, dir, rt0, bmin, bmax, t0, t1)) {\n        return true;\n    }\n    return false;\n}\n\nvoid GetSideCellBBoxDirect(int x, int y, int sideID, int level, OUT vec3 bmin, OUT vec3 bmax)\n{\n    ivec3 index = ivec3(x, y, sideID);\n    bmin = texelFetch(boxMins, index, level).rgb;\n    bmax = texelFetch(boxMaxs, index, level).rgb;\n}\n\nbool IntersectRaySideCellBBoxDirect(vec3 origin, vec3 dir, float rt0, int x, int y, int sideID, int level)\n{\n    vec3 bmin, bmax;\n    float t0, t1;\n    GetSideCellBBoxDirect(x, y, sideID, level, bmin, bmax);\n    if (IntersectRayBoundingBox(origin, dir, rt0, bmin, bmax, t0, t1)) {\n        return true;\n    }\n    return false;\n}\n\nivec2 GetBBoxArrayDimensions(int sideID, int level)\n{\n    return texelFetch(levelDims, ivec2(sideID, level), 0).rg;\n}\n\n#if DEBUG\nfloat DistToEdge(vec3 p, vec3 v0, vec3 v1)\n{\n    vec3 m = normalize(v1-v0);\n    float t0 = dot(m,p-v0)/dot(m,m);\n    float de = length(p - (v0 + t0*m));\n\n    float l = length(v1-v0);\n    de /= l;\n\n    return abs(de);\n    // return length(p - v0);\n}\n\nfloat DistToCellEdge(vec3 o, vec3 d, float t, ivec3 cell, ivec3 face)\n{\n    vec3 v0, v1, v2, v3;\n    GetFaceVertices(cell, face, v0, v1, v2, v3);\n    vec3 p = o + d*t;\n    \n    float de = FLT_MAX;\n    de = min(de, DistToEdge(p, v0, v1));\n    de = min(de, DistToEdge(p, v1, v2));\n    de = min(de, DistToEdge(p, v2, v3));\n    de = min(de, DistToEdge(p, v3, v0));\n    // de = min(de, DistToEdge(p, v0, v2));\n\n    return de;\n}\n#endif\n\nbool IsFaceThatPassedBBAnInitialCell(vec3 origin, vec3 dir, float t0, ivec3 index, ivec3 side, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n    // if (index == skipCellWhenSearchingForInit) return false;\n    float tFace;\n    vec3 null;\n    if (IntersectRayCellFace(origin, dir, t0, index, side, tFace, null)) {\n        if (IsRayEnteringCell(dir, index, side)) {\n            // Only update initial cell values if this is the closest cell\n            // if (tFace > t0 && tFace < t1) {\n            if (tFace < t1) {\n                cellIndex = index;\n                entranceFace = side;\n                t1 = tFace;\n\n#if DEBUG\n#if DEBUG_SHOW_NORMALS\n                vec3 n = GetCellNonHexahedralFaceNormalAtIntersection(origin, dir, index, side);\n                n = normalize(n/scales);\n                SD((n+vec3(1))/2.f, 0);\n#endif\n#if DEBUG_SHOW_CELL_INDEX\n                SD(index/vec3(cellDims), 0);\n#endif\n#if DEBUG_SHOW_GRID\n                float de = DistToCellEdge(origin, dir, t1, index, side);\n                if (de < 0.03) SD(WHITE, 0);\n#endif\n#endif\n            }\n            return true;\n        }\n    }\n    return false;\n}\n\n\n// The nvidia compiler optimizer cannot handle deep nested loops\n// unroll none improves compile time\n// inline none breaks the compiler\n// Side note: This is supposed to be an inline change but it is in fact a source-wide flag\n\n// #pragma optionNV(inline none)\n#pragma optionNV(unroll none)\n\n#ifdef NVIDIA\n#include BBTraversalAlgorithmsNV.frag\n#else\n#include BBTraversalAlgorithms.frag\n#endif\n\nint SearchSideForInitialCellBasic(vec3 origin, vec3 dir, float t0, int sideID, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n    int fastDim = GetFastDimForFaceIndex(sideID);\n    int slowDim = GetSlowDimForFaceIndex(sideID);\n    ivec3 side = GetFaceFromFaceIndex(sideID);\n    ivec3 index = (side+1)/2 * (cellDims-1);\n    \n    for (index[slowDim] = 0; index[slowDim] < cellDims[slowDim]; index[slowDim]++) {\n        for (index[fastDim] = 0; index[fastDim] < cellDims[fastDim]; index[fastDim]++) {\n            \n            if (IntersectRaySideCellBBox(origin, dir, t0, index, sideID, fastDim, slowDim)) {\n                if (IsFaceThatPassedBBAnInitialCell(origin, dir, t0, index, side, cellIndex, entranceFace, t1))\n                    return 1;\n            }\n        }\n    }\n    return 0;\n}\n\n// Does not work on nvidia\n// #define SearchSideForInitialCellWithOctree_NLevels(N, origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1) SearchSideForInitialCellWithOctree_ ## N ## Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1)\n\nint SearchSideForInitialCell(vec3 origin, vec3 dir, float t0, int sideID, OUT ivec3 cellIndex, OUT ivec3 entranceFace, inout float t1)\n{\n    int fastDim = GetFastDimForFaceIndex(sideID);\n    int slowDim = GetSlowDimForFaceIndex(sideID);\n\n#if   BB_LEVELS == 1\n    return SearchSideForInitialCellWithOctree_1Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 2\n    return SearchSideForInitialCellWithOctree_2Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 3\n    return SearchSideForInitialCellWithOctree_3Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 4\n    return SearchSideForInitialCellWithOctree_4Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 5\n    return SearchSideForInitialCellWithOctree_5Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 6\n    return SearchSideForInitialCellWithOctree_6Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 7\n    return SearchSideForInitialCellWithOctree_7Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 8\n    return SearchSideForInitialCellWithOctree_8Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 9\n    return SearchSideForInitialCellWithOctree_9Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 10\n    return SearchSideForInitialCellWithOctree_10Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 11\n    return SearchSideForInitialCellWithOctree_11Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#elif BB_LEVELS == 12\n    return SearchSideForInitialCellWithOctree_12Levels(origin, dir, t0, sideID, fastDim, slowDim, cellIndex, entranceFace, t1);\n#endif\n}\n\nint FindInitialCell(vec3 origin, vec3 dir, float t0, OUT ivec3 cellIndex, OUT ivec3 entranceFace, OUT float t1)\n{\n    t1 = FLT_MAX;\n    int intersections = 0;\n    for (int side = 0; side < 6; side++)\n        intersections += SearchSideForInitialCell(origin, dir, t0, side, cellIndex, entranceFace, t1);\n    return intersections;\n}\n\nvec4 Traverse(vec3 origin, vec3 dir, vec3 rayLightingNormal, float tMin, float tMax, float t0, ivec3 currentCell, ivec3 entranceFace, OUT float t1);\n\nvoid main(void)\n{\n    vec3 eye, dir, rayLightingNormal;\n    float sceneDepthT;\n    GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT);\n    \n    float t0, t1, tp;\n    \n    bool intersectBox = IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1);\n    float tMin = t0, tMax = min(t1, sceneDepthT);\n    \n    if (intersectBox) {\n        ivec3 initialCell;\n        ivec3 entranceFace;\n        float t0 = -FLT_MAX;\n        float t1;\n        vec4 accum = vec4(0);\n        int intersections;\n        int i = 0;\n        do {\n            intersections = FindInitialCell(eye, dir, t0, initialCell, entranceFace, t1);\n            // skipCellWhenSearchingForInit = initialCell;\n            \n            if (intersections > 0) {\n                vec4 color = Traverse(eye, dir, rayLightingNormal, tMin, tMax, t1, initialCell, entranceFace, t1);\n                BlendToBack(accum, color);\n            }\n            \n            // Failsafe to prevent infinite recursion due to float precision error\n            // if (i++ > 8) {\n            if (i++ > 8 || t1-t0 <= EPSILON) {\n                break;\n            }\n            // if (t1-t0 <= EPSILON) {\n            //     float unitDistanceScaled = unitDistance / length(dir * scales);\n            //     float step = unitDistanceScaled/7.f/samplingRateMultiplier * GetSamplingNoise();\n            //     t1 = t0 + step;\n            // }\n\n\n\t\t\tif (accum.a > ALPHA_BREAK)\n\t\t\t\tbreak;\n                \n            t0 = t1;\n            \n        } while (intersections > 1);\n\n        if (accum.a < ALPHA_DISCARD) {\n            // discard; // There is a bug on in the 2015 15\" AMD MBP laptops where this does not work with larger(?) datasets\n            //fragColor = vec4(0);\n            gl_FragDepth = GetDepthBuffer();\n            DEBUG_SHOW();\n            return;\n        }\n        fragColor = accum;\n        DEBUG_SHOW();\n        return;\n    }\n    // discard;\n    \n    gl_FragDepth = GetDepthBuffer();\n    fragColor = vec4(0.f);\n\n    DEBUG_SHOW();\n}\n"
  },
  {
    "path": "share/shaders/VolumeCellDVR.frag",
    "content": "#pragma auto_version\n\n#include VolumeCellBase.frag\n\nvec4 RenderCellSampling(const vec3 dir, const vec3 entranceCoord, const vec3 exitCoord, const float t0, const float t1, const float step)\n{\n    vec4 acc2 = vec4(0);\n    for (float t = step * (floor(t0/step)+1); t < t1; t+= step) {\n        vec3 hit = mix(entranceCoord, exitCoord, (t-t0)/(t1-t0));\n        vec4 color = GetColorAtCoord(hit);\n        vec3 normal = GetNormalAtCoord(hit);\n        color.rgb *= PhongLighting(normal, dir);\n        BlendToBack(acc2, PremultiplyAlpha(color));\n    }\n    return acc2;\n}\n\nvec4 RenderCellSmartSampling(const vec3 dir, vec3 rayLightingNormal, const vec3 entranceCoord, const vec3 exitCoord, const float tStart, const float tEnd, const float t0, const float t1, const float step, const float stepOpacityUnit)\n{\n    vec4 acc2 = vec4(0);\n    vec3 hit = mix(entranceCoord, exitCoord, (tStart-t0)/(t1-t0));\n    vec4 c = GetColorAtCoord(hit);\n    vec3 normal = GetNormalAtCoord(hit);\n    c.rgb *= PhongLighting(normal, rayLightingNormal);\n    float l = min(step - mod(tStart, step), tEnd-tStart)/step;\n    c.a = IntegrateConstantAlpha(c.a * density, max(l * stepOpacityUnit, 0.0f));\n    BlendToBack(acc2, PremultiplyAlpha(c));\n    \n    for (float t = step * (floor(tStart/step)+1); t < tEnd; t+= step) {\n        vec3 hit = mix(entranceCoord, exitCoord, (t-t0)/(t1-t0));\n        vec4 color = GetColorAtCoord(hit);\n        vec3 normal = GetNormalAtCoord(hit);\n        color.rgb *= PhongLighting(normal, rayLightingNormal);\n        float l = min(step, t1-t)/step;\n        color.a = IntegrateConstantAlpha(color.a * density, l * stepOpacityUnit);\n        BlendToBack(acc2, PremultiplyAlpha(color));\n    }\n    \n    return acc2;\n}\n\nvec4 RenderCellConstant(const vec3 dir, const vec3 rayLightingNormal, const ivec3 currentCell, const float t0, const float t1, const float unitDistanceScaled)\n{\n    float l = (t1-t0)/unitDistanceScaled;\n    vec4 color = GetAverageColorForCoordIndex(currentCell);\n    \n    vec3 normal = GetNormal((vec3(currentCell)+vec3(0.5))/cellDims);\n    color.rgb *= PhongLighting(normal, rayLightingNormal);\n    \n    color.a = IntegrateConstantAlpha(color.a * density, l * unitOpacityScalar);\n    \n    return PremultiplyAlpha(color);\n}\n\nvec4 Traverse(vec3 origin, vec3 dir, vec3 rayLightingNormal, float tMin, float tMax, float t0, ivec3 currentCell, ivec3 entranceFace, OUT float t1)\n{\n    vec3 entranceCoord;\n    ivec3 nextCell;\n    ivec3 exitFace;\n    vec3 exitCoord;\n    bool hasNext = true;\n    float tStart = t0;\n    ivec3 initialCell = currentCell;\n    float unitDistanceScaled = unitDistance / length(dir * scales);\n    float step = unitDistanceScaled/7.f/samplingRateMultiplier * GetSamplingNoise();\n    float stepOpacityUnit = unitOpacityScalar/samplingRateMultiplier;\n    if (fast) {\n        step = unitDistanceScaled * GetSamplingNoise();\n        stepOpacityUnit = unitOpacityScalar * 7;\n    }\n    \n    int i = 0;\n    vec4 accum = vec4(0);\n    float a = 0;\n    \n    float null;\n    IntersectRayCellFace(origin, dir, -FLT_MAX, currentCell, entranceFace, null, entranceCoord);\n    \n    while (hasNext) {\n        if (t0 > tMax)\n            break;\n        \n        hasNext = FindNextCell(origin, dir, t0, currentCell, entranceFace, nextCell, exitFace, exitCoord, t1);\n        \n        if (t0 >= tMin || (t0 <= tMin && tMin < t1)) {\n            float tEnd = min(t1, tMax);\n            float tStart = max(t0, tMin);\n            \n            if (ShouldRenderCell(currentCell)) {\n#if 1\n                BlendToBack(accum, RenderCellSmartSampling(dir, rayLightingNormal, entranceCoord, exitCoord, tStart, tEnd, t0, t1, step, stepOpacityUnit));\n#else\n                BlendToBack(accum, RenderCellConstant     (dir, rayLightingNormal, currentCell, tStart, tEnd, unitDistanceScaled));\n#endif\n            }\n        }\n        \n        currentCell = nextCell;\n        entranceFace = -exitFace;\n        entranceCoord = exitCoord;\n        t0 = t1;\n        i++;\n        \n        if (accum.a > ALPHA_BREAK || i > 4096)\n            break;\n    }\n    \n    gl_FragDepth = CalculateDepth(origin + dir*t1);\n    return accum;\n}\n"
  },
  {
    "path": "share/shaders/VolumeCellDVR.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/VolumeCellIso.frag",
    "content": "#pragma auto_version\n\n#include VolumeCellBase.frag\n#include VolumeIsoInclude.frag\n\nvoid TestIsoSegment(const vec3 origin, const vec3 dir, const vec3 rayLightingNormal, const float isoValue, const float dv, const float ld, const float t, const float lt, const float t0, const float t1, const vec3 entranceCoord, const vec3 exitCoord, inout vec4 accum)\n{\n    if ((ld < isoValue && dv >= isoValue) || (ld > isoValue && dv <= isoValue)) {\n        \n        float ti = mix(lt, t, (isoValue-ld)/(dv-ld));\n        vec3 hit = mix(entranceCoord, exitCoord, (ti-t0)/(t1-t0));\n        \n        vec3 isoSampleSTR = hit/coordDimsF;\n        vec4 color = GetIsoSurfaceColor(isoSampleSTR);\n        vec3 normal = GetNormal(isoSampleSTR);\n        \n        color.rgb *= PhongLighting(normal, rayLightingNormal);\n        \n        BlendToBack(accum, PremultiplyAlpha(color));\n        \n        if (accum.a > ALPHA_BREAK)\n            gl_FragDepth = CalculateDepth(origin + dir * ti);\n    }\n}\n\nvoid TestAllIsoSegment(const vec3 origin, const vec3 dir, const vec3 rayLightingNormal, const float dve, const float dvs, const float te, const float ts, const float t0, const float t1, const vec3 entranceCoord, const vec3 exitCoord, inout vec4 accum)\n{\n    if (isoEnabled[0]) TestIsoSegment(origin, dir, rayLightingNormal, isoValue[0], dve, dvs, te, ts, t0, t1, entranceCoord, exitCoord, accum);\n    if (isoEnabled[1]) TestIsoSegment(origin, dir, rayLightingNormal, isoValue[1], dve, dvs, te, ts, t0, t1, entranceCoord, exitCoord, accum);\n    if (isoEnabled[2]) TestIsoSegment(origin, dir, rayLightingNormal, isoValue[2], dve, dvs, te, ts, t0, t1, entranceCoord, exitCoord, accum);\n    if (isoEnabled[3]) TestIsoSegment(origin, dir, rayLightingNormal, isoValue[3], dve, dvs, te, ts, t0, t1, entranceCoord, exitCoord, accum);\n}\n\nvoid SampleCell(const vec3 origin, const vec3 dir, const vec3 rayLightingNormal, const vec3 entranceCoord, const vec3 exitCoord, const float t0, const float t1, const float ts, const float te, inout vec4 accum)\n{\n    if (accum.a > ALPHA_BREAK)\n        return;\n    \n    vec3 hitS = mix(entranceCoord, exitCoord, (ts-t0)/(t1-t0));\n    float ds = GetDataCoordinateSpace(hitS);\n    \n    float tm = (te+ts)/2.0;\n    vec3 hitm = mix(entranceCoord, exitCoord, (tm-t0)/(t1-t0));\n    float dm = GetDataCoordinateSpace(hitm);\n    \n    vec3 hitE = mix(entranceCoord, exitCoord, (te-t0)/(t1-t0));\n    float de = GetDataCoordinateSpace(hitE);\n    \n    TestAllIsoSegment(origin, dir, rayLightingNormal, dm, ds, tm, ts, t0, t1, entranceCoord, exitCoord, accum);\n    TestAllIsoSegment(origin, dir, rayLightingNormal, de, dm, te, tm, t0, t1, entranceCoord, exitCoord, accum);\n}\n\nvec4 Traverse(vec3 origin, vec3 dir, vec3 rayLightingNormal, float tMin, float tMax, float t0, ivec3 currentCell, ivec3 entranceFace, OUT float t1)\n{\n    vec3 entranceCoord;\n    ivec3 nextCell;\n    ivec3 exitFace;\n    vec3 exitCoord;\n    bool hasNext = true;\n    ivec3 initialCell = currentCell;\n    float unitDistanceScaled = unitDistance / length(dir * scales);\n    float step = unitDistanceScaled/7/samplingRateMultiplier * GetSamplingNoise();\n    if (fast)\n        step = unitDistanceScaled * GetSamplingNoise();\n    \n    int i = 0;\n    vec4 accum = vec4(0);\n    float a = 0;\n    \n    float lt;\n    IntersectRayCellFace(origin, dir, -FLT_MAX, currentCell, entranceFace, lt, entranceCoord);\n    FindNextCell(origin, dir, t0, currentCell, entranceFace, nextCell, exitFace, exitCoord, t1);\n    \n    while (hasNext) {\n        if (t0 > tMax)\n            break;\n        \n        hasNext = FindNextCell(origin, dir, t0, currentCell, entranceFace, nextCell, exitFace, exitCoord, t1);\n        \n        if (t0 >= tMin || (t0 <= tMin && tMin < t1)) {\n            float tEnd = min(t1, tMax);\n            float tStart = max(t0, tMin);\n\n\t\t\tif (ShouldRenderCell(currentCell))\n                SampleCell(origin, dir, rayLightingNormal, entranceCoord, exitCoord, t0, t1, tStart, tEnd, accum);\n        }\n        \n        currentCell = nextCell;\n        entranceFace = -exitFace;\n        entranceCoord = exitCoord;\n        t0 = t1;\n        i++;\n        \n        if (accum.a > ALPHA_BREAK || i > 4096)\n            break;\n    }\n    \n    return accum;\n}\n"
  },
  {
    "path": "share/shaders/VolumeCellIso.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/VolumeDVR.frag",
    "content": "#pragma auto_version\n\n#include VolumeBase.frag\n\n/*\nfloat Shadow(vec3 to) {\n    float t = 0, t0, t1;\n    IntersectRayBoundingBox(to, -lightDir, 0, vec3(0), vec3(1), t0, t1);\n    //return t1;\n    \n    float acc = 0;\n    for (; t < t1; t+= 0.05) {\n        float dataNorm = (texture(data, to-t*lightDir).r - LUTMin) / (LUTMax - LUTMin);\n        float opacity = texture(LUT, dataNorm).a;\n        acc += opacity * (1-acc);\n    }\n    return 1-acc;\n}\n */\n\nfloat IntegrateConstantAlpha(float a, float distance)\n{\n    return 1 - exp(-a * distance);\n}\n\nvoid main(void)\n{\n    vec3 eye, dir, rayLightingNormal;\n    float sceneDepthT;\n    GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT);\n    \n    vec4 accum = vec4(0);\n    float t0, t1;\n    \n    if (IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1)) {\n        \n        int STEPS;\n        float integratePart = 1 / samplingRateMultiplier;\n        if (fast) {\n            STEPS = 100;\n            integratePart = 7;\n        } else {\n            STEPS = int(700 * samplingRateMultiplier);\n\t\t}\n        float step = GetSamplingNoise() * max(((t1-t0)/float(STEPS))*1.01, (dataBoundsMax[2]-dataBoundsMin[2])/float(STEPS));\n        \n        t1 = min(t1, sceneDepthT);\n        int i = 0;\n        for (float t = t0; t < t1; t += step) {\n            \n            vec3 hit = eye + dir * t;\n            vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin);\n            vec4 color = GetColorForNormalizedCoord(dataSTR);\n            vec3 normal = GetNormal(dataSTR);\n\t\t\t\n            color.rgb *= PhongLighting(normal, rayLightingNormal);\n            \n            color.a = IntegrateConstantAlpha(color.a * density, integratePart);\n            \n            if (ShouldRenderSample(dataSTR))\n                BlendToBack(accum, PremultiplyAlpha(color));\n            \n            if (accum.a > ALPHA_BREAK) {\n                t1 = t;\n                break;\n            }\n                \n            // Failsafe\n            if (i++ > STEPS)\n                break;\n        }\n        \n        gl_FragDepth = CalculateDepth(eye + dir*t1);\n        fragColor = accum;\n    } else {\n        fragColor = vec4(0.f);\n\t}\n    if (accum.a < ALPHA_DISCARD)\n        gl_FragDepth = GetDepthBuffer();\n}\n"
  },
  {
    "path": "share/shaders/VolumeDVR.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/VolumeIso.frag",
    "content": "#pragma auto_version\n\n#include VolumeBase.frag\n#include VolumeIsoInclude.frag\n\nvoid TestIso(vec3 eye, vec3 dir, vec3 rayLightingNormal, float value, float dv, float ld, float step, float t, inout vec4 accum)\n{\n\tif ((ld < value && dv >= value) || (ld > value && dv <= value)) {\n\t\tfloat lt = t - step;\n\t\tfloat t = lt + step*(value-ld)/(dv-ld);\n\t\t\n\t\tvec3 hit = eye + dir * t;\n\t\tvec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin);\n\n\t\tvec4 color = GetIsoSurfaceColor(dataSTR);\n\t\tvec3 normal = GetNormal(dataSTR);\n\t\t\n\t\tcolor.rgb *= PhongLighting(normal, rayLightingNormal);\n\t\t\n\t\tBlendToBack(accum, PremultiplyAlpha(color));\n\t}\n}\n\nvoid main(void)\n{\n    vec3 eye, dir, rayLightingNormal;\n    float sceneDepthT;\n    GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT);\n    \n    vec4 accum = vec4(0);\n    float t0, t1;\n    \n    if (IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1)) {\n\n        int STEPS;\n        if (fast) {\n            STEPS = 100;\n        } else\n            STEPS = int(700 * samplingRateMultiplier);\n\n        float step = max(((t1-t0)/float(STEPS))*1.01, (dataBoundsMax[2]-dataBoundsMin[2])/float(STEPS));\n\t\tvec3 initialSample = ((eye + dir * t0) - dataBoundsMin) / (dataBoundsMax-dataBoundsMin);\n        float ld = texture(data, initialSample).r;\n\t\tbool lastShouldRender = ShouldRenderSample(initialSample);\n        \n        t1 = min(t1, sceneDepthT);\n        int i = 0;\n        for (float t = t0; t < t1; t += step) {\n            vec3 hit = eye + dir * t;\n            vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin);\n            float dv = texture(data, dataSTR).r;\n\t\t\tbool shouldRender = ShouldRenderSample(dataSTR);\n            \n\t\t\tif (shouldRender && lastShouldRender) {\n\t\t\t\t// Unrolled intentionally\n\t\t\t\tif (isoEnabled[0]) TestIso(eye, dir, rayLightingNormal, isoValue[0], dv, ld, step, t, accum);\n\t\t\t\tif (isoEnabled[1]) TestIso(eye, dir, rayLightingNormal, isoValue[1], dv, ld, step, t, accum);\n\t\t\t\tif (isoEnabled[2]) TestIso(eye, dir, rayLightingNormal, isoValue[2], dv, ld, step, t, accum);\n\t\t\t\tif (isoEnabled[3]) TestIso(eye, dir, rayLightingNormal, isoValue[3], dv, ld, step, t, accum);\n                \n                if (accum.a > ALPHA_BREAK)\n                    gl_FragDepth = CalculateDepth(hit);\n\t\t\t}\n            ld = dv;\n\t\t\tlastShouldRender = shouldRender;\n            \n            if (accum.a > ALPHA_BREAK)\n                break;\n                \n            // Failsafe\n            if (i++ > STEPS)\n                break;\n        }\n        \n        fragColor = accum;\n    } else {\n        fragColor = vec4(0.f);\n    }\n        \n    if (accum.a < ALPHA_DISCARD)\n        gl_FragDepth = GetDepthBuffer();\n}\n"
  },
  {
    "path": "share/shaders/VolumeIso.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/VolumeIsoInclude.frag",
    "content": "uniform float isoValue[4];\nuniform bool  isoEnabled[4];\nuniform vec4 constantColor;\n\nvec4 GetIsoSurfaceColor(vec3 sampleSTR)\n{\n    float value = texture(data, sampleSTR).r;\n    float valueNorm = (value - LUTMin) / (LUTMax - LUTMin);\n    float opacity = texture(LUT, valueNorm).a;\n    \n#ifdef USE_SECOND_DATA\n\tif (useColormapData) {\n\t\tif (hasMissingData2)\n\t\t\tif (DoesSampleHaveMissingData2(sampleSTR))\n\t\t\t\t\treturn vec4(0);\n\n\t\tfloat value2 = texture(data2, sampleSTR).r;\n\t\tfloat valueNorm2 = (value2 - LUTMin2) / (LUTMax2 - LUTMin2);\n        return vec4(texture(LUT2, valueNorm2).rgb, opacity);\n\t}\n#endif\n    \n    return vec4(constantColor.rgb, opacity);\n}\n"
  },
  {
    "path": "share/shaders/VolumeRayMath.frag",
    "content": "#define FLT_MAX 3.402823466e+38\n#define FLT_MIN 1.175494351e-38\n#define DBL_MAX 1.7976931348623158e+308\n#define DBL_MIN 2.2250738585072014e-308\n#define EPSILON 1.19e-07\n\nbool IntersectRayBoundingBox(vec3 o, vec3 d, float rt0, vec3 boxMin, vec3 boxMax, OUT float t0, OUT float t1)\n{\n    vec3 tMin = (boxMin - o) / d;\n    vec3 tMax = (boxMax - o) / d;\n    vec3 bt1 = min(tMin, tMax);\n    vec3 bt2 = max(tMin, tMax);\n    t0 = max(max(max(bt1.x, bt1.y), bt1.z), rt0);\n    t1 = min(min(bt2.x, bt2.y), bt2.z);\n    return t0 <= t1;\n}\n\nbool IntersectRayPlane(vec3 o, vec3 d, float rt0, vec3 v0, vec3 n, OUT float t)\n{\n    float denom = dot(n, d);\n    \n    if (abs(denom) > 1e-6) {\n        t = dot(v0 - o, n) / denom;\n        return t >= rt0;\n    }\n    return false;\n}\n\nbool IntersectRayTriangle(vec3 o, vec3 d, float rt0, vec3 v0, vec3 v1, vec3 v2, OUT float t, OUT vec3 barycentric)\n{\n    vec3 n = cross(v1-v0,v2-v0);\n    \n    if (IntersectRayPlane(o, d, rt0, v0, n, t)) {\n        vec3 P = o + d * t;\n        \n        vec3 edge0 = v1-v0;\n        vec3 vp0 = P - v0;\n        vec3 C0 = cross(edge0, vp0);\n        if (dot(n, C0) < 0) return false;\n        \n        vec3 edge1 = v2-v1;\n        vec3 vp1 = P - v1;\n        vec3 C1 = cross(edge1, vp1);\n        if (dot(n, C1) < 0) return false;\n        \n        vec3 edge2 = v0 - v2;\n        vec3 vp2 = P - v2;\n        vec3 C2 = cross(edge2, vp2);\n        if (dot(n, C2) < 0) return false;\n        \n        float area = length(n);\n        float u = length(C1) / area;\n        float v = length(C2) / area;\n        float w = 1-u-v;\n        barycentric = vec3(u,v,w);\n        \n        return true;\n    }\n    return false;\n}\n\nint MaxDimension(vec3 v)\n{\n\treturn (v.x > v.y) ? ((v.x > v.z) ? 0 : 2) : ((v.y > v.z) ? 1 : 2);\n}\n\nvec3 Permute(vec3 v, int x, int y, int z)\n{\n\treturn vec3(v[x], v[y], v[z]);\n}\n\nbool IntersectRayTriangleIntel(vec3 o, vec3 dir, float rt0, vec3 v0, vec3 v1, vec3 v2, OUT float t, OUT vec3 barycentric)\n{\n\t// Transform triangle vertices to ray coordinate space\n\t// Translate vertices based on ray origin\n\tvec3 p0t = v0 - o;\n\tvec3 p1t = v1 - o;\n\tvec3 p2t = v2 - o;\n\n\t// Permute components of triangle vertices and ray direction\n\tint kz = MaxDimension(abs(dir));\n\tint kx = kz + 1; if (kx == 3) kx = 0;\n\tint ky = kx + 1; if (ky == 3) ky = 0;\n\tvec3 d = Permute(dir, kx, ky, kz);\n\tp0t = Permute(p0t, kx, ky, kz);\n\tp1t = Permute(p1t, kx, ky, kz);\n\tp2t = Permute(p2t, kx, ky, kz);\n\n\t// Apply shear transformation to translated vertex positions\n\tfloat Sx = -d.x / d.z;\n\tfloat Sy = -d.y / d.z;\n\tfloat Sz = 1.f / d.z;\n\tp0t.x += Sx * p0t.z;\n\tp0t.y += Sy * p0t.z;\n\tp1t.x += Sx * p1t.z;\n\tp1t.y += Sy * p1t.z;\n\tp2t.x += Sx * p2t.z;\n\tp2t.y += Sy * p2t.z;\n\n\n\t// Compute edge function coefficients e0, e1, and e2\n\tfloat e0 = p1t.x * p2t.y - p1t.y * p2t.x;\n\tfloat e1 = p2t.x * p0t.y - p2t.y * p0t.x;\n\tfloat e2 = p0t.x * p1t.y - p0t.y * p1t.x;\n\n#if __VERSION__ >= 400\n\t// Fall back to double-precision test at triangle edges\n\tif (e0 == 0.0f || e1 == 0.0f || e2 == 0.0f) {\n\t\tdouble p2txp1ty = double(p2t.x) * double(p1t.y);\n\t\tdouble p2typ1tx = double(p2t.y) * double(p1t.x);\n\t\te0 = float(p2typ1tx - p2txp1ty);\n\t\tdouble p0txp2ty = double(p0t.x) * double(p2t.y);\n\t\tdouble p0typ2tx = double(p0t.y) * double(p2t.x);\n\t\te1 = float(p0typ2tx - p0txp2ty);\n\t\tdouble p1txp0ty = double(p1t.x) * double(p0t.y);\n\t\tdouble p1typ0tx = double(p1t.y) * double(p0t.x);\n\t\te2 = float(p1typ0tx - p1txp0ty);\n\t}\n#endif\n\n\t// Perform triangle edge and determinant tests\n\tif ((e0 < 0 || e1 < 0 || e2 < 0) && (e0 > 0 || e1 > 0 || e2 > 0))\n\t\treturn false;\n\tfloat det = e0 + e1 + e2;\n\tif (det == 0)\n\t\treturn false;\n\n\t// Compute scaled hit distance to triangle and test against ray t range\n//    p0t.z *= Sz;\n//    p1t.z *= Sz;\n//    p2t.z *= Sz;\n//    float tScaled = e0 * p0t.z + e1 * p1t.z + e2 * p2t.z;\n//    if (det < 0 && (tScaled >= rt0*det || tScaled < FLT_MAX * det))\n//        return false;\n//    else if (det > 0 && (tScaled <= rt0*det || tScaled > FLT_MAX * det))\n//        return false;\n//    t = tScaled * invDet;\n\n    // This routine provides consistent results at t = t0\n    // as opposed to the one above\n    if (!IntersectRayPlane(o, dir, rt0, v0, cross(v1-v0,v2-v0), t))\n        return false;\n\n\tfloat invDet = 1 / det;\n\tfloat b0 = e0 * invDet;\n\tfloat b1 = e1 * invDet;\n\tfloat b2 = e2 * invDet;\n    barycentric = vec3(b0, b1, b2);\n\n\treturn true;\n}\n\n#ifdef USE_INTEL_TRI_ISECT\n#define TRI_INSTERSECT_ROUTINE IntersectRayTriangleIntel\n#else\n#define TRI_INSTERSECT_ROUTINE IntersectRayTriangle\n#endif\n\nbool IntersectRayQuad(vec3 o, vec3 d, float rt0, vec3 v0, vec3 v1, vec3 v2, vec3 v3, OUT float t, OUT vec4 weights)\n{\n    vec3 uvw;\n    if (TRI_INSTERSECT_ROUTINE(o, d, rt0, v0, v1, v2, t, uvw)) {\n        weights = vec4(uvw, 0);\n        return true;\n    }\n    if (TRI_INSTERSECT_ROUTINE(o, d, rt0, v0, v2, v3, t, uvw)) {\n        weights = vec4(uvw.x, 0, uvw.y, uvw.z);\n        return true;\n    }\n    return false;\n}\n"
  },
  {
    "path": "share/shaders/VolumeRectilinearDVR.frag",
    "content": "#pragma auto_version\n\n#include VolumeBase.frag\n\nuniform ivec3 coordDims;\nuniform ivec3 coordSigns;\n\nuniform sampler2D coordLUT;\n\nfloat IntegrateConstantAlpha(float a, float distance)\n{\n    return 1 - exp(-a * distance);\n}\n\nvec3 ReverseCoordMapping(vec3 p)\n{\n    return vec3(\n        texture(coordLUT, vec2(p.x, 0.0)).x,\n        texture(coordLUT, vec2(p.y, 0.5)).x,\n        texture(coordLUT, vec2(p.z, 1.0)).x\n    );\n}\n\nvec3 GetNormalWithReverseCoordMapping(vec3 p)\n{\n    vec3 dims = vec3(textureSize(data, 0));\n    vec3 d = 1/dims * 0.5;\n    vec3 s0, s1;\n    s1.x = texture(data, ReverseCoordMapping(p + d*vec3(1,0,0))).r;\n    s1.y = texture(data, ReverseCoordMapping(p + d*vec3(0,1,0))).r;\n    s1.z = texture(data, ReverseCoordMapping(p + d*vec3(0,0,1))).r;\n    s0.x = texture(data, ReverseCoordMapping(p - d*vec3(1,0,0))).r;\n    s0.y = texture(data, ReverseCoordMapping(p - d*vec3(0,1,0))).r;\n    s0.z = texture(data, ReverseCoordMapping(p - d*vec3(0,0,1))).r;\n\n    // glsl::normalize does not handle 0 length vectors\n    vec3 v = s1-s0;\n    float l = length(v);\n    if (l == 0)\n        return vec3(0);\n    return v/l;\n}\n\n\nvoid main(void)\n{\n    vec3 eye, dir, rayLightingNormal;\n    float sceneDepthT;\n    GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT);\n    \n    vec4 accum = vec4(0);\n    float t0, t1;\n    \n    if (IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1)) {\n        \n        int STEPS;\n        float integratePart = 1 / samplingRateMultiplier;\n        if (fast) {\n            STEPS = 100;\n            integratePart = 7;\n        } else {\n            STEPS = int(700 * samplingRateMultiplier);\n\t\t}\n        float step = GetSamplingNoise() * max(((t1-t0)/float(STEPS))*1.01, (dataBoundsMax[2]-dataBoundsMin[2])/float(STEPS));\n        \n        t1 = min(t1, sceneDepthT);\n        int i = 0;\n        for (float t = t0; t < t1; t += step) {\n            \n            vec3 hit = eye + dir * t;\n            vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin);\n            vec3 dataSTRMapped = ReverseCoordMapping(dataSTR);\n\n            vec4 color = GetColorForNormalizedCoord(dataSTRMapped);\n            vec3 normal = GetNormalWithReverseCoordMapping(dataSTR);\n\t\t\t\n            color.rgb *= PhongLighting(normal, rayLightingNormal);\n            \n            color.a = IntegrateConstantAlpha(color.a * density, integratePart);\n            \n            if (ShouldRenderSample(dataSTRMapped))\n                BlendToBack(accum, PremultiplyAlpha(color));\n            \n            if (accum.a > ALPHA_BREAK) {\n                t1 = t;\n                break;\n            }\n                \n            // Failsafe\n            if (i++ > STEPS)\n                break;\n        }\n        \n        gl_FragDepth = CalculateDepth(eye + dir*t1);\n        fragColor = accum;\n    } else {\n        fragColor = vec4(0.f);\n\t}\n    if (accum.a < ALPHA_DISCARD)\n        gl_FragDepth = GetDepthBuffer();\n}\n"
  },
  {
    "path": "share/shaders/VolumeRectilinearDVR.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/VolumeRectilinearIso.frag",
    "content": "#pragma auto_version\n\n#include VolumeBase.frag\n#include VolumeIsoInclude.frag\n\nuniform sampler2D coordLUT;\n\nvec3 ReverseCoordMapping(vec3 p)\n{\n    return vec3(\n        texture(coordLUT, vec2(p.x, 0.0)).x,\n        texture(coordLUT, vec2(p.y, 0.5)).x,\n        texture(coordLUT, vec2(p.z, 1.0)).x\n    );\n}\n\nvec3 GetNormalWithReverseCoordMapping(vec3 p)\n{\n    vec3 dims = vec3(textureSize(data, 0));\n    vec3 d = 1/dims * 0.5;\n    vec3 s0, s1;\n    s1.x = texture(data, ReverseCoordMapping(p + d*vec3(1,0,0))).r;\n    s1.y = texture(data, ReverseCoordMapping(p + d*vec3(0,1,0))).r;\n    s1.z = texture(data, ReverseCoordMapping(p + d*vec3(0,0,1))).r;\n    s0.x = texture(data, ReverseCoordMapping(p - d*vec3(1,0,0))).r;\n    s0.y = texture(data, ReverseCoordMapping(p - d*vec3(0,1,0))).r;\n    s0.z = texture(data, ReverseCoordMapping(p - d*vec3(0,0,1))).r;\n    \n    // glsl::normalize does not handle 0 length vectors\n    vec3 v = s1-s0;\n    float l = length(v);\n    if (l == 0)\n        return vec3(0);\n    return v/l;\n}\n\nvoid TestIso(vec3 eye, vec3 dir, vec3 rayLightingNormal, float value, float dv, float ld, float step, float t, inout vec4 accum)\n{\n\tif ((ld < value && dv >= value) || (ld > value && dv <= value)) {\n\t\tfloat lt = t - step;\n\t\tfloat t = lt + step*(value-ld)/(dv-ld);\n\t\t\n\t\tvec3 hit = eye + dir * t;\n\t\tvec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin);\n        vec3 dataSTRMapped = ReverseCoordMapping(dataSTR);\n\n\t\tvec4 color = GetIsoSurfaceColor(dataSTRMapped);\n\t\tvec3 normal = GetNormalWithReverseCoordMapping(dataSTR);\n\t\t\n\t\tcolor.rgb *= PhongLighting(normal, rayLightingNormal);\n\t\t\n\t\tBlendToBack(accum, PremultiplyAlpha(color));\n\t}\n}\n\nvoid main(void)\n{\n    vec3 eye, dir, rayLightingNormal;\n    float sceneDepthT;\n    GetRayParameters(eye, dir, rayLightingNormal, sceneDepthT);\n    \n    vec4 accum = vec4(0);\n    float t0, t1;\n    \n    if (IntersectRayBoundingBox(eye, dir, 0, userExtsMin, userExtsMax, t0, t1)) {\n\n        int STEPS;\n        if (fast) {\n            STEPS = 100;\n        } else\n            STEPS = int(700 * samplingRateMultiplier);\n\n        float step = max(((t1-t0)/float(STEPS))*1.01, (dataBoundsMax[2]-dataBoundsMin[2])/float(STEPS));\n\t\tvec3 initialSample = ((eye + dir * t0) - dataBoundsMin) / (dataBoundsMax-dataBoundsMin);\n        initialSample = ReverseCoordMapping(initialSample);\n        float ld = texture(data, initialSample).r;\n\t\tbool lastShouldRender = ShouldRenderSample(initialSample);\n        \n        t1 = min(t1, sceneDepthT);\n        int i = 0;\n        for (float t = t0; t < t1; t += step) {\n            vec3 hit = eye + dir * t;\n            vec3 dataSTR = (hit - dataBoundsMin) / (dataBoundsMax-dataBoundsMin);\n            vec3 dataSTRMapped = ReverseCoordMapping(dataSTR);\n            float dv = texture(data, dataSTRMapped).r;\n\t\t\tbool shouldRender = ShouldRenderSample(dataSTRMapped);\n            \n\t\t\tif (shouldRender && lastShouldRender) {\n\t\t\t\t// Unrolled intentionally\n\t\t\t\tif (isoEnabled[0]) TestIso(eye, dir, rayLightingNormal, isoValue[0], dv, ld, step, t, accum);\n\t\t\t\tif (isoEnabled[1]) TestIso(eye, dir, rayLightingNormal, isoValue[1], dv, ld, step, t, accum);\n\t\t\t\tif (isoEnabled[2]) TestIso(eye, dir, rayLightingNormal, isoValue[2], dv, ld, step, t, accum);\n\t\t\t\tif (isoEnabled[3]) TestIso(eye, dir, rayLightingNormal, isoValue[3], dv, ld, step, t, accum);\n                \n                if (accum.a > ALPHA_BREAK)\n                    gl_FragDepth = CalculateDepth(hit);\n\t\t\t}\n            ld = dv;\n\t\t\tlastShouldRender = shouldRender;\n            \n            if (accum.a > ALPHA_BREAK)\n                break;\n                \n            // Failsafe\n            if (i++ > STEPS)\n                break;\n        }\n        \n        fragColor = accum;\n    } else {\n        fragColor = vec4(0.f);\n    }\n        \n    if (accum.a < ALPHA_DISCARD)\n        gl_FragDepth = GetDepthBuffer();\n}\n"
  },
  {
    "path": "share/shaders/VolumeRectilinearIso.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec2 vertex;\nlayout (location = 1) in vec2 vTextureCoord;\n\nout vec2 ST;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 0.0, 1.0);\n\tST = vTextureCoord;\n}\n"
  },
  {
    "path": "share/shaders/White.frag",
    "content": "#version 330 core\n\nout vec4 fragColor;\n\nvoid main(void)\n{\n\tfragColor = vec4(1);\n}\n"
  },
  {
    "path": "share/shaders/White.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vertex;\n\nvoid main()\n{\n\tgl_Position = vec4(vertex, 1.0);\n}\n"
  },
  {
    "path": "share/shaders/Wireframe.frag",
    "content": "#version 330 core\n\nuniform sampler1D colormap;\nuniform float minLUTValue;\nuniform float maxLUTValue;\n\nin float fValue;\nin float fMissing;\nout vec4 FragColor;\n\nvoid main() {\n    //FragColor = fColor;\n    \n    float s = (fValue - minLUTValue) / (maxLUTValue - minLUTValue);\n    vec4 color = texture(colormap, s);\n    FragColor = color;\n    \n    if (fMissing != 0.f)\n        discard;\n}\n"
  },
  {
    "path": "share/shaders/Wireframe.vert",
    "content": "#version 330 core\n\nlayout (location = 0) in vec3 vPos;\nlayout (location = 1) in float value;\nlayout (location = 2) in float missing;\n\nout float fValue;\nout float fMissing;\n\nuniform mat4 MVP;\n\nuniform vec4 clippingPlanes[6];\nout float gl_ClipDistance[6];\n\nvoid main() {\n    gl_Position = MVP * vec4(vPos, 1.0);\n    fValue = value;\n    fMissing = missing;\n\n\tfor (int i = 0; i < 6; i++)\n\t\tgl_ClipDistance[i] = dot(vec4(vPos, 1.0), clippingPlanes[i]);\n}\n"
  },
  {
    "path": "share/shaders/depthpeeling.efc",
    "content": "depthpeeling\ndepthpeeling\ndepthpeeling"
  },
  {
    "path": "share/shaders/font.frag",
    "content": "#version 330 core\nin vec2 TexCoords;\nout vec4 fragment;\n\nuniform vec4 color;\nuniform sampler2D text;\n\nvoid main()\n{\n    vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n    fragment = color * sampled;\n}\n"
  },
  {
    "path": "share/shaders/font.vert",
    "content": "#version 330 core\nlayout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>\nout vec2 TexCoords;\n\nuniform mat4 MVP;\n\nvoid main()\n{\n    gl_Position = MVP * vec4(vertex.xy, 0.0, 1.0);\n    TexCoords = vertex.zw;\n}\n"
  },
  {
    "path": "share/shaders/includes/alphagradient.hgl",
    "content": "//-----------------------------------------------------------------------\n// Compute the gradient using the alpha channel\n//-----------------------------------------------------------------------\nuniform sampler1D colormap;\nuniform sampler3D volumeTexture;\nuniform vec3 dimensions;\nvec3 alphaGradient()\n{\n  vec3 gradient;\n    \n  float dx = 0.5/(dimensions.x);\n    float dy = 0.5/(dimensions.y);\n    float dz = 0.5/(dimensions.z);\n    \n    vec3 a0;\n    vec3 a1;\n    \n    a0.x = texture1D(colormap, \n                     texture3D(volumeTexture, \n                               gl_TexCoord[0].xyz + vec3(dx,0,0)).x).a;\n    a1.x = texture1D(colormap, \n                     texture3D(volumeTexture, \n                               gl_TexCoord[0].xyz + vec3(-dx,0,0)).x).a;\n    \n    a0.y = texture1D(colormap, \n                     texture3D(volumeTexture, \n                               gl_TexCoord[0].xyz + vec3(0,dy,0)).x).a;\n    a1.y = texture1D(colormap, \n                     texture3D(volumeTexture, \n                               gl_TexCoord[0].xyz + vec3(0,-dy,0)).x).a;\n    \n    a0.z = texture1D(colormap, \n                     texture3D(volumeTexture, \n                               gl_TexCoord[0].xyz + vec3(0,0,dz)).x).a;\n    a1.z = texture1D(colormap, \n                     texture3D(volumeTexture, \n                               gl_TexCoord[0].xyz + vec3(0,0,-dz)).x).a;\n    \n    gradient = (a1-a0)/2.0;\n    \n    return gradient;\n  }\n  "
  },
  {
    "path": "share/shaders/includes/cart2sph.hgl",
    "content": "//-------------------------------------------------------------------------\n// Cartesian -> Spherical transform\n//-------------------------------------------------------------------------\nvec3 cart2sph(vec3 cartesian)\n{\n  const float pi = 3.14159;\n\n  vec3 spherical;\n\n  spherical.z = length(cartesian.xyz);\n  spherical.x = asin(clamp(cartesian.y / length(cartesian.yz), -1.0, 1.0));\n  spherical.y = acos(clamp(cartesian.x / spherical.z, -1.0, 1.0));\n  \n  if (cartesian.z >= 0.0)\n  {\n    if (spherical.x < 0.0) spherical.x += 2.0*pi;\n  }\n  else\n  {\n    spherical.x = pi - spherical.x;\n  }\n  \n  // Spherical coordinates \n  // spherical.y (0, pi) \n  // spherical.x (0, 2pi) \n  \n  spherical.y = (spherical.y / (pi));\n  spherical.x = (spherical.x / (2.0*pi));\n\n  // Normalized spherical coordinates \n  // spherical.z (0, 1) \n  // spherical.y (0, 1) \n  // spherical.x (0, 1) \n  spherical = (spherical - dmin) * ((tmax - tmin) / (dmax - dmin)) + tmin;\n\n  return spherical;\n}\n"
  },
  {
    "path": "share/shaders/includes/datagradient.hgl",
    "content": "\nuniform sampler3D volumeTexture;\nvec3 permute(vec3 v);\n\nuniform vec3 dimensions;\nvec3 dataGradient(vec3 coord)\n{\n  const float pi = 3.14159;\n\n  vec3 sgradient;\n  vec3 gradient;\n\n  float dx = 0.5/(dimensions.x);\n  float dy = 0.5/(dimensions.y);\n  float dz = 0.5/(dimensions.z);\n  \n  vec3 a0;\n  vec3 a1;\n\n  a0.x = texture3D(volumeTexture, coord + vec3(dx,0,0)).x;\n  a1.x = texture3D(volumeTexture, coord + vec3(-dx,0,0)).x;\n  a0.y = texture3D(volumeTexture, coord + vec3(0,dy,0)).x;\n  a1.y = texture3D(volumeTexture, coord + vec3(0,-dy,0)).x;\n  a0.z = texture3D(volumeTexture, coord + vec3(0,0,dz)).x;\n  a1.z = texture3D(volumeTexture, coord + vec3(0,0,-dz)).x;\n\n  // \n  // Compute the spherical gradient \n  // \n  sgradient = permute((a1-a0)/2.0);\n  //sgradient.x = (sgradient.x / (coord.z * sin(coord.y*pi-pi/2.0)));\n  //sgradient.y = (sgradient.y / coord.z); \n\n  // \n  // Transform the vector into the cartesian coordinate space \n  // \n  float sinphi = sin(sgradient.x * 2.0*pi-pi);\n  float cosphi = cos(sgradient.x * 2.0*pi-pi);\n  float sintheta = sin(sgradient.y * pi - pi/2.0);\n  float costheta = cos(sgradient.y * pi - pi/2.0);\n\n  mat3 t = mat3(-sinphi, costheta*cosphi,   sintheta*cosphi,\n                cosphi,  sintheta*sintheta, costheta*sinphi,\n                0,       costheta,          -sintheta);\n\n  gradient = t * sgradient;\n\n  return gradient;\n}\n"
  },
  {
    "path": "share/shaders/includes/depthpeeling.hgl",
    "content": "uniform sampler2D previousPass;\nuniform float width;\nuniform float height;\nvoid DepthPeel(in float calc_depth, in vec4 calc_color) {\n    //sample previous depth fragment value at my x,y position in the window\n    vec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height);\n    float depth = texture2D(previousPass, texCoord).z;\n    //use bias to avoid floating point rounding errors, can be adjusted to be more precise\n    // by adding more 0s if z-fighting is an issue\n    float bias =  .0000000000001;\n    //ensure that only fragments behind the previously recorded depth get tested\n    if (depth > calc_depth  || abs(depth - calc_depth) < bias )\n     \t  discard;\n\t\n    gl_FragDepth =  calc_depth;\n    gl_FragColor= calc_color;\t\n}\n"
  },
  {
    "path": "share/shaders/includes/gradient.hgl",
    "content": "uniform sampler3D volumeTexture;\t// sampled data to ray cast\nvec3 Gradient(in vec3 delta, in vec3 tc)\n  {\n    vec3 gradient;  \n    float dx = delta.x;\n    float dy = delta.y;\n    float dz = delta.z;\n    vec3 a0;\n    vec3 a1;\n  \n    a0.x = texture3D(volumeTexture, tc + vec3(dx,0,0)).x;\n    a1.x = texture3D(volumeTexture, tc - vec3(dx,0,0)).x;\n    a0.y = texture3D(volumeTexture, tc + vec3(0,dy,0)).x;\n    a1.y = texture3D(volumeTexture, tc - vec3(0,dy,0)).x;\n    a0.z = texture3D(volumeTexture, tc + vec3(0,0,dz)).x;\n    a1.z = texture3D(volumeTexture, tc - vec3(0,0,dz)).x;\n    gradient = (a1-a0)/2.0;\n    return gradient;\n  }\n  \n"
  },
  {
    "path": "share/shaders/includes/gradient2.hgl",
    "content": "uniform sampler3D volumeTexture;\n\nvec3 Gradient(in vec3 dims, in vec3 tc)\n{\n  if (dims.x<=0 || dims.y<=0 || dims.z<=0) \n    return(vec3(0.0, 0.0, 0.0));\n\n  vec3 h0 = vec3(-0.5,-0.5,-0.5) / dims;\n  vec3 h1 = vec3(0.5,0.5,0.5) / dims;\n  vec3 h = vec3(1.0, 1.0, 1.0);\n\n  if ((tc.x + h0.x) < 0.0) {\n    h0.x = 0.0;\n    h.x = 0.5;\n  }\n  if ((tc.x + h1.x) > 1.0) {\n    h1.x = 0.0;\n    h.x = 0.5;\n  }\n  if ((tc.y + h0.y) < 0.0) {\n    h0.y = 0.0;\n    h.y = 0.5;\n  }\n  if ((tc.y + h1.y) > 1.0) {\n    h1.y = 0.0;\n    h.y = 0.5;\n  }\n  if ((tc.z + h0.z) < 0.0) {\n    h0.z = 0.0;\n    h.z = 0.5;\n  }\n  if ((tc.z + h1.z) > 1.0) {\n    h1.z = 0.0;\n    h.z = 0.5;\n  }\n\n  vec3 a0, a1;\n  a0.x = texture3D(volumeTexture, tc + vec3(h0.x,0.0,0.0)).x;\n  a1.x = texture3D(volumeTexture, tc + vec3(h1.x,0.0,0.0)).x;\n  a0.y = texture3D(volumeTexture, tc + vec3(0.0,h0.y,0.0)).x;\n  a1.y = texture3D(volumeTexture, tc + vec3(0.0,h1.y,0.0)).x;\n  a0.z = texture3D(volumeTexture, tc + vec3(0.0,0.0,h0.z)).x;\n  a1.z = texture3D(volumeTexture, tc + vec3(0.0,0.0,h1.z)).x;\n\n  return (a1-a0 / h);\n}\n"
  },
  {
    "path": "share/shaders/includes/invpermute.hgl",
    "content": "uniform vec3 permutation;\nvec3 invPermute(vec3 v)\n{\n  vec3 p = v;\n\n  // \n  // Unfortunately, GLSL 2.0 doesn't seem to allow \n  // a uniform to be used as an index. We'll do it \n  // the long way. \n  // \n  if (permutation.x == 2.0) p.x = v.z;\n  else if (permutation.x == 1.0) p.x = v.y;\n\n  if (permutation.y == 2.0) p.y = v.z;\n  else if (permutation.y == 0.0) p.y = v.x;\n\n  if (permutation.z == 0.0) p.z = v.x;\n  else if (permutation.z == 1.0) p.z = v.y;\n\n  return p;\n}\n"
  },
  {
    "path": "share/shaders/includes/permute.hgl",
    "content": "uniform vec3 permutation;\n//-------------------------------------------------------------------------\n// Rearrange the vector into (lon, lat, radius) order \n//-------------------------------------------------------------------------\nvec3 permute(vec3 v)\n{\n  vec3 p = v;\n\n  // \n  // Unfortunately, GLSL 2.0 doesn't seem to allow \n  // a uniform to be used as an index. We'll do it \n  // the long way. \\n\n  // \n  if (permutation.x == 2.0) p.z = v.x;\n  else if (permutation.x == 1.0) p.y = v.x;\n\n  if (permutation.y == 2.0) p.z = v.y;\n  else if (permutation.y == 0.0) p.x = v.y;\n\n  if (permutation.z == 0.0) p.x = v.z;\n  else if (permutation.z == 1.0) p.y = v.z;\n\n  return p;\n}\n"
  },
  {
    "path": "share/shaders/includes/tex2lay.hgl",
    "content": "//-------------------------------------------------------------------------\n// texture -> layered transform\n//\n// The 3D grid represented by volumeTexture is non-regular in Z. The \n// Z coordinate of each grid point is given by volumeTexture[zidx].\n// This function maps the Z component of texCoord (in \"user\" coordinates) \n// to a new Z (in texture coordinates) that most closely matches \n// the  user coordinate Z. texCoord.xy is unchanged.\n//\n//-------------------------------------------------------------------------\nuniform sampler3D volumeTexture;\nuniform vec3 dimensions;    // ijk dimensions of 3D texture\n\n\nvec3 tex2lay(vec3 texCoord, int zidx)\n{\n\tvec3 invalid = vec3(-1.0, -1.0, -1.0); // invalid coordinate\n\n\tif (dimensions.z<=0) return(invalid);\n\tfloat zmin = (1.0 / dimensions.z) * 0.5;\n\tfloat zmax = (1.0 - zmin);\n\tif (texCoord.z<zmin || texCoord.z>zmax) return(invalid);\n\n\t// N is the number of iterations used to find Z in the search \n\t// algorithm below. \n\t// \n\tint N = int(ceil(log2(float(dimensions.z))));\n\n\tvec3 texCoord0 = texCoord;\n\tvec3 texCoord1 = texCoord;\n\tvec3 layered = texCoord;\n\n\ttexCoord0.z = zmin;\n\ttexCoord1.z = zmax;\n\tfloat z0 = texture3D(volumeTexture, texCoord0)[zidx];\n\tfloat z1 = texture3D(volumeTexture, texCoord1)[zidx];\n\tfloat z = texCoord.z;\n\n\t// make sure z is in initial interval\n\tif (((z-z1) * (z-z0)) > 0.0) {\n\t\treturn (invalid);\n\t}\n\n\t//\n\t// Use a binary search to locate the interval containing the \n\t// desired 'z' coordinate\n\t//\n\tfor (int i=0; i<N; i++) {\n      float t0save = texCoord0.z;\n\t  texCoord0.z = (texCoord0.z + texCoord1.z) * 0.5;\n\t  z0 = texture3D(volumeTexture, texCoord0)[zidx];\n      if (z0==z) break;\n\n\t  // if interval we guessed is wrong, z must be in other interval\n\t  if (((z-z1) * (z-z0)) > 0.0) {\n\t\t  texCoord1.z = texCoord0.z;\n          texCoord0.z = t0save;\n\t\t  z1 = texture3D(volumeTexture, texCoord1)[zidx];\n\t  }\n\t}\n\tz0 = texture3D(volumeTexture, texCoord0)[zidx];\n\n\tfloat weight;\n\tif ((z1-z0)<=0) {\n\t\tweight = 0.0;\n\t}\n\telse {\n\t\tweight = (z-z0) / (z1-z0);\n\t}\n\tlayered.z = texCoord0.z + (weight * (texCoord1.z-texCoord0.z));\n\n//\tclamp() doesn't work, and not sure why it is needed :-(\n//\n//\tlayered.z = clamp(layered.z,zmin,zmax);\n\n\tif (layered.z < zmin) layered.z = zmin;\n\tif (layered.z > zmax) layered.z = zmax;\n\n\treturn(layered);\n\n}\n"
  },
  {
    "path": "share/shaders/main/2DData.fgl",
    "content": "varying float lightIntensity;\nuniform sampler1D colormap;\nuniform float minLUTValue;\nuniform float maxLUTValue;\n\n#ifdef\tUSE_VERTEX_ATTR\nvarying vec2 vertexData;\n#else\nuniform sampler2D dataTexture;\n#endif\n\n//------------------------------------------------------------------\n// Fragment shader main\n//------------------------------------------------------------------\nvoid main(void)\n{\n\tif (minLUTValue >= maxLUTValue) discard;\n\n\tvec2 texCoord0 = gl_TexCoord[0].xy;\n\n#ifdef\tUSE_VERTEX_ATTR\n\tvec2 texel = vertexData;\n#else\n    vec2 texel = texture2D(dataTexture, texCoord0).xy;\n#endif\n\n\t// Check for missing value\n\t//\n\tif (texel.y != 0.0) discard;\n\n\tfloat s = (texel.x - minLUTValue) / (maxLUTValue - minLUTValue);\n\tvec4 color     = texture1D(colormap, s);\n\n\tcolor.rgb = color.rgb * lightIntensity;\n\n\tgl_FragColor = vec4(color);\n}\n"
  },
  {
    "path": "share/shaders/main/2DData.vgl",
    "content": "//\n// 2D Data surface renderer\n//\n\nvarying float lightIntensity;\n\nuniform bool lightingEnabled;\nuniform float kd;\nuniform float ka;\nuniform float ks;\nuniform float expS;\nuniform vec3 lightDirection;\n\n#ifdef  USE_VERTEX_ATTR \nattribute vec2 vertexDataAttr;\nvarying vec2 vertexData;\n#endif\n\nvoid main() {\n\n\tif (lightingEnabled) {\n\t\tvec3 ecPosition = vec3(gl_ModelViewMatrix * gl_Vertex);\n\t\tvec3 tnorm = normalize(gl_NormalMatrix * gl_Normal);\n\t\tvec3 lightVec = normalize(lightDirection);\n\t\tvec3 reflectVec = reflect(-lightVec, tnorm);\n\t\tvec3 viewVec = normalize(-ecPosition);\n\n\t\tfloat spec = clamp(dot(reflectVec, viewVec), 0.0, 1.0);\n\t\tspec = pow(spec, expS);\n\n\t\tlightIntensity = ka + kd * max(dot(lightVec, tnorm), 0.0) + ks*spec; \n\t}\n\telse {\n\t\tlightIntensity = 1.0;\n\t}\n\n\tgl_TexCoord[0] = gl_MultiTexCoord0;\n\tgl_Position = ftransform();\n\tgl_ClipVertex = gl_ModelViewMatrix * gl_Vertex; \n\n\n#ifdef  USE_VERTEX_ATTR \n\tvertexData = vertexDataAttr;\n#endif\n}\n"
  },
  {
    "path": "share/shaders/main/Iso.fgl",
    "content": "#include gradient2.hgl\n#include tex2lay.hgl\nvec3 tex2lay(vec3 texCoord, int comp);\n\n#ifdef\tMAPPED\nuniform sampler1D colormap;\n#endif\n\nuniform sampler1D coordmap;\n\nuniform sampler2D texcrd_buffer;\t// tex coords for back facing quads\nuniform sampler2D depth_buffer;\t// depth back facing quads\nuniform sampler3D volumeTexture;\t// sampled data to ray cast\nuniform float isovalue;\nuniform int zidx;\t// texel component containing user Z coordinate\nuniform int midx;\t// texel component containing missing data indicator\nuniform bool fast;\t// render fast\nuniform bool stretched;  // stretched coordinates (rectilinear grid)\n\n\n\n\n#ifdef\tMAPPED\nuniform int vidx;\t// texel component containing mapped variable\n#else\nuniform vec4 isocolor;\t// base color for isosurface\n#endif\n  \nuniform int nsamples;\t// sampling distance along ray (eye coordinates)\n\nvarying vec4 position;\t// interpolated gl_Position\n\n#ifdef\tLIGHTING\nuniform vec2 winsize;\t// Window width and height \n  \n// Lighting parameters\n  \nuniform vec3 dimensions;\t// ijk dimensions of 3D texture\nuniform vec3 lightDirection;\nuniform float kd;\nuniform float ka;\nuniform float ks;\nuniform float expS;\n  \n  \nvarying vec3 view;\t// normalized, negative position (view vector)\n#endif\n#ifdef DEPTHPEEL\nuniform int currentLayer;\nuniform sampler2D previousPass;\nuniform float width;\nuniform float height;\n#endif  \nvec3 Gradient(in vec3, in vec3);\n\n// The GLSL discard keyword is broken under MacOS 10.6 with nVidia drivers\n//\nvoid mydiscard() {\n\tgl_FragColor = vec4(0.0,0.0,0.0,0.0);\n\tgl_FragDepth = gl_DepthRange.far;\n\t// discard;\n}\n\n//------------------------------------------------------------------\n// Fragment shader main\n//------------------------------------------------------------------\n\nvoid main(void)\n{\n\t\t\n\t// Normalized window coordinates of this frament\n\tif (position.w == 0.0) {\n\t\tmydiscard(); return;\n\t}\n\tvec2 texCoord2D = ((position.xy / position.w) + 1.0) / 2.0;\n\n\t// Starting and finishing texture coordinate of ray\n\tvec3 texStop = texture2D(texcrd_buffer, texCoord2D).xyz;\n\tvec3 texStart = gl_TexCoord[0].xyz;\n\n\t// Ray direction, texture coordinates\n\tvec3 texDir = texStop - texStart;\n\tif (length(texDir) == 0.0) {\n\t\tmydiscard(); return;\n\t}\n\tvec3 texDirUnit = normalize(texDir);\n\n\tfloat n = gl_DepthRange.near;\n\tfloat f = gl_DepthRange.far;\n\tif ((f-n) == 0.0) {\n\t\tmydiscard(); return;\n\t}\n\n\t// Starting and stopping Z (window, NDC and eye coordinates)\n\t// We need eye coordinates to interpolate depth (Z) because\n\t// NDC and Window space is non-linear\n\t// N.B. Inverse transform of window coords only works for perspective\n\n\tfloat zStopWin = texture2D(depth_buffer, texCoord2D).x;\n\tfloat zStopNDC = (2*zStopWin)/(f-n) - (n+f)/(f-n);\n\tfloat zStopEye = -gl_ProjectionMatrix[3].z / (zStopNDC + gl_ProjectionMatrix[2].z);\n\tfloat zStartWin = gl_FragCoord.z;\n\tfloat zStartNDC = (2*zStartWin)/(f-n) - (n+f)/(f-n);\n\tfloat zStartEye = -gl_ProjectionMatrix[3].z / (zStartNDC + gl_ProjectionMatrix[2].z);\n\n#ifdef\tLIGHTING\n\tvec3 lightColor = vec3(1.0, 1.0, 1.0);\n\tvec2 posNDC = gl_FragCoord.xy * 2.0 / winsize.xy - 1.0;\n#endif\n\n\t// Compute number of samples based on samplin distance, delta \n\t//\n\tint nsegs = int(min(float(nsamples), 256.0));\n\tif (fast) nsegs = 16;\n\n\tvec3 deltaVec = texDir / float(nsegs-1.0);\n\tfloat deltaZ = (zStopEye-zStartEye) / float(nsegs-1.0);\n\n\t// texCoord{0,1} are the end points of a ray segment in texture coords\n\t// s{0,1} are the sampled values of the texture at ray segment endpoints\n\tvec3 texCoord0 = texStart;\n\tvec3 texCoord1 = texCoord0+deltaVec;\n\n\tfloat s0, s1;\n\n#ifdef DEPTHPEEL\n\tif (width <= 0.0 || height <= 0.0) {\n\t\tmydiscard(); return;\n\t} \n\tbool hit = false;\n\tint layerCount = 0;\n#endif\n\n\tbool missing = false;\n\tvec3 t0 = texCoord0;\n\tvec3 t1 = texCoord1;\n\tif (zidx>0 && ! fast) {\n\t\t//\n\t\t// With layered data the starting point of the ray may not reside\n\t\t// inside of the data volume. Keep stepping along ray until\n\t\t// we're inside.\n\t\t//\n\t\tbool outside = true;\n\t\twhile (outside && (nsegs > 0)) {\n\t\t\tt0 = tex2lay(texCoord0, zidx);\n\t\t\tt1 = tex2lay(texCoord1, zidx);\n\t\t\tif (t0.x < 0.0 || t0.y < 0.0 || t0.z < 0.0 ||\n\t\t\t\tt0.x > 1.0 || t0.y > 1.0 || t0.z > 1.0 || \n\t\t\t\tt1.x < 0.0 || t1.y < 0.0 || t1.z < 0.0 || \n\t\t\t\tt1.x > 1.0 || t1.y > 1.0 || t1.z > 1.0) {\n\t\t\t\t// ray starting point is outside the volume\n\t\t\t\t//\n\t\t\t\ttexCoord0 = texCoord1;\n\t\t\t\ttexCoord1 = texCoord1+deltaVec;\n\t\t\t\tnsegs--;\n\t\t\t}\n\t\t\telse {\n\t\t\t\toutside = false;\n\t\t\t}\n\t\t}\n\t\tif (outside) {\n\t\t\tmydiscard(); return;\n\t\t}\n\t}\n\telse if (stretched) {\n\t\t\tt0.x = texture1D(coordmap, t0.x).x;\n\t\t\tt0.y = texture1D(coordmap, t0.y).y;\n\t\t\tt0.z = texture1D(coordmap, t0.z).z;\n\t\t\tt1.x = texture1D(coordmap, t1.x).x;\n\t\t\tt1.y = texture1D(coordmap, t1.y).y;\n\t\t\tt1.z = texture1D(coordmap, t1.z).z;\n\t}\n\n\ts0 = texture3D(volumeTexture, t0).x;\n\ts1 = texture3D(volumeTexture, t1).x;\n\tif (midx > 0) {\n\t\tif ((texture3D(volumeTexture, t0)[midx] != 0.0) || \n\t\t\t(texture3D(volumeTexture, t1)[midx] != 0.0)) {\n\n\t\t\tmissing = true;\n\t\t}\n\t}\n\n\t// Current Z value along ray and current (accumulated) color \n\tfloat fragDepth = zStartEye;\n\tvec4 fragColor =  vec4(0.0, 0.0, 0.0, 0.0);\n\n\t// Make sure gl_FragDepth is set for all execution paths\n\tgl_FragDepth = zStopWin;\n\n\t// Composite from front to back\n\n\t// false after first isosurface interesected \n\tbool first = true;\n\n\tfor (int i = 0; i<nsegs; i++) {\n\n\t\t// If sign changes we have an isosurface\n\n\t\tif ((! missing) && (((isovalue-s1) * (isovalue-s0)) < 0.0)) {\n\n\t\t\tfloat weight = (isovalue-s0) / (s1-s0);\n\n#if defined (MAPPED) || defined (LIGHTING)\n\t\t\t// find precise texture coord of isovalue with linear \n\t\t\t// interpolation current segment end points \n\t\t\tvec3 isoTexCoord = texCoord0 + (weight * deltaVec);\n\t\t\tif (zidx>0 && ! fast) {\n\t\t\t\tisoTexCoord = tex2lay(isoTexCoord, zidx);\n\t\t\t\tif (isoTexCoord.x < 0.0) {\n\t\t\t\t\tmydiscard(); return;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (stretched) {\n\t\t\t\tisoTexCoord.x = texture1D(coordmap, isoTexCoord.x).x;\n\t\t\t\tisoTexCoord.y = texture1D(coordmap, isoTexCoord.y).y;\n\t\t\t\tisoTexCoord.z = texture1D(coordmap, isoTexCoord.z).z;\n\t\t\t}\n#endif\n\n#ifdef\tMAPPED\n\t\t\t// pseudo color isosurface with 2nd variable\n\t\t\t//\n\t\t\tfloat var2 = texture3D(volumeTexture,isoTexCoord)[vidx];\n\t\t\tvec4 color = vec4(texture1D(colormap, var2));\n#else\n\t\t\tvec4 color = isocolor;\n#endif\n\n#ifdef\tLIGHTING\n\n\t\t\t// compute surface gradient at ray's intersection with isosurface\n\t\t\tvec3 gradient = gl_NormalMatrix * Gradient(dimensions, isoTexCoord);\n\n\t\t\tfloat diffuse = 0.0;\n\t\t\tfloat specular = 0.0;\n\n\t\t\tif (length(gradient) > 0.0 && fragDepth != 0.0) {\n\n\t\t\t\tgradient = normalize(gradient);\n\t\t\t\t// Ugh. Need to convert ray intersection point to eye coords \n\t\t\t\tvec4 posClip = vec4( \n\t\t\t\t\tposNDC, \n\t\t\t\t\t-gl_ProjectionMatrix[3].z / fragDepth - gl_ProjectionMatrix[2].z,\n\t\t\t\t1.0);\n\t\t\t\tvec4 eyePos = gl_ProjectionMatrixInverse * posClip;\n\t\t\t\teyePos /= eyePos.w;\n\n\t\t\t\t//use Phong illumination if non-zero gradient\n\n\t\t\t\tvec3 lightVec      = normalize(lightDirection);\n\t\t\t\tvec3 halfv      = reflect(-lightVec, gradient);\n\t\t\t\tvec3 viewVec      = normalize(-eyePos.xyz);\n\n\t\t\t\tdiffuse  = abs(dot(lightVec, gradient));\n\t\t\t\tif (diffuse > 0.0) {\n\t\t\t\t\tspecular = pow(abs(dot(halfv, viewVec)), expS);\n\t\t\t\t}\n\n\t\t\t}\n\t\t\tdiffuse = kd * diffuse;\n\t\t\tspecular = ks * specular;\n\n\t\t\tcolor.xyz = color.xyz * (ka+diffuse) + vec3(specular*lightColor);\n#endif\n\n#ifndef DEPTHPEEL\n\t\t\t// blend fragment color with front to back compositing operator \n\t\t\tfragColor = (vec4(1.0)- vec4(fragColor.a))*color + fragColor;\n#else\n\t\t\t// no manual blending, depth peeling will automatically do this\n\t\t\tfragColor = color;\n#endif\n\n\t\t\t// The depth buffer value will be the first ray-isosurface \n\t\t\t// intersection. N.B. may not be best choice \n#ifndef DEPTHPEEL\n\t\t\tif (first) {\n\t\t\t\tfragDepth = zStartEye + (float(i) * deltaZ) + (deltaZ*weight);\n\t\t\t\tfirst = false;\n\t\t\t}\n#else\n\t\t\t// the depth peeling algorithm has two parts with regards to output:\n\t\t\t// initial pass: get the first depth layer, and run \n\t\t\t// it through a depth test\n\t\t\t//\n\t\t\tfragDepth = zStartEye + (float(i) * deltaZ) + (deltaZ*weight);\n\t\t\tfragDepth = fragDepth == 0.0 ? -1.0 : (fragDepth * gl_ProjectionMatrix[2].z + gl_ProjectionMatrix[3].z) / -fragDepth; \n\t\t\tfragDepth = fragDepth * ((f-n)/2) + (n+f)/2;\n\n\t\t\t// isosurface found, check layer and depth test if not \n\t\t\t// initial rendering\n\t\t\t//\n\t\t\tif(currentLayer == 0){ //kick out colors normally for depth testing\n\t\t\t  \tgl_FragDepth = fragDepth;\n\t\t\t  \tgl_FragColor = vec4(fragColor.r, fragColor.g, fragColor.b, fragColor.a);\n\t\t\t  \thit = true;\n\t\t\t  \tbreak;\n\t\t\t}\n\t\t\telse { //run the iso loop until the surface passes the depth peeling check,\n\t\t\t       //i.e. the iso surface has a depth greater than the previously recorded depth\n\t\t\t     //find texture coord of fragment\n\t\t\t     vec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height);\n\t\t\t     //retrieve the depth of the frag that passed the initial gl_less test, could be currentlayer ==0\n\t\t\t     //or another fragment from a different renderer\n\t\t\t     float depthWin = texture2D(previousPass, texCoord).x; \n\t\t\t     if (depthWin < fragDepth && abs(depthWin - fragDepth) > .00000000000000001){\t\t\t\n\t\t\t     \tgl_FragDepth = fragDepth;\n\t\t\t     \tgl_FragColor = vec4(fragColor.r, fragColor.g, fragColor.b, fragColor.a);\n\t\t\t     \thit = true;\n\t\t\t     \tbreak;\n\t\t\t     }\n\t\t\t}\n\t\t\tlayerCount++;\n#endif\n#ifndef DEPTHPEEL\n\t\t\t//\n\t\t\t// early ray termination\n\t\t\t//\n\t\t\tif (fragColor.a >= 0.95) break;\n#endif\n\t\t}\n\n\t\ttexCoord0 = texCoord1;\n\t\ttexCoord1 = texCoord1+deltaVec;\n\t\tt1 = texCoord1;\n\t\ts0 = s1;\n\t\tif (zidx>0 && ! fast) {\n\t\t\tt1 = tex2lay(t1, zidx);\n\t\t} \n\t\telse if (stretched) {\n\t\t\tt1.x = texture1D(coordmap, t1.x).x;\n\t\t\tt1.y = texture1D(coordmap, t1.y).y;\n\t\t\tt1.z = texture1D(coordmap, t1.z).z;\n\t\t}\n\n\t\t//\n\t\t// If outside of texture we're done\n\t\t//\n\t\tif (t1.x < 0.0 || t1.y < 0.0 || t1.z < 0.0 || \n\t\t\tt1.x > 1.0 || t1.y > 1.0 || t1.z > 1.0) {\n\t\t\t\n\t\t\tbreak;\n\t\t}\n#ifdef DEPTHPEEL\n\t\tif (hit) break;\n#endif\n\n\t\t// if texCoord1 is inside the volume then lookup new \n\t\t// value for s1. Otherwise s1 == s0 and there is no\n\t\t// ray-surface intersection\n\t\t//\n\t\ts1 = texture3D(volumeTexture, t1).x;\n\t\tif (midx > 0) {\n\t\t\tif (missing) s0 = s1;\n\t\t\tmissing = (texture3D(volumeTexture, t1)[midx] != 0.0);\n\t\t}\n\t}\n#ifdef DEPTHPEEL\n\tif(!hit) discard;\n#endif\n\tif (fragColor.a == 0.0) {\n\t\tmydiscard(); return;\n\t}\n\n\t// Convert depth from eye coordinates back to window coords \n#ifndef DEPTHPEEL\n\tfragDepth = fragDepth == 0.0 ? -1.0 : (fragDepth * gl_ProjectionMatrix[2].z + gl_ProjectionMatrix[3].z) / -fragDepth; \n\t//note: update to use DepthPeel include function\n\t//DepthPeel(fragDepth * ((f-n)/2) + (n+f)/2, fragColor);\n\tgl_FragDepth = fragDepth * ((f-n)/2) + (n+f)/2;\n\tgl_FragColor = fragColor;\n#endif\n}\n"
  },
  {
    "path": "share/shaders/main/Iso.vgl",
    "content": "//-----------------------------------------------------------------------\n// Vertex shader main\n//-----------------------------------------------------------------------\nuniform mat4 glModelViewProjectionMatrix;\nvarying vec4 position;\n\n#ifdef\tLIGHTING\nvarying vec3 view;\n#endif\n\nvoid main(void)\n{\n  gl_TexCoord[0] = gl_MultiTexCoord0;\n  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n  gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;\n\n  position       = gl_Position;\n\n#ifdef\tLIGHTING\n  view           = normalize(-gl_Position.xyz);\n#endif\n\n}\n"
  },
  {
    "path": "share/shaders/main/ProgTexture.fgl",
    "content": "uniform bool first;\nuniform sampler2D previousPass;\nuniform float width;\nuniform float height;\nuniform sampler2D image;\nvoid main(){\n     vec4 color = texture2D(image, gl_TexCoord[3].st).rgba;\n     if(first){\n     \tgl_FragColor = color;\n     \tgl_FragDepth = gl_FragCoord.z;\n     }\n     else{\n\tvec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height);\n    \tfloat depth = texture2D(previousPass, texCoord).z;\t\t    \n     \n\tif (depth > gl_FragCoord.z  || abs(depth - gl_FragCoord.z) < .00000000001 || depth == 1.0 || depth == 0.0)\n     \t  discard;\n     \tgl_FragDepth =  gl_FragCoord.z;\n\tgl_FragColor= color;\n     }\n}"
  },
  {
    "path": "share/shaders/main/ProgTexture.vgl",
    "content": "\nvoid main(){\n    gl_TexCoord[3] = gl_MultiTexCoord3;\n    gl_FrontColor = gl_Color;\n    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}"
  },
  {
    "path": "share/shaders/main/SphericalDVR.fgl",
    "content": "#include permute.hgl\n#include invpermute.hgl\nuniform sampler1D colormap;\nuniform sampler3D volumeTexture;\nuniform vec3 tmin;\nuniform vec3 tmax;\t// min and max texture coordinates in range \nuniform vec3 dmin;\nuniform vec3 dmax;\t// min and max spherical coordinates\nuniform vec3 permutation;\nuniform bvec2 clip;\n\nvec3 permute(vec3 v);\nvec3 invPermute(vec3 v);\n//------------------------------------------------------------------ \n// Fragment shader main\n//------------------------------------------------------------------ \nvoid main(void)\n{\n\n  const float pi = 3.14159;\n\n  vec3 cartesian = permute(gl_TexCoord[0].xyz);\n  vec3 spherical;\n\n  cartesian = dmax.z * (cartesian * 2.0 - 1.0);\n\n  spherical.z = length(cartesian.xyz);\n\n  if (spherical.z > dmax.z || spherical.z < dmin.z)\n  {\n    gl_FragColor = vec4(0,0,0,0);\n  }\n  else\n  {\n    spherical.x = asin(clamp(cartesian.y / length(cartesian.yz), -1.0, 1.0));\n    spherical.y = acos(clamp(cartesian.x / spherical.z, -1.0, 1.0));\n\n    if (cartesian.z >= 0.0)\n    {\n      if (spherical.x < 0.0) spherical.x += 2.0*pi;\n    }\n    else\n    {\n      spherical.x = pi - spherical.x;\n    }\n\n    // Spherical coordinates \n    // spherical.y (0, pi) \n    // spherical.x (0, 2pi) \n    \n    spherical.y = (spherical.y / (pi));\n    spherical.x = (spherical.x / (2.0*pi));\n\n    // Normalized spherical coordinates \n    // spherical.z (0, 1) \n    // spherical.y (0, 1) \n    // spherical.x (0, 1) \n\n    if ((clip.y && (spherical.y < dmin.y || spherical.y > dmax.y)) ||\n        (clip.x && (spherical.x < dmin.x || spherical.x > dmax.x)))\n    {\n      gl_FragColor = vec4(1,1,1,0);\n    }\n    else\n    {\n      // Texture coordinates (dmin, dmax) -> (tmin, tmax) \n      spherical = (spherical - dmin) * ((tmax - tmin) / (dmax - dmin))+tmin;\n\n      vec4 intensity = vec4(texture3D(volumeTexture, invPermute(spherical)));\n      gl_FragColor = vec4 (texture1D(colormap, intensity.x));\n    }\n  }\n}\n"
  },
  {
    "path": "share/shaders/main/SphericalDVR.vgl",
    "content": "//-----------------------------------------------------------------------\n// Vertex shader main\n//-----------------------------------------------------------------------\n#ifdef\tLIGHTING\nvarying vec3 ecPosition; \n#endif\nvoid main(void)\n{\n\tgl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n\tgl_TexCoord[0] = gl_MultiTexCoord0;\n\n#ifdef\tLIGHTING\n\tecPosition     = vec3(gl_ModelViewMatrix * gl_Vertex);\n#endif\n}\n"
  },
  {
    "path": "share/shaders/main/depthpeeling.fgl",
    "content": "uniform sampler2D previousPass;\nuniform float width;\nuniform float height;\nvoid main() {\n\tif ((width == 0.0) || (height == 0.0)) discard;\n\tvec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height);\n    float depth = texture2D(previousPass, texCoord).z;\n    float bias = .00000000000000001;\n    if (depth > gl_FragCoord.z  || abs(depth - gl_FragCoord.z) < bias)// || depth == 1.0 || depth == 0.0) // -old comparisons, should not be necessary\n     \t  discard;\n    gl_FragDepth =  gl_FragCoord.z;\n    gl_FragColor= vec4(gl_Color.r, gl_Color.g, gl_Color.b, gl_Color.a);\n}\n"
  },
  {
    "path": "share/shaders/main/depthpeeling.vgl",
    "content": "\nvoid main() {\n    gl_FrontColor = gl_Color;\n    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}\n"
  },
  {
    "path": "share/shaders/main/texSampler.fgl",
    "content": "uniform sampler2D texUnit;\nuniform float width; \nuniform float height;\n\nvoid main() {\n\tif (width == 0.0 || height == 0.0) discard;\n\tvec2 texCoord = vec2(gl_FragCoord.x / width, gl_FragCoord.y / height);\n\tvec4 color = texture2D(texUnit, texCoord);\n\tgl_FragColor = color;\n\tgl_FragDepth =  gl_FragCoord.z;\n}\n"
  },
  {
    "path": "share/shaders/main/texSampler.vgl",
    "content": "\nvoid main() {\n    gl_FrontColor = gl_Color;\n    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n}"
  },
  {
    "path": "share/shaders/texSampler.efc",
    "content": "texSampler\ntexSampler\ntexSampler"
  },
  {
    "path": "share/udunits/udunits2-accepted.xml",
    "content": "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n<!--\nCopyright 2008, 2009 University Corporation for Atmospheric Research\n\nThis file is part of the UDUNITS-2 package.  See the file LICENSE\nin the top-level source-directory of the package for copying and\nredistribution conditions.\n\nUnits accepted for use with the SI\n-->\n<unit-system>\n    <!-- Hour, degree, liter, and the like -->\n        <unit>\n            <def>60 s</def>\n            <name><singular>minute</singular></name>\n            <symbol>min</symbol>\n        </unit>\n        <unit>\n            <def>60 min</def>\n            <name><singular>hour</singular></name>\n            <symbol>h</symbol>\n            <aliases> <symbol>hr</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>24 h</def>\n            <name><singular>day</singular></name>\n            <symbol>d</symbol>\n        </unit>\n        <unit>\n            <!-- This \"unit\" is useful in the definition of subsequent\n                 units.  -->\n            <def>3.141592653589793238462643383279</def>\n            <aliases>\n                <name><singular>pi</singular><noplural/></name>\n                <symbol>&#x3c0;</symbol>        <!-- GREEK SMALL LETTER PI -->\n            </aliases>\n        </unit>\n        <unit>\n            <def>(pi/180) rad</def>\n            <name><singular>arc_degree</singular></name>\n            <symbol>&#xB0;</symbol>             <!-- DEGREE SIGN -->\n            <aliases>\n                <name><singular>angular_degree</singular></name>\n                <name><singular>degree</singular></name>\n                <name><singular>arcdeg</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>&#xB0;/60</def>                <!-- DEGREE SIGN -->\n            <name><singular>arc_minute</singular></name>\n            <symbol>'</symbol>\n            <symbol>&#x2032;</symbol>           <!-- PRIME -->\n            <aliases>\n                <name><singular>angular_minute</singular></name>\n                <name><singular>arcminute</singular></name>\n                <name><singular>arcmin</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>'/60</def>\n            <name><singular>arc_second</singular></name>\n            <symbol>\"</symbol>\n            <symbol>&#x2033;</symbol>           <!-- DOUBLE PRIME -->\n            <aliases>\n                <name><singular>angular_second</singular></name>\n                <name><singular>arcsecond</singular></name>\n                <name><singular>arcsec</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <!-- The following is exact.  From 1901 to 1964, however, 1\n                 liter was 1.000028 dm^3 -->\n            <def>dm^3</def>\t\t        <!-- exact -->\n            <name><singular>liter</singular></name>\n            <symbol>L</symbol>                  <!-- NIST recommendation -->\n            <aliases>\n                <name><singular>litre</singular></name>\n                <symbol>l</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1000 kg</def>\n            <name><singular>metric_ton</singular></name>\n            <symbol>t</symbol>\n            <aliases> <name><singular>tonne</singular></name> </aliases>\n        </unit>\n\n    <!-- Units whose values are obtained experimentally -->\n        <unit>\n            <def>1.60217733e-19 J</def>\n            <name><singular>electronvolt</singular></name>\n            <symbol>eV</symbol>\n            <aliases>\n                <name><singular>electron_volt</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.6605402e-27 kg</def>\n            <name><singular>unified_atomic_mass_unit</singular></name>\n            <symbol>u</symbol>\n            <aliases>\n                <name> <singular>atomic_mass_unit</singular> </name>\n                <name> <singular>atomicmassunit</singular> </name>\n                <name> <singular>amu</singular><noplural/></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.495979e11 m</def>\n            <aliases>\n                <name><singular>astronomical_unit</singular></name>\n                <symbol>ua</symbol>\n            </aliases>\n        </unit>\n\n    <!-- Units temporarily accepted for use with the SI.  NB: <name>\n         and <symbol> elements appear only within <aliases>. -->\n        <unit>\n            <def>1852 m</def>\n            <aliases>\n                <name><singular>nautical_mile</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>nautical_mile/hour</def>\n            <aliases>\n                <name><singular>international_knot</singular></name>\n                <name><singular>knot_international</singular></name>\n                <name><singular>knot</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-10 m</def>\n            <aliases>\n                <name><singular>angstrom</singular></name>\n                <name><singular>&#xE5;ngstr&#xF6;m</singular></name>\n                <symbol>&#xC5;</symbol>         <!-- LATIN CAPITAL LETTER A\n                                                     WITH RING ABOVE -->\n                <symbol>&#x212B;</symbol>       <!-- ANGSTROM SIGN -->\n            </aliases>\n        </unit>\n        <unit>\n            <def>dam^2</def>\n            <aliases>\n                <name><singular>are</singular></name>\n                <symbol>a</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>100 are</def>\n            <aliases> <name><singular>hectare</singular></name> </aliases>\n        </unit>\n        <unit>\n            <def>100 fm^2</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name><singular>barn</singular></name>\n                <symbol>b</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1000 hPa</def>\n            <aliases>\n                <name><singular>bar</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>cm/s^2</def>\n            <aliases>\n                <name><singular>gal</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.7e10 Bq</def>\n            <aliases>\n                <name><singular>curie</singular></name>\n                <symbol>Ci</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2.58e-4 C/kg</def>\n            <aliases>\n                <name><singular>roentgen</singular></name>\n                <symbol>R</symbol>\n            </aliases>\n        </unit>\n        <!-- The following is commented-out because \"rad\" has already\n             been mapped to \"radian\"\n        <unit>\n            <def>cGy</def>\n            <aliases> <name><singular>rad</singular></name> </aliases>\n        </unit>\n        -->\n        <unit>\n            <def>cSv</def>\n            <aliases>\n                <name><singular>rem</singular></name>\n            </aliases>\n        </unit>\n</unit-system>\n"
  },
  {
    "path": "share/udunits/udunits2-base.xml",
    "content": "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n<!--\nCopyright 2008, 2009 University Corporation for Atmospheric Research\n\nThis file is part of the UDUNITS-2 package.  See the file LICENSE\nin the top-level source-directory of the package for copying and\nredistribution conditions.\n\nSI base units.\n-->\n<unit-system>\n    <unit>\n        <!--\n            The meter is the length of the path travelled by light in vacuum\n            during a time interval of 1/299 792 458 of a second.\n        -->\n        <base/>\n        <name><singular>meter</singular></name>\n        <symbol>m</symbol>\n        <aliases> <name><singular>metre</singular></name> </aliases>\n    </unit>\n    <unit>\n        <!-- The kilogram is the unit of mass; it is equal to the mass of the\n             international prototype of the kilogram. -->\n        <base/>\n        <name><singular>kilogram</singular></name>\n        <symbol>kg</symbol>\n    </unit>\n    <unit>\n        <!--\n            The second is the duration of 9 192 631 770 periods of the\n            radiation corresponding to the transition between the two hyperfine\n            levels of the ground state of the cesium 133 atom.\n        -->\n        <base/>\n        <name><singular>second</singular></name>\n        <symbol>s</symbol>\n    </unit>\n    <unit>\n        <!--\n            The ampere is that constant current which, if maintained in two\n            straight parallel conductors of infinite length, of negligible\n            circular cross-section, and placed 1 meter apart in vacuum, would\n            produce between these conductors a force equal to 2e-7 newton\n            per meter of length.\n        -->\n        <base/>\n        <name><singular>ampere</singular></name>\n        <symbol>A</symbol>\n    </unit>\n    <unit>\n        <!--\n            The kelvin, unit of thermodynamic temperature, is the fraction\n            1/273.16 of the thermodynamic temperature of the triple point of\n            water.\n        -->\n        <base/>\n        <name><singular>kelvin</singular></name>\n        <symbol>K</symbol>\n    </unit>\n    <unit>\n        <!--\n            1. The mole is the amount of substance of a system which contains\n            as many elementary entities as there are atoms in 0.012 kilogram of\n            carbon 12.\n\n            2. When the mole is used, the elementary entities must be specified\n            and may be atoms, molecules, ions, electrons, other particles, or\n            specified groups of such particles. \n        -->\n        <base/>\n        <name><singular>mole</singular></name>\n        <symbol>mol</symbol>\n    </unit>\n    <unit>\n        <!--\n            The candela is the luminous intensity, in a given direction, of a\n            source that emits monochromatic radiation of frequency 540e12\n            hertz and that has a radiant intensity in that direction of 1/683\n            watt per steradian.\n        -->\n        <base/>\n        <name><singular>candela</singular></name>\n        <symbol>cd</symbol>\n    </unit>\n</unit-system>\n"
  },
  {
    "path": "share/udunits/udunits2-common.xml",
    "content": "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n<!--\nCopyright 2008, 2009 University Corporation for Atmospheric Research\n\nThis file is part of the UDUNITS-2 package.  See the file LICENSE\nin the top-level source-directory of the package for copying and\nredistribution conditions.\n\nUnits not accepted for use with the SI.  NB: <name> and <symbol>\nelements appear only within <aliases>.\n-->\n<unit-system>\n    <!-- Synonyms for SI Units -->\n        <unit>\n            <def>s</def>\n            <aliases> <name> <singular>sec</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>A</def>\n            <aliases> <name> <singular>amp</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>K</def>\n            <aliases>\n                <symbol>&#xB0;K</symbol>        <!-- DEGREE SIGN -->\n                <name>\n                    <singular>degree_kelvin</singular>\n                    <plural>degrees_kelvin</plural>\n                </name>\n                <name>\n                    <singular>degree_K</singular>\n                    <plural>degrees_K</plural>\n                </name>\n                <name>\n                    <singular>degreeK</singular>\n                    <plural>degreesK</plural>\n                </name>\n                <name>\n                    <singular>deg_K</singular>\n                    <plural>degs_K</plural>\n                </name>\n                <name>\n                    <singular>degK</singular>\n                    <plural>degsK</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>cd</def>\n            <aliases> <name> <singular>candle</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>mole</def>\n            <aliases> <name> <singular>einstein</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>Hz</def>\n            <aliases>\n                <name> <singular>baud</singular> </name>\n                <symbol>Bd</symbol>\n                <symbol>bps</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>degree_Celsius</def>\n            <aliases>\n                <symbol>&#x2103;</symbol>       <!-- DEGREE CELSIUS -->\n                <name> <singular>celsius</singular> </name>\n                <name>\n                    <singular>degree_C</singular>\n                    <plural>degrees_C</plural>\n                </name>\n                <name>\n                    <singular>degreeC</singular>\n                    <plural>degreesC</plural>\n                </name>\n                <name>\n                    <singular>deg_C</singular>\n                    <plural>degs_C</plural>\n                </name>\n                <name>\n                    <singular>degC</singular>\n                    <plural>degsC</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>knot</def>\n            <aliases>\n                <symbol>kt</symbol>\n                <symbol>kts</symbol>\n            </aliases>\n        </unit>\n\n    <!-- Constants -->\n        <unit>\n            <def>6.02214179e23/mol</def>        <!-- +-30e15 -->\n            <aliases>\n                <name><singular>avogadro_constant</singular></name>\n                <noplural/>\n            </aliases>\n        </unit>\n        <unit>\n            <def>0.01</def>\n            <aliases>\n                <name><singular>percent</singular></name>\n                <noplural/>\n                <symbol>%</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-6</def>\n            <aliases>\n                <symbol>ppm</symbol>\n                <symbol>ppmv</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-9</def>\n            <aliases>\n                <symbol>ppb</symbol>\n                <symbol>ppbv</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-12</def>\n            <aliases>\n                <symbol>ppt</symbol>\n                <symbol>pptv</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-15</def>\n            <aliases>\n                <symbol>ppq</symbol>\n                <symbol>ppqv</symbol>\n            </aliases>\n        </unit>\n\n    <!-- Plane Angle -->\n        <unit>\n            <def>0.9 arc_degree</def>\n            <aliases> <name><singular>grade</singular></name> </aliases>\n        </unit>\n        <unit>\n            <def>2 pi rad</def>\n            <aliases>\n                <name><singular>circle</singular></name>\n                <name><singular>cycle</singular></name>\n                <name><singular>turn</singular></name>\n                <name><singular>revolution</singular></name>\n                <name><singular>rotation</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>arc_degree</def>\n            <aliases>\n                <name>\n                    <singular>degree_north</singular>\n                    <plural>degrees_north</plural>\n                </name>\n                <name>\n                    <singular>degree_N</singular>\n                    <plural>degrees_N</plural>\n                </name>\n                <name>\n                    <singular>degreeN</singular>\n                    <plural>degreesN</plural>\n                </name>\n                <name>\n                    <singular>degree_east</singular>\n                    <plural>degrees_east</plural>\n                </name>\n                <name>\n                    <singular>degree_E</singular>\n                    <plural>degrees_E</plural>\n                </name>\n                <name>\n                    <singular>degreeE</singular>\n                    <plural>degreesE</plural>\n                </name>\n                <name>\n                    <singular>degree_true</singular>\n                    <plural>degrees_true</plural>\n                </name>\n                <name>\n                    <singular>degree_T</singular>\n                    <plural>degrees_T</plural>\n                </name>\n                <name>\n                    <singular>degreeT</singular>\n                    <plural>degreesT</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>-1 degree_east</def>\n            <aliases>\n                <name>\n                    <singular>degree_west</singular>\n                    <plural>degrees_west</plural>\n                </name>\n                <name>\n                    <singular>degree_W</singular>\n                    <plural>degrees_W</plural>\n                </name>\n                <name>\n                    <singular>degreeW</singular>\n                    <plural>degreesW</plural>\n                </name>\n            </aliases>\n        </unit>\n\n    <!-- Mass -->\n        <unit>\n            <def>2.916667e-2 kg</def>\n            <aliases>\n                <name> <singular>assay_ton</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2.834952e-2 kg</def>\n            <aliases>\n                <name> <singular>avoirdupois_ounce</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.5359237e-1 kg</def>\n            <aliases>\n                <name> <singular>avoirdupois_pound</singular> </name>\n                <name> <singular>pound</singular> </name>\n                <symbol>lb</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2e-4 kg</def>\n            <aliases>\n                <name> <singular>carat</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>6.479891e-5 kg</def>\n            <aliases>\n                <name> <singular>grain</singular> </name>\n                <symbol>gr</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>5.080235e1 kg</def>\n            <aliases>\n                <name> <singular>long_hundredweight</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.555174e-3 kg</def>\n            <aliases>\n                <name> <singular>pennyweight</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.535924e1 kg</def>\n            <aliases>\n                <name> <singular>short_hundredweight</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>14.59390 kg</def>\n            <aliases>\n                <name> <singular>slug</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.110348e-2 kg</def>\n            <aliases>\n                <name> <singular>troy_ounce</singular> </name>\n                <name> <singular>apothecary_ounce</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.732417e-1 kg</def>\n            <aliases>\n                <name> <singular>troy_pound</singular> </name>\n                <name> <singular>apothecary_pound</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>20 grain</def>\n            <aliases> <name> <singular>scruple</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>60 grain</def>\n            <aliases> <name> <singular>apdram</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>480 grain</def>\n            <aliases> <name> <singular>apounce</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>5760 grain</def>\n            <aliases> <name> <singular>appound</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>94 pound</def>\n            <aliases> <name> <singular>bag</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>2000 pound</def>\n            <aliases>\n                <name> <singular>short_ton</singular> </name>\n                <name> <singular>ton</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2240 pound</def>\n            <aliases>\n                <name> <singular>long_ton</singular> </name>\n            </aliases>\n        </unit>\n\n    <!-- Length -->\n        <unit>\n            <def>1e-15 m</def>\n            <aliases>\n                <name> <singular>fermi</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>9.46073e15 m</def>\n            <aliases>\n                <name> <singular>light_year</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-6 m</def>\n            <aliases>\n                <name> <singular>micron</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2.54e-5 m</def>\n            <aliases>\n                <name> <singular>mil</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.085678e16 m</def>\n            <aliases>\n                <name> <singular>parsec</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.514598e-4 m</def>\n            <aliases>\n                <name> <singular>printers_point</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2.011684e1 m</def>\n            <aliases>\n                <name> <singular>chain</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>12 printers_point</def>\n            <aliases>\n                <name> <singular>printers_pica</singular> </name>\n                <name> <singular>pica</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>nautical_mile</def>\n            <aliases>\n                <name> <singular>nmile</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>(1200/3937) m</def>\n            <aliases>\n                <name>\n                    <singular>US_survey_foot</singular>\n                    <plural>US_survey_feet</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3 US_survey_feet</def>\n            <aliases>\n                <name> <singular>US_survey_yard</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>5280 US_survey_feet</def>\n            <aliases>\n                <name> <singular>US_survey_mile</singular> </name>\n                <name> <singular>US_statute_mile</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>16.5 US_survey_feet</def>\n            <aliases>\n                <name> <singular>rod</singular> </name>\n                <name> <singular>pole</singular> </name>\n                <name> <singular>perch</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>660 US_survey_feet</def>\n            <aliases> <name> <singular>furlong</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>6 US_survey_feet</def>\n            <aliases> <name> <singular>fathom</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>2.54 cm</def>\n            <aliases>\n                <name> <singular>international_inch</singular> </name>\n                <name> <singular>inch</singular> </name>\n                <symbol>in</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>12 international_inches</def>\n            <aliases>\n                <name>\n                    <singular>international_foot</singular>\n                    <plural>international_feet</plural>\n                </name>\n                <name>\n                    <singular>foot</singular>\n                    <plural>feet</plural>\n                </name>\n                <symbol>ft</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3 international_feet</def>\n            <aliases>\n                <name> <singular>international_yard</singular> </name>\n                <name> <singular>yard</singular> </name>\n                <symbol>yd</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>5280 international_feet</def>\n            <aliases>\n                <name> <singular>international_mile</singular> </name>\n                <name> <singular>mile</singular> </name>\n                <symbol>mi</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>inch/72</def>\n            <aliases>\n                <name> <singular>big_point</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>inch/3</def>\n            <aliases>\n                <name> <singular>barleycorn</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>191.835 foot</def>\n            <aliases>\n                <name> <singular>arpentlin</singular> </name>\n            </aliases>\n        </unit>\n\n    <!-- Angular Velocity -->\n        <unit>\n            <def>rotation/second</def>\t\t<!-- exact -->\n            <aliases>\n                <name>\n                    <singular>rotation_per_second</singular>\n                    <plural>rotations_per_second</plural>\n                </name>\n                <symbol>rps</symbol>\n                <symbol>cps</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>rotation/minute</def>\t\t<!-- exact -->\n            <aliases> <symbol>rpm</symbol> </aliases>\n        </unit>\n\n    <!-- Lineic Mass -->\n        <unit>\n            <def>1.111111e-7 kg/m</def>\n            <aliases>\n                <name> <singular>denier</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-6 kg/m</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>tex</singular> </name>\n            </aliases>\n        </unit>\n\n    <!-- Mass per unit time (includes flow) -->\n        <unit>\n            <def>5.72135e-11 kg/(Pa.s.m^2)</def>\n            <aliases>\n                <name>\n                    <singular>perm_0C</singular>\n                    <plural>perms_0C</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>5.74525e-11 kg/(Pa.s.m^2)</def>\n            <aliases>\n                <name>\n                    <singular>perm_23C</singular>\n                    <plural>perms_23C</plural>\n                </name>\n            </aliases>\n        </unit>\n\n    <!-- Area -->\n        <unit>\n            <def>5.067075e-10 m^2</def>\n            <aliases>\n                <name> <singular>circular_mil</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>9.869233e-13 m^2</def> <!-- porous solid permeability -->\n            <aliases> <name> <singular>darcy</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>160 rod^2</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>acre</singular> </name>\n            </aliases>\n        </unit>\n\n    <!-- Volume -->\n        <unit>\n            <def>1.233489e3 m^3</def>\n            <!-- An \"acre.foot\", however, is 1233.4867714897 m^3.  Odd. -->\n            <aliases>\n                <name>\n                    <singular>acre_foot</singular>\n                    <plural>acre_feet</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2.359737e-3 m^3</def>\n            <aliases>\n                <name>\n                    <singular>board_foot</singular>\n                    <plural>board_feet</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.523907e-2 m^3</def>\n            <aliases>\n                <name> <singular>bushel</singular> </name>\n                <symbol>bu</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>bushel/4</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>peck</singular> </name>\n                <symbol>pk</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.546090e-3 m^3</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>Canadian_liquid_gallon</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.404884e-3 m^3</def>\n            <aliases>\n                <name> <singular>US_dry_gallon</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>cm^3</def>\t\t\t\t<!-- exact -->\n            <aliases> <symbol>cc</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>1 m^3</def>\t\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>stere</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2.831685 m^3</def>\n            <aliases>\n                <name> <singular>register_ton</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_dry_gallon/4</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>US_dry_quart</singular> </name>\n                <name> <singular>dry_quart</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_dry_gallon/8</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>US_dry_pint</singular> </name>\n                <name> <singular>dry_pint</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.785412e-3 m^3</def>\n            <aliases>\n                <name> <singular>US_liquid_gallon</singular> </name>\n                <name> <singular>liquid_gallon</singular> </name>\n                <name> <singular>gallon</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <!-- The following is the definition of the petroleum industry\n            -->\n            <def>42 US_liquid_gallon</def>\n            <aliases>\n                <name> <singular>barrel</singular> </name>\n                <symbol>bbl</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <!-- The following is exact regardless of the definition of\n            \"barrel\" -->\n            <def>barrel/4</def>\n            <aliases>\n                <name> <singular>firkin</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_liquid_gallon/4</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>US_liquid_quart</singular> </name>\n                <name> <singular>liquid_quart</singular> </name>\n                <name> <singular>quart</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_liquid_gallon/8</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>US_liquid_pint</singular> </name>\n                <name> <singular>liquid_pint</singular> </name>\n                <name> <singular>pint</singular> </name>\n                <symbol>pt</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_liquid_gallon/16</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>US_liquid_cup</singular> </name>\n                <name> <singular>liquid_cup</singular> </name>\n                <name> <singular>cup</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_liquid_gallon/32</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>US_liquid_gill</singular> </name>\n                <name> <singular>liquid_gill</singular> </name>\n                <name> <singular>gill</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_liquid_gallon/128</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>US_fluid_ounce</singular> </name>\n                <name> <singular>US_liquid_ounce</singular> </name>\n                <name> <singular>fluid_ounce</singular> </name>\n                <name> <singular>liquid_ounce</singular> </name>\n                <symbol>oz</symbol>\n                <symbol>floz</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_fluid_ounce/2</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>tablespoon</singular> </name>\n                <symbol>Tbl</symbol>\n                <symbol>Tbsp</symbol>\n                <symbol>tbsp</symbol>\n                <symbol>Tblsp</symbol>\n                <symbol>tblsp</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>US_fluid_ounce/8</def>\t\t<!-- exact -->\n            <aliases> <symbol>fldr</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>US_fluid_ounce/16</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>dram</singular> </name>\n                <symbol>dr</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>tablespoon/3</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>teaspoon</singular> </name>\n                <symbol>tsp</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.546090e-3 m^3</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>UK_liquid_gallon</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>UK_liquid_gallon/4</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>UK_liquid_quart</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>UK_liquid_gallon/8</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>UK_liquid_pint</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>UK_liquid_gallon/16</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>UK_liquid_cup</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>UK_liquid_gallon/32</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>UK_liquid_gill</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>UK_liquid_gallon/160</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>UK_fluid_ounce</singular> </name>\n                <name> <singular>UK_liquid_ounce</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>lg(re (1e-6 m)^3)</def>\n            <aliases> <symbol>BZ</symbol> </aliases>\n        </unit>\n\n    <!-- Time -->\n        <unit>\n            <def>1e-8 s</def>\n            <aliases> <name> <singular>shake</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>8.616409e4 s</def>\n            <aliases>\n                <name> <singular>sidereal_day</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.590170e3 s</def>\n            <aliases>\n                <name> <singular>sidereal_hour</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>5.983617e1 s</def>\n            <aliases>\n                <name> <singular>sidereal_minute</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>0.9972696 s</def>\n            <aliases>\n                <name> <singular>sidereal_second</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.155815e7 s</def>\n            <aliases>\n                <name> <singular>sidereal_year</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <!--\n                Interval between 2 successive passages of sun\n                through vernal equinox (365.242198781 days.  See\n                <http://www.ast.cam.ac.uk/pubinfo/leaflets/>,\n                <http://aa.usno.navy.mil/AA/>, and\n                <http://adswww.colorado.edu/adswww/astro_coord.html>):\n            -->\n            <def>3.15569259747e7 s</def>\n            <aliases>\n                <name> <singular>tropical_year</singular> </name>\n                <name> <singular>year</singular> </name>\n                <!-- The following is commented-out because \"a\" already\n                     maps to \"are\"\n                <symbol>a</symbol>\n                -->\n                <symbol>yr</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>29.530589 day</def>\n            <aliases>\n                <name> <singular>lunar_month</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>365 day</def>\n            <aliases>\n                <name> <singular>common_year</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>366 day</def>\n            <aliases>\n                <name> <singular>leap_year</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>365.25 day</def>\n            <aliases>\n                <name> <singular>Julian_year</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>365.2425 day</def>\n            <aliases>\n                <name> <singular>Gregorian_year</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>27.321661 day</def>\n            <aliases>\n                <name> <singular>sidereal_month</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>27.321582 day</def>\n            <aliases>\n                <name> <singular>tropical_month</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>14 day</def>\n            <aliases>\n                <name> <singular>fortnight</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>7 day</def>\n            <aliases> <name> <singular>week</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>0.01 s</def>\n            <aliases> <name> <singular>jiffy</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>1e9 year</def>\n            <aliases> <name> <singular>eon</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>year/12</def>\n            <aliases> <name> <singular>month</singular> </name> </aliases>\n        </unit>\n\n    <!-- Volume per time -->\n        <unit>\n            <def>1e6 m^3/s</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>sverdrup</singular> </name>\n                <!-- The following is commented-out because \"Sv\" means\n                     \"sievert\" in the SI unit-system.\n                <symbol>Sv</symbol>\n                -->\n            </aliases>\n        </unit>\n\n    <!-- Acceleration -->\n        <unit>\n            <def>9.806650 m/s^2</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>standard_free_fall</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>standard_free_fall</def>\t\t<!-- should be local -->\n            <aliases> <name> <singular>gravity</singular> </name> </aliases>\n        </unit>\n\n    <!-- Some \"units\" that make subsequent definitions easier -->\n        <unit>\n            <def>gravity 1000 kg/m^3</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>conventional_water</singular> </name>\n                <name> <singular>water</singular> </name>\n                <symbol>H2O</symbol>\n                <symbol>h2o</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>gravity 999.972 kg/m^3</def>\n            <aliases>\n                <name>\n                    <singular>water_4C</singular>\n                    <plural>waters_4C</plural>\n                </name>\n                <name>\n                    <singular>water_39F</singular>\t<!-- act. 39.2 F -->\n                    <plural>waters_39F</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>gravity 999.001 kg/m^3</def>\n            <aliases>\n                <name>\n                    <singular>water_60F</singular>\n                    <plural>waters_60F</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>gravity 13595.10 kg/m^3</def>\n            <aliases>\n                <name>\n                    <singular>mercury_0C</singular>\n                    <plural>mercuries_0C</plural>\n                </name>\n                <name>\n                    <singular>mercury_32F</singular>\n                    <plural>mercuries_32F</plural>\n                </name>\n                <name>\n                    <singular>conventional_mercury</singular>\n                    <plural>conventional_mercuries</plural>\n                </name>\n                <symbol>Hg</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>gravity 13556.8 kg/m^3</def>\n            <aliases>\n                <name>\n                    <singular>mercury_60F</singular>\n                    <plural>mercuries_60F</plural>\n                </name>\n            </aliases>\n        </unit>\n\n    <!-- Force -->\n        <unit>\n            <def>standard_free_fall</def>\n            <aliases> <name> <singular>force</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>1e-5 N</def>\t\t\t<!-- exact -->\n            <aliases> <name> <singular>dyne</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>9.806650e-3 N</def>\t\t<!-- exact -->\n            <aliases> <name> <singular>pond</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>9.806650 N</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>force_kilogram</singular> </name>\n                <name>\n                    <singular>kilogram_force</singular>\n                    <plural>kilograms_force</plural>\n                </name>\n                <symbol>kgf</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2.780139e-1 N</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>force_ounce</singular> </name>\n                <name>\n                    <singular>ounce_force</singular>\n                    <plural>ounces_force</plural>\n                </name>\n                <symbol>ozf</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.4482216152605 N</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>force_pound</singular> </name>\n                <name>\n                    <singular>pound_force</singular>\n                    <plural>pounds_force</plural>\n                </name>\n                <symbol>lbf</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.382550e-1 N</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>poundal</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>gram force</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name>\n                    <singular>gram_force</singular>\n                    <plural>grams_force</plural>\n                </name>\n                <name>\n                    <singular>force_gram</singular>\n                </name>\n                <symbol>gf</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2000 force_pound</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>force_ton</singular> </name>\n                <name>\n                    <singular>ton_force</singular>\n                    <plural>tons_force</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1000 lbf</def>\t\t\t<!-- exact -->\n            <aliases> <name><singular>kip</singular></name> </aliases>\n        </unit>\n\n    <!-- Pressure, Stress -->\n        <unit>\n            <def>1.01325e5 Pa</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>standard_atmosphere</singular> </name>\n                <name> <singular>atmosphere</singular> </name>\n                <symbol>atm</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1 kg gravity/cm2</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>technical_atmosphere</singular> </name>\n                <symbol>at</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>cm H2O</def>\n            <aliases>\n                <symbol>cm_H2O</symbol>\n                <symbol>cmH2O</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>inch water_39F</def>\t\t<!-- exact -->\n            <aliases>\n                <name>\n                    <singular>inch_H2O_39F</singular>\n                    <plural>inches_H2O_39F</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>inch water_60F</def>\t\t<!-- exact -->\n            <aliases>\n                <name>\n                    <singular>inch_H2O_60F</singular>\n                    <plural>inches_H2O_60F</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>foot water</def>\n            <aliases>\n                <name>\n                    <singular>foot_water</singular>\n                    <plural>feet_water</plural>\n                </name>\n                <name>\n                    <singular>foot_H2O</singular>\n                    <plural>feet_H2O</plural>\n                </name>\n                <name>\n                    <singular>footH2O</singular>\n                    <plural>feetH2O</plural>\n                </name>\n                <symbol>ftH2O</symbol>\n                <symbol>fth2o</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>cm Hg</def>\n            <aliases>\n                <symbol>cm_Hg</symbol>\n                <symbol>cmHg</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>mm mercury_0C</def>\t\t<!-- exact -->\n            <aliases>\n                <name>\n                    <singular>millimeter_Hg_0C</singular>\n                    <plural>millimeters_Hg_0C</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>inch mercury_32F</def>\t\t<!-- exact -->\n            <aliases>\n                <name>\n                    <singular>inch_Hg_32F</singular>\n                    <plural>inches_Hg_32F</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>inch mercury_60F</def>\t\t<!-- exact -->\n            <aliases>\n                <name>\n                    <singular>inch_Hg_60F</singular>\n                    <plural>inches_Hg_60F</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>mm Hg</def>\n            <aliases>\n                <name>\n                    <singular>millimeter_Hg</singular>\n                    <plural>millimeters_Hg</plural>\n                </name>\n                <name> <singular>torr</singular> </name>\n                <symbol>mm_Hg</symbol>\n                <symbol>mm_hg</symbol>\n                <symbol>mmHg</symbol>\n                <symbol>mmhg</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>inch Hg</def>\n            <aliases>\n                <name>\n                    <singular>inch_Hg</singular>\n                    <plural>inches_Hg</plural>\n                </name>\n                <symbol>in_Hg</symbol>\n                <symbol>inHg</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1 pound gravity/in^2</def>\t\t<!-- exact -->\n            <aliases> <symbol>psi</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>kip/in^2</def>\t\t\t<!-- exact -->\n            <aliases> <symbol>ksi</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>0.1 N/m^2</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>barie</singular> </name>\n                <name> <singular>barye</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>lg(re 20e-6 Pa)</def>      <!-- sound pressure level -->\n            <aliases> <symbol>B_SPL</symbol> </aliases>\n        </unit>\n\n    <!-- Viscosity -->\n        <unit>\n            <def>1e-1 Pa.s</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>poise</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-4 m^2/s</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>stokes</singular> </name>\n                <symbol>St</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>10/(Pa.s)</def>\t\t\t<!-- exact -->\n            <aliases> <name> <singular>rhe</singular> </name> </aliases>\n        </unit>\n\n    <!-- Energy, Work, Quantity of Heat -->\n        <unit>\n            <def>1e-7 J</def>\t\t\t<!-- exact -->\n            <aliases> <name> <singular>erg</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>1.05505585262e3 J</def>\t\t<!-- exact -->\n            <aliases>\n                <name>\n                    <singular>IT_Btu</singular>\n                    <plural>IT_Btus</plural>\n                </name>\n                <name>\n                    <singular>Btu</singular>\n                    <plural>Btus</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.05506e8 J</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>EC_therm</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.184000 J</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>thermochemical_calorie</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.1868 J</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>IT_calorie</singular> </name>\n                <name> <singular>calorie</singular> </name>\n                <symbol>cal</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.184 MJ/kg</def>\t\t\t<!-- by definition -->\n            <aliases>\n                <name> <singular>TNT</singular><noplural/></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.184e9 J</def>\t\t\t<!-- by definition -->\n            <aliases>\n                <name>\n                    <singular>ton_TNT</singular>\n                    <plural>tons_TNT</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.054804e8 J</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>US_therm</singular> </name>\n                <name> <singular>therm</singular> </name>\n                <symbol>thm</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>watt.hour</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>watthour</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e9 eV</def>\t\t\t<!-- exact -->\n            <aliases> <symbol>bev</symbol> </aliases>\n        </unit>\n\n    <!-- Power, Radiant Flux -->\n        <unit>\n            <def>V.A</def>\t\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>voltampere</singular> </name>\n                <symbol>VA</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>9.80950e3 W</def>\n            <aliases>\n                <name> <singular>boiler_horsepower</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>7.456999e2 W</def>\n            <aliases>\n                <name> <singular>shaft_horsepower</singular> </name>\n                <name> <singular>horsepower</singular> </name>\n                <symbol>hp</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>7.35499e2 W</def>\n            <aliases>\n                <name> <singular>metric_horsepower</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>7.460000e2 W</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>electric_horsepower</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>7.46043e2 W</def>\n            <aliases>\n                <name> <singular>water_horsepower</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>7.4570e2 W</def>\n            <aliases>\n                <name> <singular>UK_horsepower</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>12000 Btu/hr</def>\n            <aliases>\n                <name> <singular>refrigeration_ton</singular> </name>\n                <name>\n                    <singular>ton_of_refrigeration</singular>\n                    <plural>tons_of_refrigeration</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>lg(re 1 W)</def>\n            <aliases> <symbol>BW</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>lg(re 1 mW)</def>\n            <aliases> <symbol>Bm</symbol> </aliases>\n        </unit>\n\n    <!-- Heat -->\n        <unit>\n            <def>1.55e-1 K.m^2/W</def>\n            <aliases> <name> <singular>clo</singular> </name> </aliases>\n        </unit>\n\n    <!-- Electricity and Magnetism -->\n        <unit>\n            <def>10 A</def>\n            <aliases> <name><singular>abampere</singular></name> </aliases>\n        </unit>\n        <unit>\n            <def>7.957747e-1 A</def>\n            <aliases> <name><singular>gilbert</singular></name> </aliases>\n        </unit>\n        <unit>\n            <def>3.335640e-10 A</def>\n            <aliases>\n                <name><singular>statampere</singular></name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>10 A</def>\n            <aliases> <name><singular>biot</singular></name> </aliases>\n        </unit>\n        <unit>\n            <def>1e9 F</def>\t\t\t<!-- exact -->\n            <aliases> <name> <singular>abfarad</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>1e-9 H</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>abhenry</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e9 S</def>\t\t\t<!-- exact -->\n            <aliases> <name> <singular>abmho</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>1e-9 ohm</def>\t\t\t<!-- exact -->\n            <aliases> <name> <singular>abohm</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>1e-8 V</def>\t\t\t<!-- exact -->\n            <aliases> <name> <singular>abvolt</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>1.602176487e-19 C</def>\n            <aliases> <symbol>e</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>9.64957e4 C</def>\n            <aliases>\n                <name> <singular>chemical_faraday</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>9.65219e4 C</def>\n            <aliases>\n                <name> <singular>physical_faraday</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>9.648531e4 C</def>\n            <aliases>\n                <name> <singular>C12_faraday</singular> </name>\n                <name> <singular>faraday</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-9 T</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>gamma</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-4 T</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>gauss</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-8 Wb</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>maxwell</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>7.957747e1 A/m</def>\n            <aliases>\n                <name> <singular>oersted</singular> </name>\n                <symbol>Oe</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.335640e-10 C</def>\n            <aliases>\n                <name> <singular>statcoulomb</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.112650e-12 F</def>\n            <aliases>\n                <name> <singular>statfarad</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>8.987554e11 H</def>\n            <aliases>\n                <name> <singular>stathenry</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.112650e-12 S</def>\n            <aliases>\n                <name> <singular>statmho</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>8.987554e11 ohm</def>\n            <aliases>\n                <name> <singular>statohm</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2.997925e2 V</def>\n            <aliases>\n                <name> <singular>statvolt</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1.256637e-7 Wb</def>\n            <aliases>\n                <name> <singular>unit_pole</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>lg(re 1 V)</def>\n            <aliases> <symbol>BV</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>lg(re 0.775 V)</def>       <!-- rms voltage -->\n            <aliases> <symbol>Bv</symbol> </aliases>\n        </unit>\n        <unit>\n            <def>lg(re 1e-6 V)</def>\n            <aliases> <symbol>B&#xB5;V</symbol> </aliases>\n                                            <!-- uses MICRO SIGN -->\n        </unit>\n\n    <!-- Thermodynamic Temperature -->\n        <unit>\n            <def>K/1.8</def>\n            <aliases>\n                <symbol>&#xB0;R</symbol>    <!-- DEGREE SIGN -->\n                <name>\n                    <singular>degree_rankine</singular>\n                    <plural>degrees_rankine</plural>\n                </name>\n                <name>\n                    <singular>degreeR</singular>\n                    <plural>degreesR</plural>\n                </name>\n                <name>\n                    <singular>degree_R</singular>\n                    <plural>degrees_R</plural>\n                </name>\n                <name>\n                    <singular>degR</singular>\n                    <plural>degsR</plural>\n                </name>\n                <name>\n                    <singular>deg_R</singular>\n                    <plural>degs_R</plural>\n                </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>&#xB0;R @ 459.67</def>     <!-- DEGREE SIGN -->\n            <aliases>\n                <symbol>&#xB0;F</symbol>    <!-- DEGREE SIGN -->\n                <symbol>&#x2109;</symbol>   <!-- DEGREE FAHRENHEIT -->\n                <name> <singular>fahrenheit</singular> </name>\n                <name>\n                    <singular>degree_fahrenheit</singular>\n                    <plural>degrees_fahrenheit</plural>\n                </name>\n                <name>\n                    <singular>degreeF</singular>\n                    <plural>degreesF</plural>\n                </name>\n                <name>\n                    <singular>degree_F</singular>\n                    <plural>degrees_F</plural>\n                </name>\n                <name>\n                    <singular>degF</singular>\n                    <plural>degsF</plural>\n                </name>\n                <name>\n                    <singular>deg_F</singular>\n                    <plural>degs_F</plural>\n                </name>\n            </aliases>\n        </unit>\n\n    <!-- Illumination -->\n        <unit>\n            <def>1.076391e-1 lx</def>\n            <aliases>\n                <name> <singular>footcandle</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>3.426259 cd/m^2</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>footlambert</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>(1e4/pi) cd/m^2</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>lambert</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e4 cd/m^2</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>stilb</singular> </name>\n                <symbol>sb</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e4 lm/m^2</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>phot</singular> </name>\n                <symbol>ph</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1 cd/m^2</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>nit</singular> </name>\n                <symbol>nt</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>4.184000e4 J/m^2</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>langley</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>cd/(pi m^2)</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>blondel</singular> </name>\n                <name> <singular>apostilb</singular> </name>\n            </aliases>\n        </unit>\n\n    <!-- Miscellaneous -->\n        <unit>\n            <def>100/m</def>\t\t\t<!-- exact -->\n            <aliases> <name> <singular>kayser</singular> </name> </aliases>\n        </unit>\n        <unit>\n            <def>gravity</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>geopotential</singular> </name>\n                <name> <singular>dynamic</singular> </name>\n                <symbol>gp</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>2056 hours</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>work_year</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>work_year/12</def>\t\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>work_month</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1e-6 m^2 s^-1 K kg^-1</def>\t\t<!-- exact -->\n            <aliases>\n                <name> <singular>potential_vorticity_unit</singular> </name>\n                <symbol>PVU</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>1</def>\n            <aliases>\n                <name> <singular>count</singular> </name>\n            </aliases>\n        </unit>\n        <unit>\n            <def>446.2 micromoles/meter^2</def>\n            <aliases>\n                <name> <singular>dobson</singular> </name>\n                <symbol>DU</symbol>\n            </aliases>\n        </unit>\n</unit-system>\n"
  },
  {
    "path": "share/udunits/udunits2-derived.xml",
    "content": "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n<!--\nCopyright 2008, 2009 University Corporation for Atmospheric Research\n\nThis file is part of the UDUNITS-2 package.  See the file LICENSE\nin the top-level source-directory of the package for copying and\nredistribution conditions.\n\nSI derived units with special names and symbols\n-->\n<unit-system>\n    <unit>\n        <dimensionless/>\n        <name><singular>radian</singular></name>\n        <symbol>rad</symbol>\n    </unit>\n    <unit>\n        <def>rad^2</def>\n        <name><singular>steradian</singular></name>\n        <symbol>sr</symbol>\n    </unit>\n    <unit>\n        <def>1/s</def>\n        <name><singular>hertz</singular></name>\n        <symbol>Hz</symbol>\n    </unit>\n    <unit>\n        <def>1e-3 kg</def>\n        <name><singular>gram</singular></name>\n        <symbol>g</symbol>\n    </unit>\n    <unit>\n        <def>m.kg/s^2</def>\n        <name><singular>newton</singular></name>\n        <symbol>N</symbol>\n    </unit>\n    <unit>\n        <def>N/m^2</def>\n        <name><singular>pascal</singular></name>\n        <symbol>Pa</symbol>\n    </unit>\n    <unit>\n        <def>N.m</def>\n        <name><singular>joule</singular></name>\n        <symbol>J</symbol>\n    </unit>\n    <unit>\n        <def>J/s</def>\n        <name><singular>watt</singular></name>\n        <symbol>W</symbol>\n    </unit>\n    <unit>\n        <def>s.A</def>\n        <name><singular>coulomb</singular></name>\n        <symbol>C</symbol>\n    </unit>\n    <unit>\n        <def>W/A</def>\n        <name><singular>volt</singular></name>\n        <symbol>V</symbol>\n    </unit>\n    <unit>\n        <def>C/V</def>\n        <name><singular>farad</singular></name>\n        <symbol>F</symbol>\n    </unit>\n    <unit>\n        <def>V/A</def>\n        <name><singular>ohm</singular></name>\n        <symbol>&#x3A9;</symbol>        <!-- Greek capital letter omega\n                                             (preferred) -->\n        <aliases>\n            <symbol>&#x2126;</symbol>   <!-- OHM SIGN -->\n        </aliases>\n    </unit>\n    <unit>\n        <def>A/V</def>\n        <name> <singular>siemens</singular> </name>\n        <symbol>S</symbol>\n    </unit>\n    <unit>\n        <def>V.s</def>\n        <name><singular>weber</singular></name>\n        <symbol>Wb</symbol>\n    </unit>\n    <unit>\n        <def>Wb/m^2</def>\n        <name><singular>tesla</singular></name>\n        <symbol>T</symbol>\n    </unit>\n    <unit>\n        <def>Wb/A</def>\n        <name><singular>henry</singular></name>\n        <symbol>H</symbol>\n    </unit>\n    <unit>\n        <def>K @ 273.15</def>\n        <name>\n            <singular>degree_Celsius</singular>\n            <plural>degrees_Celsius</plural>\n        </name>\n        <symbol>&#xB0;C</symbol>            <!-- DEGREE SIGN -->\n    </unit>\n    <unit>\n        <def>cd.sr</def>\n        <name><singular>lumen</singular></name>\n        <symbol>lm</symbol>\n    </unit>\n    <unit>\n        <def>lm/m^2</def>\n        <name><singular>lux</singular></name>\n        <symbol>lx</symbol>\n    </unit>\n    <unit>\n        <def>mol/s</def>\n        <name><singular>katal</singular></name>\n        <symbol>kat</symbol>\n    </unit>\n\n    <!-- SI derived units with special names and symbols admitted for\n    reasons of safeguarding human health -->\n        <unit>\n            <def>1/s</def>\n            <aliases>\n                <!-- The following are aliases because \"1/s\" is already\n                mapped to \"hertz\" and \"Hz\" -->\n                <name><singular>becquerel</singular></name>\n                <symbol>Bq</symbol>\n            </aliases>\n        </unit>\n        <unit>\n            <def>J/kg</def>\n            <name><singular>gray</singular></name>\n            <symbol>Gy</symbol>\n        </unit>\n        <unit>\n            <def>J/kg</def>\n            <aliases>\n                <name><singular>sievert</singular></name>\n                <symbol>Sv</symbol>\n            </aliases>\n        </unit>\n</unit-system>\n"
  },
  {
    "path": "share/udunits/udunits2-prefixes.xml",
    "content": "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n<!--\nCopyright 2008, 2009 University Corporation for Atmospheric Research\n\nThis file is part of the UDUNITS-2 package.  See the file LICENSE\nin the top-level source-directory of the package for copying and\nredistribution conditions.\n\nSI prefixes\n-->\n<unit-system>\n    <prefix>\n        <value>1e24</value> <name>yotta</name>\t<symbol>Y</symbol>\n    </prefix>\n    <prefix>\n        <value>1e21</value> <name>zetta</name>\t<symbol>Z</symbol>\n    </prefix>\n    <prefix>\n        <value>1e18</value> <name>exa</name>\t<symbol>E</symbol>\n    </prefix>\n    <prefix>\n        <value>1e15</value> <name>peta</name>\t<symbol>P</symbol>\n    </prefix>\n    <prefix>\n        <value>1e12</value> <name>tera</name>\t<symbol>T</symbol>\n    </prefix>\n    <prefix>\n        <value>1e9</value> <name>giga</name>\t<symbol>G</symbol>\n    </prefix>\n    <prefix>\n        <value>1e6</value> <name>mega</name>\t<symbol>M</symbol>\n    </prefix>\n    <prefix>\n        <value>1e3</value> <name>kilo</name>\t<symbol>k</symbol>\n    </prefix>\n    <prefix>\n        <value>100</value> <name>hecto</name>\t<symbol>h</symbol>\n    </prefix>\n    <prefix>\n        <value>10</value> <name>deka</name>\t<symbol>da</symbol>\n    </prefix>\n    <prefix>\n        <value>.1</value> <name>deci</name>\t<symbol>d</symbol>\n    </prefix>\n    <prefix>\n        <value>.01</value> <name>centi</name>\t<symbol>c</symbol>\n    </prefix>\n    <prefix>\n        <value>1e-3</value> <name>milli</name>\t<symbol>m</symbol>\n    </prefix>\n    <prefix>\n        <value>1e-6</value>\n        <name>micro</name>\n        <symbol>&#xB5;</symbol>         <!-- MICRO SIGN -->\n        <symbol>&#x3BC;</symbol>\t<!-- Greek small letter \"mu\" -->\n        <symbol>u</symbol>\n    </prefix>\n    <prefix>\n        <value>1e-9</value> <name>nano</name>\t<symbol>n</symbol>\n    </prefix>\n    <prefix>\n        <value>1e-12</value> <name>pico</name>\t<symbol>p</symbol>\n    </prefix>\n    <prefix>\n        <value>1e-15</value> <name>femto</name>\t<symbol>f</symbol>\n    </prefix>\n    <prefix>\n        <value>1e-18</value> <name>atto</name>\t<symbol>a</symbol>\n    </prefix>\n    <prefix>\n        <value>1e-21</value> <name>zepto</name>\t<symbol>z</symbol>\n    </prefix>\n    <prefix>\n        <value>1e-24</value> <name>yocto</name>\t<symbol>y</symbol>\n    </prefix>\n</unit-system>\n"
  },
  {
    "path": "share/udunits/udunits2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"US-ASCII\"?>\n<!--\nCopyright 2008, 2009 University Corporation for Atmospheric Research\n\nThis file is part of the UDUNITS-2 package.  See the file LICENSE\nin the top-level source-directory of the package for copying and\nredistribution conditions.\n-->\n\n<unit-system>\n    <import>udunits2-prefixes.xml</import>\n    <import>udunits2-base.xml</import>\n    <import>udunits2-derived.xml</import>\n    <import>udunits2-accepted.xml</import>\n    <import>udunits2-common.xml</import>\n</unit-system>\n"
  },
  {
    "path": "site_files/site.NCAR",
    "content": "if (APPLE)\n    set (THIRD_PARTY_DIR     /usr/local/VAPOR-Deps/current\t\t\t           )\n    #set (QTDIR               /usr/local/VAPOR-Deps/current/Qt/5.15.8/clang_64 )\n    set (QTDIR               /usr/local/VAPOR-Deps/current/Qt/lib/cmake )\n    list (APPEND CMAKE_PREFIX_PATH ${QTDIR}/lib/cmake                          )\n\tset (OSPRAYDIR           ${THIRD_PARTY_DIR}/Ospray                         )\nelseif (UNIX AND NOT APPLE)\n    # Try to heuristically configure our third party libraries\n    if (NOT DEFINED THIRD_PARTY_DIR)\n        # If we're on casper, and set third party libraries accordingly\n        execute_process(\n            COMMAND uname -a\n            COMMAND grep -o \"casper\"\n            RESULT_VARIABLE casperFound\n            OUTPUT_STRIP_TRAILING_WHITESPACE\n        )\n        if (\"${casperFound}\" EQUAL \"0\")\n            set (THIRD_PARTY_DIR /glade/campaign/cisl/vast/vapor/third-party/current)\n            message(STATUS \"***\")\n            message(STATUS \"***\")\n            message(STATUS \"    NOTICE: TO BUILD ON CASPER, NCAR'S ENVIRONMENT MUST BE UNLOADED WITH\")\n            message(STATUS \"                module --force unload ncarenv\")\n            message(STATUS \"            TO RUN VAPOR ON CASPER, LD_LIBRARY_PATH MUST BE MODIFIED TO\")\n            message(STATUS \"                export LD_LIBRARY_PATH=${THIRD_PARTY_DIR}\")\n            message(STATUS \"***\")\n            message(STATUS \"***\")\n        else()\n            # Otherwise set the library path to our usual target\n            set (THIRD_PARTY_DIR     /usr/local/VAPOR-Deps/current\t\t\t     )\n        endif()\n    endif()\n    if (NOT DEFINED QTDIR)\n        #set (QTDIR ${THIRD_PARTY_DIR}/Qt/5.15.2/gcc_64)\n        set (QTDIR ${THIRD_PARTY_DIR})\n    endif()\n\n    set (CMAKE_PREFIX_PATH    ${QTDIR}/lib/cmake )\n    set (Qt5Core_DIR          ${QTDIR}/lib/cmake/Qt5Core )\n    set (QT_QMAKE_EXECUTABLE  ${QTDIR}/gcc_64/bin/qmake )\n    set (OSPRAYDIR            ${THIRD_PARTY_DIR}/Ospray )\nelse ()\n\tset (THIRD_PARTY_DIR    C:/2019-Aug)\n    set (QTDIR              ${THIRD_PARTY_DIR}/Qt/5.13.2/msvc2015_64)\n    set (CMAKE_PREFIX_PATH  ${QTDIR}/lib/cmake/Qt5) \n    set (OSPRAYDIR          ${THIRD_PARTY_DIR}/Ospray )\nendif ()\n\nset (THIRD_PARTY_LIB_DIR \"${THIRD_PARTY_DIR}/lib\")\n\nif (UNIX)\n        if (NOT DEFINED PYTHONVERSION)\n\t        set (PYTHONVERSION 3.9)\n        endif()\n    if (APPLE)\n        set (PYTHONDIR ${THIRD_PARTY_DIR}/Resources)\n        set (PYTHONPATH ${PYTHONDIR}/lib/python${PYTHONVERSION})\n    else ()\n        set (PYTHONDIR ${THIRD_PARTY_DIR})\n        set (PYTHONPATH ${THIRD_PARTY_LIB_DIR}/python${PYTHONVERSION})\n    endif()\n\tset (EXTRA_LIBS_SEARCH ${EXTRA_LIBS_SEARCH} dbus)\nelseif (WIN32)\n\tset (PYTHONVERSION 36)\n\tset (PYTHONPATH ${THIRD_PARTY_DIR}/Python${PYTHONVERSION})\nendif ()\n\nset (THIRD_PARTY_INC_DIR \"${THIRD_PARTY_DIR}/include\")\n\nif (WIN32)\n\tset (NUMPY_INCLUDE_DIR \"${PYTHONPATH}/Lib/site-packages/numpy/core/include\")\nelse ()\n\tset (NUMPY_INCLUDE_DIR \"${PYTHONPATH}/site-packages/numpy/core/include\")\nendif ()\n\nset (MAP_IMAGES_PATH \"${THIRD_PARTY_DIR}/share/images\")\n\ninclude (../vapor-site/site.cmake OPTIONAL)\n"
  },
  {
    "path": "test_apps/CMakeLists.txt",
    "content": "if (BUILD_TEST_APPS)\n\tadd_subdirectory (datamgr)\n\tadd_subdirectory (grid_iter)\n\tadd_subdirectory (params2)\n\tadd_subdirectory (pyengine)\n\tadd_subdirectory (smokeTests)\n\tadd_subdirectory (quadtreerectangle)\n\tadd_subdirectory (ParamsMgr)\n\tadd_subdirectory (udunits)\n\tadd_subdirectory (OpenMP)\n\t# add_subdirectory (controlExec)\nendif()\n"
  },
  {
    "path": "test_apps/OpenMP/CMakeLists.txt",
    "content": "add_executable (GetRange GetRange.cpp)\ntarget_link_libraries (GetRange vdc)\nset_target_properties(GetRange PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${test_output_dir}\")\n"
  },
  {
    "path": "test_apps/OpenMP/GetRange.cpp",
    "content": "#include <iostream>\n#include <chrono>\n#include <cstdlib>\n#include <vector>\n#include <random>\n#include <array>\n\n#include \"vapor/RegularGrid.h\"\n#include \"vapor/OpenMPSupport.h\"\n\n// Allocate a bunch of raw pointers.\n// The caller will need to delete[] them.\n//\nauto AllocateBlocks(std::array<size_t, 3> bs, std::array<size_t, 3> dims) -> std::vector<float*>\n{\n    size_t block_size = 1;\n    size_t nblocks = 1;\n\n    for (size_t i = 0; i < bs.size(); i++) {\n        block_size *= bs[i];\n        nblocks *= ((dims[i] - 1) / bs[i]) + 1;\n    }\n\n    auto blks = std::vector<float*>(nblocks, nullptr);\n    for (size_t i = 0; i < nblocks; i++)\n      blks[i] = new float[block_size];\n    \n    return (blks);\n}\n\n// Copy of Grid::GetRange() function from VAPOR release 3.6\n//\nvoid GetRange_36(VAPoR::Grid* g, float range[2])\n{\n    float missingValue = g->GetMissingValue();\n    auto itr = g->cbegin();\n    auto enditr = g->cend();\n\n    // Edge case: all values are missing values.\n    //\n    range[0] = range[1] = missingValue;\n    while (*itr == missingValue && itr != enditr) { ++itr; }\n    if (itr == enditr) return;\n\n    range[0] = *itr;\n    range[1] = range[0];\n    while (itr != enditr) {\n        if (*itr < range[0] && *itr != missingValue)\n            range[0] = *itr;\n        else if (*itr > range[1] && *itr != missingValue)\n            range[1] = *itr;\n        ++itr;\n    }\n}\n\nint main(int argc, char* argv[])\n{\n  if (argc != 2) {\n    std::cout << \"Help:  This program measures the serial and parallel (OpenMP) execution time\\n\"\n                 \"       given a regular grid of size (Dim x Dim x Dim).\\n\"\n                 \"Note:  the environment variable OMP_NUM_THREADS controls the number of threads.\\n\"\n                 \"Usage: ./GetRange Dim\\n\";\n    return 1;\n  }\n  const size_t dim = std::stol(argv[1]);\n  const auto dims = std::array<size_t, 3>{dim, dim, dim};\n  size_t num_threads = 1;\n\n#pragma omp parallel\n  {\n    if (omp_get_thread_num() == 0)\n      num_threads = omp_get_num_threads();\n  }\n  std::printf(\"Testing a grid of size (%ld, %ld, %ld), using %ld threads...\\n\",\n              dim, dim, dim, num_threads);\n\n  // Create a grid to test\n  const auto blk_size = std::array<size_t, 3>{128, 128, 128};\n  auto blks = AllocateBlocks(blk_size, dims);\n  auto* grid = new VAPoR::RegularGrid(dims, blk_size, blks, {0.0, 0.0, 0.0}, {100.0, 100.0, 100.0}); \n\n  // Fill in random values\n  std::random_device rd;\n  std::mt19937 gen(rd());\n  std::uniform_real_distribution<float> dist(-1.0, 10.0);\n  const auto stride_size = dim * dim * dim / num_threads;\n\n#pragma omp parallel for\n  for (size_t i = 0; i < num_threads; i++) {\n    auto beg = grid->begin() + i * stride_size;\n    auto end = beg;\n    if (i < num_threads - 1)\n      end += stride_size;\n    else\n      end = grid->end();\n    for (auto itr = beg; itr != end; ++itr)\n      *itr = dist(gen);\n  }\n\n  // Time a serial run\n  float range_36[2] = {0.0, 1.1};\n  const auto serial_start = std::chrono::steady_clock::now();\n  GetRange_36(grid, range_36);\n  const auto serial_end = std::chrono::steady_clock::now();\n  const auto serial_time = std::chrono::duration_cast<std::chrono::milliseconds>(serial_end - serial_start).count();\n  std::cout << \"GetRange() in serial time (milliseconds): \" << serial_time << std::endl;\n\n  // Time a parallel run\n  float range_omp[2] = {2.2, 3.3};\n  const auto omp_start = std::chrono::steady_clock::now();\n  grid->GetRange(range_omp);\n  const auto omp_end = std::chrono::steady_clock::now();\n  const auto omp_time = std::chrono::duration_cast<std::chrono::milliseconds>(omp_end - omp_start).count();\n  std::cout << \"GetRange() in OpenMP time (milliseconds): \" << omp_time << std::endl;\n\n  // Clean up\n  delete grid;\n  grid = nullptr;\n  for (size_t i = 0; i < blks.size(); i++) {\n    delete[](blks[i]);\n    blks[i] = nullptr;\n  }\n\n  return 0;\n}\n"
  },
  {
    "path": "test_apps/ParamsMgr/CMakeLists.txt",
    "content": "add_executable (test_ParamsMgr test_ParamsMgr.cpp)\nset_target_properties(test_ParamsMgr PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${debug_output_dir}\")\n\ntarget_link_libraries (test_ParamsMgr vdc params common wasp)\n"
  },
  {
    "path": "test_apps/ParamsMgr/file.xml",
    "content": "<VAPOR>\n<Global>\n<AnimationParams>\n<AnimationParams>\n<CurrentTimestep Type=\"Long\">\n  0 \n</CurrentTimestep>\n<EndTimestep Type=\"Long\">\n  0 \n</EndTimestep>\n<FrameStepSize Type=\"Long\">\n  1 \n</FrameStepSize>\n<MaxTimestep Type=\"Long\">\n  0 \n</MaxTimestep>\n<MinTimestep Type=\"Long\">\n  0 \n</MinTimestep>\n<PlayDirection Type=\"Long\">\n  0 \n</PlayDirection>\n<RepeatPlay Type=\"Long\">\n  0 \n</RepeatPlay>\n<StartTimestep Type=\"Long\">\n  0 \n</StartTimestep>\n<MaxFrameRate Type=\"Double\">\n  0.1 \n</MaxFrameRate>\n</AnimationParams>\n</AnimationParams>\n<RegionParams>\n<RegionParams>\n<BoxParams>\n<Orientation Type=\"Long\">\n  2 \n</Orientation>\n<Planar Type=\"Long\">\n  0 \n</Planar>\n<Angles Type=\"Double\">\n  0 0 0 \n</Angles>\n<Extents Type=\"Double\">\n  0 0 0 1 1 1 \n</Extents>\n</BoxParams>\n</RegionParams>\n</RegionParams>\n<VizFeatureParams>\n<VizFeatureParams>\n<AxisAnnotation Type=\"Long\">\n  0 \n</AxisAnnotation>\n<AxisDigits Type=\"Long\">\n  4 \n</AxisDigits>\n<AxisTextHeight Type=\"Long\">\n  10 \n</AxisTextHeight>\n<DomainFrame Type=\"Long\">\n  1 \n</DomainFrame>\n<LatLonAxes Type=\"Long\">\n  0 \n</LatLonAxes>\n<NumberTics Type=\"Long\">\n  0 0 0 \n</NumberTics>\n<RegionFrame Type=\"Long\">\n  0 \n</RegionFrame>\n<ShowAxisArrows Type=\"Long\">\n  0 \n</ShowAxisArrows>\n<TicDirections Type=\"Long\">\n  1 0 0 \n</TicDirections>\n<AxisArrowCoords Type=\"Double\">\n  0 0 0 \n</AxisArrowCoords>\n<AxisColor Type=\"Double\">\n  1 1 1 \n</AxisColor>\n<BackgroundColor Type=\"Double\">\n  0 0 0 \n</BackgroundColor>\n<DomainColor Type=\"Double\">\n  1 1 1 \n</DomainColor>\n<NumberTics Type=\"Double\">\n  0 0 0 \n</NumberTics>\n<RegionColor Type=\"Double\">\n  1 0 0 \n</RegionColor>\n<TicMaxPositions Type=\"Double\">\n  0 0 0 \n</TicMaxPositions>\n<TicMinPositions Type=\"Double\">\n  0 0 0 \n</TicMinPositions>\n<TicSizes Type=\"Double\">\n  0 0 0 \n</TicSizes>\n<TicWidths Type=\"Double\">\n  1 \n</TicWidths>\n</VizFeatureParams>\n</VizFeatureParams>\n</Global>\n<Windows>\n<viz0>\n<ViewpointParams>\n<NumLights Type=\"Long\">\n  1 \n</NumLights>\n<WindowSize Type=\"Long\">\n  100 100 \n</WindowSize>\n<AmbientCoefficient Type=\"Double\">\n  0.1000000014901161 \n</AmbientCoefficient>\n<DiffuseCoefficients Type=\"Double\">\n  0.800000011920929 0.800000011920929 0.800000011920929 \n</DiffuseCoefficients>\n<LightDirections Type=\"Double\">\n  0 0 1 0 0 1 0 0 1 0 0 0 \n</LightDirections>\n<SpecularCoefficients Type=\"Double\">\n  0.300000011920929 0.300000011920929 0.300000011920929 \n</SpecularCoefficients>\n<SpecularExponent Type=\"Double\">\n  20 \n</SpecularExponent>\n<StretchFactors Type=\"Double\">\n  1 1 1 \n</StretchFactors>\n<Viewpoints>\n<CurrentViewpoint>\n<Viewpoint>\n<ModelViewMatrix Type=\"Double\">\n  1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 \n</ModelViewMatrix>\n<ProjectionMatrix Type=\"Double\">\n  1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 \n</ProjectionMatrix>\n</Viewpoint>\n</CurrentViewpoint>\n<HomeViewpoint>\n<Viewpoint>\n<ModelViewMatrix Type=\"Double\">\n  1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 \n</ModelViewMatrix>\n<ProjectionMatrix Type=\"Double\">\n  1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 \n</ProjectionMatrix>\n</Viewpoint>\n</HomeViewpoint>\n</Viewpoints>\n</ViewpointParams>\n<Renderers>\n<TwoDDataParams>\n<twoD0>\n<TwoDDataParams>\n<CompressionLevel Type=\"Long\">\n  0 \n</CompressionLevel>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<RefinementLevel Type=\"Long\">\n  0 \n</RefinementLevel>\n<UseSingleColor Type=\"Long\">\n  0 \n</UseSingleColor>\n<ConstantColor Type=\"Double\">\n  1 1 1 \n</ConstantColor>\n<ConstantOpacity Type=\"Double\">\n  1 \n</ConstantOpacity>\n<HistoScale Type=\"Double\">\n  1 \n</HistoScale>\n<StretchFactors Type=\"Double\">\n  1 1 1 \n</StretchFactors>\n<ColorMapVariable Type=\"String\">\n  NULL\n</ColorMapVariable>\n<FieldVariableNames Type=\"String\">\n  P PB PH\n</FieldVariableNames>\n<HeightVariable Type=\"String\">\n  NULL\n</HeightVariable>\n<VariableName Type=\"String\">\n  U10\n</VariableName>\n<TransferFunctions>\n<U10>\n<TransferFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -49.3205451965332 33.28469848632812 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -49.3205451965332 33.28469848632812 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 \n</ColorMapControlPoints>\n</ColorMapParams>\n</TransferFunctionParams>\n</U10>\n</TransferFunctions>\n<BoxParams>\n<Orientation Type=\"Long\">\n  2 \n</Orientation>\n<Planar Type=\"Long\">\n  1 \n</Planar>\n<Angles Type=\"Double\">\n  0 0 0 \n</Angles>\n<Extents Type=\"Double\">\n  -845627.125 1991855.625 0 412793.375 3219581.5 0 \n</Extents>\n</BoxParams>\n<ColorBarSettingParams>\n<ColorbarEnabled Type=\"Long\">\n  0 \n</ColorbarEnabled>\n<ColorbarFontsize Type=\"Long\">\n  10 \n</ColorbarFontsize>\n<ColorbarNumDigits Type=\"Long\">\n  4 \n</ColorbarNumDigits>\n<ColorbarNumTics Type=\"Long\">\n  6 \n</ColorbarNumTics>\n<ColorbarBackgroundColor Type=\"Double\">\n  1 1 1 \n</ColorbarBackgroundColor>\n<ColorbarPosition Type=\"Double\">\n  0.1 0.1 \n</ColorbarPosition>\n<ColorbarSize Type=\"Double\">\n  0.1 0.1 \n</ColorbarSize>\n<ColorbarTitle Type=\"String\">\n  \n</ColorbarTitle>\n</ColorBarSettingParams>\n</TwoDDataParams>\n</twoD0>\n<twoD1>\n<TwoDDataParams>\n<CompressionLevel Type=\"Long\">\n  0 \n</CompressionLevel>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<RefinementLevel Type=\"Long\">\n  0 \n</RefinementLevel>\n<UseSingleColor Type=\"Long\">\n  0 \n</UseSingleColor>\n<ConstantColor Type=\"Double\">\n  1 1 1 \n</ConstantColor>\n<ConstantOpacity Type=\"Double\">\n  1 \n</ConstantOpacity>\n<HistoScale Type=\"Double\">\n  1 \n</HistoScale>\n<StretchFactors Type=\"Double\">\n  1 1 1 \n</StretchFactors>\n<ColorMapVariable Type=\"String\">\n  NULL\n</ColorMapVariable>\n<FieldVariableNames Type=\"String\">\n  P PB PH\n</FieldVariableNames>\n<HeightVariable Type=\"String\">\n  NULL\n</HeightVariable>\n<VariableName Type=\"String\">\n  V10\n</VariableName>\n<TransferFunctions>\n<V10>\n<TransferFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -41.49079132080078 43.95055770874023 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -41.49079132080078 43.95055770874023 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 \n</ColorMapControlPoints>\n</ColorMapParams>\n</TransferFunctionParams>\n</V10>\n</TransferFunctions>\n<BoxParams>\n<Orientation Type=\"Long\">\n  2 \n</Orientation>\n<Planar Type=\"Long\">\n  1 \n</Planar>\n<Angles Type=\"Double\">\n  0 0 0 \n</Angles>\n<Extents Type=\"Double\">\n  -845627.125 1991855.625 0 412793.375 3219581.5 0 \n</Extents>\n</BoxParams>\n<ColorBarSettingParams>\n<ColorbarEnabled Type=\"Long\">\n  0 \n</ColorbarEnabled>\n<ColorbarFontsize Type=\"Long\">\n  10 \n</ColorbarFontsize>\n<ColorbarNumDigits Type=\"Long\">\n  4 \n</ColorbarNumDigits>\n<ColorbarNumTics Type=\"Long\">\n  6 \n</ColorbarNumTics>\n<ColorbarBackgroundColor Type=\"Double\">\n  1 1 1 \n</ColorbarBackgroundColor>\n<ColorbarPosition Type=\"Double\">\n  0.1 0.1 \n</ColorbarPosition>\n<ColorbarSize Type=\"Double\">\n  0.1 0.1 \n</ColorbarSize>\n<ColorbarTitle Type=\"String\">\n  \n</ColorbarTitle>\n</ColorBarSettingParams>\n</TwoDDataParams>\n</twoD1>\n</TwoDDataParams>\n<ArrowParams>\n<arrow>\n<ArrowParams>\n<CompressionLevel Type=\"Long\">\n  0 \n</CompressionLevel>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<GridAlignedStrides Type=\"Long\">\n  0 0 \n</GridAlignedStrides>\n<GridAlignedToData Type=\"Long\">\n  0 \n</GridAlignedToData>\n<GridDimensions Type=\"Long\">\n  10 10 1 \n</GridDimensions>\n<RefinementLevel Type=\"Long\">\n  0 \n</RefinementLevel>\n<UseSingleColor Type=\"Long\">\n  0 \n</UseSingleColor>\n<ConstantColor Type=\"Double\">\n  1 1 1 \n</ConstantColor>\n<ConstantOpacity Type=\"Double\">\n  1 \n</ConstantOpacity>\n<HistoScale Type=\"Double\">\n  1 \n</HistoScale>\n<LineThickness Type=\"Double\">\n  4 \n</LineThickness>\n<StretchFactors Type=\"Double\">\n  1 1 1 \n</StretchFactors>\n<VectorScale Type=\"Double\">\n  1 \n</VectorScale>\n<ColorMapVariable Type=\"String\">\n  NULL\n</ColorMapVariable>\n<FieldVariableNames Type=\"String\">\n  P PB PH\n</FieldVariableNames>\n<HeightVariable Type=\"String\">\n  NULL\n</HeightVariable>\n<VariableName Type=\"String\">\n  P\n</VariableName>\n<TransferFunctions>\n<U>\n<TransferFunctionParams>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -62.61578750610352 45.91978073120117 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMapParams>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -62.61578750610352 45.91978073120117 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMapParams>\n</OpacityMap_0>\n</OpacityMaps>\n<ColorMapParams>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 \n</ColorMapControlPoints>\n</ColorMapParams>\n</TransferFunctionParams>\n</U>\n</TransferFunctions>\n<BoxParams>\n<Orientation Type=\"Long\">\n  2 \n</Orientation>\n<Planar Type=\"Long\">\n  0 \n</Planar>\n<Angles Type=\"Double\">\n  0 0 0 \n</Angles>\n<Extents Type=\"Double\">\n  -845627.125 1991855.625 31.70084762573242 412793.375 3219581.5 20262.4765625 \n</Extents>\n</BoxParams>\n<ColorBarSettingParams>\n<ColorbarEnabled Type=\"Long\">\n  0 \n</ColorbarEnabled>\n<ColorbarFontsize Type=\"Long\">\n  10 \n</ColorbarFontsize>\n<ColorbarNumDigits Type=\"Long\">\n  4 \n</ColorbarNumDigits>\n<ColorbarNumTics Type=\"Long\">\n  6 \n</ColorbarNumTics>\n<ColorbarBackgroundColor Type=\"Double\">\n  1 1 1 \n</ColorbarBackgroundColor>\n<ColorbarPosition Type=\"Double\">\n  0.1 0.1 \n</ColorbarPosition>\n<ColorbarSize Type=\"Double\">\n  0.1 0.1 \n</ColorbarSize>\n<ColorbarTitle Type=\"String\">\n  \n</ColorbarTitle>\n</ColorBarSettingParams>\n</ArrowParams>\n</arrow>\n</ArrowParams>\n</Renderers>\n</viz0>\n</Windows>\n</VAPOR>\n"
  },
  {
    "path": "test_apps/ParamsMgr/test_ParamsMgr.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <vector>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/MyBase.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/DataMgr.h>\n#include <vapor/DataStatus.h>\n#include <vapor/OptionParser.h>\n#include <vapor/TwoDDataParams.h>\n#include <vapor/CFuncs.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    string                  ifile;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T debug;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {\n    {\"ifile\", 1, \"\", \"Construct Xml tree from a file\"}, {\"help\", 0, \"\", \"Print this message and exit\"}, {\"quiet\", 0, \"\", \"Operate quitely\"}, {\"debug\", 0, \"\", \"Debug mode\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"ifile\", Wasp::CvtToCPPStr, &opt.ifile, sizeof(opt.ifile)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {NULL}};\n\nconst char *ProgName;\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       s;\n\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); }\n\n    if (argc != 2) {\n        cerr << \"Usage: \" << ProgName << \" VDCMaster.nc [options] \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    string vdcfile = argv[1];\n\n    DataStatus dataStatus;\n    string     dataSetName = \"mydata\";\n\n    int rc = dataStatus.Open(vector<string>{vdcfile}, vector<string>(), dataSetName, \"vdc\");\n    if (rc < 0) return (1);\n\n    ParamsMgr *pm = new ParamsMgr();\n    pm->SetSaveStateEnabled(false);\n\n    string winName = \"myWindow\";\n\n    pm->AddDataMgr(dataSetName, dataStatus.GetDataMgr(dataSetName));\n\n    TwoDDataParams *twoDparams0 = (TwoDDataParams *)pm->CreateRenderParamsInstance(winName, dataSetName, TwoDDataParams::GetClassType(), \"twoD0\");\n\n    twoDparams0->SetVariableName(\"U10\");\n\n    TwoDDataParams *twoDparams1 = (TwoDDataParams *)pm->CreateRenderParamsInstance(winName, dataSetName, TwoDDataParams::GetClassType(), \"twoD1\");\n\n    twoDparams1->SetVariableName(\"V10\");\n\n    pm->SetSaveStateEnabled(true);\n    pm->UndoRedoClear();\n\n    pm->SaveToFile(\"file.xml\");\n    twoDparams1->SetVariableName(\"U1\");\n    twoDparams1->SetCompressionLevel(1);\n    pm->RemoveVisualizer(winName);\n\n    pm->Undo();\n    pm->Undo();\n    pm->Undo();\n\n    pm->Redo();\n    pm->Redo();\n    pm->Redo();\n    pm->Undo();\n    pm->Undo();\n    pm->Undo();\n\n    pm->SaveToFile(\"fileUndo.xml\");\n\n    cout << \"Allocated XmlNode count before delete \" << XmlNode::GetAllocatedNodes().size() << endl;\n\n//#define DEBUG\n#ifdef DEBUG\n    const vector<XmlNode *> &nodes = XmlNode::GetAllocatedNodes();\n    for (int i = 0; i < nodes.size(); i++) { cout << \"   \" << nodes[i]->GetTag() << \" \" << nodes[i] << endl; }\n#endif\n\n    delete pm;\n\n    cout << \"Allocated XmlNode count after delete \" << XmlNode::GetAllocatedNodes().size() << endl;\n\n#ifdef DEBUG\n\n    for (int i = 0; i < nodes.size(); i++) { cout << \"   \" << nodes[i]->GetTag() << \" \" << nodes[i] << endl; }\n#endif\n}\n"
  },
  {
    "path": "test_apps/TransferFunction/test_TransferFunction.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <vector>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/TransferFunction.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    string                  ifile;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T debug;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {\n    {\"ifile\", 1, \"\", \"Construct Xml tree from a file\"}, {\"help\", 0, \"\", \"Print this message and exit\"}, {\"quiet\", 0, \"\", \"Operate quitely\"}, {\"debug\", 0, \"\", \"Debug mode\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"ifile\", Wasp::CvtToCPPStr, &opt.ifile, sizeof(opt.ifile)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {NULL}};\n\nconst char *ProgName;\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       s;\n\n    ProgName = Basename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); }\n\n    if (argc != 1) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    ParamsBase::StateSave save;\n\n    TransferFunction *tf = new TransferFunction(&save);\n\n    tf->SaveToFile(\"/Users/clyne/foo.xml\");\n\n    tf->LoadFromFile(\"/Users/clyne/foo.xml\");\n\n    tf->SaveToFile(\"/Users/clyne/doo.xml\");\n\n    delete tf;\n\n    cout << \"Allocated note count after delete : \" << XmlNode::GetAllocatedNodes().size() << endl;\n}\n"
  },
  {
    "path": "test_apps/base64/CMakeLists.txt",
    "content": "add_executable (test_base64 test_base64.cpp)\n\ntarget_link_libraries (test_base64 common)\n"
  },
  {
    "path": "test_apps/base64/test_base64.cpp",
    "content": "#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n\n#include <vapor/Base64.h>\n\nusing namespace Wasp;\n\nint main(int argc, char **argv)\n{\n    const int sz = 1024;\n\n    string str;\n    int    buf[sz];\n    int    outbuf[sz];\n    Base64 base64;\n\n    for (int i = 0; i < sz; i++) { buf[i] = i; }\n\n    base64.Encode((unsigned char *)buf, sz * 4, str);\n\n    cout << str;\n\n    size_t n;\n    if (base64.Decode(str, (unsigned char *)outbuf, &n) < 0) {\n        cerr << \"Base64::Decode() : \" << Base64::GetErrMsg() << endl;\n        exit(1);\n    }\n\n    for (int i = 0; i < sz; i++) {\n        if (buf[i] != outbuf[i]) { cerr << \"Buf mismatch at offset \" << i << endl; }\n    }\n    exit(0);\n}\n"
  },
  {
    "path": "test_apps/controlExec/CMakeLists.txt",
    "content": "find_package(Qt4 REQUIRED)\nset (CMAKE_AUTOUIC ON) # This needs to appear before adding sources to work properly\nset (CMAKE_AUTOMOC ON)\nset (CMAKE_INCLUDE_CURRENT_DIR ON)\n\nadd_executable (test_CE test_CE.cpp test_vizwin.cpp moc_test_vizwin.cpp)\n\ntarget_link_libraries (test_CE common vdc wasp params render ${GLEW} Qt4::QtCore Qt4::QtGui Qt4::QtOpenGL jpeg tiff)\n"
  },
  {
    "path": "test_apps/controlExec/file.xml",
    "content": "<VAPOR>\n<Global>\n<AnimationParams>\n<AnimationParams>\n<CurrentTimestep Type=\"Long\">\n  0 \n</CurrentTimestep>\n<EndTimestep Type=\"Long\">\n  0 \n</EndTimestep>\n<FrameStepSize Type=\"Long\">\n  1 \n</FrameStepSize>\n<MaxTimestep Type=\"Long\">\n  0 \n</MaxTimestep>\n<MinTimestep Type=\"Long\">\n  0 \n</MinTimestep>\n<PlayDirection Type=\"Long\">\n  0 \n</PlayDirection>\n<RepeatPlay Type=\"Long\">\n  0 \n</RepeatPlay>\n<StartTimestep Type=\"Long\">\n  0 \n</StartTimestep>\n<MaxFrameRate Type=\"Double\">\n  0.1 \n</MaxFrameRate>\n</AnimationParams>\n</AnimationParams>\n<RegionParams>\n<RegionParams>\n<Box>\n<Orientation Type=\"Long\">\n  2 \n</Orientation>\n<Planar Type=\"Long\">\n  0 \n</Planar>\n<Angles Type=\"Double\">\n  0 0 0 \n</Angles>\n<Extents Type=\"Double\">\n  0 0 0 1 1 1 \n</Extents>\n</Box>\n</RegionParams>\n</RegionParams>\n<VizFeatureParams>\n<VizFeatureParams>\n<AxisAnnotation Type=\"Long\">\n  0 \n</AxisAnnotation>\n<AxisDigits Type=\"Long\">\n  4 \n</AxisDigits>\n<AxisTextHeight Type=\"Long\">\n  10 \n</AxisTextHeight>\n<DomainFrame Type=\"Long\">\n  1 \n</DomainFrame>\n<LatLonAxes Type=\"Long\">\n  0 \n</LatLonAxes>\n<NumberTics Type=\"Long\">\n  0 0 0 \n</NumberTics>\n<RegionFrame Type=\"Long\">\n  0 \n</RegionFrame>\n<ShowAxisArrows Type=\"Long\">\n  0 \n</ShowAxisArrows>\n<TicDirections Type=\"Long\">\n  1 0 0 \n</TicDirections>\n<AxisArrowCoords Type=\"Double\">\n  0 0 0 \n</AxisArrowCoords>\n<AxisColor Type=\"Double\">\n  1 1 1 \n</AxisColor>\n<BackgroundColor Type=\"Double\">\n  0 0 0 \n</BackgroundColor>\n<DomainColor Type=\"Double\">\n  1 1 1 \n</DomainColor>\n<NumberTics Type=\"Double\">\n  0 0 0 \n</NumberTics>\n<RegionColor Type=\"Double\">\n  1 0 0 \n</RegionColor>\n<TicMaxPositions Type=\"Double\">\n  0 0 0 \n</TicMaxPositions>\n<TicMinPositions Type=\"Double\">\n  0 0 0 \n</TicMinPositions>\n<TicSizes Type=\"Double\">\n  0 0 0 \n</TicSizes>\n<TicWidths Type=\"Double\">\n  1 \n</TicWidths>\n</VizFeatureParams>\n</VizFeatureParams>\n</Global>\n<Windows>\n<win1>\n<ViewpointParams>\n<NumLights Type=\"Long\">\n  1 \n</NumLights>\n<WindowSize Type=\"Long\">\n  1280 598 \n</WindowSize>\n<AmbientCoefficient Type=\"Double\">\n  0.1000000014901161 \n</AmbientCoefficient>\n<DiffuseCoefficients Type=\"Double\">\n  0.800000011920929 0.800000011920929 0.800000011920929 \n</DiffuseCoefficients>\n<LightDirections Type=\"Double\">\n  0 0 1 0 0 1 0 0 1 0 0 0 \n</LightDirections>\n<ModelViewMatrix Type=\"Double\">\n  1 0 0 0 0 1 0 0 0 0 1 0 216416.875 -2605718.5 -1502258.75 1 \n</ModelViewMatrix>\n<SpecularCoefficients Type=\"Double\">\n  0.300000011920929 0.300000011920929 0.300000011920929 \n</SpecularCoefficients>\n<SpecularExponent Type=\"Double\">\n  20 \n</SpecularExponent>\n<StretchFactors Type=\"Double\">\n  1 1 1 \n</StretchFactors>\n<Viewpoints>\n<CurrentViewpoint>\n<Viewpoint>\n<CameraPosition Type=\"Double\">\n  -216416.875 2605718.5 1502258.75 \n</CameraPosition>\n<RotationCenter Type=\"Double\">\n  -216416.875 2605718.5625 10147.08870506287 \n</RotationCenter>\n<UpVector Type=\"Double\">\n  0 1 0 \n</UpVector>\n<ViewDirection Type=\"Double\">\n  -0 -0 -1 \n</ViewDirection>\n</Viewpoint>\n</CurrentViewpoint>\n<HomeViewpoint>\n<Viewpoint>\n<CameraPosition Type=\"Double\">\n  0 0 0.25 \n</CameraPosition>\n<RotationCenter Type=\"Double\">\n  0 0 0 \n</RotationCenter>\n<UpVector Type=\"Double\">\n  0 1 0 \n</UpVector>\n<ViewDirection Type=\"Double\">\n  0 0 -1 \n</ViewDirection>\n</Viewpoint>\n</HomeViewpoint>\n</Viewpoints>\n</ViewpointParams>\n<Renderers>\n<TwoDDataParams>\n<twoD1>\n<TwoDDataParams>\n<CompressionLevel Type=\"Long\">\n  0 \n</CompressionLevel>\n<Enabled Type=\"Long\">\n  0 \n</Enabled>\n<RefinementLevel Type=\"Long\">\n  0 \n</RefinementLevel>\n<UseSingleColor Type=\"Long\">\n  0 \n</UseSingleColor>\n<ConstantColor Type=\"Double\">\n  1 1 1 \n</ConstantColor>\n<ConstantOpacity Type=\"Double\">\n  1 \n</ConstantOpacity>\n<HistoScale Type=\"Double\">\n  1 \n</HistoScale>\n<StretchFactors Type=\"Double\">\n  1 1 1 \n</StretchFactors>\n<FieldVariableNames Type=\"String\">\n  P PB PH\n</FieldVariableNames>\n<HeightVariable Type=\"String\">\n  NULL\n</HeightVariable>\n<VariableName Type=\"String\">\n  U10\n</VariableName>\n<TransferFunctions>\n<CANWAT>\n<TransferFunction>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -1 0 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMap>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  -1 0 \n</DataBounds>\n</ColorMap>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMap>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -1 0 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMap>\n</OpacityMap_0>\n</OpacityMaps>\n</TransferFunction>\n</CANWAT>\n<U10>\n<TransferFunction>\n<OpacityComposition Type=\"Long\">\n  0 \n</OpacityComposition>\n<DataBounds Type=\"Double\">\n  -49.3205451965332 33.28469848632812 \n</DataBounds>\n<OpacityScale Type=\"Double\">\n  1 \n</OpacityScale>\n<ColorMap>\n<ColorInterpolationType Type=\"Long\">\n  4 \n</ColorInterpolationType>\n<ColorMapControlPoints Type=\"Double\">\n  0.6444444444444445 0.695 0.757 0 0.9666666666666667 0.977 0.706 0.99 \n</ColorMapControlPoints>\n<DataBounds Type=\"Double\">\n  -49.3205451965332 33.28469848632812 \n</DataBounds>\n</ColorMap>\n<OpacityMaps>\n<OpacityMap_0>\n<OpacityMap>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<OpacityInterpolation Type=\"Long\">\n  0 \n</OpacityInterpolation>\n<Type Type=\"Long\">\n  0 \n</Type>\n<DataBounds Type=\"Double\">\n  -49.3205451965332 33.28469848632812 \n</DataBounds>\n<Freq Type=\"Double\">\n  5 \n</Freq>\n<Mean Type=\"Double\">\n  0.5 \n</Mean>\n<OpacityMapControlPoints Type=\"Double\">\n  0 0 0.3333333333333333 0.3333333333333333 0.6666666666666666 0.6666666666666666 1 1 \n</OpacityMapControlPoints>\n<Phase Type=\"Double\">\n  39.47841760435743 \n</Phase>\n<RelMaxValue Type=\"Double\">\n  1 \n</RelMaxValue>\n<RelMinValue Type=\"Double\">\n  0 \n</RelMinValue>\n<SSq Type=\"Double\">\n  0.1 \n</SSq>\n</OpacityMap>\n</OpacityMap_0>\n</OpacityMaps>\n</TransferFunction>\n</U10>\n</TransferFunctions>\n<Box>\n<Orientation Type=\"Long\">\n  2 \n</Orientation>\n<Planar Type=\"Long\">\n  1 \n</Planar>\n<Angles Type=\"Double\">\n  0 0 0 \n</Angles>\n<Extents Type=\"Double\">\n  -845627.125 1991855.625 31.70084762573242 412793.375 3219581.5 20262.4765625 \n</Extents>\n</Box>\n<ColorBarSettings>\n<ColorbarEnabled Type=\"Long\">\n  0 \n</ColorbarEnabled>\n<ColorbarFontsize Type=\"Long\">\n  10 \n</ColorbarFontsize>\n<ColorbarNumDigits Type=\"Long\">\n  4 \n</ColorbarNumDigits>\n<ColorbarNumTics Type=\"Long\">\n  6 \n</ColorbarNumTics>\n<ColorbarBackgroundColor Type=\"Double\">\n  1 1 1 \n</ColorbarBackgroundColor>\n<ColorbarPosition Type=\"Double\">\n  0.1 0.1 \n</ColorbarPosition>\n<ColorbarSize Type=\"Double\">\n  0.1 0.1 \n</ColorbarSize>\n<ColorbarTitle Type=\"String\">\n  \n</ColorbarTitle>\n</ColorBarSettings>\n</TwoDDataParams>\n</twoD1>\n</TwoDDataParams>\n</Renderers>\n</win1>\n</Windows>\n</VAPOR>\n"
  },
  {
    "path": "test_apps/controlExec/moc_test_vizwin.cpp",
    "content": "/****************************************************************************\n** Meta object code from reading C++ file 'test_vizwin.h'\n**\n** Created by: The Qt Meta Object Compiler version 63 (Qt 4.8.6)\n**\n** WARNING! All changes made in this file will be lost!\n*****************************************************************************/\n\n#include \"../test_vizwin.h\"\n#if !defined(Q_MOC_OUTPUT_REVISION)\n    #error \"The header file 'test_vizwin.h' doesn't include <QObject>.\"\n#elif Q_MOC_OUTPUT_REVISION != 63\n    #error \"This file was generated using the moc from 4.8.6. It\"\n    #error \"cannot be used with the include files from this version of Qt.\"\n    #error \"(The moc has changed too much.)\"\n#endif\n\nQT_BEGIN_MOC_NAMESPACE\nstatic const uint qt_meta_data_VAPoR__Test_VizWin[] = {\n\n    // content:\n    6,       // revision\n    0,       // classname\n    0, 0,    // classinfo\n    0, 0,    // methods\n    0, 0,    // properties\n    0, 0,    // enums/sets\n    0, 0,    // constructors\n    0,       // flags\n    0,       // signalCount\n\n    0    // eod\n};\n\nstatic const char qt_meta_stringdata_VAPoR__Test_VizWin[] = {\"VAPoR::Test_VizWin\\0\"};\n\nvoid VAPoR::Test_VizWin::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)\n{\n    Q_UNUSED(_o);\n    Q_UNUSED(_id);\n    Q_UNUSED(_c);\n    Q_UNUSED(_a);\n}\n\nconst QMetaObjectExtraData VAPoR::Test_VizWin::staticMetaObjectExtraData = {0, qt_static_metacall};\n\nconst QMetaObject VAPoR::Test_VizWin::staticMetaObject = {{&QGLWidget::staticMetaObject, qt_meta_stringdata_VAPoR__Test_VizWin, qt_meta_data_VAPoR__Test_VizWin, &staticMetaObjectExtraData}};\n\n#ifdef Q_NO_DATA_RELOCATION\nconst QMetaObject &VAPoR::Test_VizWin::getStaticMetaObject() { return staticMetaObject; }\n#endif    // Q_NO_DATA_RELOCATION\n\nconst QMetaObject *VAPoR::Test_VizWin::metaObject() const { return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject; }\n\nvoid *VAPoR::Test_VizWin::qt_metacast(const char *_clname)\n{\n    if (!_clname) return 0;\n    if (!strcmp(_clname, qt_meta_stringdata_VAPoR__Test_VizWin)) return static_cast<void *>(const_cast<Test_VizWin *>(this));\n    return QGLWidget::qt_metacast(_clname);\n}\n\nint VAPoR::Test_VizWin::qt_metacall(QMetaObject::Call _c, int _id, void **_a)\n{\n    _id = QGLWidget::qt_metacall(_c, _id, _a);\n    if (_id < 0) return _id;\n    return _id;\n}\nQT_END_MOC_NAMESPACE\n"
  },
  {
    "path": "test_apps/controlExec/test_CE.cpp",
    "content": "#include <vapor/glutil.h>\n#include <iostream>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n#include <qapplication.h>\n#include <QGLWidget>\n#include <vapor/OptionParser.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/animationparams.h>\n#include <vapor/ParamsMgr.h>\n#include <vapor/TwoDDataRenderer.h>\n#include <vapor/TwoDDataParams.h>\n#include <vapor/HelloRenderer.h>\n#include <vapor/HelloParams.h>\n#include <vapor/arrowparams.h>\n#include \"test_vizwin.h\"\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    int                     nts;\n    int                     ts0;\n    string                  vdcmaster;\n    string                  sessionfile;\n    string                  var;\n    OptionParser::Boolean_T arrow;\n    OptionParser::Boolean_T twoD;\n    OptionParser::Boolean_T hello;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T debug;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"nts\", 1, \"1\", \"Number of timesteps to play\"},\n                                         {\"ts0\", 1, \"0\", \"First time step to play\"},\n                                         {\"ses\", 1, \"\", \"VAPOR session file to read\"},\n                                         {\"var\", 1, \"\", \"Primary variable name\"},\n                                         {\"arrow\", 0, \"\", \"Create arrow renderer\"},\n                                         {\"twoD\", 0, \"\", \"Create TwoD renderer\"},\n                                         {\"hello\", 0, \"\", \"Create hello renderer\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {\"quiet\", 0, \"\", \"Operate quietly\"},\n                                         {\"debug\", 0, \"\", \"Debug mode\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"nts\", Wasp::CvtToInt, &opt.nts, sizeof(opt.nts)},\n                                        {\"ts0\", Wasp::CvtToInt, &opt.ts0, sizeof(opt.ts0)},\n                                        {\"ses\", Wasp::CvtToCPPStr, &opt.sessionfile, sizeof(opt.sessionfile)},\n                                        {\"var\", Wasp::CvtToCPPStr, &opt.var, sizeof(opt.var)},\n                                        {\"arrow\", Wasp::CvtToBoolean, &opt.arrow, sizeof(opt.arrow)},\n                                        {\"twoD\", Wasp::CvtToBoolean, &opt.twoD, sizeof(opt.twoD)},\n                                        {\"hello\", Wasp::CvtToBoolean, &opt.hello, sizeof(opt.hello)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {NULL}};\n\nconst char *ProgName;\n\nvoid ErrMsgCBHandler(const char *msg, int) { cerr << ProgName << \" : \" << msg << endl; }\n\nRenderParams *CreateRender(ControlExec *CE, string winName, string className, string name)\n{\n    RenderParams *rp = NULL;\n    ParamsMgr *   pMgr = CE->GetParamsMgr();\n\n    int rc = CE->ActivateRender(winName, className, name, false);\n    if (rc < 0) {\n        cerr << \"Failed to activate renderer type : \" << className << endl;\n        return NULL;\n    }\n\n    // Create a new barbs params to be used in rendering\n    rp = pMgr->GetRenderParams(winName, className, name);\n\n    if (!rp) {\n        cerr << \"Failed to get params for renderer type : \" << className << endl;\n        return NULL;\n    }\n\n    return (rp);\n}\n\nint CreateNew(ControlExec *CE, string winName)\n{\n    int rc = CE->NewVisualizer(winName);\n    if (rc < 0) {\n        cerr << \"Failed to creat visualizer \" << endl;\n        return -1;\n    }\n\n    RenderParams *rParams = NULL;\n    if (opt.arrow) {\n        string       name = \"arrow1\";\n        ArrowParams *myRParams = NULL;\n\n        myRParams = (ArrowParams *)CreateRender(CE, winName, ArrowParams::m_classTag, name);\n\n        if (!myRParams) return (-1);\n        rParams = myRParams;\n    }\n\n    if (opt.twoD) {\n        string          name = \"twoD1\";\n        TwoDDataParams *myRParams = NULL;\n\n        myRParams = (TwoDDataParams *)CreateRender(CE, winName, TwoDDataParams::m_classTag, name);\n\n        if (!myRParams) return (-1);\n        rParams = myRParams;\n    }\n\n    if (opt.hello) {\n        string       name = \"hello1\";\n        HelloParams *myRParams = NULL;\n\n        myRParams = (HelloParams *)CreateRender(CE, winName, HelloParams::m_classTag, name);\n\n        if (!myRParams) return (-1);\n\n        myRParams->SetLineThickness(4.0);\n        rParams = myRParams;\n    }\n    if (!opt.var.empty()) { rParams->SetVariableName(opt.var); }\n\n    return (0);\n}\n\nQApplication *app;\nint           main(int argc, char **argv)\n{\n    OptionParser op;\n    double       timer = 0.0;\n    string       s;\n\n    const char *ProgName = \"test_CE\";\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] metafiles \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); }\n\n    if (argc < 2) {\n        cerr << \"Usage: \" << ProgName << \" [options] \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n    // Set up Qt application\n    QApplication a(argc, argv, true);\n    app = &a;\n\n    string       winName = \"win1\";\n    ControlExec *CE = new ControlExec;\n    // Create the OpenGL Window\n    Test_VizWin vizwin(0, CE, winName);\n\n    // Create and set up a visualizer (no. 0)\n\n    bool useSession = false;\n#ifdef VAPOR3_0_0_ALPHA\n    CE->CreateDefaultParams(0);\n    CE->SetActiveVizIndex(0);\n\n    // Restore preferences (expect .vapor3_prefs in home directory)\n    if (getenv(\"HOME\")) {\n        string prefPath = string(getenv(\"HOME\")) + \"/.vapor3_prefs\";\n        CE->RestorePreferences(prefPath);\n    }\n    // Load session if specified\n    bool enabled = false;\n    if (opt.sessionfile.length() > 0) {\n        CE->SetToDefault();\n        int rc = CE->RestoreSession(opt.sessionfile);\n        if (rc == 0) useSession = true;\n    }\n#endif\n\n    // Load data\n    vector<string> files;\n    for (int i = 1; i < argc; i++) { files.push_back(argv[i]); }\n\n    int rc = CE->LoadData(files, 1000, !useSession);\n    if (rc < 0) return (1);\n\n        // Disable command queue (not used here)\n#ifdef VAPOR3_0_0_ALPHA\n    Command::blockCapture();\n#endif\n\n    rc = CreateNew(CE, winName);\n    if (rc < 0) return (1);\n\n    // Make the Window display itself:\n    vizwin.show();\n\n#ifdef VAPOR3_0_0_ALPHA\n    if (useSession) {\n    #ifdef VAPOR3_0_0_ALPHA\n        int rc = CE->ActivateEnabledRenderers(0);\n        if (rc) exit(rc);\n    #endif\n    } else {\n        // Enable the barbs for rendering\n        rParams->SetEnabled(true);\n        // Activate the barbs renderer\n        CE->ActivateRender(winName, HelloParams::m_classTag, \"hello1\", true);\n    }\n#endif\n\n#ifdef VAPOR3_0_0_ALPHA\n    // Set up animation and capture\n    // If there is a session file, use its timestep initially, otherwise get\n    // the first time step from the command argument.\n\n    #ifdef VAPOR3_0_0_ALPHA\n    AnimationParams *animParams = CE->GetParamsMgr()->GetAnimationParams(0);\n    if (!useSession) animParams->setCurrentTimestep(opt.ts0);\n    int frameStep = animParams->getFrameStepSize();\n    // Loop through the specified number of time steps\n    for (int j = 0; j < opt.nts; j++) {\n        // Prepare for capture if enabled:\n        if (animParams->GetCaptureEnabled()) {\n            string capturePath = animParams->GetCaptureFilepath();\n            if (capturePath != \"\") CE->EnableCapture(capturePath, 0);\n        }\n\n        // Display the scene\n        printf(\"Rendering timestep %d of %d\\n\", j + 1, opt.nts);\n        vizwin.updateGL();\n\n        // Advance the frame, if more to animate\n        if (j + 1 >= opt.nts) break;\n        int currentTS = animParams->getCurrentTimestep();\n        currentTS += frameStep;\n        if (currentTS >= animParams->getMinTimestep() && currentTS <= animParams->getMaxTimestep())\n            animParams->setCurrentTimestep(currentTS);\n        else\n            break;\n    }\n\n    #endif\n    printf(\"Animation sequence complete\\n\");\n#endif\n    int estatus = a.exec();\n\n    if (!opt.quiet) { fprintf(stdout, \"total process time : %f\\n\", timer); }\n\n    ParamsMgr *pm = CE->GetParamsMgr();\n    pm->SaveToFile(\"file.xml\");\n\n    delete CE;\n\n    exit(estatus);\n}\n"
  },
  {
    "path": "test_apps/controlExec/test_vizwin.cpp",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2016\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\tFile:\t\ttest_vizwin.cpp\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tOctober 2013\n//\n//\tDescription:\tImplements the VizWin class\n//\t\tThis is the QGLWidget that performs OpenGL rendering (using associated Visualizer)\n//\t\tPlus supports mouse event reporting\n//\n#include <vapor/glutil.h>    // Must be included first!!!\n#include \"vapor/VAssert.h\"\n#include <QResizeEvent>\n#include <QFocusEvent>\n#include <QMouseEvent>\n#include <QCloseEvent>\n\n#include \"vapor/ControlExecutive.h\"\n#include \"test_vizwin.h\"\n\nusing namespace VAPoR;\n\n/*\n *  Constructs a VizWindow as a child of 'parent', with the\n *  name 'name' and widget flags set to 'f'.\n *\n */\nTest_VizWin::Test_VizWin(QWidget *parent, ControlExec *ce, string winName) : QGLWidget(parent)\n{\n    _windowName = winName;\n    _controlExec = ce;\n    m_initialized = false;\n    setAutoBufferSwap(false);\n\n    return;\n}\n\n// React to a user-change in window size/position (or possibly max/min)\n// Either the window is minimized, maximized, restored, or just resized.\nvoid Test_VizWin::resizeGL(int width, int height)\n{\n    int rc1 = CheckGLErrorMsg(\"GLVizWindowResizeEvent\");\n\n    int rc2 = _controlExec->ResizeViz(_windowName, width, height);\n    if (!rc1 && !rc2) reallyUpdate();\n    return;\n}\nvoid Test_VizWin::initializeGL()\n{\n    int rc1 = CheckGLErrorMsg(\"GLVizWindowInitializeEvent\");\n    makeCurrent();\n    int rc2 = _controlExec->InitializeViz(_windowName);\n    int rc3 = CheckGLErrorMsg(\"GLVizWindowInitializeEvent\");\n\n    if (!(rc2 < 0)) { m_initialized = true; }\n}\n\nvoid Test_VizWin::paintGL()\n{\n    if (!m_initialized) return;\n\n    // only paint if necessary\n    // Note that makeCurrent is needed when here we have multiple windows.\n    int rc0 = CheckGLErrorMsg(\"VizWindowPaintGL\");\n    int rc1 = 0, rc2 = 0;\n    if (!rc0) {\n        makeCurrent();\n\n        rc1 = _controlExec->Paint(_windowName, false);\n        if (!rc1) swapBuffers();\n        rc2 = CheckGLErrorMsg(\"VizWindowPaintGL\");\n    }\n\n    return;\n}\nvoid Test_VizWin::reallyUpdate()\n{\n    makeCurrent();\n    int rc = _controlExec->Paint(_windowName, true);\n\n    swapBuffers();\n    return;\n}\nvoid Test_VizWin::closeEvent(QCloseEvent *e) { QGLWidget::closeEvent(e); }\n"
  },
  {
    "path": "test_apps/controlExec/test_vizwin.h",
    "content": "//************************************************************************\n//\t\t\t\t\t\t\t\t\t*\n//\t\t     Copyright (C)  2013\t\t\t\t*\n//     University Corporation for Atmospheric Research\t\t\t*\n//\t\t     All Rights Reserved\t\t\t\t*\n//\t\t\t\t\t\t\t\t\t*\n//************************************************************************/\n//\n//\tFile:\t\ttest_vizwin.h\n//\n//\tAuthor:\t\tAlan Norton\n//\t\t\tNational Center for Atmospheric Research\n//\t\t\tPO 3000, Boulder, Colorado\n//\n//\tDate:\t\tJanuary 2016\n//\n//\n\n#ifndef TEST_VIZWIN_H\n#define TEST_VIZWIN_H\n\n#include <vapor/glutil.h>\n#include <QGLWidget>\n#include <QWheelEvent>\n\nclass QCloseEvent;\nclass QRect;\nclass QMouseEvent;\nclass QFocusEvent;\n\nnamespace VAPoR {\nclass Viewpoint;\nclass ControlExec;\n//! \\class Test_VizWin\n//! \\ingroup Public_GUI\n//! \\brief A QGLWidget that supports display based on GL methods invoked in a Visualizer\n//! \\author Alan Norton\n//! \\version 3.0\n//! \\date October 2013\n//!\n//!\tThe VizWin class is a QGLWidget that supports the rendering by the VAPOR Visualizer class.\n//! The standard rendering methods (resize, initialize, paint) are passed to the Visualizer.\n//! In addition this is the class that responds to mouse events, resulting in scene navigation\n//! or manipulator changes.\n//!\nclass Test_VizWin : public QGLWidget {\n    Q_OBJECT\n\npublic:\n    //! Force the window to update, even if nothing has changed.\n    void reallyUpdate();\n\n    Test_VizWin(QWidget *parent, ControlExec *, std::string winName);\n\n    virtual ~Test_VizWin() {}\n#ifndef DOXYGEN_SKIP_THIS\n\nprivate:\n    bool          m_initialized;\n    void          closeEvent(QCloseEvent *event);\n    virtual QSize minimumSizeHint() const { return QSize(400, 400); }\n\n    virtual void resizeGL(int width, int height);\n    virtual void initializeGL();\n    void         paintGL();\n\n    std::string  _windowName;\n    ControlExec *_controlExec;\n\n#endif    // DOXYGEN_SKIP_THIS\n};\n};    // namespace VAPoR\n\n#endif    // TEST_VIZWIN_H\n"
  },
  {
    "path": "test_apps/datamgr/CMakeLists.txt",
    "content": "add_executable (test_datamgr test_datamgr.cpp)\nset_target_properties(test_datamgr PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${debug_output_dir}\")\n\ntarget_link_libraries (test_datamgr common vdc wasp)\n"
  },
  {
    "path": "test_apps/datamgr/test_datamgr.cpp",
    "content": "#include <iostream>\n#include <iomanip>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/DataMgr.h>\n#include <vapor/FileUtils.h>\n#include <vapor/utils.h>\n#include <vapor/OpenMPSupport.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    int                     nts;\n    int                     ts0;\n    int                     loop;\n    int                     memsize;\n    int                     level;\n    int                     lod;\n    int                     nthreads;\n    string                  varname;\n    string                  savefilebase;\n    string                  ftype;\n    std::vector<double>     minu;\n    std::vector<double>     maxu;\n    OptionParser::Boolean_T dump;\n    OptionParser::Boolean_T tgetvalue;\n    OptionParser::Boolean_T nogeoxform;\n    OptionParser::Boolean_T novertxform;\n    OptionParser::Boolean_T verbose;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T debug;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"nts\", 1, \"1\", \"Number of timesteps to process\"},\n                                         {\"ts0\", 1, \"0\", \"First time step to process\"},\n                                         {\"loop\", 1, \"1\", \"Number of loops to execute\"},\n                                         {\"memsize\", 1, \"2000\", \"Cache size in MBs\"},\n                                         {\"level\", 1, \"0\", \"Multiresution refinement level. Zero implies coarsest resolution\"},\n                                         {\"lod\", 1, \"0\", \"Level of detail. Zero implies coarsest resolution\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"varname\", 1, \"\", \"Name of variable\"},\n                                         {\"savefilebase\", 1, \"\", \"Base path name to output file\"},\n                                         {\"ftype\", 1, \"vdc\", \"data set type (vdc|wrf|cf|mpas)\"},\n                                         {\"minu\", 1, \"\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"specifying domain min extents in user coordinates (X0:Y0:Z0)\"},\n                                         {\"maxu\", 1, \"\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"specifying domain max extents in user coordinates (X1:Y1:Z1)\"},\n                                         {\"verbose\", 0, \"\", \"Verobse output\"},\n                                         {\"tgetvalue\", 0, \"\", \"Apply Grid:;GetValue test\"},\n                                         {\"dump\", 0, \"\", \"Dump variable coordinates and data\"},\n                                         {\"nogeoxform\", 0, \"\", \"Do not apply geographic transform (projection to PCS\"},\n                                         {\"novertxform\", 0, \"\", \"Do not apply to convert pressure, etc. to meters\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {\"quiet\", 0, \"\", \"Operate quitely\"},\n                                         {\"debug\", 0, \"\", \"Debug mode\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"nts\", Wasp::CvtToInt, &opt.nts, sizeof(opt.nts)},\n                                        {\"ts0\", Wasp::CvtToInt, &opt.ts0, sizeof(opt.ts0)},\n                                        {\"loop\", Wasp::CvtToInt, &opt.loop, sizeof(opt.loop)},\n                                        {\"memsize\", Wasp::CvtToInt, &opt.memsize, sizeof(opt.memsize)},\n                                        {\"level\", Wasp::CvtToInt, &opt.level, sizeof(opt.level)},\n                                        {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"varname\", Wasp::CvtToCPPStr, &opt.varname, sizeof(opt.varname)},\n                                        {\"savefilebase\", Wasp::CvtToCPPStr, &opt.savefilebase, sizeof(opt.savefilebase)},\n                                        {\"ftype\", Wasp::CvtToCPPStr, &opt.ftype, sizeof(opt.ftype)},\n                                        {\"minu\", Wasp::CvtToDoubleVec, &opt.minu, sizeof(opt.minu)},\n                                        {\"maxu\", Wasp::CvtToDoubleVec, &opt.maxu, sizeof(opt.maxu)},\n                                        {\"verbose\", Wasp::CvtToBoolean, &opt.verbose, sizeof(opt.verbose)},\n                                        {\"dump\", Wasp::CvtToBoolean, &opt.dump, sizeof(opt.dump)},\n                                        {\"tgetvalue\", Wasp::CvtToBoolean, &opt.tgetvalue, sizeof(opt.tgetvalue)},\n                                        {\"nogeoxform\", Wasp::CvtToBoolean, &opt.nogeoxform, sizeof(opt.nogeoxform)},\n                                        {\"novertxform\", Wasp::CvtToBoolean, &opt.novertxform, sizeof(opt.novertxform)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {NULL}};\n\nconst char *ProgName;\n\nvoid ErrMsgCBHandler(const char *msg, int) { cerr << ProgName << \" : \" << msg << endl; }\n\n// Handle command line -nthreads argument so that pthreads and OpenMP threads\n// are treated consistently.\n//\nint get_num_ompthreads()\n{\n    int nthreads = 0;\n#pragma omp parallel\n    {\n        // use all available threads\n        //\n        if (opt.nthreads < 1) {\n            nthreads = omp_get_num_threads();\n        } else {\n            nthreads = opt.nthreads;\n        }\n    }\n    return (nthreads);\n}\n\nvoid print_info(DataMgr &datamgr, bool verbose)\n{\n    vector<string> dimnames;\n    dimnames = datamgr.GetDimensionNames();\n    cout << \"Dimensions:\" << endl;\n    for (int i = 0; i < dimnames.size(); i++) {\n        DC::Dimension dimension;\n        datamgr.GetDimension(dimnames[i], dimension, -1);\n        cout << \"\\t\" << dimension.GetName() << \" = \" << dimension.GetLength() << endl;\n    }\n\n    vector<string> meshnames;\n    cout << \"Meshes:\" << endl;\n    meshnames = datamgr.GetMeshNames();\n    for (int i = 0; i < meshnames.size(); i++) {\n        cout << \"\\t\" << meshnames[i] << endl;\n        if (verbose) {\n            DC::Mesh mesh;\n            datamgr.GetMesh(meshnames[i], mesh);\n            cout << mesh;\n        }\n    }\n\n    vector<string> vars;\n\n    for (int d = 1; d < 4; d++) {\n        cout << d << \"D variables: \";\n        vars = datamgr.GetDataVarNames(d);\n        for (int i = 0; i < vars.size(); i++) {\n            cout << vars[i] << endl;\n\n            if (verbose) {\n                DC::DataVar datavar;\n                datamgr.GetDataVarInfo(vars[i], datavar);\n                cout << datavar;\n            }\n        }\n        cout << endl;\n    }\n    cout << endl << endl;\n}\n\nvoid test_node_iterator(const Grid *g, VAPoR::CoordType minu, VAPoR::CoordType maxu)\n{\n    cout << \"Node Iterator Test ----->\" << endl;\n\n    Grid::ConstNodeIterator itr;\n    Grid::ConstNodeIterator enditr = g->ConstNodeEnd();\n\n    float t0 = GetTime();\n\n    itr = g->ConstNodeBegin(minu, maxu);\n\n    size_t count = 0;\n    for (; itr != enditr; ++itr) { count++; }\n    cout << \"count: \" << count << endl;\n    cout << \"time: \" << GetTime() - t0 << endl;\n    cout << endl;\n}\n\nvoid test_get_value(Grid *g)\n{\n    cout << \"Get Value Test ----->\" << endl;\n\n    g->SetInterpolationOrder(1);\n\n    float t0 = GetTime();\n\n    auto   tmp = g->GetDimensions();\n    auto   tmp2 = std::vector<size_t>{tmp[0], tmp[1], tmp[2]};\n    size_t n = VProduct(tmp2);\n\n    size_t count = 0;\n    size_t ecount = 0;\n#if defined(_OPENMP)\n    int requested_num_threads = get_num_ompthreads();\n#endif\n#pragma omp parallel num_threads(requested_num_threads)\n    {\n        size_t my_ecount = 0;\n        size_t my_count = 0;\n        int    id = omp_get_thread_num();\n        int    nthreads = omp_get_num_threads();\n        size_t istart = id * n / nthreads;\n        size_t iend = (id + 1) * n / nthreads;\n        if (id == nthreads - 1) iend = n;\n\n        Grid::ConstIterator itr = g->cbegin() + istart;\n        Grid::ConstCoordItr c_itr = g->ConstCoordBegin() + istart;\n\n        for (size_t i = istart; i < iend; i++, ++itr, ++c_itr) {\n            float v0 = *itr;\n\n            float v1 = g->GetValue(*c_itr);\n\n\n            if (!Wasp::NearlyEqual(v0, v1)) { my_ecount++; }\n            my_count++;\n        }\n#pragma omp critical\n        {\n            count += my_count;\n            ecount += my_ecount;\n        }\n    }\n\n    cout << \"error count: \" << ecount << \" out of \" << count << endl;\n    cout << \"time: \" << GetTime() - t0 << endl;\n    cout << endl;\n}\n\nvoid dump(const Grid *g)\n{\n    auto tmp = g->GetDimensions();\n    auto dims = std::vector<size_t>{tmp[0], tmp[1], tmp[2]};\n    dims.resize(g->GetNumDimensions());\n    vector<size_t> min(dims.size(), 0);\n    vector<size_t> max;\n    for (int i = 0; i < dims.size(); i++) { max.push_back(dims[i] - 1); }\n\n    vector<size_t> index = min;\n    vector<double> coord;\n\n    while (index != max) {\n        g->GetUserCoordinates(index, coord);\n        float v = g->GetValueAtIndex(index);\n\n        for (int i = 0; i < dims.size(); i++) { cout << coord[i] << \" \"; }\n        cout << v << endl;\n\n        if (index[0] == max[0]) { cout << endl; }\n\n        index = IncrementCoords(min, max, index);\n    }\n}\n\nvoid process(FILE *fp, DataMgr &datamgr, string vname, int loop, int ts)\n{\n    vector<double> timecoords;\n    datamgr.GetTimeCoordinates(timecoords);\n\n    if (!opt.savefilebase.empty()) {\n        char   buf[4 + 1];\n        string path(opt.savefilebase);\n        path.append(\".\");\n        sprintf(buf, \"%4.4d\", loop);\n        path.append(buf);\n        path.append(\".\");\n        sprintf(buf, \"%4.4d\", ts);\n        path.append(buf);\n\n        fp = fopen(path.c_str(), \"w\");\n        if (!fp) { cerr << \"Can't open output file \" << path << endl; }\n    }\n    if (!datamgr.VariableExists(ts, vname, opt.level, opt.lod)) {\n        cerr << \"Variable \" << vname << \" does not exist\" << endl;\n        return;\n    }\n\n    VAPoR::CoordType minu = {0.0, 0.0, 0.0};\n    VAPoR::CoordType maxu = {0.0, 0.0, 0.0};\n    if (opt.minu.size()) {\n        VAssert(opt.minu.size() == opt.maxu.size());\n        Grid::CopyToArr3(opt.minu, minu);\n        Grid::CopyToArr3(opt.maxu, maxu);\n    } else {\n        int rc = datamgr.GetVariableExtents(ts, vname, opt.level, opt.lod, minu, maxu);\n        if (rc < 0) exit(1);\n    }\n\n    Grid *g;\n    g = datamgr.GetVariable(ts, vname, opt.level, opt.lod, minu, maxu, false);\n\n    if (!g) { exit(1); }\n\n    if (opt.dump) { dump(g); }\n\n    if (fp) {\n        Grid::Iterator itr;\n        Grid::Iterator enditr = g->end();\n        float          v;\n        for (itr = g->begin(); itr != enditr;) {\n            v = *itr;\n            fwrite(&v, sizeof(v), 1, fp);\n            itr += 8;\n        }\n        fclose(fp);\n    }\n\n    g->GetUserExtents(minu, maxu);\n    test_node_iterator(g, minu, maxu);\n\n    if (opt.tgetvalue) { test_get_value(g); }\n\n    vector<double> rvec;\n    datamgr.GetDataRange(ts, vname, opt.level, opt.lod, rvec);\n    cout << \"Data Range: [\" << rvec[0] << \", \" << rvec[1] << \"]\" << endl;\n\n    cout << \"Cell face has CCW winding order : \" << g->HasInvertedCoordinateSystemHandiness() << endl;\n\n    auto tmp = g->GetDimensions();\n    auto dims = std::vector<size_t>{tmp[0], tmp[1], tmp[2]};\n    dims.resize(g->GetNumDimensions());\n    cout << \"Grid dimensions: [ \";\n    for (int i = 0; i < dims.size(); i++) { cout << dims[i] << \" \"; }\n    cout << \"]\" << endl;\n\n    g->GetUserExtents(minu, maxu);\n    cout << \"Min user extents: [\";\n    for (int i = 0; i < minu.size(); i++) cout << minu[i] << \" \";\n    cout << \"]\" << endl;\n\n    cout << \"Max user extents: [\";\n    for (int i = 0; i < maxu.size(); i++) cout << maxu[i] << \" \";\n    cout << \"]\" << endl;\n\n    cout << \"Has missing data : \" << g->HasMissingData() << endl;\n    if (g->HasMissingData()) {\n        cout << \"Missing data value : \" << g->GetMissingValue() << endl;\n        Grid::Iterator itr;\n        Grid::Iterator enditr = g->end();\n        float          mv = g->GetMissingValue();\n        int            count = 0;\n        for (itr = g->begin(); itr != enditr; ++itr) {\n            if (*itr == mv) count++;\n        }\n        cout << \"Num missing values : \" << count << endl;\n    }\n    cout << \"Grid type: \" << g->GetType() << endl;\n\n    cout << setprecision(16) << \"User time: \" << timecoords[ts] << endl;\n    cout << endl;\n    delete g;\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    double       timer = 0.0;\n    string       s;\n\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.minu.size() && opt.minu.size() != opt.maxu.size()) {\n        cerr << \"Usage: \" << ProgName << \" master.nc\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] metafiles \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); }\n\n    if (argc < 2) {\n        cerr << \"Usage: \" << ProgName << \" [options] vdcmaster \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    vector<string> files;\n    for (int i = 1; i < argc; i++) { files.push_back(argv[i]); }\n\n    vector<string> options;\n    if (!opt.nogeoxform) { options.push_back(\"-project_to_pcs\"); }\n    if (!opt.novertxform) { options.push_back(\"-vertical_xform\"); }\n    DataMgr datamgr(opt.ftype, opt.memsize, opt.nthreads);\n    int     rc = datamgr.Initialize(files, options);\n    if (rc < 0) exit(1);\n\n    print_info(datamgr, opt.verbose);\n\n    string vname = opt.varname;\n    if (vname.empty()) { return (0); }\n\n    FILE *fp = NULL;\n\n    cout << \"Variable name : \" << vname << endl;\n\n    int nts = datamgr.GetNumTimeSteps(vname);\n\n    for (int l = 0; l < opt.loop; l++) {\n        cout << \"Processing loop \" << l << endl;\n\n        for (int ts = opt.ts0; ts < opt.ts0 + opt.nts && ts < nts; ts++) {\n            cout << \"Processing time step \" << ts << endl;\n\n            process(fp, datamgr, vname, l, ts);\n        }\n    }\n\n    if (!opt.quiet) { fprintf(stdout, \"total process time : %f\\n\", timer); }\n\n    exit(0);\n}\n"
  },
  {
    "path": "test_apps/grid_iter/CMakeLists.txt",
    "content": "add_executable (test_grid_iter test_grid_iter.cpp)\nset_target_properties(test_grid_iter PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${debug_output_dir}\")\n\ntarget_link_libraries (test_grid_iter common vdc wasp)\n"
  },
  {
    "path": "test_apps/grid_iter/test_grid_iter.cpp",
    "content": "#include <iostream>\n#include <iomanip>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/RegularGrid.h>\n#include <vapor/LayeredGrid.h>\n#include <vapor/CurvilinearGrid.h>\n#include <vapor/StretchedGrid.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    std::vector<size_t>     bs;\n    std::vector<double>     minu;\n    std::vector<double>     maxu;\n    std::vector<double>     roimin;\n    std::vector<double>     roimax;\n    std::vector<size_t>     dims;\n    std::vector<size_t>     periodic;\n    string                  type;\n    OptionParser::Boolean_T debug;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"bs\", 1, \"64:64:64\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"specifying block size\"},\n                                         {\"minu\", 1, \"0:0:0\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"specifying minimum user coordinates\"},\n                                         {\"maxu\", 1, \"1.0:1.0:1.0\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"specifying maximum user coordinates\"},\n                                         {\"roimin\", 1, \"0.0:0.0:0.0\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"specifying min bbox coordinates for a region of interest\"},\n                                         {\"roimax\", 1, \"1.0:1.0:1.0\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"specifying max bbox coordinates for a region of interest\"},\n                                         {\"dims\", 1, \"512:512:128\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"specifying grid dimensions\"},\n                                         {\"periodic\", 1, \"0:0:0\",\n                                          \"Colon delimited 3-element vector \"\n                                          \"of booleans specifying boundary periodicity\"},\n                                         {\"type\", 1, \"regular\",\n                                          \"Grid type. One of (regular, \"\n                                          \"layered, curvlinear, stretched\"},\n                                         {\"debug\", 0, \"\", \"Print diagnostics\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"bs\", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)},\n                                        {\"minu\", Wasp::CvtToDoubleVec, &opt.minu, sizeof(opt.minu)},\n                                        {\"maxu\", Wasp::CvtToDoubleVec, &opt.maxu, sizeof(opt.maxu)},\n                                        {\"roimin\", Wasp::CvtToDoubleVec, &opt.roimin, sizeof(opt.roimin)},\n                                        {\"roimax\", Wasp::CvtToDoubleVec, &opt.roimax, sizeof(opt.roimax)},\n                                        {\"dims\", Wasp::CvtToSize_tVec, &opt.dims, sizeof(opt.dims)},\n                                        {\"periodic\", Wasp::CvtToSize_tVec, &opt.periodic, sizeof(opt.periodic)},\n                                        {\"type\", Wasp::CvtToCPPStr, &opt.type, sizeof(opt.type)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {NULL}};\n\nnamespace {\nvector<float *> Heap;\n};\n\ntemplate<class T> void out_container(T first, T last)\n{\n    for (T itr = first; itr != last; ++itr) { cout << *itr << \" \"; }\n    cout << endl;\n}\n\nconst char *ProgName;\n\nvector<float *> alloc_blocks(const vector<size_t> &bs, const vector<size_t> &dims)\n{\n    size_t block_size = 1;\n    size_t nblocks = 1;\n\n    for (int i = 0; i < bs.size(); i++) {\n        block_size *= bs[i];\n\n        VAssert(dims[i] > 0);\n        size_t nb = ((dims[i] - 1) / bs[i]) + 1;\n\n        nblocks *= nb;\n    }\n\n    float *buf = new float[nblocks * block_size];\n    Heap.push_back(buf);\n\n    vector<float *> blks;\n    for (int i = 0; i < nblocks; i++) { blks.push_back(buf + i * block_size); }\n\n    return (blks);\n}\n\nVAPoR::RegularGrid *make_regular_grid()\n{\n    VAssert(opt.bs.size() == opt.minu.size());\n    VAssert(opt.bs.size() == opt.maxu.size());\n    VAssert(opt.bs.size() == opt.dims.size());\n    VAssert(opt.bs.size() == opt.periodic.size());\n\n    vector<float *> blks = alloc_blocks(opt.bs, opt.dims);\n\n    RegularGrid *rg = new RegularGrid(opt.dims, opt.bs, blks, opt.minu, opt.maxu);\n\n    return (rg);\n}\n\nVAPoR::StretchedGrid *make_stretched_grid()\n{\n    VAssert(opt.bs.size() == opt.minu.size());\n    VAssert(opt.bs.size() == opt.maxu.size());\n    VAssert(opt.bs.size() == opt.dims.size());\n    VAssert(opt.bs.size() == opt.periodic.size());\n\n    vector<float *> blks = alloc_blocks(opt.bs, opt.dims);\n\n    vector<double>           xcoords, ycoords, zcoords;\n    vector<vector<double> *> coords = {&xcoords, &ycoords, &zcoords};\n    double                   delta;\n\n    for (int i = 0; i < opt.minu.size(); i++) {\n        delta = opt.dims[i] == 1 ? 0.0 : (opt.maxu[i] - opt.minu[i]) / (opt.dims[i] - 1);\n        for (int j = 0; i < opt.dims[j]; j++) { coords[i]->push_back(opt.minu[j] + j * delta); }\n    }\n\n    StretchedGrid *rg = new StretchedGrid(opt.dims, opt.bs, blks, xcoords, ycoords, zcoords);\n\n    return (rg);\n}\n\nVAPoR::LayeredGrid *make_layered_grid()\n{\n    VAssert(opt.bs.size() == 3);\n    VAssert(opt.bs.size() == opt.minu.size());\n    VAssert(opt.bs.size() == opt.maxu.size());\n    VAssert(opt.bs.size() == opt.dims.size());\n    VAssert(opt.bs.size() == opt.periodic.size());\n\n    vector<float *> zblks = alloc_blocks(opt.bs, opt.dims);\n\n    RegularGrid *rg = new RegularGrid(opt.dims, opt.bs, zblks, vector<double>(3, 0.0), vector<double>(3, 1.0));\n\n    for (size_t k = 0; k < rg->GetDimensions()[2]; k++) {\n        for (size_t j = 0; j < rg->GetDimensions()[1]; j++) {\n            for (size_t i = 0; i < rg->GetDimensions()[0]; i++) {\n                double z = (opt.maxu[2] - opt.minu[2]) / (opt.dims[2] - 1) * k + opt.minu[2];\n                rg->SetValueIJK(i, j, k, (float)z);\n            }\n        }\n    }\n\n    vector<float *> blks = alloc_blocks(opt.bs, opt.dims);\n\n    double         deltax = opt.maxu[0] - opt.minu[0] / (opt.dims[0] - 1);\n    vector<double> xcoords;\n    for (int i = 0; i < opt.dims[0]; i++) { xcoords.push_back(opt.minu[0] + (i * deltax)); }\n\n    double         deltay = opt.maxu[1] - opt.minu[1] / (opt.dims[1] - 1);\n    vector<double> ycoords;\n    for (int i = 0; i < opt.dims[1]; i++) { ycoords.push_back(opt.minu[1] + (i * deltay)); }\n\n    LayeredGrid *lg = new LayeredGrid(opt.dims, opt.bs, blks, xcoords, ycoords, *rg);\n\n    return (lg);\n}\n\nVAPoR::CurvilinearGrid *make_curvilinear_grid()\n{\n    VAssert(opt.bs.size() == 3);\n    VAssert(opt.bs.size() == opt.minu.size());\n    VAssert(opt.bs.size() == opt.maxu.size());\n    VAssert(opt.bs.size() == opt.dims.size());\n    VAssert(opt.bs.size() == opt.periodic.size());\n\n    vector<size_t> bs2d = {opt.bs[0], opt.bs[1]};\n    vector<size_t> dims2d = {opt.dims[0], opt.dims[1]};\n\n    vector<float *> xblks = alloc_blocks(bs2d, dims2d);\n\n    RegularGrid *xrg = new RegularGrid(dims2d, bs2d, xblks, vector<double>(2, 0.0), vector<double>(2, 1.0));\n\n    vector<float *> yblks = alloc_blocks(bs2d, dims2d);\n\n    RegularGrid *yrg = new RegularGrid(dims2d, bs2d, yblks, vector<double>(2, 0.0), vector<double>(2, 1.0));\n\n    for (size_t j = 0; j < dims2d[1]; j++) {\n        for (size_t i = 0; i < dims2d[0]; i++) {\n            double x = (opt.maxu[0] - opt.minu[0]) / (dims2d[0] - 1) * i + opt.minu[0];\n            double y = (opt.maxu[1] - opt.minu[1]) / (dims2d[1] - 1) * j + opt.minu[1];\n            xrg->SetValueIJK(i, j, 0, x);\n            yrg->SetValueIJK(i, j, 0, y);\n        }\n    }\n\n    vector<double> zcoords;\n    for (int k = 0; k < opt.dims[2]; k++) {\n        double z = (opt.maxu[2] - opt.minu[2]) / (opt.dims[2] - 1) * k + opt.minu[2];\n        zcoords.push_back(z);\n    }\n\n    vector<float *> blks = alloc_blocks(opt.bs, opt.dims);\n\n    vector<double>   minu2d = {opt.minu[0], opt.minu[1]};\n    vector<double>   maxu2d = {opt.maxu[0], opt.maxu[1]};\n    CurvilinearGrid *cg = new CurvilinearGrid(opt.dims, opt.bs, blks, *xrg, *yrg, zcoords, NULL);\n\n    return (cg);\n}\n\nVAPoR::CurvilinearGrid *make_curvilinear_terrain_grid()\n{\n    VAssert(opt.bs.size() == 3);\n    VAssert(opt.bs.size() == opt.minu.size());\n    VAssert(opt.bs.size() == opt.maxu.size());\n    VAssert(opt.bs.size() == opt.dims.size());\n    VAssert(opt.bs.size() == opt.periodic.size());\n\n    vector<size_t> bs2d = {opt.bs[0], opt.bs[1]};\n    vector<size_t> dims2d = {opt.dims[0], opt.dims[1]};\n    vector<size_t> bs = {opt.bs[0], opt.bs[1], opt.bs[2]};\n    vector<size_t> dims = {opt.dims[0], opt.dims[1], opt.dims[2]};\n\n    vector<float *> xblks = alloc_blocks(bs2d, dims2d);\n\n    RegularGrid *xrg = new RegularGrid(dims2d, bs2d, xblks, vector<double>(2, 0.0), vector<double>(2, 1.0));\n\n    vector<float *> yblks = alloc_blocks(bs2d, dims2d);\n\n    RegularGrid *yrg = new RegularGrid(dims2d, bs2d, yblks, vector<double>(2, 0.0), vector<double>(2, 1.0));\n\n    for (size_t j = 0; j < dims2d[1]; j++) {\n        for (size_t i = 0; i < dims2d[0]; i++) {\n            double x = (opt.maxu[0] - opt.minu[0]) / (dims2d[0] - 1) * i + opt.minu[0];\n            double y = (opt.maxu[1] - opt.minu[1]) / (dims2d[1] - 1) * j + opt.minu[1];\n            xrg->SetValueIJK(i, j, 0, x);\n            yrg->SetValueIJK(i, j, 0, y);\n        }\n    }\n\n    vector<float *> zblks = alloc_blocks(bs, dims);\n\n    RegularGrid *zrg = new RegularGrid(dims, bs, zblks, vector<double>(3, 0.0), vector<double>(3, 1.0));\n\n    for (size_t k = 0; k < dims[2]; k++) {\n        double z = (opt.maxu[2] - opt.minu[2]) / (dims[2] - 1) * k + opt.minu[2];\n\n        for (size_t j = 0; j < dims[1]; j++) {\n            for (size_t i = 0; i < dims[0]; i++) { zrg->SetValueIJK(i, j, k, z); }\n        }\n    }\n\n    vector<float *> blks = alloc_blocks(opt.bs, opt.dims);\n\n    vector<double>   minu2d = {opt.minu[0], opt.minu[1]};\n    vector<double>   maxu2d = {opt.maxu[0], opt.maxu[1]};\n    CurvilinearGrid *cg = new CurvilinearGrid(opt.dims, opt.bs, blks, *xrg, *yrg, *zrg, NULL);\n\n    return (cg);\n}\n\nvoid init_grid(StructuredGrid *sg)\n{\n    // Initialize data to linear ramp\n    //\n    size_t kmax = opt.dims.size() >= 1 ? opt.dims[2] : 1;\n    size_t jmax = opt.dims.size() >= 1 ? opt.dims[1] : 1;\n    size_t imax = opt.dims.size() >= 1 ? opt.dims[0] : 1;\n\n    size_t idx = 0;\n    for (size_t k = 0; k < kmax; k++) {\n        for (size_t j = 0; j < jmax; j++) {\n            for (size_t i = 0; i < imax; i++) {\n                sg->SetValueIJK(i, j, k, (float)idx);\n                idx++;\n            }\n        }\n    }\n}\n\nvoid test_iterator(const StructuredGrid *sg)\n{\n    cout << \"Value Iterator Test ----->\" << endl;\n\n    double t0 = Wasp::GetTime();\n\n    Grid::ConstIterator itr;\n    Grid::ConstIterator enditr = sg->cend();\n    double              accum = 0.0;\n    size_t              count = 0;\n    //    for (itr = sg->cbegin(opt.roimin, opt.roimax); itr!=enditr; ++itr) {\n    for (itr = sg->cbegin(); itr != enditr; ++itr) {\n        accum += *itr;\n        count++;\n    }\n    cout << \"Iteration time : \" << Wasp::GetTime() - t0 << endl;\n    cout << \"Sum and count: \" << accum << \" \" << count << endl;\n    cout << endl;\n}\n\nvoid test_operator_pg_iterator(const StructuredGrid *sg)\n{\n    cout << \"Operator += Test ----->\" << endl;\n\n    double t0 = Wasp::GetTime();\n\n    const size_t stride = 8;\n\n    Grid::ConstIterator itr1 = sg->cbegin();\n    Grid::ConstIterator enditr1 = sg->cend();\n    double              accum1 = 0.0;\n    size_t              count1 = 0;\n    size_t              index = 0;\n    for (; itr1 != enditr1; ++itr1) {\n        if ((index % stride) == 0) {\n            accum1 += *itr1;\n            count1++;\n        }\n        index++;\n    }\n    double t1 = Wasp::GetTime();\n\n    cout << \"Iteration time (inc by 1) : \" << t1 - t0 << endl;\n    cout << \"Sum and count: \" << accum1 << \" \" << count1 << endl;\n\n    double              t2 = Wasp::GetTime();\n    Grid::ConstIterator itr2 = sg->cbegin();\n    Grid::ConstIterator enditr2 = sg->cend();\n    double              accum2 = 0.0;\n    size_t              count2 = 0;\n    for (; itr2 != enditr2;) {\n        accum2 += *itr2;\n        count2++;\n        itr2 += stride;\n    }\n    double t3 = Wasp::GetTime();\n\n    cout << \"Iteration time (+=) : \" << t3 - t2 << endl;\n    cout << \"Sum and count: \" << accum2 << \" \" << count2 << endl;\n\n    itr1 = sg->cbegin();\n    enditr1 = sg->cend();\n    itr2 = sg->cbegin();\n    enditr2 = sg->cend();\n    index = 0;\n    bool mismatch = false;\n    for (; itr1 != enditr1 && itr2 != enditr2; ++itr1) {\n        if ((index % stride) == 0) {\n            if (*itr1 != *itr2) {\n                mismatch = true;\n                break;\n            }\n            itr2 += stride;\n        }\n        index++;\n    }\n    if (!mismatch) {\n        cout << \"operator+= operator++ match\" << endl;\n    } else {\n        cout << \"FAIL : operator+= operator++ mismatch\" << endl;\n    }\n    cout << endl;\n}\n\n#ifdef VAPOR3_0_0_ALPHA\nvoid test_cell_iterator(const StructuredGrid *sg)\n{\n    cout << \"Cell Iterator Test ----->\" << endl;\n    double t0 = Wasp::GetTime();\n\n    StructuredGrid::ConstCellIterator itr;\n    size_t                            count = 0;\n    for (itr = sg->ConstCellBegin(); itr != sg->ConstCellEnd(); ++itr) {\n        count++;\n        cout << \"Cell : \";\n        out_container((*itr).cbegin(), (*itr).cend());\n        vector<vector<size_t>> nodes;\n        sg->GetCellNodes(*itr, nodes);\n        cout << \"\\tNodes : \" << endl;\n        for (int i = 0; i < nodes.size(); i++) {\n            cout << \"\\t\";\n            out_container(nodes[i].cbegin(), nodes[i].cend());\n        }\n        cout << endl;\n\n        //\t\tconst vector <double> &coord = *(itr.GetCoordItr());\n        //\t\tcout << coord[0] << \" \" << coord[1] << \" \" << coord[2] << endl;\n    }\n    cout << \"Iteration time : \" << Wasp::GetTime() - t0 << endl;\n    cout << \"Cell count : \" << count << endl;\n    cout << endl;\n}\n#endif\n\nvoid test_node_iterator(const StructuredGrid *sg)\n{\n    cout << \"Node Iterator Test ----->\" << endl;\n\n    double t0 = Wasp::GetTime();\n\n    Grid::ConstNodeIterator itr;\n    Grid::ConstNodeIterator enditr = sg->ConstNodeEnd();\n\n    if (opt.roimin == opt.minu && opt.roimax == opt.maxu) {\n        itr = sg->ConstNodeBegin();\n    } else {\n        CoordType roimin = {0.0, 0.0, 0.0};\n        CoordType roimax = {0.0, 0.0, 0.0};\n        Grid::CopyToArr3(opt.roimin, roimin);\n        Grid::CopyToArr3(opt.roimax, roimax);\n        itr = sg->ConstNodeBegin(roimin, roimax);\n    }\n    size_t count = 0;\n    //    for ( ; itr!=sg->ConstNodeEnd(); ++itr)\n    for (; itr != enditr; ++itr) {\n        count++;\n        //\t\tout_container((*itr).cbegin(), (*itr).cend());\n        //\t\tcout << endl;\n    }\n    cout << \"Iteration time : \" << Wasp::GetTime() - t0 << endl;\n    cout << \"count: \" << count << endl;\n    cout << endl;\n}\n\nvoid test_cell_iterator(const StructuredGrid *sg)\n{\n    cout << \"Cell Iterator Test ----->\" << endl;\n\n    double t0 = Wasp::GetTime();\n\n    Grid::ConstCellIterator itr;\n    Grid::ConstCellIterator enditr = sg->ConstCellEnd();\n\n    if (opt.roimin == opt.minu && opt.roimax == opt.maxu) {\n        itr = sg->ConstCellBegin();\n    } else {\n        CoordType roimin = {0.0, 0.0, 0.0};\n        CoordType roimax = {0.0, 0.0, 0.0};\n        Grid::CopyToArr3(opt.roimin, roimin);\n        Grid::CopyToArr3(opt.roimax, roimax);\n        itr = sg->ConstCellBegin(roimin, roimax);\n    }\n\n    size_t count = 0;\n    //    for (itr = sg->ConstCellBegin(); itr!=sg->ConstCellEnd(); ++itr)\n    for (; itr != enditr; ++itr) {\n        count++;\n        //\t\tout_container((*itr).cbegin(), (*itr).cend());\n        //\t\tcout << endl;\n    }\n    cout << \"Iteration time : \" << Wasp::GetTime() - t0 << endl;\n    cout << \"count: \" << count << endl;\n    cout << endl;\n}\n\nvoid test_coord_iterator(const StructuredGrid *sg)\n{\n    cout << \"Coord Iterator Test ----->\" << endl;\n\n    double t0 = Wasp::GetTime();\n\n    Grid::ConstCoordItr itr;\n    Grid::ConstCoordItr enditr = sg->ConstCoordEnd();\n    size_t              count = 0;\n    for (itr = sg->ConstCoordBegin(); itr != enditr; ++itr) { count++; }\n    cout << \"Iteration time : \" << Wasp::GetTime() - t0 << endl;\n    cout << \"count: \" << count << endl;\n    cout << endl;\n}\n\nvoid test_coord_accessor(const StructuredGrid *sg)\n{\n    cout << \"Coord Accessor Test ----->\" << endl;\n\n    double t0 = Wasp::GetTime();\n\n    size_t count = 0;\n\n    vector<size_t> index(3);\n    vector<double> coord;\n    for (size_t k = 0; k < sg->GetDimensions()[2]; k++) {\n        for (size_t j = 0; j < sg->GetDimensions()[1]; j++) {\n            for (size_t i = 0; i < sg->GetDimensions()[0]; i++) {\n                index[0] = i;\n                index[1] = j;\n                index[2] = k;\n\n                sg->GetUserCoordinates(index, coord);\n                count++;\n            }\n        }\n    }\n    cout << \"Iteration time : \" << Wasp::GetTime() - t0 << endl;\n    cout << \"count: \" << count << endl;\n    cout << endl;\n}\n\nvoid test_getvalue(StructuredGrid *sg)\n{\n    cout << \"GetValue Test ----->\" << endl;\n\n    float rangev[2];\n    sg->GetRange(rangev);\n\n    sg->SetInterpolationOrder(1);\n\n    float range = rangev[1] - rangev[0];\n    if (range == 0.0) return;\n\n    double t0 = Wasp::GetTime();\n\n    Grid::ConstIterator itr;\n    Grid::ConstIterator enditr = sg->cend();\n    Grid::ConstCoordItr coord_itr = sg->ConstCoordBegin();\n    Grid::ConstCoordItr coord_enditr = sg->ConstCoordEnd();\n    float               maxErr = 0.0;\n    for (itr = sg->cbegin(); itr != enditr; ++itr, ++coord_itr) {\n        float                 v1 = *itr;\n        const CoordType &     coord = *coord_itr;\n\n        float v2 = sg->GetValue(coord);\n\n        float err = abs(v1 - v2) / range;\n        if (err > maxErr) { maxErr = err; }\n    }\n    cout << \"Iteration time : \" << Wasp::GetTime() - t0 << endl;\n    cout << \"Lmax error : \" << maxErr << endl;\n    cout << endl;\n}\n\nvoid test_roi_iterator()\n{\n    cout << \"ROI Test ----->\" << endl;\n\n    vector<size_t>  dims = {128, 128, 128};\n    vector<size_t>  bs = {64, 64, 64};\n    vector<float *> blks = alloc_blocks(bs, dims);\n\n    vector<double> minu = {0.0, 0.0, 0.0};\n    vector<double> maxu = {(double)dims[0] - 1, (double)dims[1] - 1, (double)dims[2] - 1};\n\n    RegularGrid *rg = new RegularGrid(dims, bs, blks, minu, maxu);\n\n    vector<double> delta;\n    CoordType      roiminu = {0.0, 0.0, 0.0};\n    CoordType      roimaxu = {0.0, 0.0, 0.0};\n    for (int i = 0; i < minu.size(); i++) {\n        delta.push_back(maxu[i] - minu[i] / (dims[i] - 1));\n        roiminu[i] = minu[i] + (delta[i] / 0.5);\n        roimaxu[i] = maxu[i] - (delta[i] / 0.5);\n    }\n\n    size_t idx = 0;\n    for (size_t k = 1; k < dims[2] - 1; k++) {\n        for (size_t j = 1; j < dims[1] - 1; j++) {\n            for (size_t i = 1; i < dims[0] - 1; i++) {\n                rg->SetValueIJK(i, j, k, (float)idx);\n                idx++;\n            }\n        }\n    }\n\n    Grid::ConstIterator itr = rg->cbegin(roiminu, roimaxu);\n    Grid::ConstIterator enditr = rg->cend();\n    idx = 0;\n    size_t         v = 0;\n    vector<size_t> index;\n    bool           pass = true;\n    for (; itr != enditr; ++itr) {\n        v = (size_t)*itr;\n\n        if (idx != v) {\n            pass = false;\n            cerr << \"FAIL test_roi_iterator : \" << v << \"not equal \" << idx << endl;\n        }\n    }\n\n    if (pass) { cout << \"ROI test passed\" << endl; }\n    cout << endl;\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       s;\n\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] metafiles \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); }\n\n    double t0 = Wasp::GetTime();\n\n    StructuredGrid *sg = NULL;\n    if (opt.type == \"layered\") {\n        cout << \"Layered grid\" << endl;\n        sg = make_layered_grid();\n    } else if (opt.type == \"curvilinear\") {\n        cout << \"Curvilinear grid\" << endl;\n        sg = make_curvilinear_grid();\n    } else if (opt.type == \"curvilinear_terrain\") {\n        cout << \"Curvilinear terrain grid\" << endl;\n        sg = make_curvilinear_terrain_grid();\n    } else if (opt.type == \"stretched\") {\n        cout << \"Stretched grid\" << endl;\n        sg = make_stretched_grid();\n    } else {\n        cout << \"Regular grid\" << endl;\n        sg = make_regular_grid();\n    }\n\n    if (!sg) return (1);\n\n    init_grid(sg);\n\n    cout << \"Creation time : \" << Wasp::GetTime() - t0 << endl;\n    cout << *sg;\n    vector<double> minu, maxu;\n    sg->GetUserExtents(minu, maxu);\n    cout << \"Grid Extents: \" << endl;\n    for (int i = 0; i < minu.size(); i++) { cout << \"\\t\" << minu[i] << \" \" << maxu[i] << endl; }\n    cout << endl;\n\n    test_roi_iterator();\n\n    test_iterator(sg);\n\n    test_operator_pg_iterator(sg);\n\n    test_node_iterator(sg);\n\n    test_cell_iterator(sg);\n\n    test_coord_iterator(sg);\n\n    test_coord_accessor(sg);\n\n    test_getvalue(sg);\n\n    delete sg;\n\n    for (int i = 0; i < Heap.size(); i++) { delete[] Heap[i]; }\n\n    return (0);\n}\n"
  },
  {
    "path": "test_apps/params/file.xml",
    "content": "<TOP>\n<TwoDDataParams>\n<CompressionLevel Type=\"Long\">\n  0 \n</CompressionLevel>\n<Enabled Type=\"Long\">\n  1 \n</Enabled>\n<RefinementLevel Type=\"Long\">\n  0 \n</RefinementLevel>\n<UseSingleColor Type=\"Long\">\n  0 \n</UseSingleColor>\n<ConstantColor Type=\"Double\">\n  1 1 1 \n</ConstantColor>\n<ConstantOpacity Type=\"Double\">\n  1 \n</ConstantOpacity>\n<HistoScale Type=\"Double\">\n  1 \n</HistoScale>\n<StretchFactors Type=\"Double\">\n  1 1 1 \n</StretchFactors>\n<ColorMapVariable Type=\"String\">\n  NULL\n</ColorMapVariable>\n<FieldVariableNames Type=\"String\">\n  P PB PH\n</FieldVariableNames>\n<HeightVariable Type=\"String\">\n  NULL\n</HeightVariable>\n<VariableName Type=\"String\">\n  CANWAT\n</VariableName>\n<TransferFunctions>\n</TransferFunctions>\n<BoxParams>\n<Orientation Type=\"Long\">\n  2 \n</Orientation>\n<Planar Type=\"Long\">\n  1 \n</Planar>\n<Angles Type=\"Double\">\n  0 0 0 \n</Angles>\n<Extents Type=\"Double\">\n  -845627.125 1991855.625 0 412793.375 3219581.5 0 \n</Extents>\n</BoxParams>\n<ColorBarSettingParams>\n<ColorbarEnabled Type=\"Long\">\n  0 \n</ColorbarEnabled>\n<ColorbarFontsize Type=\"Long\">\n  10 \n</ColorbarFontsize>\n<ColorbarNumDigits Type=\"Long\">\n  4 \n</ColorbarNumDigits>\n<ColorbarNumTics Type=\"Long\">\n  6 \n</ColorbarNumTics>\n<ColorbarBackgroundColor Type=\"Double\">\n  1 1 1 \n</ColorbarBackgroundColor>\n<ColorbarPosition Type=\"Double\">\n  0.1 0.1 \n</ColorbarPosition>\n<ColorbarSize Type=\"Double\">\n  0.1 0.1 \n</ColorbarSize>\n<ColorbarTitle Type=\"String\">\n  \n</ColorbarTitle>\n</ColorBarSettingParams>\n</TwoDDataParams>\n</TOP>\n"
  },
  {
    "path": "test_apps/params/test_params.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <vector>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/TwoDImageParams.h>\n#include <vapor/TwoDDataParams.h>\n#include <vapor/ParamsStateMgr.h>\n#include <vapor/TransferFunction.h>\n#include <vapor/DataMgrV3_0.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    string                  ifile;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T debug;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {\n    {\"ifile\", 1, \"\", \"Construct Xml tree from a file\"}, {\"help\", 0, \"\", \"Print this message and exit\"}, {\"quiet\", 0, \"\", \"Operate quitely\"}, {\"debug\", 0, \"\", \"Debug mode\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"ifile\", Wasp::CvtToCPPStr, &opt.ifile, sizeof(opt.ifile)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {NULL}};\n\nconst char *ProgName;\n\nvoid make_params(DataMgrV3_0 *dataMgr, string parent_name, string outfile)\n{\n    ofstream out(outfile);\n    if (!out) {\n        MyBase::SetErrMsg(\"Failed to open file %s : %M\", outfile.c_str());\n        exit(1);\n    }\n\n    ParamsBase::StateSave ssave;\n    ParamsSeparator       parent(&ssave, \"TOP\");\n\n    TwoDDataParams dataParams(dataMgr, &ssave);\n    dataParams.SetParent(&parent);\n\n    vector<string> varnames = dataMgr->GetDataVarNames();\n    for (int i = 0; i < varnames.size(); i++) { dataParams.GetTransferFunc(varnames[i]); }\n\n#ifdef VAPOR3_0_0_ALPHA\n    ParamsContainer tfs(&psm, \"TransferFunctions\");\n    tfs.GetNode()->SetParent(&parent);\n\n    TransferFunction tf1(&psm);\n    TransferFunction tf2(&psm);\n    TransferFunction tf3(&psm);\n\n    // create a second opacity map\n    //\n    (void)tf3.createOpacityMap();\n\n    tfs.Insert(&tf1, \"X\");\n    tfs.Insert(&tf2, \"Y\");\n    tfs.Insert(&tf3, \"Z\");\n\n    ParamsContainer twoDparams(&psm, &parent, \"ImageParams\");\n\n    TwoDImageParams imgparams1(&psm, NULL, 0);\n    TwoDImageParams imgparams2(&psm, NULL, 0);\n\n    TwoDImageParams imgparams3(imgparams2);\n    imgparams3.SetHeightVariableName(\"hgt\");\n\n    twoDparams.Insert(&imgparams1, \"img1\");\n    twoDparams.Insert(&imgparams2, \"img2\");\n    twoDparams.Insert(&imgparams3, \"img3\");\n#endif\n\n    out << *(parent.GetNode());\n\n    out.close();\n}\n\nvoid import_params(DataMgrV3_0 *dataMgr, string infile)\n{\n    XmlNode   parent;\n    XmlParser parser;\n\n    int rc = parser.LoadFromFile(&parent, infile);\n    if (rc < 0) exit(1);\n\n    XmlNode *tfnode = parent.GetChild(0);\n    if (!tfnode) return;\n\n    ParamsBase::StateSave ssave;\n\n    TwoDDataParams dataParams(dataMgr, &ssave, tfnode);\n\n    cout << parent;\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       s;\n\n    ProgName = Basename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); }\n\n    if (argc != 2) {\n        cerr << \"Usage: \" << ProgName << \" VDCMaster.nc [options] \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    string         vdcfile = argv[1];\n    vector<string> files(1, vdcfile);\n\n    DataMgrV3_0 dataMgr(\"vdc\", 1000);\n    int         rc = dataMgr.Initialize(files);\n    if (rc < 0) return (1);\n\n    make_params(&dataMgr, \"parent\", \"file.xml\");\n\n    import_params(&dataMgr, \"file.xml\");\n\n    cout << \"Allocated note count after delete : \" << XmlNode::GetAllocatedNodes().size() << endl;\n}\n"
  },
  {
    "path": "test_apps/params2/CMakeLists.txt",
    "content": "add_executable (test_params2 test_params2.cpp)\nset_target_properties(test_params2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${debug_output_dir}\")\n\ntarget_link_libraries (test_params2 params common vdc wasp)\n"
  },
  {
    "path": "test_apps/params2/test_params2.cpp",
    "content": "#include <iostream>\n#include <fstream>\n#include <string>\n#include <vector>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/ViewpointParams.h>\n#include <vapor/FileUtils.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"help\", 0, \"\", \"Print this message and exit\"}, {\"quiet\", 0, \"\", \"Operate quitely\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)}, {NULL}};\n\nconst char *ProgName;\n\nvoid test()\n{\n    ParamsBase::StateSave ssave;\n    ParamsSeparator       parent(&ssave, \"TOP\");\n\n    ViewpointParams vp1(&ssave);\n    vp1.SetParent(&parent);\n\n    ViewpointParams vp2(&ssave);\n    // vp2.SetParent(&parent);\n\n    if (vp1 == vp2) {\n        cout << \"SUCCESS: vp1 == vp2\" << endl;\n    } else {\n        cout << \"FAIL: vp1 == vp2\" << endl;\n    }\n\n    vp1.SetWindowSize(1280, 1024);\n    vp1.SetFOV(99.0);\n\n    if (vp1 != vp2) {\n        cout << \"SUCCESS: vp1 != vp2\" << endl;\n    } else {\n        cout << \"FAIL: vp1 != vp2\" << endl;\n    }\n\n    vp1 = vp2;\n    if (vp1 == vp2) {\n        cout << \"SUCCESS: vp1 == vp2\" << endl;\n    } else {\n        cout << \"FAIL: vp1 == vp2\" << endl;\n    }\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       s;\n\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    MyBase::SetDiagMsgFilePtr(stderr);\n\n    if (argc != 1) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    test();\n\n    cout << \"Allocated note count after delete : \" << XmlNode::GetAllocatedNodes().size() << endl;\n}\n"
  },
  {
    "path": "test_apps/pyengine/CMakeLists.txt",
    "content": "add_executable (test_pyengine test_pyengine.cpp)\nset_target_properties(test_pyengine PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${debug_output_dir}\")\n\ntarget_link_libraries (test_pyengine render common vdc wasp ${Python_LIBRARIES})\n"
  },
  {
    "path": "test_apps/pyengine/test_pyengine.cpp",
    "content": "#include <iostream>\n#include <iomanip>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/FileUtils.h>\n#include <vapor/OptionParser.h>\n#include <vapor/MyPython.h>\n#include <vapor/PyEngine.h>\n#include <vapor/ControlExecutive.h>\n#include <vapor/DataStatus.h>\n\nusing namespace std;\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nsize_t vproduct(DimsType a)\n{\n    size_t ntotal = 1;\n\n    for (int i = 0; i < a.size(); i++) ntotal *= a[i];\n    return (ntotal);\n}\n\nstruct {\n    int                     memsize;\n    int                     level;\n    int                     lod;\n    int                     nthreads;\n    string                  ftype;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T debug;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"memsize\", 1, \"2000\", \"Cache size in MBs\"},\n                                         {\"level\", 1, \"0\", \"Multiresution refinement level. Zero implies coarsest resolution\"},\n                                         {\"lod\", 1, \"0\", \"Level of detail. Zero implies coarsest resolution\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"ftype\", 1, \"vdc\", \"data set type (vdc|wrf|cf|mpas)\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {\"quiet\", 0, \"\", \"Operate quitely\"},\n                                         {\"debug\", 0, \"\", \"Debug mode\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {\n    {\"memsize\", Wasp::CvtToInt, &opt.memsize, sizeof(opt.memsize)},    {\"level\", Wasp::CvtToInt, &opt.level, sizeof(opt.level)},     {\"lod\", Wasp::CvtToInt, &opt.lod, sizeof(opt.lod)},\n    {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)}, {\"ftype\", Wasp::CvtToCPPStr, &opt.ftype, sizeof(opt.ftype)},  {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n    {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},      {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)}, {NULL}};\n\nconst char *ProgName;\n\nvoid test_calculate()\n{\n    int rc = PyEngine::Initialize();\n    if (rc < 0) return;\n\n    DimsType dims = {1000, 1000, 10};\n    //\tstring script = \"C = sqrt(A) + B\";\n    string                 script = \"C = A + B\";\n    vector<string>         inputVarNames = {\"A\", \"B\"};\n    vector<DimsType>       inputVarDims = {dims, dims};\n    vector<string>         outputVarNames = {\"C\"};\n    vector<DimsType>       outputVarDims = {dims};\n\n    float *A = new float[vproduct(dims)];\n    float *B = new float[vproduct(dims)];\n    float *C = new float[vproduct(dims)];\n\n    for (int i = 0; i < vproduct(dims); i++) {\n        A[i] = 1;\n        B[i] = 2;\n    }\n\n    vector<float *> inputVarArrays = {A, B};\n    vector<float *> outputVarArrays = {C};\n\n    rc = PyEngine::Calculate(script, inputVarNames, inputVarDims, inputVarArrays, outputVarNames, outputVarDims, outputVarArrays);\n    if (rc < 0) {\n        delete[] A;\n        delete[] B;\n        delete[] C;\n        return;\n    }\n\n    string status = \"SUCCESS\";\n    for (int i = 0; i < vproduct(dims); i++) {\n        if (C[i] != A[i] + B[i]) {\n            status = \"FAILED!!!\";\n            break;\n        }\n    }\n\n    delete[] A;\n    delete[] B;\n    delete[] C;\n\n    string s = MyPython::Instance()->PyOut();\n    if (!s.empty()) { cout << \"test_calculate : \" << s << endl; }\n\n    cout << \"test_calculate : \" << status << endl;\n\n    return;\n}\n\nvoid test_datamgr(vector<string> files)\n{\n    if (files.empty()) return;\n\n    DataMgr datamgr(opt.ftype, opt.memsize, opt.nthreads);\n    int     rc = datamgr.Initialize(files, vector<string>());\n    if (rc < 0) exit(1);\n\n    PyEngine pyEngine(&datamgr);\n    if (pyEngine.Initialize() < 0) exit(1);\n\n    vector<string> varNames = datamgr.GetDataVarNames();\n    if (varNames.empty()) return;\n\n    string inputVarName = varNames[0];\n    string outputVarName = varNames[0] + \"Copy\";\n    string script = outputVarName + \" = \" + inputVarName;\n\n    DC::DataVar datavar;\n    rc = datamgr.GetDataVarInfo(inputVarName, datavar);\n    VAssert(rc >= 0);\n\n    vector<string> inputVarNames = {inputVarName};\n    vector<string> outputVarNames = {outputVarName};\n    vector<string> outputMeshNames = {datavar.GetMeshName()};\n\n    rc = pyEngine.AddFunction(\"myscript\", script, inputVarNames, outputVarNames, outputMeshNames);\n    if (rc < 0) exit(1);\n\n    if (!opt.quiet) {\n        cout << \"Derived variable :\\n\";\n        datamgr.GetDataVarInfo(outputVarName, datavar);\n        cout << datavar;\n    }\n\n    Grid *g1 = datamgr.GetVariable(0, inputVarName, opt.level, opt.lod, true);\n    if (!g1) exit(1);\n\n    Grid *g2 = datamgr.GetVariable(0, outputVarName, opt.level, opt.lod, true);\n    if (!g2) exit(1);\n\n    Grid::ConstIterator itr1 = g1->cbegin();\n    Grid::ConstIterator enditr1 = g1->cend();\n\n    Grid::ConstIterator itr2 = g2->cbegin();\n    Grid::ConstIterator enditr2 = g2->cend();\n\n    string status = \"SUCCESS\";\n    for (; itr1 != enditr1; ++itr1, ++itr2) {\n        if (itr2 == enditr2) {\n            status = \"FAILED\";\n            break;\n        }\n        if (*itr1 != *itr2) {\n            status = \"FAILED\";\n            break;\n        }\n    }\n\n    cout << \"test_datamgr : \" << status << endl;\n}\n\nvoid test_controlexec_copy(vector<string> files)\n{\n    if (files.empty()) return;\n\n    ControlExec ce;\n\n    const string dataSetName = \"test_data\";\n    int          rc = ce.OpenData(files, dataSetName, opt.ftype);\n\n    DataStatus *dataStatus = ce.GetDataStatus();\n\n    DataMgr *dataMgr = dataStatus->GetDataMgr(dataSetName);\n\n    vector<string> varNames = dataMgr->GetDataVarNames();\n    if (varNames.empty()) return;\n\n    string inputVarName = varNames[0];\n    string outputVarName = varNames[0] + \"Copy\";\n    string script = outputVarName + \" = \" + inputVarName + \"\\n\";\n\n    DC::DataVar datavar;\n    rc = dataMgr->GetDataVarInfo(inputVarName, datavar);\n    VAssert(rc >= 0);\n\n    vector<string> inputVarNames = {inputVarName};\n    vector<string> outputVarNames = {outputVarName};\n    vector<string> outputMeshNames = {datavar.GetMeshName()};\n\n    rc = ce.AddFunction(\"Python\", dataSetName, \"myscript_ce\", script, inputVarNames, outputVarNames, outputMeshNames);\n    if (rc < 0) exit(1);\n\n    if (!opt.quiet) {\n        cout << \"Derived variable :\\n\";\n        dataMgr->GetDataVarInfo(outputVarName, datavar);\n        cout << datavar;\n    }\n\n    Grid *g1 = dataMgr->GetVariable(0, inputVarName, opt.level, opt.lod, true);\n    if (!g1) exit(1);\n\n    Grid *g2 = dataMgr->GetVariable(0, outputVarName, opt.level, opt.lod, true);\n    if (!g2) exit(1);\n\n    Grid::ConstIterator itr1 = g1->cbegin();\n    Grid::ConstIterator enditr1 = g1->cend();\n\n    Grid::ConstIterator itr2 = g2->cbegin();\n    Grid::ConstIterator enditr2 = g2->cend();\n\n    string status = \"SUCCESS\";\n    for (; itr1 != enditr1; ++itr1, ++itr2) {\n        if (itr2 == enditr2) {\n            status = \"FAILED\";\n            break;\n        }\n        if (*itr1 != *itr2) {\n            status = \"FAILED\";\n            break;\n        }\n    }\n\n    ce.CloseData(dataSetName);\n\n    cout << \"test_controlexec_copy : \" << status << endl;\n}\n\nvoid test_controlexec_coord(vector<string> files)\n{\n    if (files.empty()) return;\n\n    ControlExec ce;\n\n    const string dataSetName = \"test_data\";\n    int          rc = ce.OpenData(files, dataSetName, opt.ftype);\n\n    DataStatus *dataStatus = ce.GetDataStatus();\n\n    DataMgr *dataMgr = dataStatus->GetDataMgr(dataSetName);\n\n    vector<string> varNames = dataMgr->GetDataVarNames();\n    if (varNames.empty()) return;\n\n    string inputVarName = varNames[0];\n    string outputVarName = varNames[0] + \"Copy\";\n    string script = outputVarName + \" = \" + inputVarName + \"\\n\";\n    //\tstring script = outputVarName + \" = sqrt(\" + inputVarName +\")\";\n    script += \"import numpy as np\\n\"\n              \"for f in dir():\\n\"\n              \"\tif type(eval(f)) is np.ndarray:\\n\"\n              \"\t\tprint f, eval(f).shape, 'min,max,mean: ', eval(f).min(), eval(f).max(), eval(f).mean()\\n\"\n              \"\\n\"\n              \"\\n\";\n\n    DC::DataVar datavar;\n    rc = dataMgr->GetDataVarInfo(inputVarName, datavar);\n    VAssert(rc >= 0);\n\n    vector<string> inputVarNames = {inputVarName};\n    vector<string> outputVarNames = {outputVarName};\n    vector<string> outputMeshNames = {datavar.GetMeshName()};\n\n    bool   coordFlag = true;\n    string scriptName = \"test_controlexec_coord\";\n    rc = ce.AddFunction(\"Python\", dataSetName, scriptName, script, inputVarNames, outputVarNames, outputMeshNames, coordFlag);\n    if (rc < 0) exit(1);\n\n    if (!opt.quiet) {\n        cout << \"Derived variable :\\n\";\n        dataMgr->GetDataVarInfo(outputVarName, datavar);\n        cout << datavar;\n    }\n\n    Grid *g1 = dataMgr->GetVariable(0, inputVarName, opt.level, opt.lod, true);\n    if (!g1) exit(1);\n\n    Grid *g2 = dataMgr->GetVariable(0, outputVarName, opt.level, opt.lod, true);\n    if (!g2) exit(1);\n\n    Grid::ConstIterator itr1 = g1->cbegin();\n    Grid::ConstIterator enditr1 = g1->cend();\n\n    Grid::ConstIterator itr2 = g2->cbegin();\n    Grid::ConstIterator enditr2 = g2->cend();\n\n    string status = \"SUCCESS\";\n    for (; itr1 != enditr1; ++itr1, ++itr2) {\n        if (itr2 == enditr2) {\n            status = \"FAILED\";\n            break;\n        }\n        if (*itr1 != *itr2) {\n            status = \"FAILED\";\n            break;\n        }\n    }\n\n    cout << \"Script output : \\n\";\n    cout << ce.GetFunctionStdout(\"Python\", dataSetName, scriptName) << endl;\n\n    ce.CloseData(dataSetName);\n\n    cout << \"test_controlexec_coord : \" << status << endl;\n}\n\nvoid test_controlexec_add(vector<string> files)\n{\n    if (files.empty()) return;\n\n    ControlExec ce;\n\n    const string dataSetName = \"test_data\";\n    int          rc = ce.OpenData(files, dataSetName, opt.ftype);\n\n    DataStatus *dataStatus = ce.GetDataStatus();\n\n    DataMgr *dataMgr = dataStatus->GetDataMgr(dataSetName);\n\n    vector<string> varNames = dataMgr->GetDataVarNames();\n    if (varNames.empty()) return;\n\n    vector<string> inputVarNames = {\"U10\", \"V10\"};\n    vector<string> outputVarNames = {\"U10plusV10\"};\n    string         script = \"U10plusV10 = U10 + V10\\n\";\n    script += \"print 'UV10plusV10 shape : ', U10plusV10.shape\";\n\n    DC::DataVar datavar;\n    rc = dataMgr->GetDataVarInfo(inputVarNames[0], datavar);\n    VAssert(rc >= 0);\n\n    vector<string> outputMeshNames = {datavar.GetMeshName()};\n\n    rc = ce.AddFunction(\"Python\", dataSetName, \"myscript_ce\", script, inputVarNames, outputVarNames, outputMeshNames);\n    if (rc < 0) exit(1);\n\n    if (!opt.quiet) {\n        cout << \"Derived variable :\\n\";\n        dataMgr->GetDataVarInfo(outputVarNames[0], datavar);\n        cout << datavar;\n    }\n\n    Grid *g1 = dataMgr->GetVariable(0, inputVarNames[0], opt.level, opt.lod, true);\n    if (!g1) exit(1);\n\n    Grid *g2 = dataMgr->GetVariable(0, inputVarNames[1], opt.level, opt.lod, true);\n    if (!g2) exit(1);\n\n    Grid *g3 = dataMgr->GetVariable(0, outputVarNames[0], opt.level, opt.lod, true);\n    if (!g3) exit(1);\n\n    Grid::ConstIterator itr1 = g1->cbegin();\n    Grid::ConstIterator enditr1 = g1->cend();\n\n    Grid::ConstIterator itr2 = g2->cbegin();\n    Grid::ConstIterator enditr2 = g2->cend();\n\n    Grid::ConstIterator itr3 = g3->cbegin();\n    Grid::ConstIterator enditr3 = g3->cend();\n\n    string status = \"SUCCESS\";\n    for (; itr1 != enditr1; ++itr1, ++itr2, ++itr3) {\n        if (itr2 == enditr2 || itr3 == enditr3) {\n            status = \"FAILED\";\n            break;\n        }\n        if ((*itr1 + *itr2) != *itr3) {\n            status = \"FAILED\";\n            break;\n        }\n    }\n\n    ce.CloseData(dataSetName);\n\n    cout << \"test_controlexec_add : \" << status << endl;\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       s;\n\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); }\n\n    vector<string> files;\n    for (int i = 1; i < argc; i++) { files.push_back(argv[i]); }\n\n    test_calculate();\n\n    test_datamgr(files);\n\n    test_controlexec_copy(files);\n\n    test_controlexec_coord(files);\n\n    test_controlexec_add(files);\n\n    return 0;\n}\n"
  },
  {
    "path": "test_apps/quadtreerectangle/CMakeLists.txt",
    "content": "\nadd_executable (test_quadtreerectangle \"\")\nset_target_properties(test_quadtreerectangle PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${debug_output_dir}\")\n\ntarget_sources(test_quadtreerectangle PRIVATE test_quadtreerectangle.cpp ../smokeTests/gridTools.cpp ../smokeTests/gridTools.h)\n\ntarget_link_libraries (test_quadtreerectangle common vdc wasp)\n"
  },
  {
    "path": "test_apps/quadtreerectangle/test_quadtreerectangle.cpp",
    "content": "#include <iostream>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/FileUtils.h>\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/QuadTreeRectangle.hpp>\n#include \"../smokeTests/gridTools.h\"\n\nusing namespace std;\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    int                     n;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"n\", 1, \"1000\", \"Quad mesh X & Y dimensions\"}, {\"help\", 0, \"\", \"Print this message and exit\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"n\", Wasp::CvtToInt, &opt.n, sizeof(opt.n)}, {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)}, {NULL}};\n\nconst char *ProgName;\n\nvoid print_histo(const QuadTreeRectangle<float, size_t> &qtr)\n{\n    vector<size_t> payload_histo;\n    vector<size_t> level_histo;\n    qtr.GetStats(payload_histo, level_histo);\n    cout << \"Payload histo\" << endl;\n    for (int i = 0; i < payload_histo.size(); i++) { cout << \"   \" << i << \" \" << payload_histo[i] << endl; }\n\n    cout << \"Level histo\" << endl;\n    for (int i = 0; i < level_histo.size(); i++) { cout << \"   \" << i << \" \" << level_histo[i] << endl; }\n    cout << endl;\n}\n\nvoid test_mesh()\n{\n    size_t n = opt.n;\n    VAssert(n >= 2);\n\n    QuadTreeRectangle<float, size_t> qtr(0.0, 0.0, 1.0, 1.0, n * n);\n\n    float delta = 1.0 / (float)(n - 1);\n\n    cout << \"\tBuild\" << endl;\n    size_t index = 0;\n    for (size_t j = 0; j < n - 1; j++) {\n        for (size_t i = 0; i < n - 1; i++) {\n            float left = (float)i * delta;\n            float right = (float)i * delta + delta;\n            float top = (float)j * delta;\n            float bottom = (float)j * delta + delta;\n\n            qtr.Insert(left, top, right, bottom, index);\n\n            index++;\n        }\n    }\n    cout << \"\tSearch\" << endl;\n\n    size_t num_missed = 0;\n    size_t num_wrong = 0;\n    index = 0;\n    for (size_t j = 0; j < n - 1; j++) {\n        for (size_t i = 0; i < n - 1; i++) {\n            float x = (float)i * delta + (delta * 0.5);\n            ;\n            float y = (float)j * delta + (delta * 0.5);\n            ;\n\n            vector<size_t> payloads;\n\n            qtr.GetPayloadContained(x, y, payloads);\n            if (payloads.size() < 1) {\n                num_missed++;\n                continue;\n            }\n            bool found = false;\n            for (int ii = 0; ii < payloads.size(); ii++) {\n                if (payloads[ii] == index) {\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) { num_wrong++; }\n\n            index++;\n        }\n    }\n    cout << \"\tNum missed : \" << num_missed << endl;\n    cout << \"\tNum wrong : \" << num_wrong << endl;\n    // cout << qtr;\n\n    print_histo(qtr);\n}\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       s;\n\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    QuadTreeRectangle<float, int> qtr;\n    cout << qtr;\n\n    qtr.Insert(0.0, 0.0, 1.0, 1.0, 100);\n    qtr.Insert(0.0, 0.0, 0.2, 0.2, 101);\n    qtr.Insert(0.9, 0.9, 1.0, 1.0, 102);\n    cout << qtr;\n\n    vector<int> payloads;\n\n    qtr.GetPayloadContained(0.1, 0.1, payloads);\n\n    cout << \"quads intersecting 0.1, 0.1\" << endl;\n    for (int i = 0; i < payloads.size(); i++) { cout << payloads[i] << \" \"; }\n    cout << endl;\n\n    qtr.GetPayloadContained(0.9, 0.9, payloads);\n\n    cout << \"quads intersecting 0.9, 0.9\" << endl;\n    for (int i = 0; i < payloads.size(); i++) { cout << payloads[i] << \" \"; }\n    cout << endl;\n\n    test_mesh();\n\n    return 0;\n}\n"
  },
  {
    "path": "test_apps/render_regression_tests/README.md",
    "content": "# Render Regression Tests\n\n** **For internal use**\n\n### Components\n- **run_config.py** Primary tool to run tests. It runs the entire suite of tests as configured in config.yaml. Run with `-h` for usage help.\n- **run_test.py** Runs a single test render. Not intended to be used directly, it is used by the `run_config.py` script.\n- **config.yaml** Contains the configuration for the list of tests to run. Split into 2 secions denoted by `--- # Section`. The first specifies global settings that apply to all tests. The second is a list of tests.\n\n### Dependencies\n\nThe test requires vapor's python library to be installed as well as the pyyaml library.\n\n### Output\n\nThe test will generate an output directory as specified in the config.yaml file. In the output directory, there will be one image file per test titled `<test name>-<renderer>[-<variables> (if multiple)].png`. In the output directory there will be a `meta` folder containing for each test a log file with the config used to generate the test and stdout/stderr from the test, and the session file that reproduces the test named `meta/<image>.log` and `meta/<image>.vs3` respectively.\n\n"
  },
  {
    "path": "test_apps/render_regression_tests/config.yaml",
    "content": "--- # CONFIG\noutDir: ./out\n# dataRootDir: /Volumes/ExtremeSSD/data\ndataRootDir: /glade/p/cisl/vast/vapor/data\nresolution: [1000, 720]\n\nrendererSets:\n  default:\n    - TwoDData\n    - Image\n    - Volume\n    - IsoSurface\n    - Flow\n  2D:\n    - TwoDData\n    - Image\n    - Flow2D\n  3D:\n    - Image\n    - Volume\n    - IsoSurface\n    - Flow3D\n\n--- # Tests\n\nCAM/AdamPhillips/v5_rel04_BC5_ne120_t12_pop62:\n  files: Source/CAM/AdamPhillips/v5_rel04_BC5_ne120_t12_pop62/*.nc\n  type: cf\n\nCAM/AMIP_0.25degree:\n  files: Source/CAM/AMIP_0.25degree/cam5_1_amip_run2.cam2.h1.1979-01-0[1-3]-00000.nc\n  type: cf\n\nCAM/FiniteVolume/cam_fv:\n  # GPU out of memory for 3D\n  files: Source/CAM/FiniteVolume/cam_fv/*.nc\n  type: cf\n\nCAM/Gaussian:\n  files: Source/CAM/Gaussian/*.nc\n  type: cf\n  renderers:\n    - TwoDData\n    - Image\n\nMOM4/00010101:\n  files: Source/MOM4/00010101/*.nc\n  type: cf\n\nMOM4/19990101:\n  files: Source/MOM4/19990101/*.nc\n  type: cf\n\nMOM4/iom1/ocean_month:\n  files: Source/MOM4/iom1/ocean_month/*.nc\n  type: cf\n\nMOM4/JinHeeYuk/ocean_eta:\n  files: Source/MOM4/JinHeeYuk/ocean_eta/*.nc\n  type: cf\n  renderers:\n    - TwoDData\n    - Image\n\nMOM4/JinHeeYuk/ocean_salt:\n  files: Source/MOM4/JinHeeYuk/ocean_salt/*.nc\n  type: cf\n  renderers:\n    - Image\n    - Volume\n    - IsoSurface\n\nMOM4/om3/ocean_residency_snap:\n  files: Source/MOM4/om3/ocean_residency_snap/*.nc\n  type: cf\n  renderers:\n    - TwoDData\n    - Image\n    - Volume\n    - IsoSurface\n\nMPAS/MPAS-O:\n  files: Source/MPAS/MPAS-O/*.nc\n  type: mpas\n  renderers: 2D\n\nMPAS/FalkoJudt/30km:\n  files:\n    - Source/MPAS/FalkoJudt/30km/x1.static.nc\n    - Source/MPAS/FalkoJudt/30km/diag.2016-08-01_10.30.00.nc\n  type: mpas\n  renderers: 2D\n\nMPAS/MPAS_V4.0:\n  files: Source/MPAS/MPAS_V4.0/x1.40962.output.2012-05-25_06.00.00.nc\n  type: mpas\n  renderers: 2D\n\nMPAS/ThomasSchwitalla:\n  runConcurrently: false\n  files:\n    - Source/MPAS/ThomasSchwitalla/x1.65536002.grid.nc\n    - Source/MPAS/ThomasSchwitalla/ter_3km.nc\n  type: mpas\n  renderers:\n    TwoDData: t2m\n    Image:\n\nMPAS/RosimarRiosBerrios:\n  # skip: true\n  runConcurrently: false\n  files:\n    - Source/MPAS/RosimarRiosBerrios/x5.tropical_3km_10N.init.nc\n    - Source/MPAS/RosimarRiosBerrios/diag.2000-05-31_00.00.00.nc\n  type: mpas\n  renderers:\n    - TwoDData\n    - Image\n\nPOP/KISTI:\n  files: Source/POP/KISTI/*.nc\n  type: cf\n  renderers:\n    Image:\n    TwoDData:\n    Flow2D:\n      XFieldVariable: HUS\n      YFieldVariable: HUW\n\n\nROMS/his:\n  files: Source/ROMS/his/*.nc\n  type: cf\n  timestep: 1\n  renderers:\n    default:\n    IsoSurface: temp\n\nROMS/jsmall:\n  files: Source/ROMS/jsmall/*.nc\n  type: cf\n\nROMS/Kauffman:\n  files: Source/ROMS/Kauffman/*.nc\n  type: cf\n\nROMS/KISTI/dm1:\n  files: Source/ROMS/KISTI/dm1/*.nc\n  type: cf\n  renderers:\n    default:\n    TwoDData: zeta\n\nROMS/KISTI/Regular2:\n  files: Source/ROMS/KISTI/Regular2/*.nc\n  type: cf\n\nROMS/KISTI/Rotated:\n  files: Source/ROMS/KISTI/Rotated/*.nc\n  type: cf\n  renderers:\n    default:\n    TwoDData: zeta\n\nWRF/2D:\n  files: Source/WRF/2D/wrf.nc\n  type: wrf\n  renderers:\n    2D:\n    TwoDData:\n      variable: U10\n\nWRF/antarctic/antarctic_01:\n  files: Source/WRF/antarctic/antarctic_01/wrfout_d01_2009-04-01_00:00:00\n  type: wrf\n\nWRF/antarctic/antarctic_02:\n  files: Source/WRF/antarctic/antarctic_02/wrfout_d02_2009-04-01_00:00:00\n  type: wrf\n\nWRF/antarctic/antarctic_03:\n  files: Source/WRF/antarctic/antarctic_03/wrfout_d03_2009-04-01_00:00:00\n  type: wrf\n  renderers:\n    default:\n    Volume: V\n\nWRF/antarctic/antarctic_04:\n  files: Source/WRF/antarctic/antarctic_04/wrfout_d04_2009-04-01_00:00:00\n  type: wrf\n  renderers:\n    default:\n    Volume: U\n    TwoDData: T2\n\nWRF/antarctic/antarctic_05:\n  files: Source/WRF/antarctic/antarctic_05/wrfout_d05_2009-04-01_00:00:00\n  type: wrf\n\nWRF/antarctic/antarctic_06:\n  files: Source/WRF/antarctic/antarctic_06/wrfout_d06_2009-04-01_00:00:00\n  type: wrf\n\nWRF/april:\n  files: Source/WRF/april/wrfout_d01_2007-04-0[4-5]_00:00:00\n  type: wrf\n\nWRF/DUKU:\n  files: Source/WRF/DUKU/wrfout_d02_2007-04-01_00:00:00.nc\n  type: wrf\n\nWRF/headwaters:\n  files: Source/WRF/headwaters/wrfout_d01_2053-03-21_00:00:00\n  type: wrf\n\nWRF/HurricaneBill:\n  files:\n    - Source/WRF/HurricaneBill/wrfout_d01_2009-08-18_12:00:00\n    - Source/WRF/HurricaneBill/wrfout_d01_2009-08-18_15:00:00\n  type: wrf\n  renderers:\n    default:\n    IsoSurface:\n      IsoValues: [60.87427]\n\nWRF/idealized/kalundquist:\n  files: Source/WRF/idealized/kalundquist/wrfout_d01_2013-01-01_09_30_00\n  type: wrf\n  renderers:\n    default:\n    TwoDData:\n      variable: SWUPT\n\nWRF/idealized:\n  files: Source/WRF/idealized/wrfout_d01_0001-01-01_00:00:40\n  type: wrf\n  renderers:\n    default:\n    TwoDData:\n      variable: U10\n    Volume:\n      variable: V\n    IsoSurface:\n      variable: V\n\nWRF/Katrina:\n  files: Source/WRF/Katrina/wrfout_d02_2005-08-29_01\n  type: wrf\n\nWRF/planetwrf:\n  files: Source/WRF/planetwrf/wrfout_d01601\n  type: wrf\n\nWRF/rotlatlon/Alan1/d01:\n  files:\n    - Source/WRF/rotlatlon/Alan1/d01/wrfout_d01_2008-06-01_00\n    - Source/WRF/rotlatlon/Alan1/d01/wrfout_d01_2008-06-01_06\n    - Source/WRF/rotlatlon/Alan1/d01/wrfout_d01_2008-06-01_12\n  type: wrf\n  renderers:\n    default:\n    TwoDData: Q2\n    Volume: P\n    IsoSurface:\n      variable: P\n      IsoValues: [ 783 ]\n\nWRF/rotlatlon/Alan1/d02:\n  files:\n    - Source/WRF/rotlatlon/Alan1/d02/wrfout_d02_2008-06-01_00\n    - Source/WRF/rotlatlon/Alan1/d02/wrfout_d02_2008-06-01_06\n    - Source/WRF/rotlatlon/Alan1/d02/wrfout_d02_2008-06-01_12\n  type: wrf\n  renderers:\n    default:\n    TwoDData: Q2\n    Volume: P\n    IsoSurface:\n      variable: P\n\nWRF/rotlatlon/Alan2/d01:\n  files:\n    - Source/WRF/rotlatlon/Alan2/d01/wrfout_d01_2008-06-01_00\n    - Source/WRF/rotlatlon/Alan2/d01/wrfout_d01_2008-06-01_06\n    - Source/WRF/rotlatlon/Alan2/d01/wrfout_d01_2008-06-01_12\n  type: wrf\n  renderers:\n    default:\n    TwoDData: Q2\n    Volume: P\n    IsoSurface:\n      variable: P\n\nWRF/rotlatlon/Alan2/d02:\n  files:\n    - Source/WRF/rotlatlon/Alan2/d02/wrfout_d02_2008-06-01_00\n    - Source/WRF/rotlatlon/Alan2/d02/wrfout_d02_2008-06-01_06\n    - Source/WRF/rotlatlon/Alan2/d02/wrfout_d02_2008-06-01_12\n  type: wrf\n  renderers:\n    default:\n    TwoDData: Q2\n    Volume: P\n    IsoSurface:\n      variable: P\n\nWRF/yochen:\n  files: Source/WRF/yochen/wrfout_d05_2005-07-10_00:1[0-1]:00\n  type: wrf\n  renderers:\n    default:\n    TwoDData: T2\n    Volume: V\n\nWRF/HRRR:\n  files: Source/WRF/HRRR/wrfout_d01_2020-08-28_20_00_00\n  type: wrf\n  renderers:\n    Flow2D:\n    TwoDData:\n      variable: HFX\n    Volume:\n    IsoSurface:\n      IsoValues: [0.01773]\n\nBOV/256i.bov:\n  files: Source/BOV/256i.bov\n  type: bov\n  renderers: IsoSurface\n\n\nBOV/256f.bov:\n  files: Source/BOV/256f.bov\n  type: bov\n  renderers: IsoSurface\n\nBOV/256d.bov:\n  files: Source/BOV/256d.bov\n  type: bov\n  renderers: IsoSurface\n\nBOV/multiTimeMultiVar:\n  files: Source/BOV/multiTimeMultiVar/*.bov\n  type: bov\n  renderers: IsoSurface\n\nBOV/relativePath1.bov:\n  files: Source/BOV/relativePath1.bov\n  type: bov\n  renderers: IsoSurface\n\nBOV/relativePath2.bov:\n  files: Source/BOV/relativePath2.bov\n  type: bov\n  renderers: IsoSurface\n\nBOV/relativePath3.bov:\n  files: Source/BOV/relativePath3.bov\n  type: bov\n  renderers: IsoSurface\n\nBOV/relativePath4.bov:\n  files: Source/BOV/relativePath4.bov\n  type: bov\n  renderers: IsoSurface\n\nUGRID/NOAA-geoflow/large:\n  files: Source/UGRID/NOAA-geoflow/large/*.nc\n  type: ugrid\n  renderers:\n    Image:\n    Flow3D:\n      XFieldVariable: v1\n      YFieldVariable: v2\n      ZFieldVariable: v3\n\nUGRID/NOAA-geoflow/small:\n  files: Source/UGRID/NOAA-geoflow/small/*.nc\n  type: ugrid\n  renderers:\n    Image:\n    Flow3D:\n      XFieldVariable: v1\n      YFieldVariable: v2\n      ZFieldVariable: v3\n\nUGRID/NOAA-geoflow/2D:\n  files: Source/UGRID/NOAA-geoflow/2D/*.nc\n  type: ugrid\n  renderers:\n    TwoDData:\n    Image:\n    Flow2D:\n      XFieldVariable: v1\n      YFieldVariable: v2\n\n"
  },
  {
    "path": "test_apps/render_regression_tests/run_config.py",
    "content": "import sys, os\nfrom glob import glob\nfrom shutil import copyfile\nimport fnmatch\nimport yaml, pprint\nimport subprocess\nimport jinja2\nfrom itertools import *\nimport concurrent.futures\n\ndef ParseAruments() -> (dict, dict):\n    import argparse\n    parser = argparse.ArgumentParser()\n    parser.add_argument('configPath')\n    parser.add_argument('-n', '--dryRun', action='store_true')\n    parser.add_argument('-j', '--jobs', type=int, default=1)\n    parser.add_argument('-o', '--outDir')\n    parser.add_argument('-t', '--testName', help=\"Run specific test from config.yaml. By default will run all tests.\")\n    args = parser.parse_args()\n\n    with open(args.configPath, \"r\") as f:\n        environment = jinja2.Environment()\n        template = environment.from_string(f.read())\n        config, tests = yaml.safe_load_all(template.render(glob=glob))\n\n    config['dryRun'] = args.dryRun\n    config['jobs'] = args.jobs\n    if args.outDir: config['outDir'] = args.outDir\n    config['onlyRunTestName'] = args.testName\n\n    config.setdefault('resolution', [600, 480])\n\n    return config, tests\n\n\ndef mkdir(path):\n    os.makedirs(path, exist_ok=True)\n\ndef extract(d:dict, k, default=None):\n    v = d.get(k, default)\n    if k in d: del d[k]\n    return v\n\ndef alwaysList(x):\n    if x is None: return []\n    if isinstance(x, list): return x\n    if isinstance(x, dict): return list(x.items())\n    return [x]\n\ndef alwaysDict(x):\n    if x is None: return {}\n    if isinstance(x, dict): return x\n    if isinstance(x, list):\n        assert len(set(x)) == len(x)\n        return {k:None for k in x}\n    return {x: None}\n\ndef alwaysIterable(x):\n    if x is None: return iter(())\n    if isinstance(x, str): return iter((x,))\n    try: return iter(x)\n    except TypeError: return iter((x,))\n\ndef locateRelPath(path, root):\n    if os.path.isabs(path):\n        return path\n    return os.path.join(root, path)\n\ndef GetConfigForCompletedRun(newConfig):\n    if not os.path.exists(newConfig['outputLog']): return None\n    with open(newConfig['outputLog'], \"r\") as log:\n        lines = log.readlines()\n        oldConfigYaml = ''.join(lines[lines.index(\"=========== CONFIG ===========\\n\")+1:lines.index(\"==============================\\n\")])\n        return yaml.safe_load(oldConfigYaml)\n\nimport signal\nimport psutil\n\ngotKeyboardInterrupt = False\n\ndef signal_handler(sig, frame):\n    global gotKeyboardInterrupt\n    gotKeyboardInterrupt = True\n    current_process = psutil.Process()\n    children = current_process.children(recursive=True)\n    for child in children:\n        signal.pthread_kill(child.pid, signal.SIGKILL)\n    print('******* Jobs cancelled *******')\nsignal.signal(signal.SIGINT, signal_handler)\n\ndef RunTest(config):\n    if os.path.exists(config['output']) and os.path.exists(config['outputLog']):\n        with open(config['outputLog'], \"r\") as log:\n            if \"=========== TEST COMPLETE ===========\" in log.read():\n                if config == GetConfigForCompletedRun(config):\n                    # print(\"Skipping test\", config['name'], config['renderer'])\n                    return\n                else:\n                    print(\"Config changed for\", config['name'])\n    print(\"Run test\", config['name'], config['renderer'])\n    cmd = ['python', '-u', 'run_test.py', yaml.dump(config)]\n\n    with open(config['outputLog'], \"w\", 1) as log:\n        try:\n            subprocess.run(cmd, stdout=log, stderr=subprocess.STDOUT, text=True)\n        except Exception:\n            pass\n        if gotKeyboardInterrupt:\n            print(\"Stopped\", config['name'], config['renderer'])\n            return\n        print(\"\\n=========== TEST COMPLETE ===========\\n\", file=log)\n        if not os.path.exists(config['output']):\n            copyfile(\"missing.png\", config['output'])\n\ndef TestCanBeRunConcurrently(test:dict) -> bool:\n    return test.get('runConcurrently', True)\n\ndef GenerateTests(config, tests):\n    for name, test in tests.items():\n        file_globs = [locateRelPath(f, config['dataRootDir']) for f in alwaysList(extract(test, 'files'))]\n        files = sorted(chain.from_iterable(map(glob, file_globs)))\n        dataType = extract(test, 'type')\n\n        if not files:\n            print(\"WARNING: files not found:\", file_globs)\n\n        if extract(test, 'skip'):\n            continue\n\n        renderers:dict = alwaysDict(extract(test, 'renderers', config['rendererSets']['default']))\n        for k in renderers.copy():\n            if k in config['rendererSets']:\n                del renderers[k]\n                for r, v in alwaysDict(config['rendererSets'][k]).items():\n                    renderers.setdefault(r, v)\n\n        for ren, renConfig in renderers.items():\n            if isinstance(renConfig, str):\n                renConfig = {'variable': renConfig}\n\n            renConfig = alwaysDict(renConfig)\n            variableKeys = [k for k in renConfig if 'variable' in k.lower()]\n            variables = [i for i in renConfig.items() if i[0] in variableKeys]\n            for k,_ in variables:\n                del renConfig[k]\n\n            varCombos = [*product(*[[*zip(repeat(k), alwaysList(v))] for k,v in variables])]\n\n            for combo in varCombos:\n                fullName = f\"{name}-{ren}\"\n                if len(varCombos) > 1:\n                    fullName += '-'.join(['', *chain.from_iterable(combo)])\n                fName = fullName + \".png\"\n                fName = fName.replace('/', '-')\n\n                yield {\n                    'name': name,\n                    'outputDir': config['outDir'],\n                    'outputName': fName,\n                    'output': f\"{config['outDir']}/{fName}\",\n                    'outputSession': f\"{config['outDir']}/meta/{fName}.vs3\",\n                    'outputLog': f\"{config['outDir']}/meta/{fName}.log\",\n                    'files': files,\n                    'type': dataType,\n                    'renderer': ren,\n                    'dryRun': config['dryRun'],\n                    'resolution': config['resolution'],\n                    **dict(combo),\n                    **renConfig,\n                    **test,\n                }\n\n\nif __name__ == \"__main__\":\n    config, testConfigs = ParseAruments()\n\n    # print(\"config = \", end='')\n    # pprint.PrettyPrinter(indent=4).pprint(config)\n\n    mkdir(config['outDir'])\n    mkdir(f\"{config['outDir']}/meta\")\n\n    tests = GenerateTests(config, testConfigs)\n    if config['onlyRunTestName']:\n        tests = filter(lambda t: fnmatch.fnmatch(t['name'], config['onlyRunTestName']), tests)\n\n    tests = list(tests)\n    nJobs = config.get('jobs', 1)\n\n    if nJobs > 1:\n        concurrentTests = filter(TestCanBeRunConcurrently, tests)\n        singleTests = filter(lambda t: not TestCanBeRunConcurrently(t), tests)\n    else:\n        singleTests = tests\n        concurrentTests = []\n\n    if concurrentTests:\n        print(f\"Running concurrent tests with {nJobs} jobs\")\n        with concurrent.futures.ThreadPoolExecutor(max_workers=nJobs) as executor:\n            executor.map(RunTest, concurrentTests)\n\n    if singleTests:\n        print(f\"Running single-threaded tests\")\n        for test in singleTests:\n            RunTest(test)\n"
  },
  {
    "path": "test_apps/render_regression_tests/run_test.py",
    "content": "import os.path\nimport sys\n\nconfigExample = \"\"\"\noutput: out.png\nfiles:\n  - /Users/stasj/Work/data/DUKU/DUKU-3.2.0.alpha.nc\ntype: vdc\nrenderer: TwoDData\nvariable: ALBEDO\ntimestep: 0\n\"\"\"\n\ntry:\n    configText = sys.argv[1]\nexcept IndexError:\n    configText = configExample\n    print(\"WARNING: Missing config\")\ndryRun = True if len(sys.argv) >= 3 and sys.argv[2] == '-n' else False\n\nprint(\"=========== CONFIG ===========\")\nprint(configText)\nprint(\"==============================\")\nprint()\n\nimport yaml\nconfig:dict = yaml.safe_load(configText)\n# print(\"config =\", config)\ndryRun = dryRun or config.get('dryRun', False)\n\nif dryRun:\n    exit(0)\n\nsys.path.append(\"vapor_module_dir\")\nimport vapor.session\nses = vapor.session.Session()\n\ndataset = ses.OpenDataset(config['type'], config['files'])\n\nif 'resolution' in config:\n    ses.SetResolution(config['resolution'][0], config['resolution'][1])\n\nprint(dataset)\nfor n in [2,3]:\n    print(f\"\\t {n}D Vars: {', '.join(dataset.GetDataVarNames(n))}\")\n\nif 'timestep' in config:\n    print(\"Setting timestep to\", config['timestep'])\n    ses.SetTimestep(config['timestep'])\n\ndef GetRendererClass(typ:str):\n    typ = typ.removesuffix(\"2D\")\n    typ = typ.removesuffix(\"3D\")\n    for Class in vapor.renderer.Renderer.__subclasses_rec__():\n        if Class.VaporName == typ:\n            return Class\n\nren = dataset.NewRenderer(GetRendererClass(config['renderer']))\nif config['renderer'].endswith(\"2D\"): ren.SetDimensions(2)\nif config['renderer'].endswith(\"3D\"): ren.SetDimensions(3)\nprint(ren)\n\nfor var in [k for k in config.keys() if 'variable' in k.lower()]:\n    setter = f\"Set{var[0].upper()+var[1:]}Name\"\n    varName = config[var]\n    print(f\"ren.{setter}({varName})\")\n    ren.__getattribute__(setter)(varName)\n\n# for c in config.get('commands', []):\n\nif 'IsoValues' in config: ren.SetIsoValues(config['IsoValues'])\n\n\nses.GetCamera().ViewAll()\nif 'outputSession' in config:\n    ses.Save(config['outputSession'])\nses.Render(config['output'])\n"
  },
  {
    "path": "test_apps/smokeTests/CMakeLists.txt",
    "content": "add_executable (\n    testGrid \n    testGrid.cpp \n    gridTools.cpp \n    gridTools.h\n)\nset_target_properties(testGrid PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${test_output_dir}\")\n\nadd_executable (\n    testDataMgr \n    testDataMgr.cpp \n    dataMgrTools.cpp \n    dataMgrTools.h \n    gridTools.cpp\n    gridTools.h\n)\nset_target_properties(testDataMgr PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${test_output_dir}\")\n\ntarget_link_libraries (testGrid common vdc wasp)\ntarget_link_libraries (testDataMgr common vdc wasp)\n"
  },
  {
    "path": "test_apps/smokeTests/dataMgrTools.cpp",
    "content": "#include <sstream>\n\n#include \"gridTools.h\"\n#include \"dataMgrTools.h\"\n\nint TestDataMgr(const std::string &fileType, size_t memsize, size_t nthreads, const std::vector<std::string> &files, const std::vector<std::string> &options, bool silenceTime)\n{\n    VAPoR::DataMgr dataMgr(fileType, memsize, nthreads);\n    int            rc = dataMgr.Initialize(files, options);\n    if (rc < 0) {\n        cerr << \"Failed to intialize WRF DataMGR\" << endl;\n        return -1;\n    }\n\n    PrintDimensions(dataMgr);\n    PrintMeshes(dataMgr);\n    PrintVariables(dataMgr);\n    TestVariables(dataMgr, silenceTime);\n    PrintCoordVariables(dataMgr);\n    PrintTimeCoordinates(dataMgr);\n\n    return 0;\n}\n\nvoid PrintDimensions(const VAPoR::DataMgr &dataMgr)\n{\n    vector<string> dimnames;\n    dimnames = dataMgr.GetDimensionNames();\n    cout << endl << \"Dimensions:\" << endl;\n    for (int i = 0; i < dimnames.size(); i++) {\n        VAPoR::DC::Dimension dimension;\n        dataMgr.GetDimension(dimnames[i], dimension, -1);\n        cout << \"    \" << dimension.GetName() << \" = \" << dimension.GetLength() << endl;\n        cout << \"    Time Varying: \" << dimension.IsTimeVarying() << endl;\n    }\n    cout << endl;\n}\n\nvoid PrintMeshes(const VAPoR::DataMgr &dataMgr, bool verbose)\n{\n    vector<string> meshnames;\n    cout << \"Meshes:\" << endl;\n    meshnames = dataMgr.GetMeshNames();\n    for (int i = 0; i < meshnames.size(); i++) {\n        cout << \"    \" << meshnames[i] << endl;\n        if (verbose) {\n            VAPoR::DC::Mesh mesh;\n            dataMgr.GetMesh(meshnames[i], mesh);\n            cout << mesh;\n        }\n    }\n    cout << endl;\n}\n\nvoid PrintCoordVariables(const VAPoR::DataMgr &dataMgr)\n{\n    cout << \"Projection String:  \" << dataMgr.GetMapProjection() << endl << endl;\n    cout << \"Coordinate Variables:\" << endl;\n    std::vector<std::string> coordVars = dataMgr.GetCoordVarNames();\n    for (int i = 0; i < coordVars.size(); i++) { cout << \"    \" << coordVars[i] << endl; }\n    cout << endl;\n}\n\nvoid PrintTimeCoordinates(const VAPoR::DataMgr &dataMgr)\n{\n    std::vector<double> timeCoords = dataMgr.GetTimeCoordinates();\n    cout << \"Time Coordinates:\" << endl;\n    auto oldPrecision = std::cout.precision(10);\n    for (int i = 0; i < timeCoords.size(); i++) { cout << \"    \" << timeCoords[i] << endl; }\n    std::cout.precision(oldPrecision);\n    cout << endl;\n    cout << \"Time coordinate variable name: \";\n    cout << dataMgr.GetTimeCoordVarName() << endl;\n    cout << \"Number of time steps: \";\n    cout << dataMgr.GetNumTimeSteps() << endl;\n}\n\nvoid PrintCompressionInfo(const VAPoR::DataMgr &dataMgr, const std::string &varname)\n{\n    cout << \"Compression Info for variable \" << varname << \":\" << endl;\n\n    cout << \"    Refinement Levels:  \" << dataMgr.GetNumRefLevels(varname) << endl;\n\n    std::stringstream   ss;\n    std::vector<size_t> cRatios = dataMgr.GetCRatios(varname);\n    for (size_t i = 0; i < cRatios.size(); i++) {\n        if (i != 0) ss << \" \";\n        ss << cRatios[i];\n    }\n    std::string s = ss.str();\n    cout << \"    Compression Ratios: \" << s << endl << endl;\n}\n\nvoid PrintVariables(const VAPoR::DataMgr &dataMgr, bool verbose, bool testVars)\n{\n    vector<string> vars;\n\n    for (int d = 1; d < 4; d++) {\n        vars = dataMgr.GetDataVarNames(d);\n        if (!vars.size()) continue;\n        cout << d << \"D variables: \" << endl;\n        ;\n        for (int i = 0; i < vars.size(); i++) {\n            cout << \"    \" << vars[i] << endl;\n            if (verbose) {\n                VAPoR::DC::DataVar datavar;\n                dataMgr.GetDataVarInfo(vars[i], datavar);\n                cout << datavar;\n            }\n        }\n        cout << endl;\n    }\n}\n\nvoid TestVariables(VAPoR::DataMgr &dataMgr, bool silenceTime)\n{\n    vector<string> vars;\n    for (int d = 1; d < 4; d++) {\n        vars = dataMgr.GetDataVarNames(d);\n        if (vars.size()) {\n            std::string varName = vars[0];\n            PrintCompressionInfo(dataMgr, varName);\n            VAPoR::CoordType minExt, maxExt;\n            dataMgr.GetVariableExtents(0, varName, -1, -1, minExt, maxExt);\n\n            // Reduce extents about the center of the volume to speed tests\n            for (int i = 0; i < minExt.size(); i++) {\n                double center = (maxExt[i] + minExt[i]) / 2.0;\n                double width = (maxExt[i] - minExt[i]) / 32.0;\n                minExt[i] = center - (width / 2.0);\n                maxExt[i] = center + (width / 2.0);\n            }\n\n            VAPoR::Grid *grid = dataMgr.GetVariable(0, varName, -1, -1, minExt, maxExt);\n            if (!grid) {\n                cerr << \"Failed to read variable \" << varName << endl;\n                exit(1);\n            }\n            double rms;\n            size_t numMissingValues;\n            size_t disagreements;\n            CompareIndexToCoords(grid, rms, numMissingValues, disagreements);\n            cout << \"Grid test for \" << d << \"D variable \" << varName << \":\" << endl;\n            cout << \"    # Dimensions:       \" << dataMgr.GetNumDimensions(varName) << endl;\n\n            std::vector<size_t> dimLens;\n            dataMgr.GetDimLens(varName, dimLens, 0);\n            std::stringstream ss;\n            for (size_t i = 0; i < dimLens.size(); i++) {\n                if (i != 0) ss << \" \";\n                ss << dimLens[i];\n            }\n            std::string s = ss.str();\n            cout << \"    Dimension Lengths:  \" << s << endl;\n            cout << \"    Topology Dimension: \" << dataMgr.GetVarTopologyDim(varName) << endl;\n            cout << endl;\n            PrintStats(rms, numMissingValues, disagreements, 0.0, silenceTime);\n        }\n    }\n}\n"
  },
  {
    "path": "test_apps/smokeTests/dataMgrTools.h",
    "content": "#pragma once\n\n#include <iostream>\n\n#include <vapor/DataMgr.h>\n\nint TestDataMgr(const std::string &fileType, size_t memsize, size_t nthreads, const std::vector<std::string> &files, const std::vector<std::string> &options, bool silenceTime);\n\nvoid PrintDimensions(const VAPoR::DataMgr &dataMgr);\n\nvoid PrintMeshes(const VAPoR::DataMgr &dataMgr, bool verbose = false);\n\nvoid PrintCoordVariables(const VAPoR::DataMgr &dataMgr);\n\nvoid PrintTimeCoordinates(const VAPoR::DataMgr &dataMgr);\n\nvoid PrintVariables(const VAPoR::DataMgr &dataMgr, bool verbose = false, bool testVars = false);\n\nvoid PrintCompressionInfo(const VAPoR::DataMgr &dataMgr, const std::string &varname);\n\nvoid TestVariables(VAPoR::DataMgr &dataMgr, bool siclenceTime);\n"
  },
  {
    "path": "test_apps/smokeTests/gridTools.cpp",
    "content": "#include <iostream>\n#include <iomanip>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cmath>\n#include <cstdio>\n#include <string>\n#include <algorithm>\n#include <memory>\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/DataMgr.h>\n#include <vapor/FileUtils.h>\n#include <vapor/utils.h>\n\n#include \"vapor/VAssert.h\"\n#include \"gridTools.h\"\n\n#include <vapor/ConstantGrid.h>\n\n#include <float.h>\n#include <cmath>\n#include <random>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nenum interpOrder { nearestNeighbor = 0, linear = 1 };\n\nnamespace {\nsize_t X = 0;\nsize_t Y = 1;\nsize_t Z = 2;\n\nstd::vector<void *> Heap;\n}    // namespace\n\nvoid DeleteHeap()\n{\n    for (size_t i = 0; i < Heap.size(); i++) std::free(Heap[i]);\n}\n\ntemplate<typename T> vector<T *> AllocateBlocksType(const vector<size_t> &bs, const vector<size_t> &dims)\n{\n    size_t block_size = 1;\n    size_t nblocks = 1;\n\n    for (size_t i = 0; i < bs.size(); i++) {\n        block_size *= bs[i];\n\n        VAssert(dims[i] > 0);\n        size_t nb = ((dims[i] - 1) / bs[i]) + 1;\n\n        nblocks *= nb;\n    }\n\n    void *tmp = std::malloc(sizeof(T) * nblocks * block_size);\n    T *   buf = static_cast<T *>(tmp);\n\n    Heap.push_back(tmp);\n\n    std::vector<T *> blks;\n    for (size_t i = 0; i < nblocks; i++) { blks.push_back(buf + i * block_size); }\n    return (blks);\n}\n\nvector<float *> AllocateBlocks(const vector<size_t> &bs, const vector<size_t> &dims) { return (AllocateBlocksType<float>(bs, dims)); }\n\nvoid MakeTriangle(Grid *grid, float minVal, float maxVal, bool addRandomMissingValues)\n{\n    auto   dims = grid->GetDimensions();\n    size_t x = dims[X];\n    size_t y = dims[Y];\n    size_t z = dims[Z];\n\n    std::mt19937                    engine(0);    // Fixed seed of 0\n    std::uniform_int_distribution<> distrib(0, 9);\n\n    float value = minVal;\n    float missingValue = grid->GetMissingValue();\n    for (size_t k = 0; k < z; k++) {\n        for (size_t j = 0; j < y; j++) {\n            for (size_t i = 0; i < x; i++) {\n                value = value == minVal ? maxVal : minVal;\n                if (addRandomMissingValues) {\n                    if (!distrib(engine))\n                        grid->SetValueIJK(i, j, k, missingValue);\n                    else grid->SetValueIJK(i, j, k, value);\n                }\n                else grid->SetValueIJK(i, j, k, value);\n            }\n        }\n    }\n}\n\nvoid MakeConstantField(Grid *grid, float value, bool addRandomMissingValues)\n{\n    auto   dims = grid->GetDimensions();\n    size_t x = dims[X];\n    size_t y = dims[Y];\n    size_t z = dims[Z];\n\n    std::mt19937                    engine(0);    // Fixed seed of 0\n    std::uniform_int_distribution<> distrib(0, 9);\n\n    float missingValue = grid->GetMissingValue();\n    for (size_t k = 0; k < z; k++) {\n        for (size_t j = 0; j < y; j++) {\n            for (size_t i = 0; i < x; i++) { \n                if (addRandomMissingValues) {\n                    if (!distrib(engine))\n                        grid->SetValueIJK(i, j, k, missingValue);    // Generate random 1 or 0\n                    else grid->SetValueIJK(i, j, k, value);\n                }\n                else grid->SetValueIJK(i, j, k, value);\n            }\n        }\n    }\n}\n\nvoid MakeRamp(Grid *grid, float minVal, float maxVal, bool addRandomMissingValues)\n{\n    auto   dims = grid->GetDimensions();\n    size_t x = dims[X];\n    size_t y = dims[Y];\n    size_t z = dims[Z];\n\n    float increment = (maxVal - minVal) / ((x * y * z - 1) == 0 ? 1 : (x * y * z - 1));\n\n    std::mt19937                    engine(0);    // Fixed seed of 0\n    std::uniform_int_distribution<> distrib(0, 9);\n\n    float value = minVal; \n    float missingValue = grid->GetMissingValue();\n    for (size_t k = 0; k < z; k++) {\n        for (size_t j = 0; j < y; j++) {\n            for (size_t i = 0; i < x; i++) {\n                if (addRandomMissingValues) {\n                    if (!distrib(engine))\n                        grid->SetValueIJK(i, j, k, missingValue);    // Generate random 1 or 0\n                    else grid->SetValueIJK(i, j, k, value);\n                }\n                else grid->SetValueIJK(i, j, k, value);\n                value += increment;\n            }\n        }\n    }\n}\n\nvoid MakeRampOnAxis(Grid *grid, float minVal, float maxVal, size_t axis = X, bool addRandomMissingValues)\n{\n    auto   dims = grid->GetDimensions();\n    size_t x = dims[X];\n    size_t y = dims[Y];\n    size_t z = dims[Z];\n\n    float xIncrement = axis == X ? (maxVal - minVal) / (dims[X] - 1) : 0;\n    float yIncrement = axis == Y ? (maxVal - minVal) / (dims[Y] - 1) : 0;\n    float zIncrement = axis == Z ? (maxVal - minVal) / (dims[Z] - 1) : 0;\n\n    std::mt19937                    engine(0);    // Fixed seed of 0\n    std::uniform_int_distribution<> distrib(0, 9);\n\n    float value = minVal;\n    float missingValue = grid->GetMissingValue();\n    for (size_t k = 0; k < z; k++) {\n        value = axis == Y ? minVal : value;    // reset value if we're ramping on Y\n        for (size_t j = 0; j < y; j++) {\n            value = axis == X ? minVal : value;    // reset value if we're ramping on X\n            for (size_t i = 0; i < x; i++) {\n                if (addRandomMissingValues) {\n                    if (!distrib(engine))\n                        grid->SetValueIJK(i, j, k, missingValue);    // Generate random 1 or 0\n                    else grid->SetValueIJK(i, j, k, value);\n                }\n                else grid->SetValueIJK(i, j, k, value);\n                value += xIncrement;\n            }\n            value += yIncrement;\n        }\n        value += zIncrement;\n    }\n}\n\n// This function iterates across all nodes in a grid; making comparisons between the\n// data values returned by the functions GetValueAtIndex() and GetValue().\nbool CompareIndexToCoords(VAPoR::Grid *grid,\n                          double &     rms,                 // Root Mean Square error\n                          size_t &     numMissingValues,    // Counter for receiving MissingValue upon query\n                          size_t &     disagreements        // Counter for when GetValueAtIndex() and GetValue() disagree\n)\n{\n    bool rc = true;\n\n    rms = 0.f;\n    disagreements = 0;\n    numMissingValues = 0;\n\n    auto   dims = grid->GetDimensions();\n    size_t x = dims[X];\n    size_t y = dims[Y];\n    size_t z = dims[Z];\n\n    double peak = 0.f;\n    double sum = 0;\n    for (size_t k = 0; k < z; k++) {\n        for (size_t j = 0; j < y; j++) {\n            for (size_t i = 0; i < x; i++) {\n                DimsType indices = {i, j, k};\n                double   trueValue = grid->GetValueAtIndex(indices);\n\n                CoordType coords;\n                grid->GetUserCoordinates(indices, coords);\n                float sampleValue = grid->GetValue(coords);\n\n                float mv = grid->GetMissingValue();\n                if (trueValue == mv || sampleValue == mv) {\n                    numMissingValues++;\n\n                    // If missing value is not finite we can't do\n                    // floating point operations (i.e. computer error)\n                    //\n                    if (sampleValue != trueValue) { disagreements++; }\n                    continue;\n                }\n\n                double error = abs(sampleValue - trueValue);\n\n                if (!Wasp::NearlyEqual(error, 0.0)) { disagreements++; }\n\n                if (error > peak) peak = error;\n                sum += error * error;\n            }\n        }\n    }\n\n    rms = sqrt(sum / (x * y * z));\n\n    if ((!Wasp::NearlyEqual(rms, 0.0)) || disagreements > 0) rc = false;\n    return rc;\n}\n\nbool TestIterator(Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time)\n{\n    bool rc = true;\n    count = 0;\n    expectedCount = 1;\n    disagreements = 0;\n    double t0 = Wasp::GetTime();\n\n    Grid::Iterator itr;\n    Grid::Iterator enditr = g->end();\n\n    itr = g->begin();\n\n    auto dims = g->GetDimensions();\n    for (auto dim : dims) expectedCount *= dim;\n\n    for (; itr != enditr; ++itr) {\n        DimsType ijk;\n        Wasp::VectorizeCoords(count, dims.data(), ijk.data(), dims.size());\n\n        if (!Wasp::NearlyEqual(*itr, g->GetValueAtIndex(ijk))) { disagreements++; }\n\n        count++;\n    }\n\n    time = Wasp::GetTime() - t0;\n\n    if (expectedCount != count || disagreements > 0) { rc = false; }\n    return rc;\n}\n\nbool TestConstCoordItr(const Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time)\n{\n    bool rc = true;\n    count = 0;\n    expectedCount = 1;\n    disagreements = 0;\n    double t0 = Wasp::GetTime();\n\n    Grid::ConstCoordItr itr;\n    Grid::ConstCoordItr enditr = g->ConstCoordEnd();\n\n    itr = g->ConstCoordBegin();\n\n    auto dims = g->GetDimensions();\n    for (auto dim : dims) expectedCount *= dim;\n\n    for (; itr != enditr; ++itr) {\n        DimsType ijk;\n        Wasp::VectorizeCoords(count, dims.data(), ijk.data(), dims.size());\n        CoordType coords;\n\n        bool disagree = false;\n        g->GetUserCoordinates(ijk, coords);\n        for (size_t dim = 0; dim < g->GetGeometryDim(); dim++) {\n            if (!Wasp::NearlyEqual((*itr)[dim], coords[dim])) { disagree = true; }\n        }\n        if (disagree) { disagreements++; }\n\n        count++;\n    }\n\n    time = Wasp::GetTime() - t0;\n\n    if (expectedCount != count || disagreements > 0) { rc = false; }\n    return rc;\n}\n\nvoid PrintStats(double rms, size_t numMissingValues, size_t disagreements, double time, bool silenceTime)\n{\n    cout << \"    RMS error:                                           \" << rms << endl;\n    cout << \"    Missing value count:                                 \" << numMissingValues << endl;\n    cout << \"    GetValueAtIndex() vs GetValue() disagreement count:  \" << disagreements << endl;\n    if (!silenceTime) cout << \"    Time:                                                \" << time << endl;\n    cout << endl;\n}\n\n// Copy of Grid::GetRange() function from VAPOR release 3.6\n//\nvoid GetRange_36(VAPoR::Grid* g, float range[2])\n{\n    float missingValue = g->GetMissingValue();\n    auto itr = g->cbegin();\n    auto enditr = g->cend();\n\n    // Edge case: all values are missing values.\n    //\n    range[0] = range[1] = missingValue;\n    while (*itr == missingValue && itr != enditr) { ++itr; }\n    if (itr == enditr) return;\n\n    range[0] = *itr;\n    range[1] = range[0];\n    while (itr != enditr) {\n        if (*itr < range[0] && *itr != missingValue)\n            range[0] = *itr;\n        else if (*itr > range[1] && *itr != missingValue)\n            range[1] = *itr;\n        ++itr;\n    }\n}\n\nbool RunTests(Grid *grid, const std::vector<std::string> &tests, float minVal, float maxVal, bool silenceTime)\n{\n    auto   dims = grid->GetDimensions();\n    size_t x = dims[X];\n    size_t y = dims[Y];\n    size_t z = dims[Z];\n\n    bool        rc = true;\n    std::string type = grid->GetType();\n\n    cout << \"=======================================================\" << endl << endl;\n    if (std::find(tests.begin(), tests.end(), \"Constant\") != tests.end()) {\n        cout << type << \" \" << x << \":\" << y << \":\" << z << \" Constant field:\" << endl;\n        MakeConstantField(grid, maxVal);\n\n        grid->SetInterpolationOrder(linear);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n\n        grid->SetInterpolationOrder(nearestNeighbor);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n    }\n\n    if (std::find(tests.begin(), tests.end(), \"Ramp\") != tests.end()) {\n        cout << type << \" \" << x << \":\" << y << \":\" << z << \" Ramp up through domain:\" << endl;\n        MakeRamp(grid, minVal, maxVal);\n\n        grid->SetInterpolationOrder(linear);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n\n        grid->SetInterpolationOrder(nearestNeighbor);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n    }\n\n    if (std::find(tests.begin(), tests.end(), \"RampOnAxis\") != tests.end()) {\n        cout << type << \" \" << x << \":\" << y << \":\" << z << \" Ramp up on Z axis:\" << endl;\n        MakeRampOnAxis(grid, minVal, maxVal, Z);\n        grid->SetInterpolationOrder(linear);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n\n        grid->SetInterpolationOrder(nearestNeighbor);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n    }\n\n    if (std::find(tests.begin(), tests.end(), \"Triangle\") != tests.end()) {\n        cout << type << \" \" << x << \":\" << y << \":\" << z << \" Triangle signal:\" << endl;\n        MakeTriangle(grid, minVal, maxVal);\n\n        grid->SetInterpolationOrder(linear);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n        RunTest(grid, silenceTime);\n\n        grid->SetInterpolationOrder(nearestNeighbor);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n    }\n\n    if (std::find(tests.begin(), tests.end(), \"AllMissingValues\") != tests.end()) {\n        cout << type << \" \" << x << \":\" << y << \":\" << z << \" All missing values:\" << endl;\n        MakeConstantField(grid, grid->GetMissingValue());\n\n        grid->SetInterpolationOrder(linear);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n\n        grid->SetInterpolationOrder(nearestNeighbor);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n    }\n    if (std::find(tests.begin(), tests.end(), \"NoMissingValues\") != tests.end()) {\n        cout << type << \" \" << x << \":\" << y << \":\" << z << \" No missing values:\" << endl;\n        MakeRamp(grid, minVal, maxVal, false);\n\n        grid->SetInterpolationOrder(linear);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n\n        grid->SetInterpolationOrder(nearestNeighbor);\n        if (RunTest(grid, silenceTime) == false) { rc = false; }\n    }\n    // Iterator tests\n\n    size_t count;\n    size_t expectedCount;\n    size_t disagreements;\n    double time;\n\n    if (TestIterator(grid, count, expectedCount, disagreements, time) == false) { rc = false; }\n\n    PrintGridIteratorResults(type, \"Iterator\", count, expectedCount, disagreements, time, silenceTime);\n\n    if (TestConstCoordItr(grid, count, expectedCount, disagreements, time) == false) { rc = false; }\n\n    PrintGridIteratorResults(type, \"ConstCoordIterator\", count, expectedCount, disagreements, time, silenceTime);\n\n    if (TestConstNodeIterator(grid, count, expectedCount, disagreements, time, false) == false) { rc = false; }\n\n    PrintGridIteratorResults(type, \"ConstNodeIterator\", count, expectedCount, disagreements, time, silenceTime);\n\n    if (TestConstNodeIterator(grid, count, expectedCount, disagreements, time, true) == false) { rc = false; }\n\n    PrintGridIteratorResults(type, \"ConstNodeIterator with bounds\", count, expectedCount, disagreements, time, silenceTime);\n\n    return rc;\n}\n\nbool TestConstNodeIterator(const Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time, bool withCoordBounds)\n{\n    bool rc = true;\n    count = 0;\n    expectedCount = 1;\n    disagreements = 0;\n    double t0 = Wasp::GetTime();\n\n    Grid::ConstNodeIterator itr;\n    Grid::ConstNodeIterator enditr = g->ConstNodeEnd();\n\n    if (withCoordBounds) {\n        CoordType minu, maxu;\n        g->GetUserExtents(minu, maxu);\n        itr = g->ConstNodeBegin(minu, maxu);\n    } else {\n        itr = g->ConstNodeBegin();\n    }\n\n    auto dims = g->GetDimensions();\n    for (auto dim : dims) expectedCount *= dim;\n\n    for (; itr != enditr; ++itr) {\n        DimsType ijk3 = {0, 0, 0};\n        Wasp::VectorizeCoords(count, dims.data(), ijk3.data(), dims.size());\n\n        double itrData = g->GetValueAtIndex(*itr);\n        double gridData = g->GetValueAtIndex(ijk3);\n\n        if (!Wasp::NearlyEqual(itrData, gridData)) { disagreements++; }\n\n        count++;\n    }\n\n    time = Wasp::GetTime() - t0;\n\n    if (expectedCount != count || disagreements > 0) { rc = false; }\n    return rc;\n}\n\nbool RunTest(Grid *grid, bool silenceTime)\n{\n    bool   rc = true;\n    double rms;\n    size_t numMissingValues;\n    size_t disagreements;\n    double t0 = Wasp::GetTime();\n\n    rc = CompareIndexToCoords(grid, rms, numMissingValues, disagreements);\n\n    if (grid->GetInterpolationOrder() == 0) {\n        cout << \"  Interpolation order: nearestNeighbor \" << endl;\n    } else {\n        cout << \"  Interpolation order: linear          \" << endl;\n    }\n\n    double time = Wasp::GetTime() - t0;\n\n    PrintStats(rms, numMissingValues, disagreements, time, silenceTime);\n\n    // Test the correctness of OpenMP implementation of Grid::GetRange()\n    float range_36[2] = {0.0, 1.1};\n    float range_omp[2] = {2.2, 3.3};\n    GetRange_36(grid, range_36);\n    grid->GetRange(range_omp);\n    bool omp_good = (range_36[0] == range_omp[0] && range_36[1] == range_omp[1]);\n \n    rc = rc && omp_good;\n\n    if (rc == false) {\n        cout << \"    *** Error reported in \" << grid->GetType() << \" grid ***\" << endl << endl;\n    } else {\n        cout << endl;\n    }\n\n    return rc;\n}\n\nvoid PrintGridIteratorResults(std::string &gridType, std::string itrType, size_t count, size_t expectedCount, size_t disagreements, double time, bool silenceTime)\n{\n    std::string passFail = \" --- PASS\";\n    if (count != expectedCount || disagreements > 0) { passFail = \" --- FAIL\"; }\n\n    cout << gridType << \" Grid::\" << itrType << passFail << endl;\n    cout << \"  Count:                \" << count << endl;\n    cout << \"  Expected Count:       \" << expectedCount << endl;\n    cout << \"  Value Disagreements:  \" << disagreements << endl;\n\n    if (!silenceTime) cout << \"  Time:                 \" << time << endl;\n\n    cout << endl;\n}\n\nVAPoR::CurvilinearGrid *MakeCurvilinearTerrainGrid(const std::vector<size_t> &bs, const std::vector<double> &minu, const std::vector<double> &maxu, const std::vector<size_t> &dims)\n{\n    std::vector<size_t> bs2d = {bs[X], bs[Y]};\n    std::vector<size_t> dims2d = {dims[X], dims[Y]};\n    std::vector<double> minu2d = {minu[X], minu[Y]};\n    std::vector<double> maxu2d = {maxu[X], maxu[Y]};\n\n    std::vector<float *> xblks = AllocateBlocks(bs2d, dims2d);\n    auto                 xrg = std::unique_ptr<RegularGrid>(new RegularGrid(dims2d, bs2d, xblks, minu2d, maxu2d));\n    MakeRampOnAxis(xrg.get(), minu[X], maxu[X], X, false);\n\n    std::vector<float *> yblks = AllocateBlocks(bs2d, dims2d);\n    auto                 yrg = std::unique_ptr<RegularGrid>(new RegularGrid(dims2d, bs2d, yblks, minu2d, maxu2d));\n    MakeRampOnAxis(yrg.get(), minu[Y], maxu[Y], Y, false);\n\n    std::vector<float *> zblks = AllocateBlocks(bs, dims);\n    auto                 zrg = std::unique_ptr<RegularGrid>(new RegularGrid(dims, bs, zblks, minu, maxu));\n    MakeRampOnAxis(zrg.get(), minu[Z], maxu[Z], Z, false);\n\n    std::vector<float *> blks = AllocateBlocks(bs, dims);\n    CurvilinearGrid *    cg = new CurvilinearGrid(dims, bs, blks, *xrg, *yrg, *zrg, NULL);\n\n    return (cg);\n}\n\nLayeredGrid *MakeLayeredGrid(const vector<size_t> &dims, const vector<size_t> &bs, const std::vector<double> &minu, const std::vector<double> &maxu)\n{\n    std::vector<float *> zCoordBlocks = AllocateBlocks(bs, dims);\n\n    RegularGrid rg(dims, bs, zCoordBlocks, minu, maxu);\n    MakeRampOnAxis(&rg, minu[Z], maxu[Z], Z, false);\n\n    double         deltax = dims[X] > 1 ? maxu[X] - minu[X] / (dims[X] - 1) : 1;\n    vector<double> xcoords;\n    for (int i = 0; i < dims[X]; i++) { xcoords.push_back(minu[X] + (i * deltax)); }\n\n    // Get horizontal dimensions\n    //\n    double         deltay = dims[Y] > 2 ? maxu[Y] - minu[Y] / (dims[Y] - 1) : 1;\n    vector<double> ycoords;\n    for (int i = 0; i < dims[Y]; i++) { ycoords.push_back(minu[1] + (i * deltay)); }\n\n    std::vector<float *> dataBlocks = AllocateBlocks(bs, dims);\n    LayeredGrid *        lg = new LayeredGrid(dims, bs, dataBlocks, xcoords, ycoords, rg);\n\n    return (lg);\n}\n\nVAPoR::StretchedGrid *MakeStretchedGrid(const vector<size_t> &dims, const vector<size_t> &bs, const std::vector<double> &minu, const std::vector<double> &maxu)\n{\n    std::vector<double> xCoords(dims[X], 0);\n    std::vector<double> yCoords(dims[Y], 0);\n    std::vector<double> zCoords(dims[Z], 0);\n\n    double xRange = maxu[X] - minu[X];\n    double yRange = maxu[Y] - minu[Y];\n    double zRange = maxu[Z] - minu[Z];\n\n    double xDenom = dims[X] > 1 ? dims[X] - 1 : 1;\n    double yDenom = dims[Y] > 1 ? dims[Y] - 1 : 1;\n    double zDenom = dims[Z] > 1 ? dims[Z] - 1 : 1;\n\n    // Parabolically increasing coordinates\n    for (size_t i = 0; i < dims[X]; i++) {\n        double xIncrement = xRange * pow(float(i) / xDenom, 2.0);\n        xCoords[i] = xIncrement + minu[X];\n    }\n    for (size_t i = 0; i < dims[Y]; i++) {\n        double yIncrement = yRange * pow(float(i) / yDenom, 2.0);\n        yCoords[i] = yIncrement + minu[Y];\n    }\n    for (size_t i = 0; i < dims[Z]; i++) {\n        double zIncrement = zRange * pow(float(i) / zDenom, 2.0);\n        zCoords[i] = zIncrement + minu[Z];\n    }\n\n    vector<float *> blocks = AllocateBlocks(bs, dims);\n    StretchedGrid * sg = new StretchedGrid(dims, bs, blocks, xCoords, yCoords, zCoords);\n    return sg;\n}\n\nVAPoR::UnstructuredGrid2D *MakeUnstructuredGrid2D(const vector<size_t> &dims, const vector<size_t> &bs, const std::vector<double> &minu, const std::vector<double> &maxu)\n{\n    VAssert(dims.size() >= 2);\n    VAssert(bs.size() >= 2);\n\n    vector<size_t>             bs1d = {bs[0] * bs[1]};\n    vector<size_t>             dims1d = {dims[0] * dims[1]};\n    vector<size_t>             vertexDims = {dims[0] * dims[1]};\n    vector<size_t>             faceDims = {(dims[0] - 1) * (dims[1] - 1) * 2};\n    vector<size_t>             edgeDims;\n    UnstructuredGrid::Location location = UnstructuredGrid2D::Location::NODE;\n    size_t                     maxVertexPerFace = 3;    // each cell is a triangle\n    size_t                     maxFacePerVertex = 6;    // each interior vertex defines 6 triangles\n    long                       vertexOffset = 0;\n    long                       faceOffset = 0;\n\n    const int *faceOnFace = NULL;\n\n    std::vector<float *> xCoordBlocks = AllocateBlocksType<float>(bs1d, dims1d);\n    std::vector<float *> yCoordBlocks = AllocateBlocksType<float>(bs1d, dims1d);\n    std::vector<int *>   vertexOnFace = AllocateBlocksType<int>(vector<size_t>{faceDims[0] * maxVertexPerFace}, vector<size_t>{faceDims[0] * maxVertexPerFace});\n\n    size_t face = 0;\n    for (size_t j = 0; j < dims[1] - 1; j++) {\n        for (size_t i = 0; i < dims[0] - 1; i++) {\n            vertexOnFace[0][face + 0] = j * (dims[0]) + i;\n            vertexOnFace[0][face + 1] = j * (dims[0]) + i + 1;\n            vertexOnFace[0][face + 2] = (j + 1) * (dims[0]) + i;\n\n            face += maxVertexPerFace;\n\n            vertexOnFace[0][face + 0] = j * (dims[0]) + i + 1;\n            vertexOnFace[0][face + 1] = (j + 1) * (dims[0]) + i + 1;\n            vertexOnFace[0][face + 2] = (j + 1) * (dims[0]) + i;\n\n            face += maxVertexPerFace;\n        }\n    }\n\n    std::vector<int *> faceOnVertex = AllocateBlocksType<int>(vector<size_t>{vertexDims[0] * maxFacePerVertex}, vector<size_t>{vertexDims[0] * maxFacePerVertex});\n\n\n    // In the diagram below the x's are nodes and the triangle faces are numbered 0 to 7\n    //\n    // The faces connected to the center node (x) are 6,5,4,1,2,3.\n    // The faces connected to the bottom, left node (x) are 0\n    // The faces connected to the bottom, right node (x) are 3,2\n    //\n    //  x---x---x\n    //  |4\\5|6\\7|\n    //  x---x---x\n    //\t|0\\1|2\\3|\n    //  x---x---x\n    //\n    int vertex = 0;\n    for (long j = 0; j < dims[1]; j++) {\n        int leftMostFaceTop = (j * (dims[0] - 1)) * 2;\n        int rightMostFaceTop = leftMostFaceTop + 2 * (dims[0] - 1) - 1;\n\n        int leftMostFaceBot = ((j - 1) * (dims[0] - 1)) * 2;\n        int rightMostFaceBot = leftMostFaceBot + 2 * (dims[0] - 1) - 1;\n\n        for (long i = 0; i < dims[0]; i++, vertex++) {\n            // Initialize to missing faces\n            //\n            int face_i = 0;\n            for (face_i = 0; face_i < maxFacePerVertex; face_i++) { faceOnVertex[0][(vertex * maxFacePerVertex) + face_i] = -1; }\n\n            // No top of triangles for last row of nodes\n            //\n            face_i = 0;\n            if (j < (dims[1] - 1)) {\n                int face = ((j) * ((int)dims[0] - 1) * 2) + (2 * i);\n\n                // top row of triangles - iterate in CC order\n                //\n                for (int ii = 0; ii < 3; ii++, face--) {\n                    if (face < leftMostFaceTop || face > rightMostFaceTop) continue;\n                    faceOnVertex[0][(vertex * maxFacePerVertex) + face_i] = face;\n                    face_i++;\n                }\n            }\n\n            // No bottom row of triangles for first row of nodes\n            //\n            if (j > 0) {\n                int face = ((j - 1) * ((int)dims[0] - 1) * 2) + (2 * i) - 1;\n\n                // bottom row of triangles - iterate in CC order\n                //\n                for (int ii = 0; ii < 3; ii++, face++) {\n                    if (face < leftMostFaceBot || face > rightMostFaceBot) continue;\n                    faceOnVertex[0][(vertex * maxFacePerVertex) + face_i] = face;\n                    face_i++;\n                }\n            }\n        }\n    }\n\n    UnstructuredGridCoordless xug(vertexDims, faceDims, edgeDims, bs1d, xCoordBlocks, 2, vertexOnFace[0], faceOnVertex[0], faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset,\n                                  faceOffset);\n\n    UnstructuredGridCoordless yug(vertexDims, faceDims, edgeDims, bs1d, yCoordBlocks, 2, vertexOnFace[0], faceOnVertex[0], faceOnFace, location, maxVertexPerFace, maxFacePerVertex, vertexOffset,\n                                  faceOffset);\n\n    float deltaX = 1.0 / (dims[0] - 1);\n    float deltaY = 1.0 / (dims[1] - 1);\n    for (long j = 0; j < dims[1]; j++) {\n        for (long i = 0; i < dims[0]; i++) {\n            DimsType indices = {j * dims[0] + i, 0, 0};\n\n            xug.SetValue(indices, i * deltaX);\n            yug.SetValue(indices, j * deltaY);\n        }\n    }\n\n    UnstructuredGridCoordless zug;\n\n    vector<float *>     blocks = AllocateBlocks(bs1d, dims1d);\n    UnstructuredGrid2D *g = new UnstructuredGrid2D(vertexDims, faceDims, edgeDims, bs1d, blocks, vertexOnFace[0], faceOnVertex[0], faceOnFace, location, maxVertexPerFace, maxFacePerVertex,\n                                                   vertexOffset, faceOffset, xug, yug, zug, nullptr);\n\n    return g;\n}\n"
  },
  {
    "path": "test_apps/smokeTests/gridTools.h",
    "content": "#pragma once\n\n#include <vapor/Grid.h>\n#include <vapor/LayeredGrid.h>\n#include <vapor/CurvilinearGrid.h>\n#include <vapor/StretchedGrid.h>\n#include <vapor/UnstructuredGrid2D.h>\n\nvoid DeleteHeap();\n\nstd::vector<float *> AllocateBlocks(const std::vector<size_t> &bs, const std::vector<size_t> &dims);\n\nvoid MakeTriangle(VAPoR::Grid *grid, float minVal, float maxVal, bool addRandomMissingValues=true);\n\nvoid MakeConstantField(VAPoR::Grid *grid, float value, bool addRandomMissingValues=true);\n\nvoid MakeRamp(VAPoR::Grid *grid, float minVal, float maxVal, bool addRandomMissingValues=true);\n\nvoid MakeRampOnAxis(VAPoR::Grid *grid, float minVal, float maxVal, size_t axis, bool addRandomMissingValues=true);\n\nbool CompareIndexToCoords(VAPoR::Grid *grid,\n                          double &     rms,                 // Root Mean Square error\n                          size_t &     numMissingValues,    // Counter for receiving MissingValue upon query\n                          size_t &     disagreements        // Counter for when AccessIJK() and GetValue() disagree\n);\n\n// Returns the expected node count for Grid::Iterator\nbool TestIterator(VAPoR::Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time);\n\n// Returns the expected node count for Grid::ConstCoordIterator\nbool TestConstCoordItr(const VAPoR::Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time);\n\n// Returns the expected node count for Grid::ConstNodeIterator\nbool TestConstNodeIterator(const VAPoR::Grid *g, size_t &count, size_t &expectedCount, size_t &disagreements, double &time, bool withCoordBounds);\n\nvoid PrintStats(double rms, size_t numMissingValues, size_t disagreements, double time, bool silenceTime);\n\nbool RunTests(VAPoR::Grid *grid, const std::vector<std::string> &tests, float minVal, float maxVal, bool silenceTime);\n\nbool RunTest(VAPoR::Grid *grid, bool silenceTime);\n\nvoid PrintGridIteratorResults(std::string &gridType, std::string itrType, size_t count, size_t expectedCount, size_t disagreements, double time, bool silenceTime);\n\nVAPoR::CurvilinearGrid *MakeCurvilinearTerrainGrid(const std::vector<size_t> &bs, const std::vector<double> &minu, const std::vector<double> &maxu, const std::vector<size_t> &dims);\n\nVAPoR::LayeredGrid *MakeLayeredGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<double> &minu, const std::vector<double> &maxu);\n\nVAPoR::StretchedGrid *MakeStretchedGrid(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<double> &minu, const std::vector<double> &maxu);\n\nVAPoR::UnstructuredGrid2D *MakeUnstructuredGrid2D(const std::vector<size_t> &dims, const std::vector<size_t> &bs, const std::vector<double> &minu, const std::vector<double> &maxu);\n\n"
  },
  {
    "path": "test_apps/smokeTests/smokeTests.py",
    "content": "#! /usr/bin/env python3\n\nimport sys\nimport os\nimport subprocess\nimport difflib\nimport argparse\n\n#\n#  Argument Parser\n#\n\nparser = argparse.ArgumentParser(\n    \"A test driver for the DataMgr and Grid classes\"\n)\nparser.add_argument( \n    '-makeBaseline', \n    default=False,\n    dest='makeBaseline',\n    action='store_true',\n    help='This flag makes these test results the baseline on which future'\n    + ' tests will be compared.  If no baseline file exists, this will automatically '\n    + ' be set to true.'\n)\nparser.add_argument( \n    '-testDataRoot', \n    nargs=1,\n    type=str,\n    default=\"~/Data/smokeTestData\", \n    required=False,\n    metavar='/path/to/data',\n    help='Directory where DataMgr test data is stored.'\n)\nparser.add_argument( \n    '-binaryRoot', \n    nargs=1,\n    type=str,\n    default=\"~/VAPOR/build/test_binaries\", \n    required=False,\n    metavar='/path/to/binaries',\n    help='Directory where binary test programs (testGrid, testDataMgr) are stored.'\n)\nparser.add_argument( \n    '-resultsDir', \n    nargs=1,\n    type=str,\n    default=\"~/VAPOR/test_apps/smokeTests/testResults\", \n    required=False,\n    metavar='/path/to/write/results/to',\n    help='Directory where test results are stored.'\n)\nparser.add_argument( \n    '-silenceTime',\n    default=False,\n    dest='silenceTime',\n    action='store_true',\n    help='This flag sliences the elapsed time from the printed results.'\n)\nargs = vars(parser.parse_args())\n\n#\n#  Default directories and test data\n#\n\ngridSizes = [\n#    \"1:1:1\",\n    \"2:2:2\",\n    \"4:2:2\",\n    \"8:2:2\",\n#    \"1:8:8\",\n#    \"8:1:8\",\n#    \"8:8:1\",\n    \"7:7:7\",\n    \"8:8:8\"\n]\n\nresultsDir = os.path.expanduser(\"\".join( args['resultsDir'] ))\nif (resultsDir[-1] != r'/'):\n    resultsDir += r'/'\n\ntestDataRoot = os.path.expanduser(\"\".join( args['testDataRoot'] ))\nif (testDataRoot[-1] != r'/'):\n    testDataRoot += r'/'\n\nbinaryRoot = os.path.expanduser(\"\".join( args['binaryRoot'] ))\nif (binaryRoot[-1] != r'/'):\n    binaryRoot += r'/'\n\nif( args['silenceTime'] ): silenceTime = \"-silenceTime\"\nelse: silenceTime = \"\"\n\nprint(\"resultsDir \" + resultsDir )\nprint(\"testDataRoot \" + testDataRoot)\nprint(\"binaryRoot \" + binaryRoot )\nprint(\"silenceTime \" + str(silenceTime))\n\ndataMgrs = {\n    #\"mpas\" : (testDataRoot + \"hist.mpas-o.0001-01-01_00.00.00.nc\")\n    \"wrf\"  : (testDataRoot + \"wrfout_d02_2005-08-29_05\"),\n    \"cf\"   : (testDataRoot + \"24Maycontrol.04000.000000.nc\"),\n    \"vdc\"  : (testDataRoot + \"katrina_1timeStep.vdc\"),\n}\n\ngridProgram        = binaryRoot + \"testGrid\"\ndataMgrProgram     = binaryRoot + \"testDataMgr\"\ngridResultsFile    = resultsDir + \"gridResults.txt\"\ndataMgrResultsFile = resultsDir + \"dataMgrResults.txt\"\n\n#\n#  Tests\n#\n\ndef testGrid( grid ):\n\n    rc = 0\n\n    print( \"Testing \" + grid + \" grid\" )\n\n    print(\"  Command: \" + gridProgram + \" -dims \" + grid + \" \" + silenceTime )\n    programOutput  = subprocess.run( \n        [ gridProgram, \"-dims\", grid, silenceTime ], \n        stdout=subprocess.PIPE,  \n        universal_newlines=True \n    )\n\n    outputFileName = resultsDir + grid + \".txt\"\n    try:\n        with open( outputFileName, \"w\" ) as outputFile:\n            outputFile.write( programOutput.stdout )\n            outputFile.close()\n            print( \"  \" + outputFileName + \" written\" )\n    except IOError:\n        print( \"Unable to write to file \" + outputFileName )\n        sys.exit(-1)\n\n    if ( programOutput.returncode != 0 ):\n        rc = 1\n        print( \"  Test failed with exit code \" + str(programOutput.returncode) )\n    else:\n        print( \"  Test passed\\n\" )\n\n    return rc\n\ndef testDataMgr( dataMgrType, dataMgr, makeBaseline=False ):\n    print( \"Testing \" + dataMgrType + \" with \" + dataMgr )\n    command = []\n    if( silenceTime != \"\" ):\n        command = [ dataMgrProgram, silenceTime, \"-fileType\", dataMgrType, dataMgr ]\n    else:\n        command = [ dataMgrProgram, \"-fileType\", dataMgrType, dataMgr ]\n    print( \"  Command: \" + \" \".join(command) )\n    programOutput = subprocess.check_output( command )\n    \n    if ( makeBaseline ):\n        outputFileName = resultsDir + dataMgrType + \"_baseline.txt\"\n    else:\n        outputFileName = resultsDir + dataMgrType + \".txt\"\n\n    try:\n        with open( outputFileName, \"w\" ) as outputFile:\n            outputFile = open( outputFileName, \"w\" )\n            outputFile.write( programOutput.decode(\"utf-8\") )\n            outputFile.close()\n            print( \"  \" + outputFileName + \" written\\n\" )\n    except IOError:\n        print( \"Unable to write to file \" + outputFileName )\n        sys.exit(-1)\n    \n    return outputFileName\n\ndef testDataMgrs( makeBaseline ):\n    diff = open( dataMgrResultsFile, \"w\" )\n    \n    mismatches = 0\n\n    for dataType, dataFile in dataMgrs.items():\n\n        # If we're making a baseline file, generate it, and then skip comparisons \n        if ( makeBaseline ):\n            resultsFile = testDataMgr( dataType, dataFile, makeBaseline )\n            continue\n\n        resultsFile = testDataMgr( dataType, dataFile )\n        \n        baselineFile = resultsDir + dataType + \"_baseline.txt\"\n        baseline = open( baselineFile, \"r\" )\n        results  = open( resultsFile, \"r\" )\n        \n        # Note - we are not reading the last line of these files, since it's the\n        # runtime for the test ( hence the [:-1] specification )\n        baselineLines = baseline.readlines()[:-1]\n        resultsLines = results.readlines()[:-1]\n        \n        for line in difflib.unified_diff(resultsLines, baselineLines, resultsFile, baselineFile):\n            diff.write( line )\n            mismatches+=1\n\n        baseline.close()\n        results.close()\n    diff.close()\n\n    if ( makeBaseline == False ):    \n        print( dataMgrResultsFile + \" written\" )\n        print( \"\\n    DataMgr tests resulted in \" + str(mismatches) + \" mismatches\\n\" )\n    else:\n        print( \"Baseline files have been generated.  Re-run smokeTests.py to run comparions.\\n\" )\n\n    if ( mismatches > 0 ):\n        return -1\n    else:\n        return 0\n        \ndef main():\n    makeBaseline = args['makeBaseline']\n\n    rc = 0\n\n    if ( makeBaseline == True ): \n        print( \"    Warning: Some or all baseline files for running DataMgr tests were missing.  \"\n               \"    These files are needed as comparisons for the results of the current series \"\n               \"    of tests, versus a known working build (the baseline).\\n\"\n               \"       Generating baseline files in the results directory....\\n\"\n        )\n\n    if ( os.path.isdir( resultsDir ) == False ):    \n        os.mkdir( resultsDir )\n\n    for grid in gridSizes:\n        if ( testGrid(grid) != 0):\n            print (\"  See artifact file \" + grid + \".txt or \" + resultsDir + grid + \".txt for mismatches\")\n            print (\"  Failed assertions, if any, are shown above.\\n\" )\n            rc = 1\n \n    for dataType, dataFile in dataMgrs.items():\n        baselineFile = resultsDir + dataType + \"_baseline.txt\"\n        if ( os.path.isfile( baselineFile ) == False ):\n            makeBaseline = True\n        continue\n \n    dataMgr = testDataMgrs( makeBaseline )\n    if ( dataMgr != 0 ):\n        print( \"DataMgr tests failed.  Results are not identical to the baseline.\" )\n        rc = 1\n    else:\n        print( \"DataMgr tests passed\" )\n\n    sys.exit(rc)\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "test_apps/smokeTests/testDataMgr.cpp",
    "content": "// This test exercises the following DataMgr functions, and prints their\n// results.  These results can be captured and compared to previous results\n// as part of an automated test for reviewing Pull Requests.\n//\n// Functions under test:\n//\n//  DataMGr::DataMgr(string format, size_t mem_size, int nthreads = 0)\n//  DataMgr::GetDimensionNames()\n//  DataMgr::GetDimension( string dimname, DC:Dimension &dimension)\n//  DataMgr::GetMeshNames()\n//  DataMgr::GetMesh(string meshname, DC::Mesh &mesh)\n//  DataMgr::GetDataVarNames(int ndim)\n//  DataMgr::GetCoordVarNames()\n//  DataMgr::GetTimeCoordinates()\n//  DataMgr::GetTimeCoordVarName()\n//  DataMgr::GetNumTimeSteps()\n//  DataMgr::GetDataVarInfo(string varname, VAPoR::DC::DataVar &datavar)\n//  DataMgr::GetNumRefLevels(string varname)\n//  DataMgr::GetCRatios(string varname)\n//  DataMgr::GetVariable(\n//    size_t ts, string varname, int level, int lod, bool lock=false\n//  )\n//  DataMgr::GetVariableExtents(\n//    size_t ts, string varname, int level, int lod,\n//    std::vector <double> &min , std::vector <double> &max\n//  )\n//  DataMgr::GetDimLens(string varname, std::vector <size_t> &dims)\n//  DataMgr::GetNumDimensions( string varname )\n//  DataMgr::GetVarTopologyDim( sting varname )\n//  DataMgr::GetMapProjection()\n\n#include <iostream>\n#include <iomanip>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/DataMgr.h>\n#include <vapor/FileUtils.h>\n#include <vapor/utils.h>\n\n#include \"vapor/VAssert.h\"\n#include \"gridTools.h\"\n#include \"dataMgrTools.h\"\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    std::string             fileType;\n    int                     memsize;\n    int                     nthreads;\n    OptionParser::Boolean_T silenceTime;\n    OptionParser::Boolean_T nogeoxform;\n    OptionParser::Boolean_T novertxform;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"fileType\", 1, \"vdc\", \"data set type (vdc|wrf|cf|mpas)\"},\n                                         {\"memsize\", 1, \"2000\", \"Cache size in MBs\"},\n                                         {\"nthreads\", 1, \"0\",\n                                          \"Specify number of execution threads \"\n                                          \"0 => use number of cores\"},\n                                         {\"silenceTime\", 0, \"\", \"Do not print elapsed time for tests\"},\n                                         {\"nogeoxform\", 0, \"\", \"Do not apply geographic transform (projection to PCS\"},\n                                         {\"novertxform\", 0, \"\", \"Do not apply to convert pressure, etc. to meters\"},\n                                         {nullptr}};\n\nOptionParser::Option_T get_options[] = {{\"fileType\", Wasp::CvtToCPPStr, &opt.fileType, sizeof(opt.fileType)},\n                                        {\"memsize\", Wasp::CvtToInt, &opt.memsize, sizeof(opt.memsize)},\n                                        {\"nthreads\", Wasp::CvtToInt, &opt.nthreads, sizeof(opt.nthreads)},\n                                        {\"silenceTime\", Wasp::CvtToBoolean, &opt.silenceTime, sizeof(opt.silenceTime)},\n                                        {\"nogeoxform\", Wasp::CvtToBoolean, &opt.nogeoxform, sizeof(opt.nogeoxform)},\n                                        {\"novertxform\", Wasp::CvtToBoolean, &opt.novertxform, sizeof(opt.novertxform)},\n                                        {nullptr}};\n\nvoid InitializeOptions(int &argc, char **argv, OptionParser &op, std::vector<std::string> &files, std::vector<std::string> &options)\n{\n    std::string ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(EXIT_FAILURE);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(EXIT_FAILURE);\n    }\n\n    if (argc < 2) {\n        cerr << \"Usage: \" << ProgName << \" [options] dataFile \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(EXIT_FAILURE);\n    }\n\n    for (int i = 1; i < argc; i++) { files.push_back(argv[i]); }\n\n    if (!opt.nogeoxform) { options.push_back(\"-project_to_pcs\"); }\n    if (!opt.novertxform) { options.push_back(\"-vertical_xform\"); }\n}\n\nint main(int argc, char **argv)\n{\n    double t0 = Wasp::GetTime();\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    OptionParser        op;\n    std::vector<string> files;\n    std::vector<string> options;\n    InitializeOptions(argc, argv, op, files, options);\n\n    for (int i = 0; i < files.size(); i++) {\n        std::string fileName = files[i];\n        fileName = fileName.substr(fileName.find_last_of(\"\\\\/\") + 1);\n        cout << fileName << endl;\n    }\n\n    int rc = TestDataMgr(opt.fileType, opt.memsize, opt.nthreads, files, options, opt.silenceTime);\n\n    if (!opt.silenceTime) cout << \"Elapsed time: \" << Wasp::GetTime() - t0 << endl;\n\n    return rc;\n}\n"
  },
  {
    "path": "test_apps/smokeTests/testGrid.cpp",
    "content": "// This test exercises the RegularGrid, StretchedGrid, LayeredGrid,\n// and CurvilinearGrid classes.  These grids are created according to\n// a user-changable discretization, coordinate range, value range,\n// and block size.\n//\n// The grids are then assigned values according to\n// three data patterns: a constant field, a linear ramp, and a triangle\n// signal.\n//\n// After values are assigned, values are gathered and compared\n// from the functions Grid::GetValue( {i, j, k} ) and Grid::AccessIJK(i,j,k).\n// RMS error is computed, along with counts for mismatches, and queries\n// that yield missing values.\n//\n// This process is repeated once for linear interpolation, and once for\n// nearest-neighbor interpolation.\n//\n// Functions under test:\n//  LayeredGrid::LayeredGrid(\n//    const std::vector <size_t> &dims,\n//    const std::vector <size_t> &bs,\n//    const std::vector <float *> &blks,\n//    const std::vector <double> &xcoords,\n//    const std::vector <double> &ycoords,\n//    const RegularGrid &rg\n//  )\n//  RegularGrid::RegularGrid(\n//    const std::vector <size_t> &dims,\n//    const std::vector <size_t> &bs,\n//    const std::vector <float *> &blks,\n//    const std::vector <double> &minu,\n//    const std::vector <double> &maxu\n//  )\n//  StretchedGrid::StretchedGrid(\n//    const std::vector <size_t> &dims,\n//    const std::vector <size_t> &bs,\n//    const std::vector <float *> &blks,\n//    const std::vector <double> &xcoords,\n//    const std::vector <double> &ycoords,\n//    const std::vector <double> &zcoords\n//  )\n//  CurvilinearGrid::CurvilinearGrid(\n//    const std::vector <size_t> &dims,\n//    const std::vector <size_t> &bs,\n//    const std::vector <float *> &blks,\n//    const RegularGrid &xrg,\n//    const RegularGrid &yrg,\n//    const RegularGrid &zrg,\n//    std::shared_ptr <const QuadTreeRectangle<float, size_t> > qtr\n//  )\n//  Grid::GetDimensions()\n//  Grid::SetValueIJK(size_t i, size_t j, size_t k, float v)\n//  Grid::GetUserExtents(\n//    std::vector <double> &minu, std::vector <double> &maxu\n//  )\n//  Grid::GetValueAtIndex(const size_t indices[3])\n//  Grid::GetUserCoordinates(\n//    const size_t indices[],\n//    double coords[]\n//  )\n//  Grid::GetValue(const std::vector <double> &coords)\n//  Grid::GetMissingValue()\n//  Grid::SetInterpolationOrder(int order)\n\n#include <iostream>\n#include <iomanip>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include <algorithm>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/FileUtils.h>\n#include <vapor/OpenMPSupport.h>\n#include \"gridTools.h\"\n\n#include <vapor/ConstantGrid.h>\n\n#include <float.h>\n#include <cmath>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nnamespace {\nsize_t X = 0;\nsize_t Y = 1;\nsize_t Z = 2;\n\nstd::vector<float *> Heap;\n}    // namespace\n\nstruct opt_t {\n    std::vector<std::string> grids;\n    std::vector<std::string> arrangements;\n    std::vector<size_t>      dims;\n    std::vector<size_t>      bs;\n    std::vector<float>       extents;\n    double                   minValue;\n    double                   maxValue;\n    OptionParser::Boolean_T  silenceTime;\n    OptionParser::Boolean_T  help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"grids\", 1, \"Regular:Stretched:Layered:Curvilinear:Unstructured2D\", \"Colon delimited list of grids to test\"},\n                                         {\"arrangements\", 1, \"Constant:Ramp:RampOnAxis:Triangle:AllMissingValues:NoMissingValues\",\n                                          \"Colon delimited list of \"\n                                          \"data arrangements to test synthetic grids with\"},\n                                         {\"dims\", 1, \"8:8:8\",\n                                          \"Data volume dimensions expressed in \"\n                                          \"grid points (NX:NY:NZ)\"},\n                                         {\"bs\", 1, \"64:64:64\", \"Internal storage blocking factor expressed in grid points (NX:NY:NZ)\"},\n                                         {\"extents\", 1, \"0:0:0:1:1:1\",\n                                          \"Colon delimited 6-element vector \"\n                                          \"specifying domain extents of synthetic grids in user coordinates \"\n                                          \"(X0:Y0:Z0:X1:Y1:Z1)\"},\n                                         {\"minValue\", 1, \"0\", \"The minimum data value to be assigned to cells in synthetic grids\"},\n                                         {\"maxValue\", 1, \"1\", \"The maximum data value to be assigned to cells in synthetic grids\"},\n                                         {\"silenceTime\", 0, \"\", \"Do not print elapsed time for tests\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {nullptr}};\n\nOptionParser::Option_T get_options[] = {{\"grids\", Wasp::CvtToStrVec, &opt.grids, sizeof(opt.grids)},\n                                        {\"arrangements\", Wasp::CvtToStrVec, &opt.arrangements, sizeof(opt.arrangements)},\n                                        {\"dims\", Wasp::CvtToSize_tVec, &opt.dims, sizeof(opt.dims)},\n                                        {\"bs\", Wasp::CvtToSize_tVec, &opt.bs, sizeof(opt.bs)},\n                                        {\"extents\", Wasp::CvtToFloatVec, &opt.extents, sizeof(opt.extents)},\n                                        {\"minValue\", Wasp::CvtToDouble, &opt.minValue, sizeof(opt.minValue)},\n                                        {\"maxValue\", Wasp::CvtToDouble, &opt.maxValue, sizeof(opt.maxValue)},\n                                        {\"silenceTime\", Wasp::CvtToBoolean, &opt.silenceTime, sizeof(opt.silenceTime)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {nullptr}};\n\nvoid InitializeOptions(int argc, char **argv, OptionParser &op)\n{\n    std::string ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(EXIT_FAILURE);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(EXIT_FAILURE);\n    }\n\n    if (opt.extents.size() != 6) {\n        cerr << \"The -extents flag must contain 6 elements if used\" << endl;\n        op.PrintOptionHelp(stderr, 80, false);\n        exit(EXIT_FAILURE);\n    }\n\n    if (opt.dims.size() != 3) {\n        cerr << \"The -dims flag must contain 3 elements if used\" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(EXIT_FAILURE);\n    }\n\n    if (opt.help) {\n        op.PrintOptionHelp(stderr);\n        exit(EXIT_FAILURE);\n    }\n}\n\nint main(int argc, char **argv)\n{\n    double t0 = Wasp::GetTime();\n\n    OptionParser op;\n    InitializeOptions(argc, argv, op);\n\n    std::cout << std::fixed << std::showpoint;\n    std::cout << std::setprecision(4);\n\n    std::vector<double> minu = {opt.extents[X], opt.extents[Y], opt.extents[Z]};\n    std::vector<double> maxu = {opt.extents[X + 3], opt.extents[Y + 3], opt.extents[Z + 3]};\n\n    std::vector<size_t> bs2d = {opt.bs[X], opt.bs[Y]};\n    std::vector<double> minu2d = {minu[X], minu[Y]};\n    std::vector<double> maxu2d = {maxu[X], maxu[Y]};\n\n    std::vector<size_t> dims2d = {opt.dims[X], opt.dims[Y]};\n\n    int  rc = EXIT_SUCCESS;\n    bool regularRC = true;\n    bool stretchedRC = true;\n    bool layeredRC = true;\n    bool curvilinearRC = true;\n    bool unstructured2DRC = true;\n\n#pragma omp parallel\n    {\n        if (omp_get_thread_num() == 0)\n          cout << \"Num threads: \" << omp_get_num_threads() << endl;\n    }\n\n    // Test Regular Grid\n    if (std::find(opt.grids.begin(), opt.grids.end(), \"Regular\") != opt.grids.end()) {\n        double               t0 = Wasp::GetTime();\n        std::vector<float *> rgBlks = AllocateBlocks(opt.bs, opt.dims);\n        RegularGrid *        regularGrid = new RegularGrid(opt.dims, opt.bs, rgBlks, minu, maxu);\n        double               t1 = Wasp::GetTime() - t0;\n        if (!opt.silenceTime) cout << \"RegularGrid() time: \" << t1 << endl;\n        regularRC = RunTests(regularGrid, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime);\n        delete regularGrid;\n    }\n\n    // Test Stretched Grid\n    if (std::find(opt.grids.begin(), opt.grids.end(), \"Stretched\") != opt.grids.end()) {\n        double         t0 = Wasp::GetTime();\n        StretchedGrid *stretchedGrid = MakeStretchedGrid(opt.dims, opt.bs, minu, maxu);\n        double         t1 = Wasp::GetTime() - t0;\n        if (!opt.silenceTime) cout << \"MakeStretchedGrid() time: \" << t1 << endl;\n        stretchedRC = RunTests(stretchedGrid, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime);\n        delete stretchedGrid;\n    }\n\n    // Test Layered Grid\n    if (std::find(opt.grids.begin(), opt.grids.end(), \"Layered\") != opt.grids.end()) {\n        double       t0 = Wasp::GetTime();\n        LayeredGrid *layeredGrid = MakeLayeredGrid(opt.dims, opt.bs, minu, maxu);\n        double       t1 = Wasp::GetTime() - t0;\n        if (!opt.silenceTime) cout << \"MakeLayeredGrid() time: \" << t1 << endl;\n        layeredRC = RunTests(layeredGrid, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime);\n        delete layeredGrid;\n    }\n\n    // Test Curvilinear Grid\n    if (std::find(opt.grids.begin(), opt.grids.end(), \"Curvilinear\") != opt.grids.end()) {\n        double           t0 = Wasp::GetTime();\n        CurvilinearGrid *curvilinearGrid;\n        curvilinearGrid = MakeCurvilinearTerrainGrid(opt.bs, minu, maxu, opt.dims);\n        double t1 = Wasp::GetTime() - t0;\n        if (!opt.silenceTime) cout << \"MakeCurvilinearTerrainGrid() time: \" << t1 << endl;\n        curvilinearRC = RunTests(curvilinearGrid, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime);\n        delete curvilinearGrid;\n    }\n\n    // Test Unstructured Grid 2D\n    if (std::find(opt.grids.begin(), opt.grids.end(), \"Unstructured2D\") != opt.grids.end() && opt.dims[0] > 1 && opt.dims[1] > 1) {\n        double              t0 = Wasp::GetTime();\n        UnstructuredGrid2D *g = MakeUnstructuredGrid2D(opt.dims, opt.bs, minu, maxu);\n        double              t1 = Wasp::GetTime() - t0;\n        if (!opt.silenceTime) cout << \"MakeUnstructuredGrid2D() time: \" << t1 << endl;\n        unstructured2DRC = RunTests(g, opt.arrangements, opt.minValue, opt.maxValue, opt.silenceTime);\n        delete g;\n    }\n\n    if (regularRC == false) {\n        cerr << \"Errors occurred while testing Grid::RegularGrid.\" << endl;\n        rc = EXIT_FAILURE;\n    }\n    if (stretchedRC == false) {\n        cerr << \"Errors occurred while testing Grid::StretchedGrid.\" << endl;\n        rc = EXIT_FAILURE;\n    }\n    if (layeredRC == false) {\n        cerr << \"Errors occurred while testing Grid::LayeredGrid.\" << endl;\n        rc = EXIT_FAILURE;\n    }\n    if (curvilinearRC == false) {\n        cerr << \"Errors occurred while testing Grid::CurvilinearGrid.\" << endl;\n        rc = EXIT_FAILURE;\n    }\n    if (unstructured2DRC == false) {\n        cerr << \"Errors occurred while testing Grid::UnstructuredGrid2D.\" << endl;\n        rc = EXIT_FAILURE;\n    }\n\n    double t1 = Wasp::GetTime();\n    if (!opt.silenceTime) cout << \"Elapsed time: \" << t1 - t0 << endl;\n\n    DeleteHeap();\n\n    return rc;\n}\n"
  },
  {
    "path": "test_apps/smokeTests/testResults/cf_baseline.txt",
    "content": "24Maycontrol.04000.000000.nc\n\nDimensions:\n    time = 1\n    Time Varying: 0\n    xh = 371\n    Time Varying: 0\n    yh = 441\n    Time Varying: 0\n    zf = 201\n    Time Varying: 0\n    zh = 201\n    Time Varying: 0\n\nMeshes:\n    \n    xhxyhxzh\n\n3D variables: \n    dbz\n    hvort\n    prespert\n    qc\n    qg\n    qr\n    streamvort\n    thrhopert\n    uinterp\n    vinterp\n    vortmag\n    winterp\n    xvort\n    yvort\n    zvort\n\nCompression Info for variable dbz:\n    Refinement Levels:  1\n    Compression Ratios: 1\n\nGrid test for 3D variable dbz:\n    # Dimensions:       3\n    Dimension Lengths:  371 441 201\n    Topology Dimension: 3\n\n    RMS error:                                           0\n    Missing value count:                                 0\n    GetValueAtIndex() vs GetValue() disagreement count:  0\n    Time:                                                0\n\nProjection String:  \n\nCoordinate Variables:\n    time\n    xh\n    yh\n    zf\n    zh\n    time\n\nTime Coordinates:\n    -31618400\n\nTime coordinate variable name: time\nNumber of time steps: 1\nElapsed time: 0.00193455\n"
  },
  {
    "path": "test_apps/smokeTests/testResults/vdc_baseline.txt",
    "content": "katrina_1timeStep.vdc\n\nDimensions:\n    DateStrLen = 19\n    Time Varying: 0\n    Time = 1\n    Time Varying: 0\n    bottom_top = 34\n    Time Varying: 0\n    bottom_top_stag = 35\n    Time Varying: 0\n    ext_scalar = 1\n    Time Varying: 0\n    soil_layers_stag = 5\n    Time Varying: 0\n    south_north = 309\n    Time Varying: 0\n    south_north_stag = 310\n    Time Varying: 0\n    west_east = 315\n    Time Varying: 0\n    west_east_stag = 316\n    Time Varying: 0\n\nMeshes:\n    west_eastXsouth_north\n    west_eastXsouth_northXbottom_top\n    west_eastXsouth_northXbottom_top_stag\n    west_eastXsouth_northXsoil_layers_stag\n    west_eastXsouth_north_stag\n    west_eastXsouth_north_stagXbottom_top\n    west_east_stagXsouth_north\n    west_east_stagXsouth_northXbottom_top\n\n2D variables: \n    CANWAT\n    COSALPHA\n    E\n    F\n    GLW\n    GRDFLX\n    HFX\n    HGT\n    LANDMASK\n    LH\n    LU_INDEX\n    MAPFAC_M\n    MAPFAC_U\n    MAPFAC_V\n    MU\n    MUB\n    NEST_POS\n    PBLH\n    PSFC\n    Q2\n    QFX\n    RAINC\n    RAINNC\n    RMOL\n    SFROFF\n    SINALPHA\n    SNOW\n    SNOWC\n    SNOWH\n    SST\n    SWDOWN\n    T2\n    TH2\n    TMN\n    TSK\n    U10\n    UDROFF\n    V10\n    VEGFRA\n    XICE\n    XLAND\n\n3D variables: \n    P\n    PB\n    PH\n    PHB\n    QCLOUD\n    QRAIN\n    QVAPOR\n    SH2O\n    SMOIS\n    T\n    TSLB\n    U\n    V\n    W\n\nCompression Info for variable CANWAT:\n    Refinement Levels:  4\n    Compression Ratios: 62 21 4 1\n\nGrid test for 2D variable CANWAT:\n    # Dimensions:       2\n    Dimension Lengths:  315 309\n    Topology Dimension: 2\n\n    RMS error:                                           0\n    Missing value count:                                 0\n    GetValueAtIndex() vs GetValue() disagreement count:  0\n    Time:                                                0\n\nCompression Info for variable P:\n    Refinement Levels:  4\n    Compression Ratios: 500 100 10 1\n\nGrid test for 3D variable P:\n    # Dimensions:       3\n    Dimension Lengths:  315 309 34\n    Topology Dimension: 3\n\n    RMS error:                                           0\n    Missing value count:                                 0\n    GetValueAtIndex() vs GetValue() disagreement count:  0\n    Time:                                                0\n\nProjection String:  +proj=merc +lon_0=-85 +lat_ts=30 +ellps=WGS84\n\nCoordinate Variables:\n    Time\n    XLAT\n    XLAT_U\n    XLAT_V\n    XLONG\n    XLONG_U\n    XLONG_V\n    bottom_top\n    bottom_top_stag\n    soil_layers_stag\n    Elevation\n    ElevationU\n    ElevationV\n    ElevationW\n    XLATY\n    XLAT_UY\n    XLAT_VY\n    XLONGX\n    XLONG_UX\n    XLONG_VX\n\nTime Coordinates:\n    147016800\n\nTime coordinate variable name: Time\nNumber of time steps: 1\nElapsed time: 0.017814\n"
  },
  {
    "path": "test_apps/smokeTests/testResults/wrf_baseline.txt",
    "content": "wrfout_d02_2005-08-29_05\n\nDimensions:\n    DateStrLen = 19\n    Time Varying: 0\n    Time = 1\n    Time Varying: 0\n    bottom_top = 34\n    Time Varying: 0\n    bottom_top_stag = 35\n    Time Varying: 0\n    ext_scalar = 1\n    Time Varying: 0\n    soil_layers_stag = 5\n    Time Varying: 0\n    south_north = 309\n    Time Varying: 0\n    south_north_stag = 310\n    Time Varying: 0\n    west_east = 315\n    Time Varying: 0\n    west_east_stag = 316\n    Time Varying: 0\n\nMeshes:\n    west_east_stagxsouth_north\n    west_east_stagxsouth_northxbottom_top\n    west_eastxsouth_north\n    west_eastxsouth_north_stag\n    west_eastxsouth_north_stagxbottom_top\n    west_eastxsouth_northxbottom_top\n    west_eastxsouth_northxbottom_top_stag\n    west_eastxsouth_northxsoil_layers_stag\n\n2D variables: \n    CANWAT\n    COSALPHA\n    E\n    F\n    GLW\n    GRDFLX\n    HFX\n    HGT\n    ISLTYP\n    IVGTYP\n    LANDMASK\n    LH\n    LU_INDEX\n    MAPFAC_M\n    MAPFAC_U\n    MAPFAC_V\n    MU\n    MUB\n    NEST_POS\n    PBLH\n    PSFC\n    Q2\n    QFX\n    RAINC\n    RAINNC\n    RMOL\n    SFROFF\n    SINALPHA\n    SNOW\n    SNOWC\n    SNOWH\n    SST\n    SWDOWN\n    T2\n    TH2\n    TMN\n    TSK\n    U10\n    UDROFF\n    V10\n    VEGFRA\n    XICE\n    XLAND\n\n3D variables: \n    P\n    PB\n    PH\n    PHB\n    QCLOUD\n    QRAIN\n    QVAPOR\n    SH2O\n    SMOIS\n    T\n    TSLB\n    U\n    V\n    W\n\nCompression Info for variable CANWAT:\n    Refinement Levels:  1\n    Compression Ratios: 1\n\nGrid test for 2D variable CANWAT:\n    # Dimensions:       2\n    Dimension Lengths:  315 309\n    Topology Dimension: 2\n\n    RMS error:                                           0\n    Missing value count:                                 0\n    GetValueAtIndex() vs GetValue() disagreement count:  0\n    Time:                                                0\n\nCompression Info for variable P:\n    Refinement Levels:  1\n    Compression Ratios: 1\n\nGrid test for 3D variable P:\n    # Dimensions:       3\n    Dimension Lengths:  315 309 34\n    Topology Dimension: 3\n\n    RMS error:                                           0\n    Missing value count:                                 0\n    GetValueAtIndex() vs GetValue() disagreement count:  0\n    Time:                                                0\n\nProjection String:  +proj=merc +lon_0=-85 +lat_ts=30 +ellps=WGS84\n\nCoordinate Variables:\n    Time\n    XLAT\n    XLAT_U\n    XLAT_V\n    XLONG\n    XLONG_U\n    XLONG_V\n    bottom_top\n    bottom_top_stag\n    soil_layers_stag\n    Elevation\n    ElevationU\n    ElevationV\n    ElevationW\n    XLATY\n    XLAT_UY\n    XLAT_VY\n    XLONGX\n    XLONG_UX\n    XLONG_VX\n\nTime Coordinates:\n    146984400\n\nTime coordinate variable name: Time\nNumber of time steps: 1\nElapsed time: 3.46721\n"
  },
  {
    "path": "test_apps/udunits/CMakeLists.txt",
    "content": "add_executable (test_udunits test_udunits.cpp)\nset_target_properties(test_udunits PROPERTIES RUNTIME_OUTPUT_DIRECTORY \"${debug_output_dir}\")\n\ntarget_link_libraries (test_udunits common vdc wasp)\n"
  },
  {
    "path": "test_apps/udunits/test_udunits.cpp",
    "content": "#include <iostream>\n#include <iomanip>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/UDUnitsClass.h>\n#include <vapor/FileUtils.h>\n\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    int                     year;\n    int                     month;\n    int                     day;\n    int                     hour;\n    int                     minute;\n    int                     second;\n    OptionParser::Boolean_T help;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {{\"year\", 1, \"2020\", \"year\"},\n                                         {\"month\", 1, \"1\", \"month\"},\n                                         {\"day\", 1, \"1\", \"day\"},\n                                         {\"hour\", 1, \"1\", \"hour\"},\n                                         {\"minute\", 1, \"1\", \"minute\"},\n                                         {\"second\", 1, \"1\", \"second\"},\n                                         {\"help\", 0, \"\", \"Print this message and exit\"},\n                                         {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"year\", Wasp::CvtToInt, &opt.year, sizeof(opt.year)},       {\"month\", Wasp::CvtToInt, &opt.month, sizeof(opt.month)},\n                                        {\"day\", Wasp::CvtToInt, &opt.day, sizeof(opt.day)},          {\"hour\", Wasp::CvtToInt, &opt.hour, sizeof(opt.hour)},\n                                        {\"minute\", Wasp::CvtToInt, &opt.minute, sizeof(opt.minute)}, {\"second\", Wasp::CvtToInt, &opt.second, sizeof(opt.second)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},   {NULL}};\n\n\nconst char *ProgName;\n\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    string       s;\n\n    ProgName = FileUtils::LegacyBasename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << \" [options] \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n\n    UDUnits udunits;\n    int     rc = udunits.Initialize();\n    if (rc < 0) return (1);\n\n    double seconds_since_epoch = 0.0;\n    seconds_since_epoch = udunits.EncodeTime(opt.year, opt.month, opt.day, opt.hour, opt.minute, opt.second);\n\n\n    int year, month, day, hour, minute, second;\n    udunits.DecodeTime(seconds_since_epoch, &year, &month, &day, &hour, &minute, &second);\n\n    if (year != opt.year || month != opt.month || day != opt.day || hour != opt.hour || minute != opt.minute || second != opt.second) {\n        cerr << \"Time/dates disagree\" << endl;\n        cerr << \"Input \" << opt.year << \"-\";\n        cerr << opt.month << \"-\";\n        cerr << opt.day << \"_\";\n        cerr << opt.hour << \":\";\n        cerr << opt.minute << \":\";\n        cerr << opt.second << endl;\n\n        cerr << \"Output \" << year << \"-\";\n        cerr << month << \"-\";\n        cerr << day << \"_\";\n        cerr << hour << \":\";\n        cerr << minute << \":\";\n        cerr << second << endl;\n\n        return (1);\n    }\n    return (0);\n}\n"
  },
  {
    "path": "test_apps/vdc3test/test.csh",
    "content": "#!/bin/csh -f\n\nset data = /glade/p/DASG/VAPOR/Data/Raw/checker128\nset dataconst = /glade/p/DASG/VAPOR/Data/Raw/constant\nset data64 = /glade/p/DASG/VAPOR/Data/Raw/checker64\n\n#./vdc3test.csh -dim 512x512x255 -- -- -lod -1 -level -1 $dataconst\n\n#\n# DIM\n#\n./vdc3test.csh -dim 64x64x64 -- -- $data64\nif ($status) exit 1\n\n./vdc3test.csh -dim 128x128x128 -- -- $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 120x128x128 -- -- $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 128x120x128 -- -- $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 128x128x120 -- -- $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 120x63x120 -- -- $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 127x94x33 -- -- $data\nif ($status) exit 1\n\n\n#\n# LOD\n#\n./vdc3test.csh -dim 128x128x128 -- -lod 0 -- -lod 0 $data\nif ($status) exit 1\n./vdc3test.csh -dim 128x128x128 -- -lod 1 -- -lod 1 $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 128x128x128 -- -- -lod 0 $data\nif ($status) exit 1\n./vdc3test.csh -dim 128x128x128 -- -- -lod 1 $data\nif ($status) exit 1\n\n#\n# LEVEL\n#\n./vdc3test.csh -dim 128x128x128 -- -- -level 0 $data\nif ($status) exit 1\n./vdc3test.csh -dim 128x128x128 -- -- -level 1 $data\nif ($status) exit 1\n\n#\n# LEVEL+LOD\n#\n./vdc3test.csh -dim 128x128x128 -- -- -lod 2 -level 0 $data\nif ($status) exit 1\n./vdc3test.csh -dim 128x128x128 -- -- -lod 2 -level 1 $data\nif ($status) exit 1\n\n#\n# BS\n#\n./vdc3test.csh -cratio 1:10:100:300 -dim 128x128x128 -bs 65x65x65 -- -- $data\nif ($status) exit 1\n\n#\n# appears to be broken in raw2vdf\n#\n#./vdc3test.csh -cratio 1:10:100:300 -dim 121x119x134 -bs 65x66x67 -- -- $data\n#if ($status) exit 1\n\n#\n# CRATIO\n#\n./vdc3test.csh -dim 128x128x63 -cratio 1 -- -- -lod -1 -level -1 $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 128x128x63 -cratio 1 -- -- -lod -1 -level -1 $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 128x128x128 -cratio 10:50 -- -- -lod 1 $data\nif ($status) exit 1\n\n# broken in 2.x\n#./vdc3test.csh -dim 128x128x128 -cratio 10:50 -- -- $data\n#if ($status) exit 1\n\n\n#\n# region\n#\n./vdc3test.csh -dim 128x128x128 -- -- -xregion 5:123 $data\nif ($status) exit 1\n./vdc3test.csh -dim 128x128x128 -- -- -yregion 5:123 $data\nif ($status) exit 1\n./vdc3test.csh -dim 128x128x128 -- -- -zregion 5:123 $data\nif ($status) exit 1\n./vdc3test.csh -dim 128x128x128 -- -- -xregion 90:100 -yregion 5:123 -zregion 10:63  $data\nif ($status) exit 1\n\n#\n# TS, NUMTS\n#\n./vdc3test.csh -dim 128x128x128 -numts 10 -- -ts 9 -- -ts 9 $data\nif ($status) exit 1\n\n\n##\n## 2D DATA\n##\n\n\n#\n# VAR2DXY\n#\n./vdc3test.csh -dim 128x128x128 -vars2dxy var2dxy -- -var var2dxy -- -var var2dxy $data\nif ($status) exit 1\n\n./vdc3test.csh -dim 128x128x128 -vars2dxy var2dxy -- -var var2dxy -- -var var2dxy -xregion 5:123 -yregion 5:50 $data\nif ($status) exit 1\n"
  },
  {
    "path": "test_apps/vdc3test/vdc3test.csh",
    "content": "#!/bin/csh -f\n\nset TmpDir = \"/tmp\"\n\nif ($#argv < 1) then\n\techo \"Usage $0 [xcreate options] -- [raw2x options] -- [x2raw options] rawfile\"\n\texit 1\nendif\n\nset ProgName = `basename $0`\nset state = 0\nset xcreate_options = \"\"\nset raw2x_options = \"\"\nset x2raw_options = \"\"\n\nwhile ($#argv > 1) \n\n\tif (\"$argv[1]\" == \"--\") then\n\t\t@ state += 1\n\telse \n\t\tswitch (\"$state\")\n\t\tcase \"0\":\n\t\t\tset xcreate_options = ($xcreate_options $argv[1])\n\t\t\tbreaksw\n\t\tcase \"1\":\n\t\t\tset raw2x_options = ($raw2x_options $argv[1])\n\t\t\tbreaksw\n\t\tcase \"2\":\n\t\t\tset x2raw_options = ($x2raw_options $argv[1])\n\t\t\tbreaksw\n\t\tdefault:\t\t\n\t\t\techo \"BOGUS\"\n\t\t\texit 1\n\t\t\tbreaksw\n\t\tendsw\n\tendif\n\tshift\nend\n\nset rawfile = $argv[1]\n\n#echo xcreate_options = $xcreate_options\n#echo raw2x_options = $raw2x_options\n#echo x2raw_options = $x2raw_options\n#echo rawfile = $rawfile\n#exit 0\n\nset vdffile = $TmpDir/${ProgName:r}_vdf.vdf\n/bin/rm -fr $vdffile\n/bin/rm -fr ${vdffile:r}_data\nset cmd = \"vdfcreate -vdc2 $xcreate_options $vdffile\"\necho $cmd\n$cmd\nif ($status != 0) then\n\techo \"FAILED : $cmd\"\n\texit 1\nendif\n\nset cmd = \"raw2vdf $raw2x_options $vdffile $rawfile\"\necho $cmd\n$cmd\nif ($status != 0) then\n\techo \"FAILED : $cmd\"\n\texit 1\nendif\n\nset vdfrfile = $TmpDir/${ProgName:r}_vdfr.raw\nset cmd = \"vdf2raw $x2raw_options $vdffile $vdfrfile\"\necho $cmd\n$cmd\nif ($status != 0) then\n\techo \"FAILED : $cmd\"\n\texit 1\nendif\n\nset master = $TmpDir/${ProgName:r}_nc.nc\n/bin/rm -fr $master\n/bin/rm -fr ${master:r}_data\nset cmd = \"vdccreate $xcreate_options $master\"\necho $cmd\n$cmd\nif ($status != 0) then\n\techo \"FAILED : $cmd\"\n\texit 1\nendif\n\nset cmd = \"raw2vdc $raw2x_options $master $rawfile\"\necho $cmd\n$cmd\nif ($status != 0) then\n\techo \"FAILED : $cmd\"\n\texit 1\nendif\n\nset vdcrfile = $TmpDir/${ProgName:r}_vdcr.raw\nset cmd = \"vdc2raw $x2raw_options $master $vdcrfile\"\necho $cmd\n$cmd\nif ($status != 0) then\n\techo \"FAILED : $cmd\"\n\texit 1\nendif\n\nset cmd = \"diff $vdfrfile $vdcrfile\"\necho $cmd\n$cmd\nif ($status != 0) then\n\techo \"FAILED : $cmd\"\n\texit 1\nendif\n\necho \"SUCCESS\"\n/bin/rm $vdfrfile $vdcrfile\nexit 0\n"
  },
  {
    "path": "test_apps/xmlnode/test_xmlnode.cpp",
    "content": "#include <iostream>\n#include <iomanip>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <cstdio>\n#include \"vapor/VAssert.h\"\n\n#include <vapor/CFuncs.h>\n#include <vapor/OptionParser.h>\n#include <vapor/XmlNode.h>\n\nusing namespace Wasp;\nusing namespace VAPoR;\n\nstruct {\n    string                  ifile;\n    OptionParser::Boolean_T help;\n    OptionParser::Boolean_T quiet;\n    OptionParser::Boolean_T debug;\n} opt;\n\nOptionParser::OptDescRec_T set_opts[] = {\n    {\"ifile\", 1, \"\", \"Construct Xml tree from a file\"}, {\"help\", 0, \"\", \"Print this message and exit\"}, {\"quiet\", 0, \"\", \"Operate quitely\"}, {\"debug\", 0, \"\", \"Debug mode\"}, {NULL}};\n\nOptionParser::Option_T get_options[] = {{\"ifile\", Wasp::CvtToCPPStr, &opt.ifile, sizeof(opt.ifile)},\n                                        {\"help\", Wasp::CvtToBoolean, &opt.help, sizeof(opt.help)},\n                                        {\"quiet\", Wasp::CvtToBoolean, &opt.quiet, sizeof(opt.quiet)},\n                                        {\"debug\", Wasp::CvtToBoolean, &opt.debug, sizeof(opt.debug)},\n                                        {NULL}};\n\nconst char *ProgName;\n\nint main(int argc, char **argv)\n{\n    OptionParser op;\n    double       timer = 0.0;\n    string       s;\n\n    ProgName = Basename(argv[0]);\n\n    MyBase::SetErrMsgFilePtr(stderr);\n\n    if (op.AppendOptions(set_opts) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (op.ParseOptions(&argc, argv, get_options) < 0) {\n        cerr << ProgName << \" : \" << op.GetErrMsg();\n        exit(1);\n    }\n\n    if (opt.help) {\n        cerr << \"Usage: \" << ProgName << endl;\n        op.PrintOptionHelp(stderr);\n        exit(0);\n    }\n\n    if (opt.debug) { MyBase::SetDiagMsgFilePtr(stderr); }\n\n    if (argc != 1) {\n        cerr << \"Usage: \" << ProgName << \" [options] \" << endl;\n        op.PrintOptionHelp(stderr);\n        exit(1);\n    }\n\n    XmlNode *parent = new XmlNode(\"parent\");\n    parent->SetElementLong(\"long_data1\", 1);\n    parent->SetElementLong(\"long_data2\", 2);\n    parent->SetElementString(\"string_data\", \"my string\");\n    parent->SetElementDouble(\"double_data1\", 3.0);\n\n    XmlNode *child1 = parent->NewChild(\"child1\");\n    child1->SetElementLong(\"long_data1\", 4);\n    child1->SetElementLong(\"long_data2\", 5);\n    child1->SetElementString(\"string_data\", \"my string\");\n    child1->SetElementDouble(\"double_data1\", 6.0);\n    VAssert(child1->GetParent() == parent);\n\n    XmlNode *child2 = parent->NewChild(\"child2\");\n    child2->SetElementLong(\"long_data1\", 7);\n    child2->SetElementLong(\"long_data2\", 8);\n    child2->SetElementString(\"string_data\", \"my string\");\n    child2->SetElementDouble(\"double_data1\", 9.0);\n    VAssert(child2->GetParent() == parent);\n\n    XmlNode *child3 = child2->NewChild(\"child3\");\n    VAssert(child3 != NULL);\n    VAssert(child3->GetParent() == child2);\n\n    child3->SetElementLong(\"long_data1\", 10);\n    child3->SetElementLong(\"long_data2\", 11);\n    child3->SetElementString(\"string_data\", \"my string\");\n    child3->SetElementDouble(\"double_data1\", 12.0);\n\n    XmlNode *parent2 = new XmlNode(*parent);\n\n    if (*parent2 == *parent) {\n        cout << \"parent == parent 2\" << endl;\n    } else {\n        cout << \"parent != parent 2\" << endl;\n    }\n\n    child3->SetElementDouble(\"double_data1\", 99.0);\n\n    if (*parent2 == *parent) {\n        cout << \"parent == parent 2\" << endl;\n    } else {\n        cout << \"parent != parent 2\" << endl;\n    }\n\n    cout << \"Allocated note count before delete : \" << XmlNode::GetAllocatedNodes().size() << endl;\n\n    delete parent;\n    delete parent2;\n\n    cout << \"Allocated note count after delete : \" << XmlNode::GetAllocatedNodes().size() << endl;\n\n    // cout << \"parent 1 \" << endl << parent;\n    // cout << \"parent 2 \" << endl << *parent2;\n\n    if (!opt.ifile.empty()) {\n        XmlNode   parent3;\n        XmlParser parser;\n        int       rc = parser.LoadFromFile(&parent3, opt.ifile);\n        if (rc < 0) return 1;\n        cout << \"parent 3 \" << endl << parent3;\n    }\n}\n"
  }
]